From 600bcf4b21053a0192c3f8296eaea8e51a3a76f8 Mon Sep 17 00:00:00 2001 From: superbigcup325 <2025150125@mails.szu.edu.cn> Date: Thu, 10 Sep 2026 23:52:36 +0800 Subject: [PATCH] python: avoid empty LD_LIBRARY_PATH/PATH entries on import (4.x backport of #29905) Backport of #29905 to the 4.x branch, applied verbatim: after this change `modules/python/package/cv2/__init__.py` is byte-identical to the 5.x version (same blob 99685b3791dc), since both branches carried the same code here. `import cv2` unconditionally rewrites the environment; when LD_LIBRARY_PATH was previously unset this creates a dangling separator, i.e. an empty entry which, per ld.so(8), resolves to the current working directory of every subsequently spawned child process. Children may then pick up same-named shared libraries from the CWD and fail (real-world case reported in opencv/opencv-python#1268: a Nuitka-standalone app's `xdg-open -> kde-open` dying with `libssl.so.3: version 'OPENSSL_3.2.0' not found`; reproduced on 4.11.0.86 - 4.14.0.94 manylinux wheels). The Windows PATH line has the same dangling-separator pattern. Identical to #29905: factor the prepend into _prepend_env_paths(), filter empty entries, write the variable only when there is something to add, and join with the old value without producing an empty entry. The follow-up question of not mutating the process environment at all remains tracked in #28994. --- modules/python/package/cv2/__init__.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/modules/python/package/cv2/__init__.py b/modules/python/package/cv2/__init__.py index 11994a2cd3..99685b3791 100644 --- a/modules/python/package/cv2/__init__.py +++ b/modules/python/package/cv2/__init__.py @@ -20,6 +20,14 @@ except ImportError: # is_x64 = sys.maxsize > 2**32 +def _prepend_env_paths(env_key, paths, sep): + extra = [p for p in paths if p] + if not extra: + return + old = os.environ.get(env_key) + os.environ[env_key] = sep.join(extra) + ((sep + old) if old else '') + + def __load_extra_py_code_for_module(base, name, enable_debug_print=False): module_name = "{}.{}".format(__name__, name) export_module_name = "{}.{}".format(base, name) @@ -140,11 +148,11 @@ def bootstrap(): except Exception as e: if DEBUG: print('Failed os.add_dll_directory(): '+ str(e)) pass - os.environ['PATH'] = ';'.join(l_vars['BINARIES_PATHS']) + ';' + os.environ.get('PATH', '') - if DEBUG: print('OpenCV loader: PATH={}'.format(str(os.environ['PATH']))) + _prepend_env_paths('PATH', l_vars['BINARIES_PATHS'], ';') + if DEBUG: print('OpenCV loader: PATH={}'.format(str(os.environ.get('PATH')))) else: # amending of LD_LIBRARY_PATH works for sub-processes only - os.environ['LD_LIBRARY_PATH'] = ':'.join(l_vars['BINARIES_PATHS']) + ':' + os.environ.get('LD_LIBRARY_PATH', '') + _prepend_env_paths('LD_LIBRARY_PATH', l_vars['BINARIES_PATHS'], ':') if DEBUG: print("Relink everything from native cv2 module to cv2 package")