exponenta event banner

CERT C: ENV34-C правил

Не сохранять указатели, возвращенные определенными функциями

Описание

Определение правила

Не сохранять указатели, возвращенные определенными функциями. [1 ]

Внедрение Polyspace

Эта проверка проверяет, не используется ли возвращаемое значение из нестандартной стандартной функции.

Примеры

развернуть все

Проблема

Неправильное использование возвращаемого значения из неназначенной стандартной функции происходит, когда эти события происходят в следующей последовательности:

  1. Вы указываете на буфер, возвращенный из неназначенной стандартной функции, такой как getenv или setlocale.

    user = getenv("USER");
  2. Вы снова вызываете эту неназначенную стандартную функцию.

    user2 = getenv("USER2");
  3. Вы используете или отменяете привязку указателя с первого шага, ожидая, что буфер останется неизмененным с момента этого шага. Тем временем вызов на втором шаге изменил буфер.

    Например:

    var=*user;

В некоторых случаях дефект может появиться, даже если вы не вызываете getenv функция во второй раз, но просто возвращает указатель. Например:

char* func() {
     user=getenv("USER");
     .
     .
     return user;
}

Для получения информации о том, какие функции охватываются этим дефектом, см. документацию по не входящим стандартным функциям.

Риск

Стандарт C позволяет выполнять такие функции, как getenv возвращает указатель на статический буфер. Поскольку буфер является статическим, второй вызов getenv изменяет буфер. При продолжении использования указателя, возвращенного при первом вызове после второго вызова, можно увидеть неожиданные результаты. Буфер, на который он указывает, больше не имеет значений с первого вызова.

Дефект появляется, даже если вы не вызываете getenv второй раз, но просто вернуть указатель. Причина в том, что человек, вызывающий вашу функцию, может использовать возвращенный указатель после второго вызова getenv. Возвращая указатель из звонка в getenv, вы делаете свою функцию небезопасной для использования.

То же обоснование справедливо и для других неназначенных функций, охватываемых этим дефектом.

Зафиксировать

После первого звонка на getenv, создайте копию буфера, на который указывает возвращенный указатель. После второго звонка на getenv, используйте эту копь. даже если второй вызов изменяет буфер, ваша копия не тронута.

Пример - Возврат из getenv Используется после второго вызова getenv
#include <stdlib.h>
#include <string.h>

int func()
{
    int result = 0;

    char *home = getenv("HOME");   /* First call */ 
    if (home != NULL) {
        char *user = NULL;
        char *user_name_from_home = strrchr(home, '/');
 
        if (user_name_from_home != NULL) {
            user = getenv("USER");   /* Second call */
            if ((user != NULL) &&
                (strcmp(user, user_name_from_home) == 0)) 
            {
                result = 1;
            }
        }
    }
    return result;
}

В этом примере указатель user_name_from_home является производным от указателя home. home указывает на буфер, возвращенный с первого вызова getenv. Поэтому user_name_from_home указывает на расположение в том же буфере.

После второго звонка на getenv, буфер изменен. Если вы продолжаете использовать user_name_from_home, вы можете получить неожиданные результаты.

Исправление - копирование буфера перед вторым вызовом

Если требуется получить доступ к буферу с первого вызова getenv после второго вызова создайте копию буфера после первого вызова. Одной из возможных корректировок является использование strdup для создания копии.

#include <stdlib.h>
#include <string.h>

int func()
{
    int result = 0;

    char *home = getenv("HOME");    
    if (home != NULL) {
        char *user = NULL;
        char *user_name_from_home = strrchr(home, '/'); 
        if (user_name_from_home != NULL) {
            /* Make copy before second call */
            char *saved_user_name_from_home = strdup(user_name_from_home); 
            if (saved_user_name_from_home != NULL) {
                user = getenv("USER");  
                if ((user != NULL) &&
                    (strcmp(user, saved_user_name_from_home) == 0)) 
                {
                    result = 1;
                }
                free(saved_user_name_from_home);
            }
        }
    }
    return result;
}

Проверить информацию

Группа: Правило 10. Окружающая среда (ENV)
Представлен в R2019a

[1] Данное программное обеспечение было создано компанией MathWorks и включает в себя следующие компоненты: «Веб-сайт SEI CERT-C», © 2017 Университет Карнеги-Меллон, веб-сайт SEI CERT-C + + © 2017 Университет Карнеги-Меллон, "Стандарт кодирования SEI CERT C - Правила разработки безопасных, Надежные и безопасные системы - 2016 Edition ", © 2016 Университет Карнеги-Меллон, и "Стандарт кодирования SEI CERT C++ - Правила разработки безопасных, Надежные и безопасные системы в C++ - 2016 Edition "© 2016 Университет Карнеги-Меллон, со специальным разрешением от его Института программного обеспечения.

ЛЮБОЙ МАТЕРИАЛ УНИВЕРСИТЕТА КАРНЕГИ МЕЛЛОНА И/ИЛИ ЕГО ПРОГРАММНОГО ИНЖЕНЕРНОГО ИНСТИТУТА, СОДЕРЖАЩИЙСЯ В НАСТОЯЩЕМ ДОКУМЕНТЕ, ПОСТАВЛЯЕТСЯ КАК ЕСТЬ. УНИВЕРСИТЕТ КАРНЕГИ МЕЛЛОН НЕ ДАЕТ НИКАКИХ ГАРАНТИЙ, ВЫРАЖЕННЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ, В ОТНОШЕНИИ ЛЮБЫХ ВОПРОСОВ, ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЬ, ГАРАНТИИ ПРИГОДНОСТИ ДЛЯ ЦЕЛЕЙ ИЛИ ТОВАРНОЙ ПРИГОДНОСТИ, ИСКЛЮЧИТЕЛЬНОСТИ ИЛИ РЕЗУЛЬТАТОВ, ПОЛУЧЕННЫХ ОТ ИСПОЛЬЗОВАНИЯ УНИВЕРСИТЕТ КАРНЕГИ МЕЛЛОН НЕ ДАЕТ НИКАКИХ ГАРАНТИЙ В ОТНОШЕНИИ СВОБОДЫ ОТ ПАТЕНТА, ТОВАРНОГО ЗНАКА ИЛИ НАРУШЕНИЯ АВТОРСКИХ ПРАВ.

Данное программное обеспечение и связанная с ним документация не были рассмотрены и не одобрены Университетом Карнеги-Меллона или его Институтом разработки программного обеспечения.