mirror of https://github.com/python/cpython
Years in the making.
objimpl.h, pymem.h: Stop mapping PyMem_{Del, DEL} and PyMem_{Free, FREE} to PyObject_{Free, FREE} in a release build. They're aliases for the system free() now. _subprocess.c/sp_handle_dealloc(): Since the memory was originally obtained via PyObject_NEW, it must be released via PyObject_FREE (or _DEL). pythonrun.c, tokenizer.c, parsermodule.c: I lost count of the number of PyObject vs PyMem mismatches in these -- it's like the specific function called at each site was picked at random, sometimes even with memory obtained via PyMem getting released via PyObject. Changed most to use PyObject uniformly, since the blobs allocated are predictably small in most cases, and obmalloc is generally faster than system mallocs then. If extension modules in real life prove as sloppy as Python's front end, we'll have to revert the objimpl.h + pymem.h part of this patch. Note that no problems will show up in a debug build (all calls still go thru obmalloc then). Problems will show up only in a release build, most likely segfaults.
This commit is contained in:
parent
1c168d8eeb
commit
c9d78aa470
|
@ -101,7 +101,7 @@ PyAPI_FUNC(void) PyObject_Free(void *);
|
|||
|
||||
/* Macros */
|
||||
#ifdef WITH_PYMALLOC
|
||||
#ifdef PYMALLOC_DEBUG
|
||||
#ifdef PYMALLOC_DEBUG /* WITH_PYMALLOC && PYMALLOC_DEBUG */
|
||||
PyAPI_FUNC(void *) _PyObject_DebugMalloc(size_t nbytes);
|
||||
PyAPI_FUNC(void *) _PyObject_DebugRealloc(void *p, size_t nbytes);
|
||||
PyAPI_FUNC(void) _PyObject_DebugFree(void *p);
|
||||
|
@ -124,11 +124,7 @@ PyAPI_FUNC(void) _PyObject_DebugMallocStats(void);
|
|||
#else /* ! WITH_PYMALLOC */
|
||||
#define PyObject_MALLOC PyMem_MALLOC
|
||||
#define PyObject_REALLOC PyMem_REALLOC
|
||||
/* This is an odd one! For backward compatibility with old extensions, the
|
||||
PyMem "release memory" functions have to invoke the object allocator's
|
||||
free() function. When pymalloc isn't enabled, that leaves us using
|
||||
the platform free(). */
|
||||
#define PyObject_FREE free
|
||||
#define PyObject_FREE PyMem_FREE
|
||||
|
||||
#endif /* WITH_PYMALLOC */
|
||||
|
||||
|
|
|
@ -59,6 +59,7 @@ PyAPI_FUNC(void) PyMem_Free(void *);
|
|||
/* Redirect all memory operations to Python's debugging allocator. */
|
||||
#define PyMem_MALLOC PyObject_MALLOC
|
||||
#define PyMem_REALLOC PyObject_REALLOC
|
||||
#define PyMem_FREE PyObject_FREE
|
||||
|
||||
#else /* ! PYMALLOC_DEBUG */
|
||||
|
||||
|
@ -68,14 +69,10 @@ PyAPI_FUNC(void) PyMem_Free(void *);
|
|||
pymalloc. To solve these problems, allocate an extra byte. */
|
||||
#define PyMem_MALLOC(n) malloc((n) ? (n) : 1)
|
||||
#define PyMem_REALLOC(p, n) realloc((p), (n) ? (n) : 1)
|
||||
#define PyMem_FREE free
|
||||
|
||||
#endif /* PYMALLOC_DEBUG */
|
||||
|
||||
/* In order to avoid breaking old code mixing PyObject_{New, NEW} with
|
||||
PyMem_{Del, DEL} and PyMem_{Free, FREE}, the PyMem "release memory"
|
||||
functions have to be redirected to the object deallocator. */
|
||||
#define PyMem_FREE PyObject_FREE
|
||||
|
||||
/*
|
||||
* Type-oriented memory interface
|
||||
* ==============================
|
||||
|
@ -95,11 +92,11 @@ PyAPI_FUNC(void) PyMem_Free(void *);
|
|||
#define PyMem_RESIZE(p, type, n) \
|
||||
( (p) = (type *) PyMem_REALLOC((p), (n) * sizeof(type)) )
|
||||
|
||||
/* In order to avoid breaking old code mixing PyObject_{New, NEW} with
|
||||
PyMem_{Del, DEL} and PyMem_{Free, FREE}, the PyMem "release memory"
|
||||
functions have to be redirected to the object deallocator. */
|
||||
#define PyMem_Del PyObject_Free
|
||||
#define PyMem_DEL PyObject_FREE
|
||||
/* PyMem{Del,DEL} are left over from ancient days, and shouldn't be used
|
||||
* anymore. They're just confusing aliases for PyMem_{Free,FREE} now.
|
||||
*/
|
||||
#define PyMem_Del PyMem_Free
|
||||
#define PyMem_DEL PyMem_FREE
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
11
Misc/NEWS
11
Misc/NEWS
|
@ -942,6 +942,17 @@ Build
|
|||
C API
|
||||
-----
|
||||
|
||||
- ``PyMem_{Del, DEL}`` and ``PyMem_{Free, FREE}`` no longer map to
|
||||
``PyObject_{Free, FREE}``. They map to the system ``free()`` now. If memory
|
||||
is obtained via the ``PyObject_`` family, it must be released via the
|
||||
``PyObject_`` family, and likewise for the ``PyMem_`` family. This has
|
||||
always been officially true, but when Python's small-object allocator was
|
||||
introduced, an attempt was made to cater to a few extension modules
|
||||
discovered at the time that obtained memory via ``PyObject_New`` but
|
||||
released it via ``PyMem_DEL``. It's years later, and if such code still
|
||||
exists it will fail now (probably with segfaults, but calling wrong
|
||||
low-level memory management functions can yield many symptoms).
|
||||
|
||||
- Added a C API for set and frozenset objects.
|
||||
|
||||
- Removed PyRange_New().
|
||||
|
|
|
@ -701,7 +701,7 @@ build_node_children(PyObject *tuple, node *root, int *line_num)
|
|||
}
|
||||
}
|
||||
len = PyString_GET_SIZE(temp) + 1;
|
||||
strn = (char *)PyMem_MALLOC(len);
|
||||
strn = (char *)PyObject_MALLOC(len);
|
||||
if (strn != NULL)
|
||||
(void) memcpy(strn, PyString_AS_STRING(temp), len);
|
||||
Py_DECREF(temp);
|
||||
|
@ -719,11 +719,11 @@ build_node_children(PyObject *tuple, node *root, int *line_num)
|
|||
}
|
||||
err = PyNode_AddChild(root, type, strn, *line_num, 0);
|
||||
if (err == E_NOMEM) {
|
||||
PyMem_DEL(strn);
|
||||
PyObject_FREE(strn);
|
||||
return (node *) PyErr_NoMemory();
|
||||
}
|
||||
if (err == E_OVERFLOW) {
|
||||
PyMem_DEL(strn);
|
||||
PyObject_FREE(strn);
|
||||
PyErr_SetString(PyExc_ValueError,
|
||||
"unsupported number of child nodes");
|
||||
return NULL;
|
||||
|
@ -742,7 +742,7 @@ build_node_children(PyObject *tuple, node *root, int *line_num)
|
|||
}
|
||||
Py_XDECREF(elem);
|
||||
}
|
||||
return (root);
|
||||
return root;
|
||||
}
|
||||
|
||||
|
||||
|
@ -787,7 +787,7 @@ build_node_tree(PyObject *tuple)
|
|||
if (res && encoding) {
|
||||
Py_ssize_t len;
|
||||
len = PyString_GET_SIZE(encoding) + 1;
|
||||
res->n_str = (char *)PyMem_MALLOC(len);
|
||||
res->n_str = (char *)PyObject_MALLOC(len);
|
||||
if (res->n_str != NULL)
|
||||
(void) memcpy(res->n_str, PyString_AS_STRING(encoding), len);
|
||||
Py_DECREF(encoding);
|
||||
|
|
|
@ -104,7 +104,7 @@ sp_handle_dealloc(sp_handle_object* self)
|
|||
{
|
||||
if (self->handle != INVALID_HANDLE_VALUE)
|
||||
CloseHandle(self->handle);
|
||||
PyMem_DEL(self);
|
||||
PyObject_FREE(self);
|
||||
}
|
||||
|
||||
static PyMethodDef sp_handle_methods[] = {
|
||||
|
|
|
@ -163,7 +163,7 @@ error_ret(struct tok_state *tok) /* XXX */
|
|||
{
|
||||
tok->decoding_erred = 1;
|
||||
if (tok->fp != NULL && tok->buf != NULL) /* see PyTokenizer_Free */
|
||||
PyMem_DEL(tok->buf);
|
||||
PyObject_FREE(tok->buf);
|
||||
tok->buf = NULL;
|
||||
return NULL; /* as if it were EOF */
|
||||
}
|
||||
|
@ -171,7 +171,7 @@ error_ret(struct tok_state *tok) /* XXX */
|
|||
static char *
|
||||
new_string(const char *s, Py_ssize_t len)
|
||||
{
|
||||
char* result = PyMem_NEW(char, len + 1);
|
||||
char* result = (char *)PyObject_MALLOC(len + 1);
|
||||
if (result != NULL) {
|
||||
memcpy(result, s, len);
|
||||
result[len] = '\0';
|
||||
|
@ -236,7 +236,7 @@ get_coding_spec(const char *s, Py_ssize_t size)
|
|||
char* r = new_string(begin, t - begin);
|
||||
char* q = get_normal_name(r);
|
||||
if (r != q) {
|
||||
PyMem_DEL(r);
|
||||
PyObject_FREE(r);
|
||||
r = new_string(q, strlen(q));
|
||||
}
|
||||
return r;
|
||||
|
@ -277,18 +277,18 @@ check_coding_spec(const char* line, Py_ssize_t size, struct tok_state *tok,
|
|||
tok->decoding_state = -1;
|
||||
}
|
||||
else
|
||||
PyMem_DEL(cs);
|
||||
PyObject_FREE(cs);
|
||||
#else
|
||||
/* Without Unicode support, we cannot
|
||||
process the coding spec. Since there
|
||||
won't be any Unicode literals, that
|
||||
won't matter. */
|
||||
PyMem_DEL(cs);
|
||||
PyObject_FREE(cs);
|
||||
#endif
|
||||
}
|
||||
} else { /* then, compare cs with BOM */
|
||||
r = (strcmp(tok->encoding, cs) == 0);
|
||||
PyMem_DEL(cs);
|
||||
PyObject_FREE(cs);
|
||||
}
|
||||
}
|
||||
if (!r) {
|
||||
|
@ -334,7 +334,7 @@ check_bom(int get_char(struct tok_state *),
|
|||
return 1;
|
||||
}
|
||||
if (tok->encoding != NULL)
|
||||
PyMem_DEL(tok->encoding);
|
||||
PyObject_FREE(tok->encoding);
|
||||
tok->encoding = new_string("utf-8", 5); /* resulting is in utf-8 */
|
||||
return 1;
|
||||
NON_BOM:
|
||||
|
@ -537,13 +537,15 @@ decoding_feof(struct tok_state *tok)
|
|||
|
||||
/* Fetch a byte from TOK, using the string buffer. */
|
||||
|
||||
static int buf_getc(struct tok_state *tok) {
|
||||
static int
|
||||
buf_getc(struct tok_state *tok) {
|
||||
return Py_CHARMASK(*tok->str++);
|
||||
}
|
||||
|
||||
/* Unfetch a byte from TOK, using the string buffer. */
|
||||
|
||||
static void buf_ungetc(int c, struct tok_state *tok) {
|
||||
static void
|
||||
buf_ungetc(int c, struct tok_state *tok) {
|
||||
tok->str--;
|
||||
assert(Py_CHARMASK(*tok->str) == c); /* tok->cur may point to read-only segment */
|
||||
}
|
||||
|
@ -551,7 +553,8 @@ static void buf_ungetc(int c, struct tok_state *tok) {
|
|||
/* Set the readline function for TOK to ENC. For the string-based
|
||||
tokenizer, this means to just record the encoding. */
|
||||
|
||||
static int buf_setreadl(struct tok_state *tok, const char* enc) {
|
||||
static int
|
||||
buf_setreadl(struct tok_state *tok, const char* enc) {
|
||||
tok->enc = enc;
|
||||
return 1;
|
||||
}
|
||||
|
@ -653,7 +656,7 @@ PyTokenizer_FromFile(FILE *fp, char *ps1, char *ps2)
|
|||
struct tok_state *tok = tok_new();
|
||||
if (tok == NULL)
|
||||
return NULL;
|
||||
if ((tok->buf = PyMem_NEW(char, BUFSIZ)) == NULL) {
|
||||
if ((tok->buf = (char *)PyObject_MALLOC(BUFSIZ)) == NULL) {
|
||||
PyTokenizer_Free(tok);
|
||||
return NULL;
|
||||
}
|
||||
|
@ -672,14 +675,14 @@ void
|
|||
PyTokenizer_Free(struct tok_state *tok)
|
||||
{
|
||||
if (tok->encoding != NULL)
|
||||
PyMem_DEL(tok->encoding);
|
||||
PyObject_FREE(tok->encoding);
|
||||
#ifndef PGEN
|
||||
Py_XDECREF(tok->decoding_readline);
|
||||
Py_XDECREF(tok->decoding_buffer);
|
||||
#endif
|
||||
if (tok->fp != NULL && tok->buf != NULL)
|
||||
PyMem_DEL(tok->buf);
|
||||
PyMem_DEL(tok);
|
||||
PyObject_FREE(tok->buf);
|
||||
PyMem_FREE(tok);
|
||||
}
|
||||
|
||||
#if !defined(PGEN) && defined(Py_USING_UNICODE)
|
||||
|
@ -721,7 +724,7 @@ tok_stdin_decode(struct tok_state *tok, char **inp)
|
|||
PyMem_FREE(*inp);
|
||||
*inp = converted;
|
||||
if (tok->encoding != NULL)
|
||||
PyMem_DEL(tok->encoding);
|
||||
PyObject_FREE(tok->encoding);
|
||||
tok->encoding = new_string(encoding, strlen(encoding));
|
||||
if (tok->encoding == NULL)
|
||||
goto error_nomem;
|
||||
|
@ -790,10 +793,10 @@ tok_nextc(register struct tok_state *tok)
|
|||
size_t oldlen = tok->cur - tok->buf;
|
||||
size_t newlen = oldlen + strlen(new);
|
||||
char *buf = tok->buf;
|
||||
PyMem_RESIZE(buf, char, newlen+1);
|
||||
buf = (char *)PyObject_REALLOC(buf, newlen+1);
|
||||
tok->lineno++;
|
||||
if (buf == NULL) {
|
||||
PyMem_DEL(tok->buf);
|
||||
PyObject_FREE(tok->buf);
|
||||
tok->buf = NULL;
|
||||
PyMem_FREE(new);
|
||||
tok->done = E_NOMEM;
|
||||
|
@ -811,7 +814,7 @@ tok_nextc(register struct tok_state *tok)
|
|||
else {
|
||||
tok->lineno++;
|
||||
if (tok->buf != NULL)
|
||||
PyMem_DEL(tok->buf);
|
||||
PyObject_FREE(tok->buf);
|
||||
tok->buf = new;
|
||||
tok->line_start = tok->buf;
|
||||
tok->cur = tok->buf;
|
||||
|
@ -826,7 +829,8 @@ tok_nextc(register struct tok_state *tok)
|
|||
char *pt;
|
||||
if (tok->start == NULL) {
|
||||
if (tok->buf == NULL) {
|
||||
tok->buf = PyMem_NEW(char, BUFSIZ);
|
||||
tok->buf = (char *)
|
||||
PyObject_MALLOC(BUFSIZ);
|
||||
if (tok->buf == NULL) {
|
||||
tok->done = E_NOMEM;
|
||||
return EOF;
|
||||
|
@ -861,7 +865,8 @@ tok_nextc(register struct tok_state *tok)
|
|||
Py_ssize_t curvalid = tok->inp - tok->buf;
|
||||
Py_ssize_t newsize = curvalid + BUFSIZ;
|
||||
char *newbuf = tok->buf;
|
||||
PyMem_RESIZE(newbuf, char, newsize);
|
||||
newbuf = (char *)PyObject_REALLOC(newbuf,
|
||||
newsize);
|
||||
if (newbuf == NULL) {
|
||||
tok->done = E_NOMEM;
|
||||
tok->cur = tok->inp;
|
||||
|
|
|
@ -1457,7 +1457,7 @@ err_input(perrdetail *err)
|
|||
v = Py_BuildValue("(ziiz)", err->filename,
|
||||
err->lineno, err->offset, err->text);
|
||||
if (err->text != NULL) {
|
||||
PyMem_DEL(err->text);
|
||||
PyObject_FREE(err->text);
|
||||
err->text = NULL;
|
||||
}
|
||||
w = NULL;
|
||||
|
|
Loading…
Reference in New Issue