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]
[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)); |
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
Pymunkpackage: the functionspmFloatArrayNew()[1] andpmIntArrayNew()[2] do not check the return values of their internal memory allocation calls. After allocating memory for the outer struct usingcpcalloc()[3],[4] each function immediately attempts to allocate the internal array (arr->arr) through a secondcpcalloc()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
pmFloatArrayNewandpmIntArrayNew, respectively:For
pmFloatArrayNew()For
pmIntArrayNew()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
pmFloatArrayorpmIntArrayinstances does not dereference a NULL internal buffer under any circumstances.References
[1]
pymunk/pymunk_cffi/extensions.c
Line 72 in f3c3b38
[2]
pymunk/pymunk_cffi/extensions.c
Line 134 in f3c3b38
[3]
pymunk/pymunk_cffi/extensions.c
Line 74 in f3c3b38
[4]
pymunk/pymunk_cffi/extensions.c
Line 136 in f3c3b38
[5]
pymunk/pymunk_cffi/extensions.c
Line 78 in f3c3b38
[6]
pymunk/pymunk_cffi/extensions.c
Line 140 in f3c3b38