Skip to content

Commit 15bbdd1

Browse files
[lldb][windows] print an error if python.dll is not in the DLL search path (llvm#164893)
This is a follow up to llvm#162509. Using the `SearchPathW` API, we can ensure that the correct version of Python is installed before `liblldb` is loaded (and `python.dll` subsequently). If it's not, we try to add it to the search path with the methods introduced in llvm#162509. If that fails or if that method is `#ifdef`'d out, we print an error which will appear before lldb crashes due to the missing dll. Before llvm#162509, when invoked from Powershell, lldb would silently crash (no error message/crash report). After llvm#162509, it crashes without any indications that the root cause is the missing python.dll. With this patch, we print the error before crashing.
1 parent a8ea7f4 commit 15bbdd1

File tree

3 files changed

+65
-12
lines changed

3 files changed

+65
-12
lines changed

lldb/CMakeLists.txt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,12 @@ if (LLDB_ENABLE_PYTHON)
8787
set(LLDB_PYTHON_EXT_SUFFIX "_d${LLDB_PYTHON_EXT_SUFFIX}")
8888
endif()
8989
endif()
90+
if(TARGET Python3::Python)
91+
get_target_property(_Python3_LIB_PATH Python3::Python IMPORTED_LIBRARY_LOCATION)
92+
if(_Python3_LIB_PATH)
93+
get_filename_component(LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME "${_Python3_LIB_PATH}" NAME)
94+
endif()
95+
endif()
9096
endif ()
9197

9298
if (LLDB_ENABLE_LUA)

lldb/tools/driver/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ add_dependencies(lldb
3737
if(DEFINED LLDB_PYTHON_DLL_RELATIVE_PATH)
3838
target_compile_definitions(lldb PRIVATE LLDB_PYTHON_DLL_RELATIVE_PATH="${LLDB_PYTHON_DLL_RELATIVE_PATH}")
3939
endif()
40+
if(DEFINED LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME)
41+
target_compile_definitions(lldb PRIVATE LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME="${LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME}")
42+
endif()
4043

4144
if(LLDB_BUILD_FRAMEWORK)
4245
# In the build-tree, we know the exact path to the framework directory.

lldb/tools/driver/Driver.cpp

Lines changed: 56 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -433,7 +433,8 @@ SBError Driver::ProcessArgs(const opt::InputArgList &args, bool &exiting) {
433433
return error;
434434
}
435435

436-
#if defined(_WIN32) && defined(LLDB_PYTHON_DLL_RELATIVE_PATH)
436+
#ifdef _WIN32
437+
#ifdef LLDB_PYTHON_DLL_RELATIVE_PATH
437438
/// Returns the full path to the lldb.exe executable.
438439
inline std::wstring GetPathToExecutableW() {
439440
// Iterate until we reach the Windows API maximum path length (32,767).
@@ -447,30 +448,73 @@ inline std::wstring GetPathToExecutableW() {
447448
return L"";
448449
}
449450

450-
/// Resolve the full path of the directory defined by
451+
/// \brief Resolve the full path of the directory defined by
451452
/// LLDB_PYTHON_DLL_RELATIVE_PATH. If it exists, add it to the list of DLL
452453
/// search directories.
453-
void AddPythonDLLToSearchPath() {
454+
/// \return `true` if the library was added to the search path.
455+
/// `false` otherwise.
456+
bool AddPythonDLLToSearchPath() {
454457
std::wstring modulePath = GetPathToExecutableW();
455-
if (modulePath.empty()) {
456-
llvm::errs() << "error: unable to find python.dll." << '\n';
457-
return;
458-
}
458+
if (modulePath.empty())
459+
return false;
459460

460461
SmallVector<char, MAX_PATH> utf8Path;
461462
if (sys::windows::UTF16ToUTF8(modulePath.c_str(), modulePath.length(),
462463
utf8Path))
463-
return;
464+
return false;
464465
sys::path::remove_filename(utf8Path);
465466
sys::path::append(utf8Path, LLDB_PYTHON_DLL_RELATIVE_PATH);
466467
sys::fs::make_absolute(utf8Path);
467468

468469
SmallVector<wchar_t, 1> widePath;
469470
if (sys::windows::widenPath(utf8Path.data(), widePath))
470-
return;
471+
return false;
471472

472473
if (sys::fs::exists(utf8Path))
473-
SetDllDirectoryW(widePath.data());
474+
return SetDllDirectoryW(widePath.data());
475+
return false;
476+
}
477+
#endif
478+
479+
#ifdef LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME
480+
/// Returns whether `python3x.dll` is in the DLL search path.
481+
bool IsPythonDLLInPath() {
482+
#define WIDEN2(x) L##x
483+
#define WIDEN(x) WIDEN2(x)
484+
WCHAR foundPath[MAX_PATH];
485+
DWORD result =
486+
SearchPathW(nullptr, WIDEN(LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME), nullptr,
487+
MAX_PATH, foundPath, nullptr);
488+
#undef WIDEN2
489+
#undef WIDEN
490+
491+
return result > 0;
492+
}
493+
#endif
494+
495+
/// Try to setup the DLL search path for the Python Runtime Library
496+
/// (python3xx.dll).
497+
///
498+
/// If `LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME` is set, we first check if
499+
/// python3xx.dll is in the search path. If it's not, we try to add it and
500+
/// check for it a second time.
501+
/// If only `LLDB_PYTHON_DLL_RELATIVE_PATH` is set, we try to add python3xx.dll
502+
/// to the search path python.dll is already in the search path or not.
503+
void SetupPythonRuntimeLibrary() {
504+
#ifdef LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME
505+
if (IsPythonDLLInPath())
506+
return;
507+
#ifdef LLDB_PYTHON_DLL_RELATIVE_PATH
508+
if (AddPythonDLLToSearchPath() && IsPythonDLLInPath())
509+
return;
510+
#endif
511+
llvm::errs() << "error: unable to find '"
512+
<< LLDB_PYTHON_RUNTIME_LIBRARY_FILENAME << "'.\n";
513+
return;
514+
#elif defined(LLDB_PYTHON_DLL_RELATIVE_PATH)
515+
if (!AddPythonDLLToSearchPath())
516+
llvm::errs() << "error: unable to find the Python runtime library.\n";
517+
#endif
474518
}
475519
#endif
476520

@@ -776,8 +820,8 @@ int main(int argc, char const *argv[]) {
776820
"~/Library/Logs/DiagnosticReports/.\n");
777821
#endif
778822

779-
#if defined(_WIN32) && defined(LLDB_PYTHON_DLL_RELATIVE_PATH)
780-
AddPythonDLLToSearchPath();
823+
#ifdef _WIN32
824+
SetupPythonRuntimeLibrary();
781825
#endif
782826

783827
// Parse arguments.

0 commit comments

Comments
 (0)