diff options
-rw-r--r-- | Doc/api/utilities.tex | 2 | ||||
-rw-r--r-- | Include/object.h | 62 | ||||
-rw-r--r-- | Include/pydebug.h | 2 | ||||
-rw-r--r-- | Misc/NEWS | 4 | ||||
-rw-r--r-- | Objects/object.c | 15 | ||||
-rw-r--r-- | Parser/pgenmain.c | 2 | ||||
-rw-r--r-- | Python/pythonrun.c | 2 |
7 files changed, 58 insertions, 31 deletions
diff --git a/Doc/api/utilities.tex b/Doc/api/utilities.tex index d60a79f..ae04c40 100644 --- a/Doc/api/utilities.tex +++ b/Doc/api/utilities.tex @@ -58,7 +58,7 @@ values from C values. \section{Process Control \label{processControl}} -\begin{cfuncdesc}{void}{Py_FatalError}{char *message} +\begin{cfuncdesc}{void}{Py_FatalError}{const char *message} Print a fatal error message and kill the process. No cleanup is performed. This function should only be invoked when a condition is detected that would make it dangerous to continue using the Python diff --git a/Include/object.h b/Include/object.h index 454c997..db4fd56 100644 --- a/Include/object.h +++ b/Include/object.h @@ -66,6 +66,8 @@ whose size is determined when the object is allocated. * Note that if this count increases when you're not storing away new objects, * there's probably a leak. Remember, though, that in interactive mode the * special name "_" holds a reference to the last result displayed! + * Py_REF_DEBUG also checks after every decref to verify that the refcount + * hasn't gone negative, and causes an immediate fatal error if it has. */ #define Py_REF_DEBUG @@ -536,18 +538,34 @@ environment the global variable trick is not safe.) #ifdef Py_REF_DEBUG extern DL_IMPORT(long) _Py_RefTotal; -#define _PyMAYBE_BUMP_REFTOTAL _Py_RefTotal++ +extern DL_IMPORT(void) _Py_NegativeRefcount(const char *fname, + int lineno, PyObject *op); +#define _PyMAYBE_BUMP_REFTOTAL _Py_RefTotal++ +#define _PyMAYBE_DROP_REFTOTAL _Py_RefTotal-- +#define _PyMAYBE_REFTOTAL_COMMA , +#define _PyMAYBE_CHECK_REFCNT(OP) \ +{ if ((OP)->ob_refcnt < 0) \ + _Py_NegativeRefcount(__FILE__, __LINE__, \ + (PyObject *)(OP)); \ +} #else -#define _PyMAYBE_BUMP_REFTOTAL (void)0 +#define _PyMAYBE_BUMP_REFTOTAL +#define _PyMAYBE_DROP_REFTOTAL +#define _PyMAYBE_REFTOTAL_COMMA +#define _PyMAYBE_CHECK_REFCNT(OP) ; #endif #ifdef COUNT_ALLOCS extern DL_IMPORT(void) inc_count(PyTypeObject *); #define _PyMAYBE_BUMP_COUNT(OP) inc_count((OP)->ob_type) #define _PyMAYBE_BUMP_FREECOUNT(OP) (OP)->ob_type->tp_frees++ +#define _PyMAYBE_BUMP_COUNT_COMMA , +#define _PyMAYBE_BUMP_FREECOUNT_COMMA , #else -#define _PyMAYBE_BUMP_COUNT(OP) (void)0 -#define _PyMAYBE_BUMP_FREECOUNT(OP) (void)0 +#define _PyMAYBE_BUMP_COUNT(OP) +#define _PyMAYBE_BUMP_FREECOUNT(OP) +#define _PyMAYBE_BUMP_COUNT_COMMA +#define _PyMAYBE_BUMP_FREECOUNT_COMMA #endif #ifdef Py_TRACE_REFS @@ -562,38 +580,28 @@ extern DL_IMPORT(void) _Py_ResetReferences(void); /* Without Py_TRACE_REFS, there's little enough to do that we expand code * inline. */ -#define _Py_NewReference(op) ( \ - _PyMAYBE_BUMP_COUNT(op), \ - _PyMAYBE_BUMP_REFTOTAL, \ +#define _Py_NewReference(op) ( \ + _PyMAYBE_BUMP_COUNT(op) _PyMAYBE_BUMP_COUNT_COMMA \ + _PyMAYBE_BUMP_REFTOTAL _PyMAYBE_REFTOTAL_COMMA \ (op)->ob_refcnt = 1) -#define _Py_ForgetReference(op) (_PyMAYBE_BUMP_FREECOUNT(op)) +#define _Py_ForgetReference(op) _PyMAYBE_BUMP_FREECOUNT(op) -#define _Py_Dealloc(op) ( \ - _Py_ForgetReference(op), \ +#define _Py_Dealloc(op) ( \ + _PyMAYBE_BUMP_FREECOUNT(op) _PyMAYBE_BUMP_FREECOUNT_COMMA \ (*(op)->ob_type->tp_dealloc)((PyObject *)(op))) - #endif /* !Py_TRACE_REFS */ -#define Py_INCREF(op) ( \ - _PyMAYBE_BUMP_REFTOTAL, \ +#define Py_INCREF(op) ( \ + _PyMAYBE_BUMP_REFTOTAL _PyMAYBE_REFTOTAL_COMMA \ (op)->ob_refcnt++) -#ifdef Py_REF_DEBUG -/* under Py_REF_DEBUG: also log negative ref counts after Py_DECREF() !! */ -#define Py_DECREF(op) \ - if (--_Py_RefTotal, 0 < (--((op)->ob_refcnt))) ; \ - else if (0 == (op)->ob_refcnt) _Py_Dealloc( (PyObject*)(op)); \ - else ((void)fprintf(stderr, "%s:%i negative ref count %i\n", \ - __FILE__, __LINE__, (op)->ob_refcnt), abort()) - -#else -#define Py_DECREF(op) \ - if (--(op)->ob_refcnt != 0) \ - ; \ - else \ +#define Py_DECREF(op) \ + if (_PyMAYBE_DROP_REFTOTAL _PyMAYBE_REFTOTAL_COMMA \ + --(op)->ob_refcnt != 0) \ + _PyMAYBE_CHECK_REFCNT(op) \ + else \ _Py_Dealloc((PyObject *)(op)) -#endif /* !Py_REF_DEBUG */ /* Macros to use in case the object pointer may be NULL: */ #define Py_XINCREF(op) if ((op) == NULL) ; else Py_INCREF(op) diff --git a/Include/pydebug.h b/Include/pydebug.h index d92161c..e24c9fe 100644 --- a/Include/pydebug.h +++ b/Include/pydebug.h @@ -26,7 +26,7 @@ extern DL_IMPORT(int) _Py_QnewFlag; PYTHONPATH and PYTHONHOME from the environment */ #define Py_GETENV(s) (Py_IgnoreEnvironmentFlag ? NULL : getenv(s)) -DL_IMPORT(void) Py_FatalError(char *message); +DL_IMPORT(void) Py_FatalError(const char *message); #ifdef __cplusplus } @@ -352,6 +352,10 @@ Build C API +- Py_FatalError() is now declared as taking a const char* argument. It + was previously declared without const. This should not affect working + code. + - Added new macro PySequence_ITEM(o, i) that directly calls sq_item without rechecking that o is a sequence and without adjusting for negative indices. diff --git a/Objects/object.c b/Objects/object.c index fd069f1..4987ff3 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -91,6 +91,21 @@ inc_count(PyTypeObject *tp) } #endif +#ifdef Py_REF_DEBUG +/* Log a fatal error; doesn't return. */ +void +_Py_NegativeRefcount(const char *fname, int lineno, PyObject *op) +{ + char buf[300]; + + PyOS_snprintf(buf, sizeof(buf), + "%s:%i object at %p has negative ref count %i", + fname, lineno, op, op->ob_refcnt); + Py_FatalError(buf); +} + +#endif /* Py_REF_DEBUG */ + PyObject * PyObject_Init(PyObject *op, PyTypeObject *tp) { diff --git a/Parser/pgenmain.c b/Parser/pgenmain.c index 4470193..63be88f 100644 --- a/Parser/pgenmain.c +++ b/Parser/pgenmain.c @@ -147,7 +147,7 @@ askfile(void) #endif void -Py_FatalError(char *msg) +Py_FatalError(const char *msg) { fprintf(stderr, "pgen: FATAL ERROR: %s\n", msg); Py_Exit(1); diff --git a/Python/pythonrun.c b/Python/pythonrun.c index 63e0e8e..ec8291c 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -1266,7 +1266,7 @@ err_input(perrdetail *err) /* Print fatal error message and abort */ void -Py_FatalError(char *msg) +Py_FatalError(const char *msg) { fprintf(stderr, "Fatal Python error: %s\n", msg); #ifdef macintosh |