]> granicus.if.org Git - python/commitdiff
The Py_REF_DEBUG/COUNT_ALLOCS/Py_TRACE_REFS macro minefield: added
authorTim Peters <tim.peters@gmail.com>
Tue, 9 Jul 2002 02:57:01 +0000 (02:57 +0000)
committerTim Peters <tim.peters@gmail.com>
Tue, 9 Jul 2002 02:57:01 +0000 (02:57 +0000)
more trivial lexical helper macros so that uses of these guys expand
to nothing at all when they're not enabled.  This should help sub-
standard compilers that can't do a good job of optimizing away the
previous "(void)0" expressions.

Py_DECREF:  There's only one definition of this now.  Yay!  That
was that last one in the family defined multiple times in an #ifdef
maze.

Py_FatalError():  Changed the char* signature to const char*.

_Py_NegativeRefcount():  New helper function for the Py_REF_DEBUG
expansion of Py_DECREF.  Calling an external function cuts down on
the volume of generated code.  The previous inline expansion of abort()
didn't work as intended on Windows (the program often kept going, and
the error msg scrolled off the screen unseen).  _Py_NegativeRefcount
calls Py_FatalError instead, which captures our best knowledge of
how to abort effectively across platforms.

Doc/api/utilities.tex
Include/object.h
Include/pydebug.h
Misc/NEWS
Objects/object.c
Parser/pgenmain.c
Python/pythonrun.c

index d60a79f95b133924a233ce78a60d64931e25264f..ae04c40f99bb9e32222e22ce34f8900a567a9715 100644 (file)
@@ -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
index 454c9978da2a9f6d7152bea78cf8235db2f13fbe..db4fd569eb1ea2230455dd202fa186946f633338 100644 (file)
@@ -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)
index d92161cd64a496791df10481dd06a67167101f12..e24c9fe00572243e2bbbad44576bbadd80384221 100644 (file)
@@ -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
 }
index 7bc9817f1be2f6b546395f395d52bb06be8a757a..b17661e4d815aba752e76c3ecc38816cb817be98 100644 (file)
--- 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.
index fd069f1fe637dbdd389a0b3454219b7955e94a38..4987ff301817067a6683350aa4dfe8c51a4f4cda 100644 (file)
@@ -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)
 {
index 447019341d9df28531212a380d85c820c9f79762..63be88f8ed267c2583996a1ac6dfce3ba861d13c 100644 (file)
@@ -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);
index 63e0e8e7662d710b76e8171f72699417df1f9910..ec8291c06b18449884e47bda7703637a929753dc 100644 (file)
@@ -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