CPython compilation get stuck at generate-posix-vars

I’m trying to compile CPython in debug mode:

CC=gcc-10 CXX=g++-10 ../cpython_mine/configure --with-pydebug --with-assertions

Unluckily, the compilation get stuck here:

./python -E -S -m sysconfig --generate-posix-vars ;\
if test $? -ne 0 ; then \
	echo "generate-posix-vars failed" ; \
	rm -f ./pybuilddir.txt ; \
	exit 1 ; \
fi

^Cmake: *** Deleting file 'pybuilddir.txt'
Makefile:601: recipe for target 'pybuilddir.txt' failed
make: *** [pybuilddir.txt] Interrupt

(venv_3_10) marco@buzz:~

In past I had no problem to compile the debug build. How can I debug the debug?

Now I changed the code, but I get a segfault.

This is the diff:

diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index 6c3fc62d2e..99c48f63dc 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -1216,6 +1216,49 @@ a combined table, then the me_value slots in the old table are NULLed out.
 After resizing a table is always combined,
 but can be resplit by make_keys_shared().
 */
+static int
+dictresize2(PyDictObject *mp, Py_ssize_t newsize)
+{
+    Py_ssize_t numentries;
+    PyDictKeysObject *oldkeys;
+    PyDictKeyEntry *newentries;
+
+    if (newsize <= 0) {
+        PyErr_NoMemory();
+        return -1;
+    }
+    assert(IS_POWER_OF_2(newsize));
+    assert(newsize >= PyDict_MINSIZE);
+
+    oldkeys = mp->ma_keys;
+
+    /* NOTE: Current odict checks mp->ma_keys to detect resize happen.
+     * So we can't reuse oldkeys even if oldkeys->dk_size == newsize.
+     * TODO: Try reusing oldkeys when reimplement odict.
+     */
+
+    /* Allocate a new table. */
+    mp->ma_keys = new_keys_object(newsize);
+    if (mp->ma_keys == NULL) {
+        mp->ma_keys = oldkeys;
+        return -1;
+    }
+    // New table must be large enough.
+    assert(mp->ma_keys->dk_usable >= mp->ma_used);
+    if (oldkeys != NULL && oldkeys->dk_lookup == lookdict) {
+        mp->ma_keys->dk_lookup = lookdict;
+    }
+
+    numentries = mp->ma_used;
+    newentries = DK_ENTRIES(mp->ma_keys);
+
+    build_indices(mp->ma_keys, newentries, numentries);
+    mp->ma_keys->dk_usable -= numentries;
+    mp->ma_keys->dk_nentries = numentries;
+    return 0;
+}
+
+
 static int
 dictresize(PyDictObject *mp, Py_ssize_t newsize)
 {
@@ -2382,7 +2425,6 @@ dict_update_common(PyObject *self, PyObject *args, PyObject *kwds,
 {
+    mp->ma_keys->dk_nentries = numentries;
+    return 0;
+}
+
+
 static int
 dictresize(PyDictObject *mp, Py_ssize_t newsize)
+
+
 static int
 dictresize(PyDictObject *mp, Py_ssize_t newsize)
 {
@@ -2382,7 +2425,6 @@ dict_update_common(PyObject *self, PyObject *args, PyObjec
t *kwds,
 {
     PyObject *arg = NULL;
     int result = 0;
-
     if (!PyArg_UnpackTuple(args, methname, 0, 1, &arg)) {
         result = -1;
     }
@@ -2405,8 +2447,9 @@ dict_update_common(PyObject *self, PyObject *args, PyObject *kwds,
 static PyObject *
 dict_update(PyObject *self, PyObject *args, PyObject *kwds)
 {
-    if (dict_update_common(self, args, kwds, "update") != -1)
+    if (dict_update_common(self, args, kwds, "update") != -1) {
         Py_RETURN_NONE;
+    }
     return NULL;
 }
 
@@ -3419,8 +3462,34 @@ dict_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
 
     d->ma_used = 0;
     d->ma_version_tag = DICT_NEXT_VERSION();
-    dictkeys_incref(Py_EMPTY_KEYS);
-    d->ma_keys = Py_EMPTY_KEYS;
+    
+    
+    PyObject* arg = NULL;
+    
+    if (args != NULL) {
+        if (! PyArg_UnpackTuple(args, __func__, 0, 1, &arg)) {
+            Py_DECREF(self);
+            return NULL;
+        }
+    }
+    
+    int arg_size = ((arg != NULL) 
+        ? PyObject_Length(arg) 
+        : 0
+    );
+    
+    int kwds_size = ((kwds != NULL) 
+        ? ((PyDictObject*) kwds)->ma_used 
+        : 0
+    );
+    
+    Py_ssize_t keys_size = calculate_keysize(arg_size + kwds_size);
+    
+    if (dictresize2((PyDictObject *)self, keys_size)) {
+        Py_DECREF(self);
+        return NULL;
+    }
+    
     d->ma_values = empty_values;
     ASSERT_CONSISTENT(d);
     return self;
if test $? -ne 0 ; then \
	echo "generate-posix-vars failed" ; \
	rm -f ./pybuilddir.txt ; \
	exit 1 ; \
fi
Segmentation fault (core dumped)

This is the diff

I found where is the problem: in enum.py. But not why.

     def value(self):
         """The value of the Enum member."""
         return self._value_
+    
+    print("enum 0", file=sys.stderr)
 
-
+print("enum 1", file=sys.stderr)

After this changes, I get:

marco@buzz:~/sources/cpython_mine_build_normal$ make -j
./python -E -S -m sysconfig --generate-posix-vars ;\
if test $? -ne 0 ; then \
	echo "generate-posix-vars failed" ; \
	rm -f ./pybuilddir.txt ; \
	exit 1 ; \
fi
enum 0
Segmentation fault (core dumped)

So it seems that the creation itself of the Enum class causes the the segfault.

The sysconfig --generate-posix-vars call is (on *nix) the first place in the build process that runs the newly built Python. If there are crasher bugs in critical code like dict resize, that’s where you’ll usually see them.

Run ./python (or even ./python -E -S -m sysconfig --generate-posix-vars) under a C debugger.

1 Like