diff -r 4b97092aa4bd Doc/c-api/memory.rst
--- a/Doc/c-api/memory.rst Sun Apr 27 18:02:35 2014 +0100
+++ b/Doc/c-api/memory.rst Mon Apr 28 11:01:08 2014 +0200
@@ -92,8 +92,8 @@ functions are thread-safe, the :term:`GI
need to be held.
The default raw memory block allocator uses the following functions:
-:c:func:`malloc`, :c:func:`realloc` and :c:func:`free`; call ``malloc(1)`` when
-requesting zero bytes.
+:c:func:`malloc`, :c:func:`calloc`, :c:func:`realloc` and :c:func:`free`; call
+``malloc(1)`` (or ``calloc(1, 1)``) when requesting zero bytes.
.. versionadded:: 3.4
@@ -106,6 +106,17 @@ requesting zero bytes.
been initialized in any way.
+.. c:function:: void* PyMem_RawCalloc(size_t nelem, size_t elsize)
+
+ Allocates *nelem* elements each whose size in bytes is *elsize* and returns
+ a pointer of type :c:type:`void\*` to the allocated memory, or *NULL* if the
+ request fails. The memory is initialized to zeros. Requesting zero elements
+ or elements of size zero bytes returns a distinct non-*NULL* pointer if
+ possible, as if ``PyMem_RawCalloc(1, 1)`` had been called instead.
+
+ .. versionadded:: 3.5
+
+
.. c:function:: void* PyMem_RawRealloc(void *p, size_t n)
Resizes the memory block pointed to by *p* to *n* bytes. The contents will
@@ -136,8 +147,8 @@ behavior when requesting zero bytes, are
memory from the Python heap.
The default memory block allocator uses the following functions:
-:c:func:`malloc`, :c:func:`realloc` and :c:func:`free`; call ``malloc(1)`` when
-requesting zero bytes.
+:c:func:`malloc`, :c:func:`calloc`, :c:func:`realloc` and :c:func:`free`; call
+``malloc(1)`` (or ``calloc(1, 1)``) when requesting zero bytes.
.. warning::
@@ -152,6 +163,17 @@ requesting zero bytes.
been called instead. The memory will not have been initialized in any way.
+.. c:function:: void* PyMem_Calloc(size_t nelem, size_t elsize)
+
+ Allocates *nelem* elements each whose size in bytes is *elsize* and returns
+ a pointer of type :c:type:`void\*` to the allocated memory, or *NULL* if the
+ request fails. The memory is initialized to zeros. Requesting zero elements
+ or elements of size zero bytes returns a distinct non-*NULL* pointer if
+ possible, as if ``PyMem_Calloc(1, 1)`` had been called instead.
+
+ .. versionadded:: 3.5
+
+
.. c:function:: void* PyMem_Realloc(void *p, size_t n)
Resizes the memory block pointed to by *p* to *n* bytes. The contents will be
@@ -222,11 +244,17 @@ Customize Memory Allocators
+----------------------------------------------------------+---------------------------------------+
| ``void* malloc(void *ctx, size_t size)`` | allocate a memory block |
+----------------------------------------------------------+---------------------------------------+
+ | ``void* calloc(void *ctx, size_t nelem, size_t elsize)`` | allocate a memory block initialized |
+ | | with zeros |
+ +----------------------------------------------------------+---------------------------------------+
| ``void* realloc(void *ctx, void *ptr, size_t new_size)`` | allocate or resize a memory block |
+----------------------------------------------------------+---------------------------------------+
| ``void free(void *ctx, void *ptr)`` | free a memory block |
+----------------------------------------------------------+---------------------------------------+
+ .. versionchanged:: 3.5
+ Add a new field ``calloc``.
+
.. c:type:: PyMemAllocatorDomain
Enum used to identify an allocator domain. Domains:
diff -r 4b97092aa4bd Include/objimpl.h
--- a/Include/objimpl.h Sun Apr 27 18:02:35 2014 +0100
+++ b/Include/objimpl.h Mon Apr 28 11:01:08 2014 +0200
@@ -95,6 +95,7 @@ PyObject_{New, NewVar, Del}.
the raw memory.
*/
PyAPI_FUNC(void *) PyObject_Malloc(size_t size);
+PyAPI_FUNC(void *) PyObject_Calloc(size_t nelem, size_t elsize);
PyAPI_FUNC(void *) PyObject_Realloc(void *ptr, size_t new_size);
PyAPI_FUNC(void) PyObject_Free(void *ptr);
@@ -321,7 +322,8 @@ extern PyGC_Head *_PyGC_generation0;
(!PyTuple_CheckExact(obj) || _PyObject_GC_IS_TRACKED(obj)))
#endif /* Py_LIMITED_API */
-PyAPI_FUNC(PyObject *) _PyObject_GC_Malloc(size_t);
+PyAPI_FUNC(PyObject *) _PyObject_GC_Malloc(size_t size);
+PyAPI_FUNC(PyObject *) _PyObject_GC_Calloc(size_t size);
PyAPI_FUNC(PyObject *) _PyObject_GC_New(PyTypeObject *);
PyAPI_FUNC(PyVarObject *) _PyObject_GC_NewVar(PyTypeObject *, Py_ssize_t);
PyAPI_FUNC(void) PyObject_GC_Track(void *);
diff -r 4b97092aa4bd Include/pymem.h
--- a/Include/pymem.h Sun Apr 27 18:02:35 2014 +0100
+++ b/Include/pymem.h Mon Apr 28 11:01:08 2014 +0200
@@ -13,6 +13,7 @@ extern "C" {
#ifndef Py_LIMITED_API
PyAPI_FUNC(void *) PyMem_RawMalloc(size_t size);
+PyAPI_FUNC(void *) PyMem_RawCalloc(size_t nelem, size_t elsize);
PyAPI_FUNC(void *) PyMem_RawRealloc(void *ptr, size_t new_size);
PyAPI_FUNC(void) PyMem_RawFree(void *ptr);
#endif
@@ -57,6 +58,7 @@ PyAPI_FUNC(void) PyMem_RawFree(void *ptr
*/
PyAPI_FUNC(void *) PyMem_Malloc(size_t size);
+PyAPI_FUNC(void *) PyMem_Calloc(size_t nelem, size_t elsize);
PyAPI_FUNC(void *) PyMem_Realloc(void *ptr, size_t new_size);
PyAPI_FUNC(void) PyMem_Free(void *ptr);
@@ -132,6 +134,9 @@ typedef struct {
/* allocate a memory block */
void* (*malloc) (void *ctx, size_t size);
+ /* allocate a memory block initialized by zeros */
+ void* (*calloc) (void *ctx, size_t nelem, size_t elsize);
+
/* allocate or resize a memory block */
void* (*realloc) (void *ctx, void *ptr, size_t new_size);
diff -r 4b97092aa4bd Modules/_testcapimodule.c
--- a/Modules/_testcapimodule.c Sun Apr 27 18:02:35 2014 +0100
+++ b/Modules/_testcapimodule.c Mon Apr 28 11:01:08 2014 +0200
@@ -2710,6 +2710,20 @@ test_pymem_alloc0(PyObject *self)
{
void *ptr;
+ ptr = PyMem_RawMalloc(0);
+ if (ptr == NULL) {
+ PyErr_SetString(PyExc_RuntimeError, "PyMem_RawMalloc(0) returns NULL");
+ return NULL;
+ }
+ PyMem_RawFree(ptr);
+
+ ptr = PyMem_RawCalloc(0, 0);
+ if (ptr == NULL) {
+ PyErr_SetString(PyExc_RuntimeError, "PyMem_RawCalloc(0, 0) returns NULL");
+ return NULL;
+ }
+ PyMem_RawFree(ptr);
+
ptr = PyMem_Malloc(0);
if (ptr == NULL) {
PyErr_SetString(PyExc_RuntimeError, "PyMem_Malloc(0) returns NULL");
@@ -2717,6 +2731,13 @@ test_pymem_alloc0(PyObject *self)
}
PyMem_Free(ptr);
+ ptr = PyMem_Calloc(0, 0);
+ if (ptr == NULL) {
+ PyErr_SetString(PyExc_RuntimeError, "PyMem_Calloc(0, 0) returns NULL");
+ return NULL;
+ }
+ PyMem_Free(ptr);
+
ptr = PyObject_Malloc(0);
if (ptr == NULL) {
PyErr_SetString(PyExc_RuntimeError, "PyObject_Malloc(0) returns NULL");
@@ -2724,6 +2745,13 @@ test_pymem_alloc0(PyObject *self)
}
PyObject_Free(ptr);
+ ptr = PyObject_Calloc(0, 0);
+ if (ptr == NULL) {
+ PyErr_SetString(PyExc_RuntimeError, "PyObject_Calloc(0, 0) returns NULL");
+ return NULL;
+ }
+ PyObject_Free(ptr);
+
Py_RETURN_NONE;
}
@@ -2731,6 +2759,8 @@ typedef struct {
PyMemAllocator alloc;
size_t malloc_size;
+ size_t calloc_nelem;
+ size_t calloc_elsize;
void *realloc_ptr;
size_t realloc_new_size;
void *free_ptr;
@@ -2743,6 +2773,14 @@ static void* hook_malloc (void* ctx, siz
return hook->alloc.malloc(hook->alloc.ctx, size);
}
+static void* hook_calloc (void* ctx, size_t nelem, size_t elsize)
+{
+ alloc_hook_t *hook = (alloc_hook_t *)ctx;
+ hook->calloc_nelem = nelem;
+ hook->calloc_elsize = elsize;
+ return hook->alloc.calloc(hook->alloc.ctx, nelem, elsize);
+}
+
static void* hook_realloc (void* ctx, void* ptr, size_t new_size)
{
alloc_hook_t *hook = (alloc_hook_t *)ctx;
@@ -2765,16 +2803,14 @@ test_setallocators(PyMemAllocatorDomain
const char *error_msg;
alloc_hook_t hook;
PyMemAllocator alloc;
- size_t size, size2;
+ size_t size, size2, nelem, elsize;
void *ptr, *ptr2;
- hook.malloc_size = 0;
- hook.realloc_ptr = NULL;
- hook.realloc_new_size = 0;
- hook.free_ptr = NULL;
+ memset(&hook, 0, sizeof(hook));
alloc.ctx = &hook;
alloc.malloc = &hook_malloc;
+ alloc.calloc = &hook_calloc;
alloc.realloc = &hook_realloc;
alloc.free = &hook_free;
PyMem_GetAllocator(domain, &hook.alloc);
@@ -2831,6 +2867,33 @@ test_setallocators(PyMemAllocatorDomain
goto fail;
}
+ nelem = 2;
+ elsize = 5;
+ switch(domain)
+ {
+ case PYMEM_DOMAIN_RAW: ptr = PyMem_RawCalloc(nelem, elsize); break;
+ case PYMEM_DOMAIN_MEM: ptr = PyMem_Calloc(nelem, elsize); break;
+ case PYMEM_DOMAIN_OBJ: ptr = PyObject_Calloc(nelem, elsize); break;
+ default: ptr = NULL; break;
+ }
+
+ if (ptr == NULL) {
+ error_msg = "calloc failed";
+ goto fail;
+ }
+
+ if (hook.calloc_nelem != nelem || hook.calloc_elsize != elsize) {
+ error_msg = "calloc invalid nelem or elsize";
+ goto fail;
+ }
+
+ switch(domain)
+ {
+ case PYMEM_DOMAIN_RAW: PyMem_RawFree(ptr); break;
+ case PYMEM_DOMAIN_MEM: PyMem_Free(ptr); break;
+ case PYMEM_DOMAIN_OBJ: PyObject_Free(ptr); break;
+ }
+
Py_INCREF(Py_None);
res = Py_None;
goto finally;
diff -r 4b97092aa4bd Modules/_tracemalloc.c
--- a/Modules/_tracemalloc.c Sun Apr 27 18:02:35 2014 +0100
+++ b/Modules/_tracemalloc.c Mon Apr 28 11:01:08 2014 +0200
@@ -476,17 +476,24 @@ tracemalloc_remove_trace(void *ptr)
}
static void*
-tracemalloc_malloc(void *ctx, size_t size)
+tracemalloc_alloc(void *ctx, size_t nelem, size_t elsize, int zero)
{
PyMemAllocator *alloc = (PyMemAllocator *)ctx;
void *ptr;
- ptr = alloc->malloc(alloc->ctx, size);
+ assert(nelem <= PY_SIZE_MAX / elsize);
+
+ if (zero)
+ ptr = alloc->calloc(alloc->ctx, nelem, elsize);
+ else {
+ assert(nelem == 1);
+ ptr = alloc->malloc(alloc->ctx, elsize);
+ }
if (ptr == NULL)
return NULL;
TABLES_LOCK();
- if (tracemalloc_add_trace(ptr, size) < 0) {
+ if (tracemalloc_add_trace(ptr, nelem * elsize) < 0) {
/* Failed to allocate a trace for the new memory block */
TABLES_UNLOCK();
alloc->free(alloc->ctx, ptr);
@@ -560,13 +567,18 @@ tracemalloc_free(void *ctx, void *ptr)
}
static void*
-tracemalloc_malloc_gil(void *ctx, size_t size)
+tracemalloc_alloc_gil(void *ctx, size_t nelem, size_t elsize, int zero)
{
void *ptr;
if (get_reentrant()) {
PyMemAllocator *alloc = (PyMemAllocator *)ctx;
- return alloc->malloc(alloc->ctx, size);
+ if (zero)
+ return alloc->calloc(alloc->ctx, nelem, elsize);
+ else {
+ assert(nelem == 1);
+ return alloc->malloc(alloc->ctx, elsize);
+ }
}
/* Ignore reentrant call. PyObjet_Malloc() calls PyMem_Malloc() for
@@ -574,13 +586,25 @@ tracemalloc_malloc_gil(void *ctx, size_t
allocation twice. */
set_reentrant(1);
- ptr = tracemalloc_malloc(ctx, size);
+ ptr = tracemalloc_alloc(ctx, nelem, elsize, zero);
set_reentrant(0);
return ptr;
}
static void*
+tracemalloc_malloc_gil(void *ctx, size_t size)
+{
+ return tracemalloc_alloc_gil(ctx, 1, size, 0);
+}
+
+static void*
+tracemalloc_calloc_gil(void *ctx, size_t nelem, size_t elsize)
+{
+ return tracemalloc_alloc_gil(ctx, nelem, elsize, 1);
+}
+
+static void*
tracemalloc_realloc_gil(void *ctx, void *ptr, size_t new_size)
{
void *ptr2;
@@ -614,7 +638,7 @@ tracemalloc_realloc_gil(void *ctx, void
#ifdef TRACE_RAW_MALLOC
static void*
-tracemalloc_raw_malloc(void *ctx, size_t size)
+tracemalloc_raw_alloc(void *ctx, size_t nelem, size_t elsize, int zero)
{
#ifdef WITH_THREAD
PyGILState_STATE gil_state;
@@ -623,7 +647,12 @@ tracemalloc_raw_malloc(void *ctx, size_t
if (get_reentrant()) {
PyMemAllocator *alloc = (PyMemAllocator *)ctx;
- return alloc->malloc(alloc->ctx, size);
+ if (zero)
+ return alloc->calloc(alloc->ctx, nelem, elsize);
+ else {
+ assert(nelem == 1);
+ return alloc->malloc(alloc->ctx, elsize);
+ }
}
/* Ignore reentrant call. PyGILState_Ensure() may call PyMem_RawMalloc()
@@ -633,10 +662,10 @@ tracemalloc_raw_malloc(void *ctx, size_t
#ifdef WITH_THREAD
gil_state = PyGILState_Ensure();
- ptr = tracemalloc_malloc(ctx, size);
+ ptr = tracemalloc_alloc(ctx, nelem, elsize, zero);
PyGILState_Release(gil_state);
#else
- ptr = tracemalloc_malloc(ctx, size);
+ ptr = tracemalloc_alloc(ctx, nelem, elsize, zero);
#endif
set_reentrant(0);
@@ -644,6 +673,18 @@ tracemalloc_raw_malloc(void *ctx, size_t
}
static void*
+tracemalloc_raw_malloc(void *ctx, size_t size)
+{
+ return tracemalloc_raw_alloc(ctx, 1, size, 0);
+}
+
+static void*
+tracemalloc_raw_calloc(void *ctx, size_t nelem, size_t elsize)
+{
+ return tracemalloc_raw_alloc(ctx, nelem, elsize, 1);
+}
+
+static void*
tracemalloc_raw_realloc(void *ctx, void *ptr, size_t new_size)
{
#ifdef WITH_THREAD
@@ -856,6 +897,7 @@ tracemalloc_start(int max_nframe)
#ifdef TRACE_RAW_MALLOC
alloc.malloc = tracemalloc_raw_malloc;
+ alloc.calloc = tracemalloc_raw_calloc;
alloc.realloc = tracemalloc_raw_realloc;
alloc.free = tracemalloc_free;
@@ -865,6 +907,7 @@ tracemalloc_start(int max_nframe)
#endif
alloc.malloc = tracemalloc_malloc_gil;
+ alloc.calloc = tracemalloc_calloc_gil;
alloc.realloc = tracemalloc_realloc_gil;
alloc.free = tracemalloc_free;
diff -r 4b97092aa4bd Modules/gcmodule.c
--- a/Modules/gcmodule.c Sun Apr 27 18:02:35 2014 +0100
+++ b/Modules/gcmodule.c Mon Apr 28 11:01:08 2014 +0200
@@ -1703,15 +1703,19 @@ PyObject_GC_UnTrack(void *op)
_PyObject_GC_UNTRACK(op);
}
-PyObject *
-_PyObject_GC_Malloc(size_t basicsize)
+static PyObject *
+_PyObject_GC_Alloc(size_t basicsize, int zero)
{
PyObject *op;
PyGC_Head *g;
+ size_t size;
if (basicsize > PY_SSIZE_T_MAX - sizeof(PyGC_Head))
return PyErr_NoMemory();
- g = (PyGC_Head *)PyObject_MALLOC(
- sizeof(PyGC_Head) + basicsize);
+ size = sizeof(PyGC_Head) + basicsize;
+ if (zero)
+ g = (PyGC_Head *)PyObject_Calloc(1, size);
+ else
+ g = (PyGC_Head *)PyObject_Malloc(size);
if (g == NULL)
return PyErr_NoMemory();
g->gc.gc_refs = 0;
@@ -1731,6 +1735,18 @@ PyObject *
}
PyObject *
+_PyObject_GC_Malloc(size_t basicsize)
+{
+ return _PyObject_GC_Alloc(basicsize, 0);
+}
+
+PyObject *
+_PyObject_GC_Calloc(size_t basicsize)
+{
+ return _PyObject_GC_Alloc(basicsize, 1);
+}
+
+PyObject *
_PyObject_GC_New(PyTypeObject *tp)
{
PyObject *op = _PyObject_GC_Malloc(_PyObject_SIZE(tp));
diff -r 4b97092aa4bd Objects/bytearrayobject.c
--- a/Objects/bytearrayobject.c Sun Apr 27 18:02:35 2014 +0100
+++ b/Objects/bytearrayobject.c Mon Apr 28 11:01:08 2014 +0200
@@ -813,9 +813,21 @@ bytearray_init(PyByteArrayObject *self,
}
else {
if (count > 0) {
- if (PyByteArray_Resize((PyObject *)self, count))
+ void *sval;
+ Py_ssize_t alloc;
+
+ assert (Py_SIZE(self) == 0);
+
+ alloc = count + 1;
+ sval = PyObject_Calloc(1, alloc);
+ if (sval == NULL)
return -1;
- memset(PyByteArray_AS_STRING(self), 0, count);
+
+ PyObject_Free(self->ob_bytes);
+
+ self->ob_bytes = self->ob_start = sval;
+ Py_SIZE(self) = count;
+ self->ob_alloc = alloc;
}
return 0;
}
diff -r 4b97092aa4bd Objects/bytesobject.c
--- a/Objects/bytesobject.c Sun Apr 27 18:02:35 2014 +0100
+++ b/Objects/bytesobject.c Mon Apr 28 11:01:08 2014 +0200
@@ -71,6 +71,44 @@ static PyBytesObject *nullstring;
PyBytes_FromStringAndSize()) or the length of the string in the `str'
parameter (for PyBytes_FromString()).
*/
+static PyObject *
+_PyBytes_FromSize(Py_ssize_t size, int zero)
+{
+ PyBytesObject *op;
+ assert(size >= 0);
+ if (size == 0 && (op = nullstring) != NULL) {
+#ifdef COUNT_ALLOCS
+ null_strings++;
+#endif
+ Py_INCREF(op);
+ return (PyObject *)op;
+ }
+
+ if (size > PY_SSIZE_T_MAX - PyBytesObject_SIZE) {
+ PyErr_SetString(PyExc_OverflowError,
+ "byte string is too large");
+ return NULL;
+ }
+
+ /* Inline PyObject_NewVar */
+ if (zero)
+ op = (PyBytesObject *)PyObject_Calloc(1, PyBytesObject_SIZE + size);
+ else
+ op = (PyBytesObject *)PyObject_Malloc(PyBytesObject_SIZE + size);
+ if (op == NULL)
+ return PyErr_NoMemory();
+ (void)PyObject_INIT_VAR(op, &PyBytes_Type, size);
+ op->ob_shash = -1;
+ if (!zero)
+ op->ob_sval[size] = '\0';
+ /* empty byte string singleton */
+ if (size == 0) {
+ nullstring = op;
+ Py_INCREF(op);
+ }
+ return (PyObject *) op;
+}
+
PyObject *
PyBytes_FromStringAndSize(const char *str, Py_ssize_t size)
{
@@ -80,13 +118,6 @@ PyBytes_FromStringAndSize(const char *st
"Negative size passed to PyBytes_FromStringAndSize");
return NULL;
}
- if (size == 0 && (op = nullstring) != NULL) {
-#ifdef COUNT_ALLOCS
- null_strings++;
-#endif
- Py_INCREF(op);
- return (PyObject *)op;
- }
if (size == 1 && str != NULL &&
(op = characters[*str & UCHAR_MAX]) != NULL)
{
@@ -97,26 +128,15 @@ PyBytes_FromStringAndSize(const char *st
return (PyObject *)op;
}
- if (size > PY_SSIZE_T_MAX - PyBytesObject_SIZE) {
- PyErr_SetString(PyExc_OverflowError,
- "byte string is too large");
+ op = (PyBytesObject *)_PyBytes_FromSize(size, 0);
+ if (op == NULL)
return NULL;
- }
-
- /* Inline PyObject_NewVar */
- op = (PyBytesObject *)PyObject_MALLOC(PyBytesObject_SIZE + size);
- if (op == NULL)
- return PyErr_NoMemory();
- (void)PyObject_INIT_VAR(op, &PyBytes_Type, size);
- op->ob_shash = -1;
- if (str != NULL)
- Py_MEMCPY(op->ob_sval, str, size);
- op->ob_sval[size] = '\0';
+ if (str == NULL)
+ return (PyObject *) op;
+
+ Py_MEMCPY(op->ob_sval, str, size);
/* share short strings */
- if (size == 0) {
- nullstring = op;
- Py_INCREF(op);
- } else if (size == 1 && str != NULL) {
+ if (size == 1) {
characters[*str & UCHAR_MAX] = op;
Py_INCREF(op);
}
@@ -2482,7 +2502,7 @@ bytes_new(PyTypeObject *type, PyObject *
"argument");
return NULL;
}
- return PyBytes_FromString("");
+ return PyBytes_FromStringAndSize(NULL, 0);
}
if (PyUnicode_Check(x)) {
@@ -2532,11 +2552,9 @@ bytes_new(PyTypeObject *type, PyObject *
return NULL;
}
else {
- new = PyBytes_FromStringAndSize(NULL, size);
+ new = _PyBytes_FromSize(size, 1);
if (new == NULL)
return NULL;
- if (size > 0)
- memset(((PyBytesObject*)new)->ob_sval, 0, size);
return new;
}
diff -r 4b97092aa4bd Objects/obmalloc.c
--- a/Objects/obmalloc.c Sun Apr 27 18:02:35 2014 +0100
+++ b/Objects/obmalloc.c Mon Apr 28 11:01:08 2014 +0200
@@ -5,6 +5,7 @@
#ifdef PYMALLOC_DEBUG /* WITH_PYMALLOC && PYMALLOC_DEBUG */
/* Forward declaration */
static void* _PyMem_DebugMalloc(void *ctx, size_t size);
+static void* _PyMem_DebugCalloc(void *ctx, size_t nelem, size_t elsize);
static void _PyMem_DebugFree(void *ctx, void *p);
static void* _PyMem_DebugRealloc(void *ctx, void *ptr, size_t size);
@@ -43,6 +44,7 @@ static void _PyMem_DebugCheckAddress(cha
/* Forward declaration */
static void* _PyObject_Malloc(void *ctx, size_t size);
+static void* _PyObject_Calloc(void *ctx, size_t nelem, size_t elsize);
static void _PyObject_Free(void *ctx, void *p);
static void* _PyObject_Realloc(void *ctx, void *ptr, size_t size);
#endif
@@ -51,7 +53,7 @@ static void* _PyObject_Realloc(void *ctx
static void *
_PyMem_RawMalloc(void *ctx, size_t size)
{
- /* PyMem_Malloc(0) means malloc(1). Some systems would return NULL
+ /* PyMem_RawMalloc(0) means malloc(1). Some systems would return NULL
for malloc(0), which would be treated as an error. Some platforms would
return a pointer with no memory behind it, which would break pymalloc.
To solve these problems, allocate an extra byte. */
@@ -61,6 +63,20 @@ static void *
}
static void *
+_PyMem_RawCalloc(void *ctx, size_t nelem, size_t elsize)
+{
+ /* PyMem_RawCalloc(0, 0) means calloc(1, 1). Some systems would return NULL
+ for calloc(0, 0), which would be treated as an error. Some platforms
+ would return a pointer with no memory behind it, which would break
+ pymalloc. To solve these problems, allocate an extra byte. */
+ if (nelem == 0 || elsize == 0) {
+ nelem = 1;
+ elsize = 1;
+ }
+ return calloc(nelem, elsize);
+}
+
+static void *
_PyMem_RawRealloc(void *ctx, void *ptr, size_t size)
{
if (size == 0)
@@ -123,9 +139,9 @@ static void
#endif
-#define PYRAW_FUNCS _PyMem_RawMalloc, _PyMem_RawRealloc, _PyMem_RawFree
+#define PYRAW_FUNCS _PyMem_RawMalloc, _PyMem_RawCalloc, _PyMem_RawRealloc, _PyMem_RawFree
#ifdef WITH_PYMALLOC
-# define PYOBJ_FUNCS _PyObject_Malloc, _PyObject_Realloc, _PyObject_Free
+# define PYOBJ_FUNCS _PyObject_Malloc, _PyObject_Calloc, _PyObject_Realloc, _PyObject_Free
#else
# define PYOBJ_FUNCS PYRAW_FUNCS
#endif
@@ -147,7 +163,7 @@ static struct {
{'o', {NULL, PYOBJ_FUNCS}}
};
-#define PYDBG_FUNCS _PyMem_DebugMalloc, _PyMem_DebugRealloc, _PyMem_DebugFree
+#define PYDBG_FUNCS _PyMem_DebugMalloc, _PyMem_DebugCalloc, _PyMem_DebugRealloc, _PyMem_DebugFree
#endif
static PyMemAllocator _PyMem_Raw = {
@@ -196,6 +212,7 @@ PyMem_SetupDebugHooks(void)
PyMemAllocator alloc;
alloc.malloc = _PyMem_DebugMalloc;
+ alloc.calloc = _PyMem_DebugCalloc;
alloc.realloc = _PyMem_DebugRealloc;
alloc.free = _PyMem_DebugFree;
@@ -228,11 +245,8 @@ PyMem_GetAllocator(PyMemAllocatorDomain
case PYMEM_DOMAIN_MEM: *allocator = _PyMem; break;
case PYMEM_DOMAIN_OBJ: *allocator = _PyObject; break;
default:
- /* unknown domain */
- allocator->ctx = NULL;
- allocator->malloc = NULL;
- allocator->realloc = NULL;
- allocator->free = NULL;
+ /* unknown domain: set all attributes to NULL */
+ memset(allocator, 0, sizeof(*allocator));
}
}
@@ -272,8 +286,16 @@ PyMem_RawMalloc(size_t size)
*/
if (size > (size_t)PY_SSIZE_T_MAX)
return NULL;
+ return _PyMem_Raw.malloc(_PyMem_Raw.ctx, size);
+}
- return _PyMem_Raw.malloc(_PyMem_Raw.ctx, size);
+void *
+PyMem_RawCalloc(size_t nelem, size_t elsize)
+{
+ /* see PyMem_RawMalloc() */
+ if (elsize != 0 && nelem > (size_t)PY_SSIZE_T_MAX / elsize)
+ return NULL;
+ return _PyMem_Raw.calloc(_PyMem_Raw.ctx, nelem, elsize);
}
void*
@@ -300,6 +322,15 @@ PyMem_Malloc(size_t size)
}
void *
+PyMem_Calloc(size_t nelem, size_t elsize)
+{
+ /* see PyMem_RawMalloc() */
+ if (elsize != 0 && nelem > (size_t)PY_SSIZE_T_MAX / elsize)
+ return NULL;
+ return _PyMem.calloc(_PyMem.ctx, nelem, elsize);
+}
+
+void *
PyMem_Realloc(void *ptr, size_t new_size)
{
/* see PyMem_RawMalloc() */
@@ -352,6 +383,15 @@ PyObject_Malloc(size_t size)
}
void *
+PyObject_Calloc(size_t nelem, size_t elsize)
+{
+ /* see PyMem_RawMalloc() */
+ if (elsize != 0 && nelem > (size_t)PY_SSIZE_T_MAX / elsize)
+ return NULL;
+ return _PyObject.calloc(_PyObject.ctx, nelem, elsize);
+}
+
+void *
PyObject_Realloc(void *ptr, size_t new_size)
{
/* see PyMem_RawMalloc() */
@@ -1122,8 +1162,9 @@ int Py_ADDRESS_IN_RANGE(void *P, poolp p
*/
static void *
-_PyObject_Malloc(void *ctx, size_t nbytes)
+_PyObject_Alloc(void *ctx, size_t nelem, size_t elsize, int zero)
{
+ size_t nbytes;
block *bp;
poolp pool;
poolp next;
@@ -1138,9 +1179,12 @@ static void *
goto redirect;
#endif
- /*
- * This implicitly redirects malloc(0).
- */
+ if (nelem == 0 || elsize == 0)
+ goto redirect;
+
+ assert(nelem <= PY_SSIZE_T_MAX / elsize);
+ nbytes = nelem * elsize;
+
if ((nbytes - 1) < SMALL_REQUEST_THRESHOLD) {
LOCK();
/*
@@ -1158,6 +1202,8 @@ static void *
assert(bp != NULL);
if ((pool->freeblock = *(block **)bp) != NULL) {
UNLOCK();
+ if (zero)
+ memset(bp, 0, nbytes);
return (void *)bp;
}
/*
@@ -1170,6 +1216,8 @@ static void *
pool->nextoffset += INDEX2SIZE(size);
*(block **)(pool->freeblock) = NULL;
UNLOCK();
+ if (zero)
+ memset(bp, 0, nbytes);
return (void *)bp;
}
/* Pool is full, unlink from used pools. */
@@ -1178,6 +1226,8 @@ static void *
next->prevpool = pool;
pool->nextpool = next;
UNLOCK();
+ if (zero)
+ memset(bp, 0, nbytes);
return (void *)bp;
}
@@ -1257,6 +1307,8 @@ static void *
assert(bp != NULL);
pool->freeblock = *(block **)bp;
UNLOCK();
+ if (zero)
+ memset(bp, 0, nbytes);
return (void *)bp;
}
/*
@@ -1272,6 +1324,8 @@ static void *
pool->freeblock = bp + size;
*(block **)(pool->freeblock) = NULL;
UNLOCK();
+ if (zero)
+ memset(bp, 0, nbytes);
return (void *)bp;
}
@@ -1311,13 +1365,31 @@ redirect:
* has been reached.
*/
{
- void *result = PyMem_RawMalloc(nbytes);
+ void *result;
+ if (zero)
+ result = PyMem_RawCalloc(nelem, elsize);
+ else {
+ assert(nelem == 1);
+ result = PyMem_RawMalloc(elsize);
+ }
if (!result)
_Py_AllocatedBlocks--;
return result;
}
}
+static void *
+_PyObject_Malloc(void *ctx, size_t nbytes)
+{
+ return _PyObject_Alloc(ctx, 1, nbytes, 0);
+}
+
+static void *
+_PyObject_Calloc(void *ctx, size_t nelem, size_t elsize)
+{
+ return _PyObject_Alloc(ctx, nelem, elsize, 1);
+}
+
/* free */
ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS
@@ -1561,7 +1633,7 @@ static void *
#endif
if (p == NULL)
- return _PyObject_Malloc(ctx, nbytes);
+ return _PyObject_Alloc(ctx, 1, nbytes, 0);
#ifdef WITH_VALGRIND
/* Treat running_on_valgrind == -1 the same as 0 */
@@ -1589,7 +1661,7 @@ static void *
}
size = nbytes;
}
- bp = _PyObject_Malloc(ctx, nbytes);
+ bp = _PyObject_Alloc(ctx, 1, nbytes, 0);
if (bp != NULL) {
memcpy(bp, p, size);
_PyObject_Free(ctx, p);
@@ -1745,7 +1817,7 @@ p[2*S+n+S: 2*S+n+2*S]
*/
static void *
-_PyMem_DebugMalloc(void *ctx, size_t nbytes)
+_PyMem_DebugAlloc(void *ctx, size_t nbytes, int zero)
{
debug_alloc_api_t *api = (debug_alloc_api_t *)ctx;
uchar *p; /* base address of malloc'ed block */
@@ -1758,7 +1830,10 @@ static void *
/* overflow: can't represent total as a size_t */
return NULL;
- p = (uchar *)api->alloc.malloc(api->alloc.ctx, total);
+ if (zero)
+ p = (uchar *)api->alloc.calloc(api->alloc.ctx, 1, total);
+ else
+ p = (uchar *)api->alloc.malloc(api->alloc.ctx, total);
if (p == NULL)
return NULL;
@@ -1767,7 +1842,7 @@ static void *
p[SST] = (uchar)api->api_id;
memset(p + SST + 1, FORBIDDENBYTE, SST-1);
- if (nbytes > 0)
+ if (nbytes > 0 && !zero)
memset(p + 2*SST, CLEANBYTE, nbytes);
/* at tail, write pad (SST bytes) and serialno (SST bytes) */
@@ -1778,6 +1853,21 @@ static void *
return p + 2*SST;
}
+static void *
+_PyMem_DebugMalloc(void *ctx, size_t nbytes)
+{
+ return _PyMem_DebugAlloc(ctx, nbytes, 0);
+}
+
+static void *
+_PyMem_DebugCalloc(void *ctx, size_t nelem, size_t elsize)
+{
+ size_t nbytes;
+ assert(elsize == 0 || nelem <= PY_SSIZE_T_MAX / elsize);
+ nbytes = nelem * elsize;
+ return _PyMem_DebugAlloc(ctx, nbytes, 1);
+}
+
/* The debug free first checks the 2*SST bytes on each end for sanity (in
particular, that the FORBIDDENBYTEs with the api ID are still intact).
Then fills the original bytes with DEADBYTE.
@@ -1811,7 +1901,7 @@ static void *
int i;
if (p == NULL)
- return _PyMem_DebugMalloc(ctx, nbytes);
+ return _PyMem_DebugAlloc(ctx, nbytes, 0);
_PyMem_DebugCheckAddress(api->api_id, p);
bumpserialno();