Функции вызова с правильным количеством и типом аргументов
Функции вызова с правильным количеством и типом аргументов. [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. |
| Пройти либо O_APPEND|O_WRONLY или O_APPEND|O_RDWR в качестве режима доступа. |
Вы передаете флаги состояния O_APPEND и O_TRUNC вместе с open функция. |
| В зависимости от того, что вы намерены сделать, передайте один из двух режимов. |
Вы передаете флаг состояния 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. | Поведение функции не определено. Большинство реализаций | Проверьте возвращаемое значение Если возвращаемое значение равно -1, проверьте значение |
| Аргумент дескриптора файла представляет собой закрытый дескриптор файла. | Поведение функции не определено. | Закройте дескриптор файла только после завершения его использования. Либо повторно откройте дескриптор файла, прежде чем использовать его в качестве аргумента функции. | |
Функции создания имен каталогов, такие как mkdtemp и mkstemps | Последние шесть символов шаблона строки не являются XXXXXX. | Функция заменяет последние шесть символов строкой, делающей имя файла уникальным. Если последние шесть символов не являются XXXXXX, функция не может создать достаточно уникальное имя каталога. | Проверка, являются ли последние шесть символов строки XXXXXX перед использованием строки в качестве аргумента функции. |
Функции, связанные с переменными среды, такими как getenv и setenv | Строковый аргумент: "". | Поведение определяется реализацией. | Проверка строкового аргумента для "" перед использованием в качестве getenv или setenv аргумент. |
Строковый аргумент заканчивается знаком равенства, =. Например, "C=" вместо "C". | Поведение определяется реализацией. | Не завершайте строковый аргумент =. | |
Функции обработки строк, такие как 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);
}
Неподдерживаемые сложные аргументы возникают при вызове этих функций с помощью 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 поднимет этот дефект.
При выводе прототипа функции из вызова такой функции Полиспейс делает следующие предположения:
Число аргументов выведенного прототипа равно входному аргументу вызова функции.
Типы аргументов выводимого прототипа устанавливаются путем неявного продвижения типов аргументов вызова функции. Например, как подписанные, так и неподписанные char или short аргументы типа повышаются до int. Так же float аргументы типа повышаются до double.
Несоответствие типов аргументов определения функции и прототипа функции может зависеть от среды. Polyspace считает два типа совместимыми, если они имеют одинаковый размер и соответствие в используемой среде. Например, если указано -target как i386, Полиспейс считает long и int как совместимые типы.
Средство проверки не помечает эту проблему в анализе Polyspace по умолчанию в качестве кода. См. раздел Шашки, деактивированные в Polyspace как анализ кода по умолчанию (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. По иным вопросам, например если надо исправить заблокированное для перевода слово, обратитесь к редакторам через форму технической поддержки.