Функции вызова с правильным номером и типом аргументов
Функции вызова с правильным номером и типом аргументов.[1]
Эта проверка проверяет на наличие следующих проблем:
Неправильный режим доступа к файлам или состояние.
Ненадежное приведение указателя на функцию.
Стандартный вызов функции с неправильными аргументами.
Неподдерживаемые комплексные аргументы
Несоответствие объявления функции
Плохой режим доступа к файлам или состояние происходит, когда вы используете функции в 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
и так далее.
Дефект может возникнуть в следующих ситуациях.
Ситуация | Риск | Зафиксировать |
---|---|---|
Вы передаете пустой или недопустимый режим доступа к Согласно ANSI® Стандарт C, допустимые режимы доступа для
|
Некоторые реализации допускают расширение режима доступа, такого как:
Однако строка режима доступа должна начинаться с одной из допустимых последовательностей. | Передайте допустимый режим доступа к fopen . |
Вы передаете флаг состояния O_APPEND на open функция, не объединяя ее ни с одним из O_WRONLY или O_RDWR . |
The | Пройдите или O_APPEND|O_WRONLY или O_APPEND|O_RDWR как режим доступа. |
Вы передаете флаги состояния O_APPEND и O_TRUNC вместе с open функция. |
The | В зависимости от того, что вы намерены сделать, передайте один из двух режимов. |
Вы передаете флаг состояния O_ASYNC на open функция. | В некоторых реализациях режим O_ASYNC не включает операции ввода-вывода, управляемые сигналом. | Используйте fcntl(pathname, F_SETFL, O_ASYNC); вместо этого. |
Исправление зависит от первопричины дефекта. Часто детали результата показывают последовательность событий, которые привели к дефекту. Вы можете реализовать исправление на любом событии в последовательности. Если сведения о результате не отображают историю событий, можно отследить их с помощью опций правого щелчка в исходном коде и просмотреть предыдущие связанные события. Смотрите также Результаты интерпретации Bug Finder в интерфейсе пользователя Polyspace Desktop.
См. примеры исправлений ниже.
Если вы не хотите устранять проблему, добавьте комментарии к своему результату или коду, чтобы избежать другой проверки. Смотрите Адрес Результаты Polyspace через исправления ошибок или обоснования.
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.
Если вы приведете указатель на функцию к другому указателю на функцию с другим аргументом или возвращаемым типом, а затем используете последний указатель на функцию для вызова функции, поведение не определено.
Избегайте приведения между двумя указателями на функцию с несовпадением аргументов или возвращаемых типов.
См. примеры исправлений ниже.
Если вы не хотите устранять проблему, добавьте комментарии к своему результату или коду, чтобы избежать другой проверки. Смотрите Адрес Результаты Polyspace через исправления ошибок или обоснования.
#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 -terminated string. | Поведение функции не определено. | Передайте NULL -terminated string to string mandipulation functions. |
Функции обработки файлов в stdio.h такие как fputc и fread | The FILE* аргумент указателя может иметь значение NULL . | Поведение функции не определено. | Протестируйте FILE* указатель на NULL перед использованием в качестве аргумента функции. |
Функции обработки файлов в unistd.h такие как lseek и read | Аргумент дескриптора файла может быть -1. | Поведение функции не определено. Большинство реализаций | Проверьте возвращаемое значение Если возврат значение -1, проверьте значение |
Аргумент дескриптора файла представляет дескриптор закрытого файла. | Поведение функции не определено. | Закройте дескриптор файла только после того, как вы полностью закончите его использование. Кроме того, повторно откройте дескриптор файла перед использованием его в качестве аргумента функции. | |
Функции генерации имен директорий, такие как mkdtemp и mkstemps | Последние шесть символов шаблона строки не XXXXXX . | Функция заменяет последние шесть символов строкой, которая делает имя файла уникальным. Если последние шесть символов не XXXXXX функция не может сгенерировать достаточно уникальное имя директории. | Проверяйте, XXXXXX ли последние шесть символов строки перед использованием строки в качестве аргумента функции. |
Функции, связанные с переменными окружения, такими как getenv и setenv | Строковый аргумент "" . | Поведение определяется реализацией. | Протестируйте строковый аргумент для "" прежде чем использовать его как getenv или setenv аргумент. |
Строковый аргумент заканчивается знаком равенства, = . Для образца, "C=" вместо "C" . | Поведение определяется реализацией. | Не завершайте строковый аргумент = . | |
Функции обработки строк, такие как strtok и strstr |
| Некоторые реализации не обрабатывают эти краевые случаи. | Проверьте строку на "" перед использованием в качестве аргумента функции. |
Исправление зависит от первопричины дефекта. Часто детали результата показывают последовательность событий, которые привели к дефекту. Вы можете реализовать исправление на любом событии в последовательности. Если сведения о результате не отображают историю событий, можно отследить их с помощью опций правого щелчка в исходном коде и просмотреть предыдущие связанные события. Смотрите также Результаты интерпретации Bug Finder в интерфейсе пользователя Polyspace Desktop.
См. примеры исправлений ниже.
Если вы не хотите устранять проблему, добавьте комментарии к своему результату или коду, чтобы избежать другой проверки. Смотрите Адрес Результаты Polyspace через исправления ошибок или обоснования.
NULL
Указатель прошел как strnlen
Аргумент#include <string.h>
#include <stdlib.h>
enum {
SIZE10 = 10,
SIZE20 = 20
};
int func() {
char* s = NULL;
return strnlen(s, SIZE20);
}
В этом примере a NULL
указатель передается следующим strnlen
аргумент вместо NULL
-terminated string.
Перед выполнением анализа кода укажите компилятор 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); }
Неподдерживаемые комплексные аргументы возникают, когда эти функции вызываются со complex
аргумент:
atan2
erf
fdim
fmin
ilogb
llround
logb
nextafter
rint
tgamma
cbrt
erfc
floor
fmod
ldexp
log10
lrint
nexttoward
round
trunc
ceil
exp2
fma
frexp
lgamma
log1p
round
remainder
scalbn
copysign
expm1
fmax
hypot
llrint
log2
nearbyint
remquo
scalbln
Вызов любой из предыдущих функций с complex
аргумент является неопределенным поведением в стандарте C++, что может привести к неожиданным результатам. Потому что некоторые математические функции поддерживают complex
аргументы в то время как функции в предыдущем списке нет, неожиданные результаты могут оказаться трудными для отладки. Выполнение некоторых из этих математических операций на complex
возможно, номер не является математически звуком, что указывает на проблему в основной логике вашего кода.
Избегайте вызова предыдущих функций с помощью complex
входной параметр. Чтобы выполнить предыдущие математические операции над комплексным числом, задайте альтернативные функции, которые поддерживают complex
аргументы.
log2
и trunc
Функции со сложными аргументами#include <complex.h> #include <tgmath.h> typedef double complex cDouble; cDouble Noncompliant (void) { cDouble Z = 2.0 + 4.0 * I; cDouble result = log2 (Z); //Noncompliant return trunc(result);//Noncompliant }
В этом примере функция Noncompliant
вычисляет базовый два логарифма комплексного числа, обрезает результат и возвращает его. Функции log2
и trunc
не поддерживает сложный аргумент. Polyspace® помечает эти операции.
Одним из возможных коррекций является определение альтернативных функций, которые поддержка комплексные числа. Для образца, в то время log2
не поддерживает complex
числа, функции log
делает. Задайте complexLog2 функции
который использует log
для вычисления основы два логарифма комплексного числа. Точно так же trunc
не поддерживает complex
числа и математическое правило для усечения комплексного числа не четко задано. Задайте complexTrunc функции
что обрезает комплексное число путем усечения его вещественных и мнимых частей отдельно.
#include <complex.h> #include <tgmath.h> typedef double complex cDouble; cDouble complexLog2(cDouble z) { return log (z) / log (2); // Compliant } cDouble complexTrunc(cDouble z){ return trunc(creal(z)) + I*trunc(cimag(z)); //Compliant } cDouble Compliant (void) { cDouble Z = 2.0 + 4.0 * I; cDouble result = complexLog2 (Z); //Compliant return complexTrunc(result);//Compliant }
Несоответствие объявления функции происходит, когда прототип функции не соответствует ее определению. Если в функции отсутствует прототип в файле, где он вызывается, Polyspace выводит его прототип на основе подписи вызова. Если выведенный прототип не соответствует определению функции, Polyspace поднимает этот дефект. Прототип вариадной функции не может быть выведен из ее вызова функции. Если вы вызываете вариадную функцию, не задавая ее прототип в том же файле, Polyspace поднимает этот дефект.
При выведении прототипа функции из вызова такой функции Polyspace делает следующие предположения:
Количество аргументов выведенного прототипа равно входному параметру вызова функции.
Типы аргументов выведенного прототипа устанавливаются неявным продвижением типов аргументов вызова функции. Например, как подписанные, так и беззнаковые char
или short
аргументы типа повышаются до int
. Точно так же float
аргументы типа повышаются до double
.
Несоответствие типов аргументов определения функции и прототипа функции может зависеть от вашего окружения. Polyspace рассматривает два типа как совместимые, если они имеют одинаковый размер и сигнальность в окружении, которую вы используете. Например, если вы задаете -target
как i386, Polyspace рассматривает long
и int
как совместимые типы.
Чекер не помечает эту проблему в Polyspace по умолчанию во время анализа You Code. Смотрите Checkers Deactivated in Polyspace как You Code Default Analysis (Polyspace Bug Finder Access).
Согласно стандарту C, несоответствие объявления функции может привести к неопределенному поведению, хотя такой код может успешно компилироваться, выдавая только предупреждения во время компиляции. Поскольку код с этой проблемой может успешно скомпилироваться, несоответствия объявления функции могут привести к неожиданным результатам, которые трудно диагностировать.
Прежде чем вы вызовете функцию, предоставьте ее полный прототип, даже если вы задаете функцию позже в том же файле.
Избегайте любого несоответствия между числовыми аргументами в объявлении прототипа функции и определении функции.
Избегайте любого несоответствия между типами аргументов объявления прототипа функции и определением функции.
Когда предоставляются полные прототипы вызываемых функций, компилятор пытается разрешить любые несоответствия объявления функции через неявное приведение. Если компилятору не удается устранить несоответствие, компиляция прекращает работать, что препятствует непредвиденному поведению. Чтобы исправить такие ошибки компиляции, вызывайте функции с помощью типов аргументов и чисел, которые совпадают с определением функции.
// file1.c void foo(int iVar){ //... } void bar(float fVar1, float fVar2){ //... } void bar2(float fVar1){ //... } void fubar(const char* str,...){ //... } void foo2(char cVar){ //... } void call_variadic(){ fubar("String"); } |
//file2.c void bar2(float); void foo2(int); void call_funcs(){ int iTemp; float fTemp; foo();//Noncompliant bar(fTemp,fTemp);//Noncompliant fubar("String"); //Noncompliant bar2(iTemp);//Compliant foo2(iTemp); //Noncompliant } |
В этом примере функции foo
, foo2
, bar
, bar2
, и fubar
определяются в файле file1.c
. Затем эти функции вызываются в файле file2.c
.
Функция foo
определяется в file1.c
с одним int
входные и входные вызовы file2.c
без какого-либо входа. Потому что file2.c
не имеет прототипа для foo
Polyspace выводит прототип на основе вызова foo()
, который не принимает входов. Этот выведенный прототип не соответствует объявлению функции в file1.c
. Polyspace помечает вызов.
Функция bar
определяется в file1.c
с двумя float
входы и вызовы в file2.c
с двумя float
входы. Потому что file2.c
не имеет прототипа для bar
Polyspace выводит прототип на основе вызова bar(fTemp,fTemp)
. Путем продвижения типов аргументов вызова функции, сигнатура этого выведенного прототипа bar(double, double)
, который не соответствует объявлению функции в file1.c
. Polyspace помечает вызов.
Функция bar2
определяется в file1.c
с одним float
вход. Полный прототип для bar2
, который соответствует определению, приведено в file2.c
. Поскольку полный прототип присутствует в этом файле, когда bar2
вызывается с неправильным входом, компилятор неявно преобразует int
входной iTemp
в float
. Поскольку вызов функции совпадает с объявлением после неявного преобразования, облегченного прототипом, Polyspace не помечает вызов.
Функция foo2
определяется в file1.c
с char
вход. Его прототип в file2.c
определяется как int
вход. Поскольку определение и прототип не совпадают, Polyspace помечает вызов на foo2
.
Вариадная функция fubar
определяется в file1.c
. Вызов к нему в call_variadic
является совместимым, поскольку вызов поступает после определения. Функция fubar
не имеет прототипа в file2.c
. Поскольку функция принимает переменное количество входов, ее прототип не может быть выведен. Вызов fubar
в file2.c
не имеет прототипа, и Polyspace помечает вызов.
Исправление этого дефекта состоит в том, чтобы объявить полные прототипы для вызываемых функций во всех модулях компиляции. Это - лучшая практика объединить объявления прототипа функции в заголовочном файле, а затем включить его в файлы, где вызываются функции. В этом случае решите отмеченные проблемы, включив такой заголовочный файл prototype.h
в file2.c
. После объявления правильного прототипа вызов foo()
в file2.c
приводит к отказу компиляции, поскольку компилятору не удается устранить несоответствие между вызовом и объявленным прототипом. Функции foo
с int
для устранения отказа компиляции.
// file1.c void foo(int iVar){ //... } void bar(float fVar1, float fVar2){ //... } void bar2(float fVar1){ //... } void fubar(const char* str,...){ //... } void foo2(char cVar){ //... } void call_variadic(){ fubar("String"); } |
//prototypes.h void foo(int iVar); void bar(float fVar1, float fVar2); void fubar(const char* str,...); void bar2(float); void foo2(char); void call_variadic(void); void call_funcs(void); |
//file2.c #include"prototype.h" void call_funcs(){ int iTemp; float fTemp; //foo(); This call results in compile failure foo(iTemp);//Compliant bar(fTemp,fTemp);//Compliant fubar("String"); //Compliant bar2(iTemp);//Compliant foo2('a'); //Compliant } |
Группа: Правило 03. Выражения (EXP) |
[1] Это программное обеспечение было создано MathWorks, включающее фрагменты: «Сайт SEI CERT-C», © 2017 Университет Карнеги Меллон, Веб-сайт SEI CERT-C + + © 2017 Университет Карнеги Меллон, "Стандарт кодирования SEI CERT C - Правила разработки безопасных, Надежные и безопасные системы - 2016 Edition ", © 2016 Университет Карнеги Меллон, и "Стандарт кодирования SEI CERT C++ - Правила разработки безопасных, Надежные и безопасные системы в C++ - 2016 Edition "© 2016 Университет Карнеги Меллон, с специального разрешения от его Института программной инженерии.
ЛЮБОЙ МАТЕРИАЛ УНИВЕРСИТЕТА КАРНЕГИ МЕЛЛОН И/ИЛИ ЕГО ИНЖЕНЕРНОГО ИНСТИТУТА ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ, СОДЕРЖАЩИЙСЯ В НАСТОЯЩЕМ ДОКУМЕНТЕ, ПОСТАВЛЯЕТСЯ НА БАЗИСЕ «КАК ЕСТЬ». УНИВЕРСИТЕТ КАРНЕГИ МЕЛЛОН НЕ ДАЕТ НИКАКИХ ГАРАНТИЙ, ВЫРАЖЕННЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ, В ОТНОШЕНИИ ЛЮБОГО ВОПРОСА, ВКЛЮЧАЯ, НО НЕ ОГРАНИЧИВАЯСЬ, ГАРАНТИЮ ПРИГОДНОСТИ ДЛЯ ЦЕЛЕЙ ИЛИ КОММЕРЧЕСКОЙ ВЫГОДЫ, ИСКЛЮЧИТЕЛЬНОСТИ, ИЛИ УНИВЕРСИТЕТ КАРНЕГИ МЕЛЛОН НЕ ДАЕТ НИКАКИХ ГАРАНТИЙ В ОТНОШЕНИИ СВОБОДЫ ОТ ПАТЕНТА, ТОВАРНОГО ЗНАКА ИЛИ НАРУШЕНИЯ АВТОРСКИХ ПРАВ.
Это программное обеспечение и связанная с ним документация не были рассмотрены и не одобрены Университетом Карнеги-Меллон или его Институтом программной инженерии.
1. Если смысл перевода понятен, то лучше оставьте как есть и не придирайтесь к словам, синонимам и тому подобному. О вкусах не спорим.
2. Не дополняйте перевод комментариями “от себя”. В исправлении не должно появляться дополнительных смыслов и комментариев, отсутствующих в оригинале. Такие правки не получится интегрировать в алгоритме автоматического перевода.
3. Сохраняйте структуру оригинального текста - например, не разбивайте одно предложение на два.
4. Не имеет смысла однотипное исправление перевода какого-то термина во всех предложениях. Исправляйте только в одном месте. Когда Вашу правку одобрят, это исправление будет алгоритмически распространено и на другие части документации.
5. По иным вопросам, например если надо исправить заблокированное для перевода слово, обратитесь к редакторам через форму технической поддержки.