summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/api/utilities.tex2
-rw-r--r--Include/object.h62
-rw-r--r--Include/pydebug.h2
-rw-r--r--Misc/NEWS4
-rw-r--r--Objects/object.c15
-rw-r--r--Parser/pgenmain.c2
-rw-r--r--Python/pythonrun.c2
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
}
diff --git a/Misc/NEWS b/Misc/NEWS
index 7bc9817..b17661e 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -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