Skip to content

Commit d9e063f

Browse files
tnytowngodlygeek
andcommitted
attach: Gracefully handle file permission errors
When `memray attach` uses a debugger to attach to the target process, it instructs the process to `dlopen()` a shared library that's part of Memray. If the Memray install is owned by a different user than the process being attached to, it's possible the target process won't have the privileges necessary to load the library. In GDB's case this leads to an internal error, taking the target process down with the debugger. Work around this by adding an explicit permission check to the GDB script and bailing out with a clear error message if the shared library can't be read. Add a matching error message to the LLDB script, though for LLDB we can let the `dlopen` run and gracefully handle the failure. Signed-off-by: Andrew Pan <andrew.pan@trailofbits.com> Co-authored-by: Matt Wozniski <mwozniski@bloomberg.net>
1 parent fb215dd commit d9e063f

4 files changed

Lines changed: 21 additions & 2 deletions

File tree

news/940.bugfix.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Fix a bug that crashed target processes when ``memray attach`` fails. The underlying permissions issue is now accounted for and a troubleshooting message prints when it arises.

src/memray/commands/_attach.gdb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@ p "MEMRAY: Process is Python 3.7+."
1818
set scheduler-locking on
1919
call (int)Py_AddPendingCall(&PyCallable_Check, (void*)0)
2020

21+
p "Checking if we can access the library"
22+
set $result = (int)access($libpath, 5)
23+
if $result != 0
24+
p "cannot open shared object file"
25+
quit 1
26+
end
27+
2128
# When updating this list, also update the "commands" call below,
2229
# and the breakpoints hardcoded for lldb in attach.py
2330
b malloc

src/memray/commands/_attach.lldb

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ p ((void(*)(void*))PyMem_Free)
99

1010
p "MEMRAY: Process is Python 3.7+."
1111

12-
# When adding new breakpoints, also update _attach.gdb
12+
# When adding new breakpoints, also update _attach.gdb - but note that
13+
# PyErr_CheckSignals and PyCallable_Check are intentionally excluded,
14+
# as for some reason including them caused lldb on Linux to stop at
15+
# breakpoints that had already been deleted.
1316
breakpoint set -b malloc -b calloc -b realloc -b free -b PyMem_Malloc -b PyMem_Calloc -b PyMem_Realloc -b PyMem_Free
1417

1518
# Set commands to execute when breakpoint is reached
@@ -21,7 +24,8 @@ expr auto $dlerror = $dlsym($rtld_default, "dlerror")
2124
expr auto $dll = ((void*(*)(const char*, int))$dlopen)($libpath, $rtld_now)
2225
p ((char*(*)(void))$dlerror)()
2326
expr auto $spawn = $dlsym($dll, "memray_spawn_client")
24-
p ((int(*)(int))$spawn)($port)?"FAILURE":"SUCCESS"
27+
p ((char*(*)(void))$dlerror)()
28+
p (!$dll || !$spawn || ((int(*)(int))$spawn)($port)) ? "FAILURE" : "SUCCESS"
2529
DONE
2630

2731
continue

src/memray/commands/attach.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,13 @@ def debugger_inject(debugger: str, pid: int, port: int, verbose: bool) -> str |
231231
if "MEMRAY: Process is Python 3.7+." not in output:
232232
return "The process does not seem to be running Python 3.7 or newer."
233233

234+
if "cannot open shared object file" in output:
235+
return (
236+
"The target process couldn't open the memray shared library.\n"
237+
"This can occur if the memray installation is owned by a different user "
238+
"and is inaccessible to the target process."
239+
)
240+
234241
return "An unexpected error occurred. Run with --verbose to debug the failure."
235242

236243

0 commit comments

Comments
 (0)