Function Call With Incorrect Argument Type

Description

Function Call With Incorrect Argument Type is a programming error where code calls a function, procedure, or routine with an argument that has the wrong data type compared to what the function expects. This vulnerability most commonly occurs in loosely typed languages, in strongly typed languages where variable argument types cannot be enforced at compile time, or when implicit type casting occurs. When functions receive arguments of unexpected types, they may misinterpret the data, perform incorrect operations, or exhibit undefined behavior that can lead to security vulnerabilities.

Risk

Incorrect argument types create significant security risks depending on the context. Passing a pointer where an integer is expected (or vice versa) can lead to memory corruption. Character handling functions receiving values outside the valid range can access memory incorrectly. Type confusion in security-critical functions can bypass authentication or authorization checks. In languages with implicit casting, subtle type mismatches may compile successfully but produce dangerously incorrect results at runtime. Format string functions are particularly vulnerable—passing an integer where a string pointer is expected can cause crashes or information disclosure.

Solution

Use strongly typed languages when possible. Enable compiler warnings for type mismatches and treat warnings as errors. In C, always use function prototypes and enable -Wformat and -Wconversion warnings. For functions accepting variable arguments, use format attributes to enable compiler checking. Avoid implicit casts—use explicit casts only when necessary and after careful consideration. Follow CERT guidelines for character handling functions. Use static analysis tools that detect type mismatches. In dynamically typed languages, add explicit type checking at function entry points.

Common Consequences

ImpactDetails
OtherScope: Other

Quality Degradation - Functions produce incorrect or undefined behavior when called with wrong argument types.
IntegrityScope: Integrity

Modify Memory - Type confusion can cause functions to write to incorrect memory locations.
AvailabilityScope: Availability

DoS: Crash, Exit, or Restart - Type mismatches can cause crashes, especially with pointer/integer confusion.

Example Code

Vulnerable Code

// Vulnerable: Passing int where pointer expected in printf
#include <stdio.h>

void vulnerable_printf_type(int value) {
    // Vulnerable: %s expects char*, but int is provided
    printf("Value: %s\n", value);  // WRONG TYPE!
    // Treats integer as memory address - crashes or leaks memory
}

// Vulnerable: Character function with out-of-range value
#include <ctype.h>

int vulnerable_char_check(int input) {
    // Vulnerable: isalpha expects unsigned char range (0-255) or EOF
    // Passing arbitrary int can cause undefined behavior
    char c = (char)input;  // May be negative on some platforms

    if (isalpha(c)) {  // Undefined if c is negative and not EOF
        return 1;
    }
    return 0;
}

// Vulnerable: Signed/unsigned mismatch
void vulnerable_memset(char* buffer, int value, int size) {
    // If size is negative, memset interprets it as huge positive number
    memset(buffer, value, size);  // size_t expected, int provided
}

// Vulnerable: Float where int expected
void process_count(int count) {
    for (int i = 0; i < count; i++) {
        // Process item
    }
}

void vulnerable_float() {
    float f = 10.7f;
    // Vulnerable: Float silently truncated to int
    process_count(f);  // Implicit conversion, might expect 11 iterations
}
// Vulnerable: Java type confusion with generics
import java.util.*;

public class VulnerableTypes {

    // Vulnerable: Raw type allows wrong types
    @SuppressWarnings("unchecked")
    public void vulnerableGeneric() {
        List list = new ArrayList();  // Raw type
        list.add("string");
        list.add(123);  // Mixing types!

        for (Object item : list) {
            // Vulnerable: ClassCastException at runtime
            String s = (String) item;  // Crashes on Integer
            process(s);
        }
    }

    // Vulnerable: Varargs type confusion
    public void logMessage(String format, Object... args) {
        System.out.printf(format, args);
    }

    public void vulnerableVarargs() {
        int[] numbers = {1, 2, 3};
        // Vulnerable: Passing int[] where multiple Objects expected
        logMessage("Values: %d, %d, %d", numbers);  // Wrong!
        // numbers is treated as single Object, not 3 separate args
    }
}
# Vulnerable: Python type errors
def process_items(items: list) -> int:
    """Process a list of items and return count."""
    total = 0
    for item in items:
        total += len(item)  # Expects items with len()
    return total

# Vulnerable: Passing string where list expected
result = process_items("hello")  # String is iterable, but len("h") etc.
# Works but produces unexpected result (counts characters)

# Vulnerable: Passing wrong type to security function
def verify_hash(data: bytes, expected_hash: str) -> bool:
    """Verify data hash matches expected."""
    import hashlib
    actual = hashlib.sha256(data).hexdigest()
    return actual == expected_hash

# Vulnerable: Passing str instead of bytes
user_data = request.form['data']  # str type
# verify_hash(user_data, expected)  # TypeError or encoding issues
// Vulnerable: Variadic function type confusion
#include <stdarg.h>
#include <stdio.h>

void vulnerable_variadic(int count, ...) {
    va_list args;
    va_start(args, count);

    for (int i = 0; i < count; i++) {
        // Assumes all args are char*
        char* str = va_arg(args, char*);  // Type must match!
        printf("%s\n", str);
    }

    va_end(args);
}

void call_vulnerable() {
    // Vulnerable: Passing int where char* expected
    vulnerable_variadic(3, "hello", 12345, "world");
    // 12345 interpreted as pointer - crash or garbage
}

Fixed Code

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

void secure_printf_type(int value) {
    // Fixed: %d for int, not %s
    printf("Value: %d\n", value);
}

void secure_printf_string(const char* str) {
    // Fixed: %s with actual string pointer
    printf("Value: %s\n", str);
}

// Fixed: Safe character handling
#include <ctype.h>

int secure_char_check(int input) {
    // Fixed: Cast to unsigned char for character functions
    unsigned char c = (unsigned char)input;

    // Or validate range first
    if (input < 0 || input > 255) {
        return 0;  // Invalid character value
    }

    if (isalpha(c)) {
        return 1;
    }
    return 0;
}

// Fixed: Proper type for size
#include <string.h>
#include <stddef.h>

void secure_memset(char* buffer, int value, size_t size) {
    // Fixed: Use size_t for sizes
    memset(buffer, value, size);
}

int secure_memset_checked(char* buffer, int value, int size) {
    // Fixed: Validate before implicit conversion
    if (size < 0) {
        return -1;  // Error: invalid size
    }
    memset(buffer, value, (size_t)size);
    return 0;
}

// Fixed: Explicit type conversion with awareness
void secure_float_handling() {
    float f = 10.7f;

    // Fixed: Explicit conversion with rounding decision
    int count_floor = (int)f;           // 10 - truncate
    int count_round = (int)(f + 0.5f);  // 11 - round

    // Choose appropriate one based on requirements
    process_count(count_round);
}
// Fixed: Java with proper generics
import java.util.*;

public class SecureTypes {

    // Fixed: Use parameterized types
    public void secureGeneric() {
        List<String> list = new ArrayList<>();
        list.add("string");
        // list.add(123);  // Compile error!

        for (String s : list) {
            // Type-safe iteration
            process(s);
        }
    }

    // Fixed: Proper varargs handling
    public void logMessage(String format, Object... args) {
        System.out.printf(format, args);
    }

    public void secureVarargs() {
        int[] numbers = {1, 2, 3};

        // Fixed: Convert to wrapper objects
        logMessage("Values: %d, %d, %d", numbers[0], numbers[1], numbers[2]);

        // Or use Integer array
        Integer[] boxedNumbers = {1, 2, 3};
        logMessage("Values: %d, %d, %d", (Object[]) boxedNumbers);
    }

    // Fixed: Type-safe logging
    public void secureLog(String message, int... values) {
        StringBuilder sb = new StringBuilder(message);
        for (int v : values) {
            sb.append(" ").append(v);
        }
        System.out.println(sb);
    }
}
# Fixed: Python with type validation
from typing import List, Union

def process_items_secure(items: List[str]) -> int:
    """Process a list of string items and return total length."""
    if not isinstance(items, list):
        raise TypeError(f"Expected list, got {type(items).__name__}")

    total = 0
    for item in items:
        if not isinstance(item, str):
            raise TypeError(f"Expected str items, got {type(item).__name__}")
        total += len(item)
    return total

# Fixed: Type-safe hash verification
def verify_hash_secure(data: Union[bytes, str], expected_hash: str) -> bool:
    """Verify data hash matches expected."""
    import hashlib

    # Fixed: Handle both bytes and str
    if isinstance(data, str):
        data = data.encode('utf-8')
    elif not isinstance(data, bytes):
        raise TypeError(f"Expected bytes or str, got {type(data).__name__}")

    actual = hashlib.sha256(data).hexdigest()
    return actual == expected_hash

# Using runtime type checking
from typing import get_type_hints
import functools

def type_checked(func):
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        hints = get_type_hints(func)
        # Validate argument types against hints
        # (simplified - production would be more thorough)
        return func(*args, **kwargs)
    return wrapper
// Fixed: Type-safe variadic alternatives
#include <stdio.h>

// Fixed: Use typed array instead of variadic
void secure_print_strings(const char** strings, int count) {
    for (int i = 0; i < count; i++) {
        if (strings[i] != NULL) {
            printf("%s\n", strings[i]);
        }
    }
}

void call_secure() {
    const char* strings[] = {"hello", "world", "test"};
    secure_print_strings(strings, 3);
}

// Fixed: Type-safe union for mixed types
typedef enum { TYPE_INT, TYPE_STRING, TYPE_FLOAT } ArgType;

typedef struct {
    ArgType type;
    union {
        int i;
        const char* s;
        float f;
    } value;
} TypedArg;

void secure_mixed_print(TypedArg* args, int count) {
    for (int i = 0; i < count; i++) {
        switch (args[i].type) {
            case TYPE_INT:
                printf("%d\n", args[i].value.i);
                break;
            case TYPE_STRING:
                printf("%s\n", args[i].value.s);
                break;
            case TYPE_FLOAT:
                printf("%f\n", args[i].value.f);
                break;
        }
    }
}

CVE Examples

  • CVE-2006-1174: Argument type mismatch in function call leading to security bypass.
  • CVE-2007-1420: Type confusion causing crash in string handling function.

References

  1. MITRE Corporation. "CWE-686: Function Call With Incorrect Argument Type." https://cwe.mitre.org/data/definitions/686.html
  2. CERT C Coding Standard. "EXP37-C. Call functions with the correct number and type of arguments."
  3. CERT C Coding Standard. "STR37-C. Arguments to character handling functions must be representable as an unsigned char."