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, wbA, B

  • 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 не включает управляемые сигналом операции I/O.Используйте fcntl(pathname, F_SETFL, O_ASYNC); вместо этого.

Исправление

Фиксация зависит от первопричины дефекта. Часто детали результата показывают последовательность событий, которые привели к дефекту. Можно реализовать закрепление на любом событии в последовательности. Если детали результата не показывают историю события, можно проследить использование, щелкните правой кнопкой по опциям по исходному коду и смотрите предыдущие связанные события. См. также Интерпретируют Результаты Bug Finder в Пользовательском интерфейсе Рабочего стола 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);
    }
}
Проблема

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

Риск

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

Исправление

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

Смотрите примеры мер ниже.

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

Пример - ненадежный бросок ошибки указателя функции
int f(char c) {
	return c;
}

int g(int i) {
	return i;
}

typedef int (*fptr_t)(char);
typedef int (*gptr_t)(int);

void call() {
	gptr_t ptr = (gptr_t) f;//Noncompliant
	int i = ptr(511); // Undefined behavior
}

В этом примере, указателе на функциональный f брошен к gptr_t, который является типом функционального g. Когда указатель функции используется, чтобы вызвать f при помощи целых чисел поведение кода не определено. Polyspace® отмечает ненадежный бросок указателя функции.

Коррекция — избегает броска указателя функции

Чтобы избежать неопределенного поведения, осуществите рефакторинг свой код так, чтобы функциональный f не брошен в различный тип аргумента. Например:

 int f(int c) { //Fix: declare f with int argument
	return c;
}

int g(int i) {
	return i;
}

typedef int (*fptr_t)(char);
typedef int (*gptr_t)(int);

void call() {
	gptr_t ptr = (gptr_t) f;//Compliant
	int i = ptr(511); 
}
Проблема

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

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

Функциональный типСитуацияРискИсправление
Обработка строк функционирует, такие как strlen и strcpyАргументы указателя не указывают на NULL- отключенная строка.Поведение функции не определено.Передайте NULL- отключенная строка к функциям обработки строк.
Обработка файла функционирует в stdio.h такой как fputc и freadFILE* аргумент указателя может иметь значение 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: Аргументом строки поиска является "".

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

Исправление

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

Смотрите примеры мер ниже.

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

Пример - 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);
}
Проблема

Примечание

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

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

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

Средство проверки не отмечает эту проблему в Polyspace по умолчанию как Вы Анализ кода. Смотрите Средства проверки, Деактивированные в Polyspace, когда Вы Кодируете Анализ По умолчанию.

Риск

Несоответствие объявления функции может привести к неопределенному поведению. Когда объявления функции заданы с 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панель, и fubar заданы в файле file1.c. Их прототипы объявляются в prototype.h. Эти функции затем вызваны в файле file2.c.

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

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

  • Вызов variadic функционирует 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
	
}
Проблема

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

extern long foo(int);

long bar(long i) {
    return foo(i); //Noncompliant: calls foo(int) with a long              
}
Внешний функциональный foo вызван long когда int ожидается. В средах, где размер int меньше, чем размер long, этот вызов функции несовместим с прототипом, приводящим к дефекту.

На C++, эта дефектная причина силы ошибка компиляции.

Риск

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

Исправление

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

Пример — Вызывает Внешние Функции с аргументом Incompatible
extern long foo1(int);
extern long foo2(long);
void bar(){
	int varI;
	long varL;
	foo1(varL);//Noncompliant
	foo2(varI);//Compliant
}

В этом примере, внешнем функциональном foo1 вызван long аргумент, в то время как прототип задает параметр как int. В x86 архитектура, размер long больше, чем размер int. Вызов foo1(varL) может привести к неопределенному поведению. Polyspace отмечает вызов. Вызов foo2(varI) использует int аргумент, в то время как параметр задан как long. Этот тип несоответствия совместим с этим правилом потому что размер int не больше, чем размер long.

Чтобы запустить этот пример в Polyspace, используйте эти опции:

  • -target x86_64

Смотрите Target processor type (-target).

Коррекция — переменные броска явным образом, чтобы совпадать с аргументом к параметру

Чтобы устранить эту проблему, бросьте аргумент foo1 явным образом так, чтобы тип аргумента и параметр вводят соответствия.

extern long foo1(int);
extern long foo2(long);
void bar(){
	int varI;
	long varL;
	foo1((int)varL);//Compliant
	foo2(varI);//Compliant
}

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

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

[1] Это программное обеспечение было создано MathWorks, включающим фрагменты: “Веб-сайт SEI CERT-C”, © 2017 Carnegie Mellon University, веб-сайт SEI CERT-C © 2017 Carnegie Mellon University”, CERT SEI C Кодирование Стандарта – Правил для Разработки безопасных, Надежных и Защищенных систем – 2 016 Выпусков”, © 2016 Carnegie Mellon University, and “CERT SEI Стандарт Кодирования C++ – Правил для Разработки безопасных, Надежных и Защищенных систем на C++ – 2 016 Выпусков” © 2016 Carnegie Mellon University, со специальным разрешением от его Института программной инженерии.

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

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