Skip to content

Commit d3d2edf

Browse files
authored
Merge branch 'main' into fix/opcode-deref-free-flags-151321
2 parents 9ea5992 + c375992 commit d3d2edf

3 files changed

Lines changed: 52 additions & 1 deletion

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix an invalid pointer dereference that could occur when calling :c:func:`PyObject_Realloc` with a NULL pointer in :term:`free-threaded builds <free-threaded build>` or with :envvar:`PYTHONMALLOC` set to ``mimalloc``.

Modules/_testcapi/mem.c

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -345,6 +345,53 @@ test_setallocators(PyMemAllocatorDomain domain)
345345
goto fail;
346346
}
347347

348+
/* realloc(NULL, size) should behave like malloc(size) */
349+
size_t size3 = 100;
350+
void *ptr3;
351+
switch(domain) {
352+
case PYMEM_DOMAIN_RAW:
353+
ptr3 = PyMem_RawRealloc(NULL, size3);
354+
break;
355+
case PYMEM_DOMAIN_MEM:
356+
ptr3 = PyMem_Realloc(NULL, size3);
357+
break;
358+
case PYMEM_DOMAIN_OBJ:
359+
ptr3 = PyObject_Realloc(NULL, size3);
360+
break;
361+
default:
362+
ptr3 = NULL;
363+
break;
364+
}
365+
366+
CHECK_CTX("realloc(NULL, size)");
367+
if (ptr3 == NULL) {
368+
error_msg = "realloc(NULL, size) failed";
369+
goto fail;
370+
}
371+
if (hook.realloc_ptr != NULL || hook.realloc_new_size != size3) {
372+
error_msg = "realloc(NULL, size) invalid parameters";
373+
goto fail;
374+
}
375+
376+
hook.free_ptr = NULL;
377+
switch(domain) {
378+
case PYMEM_DOMAIN_RAW:
379+
PyMem_RawFree(ptr3);
380+
break;
381+
case PYMEM_DOMAIN_MEM:
382+
PyMem_Free(ptr3);
383+
break;
384+
case PYMEM_DOMAIN_OBJ:
385+
PyObject_Free(ptr3);
386+
break;
387+
}
388+
389+
CHECK_CTX("realloc(NULL, size) free");
390+
if (hook.free_ptr != ptr3) {
391+
error_msg = "unexpected pointer passed to free";
392+
goto fail;
393+
}
394+
348395
res = Py_NewRef(Py_None);
349396
goto finally;
350397

Objects/obmalloc.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -363,7 +363,10 @@ _PyObject_MiRealloc(void *ctx, void *ptr, size_t nbytes)
363363
_mi_memcpy((char*)newp + offset, (char*)ptr + offset, copy_size - offset);
364364
}
365365
else {
366-
_mi_memcpy(newp, ptr, copy_size);
366+
// memcpy(dst, NULL, 0) is undefined behavior. See gh-151297.
367+
if mi_likely(ptr) {
368+
_mi_memcpy(newp, ptr, copy_size);
369+
}
367370
}
368371
mi_free(ptr);
369372
return newp;

0 commit comments

Comments
 (0)