CWE Rule 686
Description
The software calls a function, procedure, or routine, but the caller specifies an argument that is the wrong data type, which may lead to resultant weaknesses.
Polyspace Implementation
The rule checker checks for these issues:
Bad file access mode or status
Incorrect data type passed to va_arg
Standard function call with incorrect arguments
Use of automatic variable as putenv-family function argument
Writing to const qualified object
Examples
This issue occurs when you use functions in the fopen or open group with invalid or incompatible file access modes, file creation flags, or file status flags as arguments. For instance, for the open function, examples of valid:
Access modes include
O_RDONLY,O_WRONLY, andO_RDWRFile creation flags include
O_CREAT,O_EXCL,O_NOCTTY, andO_TRUNC.File status flags include
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_SYNCand so on.
The defect can occur in the following situations.
| Situation | Risk | Fix |
|---|---|---|
You pass an empty or invalid access mode to the According to the ANSI® C standard, the valid access modes for
|
Some implementations allow extension of the access mode such as:
However, your access mode string must begin with one of the valid sequences. | Pass a valid access mode to fopen. |
You pass the status flag O_APPEND to the open function without combining it with either O_WRONLY or O_RDWR. |
The | Pass either O_APPEND|O_WRONLY or O_APPEND|O_RDWR as access mode. |
You pass the status flags O_APPEND and O_TRUNC together to the open function. |
The | Depending on what you intend to do, pass one of the two modes. |
You pass the status flag O_ASYNC to the open function. | On certain implementations, the mode O_ASYNC does not enable signal-driven I/O operations. | Use the fcntl(pathname, F_SETFL, O_ASYNC); instead. |
The fix depends on the function and the flags used. See fixes in the table above and code examples with fixes below.
If you do not want to fix the issue, add comments to your result or code to avoid another review. See:
Address Polyspace Results Through Bug Fixes or Justifications if you review results in the Polyspace user interface.
Address Results in Polyspace Access Through Bug Fixes or Justifications (Polyspace Access) if you review results in a web browser.
Annotate Code and Hide Known or Acceptable Results if you review results in an IDE.
#include <stdio.h>
void func(void) {
FILE *file = fopen("data.txt", "rw"); //Noncompliant
if(file!=NULL) {
fputs("new data",file);
fclose(file);
}
}In this example, the access mode rw is invalid. Because r indicates that you open the file for reading and w indicates that you create a new file for writing, the two access modes are incompatible.
r or w as Access ModeOne possible correction is to use the access mode corresponding to what you intend to do.
#include <stdio.h>
void func(void) {
FILE *file = fopen("data.txt", "w");
if(file!=NULL) {
fputs("new data",file);
fclose(file);
}
}This issue occurs when the data type in a va_arg call does not match the data type of the variadic function argument that va_arg reads.
For instance, you pass an unsigned char argument to a variadic function func. Because of default argument promotion, the argument is promoted to int. When you use a va_arg call that reads an unsigned char argument, a type mismatch occurs.
void func (int n, ...) {
...
va_list args;
va_arg(args, unsigned char);
...
}
void main(void) {
unsigned char c;
func(1,c);
}In a variadic function (function with variable number of arguments), you use va_arg to read each argument from the variable argument list (va_list). The va_arg use does not guarantee that there actually exists an argument to read or that the argument data type matches the data type in the va_arg call. You have to make sure that both conditions are true.
Reading an incorrect type with a va_arg call can result in undefined behavior. Because function arguments reside on the stack, you might access an unwanted area of the stack.
Make sure that the data type of the argument passed to the variadic function matches the data type in the va_arg call.
Arguments of a variadic function undergo default argument promotions. The argument data types of a variadic function cannot be determined from a prototype. The arguments of such functions undergo default argument promotions (see Sec. 6.5.2.2 and 7.15.1.1 in the C99 Standard). Integer arguments undergo integer promotion and arguments of type float are promoted to double. For integer arguments, if a data type can be represented by an
int, for instance, char or short, it is promoted to an int. Otherwise, it is promoted to an unsigned int. All other arguments do not undergo promotion.
To avoid undefined and implementation-defined behavior, minimize the use of variadic functions. Use the checkers for MISRA C:2012 Rule 17.1 or MISRA C++:2008 Rule 8-4-1 to detect use of variadic functions.
#include <stdarg.h>
#include <stdio.h>
unsigned char func(size_t count, ...) {
va_list ap;
unsigned char result = 0;
va_start(ap, count);
if (count > 0) {
result = va_arg(ap, unsigned char); //Noncompliant
}
va_end(ap);
return result;
}
void func_caller(void) {
unsigned char c = 0x12;
(void)func(1, c);
}In this example, func takes an unsigned char argument, which undergoes default argument promotion to int. The data type in the va_arg call is still unsigned char, which does not match the int argument type.
int as va_arg ArgumentOne possible correction is to read an int argument with va_arg.
#include <stdarg.h>
#include <stdio.h>
unsigned char func(size_t count, ...) {
va_list ap;
unsigned char result = 0;
va_start(ap, count);
if (count > 0) {
result = va_arg(ap, int);
}
va_end(ap);
return result;
}
void func_caller(void) {
unsigned char c = 0x12;
(void)func(1, c);
}This issue occurs when the arguments to certain standard functions do not meet the requirements for their use in the functions.
For instance, the arguments to these functions can be invalid in the following ways.
| Function Type | Situation | Risk | Fix |
|---|---|---|---|
String manipulation functions such as strlen and strcpy | The pointer arguments do not point to a NULL-terminated string. | The behavior of the function is undefined. | Pass a NULL-terminated string to string manipulation functions. |
File handling functions in stdio.h such as fputc and fread | The FILE* pointer argument can have the value NULL. | The behavior of the function is undefined. | Test the FILE* pointer for NULL before using it as function argument. |
File handling functions in unistd.h such as lseek and read | The file descriptor argument can be -1. | The behavior of the function is undefined. Most implementations of the | Test the return value of the If the return value is -1, check the value of |
| The file descriptor argument represents a closed file descriptor. | The behavior of the function is undefined. | Close the file descriptor only after you have completely finished using it. Alternatively, reopen the file descriptor before using it as function argument. | |
Directory name generation functions such as mkdtemp and mkstemps | The last six characters of the string template are not XXXXXX. | The function replaces the last six characters with a string that makes the file name unique. If the last six characters are not XXXXXX, the function cannot generate a unique enough directory name. | Test if the last six characters of a string are XXXXXX before using the string as function argument. |
Functions related to environment variables such as getenv and setenv | The string argument is "". | The behavior is implementation-defined. | Test the string argument for "" before using it as getenv or setenv argument. |
The string argument terminates with an equal sign, =. For instance, "C=" instead of "C". | The behavior is implementation-defined. | Do not terminate the string argument with =. | |
String handling functions such as strtok and strstr |
| Some implementations do not handle these edge cases. | Test the string for "" before using it as function argument. |
The fix depends on the root cause of the defect. See fixes in the table above and code examples with fixes below.
If you do not want to fix the issue, add comments to your result or code to avoid another review. See:
Address Polyspace Results Through Bug Fixes or Justifications if you review results in the Polyspace user interface.
Address Results in Polyspace Access Through Bug Fixes or Justifications (Polyspace Access) if you review results in a web browser.
Annotate Code and Hide Known or Acceptable Results if you review results in an IDE.
#include <string.h>
#include <stdlib.h>
enum {
SIZE10 = 10,
SIZE20 = 20
};
int func() {
char* s = NULL;
return strnlen(s, SIZE20); //Noncompliant
}
In this example, a NULL pointer is passed as strnlen argument instead of a NULL-terminated string.
Before running analysis on the code, specify a GNU compiler. See Compilation toolchain (Static analysis).
NULL-terminated StringPass a NULL-terminated string as the first argument of strnlen.
#include <string.h>
#include <stdlib.h>
enum {
SIZE10 = 10,
SIZE20 = 20
};
int func() {
char* s = "";
return strnlen(s, SIZE20);
}
This issue occurs when the argument of a putenv-family function is a local variable with automatic duration.
The function putenv(char *string) inserts a pointer to its supplied argument into the environment array, instead of making a copy of the argument. If the argument is an automatic variable, its memory can be overwritten after the function containing the putenv() call returns. A subsequent call to getenv() from another function returns the address of an out-of-scope variable that cannot be dereferenced legally. This
out-of-scope variable can cause environment variables to take on unexpected values, cause the program to stop responding, or allow arbitrary code execution vulnerabilities.
Use setenv()/unsetenv() to set and unset environment variables. Alternatively, use putenv-family function arguments with dynamically allocated memory, or, if your application has no reentrancy requirements, arguments with static duration. For example, a single thread execution with no recursion or interrupts does not require reentrancy. It cannot be called (reentered) during its execution.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE1024 1024
void func(int var)
{
char env[SIZE1024];
int retval = sprintf(env, "TEST=%s", var ? "1" : "0");
if (retval <= 0) {
/* Handle error */
}
/* Environment variable TEST is set using putenv().
The argument passed to putenv is an automatic variable. */
retval = putenv(env); //Noncompliant
if (retval != 0) {
/* Handle error */
}
}
In this example, sprintf() stores the character string TEST=var in env. The value of the environment variable TEST is then set to var by using putenv(). Because env is an automatic variable, the value of TEST can change once func() returns.
static Variable for Argument of putenv()Declare env as a static-duration variable. The memory location of env is not overwritten for the duration of the program, even after func() returns.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE1024 1024
void func(int var)
{
/* static duration variable */
static char env[SIZE1024];
int retval = snprintf(env,"TEST=%s", var ? "1" : "0");
if (retval <= 0) {
/* Handle error */
}
/* Environment variable TEST is set using putenv() */
retval=putenv(env);
if (retval != 0) {
/* Handle error */
}
}setenv() to Set Environment Variable ValueTo set the value of TEST to var, use setenv().
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE1024 1024
void func(int var)
{
/* Environment variable TEST is set using setenv() */
int retval = setenv("TEST", var ? "1" : "0", 1);
if (retval != 0) {
/* Handle error */
}
}This issue occurs when you do one of the following:
Use a
const-qualified object as the destination of an assignment.Pass a
const-qualified object to a function that modifies the argument.
For instance, the defect can occur in the following situations:
You pass a
const-qualified object as first argument of one of the following functions:mkstempmkostempmkostempsmkdtemp
You pass a
const-qualified object as the destination argument of one of the following functions:strcpystrncpystrcatmemset
You perform a write operation on a
const-qualified object.
The risk depends upon the modifications made to the const-qualified object.
| Situation | Risk |
|---|---|
Passing to mkstemp, mkostemp, mkostemps, mkdtemp, and so on. | These functions replace the last six characters of their first argument with a string. Therefore, they expect a modifiable char array as their first argument. |
Passing to strcpy, strncpy, strcat, memset and so on. | These functions modify their destination argument. Therefore, they expect a modifiable char array as their destination argument. |
| Writing to the object | The const qualifier implies an agreement that the value of the object will not be modified. By writing to a const-qualified object, you break the agreement. The result of the operation is undefined. |
The fix depends on the modification made to the const-qualified object.
| Situation | Fix |
|---|---|
Passing to mkstemp, mkostemp, mkostemps, mkdtemp, and so on. | Pass a non-const object as first argument of the function. |
Passing to strcpy, strncpy, strcat, memset and so on. | Pass a non-const object as destination argument of the function. |
| Writing to the object | Perform the write operation on a non-const object. |
See examples of fixes below.
If you do not want to fix the issue, add comments to your result or code to avoid another review. See:
Address Polyspace Results Through Bug Fixes or Justifications if you review results in the Polyspace user interface.
Address Results in Polyspace Access Through Bug Fixes or Justifications (Polyspace Access) if you review results in a web browser.
Annotate Code and Hide Known or Acceptable Results if you review results in an IDE.
#include <string.h>
const char* buffer = "abcdeXXXXXXX";
void func(char* string) {
char *ptr = (char*)strchr(buffer,'X');
if(ptr)
strcpy(ptr,string); //Noncompliant
}
In this example, because the pointer buffer is const-qualified, strchr(buffer,'X') returns a const-qualified char* pointer. When this char* pointer is used as the destination argument of strcpy, a Writing to const qualified object error appears.
const-Qualified Object to Non-const ObjectOne possible correction is to assign the constant string to a non-const object and use the non-const object as destination argument of strchr.
#include <string.h>
char buffer[] = "abcdeXXXXXXX";
void func(char* string) {
char *ptr = (char*)strchr(buffer,'X');
if(ptr)
strcpy(ptr,string);
}Check Information
| Category: Others |
PQL Name:
std.cwe_native.R686
|
Version History
Introduced in R2023b
See Also
External Websites
MATLAB Command
You clicked a link that corresponds to this MATLAB command:
Run the command by entering it in the MATLAB Command Window. Web browsers do not support MATLAB commands.
Web サイトの選択
Web サイトを選択すると、翻訳されたコンテンツにアクセスし、地域のイベントやサービスを確認できます。現在の位置情報に基づき、次のサイトの選択を推奨します:
また、以下のリストから Web サイトを選択することもできます。
最適なサイトパフォーマンスの取得方法
中国のサイト (中国語または英語) を選択することで、最適なサイトパフォーマンスが得られます。その他の国の MathWorks のサイトは、お客様の地域からのアクセスが最適化されていません。
南北アメリカ
- América Latina (Español)
- Canada (English)
- United States (English)
ヨーロッパ
- Belgium (English)
- Denmark (English)
- Deutschland (Deutsch)
- España (Español)
- Finland (English)
- France (Français)
- Ireland (English)
- Italia (Italiano)
- Luxembourg (English)
- Netherlands (English)
- Norway (English)
- Österreich (Deutsch)
- Portugal (English)
- Sweden (English)
- Switzerland
- United Kingdom (English)