Skip to content

Potential NULL Pointer Dereference in pmFloatArrayNew and pmIntArrayNew #299

@mpap10

Description

@mpap10

We are researchers from the University of Athens, working on cross-language analysis of Python packages with C/C++ native extensions.

Problem

We found an issue in the Pymunk package: the functions pmFloatArrayNew() [1] and pmIntArrayNew() [2] do not check the return values of their internal memory allocation calls. After allocating memory for the outer struct using cpcalloc() [3],[4] each function immediately attempts to allocate the internal array (arr->arr) through a second cpcalloc() call [5], [6].
If this allocation fails, the internal buffer is NULL while the outer struct remains allocated, which can lead to NULL pointer dereference when the buffer is used.

Observed Behavior in Python

To explore the bug, we ran the following scripts for pmFloatArrayNew and pmIntArrayNew, respectively:
For pmFloatArrayNew()

from pymunk._chipmunk import lib as chiplib
SIZE = 250
COUNT = 10000000
y = []
for i in range(COUNT):
    p = chiplib.pmFloatArrayNew(SIZE)
    y.append(p)

For pmIntArrayNew()

from pymunk._chipmunk import lib as chiplib
SIZE = 250
COUNT = 10000000
y = []
for i in range(COUNT):
    p = chiplib.pmIntArrayNew(SIZE)
    y.append(p)

In practice, the interpreter raises a MemoryError in Python before cpcalloc() returns NULL, which means that a NULL pointer dereference is rarely observed directly as a segmentation fault. However, the underlying issue remains and can result in undefined behavior in memory-constrained scenarios or when very large allocations are requested.

Potential Fix

  • Ensure that the internal allocation for arr->arr is checked before the function proceeds or returns the struct.
  • Add defensive NULL checks so that code handling pmFloatArray or pmIntArray instances does not dereference a NULL internal buffer under any circumstances.

References

[1]

pmFloatArrayNew(int size)

[2]
pmIntArrayNew(int size)

[3]
pmFloatArray *arr = (pmFloatArray *)cpcalloc(1, sizeof(pmFloatArray));

[4]
pmIntArray *arr = (pmIntArray *)cpcalloc(1, sizeof(pmIntArray));

[5]
arr->arr = (cpFloat *)cpcalloc(arr->max, sizeof(cpFloat));

[6]
arr->arr = (uintptr_t *)cpcalloc(arr->max, sizeof(uintptr_t));

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions