Main Content

CWE Rule 685

Function Call With Incorrect Number of Arguments

Since R2023a

Description

Rule Description

The software calls a function, procedure, or routine, but the caller specifies too many arguments, or too few arguments, which may lead to undefined behavior and resultant weaknesses.

Polyspace Implementation

The rule checker checks for these issues:

  • Format string specifiers and arguments mismatch

  • Too many va_arg calls for current argument list

  • Unreliable cast of function pointer

Examples

expand all

Issue

This issue occurs when the format specifiers in the formatted output functions such as printf do not match their corresponding arguments. For example, an argument of type unsigned long must have a format specification of %lu.

Risk

Mismatch between format specifiers and the corresponding arguments result in undefined behavior.

Fix

Make sure that the format specifiers match the corresponding arguments. For instance, in this example, the %d specifier does not match the string argument message and the %s specifier does not match the integer argument err_number.

  const char *message = "License not available";
  int err_number = ;-4
  printf("Error: %d (error type %s)\n", message, err_number);
Switching the two format specifiers fixes the issue. See the specifications for the printf function for more information about format specifiers.

In cases where integer promotion modifies the perceived data type of an argument, the analysis result shows both the original type and the type after promotion. The format specifier has to match the type after integer promotion.

If you do not want to fix the issue, add comments to your result or code to avoid another review. See:

Example — Printing a Float
#include <stdio.h>

void string_format(void) {

    unsigned long fst = 1;

    printf("%d\n", fst);  //Noncompliant
}

In the printf statement, the format specifier, %d, does not match the data type of fst.

Correction — Use an Unsigned Long Format Specifier

One possible correction is to use the %lu format specifier. This specifier matches the unsigned integer type and long size of fst.

#include <stdio.h>

void string_format(void) {

    unsigned long fst = 1;

    printf("%lu\n", fst);
}
Correction — Use an Integer Argument

One possible correction is to change the argument to match the format specifier. Convert fst to an integer to match the format specifier and print the value 1.

#include <stdio.h>

void string_format(void) {

    unsigned long fst = 1;

    printf("%d\n", (int)fst);
}
Issue

This issue occurs when the number of calls to va_arg exceeds the number of arguments passed to the corresponding variadic function. The analysis raises a defect only when the variadic function is called.

Too many va_arg calls for current argument list does not raise a defect when:

  • The number of calls to va_arg inside the variadic function is indeterminate. For example, if the calls are from an external source.

  • The va_list used in va_arg is invalid.

Risk

When you call va_arg and there is no next argument available in va_list, the behavior is undefined. The call to va_arg might corrupt data or return an unexpected result.

Fix

Ensure that you pass the correct number of arguments to the variadic function.

Example — No Argument Available When Calling va_arg
#include <stdarg.h>
#include <stddef.h>
#include <math.h>

/* variadic function defined with
* one named argument 'count'
*/
int variadic_func(int count, ...) {
    int result = -1;
    va_list ap;
    va_start(ap, count);
    if (count > 0) {
        result = va_arg(ap, int);
        count --;
        if (count > 0) {
/* No further argument available 
* in va_list when calling va_arg
*/	

            result += va_arg(ap, int);  //Noncompliant
        }
    }
    va_end(ap);
    return result;
}

void func(void) {

    (void)variadic_func(2, 100); 

}

In this example, the named argument and only one variadic argument are passed to variadic_func() when it is called inside func(). On the second call to va_arg, no further variadic argument is available in ap and the behavior is undefined.

Correction — Pass Correct Number of Arguments to Variadic Function

One possible correction is to ensure that you pass the correct number of arguments to the variadic function.

#include <stdarg.h>
#include <stddef.h>
#include <math.h>

/* variadic function defined with
* one named argument 'count'
*/

int variadic_func(int count, ...) {
    int result = -1;
    va_list ap;
    va_start(ap, count);
    if (count > 0) {
        result = va_arg(ap, int);
        count --;
        if (count > 0) {

/* The correct number of arguments is
* passed to va_list when variadic_func()
* is called inside func()
*/			
            result += va_arg(ap, int); 
        }
    }
    va_end(ap);
    return result;
}

void func(void) {

    (void)variadic_func(2, 100, 200); 

} 
Issue

This issue occurs when a function pointer is cast to another function pointer that has different argument or return type.

Risk

If you cast a function pointer to another function pointer with different argument or return type and then use the latter function pointer to call a function, the behavior is undefined.

Fix

Avoid a cast between two function pointers with mismatch in argument or return types.

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:

Example — Unreliable cast of function pointer error
#include <stdio.h>
#include <math.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);  //Noncompliant
    /* Defect: fp implicitly cast to int(*) (double) */

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

The function pointer fp is declared as double (*)(double). However in passing it to function Calculate_Sum, fp is implicitly cast to int (*)(double).

Correction — Avoid Function Pointer Cast

One possible correction is to check that the function pointer in the definition of Calculate_Sum has the same argument and return type as fp. This step makes sure that fp is not implicitly cast to a different argument or return type.

#include <stdio.h>
#include <math.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;
}

Check Information

Category: Others

Version History

Introduced in R2023a