Opencv causes debug-enabled python interpreter to abort with a refcount error

When python is compiled with debugging support enabled, it includes extra checks not present in production interpreters. Importing cv2 consistently fails these checks with the following error:

../Modules/gcmodule.c:113: gc_decref: Assertion "gc_get_refs(g) > 0" failed: refcount is too small

This error normally means that python’s garbage collector found more owned references to an object than are recorded in that object’s refcount, which is fatal, but a native module reporting more owned references than it actually holds can cause a false positive. I expect that it’s a false positive, but either way this makes python’s heap tracing mode unusable with any program or module that depends on opencv.

pip package versions 4.7.0.72 and 4.7.0.68 for python 3.10 on x86_64/linux are affected. I haven’t tested other versions.

Tested using debian’s python3.10.10 debug build with venv.

To reproduce

$ sudo apt-get install python3.10-dbg
$ python3.10d -m venv venv
$ source venv/bin/activate
$ pip install opencv-python
$ PYTHONTRACEMALLOC=1 python3.10d
>>> import cv2

../Modules/gcmodule.c:113: gc_decref: Assertion "gc_get_refs(g) > 0" failed: refcount is too small
Memory block allocated at (most recent call first):
  File "<frozen importlib._bootstrap>", line 241

object address  : 0x20d1ff0
object refcount : 7
object type     : 0x9507a0
object type name: type
object repr     : <class 'cv2.utils.ClassWithKeywordProperties'>

Fatal Python error: _PyObject_AssertFailed: _PyObject_AssertFailed
Python runtime state: initialized

Current thread 0x00007f8545192040 (most recent call first):
  Garbage-collecting
  File "<frozen importlib._bootstrap>", line 241 in _call_with_frames_removed
  File "<frozen importlib._bootstrap_external>", line 1176 in create_module
  File "<frozen importlib._bootstrap>", line 571 in module_from_spec
  File "<frozen importlib._bootstrap>", line 674 in _load_unlocked
  File "<frozen importlib._bootstrap>", line 1006 in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 1027 in _find_and_load
  File "<frozen importlib._bootstrap>", line 1050 in _gcd_import
  File "/usr/lib/python3.10/importlib/__init__.py", line 126 in import_module
  File "/path/to/venv/lib/python3.10/site-packages/cv2/__init__.py", line 153 in bootstrap
  File "/path/to/venv/lib/python3.10/site-packages/cv2/__init__.py", line 181 in <module>
  File "<frozen importlib._bootstrap>", line 241 in _call_with_frames_removed
  File "<frozen importlib._bootstrap_external>", line 883 in exec_module
  File "<frozen importlib._bootstrap>", line 688 in _load_unlocked
  File "<frozen importlib._bootstrap>", line 1006 in _find_and_load_unlocked
  File "<frozen importlib._bootstrap>", line 1027 in _find_and_load
  File "<stdin>", line 1 in <module>

Extension modules: numpy.core._multiarray_umath, numpy.core._multiarray_tests, numpy.linalg._umath_linalg, numpy.fft._pocketfft_internal, numpy.random._common, numpy.random.bit_generator, numpy.random._bounded_integers, numpy.random._mt19937, numpy.random.mtrand, numpy.random._philox, numpy.random._pcg64, numpy.random._sfc64, numpy.random._generator (total: 13)
Aborted

Either cv2.utils.ClassWithKeywordProperties or cv2.utils.nested.ExportClassName may be reported as faulty, but it is likely a general problem in opencv and those are just the ones that get noticed first.

Importing another module before cv2 will sometimes allow it to finish loading, but running any of the following scripts will crash with a reference count error in cv2.utils:

import gc
gc.collect()
class Foo():
    def __init__(self, value):
        self.value = value
l = list(Foo(x) for x in range(1000000))
exit()

It seems I didn’t search carefully enough. This has already been reported as Potential reference counting error in Python module · Issue #23059 · opencv/opencv · GitHub

2 Likes