I'm experiencing a wierd crash when trying to run a C++ library entry point from a Python script. I'm under Windows 10.
I isolated this into a very simple example.
Here is my C++ code:
sdetests_lib_bind_python.h:
#pragma once
#ifdef SDETESTS_LIB_BIND_PYTHON_EXPORTS
/** Export symbols statement */
#define SDETESTS_LIB_BIND_PYTHON __declspec(dllexport)
#else
/** Import symbols statement */
#define SDETESTS_LIB_BIND_PYTHON __declspec(dllimport)
#endif
#ifdef __cplusplus
extern "C" {
#endif
SDETESTS_LIB_BIND_PYTHON void func(int lock);
#ifdef __cplusplus
}
#endif
sdetests_lib_bind_python.cpp:
#include "sdetests_lib_bind_python.h"
#include <iostream>
#include <mutex>
SDETESTS_LIB_BIND_PYTHON void func( int lock )
{
if (lock!=0)
{
std::cout << "Creating mutex" << std::endl;
std::recursive_mutex mutex;
std::cout << "Created mutex" << std::endl;
std::cout << "Locking mutex" << std::endl;
std::lock_guard<std::recursive_mutex> lock_guard(mutex);
std::cout << "Locked mutex" << std::endl;
}
std::cout << "Hello world" << std::endl;
}
I compile this as a shared library using Visual Studio 2022 (MSVC 19.43.34808.0)
Later I run ctypesgen
to generate a binding sdetests_lib_bind_python.py
and I use it from a very simple Python script:
import sdetests_lib_bind_python
print("Calling func without lock")
sdetests_lib_bind_python.func(0)
print("Calling func with lock")
sdetests_lib_bind_python.func(1)
This works fine and output:
Hello from Python script without lock
Hello world
Hello from Python script with lock
Creating mutex
Created mutex
Locking mutex
Locked mutex
Hello world
However, if I load PyQt from my Python script, being now:
from PyQt5.QtCore import QT_VERSION_STR, PYQT_VERSION_STR
print("Qt: v", QT_VERSION_STR, "\tPyQt: v", PYQT_VERSION_STR)
import sdetests_lib_bind_python
print("Calling func without lock")
sdetests_lib_bind_python.func(0)
print("Calling func with lock")
sdetests_lib_bind_python.func(1)
Now the program crashs with output:
Qt: v 5.15.2 PyQt: v 5.15.9
Hello from Python script without lock
Hello world
Hello from Python script with lock
Creating mutex
Created mutex
Locking mutex
Traceback (most recent call last):
File "example_sdetests_lib_bind_python_def.py", line 10, in <module>
sdetests_lib_bind_python_def.func(1)
OSError: exception: access violation reading 0x0000000000000000
So the stcipt crashs if PyQt
is loaded BEFORE (see below) sdetests_lib_bind_python
and if sdetests_lib_bind_python
tries to use a std::recursive_mutex
.
Note that the script also crashs with other modules than PyQt, like rclpy
(all this comes from a ROS2 environment before I isolated it as an MCVE here).
Note that NO crash is observed:
- If
import sdetests_lib_bind_python
statement is the very first line of the script, then I can load PyQt, rclpy, and everything works fine. It only crashs if those other modules are loaded BEFORE sdetests_lib_bind_python - If I compile with an older compiler (MSVC 19.38.33135.0)...this crash appeared recently in my enviropnment after a compiler upgrade
- If my library does not use
std::recursive_mutex
, loading<mutex>
has no impact, but creating a mutex makes the whole thing crash withOSError
. - If I compile the library in "Debug" mode
I'm packaging my library for external users, so asking them to load it first or, if this could be a solution, to upgrade their PyQt or rlypy modules (and whatever other module leading to a crash) is not an acceptable solution for me...
As proposed by 'Ahmed AEK', I checked library loading.
With PyQt5 loaded after my library (no crash), I get:
'python.exe' (Win32) : Chargé 'C:\Python38\python.exe'. Les symboles ont été chargés.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\ntdll.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\kernel32.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\KernelBase.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\ucrtbase.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Python38\python38.dll'. Les symboles ont été chargés.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\shlwapi.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\msvcrt.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\ws2_32.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\rpcrt4.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\advapi32.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\sechost.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\bcrypt.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Python38\vcruntime140.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\version.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
Le thread 27884 s'est arrêté avec le code 0 (0x0).
'python.exe' (Win32) : Chargé 'C:\Windows\System32\cryptsp.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\rsaenh.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\cryptbase.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\bcryptprimitives.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Python38\python3.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Python38\DLLs\_ctypes.pyd'. Les symboles ont été chargés.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\ole32.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Python38\DLLs\libffi-7.dll'. Le module a été généré sans symboles.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\combase.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\gdi32.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\win32u.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\gdi32full.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\msvcp_win.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\user32.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\oleaut32.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\imm32.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Python38\DLLs\_bz2.pyd'. Les symboles ont été chargés.
'python.exe' (Win32) : Chargé 'C:\Python38\DLLs\_lzma.pyd'. Les symboles ont été chargés.
'python.exe' (Win32) : Chargé 'C:\dev\vobs_sde\build\sdetests_python_binding\win64\stg\Release\sdetests_lib_bind_python.dll'. Le module a été généré sans symboles.
'python.exe' (Win32) : Chargé 'C:\Python38\vcruntime140_1.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\msvcp140.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Python38\Lib\site-packages\PyQt5\QtCore.pyd'. Le module a été généré sans symboles.
'python.exe' (Win32) : Chargé 'C:\Python38\Lib\site-packages\PyQt5\Qt5\bin\Qt5Core.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\shell32.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\mpr.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\netapi32.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\userenv.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Python38\Lib\site-packages\PyQt5\Qt5\bin\msvcp140_1.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\winmm.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\netutils.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\srvcli.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Python38\Lib\site-packages\PyQt5\sip.cp38-win_amd64.pyd'. Le module a été généré sans symboles.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\kernel.appcore.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
Le thread 936 s'est arrêté avec le code 0 (0x0).
Le thread 32580 s'est arrêté avec le code 0 (0x0).
Le thread 21676 s'est arrêté avec le code 0 (0x0).
Le programme '[30116] python.exe' s'est arrêté avec le code 0 (0x0).
With PyQt5 loaded before my library (crash), I get:
'python.exe' (Win32) : Chargé 'C:\Python38\python.exe'. Les symboles ont été chargés.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\ntdll.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\kernel32.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\KernelBase.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\ucrtbase.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Python38\python38.dll'. Les symboles ont été chargés.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\shlwapi.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\msvcrt.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\ws2_32.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\rpcrt4.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\advapi32.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\sechost.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\bcrypt.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Python38\vcruntime140.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\version.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
Le thread 17140 s'est arrêté avec le code 0 (0x0).
'python.exe' (Win32) : Chargé 'C:\Windows\System32\cryptsp.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\rsaenh.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\cryptbase.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\bcryptprimitives.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Python38\python3.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Python38\Lib\site-packages\PyQt5\QtCore.pyd'. Le module a été généré sans symboles.
'python.exe' (Win32) : Chargé 'C:\Python38\Lib\site-packages\PyQt5\Qt5\bin\Qt5Core.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\ole32.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\combase.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\mpr.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\userenv.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\gdi32.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\win32u.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\gdi32full.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\msvcp_win.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\netapi32.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\user32.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\shell32.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Python38\Lib\site-packages\PyQt5\Qt5\bin\msvcp140.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\winmm.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Python38\Lib\site-packages\PyQt5\Qt5\bin\msvcp140_1.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Python38\vcruntime140_1.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Python38\vcruntime140_1.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Déchargé 'C:\Python38\vcruntime140_1.dll'
'python.exe' (Win32) : Chargé 'C:\Windows\System32\netutils.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\srvcli.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\imm32.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Python38\Lib\site-packages\PyQt5\sip.cp38-win_amd64.pyd'. Le module a été généré sans symboles.
'python.exe' (Win32) : Chargé 'C:\Python38\DLLs\_ctypes.pyd'. Les symboles ont été chargés.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\oleaut32.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Python38\DLLs\libffi-7.dll'. Le module a été généré sans symboles.
'python.exe' (Win32) : Chargé 'C:\Python38\DLLs\_bz2.pyd'. Les symboles ont été chargés.
'python.exe' (Win32) : Chargé 'C:\Python38\DLLs\_lzma.pyd'. Les symboles ont été chargés.
'python.exe' (Win32) : Chargé 'C:\dev\vobs_sde\build\sdetests_python_binding\win64\stg\Release\sdetests_lib_bind_python.dll'. Le module a été généré sans symboles.
Exception levée à 0x00007FF9F2412EA0 (msvcp140.dll) dans python.exe : 0xC0000005 : Violation d'accès lors de la lecture de l'emplacement 0x0000000000000000.
The debugger reports the crash msvcp140.dll. A notable difference is that:
- When my library is loaded before PyQt5 (no crash), msvcp140.dll is loaded from 'C:\Windows\System32'
- When my library is loaded after PyQt5 (crash), msvcp140.dll is loaded from 'C:\Python38\Lib\site-packages\PyQt5\Qt5\bin'
The version of the file in System32 is 14.42.34480.0 The version of the file on PyQt5 folder is 14.26.28720.3
If I remove msvcp140.dll from PyQt5 folder, or replace it by a copy of the one found in System32, the crash disappears. So this is likelly the root cause of the problem. But how to fix it? It's not acceptable to have to tell every user of my dll to hack PyQt5 (or any other module using msvcp140.dll) this way....
I'm experiencing a wierd crash when trying to run a C++ library entry point from a Python script. I'm under Windows 10.
I isolated this into a very simple example.
Here is my C++ code:
sdetests_lib_bind_python.h:
#pragma once
#ifdef SDETESTS_LIB_BIND_PYTHON_EXPORTS
/** Export symbols statement */
#define SDETESTS_LIB_BIND_PYTHON __declspec(dllexport)
#else
/** Import symbols statement */
#define SDETESTS_LIB_BIND_PYTHON __declspec(dllimport)
#endif
#ifdef __cplusplus
extern "C" {
#endif
SDETESTS_LIB_BIND_PYTHON void func(int lock);
#ifdef __cplusplus
}
#endif
sdetests_lib_bind_python.cpp:
#include "sdetests_lib_bind_python.h"
#include <iostream>
#include <mutex>
SDETESTS_LIB_BIND_PYTHON void func( int lock )
{
if (lock!=0)
{
std::cout << "Creating mutex" << std::endl;
std::recursive_mutex mutex;
std::cout << "Created mutex" << std::endl;
std::cout << "Locking mutex" << std::endl;
std::lock_guard<std::recursive_mutex> lock_guard(mutex);
std::cout << "Locked mutex" << std::endl;
}
std::cout << "Hello world" << std::endl;
}
I compile this as a shared library using Visual Studio 2022 (MSVC 19.43.34808.0)
Later I run ctypesgen
to generate a binding sdetests_lib_bind_python.py
and I use it from a very simple Python script:
import sdetests_lib_bind_python
print("Calling func without lock")
sdetests_lib_bind_python.func(0)
print("Calling func with lock")
sdetests_lib_bind_python.func(1)
This works fine and output:
Hello from Python script without lock
Hello world
Hello from Python script with lock
Creating mutex
Created mutex
Locking mutex
Locked mutex
Hello world
However, if I load PyQt from my Python script, being now:
from PyQt5.QtCore import QT_VERSION_STR, PYQT_VERSION_STR
print("Qt: v", QT_VERSION_STR, "\tPyQt: v", PYQT_VERSION_STR)
import sdetests_lib_bind_python
print("Calling func without lock")
sdetests_lib_bind_python.func(0)
print("Calling func with lock")
sdetests_lib_bind_python.func(1)
Now the program crashs with output:
Qt: v 5.15.2 PyQt: v 5.15.9
Hello from Python script without lock
Hello world
Hello from Python script with lock
Creating mutex
Created mutex
Locking mutex
Traceback (most recent call last):
File "example_sdetests_lib_bind_python_def.py", line 10, in <module>
sdetests_lib_bind_python_def.func(1)
OSError: exception: access violation reading 0x0000000000000000
So the stcipt crashs if PyQt
is loaded BEFORE (see below) sdetests_lib_bind_python
and if sdetests_lib_bind_python
tries to use a std::recursive_mutex
.
Note that the script also crashs with other modules than PyQt, like rclpy
(all this comes from a ROS2 environment before I isolated it as an MCVE here).
Note that NO crash is observed:
- If
import sdetests_lib_bind_python
statement is the very first line of the script, then I can load PyQt, rclpy, and everything works fine. It only crashs if those other modules are loaded BEFORE sdetests_lib_bind_python - If I compile with an older compiler (MSVC 19.38.33135.0)...this crash appeared recently in my enviropnment after a compiler upgrade
- If my library does not use
std::recursive_mutex
, loading<mutex>
has no impact, but creating a mutex makes the whole thing crash withOSError
. - If I compile the library in "Debug" mode
I'm packaging my library for external users, so asking them to load it first or, if this could be a solution, to upgrade their PyQt or rlypy modules (and whatever other module leading to a crash) is not an acceptable solution for me...
As proposed by 'Ahmed AEK', I checked library loading.
With PyQt5 loaded after my library (no crash), I get:
'python.exe' (Win32) : Chargé 'C:\Python38\python.exe'. Les symboles ont été chargés.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\ntdll.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\kernel32.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\KernelBase.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\ucrtbase.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Python38\python38.dll'. Les symboles ont été chargés.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\shlwapi.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\msvcrt.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\ws2_32.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\rpcrt4.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\advapi32.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\sechost.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\bcrypt.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Python38\vcruntime140.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\version.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
Le thread 27884 s'est arrêté avec le code 0 (0x0).
'python.exe' (Win32) : Chargé 'C:\Windows\System32\cryptsp.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\rsaenh.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\cryptbase.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\bcryptprimitives.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Python38\python3.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Python38\DLLs\_ctypes.pyd'. Les symboles ont été chargés.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\ole32.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Python38\DLLs\libffi-7.dll'. Le module a été généré sans symboles.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\combase.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\gdi32.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\win32u.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\gdi32full.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\msvcp_win.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\user32.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\oleaut32.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\imm32.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Python38\DLLs\_bz2.pyd'. Les symboles ont été chargés.
'python.exe' (Win32) : Chargé 'C:\Python38\DLLs\_lzma.pyd'. Les symboles ont été chargés.
'python.exe' (Win32) : Chargé 'C:\dev\vobs_sde\build\sdetests_python_binding\win64\stg\Release\sdetests_lib_bind_python.dll'. Le module a été généré sans symboles.
'python.exe' (Win32) : Chargé 'C:\Python38\vcruntime140_1.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\msvcp140.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Python38\Lib\site-packages\PyQt5\QtCore.pyd'. Le module a été généré sans symboles.
'python.exe' (Win32) : Chargé 'C:\Python38\Lib\site-packages\PyQt5\Qt5\bin\Qt5Core.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\shell32.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\mpr.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\netapi32.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\userenv.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Python38\Lib\site-packages\PyQt5\Qt5\bin\msvcp140_1.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\winmm.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\netutils.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\srvcli.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Python38\Lib\site-packages\PyQt5\sip.cp38-win_amd64.pyd'. Le module a été généré sans symboles.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\kernel.appcore.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
Le thread 936 s'est arrêté avec le code 0 (0x0).
Le thread 32580 s'est arrêté avec le code 0 (0x0).
Le thread 21676 s'est arrêté avec le code 0 (0x0).
Le programme '[30116] python.exe' s'est arrêté avec le code 0 (0x0).
With PyQt5 loaded before my library (crash), I get:
'python.exe' (Win32) : Chargé 'C:\Python38\python.exe'. Les symboles ont été chargés.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\ntdll.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\kernel32.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\KernelBase.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\ucrtbase.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Python38\python38.dll'. Les symboles ont été chargés.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\shlwapi.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\msvcrt.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\ws2_32.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\rpcrt4.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\advapi32.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\sechost.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\bcrypt.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Python38\vcruntime140.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\version.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
Le thread 17140 s'est arrêté avec le code 0 (0x0).
'python.exe' (Win32) : Chargé 'C:\Windows\System32\cryptsp.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\rsaenh.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\cryptbase.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\bcryptprimitives.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Python38\python3.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Python38\Lib\site-packages\PyQt5\QtCore.pyd'. Le module a été généré sans symboles.
'python.exe' (Win32) : Chargé 'C:\Python38\Lib\site-packages\PyQt5\Qt5\bin\Qt5Core.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\ole32.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\combase.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\mpr.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\userenv.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\gdi32.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\win32u.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\gdi32full.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\msvcp_win.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\netapi32.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\user32.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\shell32.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Python38\Lib\site-packages\PyQt5\Qt5\bin\msvcp140.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\winmm.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Python38\Lib\site-packages\PyQt5\Qt5\bin\msvcp140_1.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Python38\vcruntime140_1.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Python38\vcruntime140_1.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Déchargé 'C:\Python38\vcruntime140_1.dll'
'python.exe' (Win32) : Chargé 'C:\Windows\System32\netutils.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\srvcli.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\imm32.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Python38\Lib\site-packages\PyQt5\sip.cp38-win_amd64.pyd'. Le module a été généré sans symboles.
'python.exe' (Win32) : Chargé 'C:\Python38\DLLs\_ctypes.pyd'. Les symboles ont été chargés.
'python.exe' (Win32) : Chargé 'C:\Windows\System32\oleaut32.dll'. Chargement des symboles désactivé par le paramètre Include/Exclude.
'python.exe' (Win32) : Chargé 'C:\Python38\DLLs\libffi-7.dll'. Le module a été généré sans symboles.
'python.exe' (Win32) : Chargé 'C:\Python38\DLLs\_bz2.pyd'. Les symboles ont été chargés.
'python.exe' (Win32) : Chargé 'C:\Python38\DLLs\_lzma.pyd'. Les symboles ont été chargés.
'python.exe' (Win32) : Chargé 'C:\dev\vobs_sde\build\sdetests_python_binding\win64\stg\Release\sdetests_lib_bind_python.dll'. Le module a été généré sans symboles.
Exception levée à 0x00007FF9F2412EA0 (msvcp140.dll) dans python.exe : 0xC0000005 : Violation d'accès lors de la lecture de l'emplacement 0x0000000000000000.
The debugger reports the crash msvcp140.dll. A notable difference is that:
- When my library is loaded before PyQt5 (no crash), msvcp140.dll is loaded from 'C:\Windows\System32'
- When my library is loaded after PyQt5 (crash), msvcp140.dll is loaded from 'C:\Python38\Lib\site-packages\PyQt5\Qt5\bin'
The version of the file in System32 is 14.42.34480.0 The version of the file on PyQt5 folder is 14.26.28720.3
If I remove msvcp140.dll from PyQt5 folder, or replace it by a copy of the one found in System32, the crash disappears. So this is likelly the root cause of the problem. But how to fix it? It's not acceptable to have to tell every user of my dll to hack PyQt5 (or any other module using msvcp140.dll) this way....
Share Improve this question edited Mar 11 at 7:16 jpo38 asked Mar 10 at 16:50 jpo38jpo38 21.6k12 gold badges81 silver badges180 bronze badges 15 | Show 10 more comments1 Answer
Reset to default 2@AhmedAEK, @jpo38 did a great job identifying the cause of the problem, and also providing possible fixes / workarounds.
Restating it.
Attempting in a Python process to:
Load a .dll:
Built with VStudio 2022
Depending on msvcp140.dll (C++ runtime - libstdc++.so equivalent)
Locking a
std::recursive_mutex
Import PyQt5 (
import PyQt5
) before loading the .dll. This applies (may apply) to other packages as well
results in a crash: Access Violation (SegFault) with NULL pointer access.
Will discuss #1.1. later.
#1.2.: msvcp140.dll will be loaded in the process as a side effect of #1.
#1.3.: I think this is one scenario that leads to this situation and it was encountered by chance, most likely there could be more STL functionalities behaving in the same way
#2.: PyQt5 ships (among others) the VC++ Runtime files msvcp140.dll (v14.26.28720.3). Will refer to this as MSVCP. This allows using the module OOTB (after
pip install
) without the need of installing 3rd-party applications / packages (out of which some might require Administrator privileges - [MS]: Visual C++ Redistributable for Visual Studio 2015).
But this is considered a bad practice (I wrote an email to maintainers ([email protected]) asking a bunch of questions), and can create huge problems if more than one package doing this is loaded in the same process. Check [SO]: ctypes.ArgumentError when using kivy with pywinauto (@CristiFati's answer) for an example (different than the current) of 2 packages stepping on each other 's toes.
Importing PyQt5 doesn't load any libraries, but changes the location where the .dlls are loaded first, adding its own, so any later (automatic) MSVCP load (if not already loaded) will pick it up from there. For more details on .dll load, check items (#3.) from the list at the end
In the question there are listed a bunch of situations where the crash isn't encountered. Let's examine them:
If MSVCP is already loaded (this case), then it will have no (immediate) effect. If it isn't loaded yet, it will be loaded from PyQt5 location, leading to the crash
Same as item #1.1. (from previous list)
Same as item #1.3. (from previous list)
The library links to msvcp140d.dll, which is separate from msvcp140.dll and it's also in System32 (although having 2 MSVCPs in the same process might have disastrous effects)
I was able to reproduce the problem (didn't manage it via CTypesGen, but the old fashioned way (check [SO]: C function called from Python via ctypes returns incorrect value (@CristiFati's answer) for a common pitfall when working with CTypes (calling functions))). Just for the reference, my current (System32) MSVCP version is 14.42.34433.0 (newer than PyQt5's). For .dll dependencies, might want to check [SO]: Discover missing module using command-line ("DLL load failed" error) (@CristiFati's answer).
Now, regarding item #1.1. (#2. from 2nd list): lately, I've encountered on SO other questions about weird problems with C (C++) code built with VStudio 2022 which disappeared when building the same code with VStudio 2019.
I thought this might be a regression bug. But I did some searching and landed on [MS.Learn]: Microsoft Visual C++ Redistributable latest supported downloads - Notes which states (emphasis is mine):
Visual Studio versions since Visual Studio 2015 share the same Redistributable files. For example, any apps built by the Visual Studio 2015, 2017, 2019, or 2022 toolsets can use the latest Microsoft Visual C++ Redistributable. However, the version of the Microsoft Visual C++ Redistributable installed on the machine must be the same or higher than the version of the Visual C++ toolset used to create your application. For more information about which version of the Redistributable to install, see Determining which DLLs to redistribute. For more information about binary compatibility, see C++ binary compatibility between Visual Studio versions.
It starts to make sense: MSVCP (UCRT) is backward (not forward) compatible ([SO]: How to circumvent Windows Universal CRT headers dependency on vcruntime.h (@CristiFati's answer) might have some useful info). Here's the (slightly modified) example:
dll00/include/dll00.h:
#pragma once #if defined(_WIN32) # if defined(DLL00_EXPORTS) # define DLL00_EXPORT_API __declspec(dllexport) # else # define DLL00_EXPORT_API __declspec(dllimport) # endif #else # define DLL00_EXPORT_API #endif #if defined(__cplusplus) extern "C" { #endif DLL00_EXPORT_API int dll00Func00(int lock); #if defined(__cplusplus) } #endif
dll00/src/dll00.cpp:
#define DLL00_EXPORTS #include <dll00.h> #include <iostream> #include <mutex> int dll00Func00(int lock) { if (lock) { std::cout << "Creating mutex" << std::endl; std::recursive_mutex mutex; std::cout << "Created mutex. Locking" << std::endl; std::lock_guard<std::recursive_mutex> lock_guard(mutex); std::cout << "Locked mutex" << std::endl; } std::cout << "Hello world" << std::endl; return lock; }
code00.py:
#!/usr/bin/env python import ctypes as cts import sys def main(*argv): if not argv: print("At least one argument (the .dll) required") return -1 func_arg = 0 if len(argv) > 1: func_arg = int(argv[1]) if argv[1].isdigit() else 0 if len(argv) > 2: #input("Press <Enter> to load PyQt5... ") print("Import PyQt") import PyQt5 dll_name = f"./{argv[0]}" print(f"Loading {dll_name}") dll = cts.CDLL(dll_name) dll00Func00 = dll.dll00Func00 dll00Func00.argtypes = (cts.c_int,) dll00Func00.restype = cts.c_int #input(f"Press <Enter> call dll00Func00({func_arg})... ") res = dll00Func00(func_arg) print("\n{:s} returned: {:d}".format(dll00Func00.__name__, res)) #input("\nPress <Enter> to exit... ") if __name__ == "__main__": print( "Python {:s} {:03d}bit on {:s}\n".format( " ".join(elem.strip() for elem in sys.version.split("\n")), 64 if sys.maxsize > 0x100000000 else 32, sys.platform, ) ) rc = main(*sys.argv[1:]) print("\nDone.\n") sys.exit(rc)
Output:
Console 1:
[cfati@CFATI-5510-0:e:\Work\Dev\StackExchange\StackOverflow\q079498634]> sopr.bat ### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ### [prompt]> :: ---------- TERMINAL 1 (VS2019) ---------- [prompt]> [prompt]> "c:\Install\pc032\Microsoft\VisualStudioCommunity\2019\VC\Auxiliary\Build\vcvarsall.bat" x64 > nul [prompt]> [prompt]> cl /nologo /MD /DDLL /EHsc /Idll00\include dll00\src\dll00.cpp /link /NOLOGO /DLL /OUT:libdll00_19.dll dll00.cpp Creating library libdll00_19.lib and object libdll00_19.exp
Console 2:
[cfati@CFATI-5510-0:e:\Work\Dev\StackExchange\StackOverflow\q079498634]> sopr.bat ### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ### [prompt]> :: ---------- TERMINAL 2 (VS2017) ---------- [prompt]> [prompt]> "c:\Install\pc032\Microsoft\VisualStudioCommunity\2017\VC\Auxiliary\Build\vcvarsall.bat" x64 > nul [prompt]> [prompt]> cl /nologo /MD /DDLL /EHsc /Idll00\include dll00\src\dll00.cpp /link /NOLOGO /DLL /OUT:libdll00_17.dll dll00.cpp Creating library libdll00_17.lib and object libdll00_17.exp
Console 3:
[cfati@CFATI-5510-0:e:\Work\Dev\StackExchange\StackOverflow\q079498634]> sopr.bat ### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ### [prompt]> :: ---------- TERMINAL 3 (VS2015) ---------- [prompt]> [prompt]> "f:\Install\pc032\Microsoft\VisualStudioCommunity\2015\VC\vcvarsall.bat" x64 > nul [prompt]> [prompt]> cl /nologo /MD /DDLL /EHsc /Idll00\include dll00\src\dll00.cpp /link /NOLOGO /DLL /OUT:libdll00_15.dll dll00.cpp Creating library libdll00_15.lib and object libdll00_15.exp
Console 0:
[cfati@CFATI-5510-0:e:\Work\Dev\StackExchange\StackOverflow\q079498634]> sopr.bat ### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ### [prompt]> :: ---------- TERMINAL 0 (Main && VS2022) ---------- [prompt]> [prompt]> dir /b code00.py dll00 [prompt]> [prompt]> "c:\Install\pc064\Microsoft\VisualStudioCommunity\2022\VC\Auxiliary\Build\vcvarsall.bat" x64 > nul [prompt]> [prompt]> cl /nologo /MD /DDLL /EHsc /Idll00\include dll00\src\dll00.cpp /link /NOLOGO /DLL /OUT:libdll00_22.dll dll00.cpp Creating library libdll00_22.lib and object libdll00_22.exp [prompt]> [prompt]> :: Build with older VSs on the other terminal(s) [prompt]> [prompt]> dir /b code00.py dll00 dll00.obj libdll00_15.dll libdll00_15.exp libdll00_15.lib libdll00_17.dll libdll00_17.exp libdll00_17.lib libdll00_19.dll libdll00_19.exp libdll00_19.lib libdll00_22.dll libdll00_22.exp libdll00_22.lib [prompt]> [prompt]> for /f %g in ('dir /b "*.dll"') do ("e:\Work\Dev\VEnvs\py_pc064_03.08_test3_pyqt\Scripts\python.exe" ./code00.py %g 1 load_pyqt) [prompt]> ("e:\Work\Dev\VEnvs\py_pc064_03.08_test3_pyqt\Scripts\python.exe" ./code00.py libdll00_15.dll 1 load_pyqt ) Python 3.8.10 (tags/v3.8.10:3d8993a, May 3 2021, 11:48:03) [MSC v.1928 64 bit (AMD64)] 064bit on win32 Import PyQt Loading ./libdll00_15.dll Creating mutex Created mutex. Locking Locked mutex Hello world dll00Func00 returned: 1 Done. [prompt]> ("e:\Work\Dev\VEnvs\py_pc064_03.08_test3_pyqt\Scripts\python.exe" ./code00.py libdll00_17.dll 1 load_pyqt ) Python 3.8.10 (tags/v3.8.10:3d8993a, May 3 2021, 11:48:03) [MSC v.1928 64 bit (AMD64)] 064bit on win32 Import PyQt Loading ./libdll00_17.dll Creating mutex Created mutex. Locking Locked mutex Hello world dll00Func00 returned: 1 Done. [prompt]> ("e:\Work\Dev\VEnvs\py_pc064_03.08_test3_pyqt\Scripts\python.exe" ./code00.py libdll00_19.dll 1 load_pyqt ) Python 3.8.10 (tags/v3.8.10:3d8993a, May 3 2021, 11:48:03) [MSC v.1928 64 bit (AMD64)] 064bit on win32 Import PyQt Loading ./libdll00_19.dll Creating mutex Created mutex. Locking Locked mutex Hello world dll00Func00 returned: 1 Done. [prompt]> ("e:\Work\Dev\VEnvs\py_pc064_03.08_test3_pyqt\Scripts\python.exe" ./code00.py libdll00_22.dll 1 load_pyqt ) Python 3.8.10 (tags/v3.8.10:3d8993a, May 3 2021, 11:48:03) [MSC v.1928 64 bit (AMD64)] 064bit on win32 Import PyQt Loading ./libdll00_22.dll Creating mutex Created mutex. Locking Traceback (most recent call last): File "./code00.py", line 38, in <module> rc = main(*sys.argv[1:]) File "./code00.py", line 25, in main res = dll00Func00(func_arg) OSError: exception: access violation reading 0x0000000000000000
I've built the .dll using different VStudio versions (have 9 of them installed). Same thing happens if building from VStudio 2022 IDE with an older Platform Toolset ([SO]: What is "Platform Toolset" setting in visual studio project).
As seen, building the .dll with VStudio 2019 (or even an older VStudio 2022 version as in your care) does the trick. But that happens for (latest version (at answer time) of ) PyQt5. Other packages / versions might ship older MSVCPs. So, in order to be as inclusive as possible, the oldest VStudio version (or Platform Toolset) should be used (2015, 140). Of course, those might lack some of the features introduced in newer versions and might run slower (or code might not even compile). So (as almost everywhere else in this life) it's a tradeoff.
Personally, I prefer this approach to others like forcing the load of System32 MSVCP because nothing guarantees that one is newer on every machine (and where isn't we're back to Square 1).
Might also be interesting to read:
[SO]: Python Ctypes - loading dll throws OSError: [WinError 193] %1 is not a valid Win32 application (@CristiFati's answer)
[SO]: Load a DLL with dependencies in Python (@CristiFati's answer)
[SO]: Can't import dll module in Python (@CristiFati's answer)
msvcp140.dll
. Unfortunately, linking statically is too hard work, because in my original code (not MCVE) we have many libraries and use many other third parties, some of them not designed for static linkage... – jpo38 Commented Mar 11 at 7:18msvcp140.dll
by shipping the installer, shipping it in binary form is very wrong, you'd even need a legal permit from microsoft just to legally be able to do it and you have seen why .... try seeing if you can statically link the CRT/MT
instead of/MD
, this can bite you in many ways though. if this doesn't solve the issue then simply don't userecursive_mutex
, or see if you can actually link this older CRT instead by using an older compiler version. – Ahmed AEK Commented Mar 11 at 8:30