CERT C: Rule 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 Университет Карнеги Меллон, с специального разрешения от его Института программной инженерии.

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

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