Why doesn't lldb forward my environment variable anymore?

18

I'm working on a patch for FFmpeg and need to debug my code. I'm loading an external library, and in order to test different library versions, I have them in different folders. To select which one I want to use, I've been using DYLD_LIBRARY_PATH=/path/to/lib/dir ./ffmpeg and that works okay. But when I try it within lldb, it crashes saying dyld: Library not loaded and Reason: image not found. This used to work pre-Xcode 7.1, but I just recently upgraded and it stopped working.


Here's my MVCE:

#include <stdio.h>
#include <stdlib.h>

int main() {
  char* str = getenv("DYLD_LIBRARY_PATH");
  if (str) puts(str);
  else     puts("(null)");
  return 0;
}

Running this program as follows produces the output:

$ ./a.out
(null)
$ DYLD_LIBRARY_PATH=/tmp ./a.out
/tmp

That looks okay. But when I try to use lldb it fails:

$ DYLD_LIBRARY_PATH=/tmp lldb ./a.out
(lldb) target create "./a.out"
Current executable set to './a.out' (x86_64).
(lldb) run
Process 54255 launched: './a.out' (x86_64)
(null)
Process 54255 exited with status = 0 (0x00000000)

Trying to set the environment variable inside lldb works:

lldb ./a.out
(lldb) target create "./a.out"
Current executable set to './a.out' (x86_64).
(lldb) env DYLD_LIBRARY_PATH=/tmp
(lldb) run
Process 54331 launched: './a.out' (x86_64)
/tmp
Process 54331 exited with status = 0 (0x00000000) 

lldb version (it's from Xcode 7.1):

$ lldb --version
lldb-340.4.110

Question: Is this an intended new "feature," or is this a new bug in lldb (or am I totally crazy and this never used to work)? I'm quite positive lldb used to forward the DYLD_LIBRARY_PATH environment variable, so how come it isn't anymore?


Edit: This is on OS X 10.11.1.

c
xcode
lldb
asked on Stack Overflow Nov 7, 2015 by Cornstalks • edited Nov 8, 2015 by Cornstalks

1 Answer

30

If this is on El Capitan (OS X 10.11), then it's almost certainly a side effect of System Integrity Protection. From the System Integrity Protection Guide: Runtime Protections article:

When a process is started, the kernel checks to see whether the main executable is protected on disk or is signed with an special system entitlement. If either is true, then a flag is set to denote that it is protected against modification. …

… Any dynamic linker (dyld) environment variables, such as DYLD_LIBRARY_PATH, are purged when launching protected processes.

Everything in /usr/bin is protected in this fashion. Therefore, when you invoke /usr/bin/lldb, all DYLD_* environment variables are purged.

It should work to run lldb from within Xcode.app or the Command Line Tools, like so:

DYLD_LIBRARY_PATH=whatever /Applications/Xcode.app/Contents/Developer/usr/bin/lldb <whatever else>

I don't believe that copy of lldb is protected. /usr/bin/lldb is actually just a trampoline that executes the version in Xcode or the Command Line Tools, so you're ultimately running the same thing. But /usr/bin/lldb is protected so the DYLD_* environment variables are purged when running that.

Otherwise, you will have to set the environment variable inside lldb as shown in this thread:

(lldb) process launch --environment DYLD_LIBRARY_PATH=<mydylibpath> -- arg1 arg2 arg3

or using the short -v option:

(lldb) process launch -v DYLD_LIBRARY_PATH=<mydylibpath> -- arg1 arg2 arg3

Or, you can disable System Integrity Protection, although it serves a good purpose.

answered on Stack Overflow Nov 8, 2015 by Ken Thomases • edited May 11, 2019 by Ken Thomases

User contributions licensed under CC BY-SA 3.0