Avoiding LD_LIBRARY_PATH: The Options
By Ali Bahrami on Nov 02, 2007
LD_LIBRARY_PATH Seems Useful. What's the Problem?The problem is that LD_LIBRARY_PATH is a crude tool, and cannot be easily targeted at a problem program without also hitting other innocent programs. Sometimes this overspray is harmless (it costs some time, but doesn't break anything). Other times, it causes a program to link to the wrong version of something, and that program dies in mysterious ways.
Historically, inappropriate use of LD_LIBRARY_PATH might be the #1 one way to get yourself into trouble in an ELF environment. In particular, people who redistribute binaries with instructions for their users to set LD_LIBRARY_PATH in their shell startup scripts are unleashing forces beyond their control. Experience tells us that such use is destined to end badly.
This subject has been written about many times by many people. My colleague Rod Evans wrote about this ( LD_LIBRARY_PATH - just say no) for one of his first blog entries.
If you need additional convincing on this point, here are some suggested Google searches you might want to try:
If LD_LIBRARY_PATH is so bad, why does its use persist? Simply because it is the option of last resort, used when everything else has failed. We probably can't eliminate it, but we should strive to reduce its use to the bare minimum.
How to Use, and How To Avoid Using LD_LIBRARY_PATHThe best way to use LD_LIBRARY_PATH is interactively, as a short term aid for testing or development. A developer might use it to point his test program at an alternative version of a library. Beyond that, the less you use it, the better off you'll be. With that in mind, here is a list of ways to avoid LD_LIBRARY_PATH. The items are ordered from best to worst, with the best option right at the top:
- Explicitly set the correct runpath for the objects you
build. If you have the ability to relink the object, you
can always do this, and no other workaround is needed.
To set a runpath in an object, use the -R compiler/linker option.
One common problem that people run into with a built in runpath is the use of an absolute path (e.g. /usr/local/lib). Absolute paths are no problem for the well known system libraries, because their location is fixed by convention as well as by standards. However, they can be trouble for libraries supplied by third parties and installed onto the system. Usually the user has a choice of where such applications are installed, their home directory, or /usr/local being two of the more popular places. An application that hard wires the location of user installed libraries cannot handle this. The solution in this case is to use the $ORIGIN token in those runpaths. The $ORIGIN token, which refers to the directory in which the using object resides, can be used to set a non-absolute runpath that will work in any location, as long as the desired libraries reside at a known location relative to the using program. Fortunately, this is often the case.
For example, consider the case of a 32-bit application named myapp, which relies on a sharable library named mylib.so, as well as on the standard system libraries found in /lib and /usr/lib. The -R option to put the runpath into myapp that will look in these places would be:
This allows myapp and mylib.so to be installed anywhere, as long as they are kept in the same positions relative to each other.
Even for system libraries, the use of $ORIGIN can be useful. We use it for all of the linker components in the system. For instance:
By setting the runpath using $ORIGIN instead of simply hardwiring the well known location /lib, we make it easier to test a tree of alternative linker components, such as results when we do a full build of the Solaris ON consolidation. We know that when we run a test copy of ld, that it will use the related libraries that were built with it, instead of binding to the installed system libraries.
% elfdump -d /usr/bin/ld | grep RUNPATH  RUNPATH 0x2e6 $ORIGIN/../../lib
There is one exception to the advice to make heavy use of $ORIGIN. The runtime linker will not expand tokens like $ORIGIN for secure (setuid) applications. This should not be a problem in the vast majority of cases.
- Many times, the problem comes in the form of open source software that explicitly sets the runpath to an incorrect value for Solaris. Can you fix the configuration script and contribute the change back to the package maintainer? You'll be doing lots of people a favor if you do.
- If you have an object with a bad runpath (or no runpath) and the
object cannot be rebuilt, it may be possible to alter its runpath
using the elfedit command. Using the myapp example from the
For this option to be possible, you need to be running a recent version of Solaris that has elfedit, and your object has to have been linked by a version of Solaris that has the necessary extra room. Quoting from the elfedit manpage:
elfedit -e 'dyn:runpath $ORIGIN/../lib:/lib:/usr/lib' myapp
The desired string must already exist in the dynamic string table, or there must be enough reserved space within this section for the new string to be added. If your object has a string table reservation area, the value of the .dynamic DT_SUNW_STRPAD element indicates the size of the area. The following elfedit command can be used to check this:
% elfedit -r -e 'dyn:tag DT_SUNW_STRPAD' file
The dynamic section must already have a runpath element, or there must be an unused dynamic slot available where one can be inserted. To test for the presence of an existing runpath:
% elfedit -r -e 'dyn:runpath' file
A dynamic section uses an element of type DT_NULL to terminate the array found in that section. The final DT_NULL cannot be changed, but if there are more than one of these, elfedit can convert one of them into a runpath element. To test for extra dynamic slots:
% elfedit -r -e 'dyn:tag DT_NULL' file
- If your application was linked with the -c option to the linker,
then you can use the crle command to alter the configuration file
associated with the application and change the settings for
LD_LIBRARY_PATH that are applied for that application. This is a
pretty good solution, but is limited by its complexity, and by the
fact that the person who linked the object needs to have thought
ahead far enough to provide for this option. Odds are that they
didn't. If they had, they might just as well have set the
runpath correctly in the first place, eliminating the need for
You can use crle with an application that was not linked with -c, either by setting the LD_CONFIG environment variable, or by modifying the global system configuration file. However, both of these options suffer from the same issues as the LD_LIBRARY_PATH environment variable: They are too coarse grained to be applied to a single application in a targeted way.
- If none of the above are possible, then you are indeed stuck with
LD_LIBRARY_PATH. In this case, the goal should be to minimize the
number of applications that see this environment variable. You should
never set it in your interactive shell environment (via whatever
dot file your shell supports: .profile, .login, .cshrc, .basrc, etc...).
Instead, put it in a wrapper shell script that you use to run the
The use of a wrapper script is a pretty safe way to use LD_LIBRARY_PATH, but you should be aware of one limitation of this approach: If the program being wrapped starts any other programs, then those programs will see the LD_LIBRARY_PATH environment variable. Since programs starting other programs is a common Unix technique, this form of leakage can be more common that you might realize.