From af3e8de580ba756e820171253a5b580318914b79 Mon Sep 17 00:00:00 2001 From: Tim Peters Date: Fri, 12 Apr 2002 07:22:56 +0000 Subject: First stab at rationalizing the PyMem_ API. Mixing PyObject_xyz with PyMem_{Del, DEL} doesn't work yet (compilation problems). pyport.h: _PyMem_EXTRA is gone. pmem.h: Repaired comments. PyMem_{Malloc, MALLOC} and PyMem_{Realloc, REALLOC} now make the same x-platform guarantees when asking for 0 bytes, and when passing a NULL pointer to the latter. object.c: PyMem_{Malloc, Realloc} just call their macro versions now, since the latter take care of the x-platform 0 and NULL stuff by themselves now. pypcre.c, grow_stack(): So sue me. On two lines, this called PyMem_RESIZE to grow a "const" area. It's not legit to realloc a const area, so the compiler warned given the new expansion of PyMem_RESIZE. It would have gotten the same warning before if it had used PyMem_Resize() instead; the older macro version, but not the function version, silently cast away the constness. IMO that was a wrong thing to do, and the docs say the macro versions of PyMem_xyz are deprecated anyway. If somebody else is resizing const areas with the macro spelling, they'll get a warning when they recompile now too. --- Include/pymem.h | 95 ++++++++++++++++++++++++++++++++------------------------ Include/pyport.h | 22 ------------- Modules/pypcre.c | 7 +++-- Objects/object.c | 7 +---- 4 files changed, 61 insertions(+), 70 deletions(-) diff --git a/Include/pymem.h b/Include/pymem.h index b9c5d2c..3b9c0e2 100644 --- a/Include/pymem.h +++ b/Include/pymem.h @@ -18,30 +18,32 @@ extern "C" { Python runtime switches to its own malloc (different from standard malloc), no recompilation is required for the extensions. - The macro versions trade compatibility for speed. They can be used - whenever there is a performance problem, but their use implies - recompilation of the code for each new Python release. The Python - core uses the macros because it *is* compiled on every upgrade. - This might not be the case with 3rd party extensions in a custom - setup (for example, a customer does not always have access to the - source of 3rd party deliverables). You have been warned! */ + The macro versions are free to trade compatibility for speed, although + there's no guarantee they're ever faster. Extensions shouldn't use the + macro versions, as they don't gurantee binary compatibility across + releases. + + Do not mix calls to PyMem_xyz with calls to platform + malloc/realloc/calloc/free. */ /* * Raw memory interface * ==================== */ -/* To make sure the interpreter is user-malloc friendly, all memory - APIs are implemented on top of this one. */ - /* Functions */ -/* Function wrappers around PyMem_MALLOC and friends; useful if you - need to be sure that you are using the same memory allocator as - Python. Note that the wrappers make sure that allocating 0 bytes - returns a non-NULL pointer, even if the underlying malloc - doesn't. Returned pointers must be checked for NULL explicitly. - No action is performed on failure. */ +/* Functions supplying platform-independent semantics for malloc/realloc/ + free; useful if you need to be sure you're using the same memory + allocator as Python (this can be especially important on Windows, if + you need to make sure you're using the same MS malloc/free, and out of + the same heap, as the main Python DLL uses). + These functions make sure that allocating 0 bytes returns a distinct + non-NULL pointer (whenever possible -- if we're flat out of memory, NULL + may be returned), even if the platform malloc and realloc don't. + Returned pointers must be checked for NULL explicitly. No action is + performed on failure (no exception is set, no warning is printed, etc).` */ + extern DL_IMPORT(void *) PyMem_Malloc(size_t); extern DL_IMPORT(void *) PyMem_Realloc(void *, size_t); extern DL_IMPORT(void) PyMem_Free(void *); @@ -49,16 +51,29 @@ extern DL_IMPORT(void) PyMem_Free(void *); /* Starting from Python 1.6, the wrappers Py_{Malloc,Realloc,Free} are no longer supported. They used to call PyErr_NoMemory() on failure. */ -/* Macros (override these if you want to a different malloc */ +/* Macros. */ #ifndef PyMem_MALLOC -#define PyMem_MALLOC(n) malloc(n) -#define PyMem_REALLOC(p, n) realloc((void *)(p), (n)) -#define PyMem_FREE(p) free((void *)(p)) +#ifdef MALLOC_ZERO_RETURNS_NULL +#define PyMem_MALLOC(n) malloc((n) ? (n) : 1) +#else +#define PyMem_MALLOC malloc #endif +/* Caution: whether MALLOC_ZERO_RETURNS_NULL is #defined has nothing to + do with whether platform realloc(non-NULL, 0) normally frees the memory + or returns NULL. Rather than introduce yet another config variation, + just make a realloc to 0 bytes act as if to 1 instead. */ +#define PyMem_REALLOC(p, n) realloc((p), (n) ? (n) : 1) + +#define PyMem_FREE free +#endif /* PyMem_MALLOC */ + /* * Type-oriented memory interface * ============================== + * + * These are carried along for historical reasons. There's rarely a good + * reason to use them anymore. */ /* Functions */ @@ -66,29 +81,29 @@ extern DL_IMPORT(void) PyMem_Free(void *); ( (type *) PyMem_Malloc((n) * sizeof(type)) ) #define PyMem_Resize(p, type, n) \ ( (p) = (type *) PyMem_Realloc((p), (n) * sizeof(type)) ) -#define PyMem_Del(p) PyMem_Free(p) + +/* In order to avoid breaking old code mixing PyObject_{New, NEW} with + PyMem_{Del, DEL} (there was no choice about this in 1.5.2), the latter + have to be redirected to the object allocator. */ +/* XXX The parser module needs rework before this can be enabled. */ +#if 0 +#define PyMem_Del PyObject_Free +#else +#define PyMem_Del PyMem_Free +#endif /* Macros */ #define PyMem_NEW(type, n) \ - ( (type *) PyMem_MALLOC(_PyMem_EXTRA + (n) * sizeof(type)) ) - -/* See comment near MALLOC_ZERO_RETURNS_NULL in pyport.h. */ -#define PyMem_RESIZE(p, type, n) \ - do { \ - size_t _sum = (n) * sizeof(type); \ - if (!_sum) \ - _sum = 1; \ - (p) = (type *)((p) ? \ - PyMem_REALLOC(p, _sum) : \ - PyMem_MALLOC(_sum)); \ - } while (0) - -#define PyMem_DEL(p) PyMem_FREE(p) - -/* PyMem_XDEL is deprecated. To avoid the call when p is NULL, - it is recommended to write the test explicitly in the code. - Note that according to ANSI C, free(NULL) has no effect. */ - + ( (type *) PyMem_MALLOC((n) * sizeof(type)) ) +#define PyMem_RESIZE(p, type, n) \ + ( (p) = (type *) PyMem_REALLOC((p), (n) * sizeof(type)) ) + +/* XXX The parser module needs rework before this can be enabled. */ +#if 0 +#define PyMem_DEL PyObject_FREE +#else +#define PyMem_DEL PyMem_FREE +#endif #ifdef __cplusplus } diff --git a/Include/pyport.h b/Include/pyport.h index 86bbab2..790c7af 100644 --- a/Include/pyport.h +++ b/Include/pyport.h @@ -384,32 +384,10 @@ extern int fsync(int fd); extern double hypot(double, double); #endif - -/************************************ - * MALLOC COMPATIBILITY FOR pymem.h * - ************************************/ - #ifndef DL_IMPORT /* declarations for DLL import */ #define DL_IMPORT(RTYPE) RTYPE #endif -#ifdef MALLOC_ZERO_RETURNS_NULL -/* Allocate an extra byte if the platform malloc(0) returns NULL. - Caution: this bears no relation to whether realloc(p, 0) returns NULL - when p != NULL. Even on platforms where malloc(0) does not return NULL, - realloc(p, 0) may act like free(p) and return NULL. Examples include - Windows, and Python's own obmalloc.c (as of 2-Mar-2002). For whatever - reason, our docs promise that PyMem_Realloc(p, 0) won't act like - free(p) or return NULL, so realloc() calls may have to be hacked - too, but MALLOC_ZERO_RETURNS_NULL's state is irrelevant to realloc (it - needs a different hack). -*/ -#define _PyMem_EXTRA 1 -#else -#define _PyMem_EXTRA 0 -#endif - - /* If the fd manipulation macros aren't defined, here is a set that should do the job */ diff --git a/Modules/pypcre.c b/Modules/pypcre.c index e0aa8d0..5f21005 100644 --- a/Modules/pypcre.c +++ b/Modules/pypcre.c @@ -3078,8 +3078,11 @@ static int grow_stack(match_data *md) else {md->length = 80;} } PyMem_RESIZE(md->offset_top, int, md->length); - PyMem_RESIZE(md->eptr, const uschar *, md->length); - PyMem_RESIZE(md->ecode, const uschar *, md->length); + /* Can't realloc a pointer-to-const; cast const away. */ + md->eptr = (const uschar **)PyMem_Realloc((void *)md->eptr, + sizeof(uschar *) * md->length); + md->ecode = (const uschar **)PyMem_Realloc((void *)md->ecode, + sizeof(uschar *) * md->length); PyMem_RESIZE(md->off_num, int, md->length); PyMem_RESIZE(md->r1, int, md->length); PyMem_RESIZE(md->r2, int, md->length); diff --git a/Objects/object.c b/Objects/object.c index 6090838..e47f80e 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -1897,18 +1897,13 @@ int (*_Py_abstract_hack)(PyObject *) = &PyObject_Size; void * PyMem_Malloc(size_t nbytes) { -#if _PyMem_EXTRA > 0 - if (nbytes == 0) - nbytes = _PyMem_EXTRA; -#endif return PyMem_MALLOC(nbytes); } void * PyMem_Realloc(void *p, size_t nbytes) { - /* See comment near MALLOC_ZERO_RETURNS_NULL in pyport.h. */ - return PyMem_REALLOC(p, nbytes ? nbytes : 1); + return PyMem_REALLOC(p, nbytes); } void -- cgit v0.12