summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2018-11-30-17-50-28.bpo-35368.DNaDao.rst1
-rw-r--r--Objects/obmalloc.c59
2 files changed, 54 insertions, 6 deletions
diff --git a/Misc/NEWS.d/next/Core and Builtins/2018-11-30-17-50-28.bpo-35368.DNaDao.rst b/Misc/NEWS.d/next/Core and Builtins/2018-11-30-17-50-28.bpo-35368.DNaDao.rst
new file mode 100644
index 0000000000..4bcf608fdd
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2018-11-30-17-50-28.bpo-35368.DNaDao.rst
@@ -0,0 +1 @@
+:c:func:`PyMem_Malloc` is now also thread-safe in debug mode.
diff --git a/Objects/obmalloc.c b/Objects/obmalloc.c
index 9adcff7a27..0778c851fa 100644
--- a/Objects/obmalloc.c
+++ b/Objects/obmalloc.c
@@ -1413,6 +1413,38 @@ pool_is_in_list(const poolp target, poolp list)
#endif /* Py_DEBUG */
+static void *
+_PyMem_Malloc(size_t nbytes)
+{
+ if (nbytes > (size_t)PY_SSIZE_T_MAX) {
+ return NULL;
+ }
+ if (nbytes == 0) {
+ nbytes = 1;
+ }
+ return malloc(nbytes);
+}
+
+static void *
+_PyMem_Realloc(void *p, size_t nbytes)
+{
+ if (nbytes > (size_t)PY_SSIZE_T_MAX) {
+ return NULL;
+ }
+ if (nbytes == 0) {
+ nbytes = 1;
+ }
+ return realloc(p, nbytes);
+}
+
+
+static void
+_PyMem_Free(void *p)
+{
+ free(p);
+}
+
+
/* Let S = sizeof(size_t). The debug malloc asks for 4*S extra bytes and
fills them with useful stuff, here calling the underlying malloc's result p:
@@ -1479,7 +1511,7 @@ _PyObject_DebugCheckAddress(const void *p)
/* generic debug memory api, with an "id" to identify the API in use */
void *
-_PyObject_DebugMallocApi(char id, size_t nbytes)
+_PyObject_DebugMallocApi(char api, size_t nbytes)
{
uchar *p; /* base address of malloc'ed block */
uchar *tail; /* p + 2*SST + nbytes == pointer to tail pad bytes */
@@ -1491,13 +1523,18 @@ _PyObject_DebugMallocApi(char id, size_t nbytes)
/* overflow: can't represent total as a size_t */
return NULL;
- p = (uchar *)PyObject_Malloc(total);
+ if (api == _PYMALLOC_OBJ_ID) {
+ p = (uchar *)PyObject_Malloc(total);
+ }
+ else {
+ p = (uchar *)_PyMem_Malloc(total);
+ }
if (p == NULL)
return NULL;
- /* at p, write size (SST bytes), id (1 byte), pad (SST-1 bytes) */
+ /* at p, write size (SST bytes), api (1 byte), pad (SST-1 bytes) */
write_size_t(p, nbytes);
- p[SST] = (uchar)id;
+ p[SST] = (uchar)api;
memset(p + SST + 1 , FORBIDDENBYTE, SST-1);
if (nbytes > 0)
@@ -1529,7 +1566,12 @@ _PyObject_DebugFreeApi(char api, void *p)
nbytes += 4*SST;
if (nbytes > 0)
memset(q, DEADBYTE, nbytes);
- PyObject_Free(q);
+ if (api == _PYMALLOC_OBJ_ID) {
+ PyObject_Free(q);
+ }
+ else {
+ _PyMem_Free(q);
+ }
}
void *
@@ -1561,7 +1603,12 @@ _PyObject_DebugReallocApi(char api, void *p, size_t nbytes)
* case we didn't get the chance to mark the old memory with DEADBYTE,
* but we live with that.
*/
- q = (uchar *)PyObject_Realloc(q - 2*SST, total);
+ if (api == _PYMALLOC_OBJ_ID) {
+ q = (uchar *)PyObject_Realloc(q - 2*SST, total);
+ }
+ else {
+ q = (uchar *)_PyMem_Realloc(q - 2*SST, total);
+ }
if (q == NULL) {
if (nbytes <= original_nbytes) {
/* bpo-31626: the memset() above expects that realloc never fails