Function Call With Incorrect Number of Arguments

Description

Function Call With Incorrect Number of Arguments is a programming error where code invokes a function, procedure, or routine with either too many or too few arguments compared to what the function signature expects. This commonly occurs in languages like C that support variadic functions or in dynamically typed languages like Perl that don't enforce strict argument counts at compile time. When functions receive unexpected argument counts, they may read uninitialized memory, skip critical processing, or exhibit undefined behavior that attackers can exploit.

Risk

Incorrect argument counts create serious risks especially in security-critical functions. Functions receiving too few arguments may read garbage values from the stack, potentially exposing sensitive data or causing crashes. Functions receiving too many arguments might ignore the extra values or corrupt the stack depending on calling convention. In format string functions, argument count mismatches between format specifiers and actual arguments enable format string attacks. Security functions like authentication or authorization checks may fail insecurely when arguments are missing. The risk is compounded in languages without compile-time checking where these errors only manifest at runtime.

Solution

Use compilers with strict type and argument checking enabled. In C, use function prototypes and enable warnings like -Wmissing-prototypes and -Wformat. For variadic functions, ensure format strings match argument lists. In dynamically typed languages, add explicit argument validation at function entry. Use static analysis tools that can detect argument count mismatches. Consider using languages or linters that enforce argument checking. Write comprehensive unit tests that exercise all code paths. During code reviews, specifically verify that function calls match their declarations.

Common Consequences

ImpactDetails
OtherScope: Other

Quality Degradation - Functions produce incorrect results or undefined behavior when called with wrong argument counts.
AvailabilityScope: Availability

DoS: Crash, Exit, or Restart - Stack corruption or reading uninitialized values can cause program crashes.
ConfidentialityScope: Confidentiality

Read Memory - Too few arguments may cause functions to read uninitialized stack data.

Example Code

Vulnerable Code

// Vulnerable: Missing argument to printf format string
#include <stdio.h>

void vulnerable_printf(char* username, int user_id) {
    // Format expects 3 arguments but only 2 provided
    printf("User: %s, ID: %d, Status: %s\n", username, user_id);
    // Missing third argument - reads garbage from stack
    // May expose sensitive data or crash
}

// Vulnerable: Variable arguments function with wrong count
void vulnerable_log(const char* format, ...) {
    va_list args;
    va_start(args, format);
    vprintf(format, args);
    va_end(args);
}

void use_vulnerable_log() {
    int error_code = 404;
    char* path = "/api/users";

    // Vulnerable: Format expects 3 args, only 2 provided
    vulnerable_log("Error %d at %s: %s\n", error_code, path);
    // Missing error message - undefined behavior
}

// Vulnerable: Security function with missing argument
int check_permission(int user_id, int resource_id, int permission_level) {
    // Implementation checks all three parameters
    return database_check(user_id, resource_id, permission_level);
}

void vulnerable_access() {
    int user = 123;
    int resource = 456;

    // Vulnerable: Missing permission_level argument (in some languages)
    // In weakly typed languages, this might compile/run with garbage value
    // check_permission(user, resource);  // Missing third arg!
}
# Vulnerable: Perl doesn't enforce argument counts
sub authenticate {
    my ($username, $password, $domain) = @_;

    # Domain defaults to undef if not provided
    if (!defined $domain) {
        $domain = "default";  # May not be the intended domain
    }

    return check_credentials($username, $password, $domain);
}

# Vulnerable: Called with only 2 arguments
my $result = authenticate($user_input, $pass_input);
# Missing domain argument - uses default, may bypass domain-specific rules

# Vulnerable: Too many arguments - extras silently ignored
my $result2 = authenticate($user, $pass, $domain, $extra_arg);
# $extra_arg is silently ignored - may indicate logic error
// Vulnerable: snprintf with wrong argument count
#include <stdio.h>

void vulnerable_format(char* buffer, size_t size,
                       char* user, char* action, char* target) {
    // Format expects 3 arguments but only 2 provided
    snprintf(buffer, size,
             "User %s performed %s on %s",
             user, action);  // Missing 'target' argument!
    // Reads garbage for third %s
}

// Vulnerable: Callback with wrong argument count
typedef void (*callback_t)(int, int, int);

void process_with_callback(callback_t cb, int a, int b, int c) {
    cb(a, b, c);
}

void wrong_callback(int x, int y) {  // Only takes 2 args
    printf("x=%d, y=%d\n", x, y);
}

void vulnerable_callback() {
    // Vulnerable: Passing callback that expects 2 args where 3 are provided
    process_with_callback((callback_t)wrong_callback, 1, 2, 3);
    // Third argument is pushed but ignored - may corrupt stack
}

Fixed Code

// Fixed: Correct argument count for printf
#include <stdio.h>

void secure_printf(char* username, int user_id, char* status) {
    // Fixed: All format specifiers have corresponding arguments
    printf("User: %s, ID: %d, Status: %s\n", username, user_id, status);
}

// Fixed: Validate format string at compile time
#ifdef __GNUC__
__attribute__((format(printf, 1, 2)))
#endif
void secure_log(const char* format, ...) {
    va_list args;
    va_start(args, format);
    vprintf(format, args);
    va_end(args);
}

void use_secure_log() {
    int error_code = 404;
    char* path = "/api/users";
    char* message = "Not found";

    // Fixed: Correct number of arguments
    secure_log("Error %d at %s: %s\n", error_code, path, message);
}

// Fixed: Use compiler warnings
// Compile with: gcc -Wformat -Werror ...
void secure_format(char* buffer, size_t size,
                   char* user, char* action, char* target) {
    // Fixed: All arguments provided
    snprintf(buffer, size,
             "User %s performed %s on %s",
             user, action, target);
}
# Fixed: Validate argument count in Perl
sub authenticate_secure {
    my ($username, $password, $domain) = @_;

    # Fixed: Validate required arguments
    unless (defined $username && defined $password && defined $domain) {
        die "authenticate requires username, password, and domain";
    }

    return check_credentials($username, $password, $domain);
}

# Alternative: Use signatures (Perl 5.20+)
use feature 'signatures';

sub authenticate_with_sig($username, $password, $domain) {
    # Perl will throw an error if wrong number of args provided
    return check_credentials($username, $password, $domain);
}

# Fixed: Check for unexpected extra arguments
sub process_secure {
    die "Too many arguments" if @_ > 3;
    my ($a, $b, $c) = @_;
    # ... processing
}
// Fixed: Type-safe callbacks
#include <stdio.h>

// Define correct callback type
typedef void (*callback_3arg_t)(int, int, int);

void correct_callback(int x, int y, int z) {
    printf("x=%d, y=%d, z=%d\n", x, y, z);
}

void process_with_callback(callback_3arg_t cb, int a, int b, int c) {
    cb(a, b, c);
}

void secure_callback() {
    // Fixed: Callback has correct signature
    process_with_callback(correct_callback, 1, 2, 3);
}

// Fixed: Use static assert for compile-time validation where possible
#define CALL_WITH_3_ARGS(fn, a, b, c) \
    do { \
        _Static_assert(_Generic((fn), \
            void (*)(int, int, int): 1, \
            default: 0), \
            "Function must accept exactly 3 int arguments"); \
        (fn)((a), (b), (c)); \
    } while(0)

CVE Examples

  • CVE-2005-2709: Buffer overflow in format string function due to incorrect number of arguments.
  • CVE-2006-1174: Function called with wrong number of arguments leading to authentication bypass.

References

  1. MITRE Corporation. "CWE-685: Function Call With Incorrect Number of Arguments." https://cwe.mitre.org/data/definitions/685.html
  2. CERT C Coding Standard. "EXP37-C. Call functions with the correct number and type of arguments."
  3. CERT C Coding Standard. "FIO47-C. Use valid format strings."