exponenta event banner

CERT C++: EXP37-C

Функции вызова с правильным количеством и типом аргументов

Описание

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

Функции вызова с правильным количеством и типом аргументов. [1 ]

Внедрение Polyspace

Эта проверка проверяет наличие следующих проблем:

  • Неправильный режим доступа к файлам или состояние.

  • Ненадежная приведение указателя функции.

  • Вызов стандартной функции с неверными аргументами.

  • Несоответствие объявления функции

Примеры

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

Проблема

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

  • Режимы доступа включают O_RDONLY, O_WRONLY, и O_RDWR

  • Флаги создания файлов включают O_CREAT, O_EXCL, O_NOCTTY, и O_TRUNC.

  • Флаги состояния файлов включают O_APPEND, O_ASYNC, O_CLOEXEC, O_DIRECT, O_DIRECTORY, O_LARGEFILE, O_NOATIME, O_NOFOLLOW, O_NONBLOCK, O_NDELAY, O_SHLOCK, O_EXLOCK, O_FSYNC, O_SYNC и так далее.

Дефект может возникнуть в следующих ситуациях.

СитуацияРискЗафиксировать

Вы передаете пустой или недопустимый режим доступа fopen функция.

В соответствии со стандартом ANSI ® C допустимые режимы доступа дляfopen являются:

  • r,r+

  • w,w+

  • a,a+

  • rb, wb, ab

  • r+b, w+b, a+b

  • rb+, wb+, ab+

fopen имеет неопределенное поведение для недопустимых режимов доступа.

Некоторые реализации допускают расширение режима доступа, например:

  • GNU ® :rb+cmxe,ccs=utf

  • Visual C++ ® :a+t, где t задает текстовый режим.

Однако строка режима доступа должна начинаться с одной из допустимых последовательностей.

Передать допустимый режим доступа в fopen.
Вы передаете флаг состояния O_APPEND в open функция без объединения с O_WRONLY или O_RDWR.

O_APPEND указывает на необходимость добавления нового содержимого в конце файла. Однако без O_WRONLY или O_RDWR, запись в файл невозможна.

open функция не возвращает -1 для этой логической ошибки.

Пройти либо O_APPEND|O_WRONLY или O_APPEND|O_RDWR в качестве режима доступа.
Вы передаете флаги состояния O_APPEND и O_TRUNC вместе с open функция.

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

open функция не возвращает -1 для этой логической ошибки.

В зависимости от того, что вы намерены сделать, передайте один из двух режимов.
Вы передаете флаг состояния O_ASYNC в open функция. В определенных реализациях режим O_ASYNC не включает операции ввода-вывода, управляемые сигналом.Используйте fcntl(pathname, F_SETFL, O_ASYNC); вместо этого.

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

Исправление зависит от первопричины дефекта. Часто детали результата показывают последовательность событий, которые привели к дефекту. Исправление может быть реализовано для любого события в последовательности. Если сведения о результатах не отображают историю событий, можно выполнить обратную трассировку, щелкнув правой кнопкой мыши параметры в исходном коде и просмотреть предыдущие связанные события. См. также раздел Интерпретация результатов поиска ошибок в интерфейсе пользователя Polyspace Desktop.

См. примеры исправлений ниже.

Если вы не хотите устранять проблему, добавьте комментарии к результату или коду, чтобы избежать другой проверки. См. раздел Результаты анализа пространства адресов с помощью исправлений ошибок или обоснований.

Пример - Недопустимый режим доступа с fopen
#include <stdio.h>

void func(void) {
    FILE *file = fopen("data.txt", "rw");
    if(file!=NULL) {
        fputs("new data",file);
        fclose(file);
    }
}

В этом примере режим доступа rw недопустим. Поскольку r указывает, что вы открываете файл для чтения и w указывает, что вы создаете новый файл для записи, два режима доступа несовместимы.

Исправление - Использовать либо r или w как режим доступа

Одной из возможных корректировок является использование режима доступа, соответствующего намерениям.

#include <stdio.h>

void func(void) {
    FILE *file = fopen("data.txt", "w");
    if(file!=NULL) {
        fputs("new data",file);
        fclose(file);
    }
}
Проблема

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

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

Риск

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

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

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

См. примеры исправлений ниже.

Если вы не хотите устранять проблему, добавьте комментарии к результату или коду, чтобы избежать другой проверки. См. раздел Результаты анализа пространства адресов с помощью исправлений ошибок или обоснований.

Пример - Ненадежное приведение ошибки указателя функции
#include <stdio.h>
#include <math.h>
#include <stdio.h>
#define PI 3.142
 
double Calculate_Sum(int (*fptr)(double))
{
    double  sum = 0.0;
    double  y;
	  
    for (int i = 0;  i <= 100;  i++)
    {
        y = (*fptr)(i*PI/100);
        sum += y;
    }
    return sum / 100;
}
 
int main(void)
{
    double  (*fp)(double);      
    double  sum;
 
    fp = sin;
    sum = Calculate_Sum(fp); 
    /* Defect: fp implicitly cast to int(*) (double) */

    printf("sum(sin): %f\n", sum);
    return 0;
}

Указатель функции fp объявлен как double (*)(double). Однако, передавая его для функционирования Calculate_Sum, fp неявно приводится к int (*)(double).

Коррекция - избежать приведения указателя функции

Одной из возможных корректировок является проверка того, что указатель функции в определении Calculate_Sum имеет тот же аргумент и возвращаемый тип, что и fp. Этот шаг гарантирует, что fp не является неявно приведенным к другому аргументу или возвращаемому типу.

#include <stdio.h>
#include <math.h>
#include <stdio.h>
# define PI 3.142
 
/*Fix: fptr has same argument and return type everywhere*/
double Calculate_Sum(double (*fptr)(double)) 
{
    double  sum = 0.0;
    double y;
	    
    for (int i = 0;  i <= 100;  i++)
    {
        y = (*fptr)(i*PI/100);
        sum += y;
    }
    return sum / 100;
}
 
int main(void)
{
    double  (*fp)(double);      
    double  sum;
 
    
    fp = sin;
    sum = Calculate_Sum(fp);
    printf("sum(sin): %f\n", sum);
 
    return 0;
}
Проблема

Вызов стандартной функции с неверными аргументами происходит, когда аргументы определенных стандартных функций не соответствуют требованиям для их использования в функциях.

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

Тип функцииСитуацияРискЗафиксировать
Функции управления строками, такие как strlen и strcpyАргументы указателя не указывают на NULL- завершенная строка.Поведение функции не определено.Пройти а NULL- завершенная строка для функций манипуляции строками.
Функции обработки файлов в stdio.h такие как fputc и fread FILE* аргумент указателя может иметь значение NULL.Поведение функции не определено.Протестируйте FILE* указатель для NULL перед использованием в качестве аргумента функции.
Функции обработки файлов в unistd.h такие как lseek и read Аргумент дескриптора файла может иметь значение -1.

Поведение функции не определено.

Большинство реализаций open функция возвращает значение дескриптора файла, равное -1. Кроме того, они установили errno указывает, что при открытии файла произошла ошибка.

Проверьте возвращаемое значение open функция для -1, прежде чем использовать ее в качестве аргумента для read или lseek.

Если возвращаемое значение равно -1, проверьте значение errno чтобы увидеть, какая ошибка произошла.

Аргумент дескриптора файла представляет собой закрытый дескриптор файла.Поведение функции не определено.Закройте дескриптор файла только после завершения его использования. Либо повторно откройте дескриптор файла, прежде чем использовать его в качестве аргумента функции.
Функции создания имен каталогов, такие как mkdtemp и mkstempsПоследние шесть символов шаблона строки не являются XXXXXX.Функция заменяет последние шесть символов строкой, делающей имя файла уникальным. Если последние шесть символов не являются XXXXXX, функция не может создать достаточно уникальное имя каталога.Проверка, являются ли последние шесть символов строки XXXXXX перед использованием строки в качестве аргумента функции.
Функции, связанные с переменными среды, такими как getenv и setenvСтроковый аргумент: "".Поведение определяется реализацией.Проверка строкового аргумента для "" перед использованием в качестве getenv или setenv аргумент.
Строковый аргумент заканчивается знаком равенства, =. Например, "C=" вместо "C".Поведение определяется реализацией.Не завершайте строковый аргумент =.
Функции обработки строк, такие как strtok и strstr

  • strtok: Аргумент разделителя: "".

  • strstr: Аргумент строки поиска: "".

В некоторых реализациях эти краевые случаи не обрабатываются.Проверить строку для "" перед использованием в качестве аргумента функции.

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

Исправление зависит от первопричины дефекта. Часто детали результата показывают последовательность событий, которые привели к дефекту. Исправление может быть реализовано для любого события в последовательности. Если сведения о результатах не отображают историю событий, можно выполнить обратную трассировку, щелкнув правой кнопкой мыши параметры в исходном коде и просмотреть предыдущие связанные события. См. также раздел Интерпретация результатов поиска ошибок в интерфейсе пользователя Polyspace Desktop.

См. примеры исправлений ниже.

Если вы не хотите устранять проблему, добавьте комментарии к результату или коду, чтобы избежать другой проверки. См. раздел Результаты анализа пространства адресов с помощью исправлений ошибок или обоснований.

Пример - NULL Указатель передан как strnlen Аргумент
#include <string.h>
#include <stdlib.h>

enum {
    SIZE10 = 10,
    SIZE20 = 20
};

int func() {
    char* s = NULL;
    return strnlen(s, SIZE20);
}

В этом примере NULL указатель передается как strnlen аргумент вместо NULL- завершенная строка.

Перед выполнением анализа кода укажите компилятор GNU. Посмотрите Compiler (-compiler).

Коррекция - проход NULL- завершенная строка

Пройти а NULL- завершенная строка в качестве первого аргумента strnlen.

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

enum {
    SIZE10 = 10,
    SIZE20 = 20
};

int func() {
    char* s = "";
    return strnlen(s, SIZE20);
}
Проблема

Примечание

В коде C++ эта проверка применяется к функциям, указанным как extern "C".

Несоответствие объявления функции возникает, когда прототип extern "C" функция не соответствует ее определению. Несоответствие типов аргументов определения функции и прототипа функции может зависеть от среды. Polyspace ® считает два типа совместимыми, если они имеют одинаковый размер и соответствие в используемой среде. Например, если указано-target как i386, Полиспейс считает long и int как совместимые типы.

В C++, если функция не указана как extern "C" и его прототип не соответствует какому-либо определению функции, компилятор рассматривает прототип как прототип неопределенной перегрузки функции. Polyspace не помечает вызовы таких неопределенных функций.

Средство проверки не помечает эту проблему в анализе Polyspace по умолчанию в качестве кода. См. раздел Шашки, деактивированные в Polyspace как анализ кода по умолчанию (Polyspace Bug Finder Access).

Риск

Несоответствие объявления функции может привести к неопределенному поведению. Когда объявления функций указаны с помощью extern "C", несоответствия между определением и объявлением функции могут вызывать только предупреждения во время компиляции, что приводит к компиляции кода, но ведет себя неожиданным образом.

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

  • Перед вызовом функции укажите ее полный прототип, даже если функция будет определена позже в том же файле.

  • Избегайте любого несоответствия между аргументами числа в объявлении прототипа функции и определением функции.

  • Избегайте любого несоответствия между типами аргументов описания прототипа функции и определения функции.

Пример - Вызовы несоответствующей функции
// file1.c
extern "C" void foo(int iVar){
	//...
}
extern "C" void bar(int iVar){
	//...
}
extern "C" void fubar(int A, ...){
	//...
}


//prototype.h
extern "C" void foo(void);
extern "C" void fubar(int A, ...);
extern "C" void bar(long iVar);
//file2.c
//file2.c
#include"prototype.h"
void call_funcs(){
	int iTemp;
	float fTemp;
	long lTemp;
	foo(); //Noncompliant
	bar(lTemp);//Noncompliant in x86_64
	fubar(iTemp,fTemp);//Compliant
	
}

В этом примере функции foo, bar, и fubar определены в файле file1.c. Их прототипы заявлены в prototype.h. Эти функции затем вызываются в файле. file2.c.

  • Функция foo определяется с помощью int аргумент, но его прототип объявляется без какого-либо аргумента. Из-за этого несоответствия Polyspace помечает вызов функции.

  • Функция bar определяется с помощью int аргумент, но его прототип объявляется с помощью long аргумент. Эти два типа несовместимы в x86_64 окружающей среды. При указании -target как x86_64, Polyspace помечает вызов функции.

  • Вызов переменной функции fubar соответствует, поскольку его подпись вызова, прототип и определение совпадают.

Коррекция - соответствующие вызовы функции

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

// file1.c
extern "C" void foo(int iVar){
	//...
}
extern "C" void bar(int iVar){
	//...
}
extern "C" void fubar(int A, ...){
	//...
}


//prototype.h
extern "C" void foo(int);
extern "C" void fubar(int A, ...);
extern "C" void bar(int iVar);
//file2.c
//file2.c
#include"prototype.h"
void call_funcs(){
	int iTemp;
	float fTemp;
	long lTemp;
	foo(iTemp); //Compliant
	bar(iTemp);//Compliant in x86_64
	fubar(iTemp,fTemp);//Compliant
	
}

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

Группа: 02. Выражения (EXP)
Представлен в R2019a

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

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

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