Access of Uninitialized Pointer

Description

Access of Uninitialized Pointer is a memory safety vulnerability where software accesses or uses a pointer variable that has not been initialized to a valid memory address. Uninitialized pointers contain indeterminate values—whatever data happened to be in that memory location. When dereferenced, such pointers may reference arbitrary memory locations, causing the program to read from or write to unexpected memory areas. If the pointer is used as a function pointer, arbitrary functions could be invoked. The severity of this vulnerability depends on memory layout, memory management behaviors, and how the product operates.

Risk

This vulnerability can lead to crashes, information disclosure, or code execution. When an uninitialized pointer is dereferenced for reading, it may access sensitive data from other parts of memory, or it may access invalid memory causing a crash. When used for writing, it can corrupt arbitrary memory locations, potentially overwriting security-critical data or function pointers. Attackers who can influence the contents of uninitialized memory (through heap spraying or other techniques) can control where the pointer points, enabling exploitation for arbitrary code execution. The unpredictable nature of uninitialized data makes this vulnerability particularly dangerous in security-sensitive contexts.

Solution

Always initialize pointers when they are declared, either to a valid address or to NULL. Use compiler warnings (-Wuninitialized, -Werror) to catch uninitialized variable usage. Initialize all local variables at declaration, especially in C/C++. Use static analysis tools to detect potential use of uninitialized pointers. In C++, prefer RAII patterns and smart pointers that enforce initialization. Consider using languages with automatic memory management where uninitialized pointer access is not possible. When a pointer might not be assigned in all code paths, initialize it to NULL and check before dereferencing. Enable runtime sanitizers like MemorySanitizer during testing to detect uninitialized memory access.

Common Consequences

ImpactDetails
ConfidentialityScope: Confidentiality

Read Memory - Uninitialized pointers used in read operations could expose sensitive memory contents from arbitrary locations.
AvailabilityScope: Availability

DoS: Crash, Exit, or Restart - Invalid memory references cause crashes when accessing inaccessible or malformed memory locations.
Integrity, Confidentiality, AvailabilityScope: Integrity, Confidentiality, Availability

Execute Unauthorized Code or Commands - If used as a function pointer or for writes, attackers may achieve arbitrary code execution.

Example Code

Vulnerable Code

// Vulnerable: Pointer declared but not initialized
void vulnerable_uninitialized(int condition) {
    char *ptr;  // Uninitialized - contains garbage value

    if (condition) {
        ptr = malloc(100);
        strcpy(ptr, "data");
    }

    // Vulnerable: ptr may be uninitialized if condition is false
    printf("Value: %s\n", ptr);  // Dereferences garbage address
}
// Vulnerable: Pointer not initialized in all code paths
int vulnerable_conditional(int type, char **out_ptr) {
    char *buffer;  // Uninitialized

    if (type == 1) {
        buffer = malloc(256);
        strcpy(buffer, "Type 1 data");
    } else if (type == 2) {
        buffer = malloc(512);
        strcpy(buffer, "Type 2 data");
    }
    // Vulnerable: if type != 1 and type != 2, buffer is uninitialized

    *out_ptr = buffer;  // May store garbage pointer
    return 0;
}
// Vulnerable: Function pointer not initialized
typedef void (*callback_t)(void);

void vulnerable_callback(int registered) {
    callback_t handler;  // Uninitialized function pointer

    if (registered) {
        handler = registered_callback;
    }

    // Vulnerable: If not registered, handler is garbage
    handler();  // Calls arbitrary address!
}
// Vulnerable: Struct with uninitialized pointer member
struct node {
    int value;
    struct node *next;  // May be uninitialized
};

void vulnerable_list(void) {
    struct node head;  // next pointer is uninitialized
    head.value = 1;
    // Forgot to set head.next = NULL

    // Later traversal
    struct node *current = &head;
    while (current != NULL) {
        printf("%d\n", current->value);
        current = current->next;  // Follows garbage pointer!
    }
}
// Vulnerable: Pointer in constructor not initialized
class VulnerableClass {
private:
    char *buffer;
    int size;

public:
    VulnerableClass(int sz) {
        size = sz;
        // Forgot to initialize buffer!
    }

    void write(const char *data) {
        // buffer is uninitialized
        strcpy(buffer, data);  // Writes to arbitrary memory
    }
};
// Vulnerable: Uninitialized in error path
char* vulnerable_read_file(const char *filename) {
    FILE *fp;
    char *content;  // Uninitialized
    long size;

    fp = fopen(filename, "r");
    if (!fp) {
        return content;  // Returns uninitialized pointer!
    }

    fseek(fp, 0, SEEK_END);
    size = ftell(fp);
    fseek(fp, 0, SEEK_SET);

    content = malloc(size + 1);
    fread(content, 1, size, fp);
    content[size] = '\0';

    fclose(fp);
    return content;
}

Fixed Code

// Fixed: Initialize pointer at declaration
void fixed_uninitialized(int condition) {
    char *ptr = NULL;  // Fixed: Initialized to NULL

    if (condition) {
        ptr = malloc(100);
        if (ptr) {
            strcpy(ptr, "data");
        }
    }

    // Fixed: Check before dereference
    if (ptr != NULL) {
        printf("Value: %s\n", ptr);
        free(ptr);
    }
}
// Fixed: Initialize and handle all code paths
int fixed_conditional(int type, char **out_ptr) {
    char *buffer = NULL;  // Fixed: Initialize to NULL

    if (type == 1) {
        buffer = malloc(256);
        if (buffer) strcpy(buffer, "Type 1 data");
    } else if (type == 2) {
        buffer = malloc(512);
        if (buffer) strcpy(buffer, "Type 2 data");
    } else {
        // Fixed: Handle default case
        *out_ptr = NULL;
        return -1;  // Unknown type
    }

    *out_ptr = buffer;
    return buffer ? 0 : -1;
}
// Fixed: Initialize function pointer
typedef void (*callback_t)(void);

static void default_handler(void) {
    // No-op default handler
}

void fixed_callback(int registered) {
    callback_t handler = default_handler;  // Fixed: Safe default

    if (registered) {
        handler = registered_callback;
    }

    // Safe: handler always points to valid function
    handler();
}
// Fixed: Initialize all struct members
struct node {
    int value;
    struct node *next;
};

void fixed_list(void) {
    struct node head = {0};  // Fixed: Zero-initialize all members
    // Or explicitly:
    // struct node head;
    // head.value = 1;
    // head.next = NULL;

    head.value = 1;

    struct node *current = &head;
    while (current != NULL) {
        printf("%d\n", current->value);
        current = current->next;  // Safe: next is NULL
    }
}
// Fixed: Initialize in constructor initializer list
class FixedClass {
private:
    char *buffer;
    int size;

public:
    FixedClass(int sz) : buffer(nullptr), size(sz) {
        // Fixed: buffer initialized in initializer list
        if (size > 0) {
            buffer = new char[size];
        }
    }

    ~FixedClass() {
        delete[] buffer;
    }

    void write(const char *data) {
        if (buffer != nullptr && strlen(data) < static_cast<size_t>(size)) {
            strcpy(buffer, data);
        }
    }
};
// Fixed: Return NULL on error
char* fixed_read_file(const char *filename) {
    FILE *fp;
    char *content = NULL;  // Fixed: Initialize to NULL
    long size;

    fp = fopen(filename, "r");
    if (!fp) {
        return NULL;  // Fixed: Return known value
    }

    fseek(fp, 0, SEEK_END);
    size = ftell(fp);
    fseek(fp, 0, SEEK_SET);

    content = malloc(size + 1);
    if (content) {
        fread(content, 1, size, fp);
        content[size] = '\0';
    }

    fclose(fp);
    return content;  // Returns NULL or valid pointer
}

  • CWE-119: Improper Restriction of Operations within Bounds of Memory Buffer (parent)
  • CWE-457: Use of Uninitialized Variable (related - general form)
  • CWE-125: Out-of-bounds Read (can follow)
  • CWE-787: Out-of-bounds Write (can follow)
  • CWE-908: Use of Uninitialized Resource (parent)

References

  1. MITRE Corporation. "CWE-824: Access of Uninitialized Pointer." https://cwe.mitre.org/data/definitions/824.html
  2. CERT C Secure Coding Standard. "EXP33-C. Do not read uninitialized memory."
  3. Google. "MemorySanitizer." https://github.com/google/sanitizers/wiki/MemorySanitizer