[New-bugs-announce] [issue15976] Inconsistent behavior of search_for_exec_prefix() results in startup failure in certain cases

Evangelos Foutras report at bugs.python.org
Wed Sep 19 21:57:41 CEST 2012

New submission from Evangelos Foutras:

On Arch Linux /lib is a symbolic link to /usr/lib. When the Python interpreter is provided with an argv[0] of e.g. '/python2.7' and the current working directory is /, it'll fail to start with the following error:

IOError: invalid Python installation: unable to open //include/python2.7/pyconfig.h (No such file or directory)

>From what I understand, what is happening inside Modules/getpath.c is:

1) search_for_exec_prefix() is given an empty `argv0_path`
2) PYTHONHOME is not set, and we're not in a build directory, so step three is executed:

 * Step 3. Try to find prefix and exec_prefix relative to argv0_path,
 * backtracking up the path until it is exhausted.  This is the most common
 * step to succeed.  Note that if prefix and exec_prefix are different,
 * exec_prefix is more likely to be found; however if exec_prefix is a
 * subdirectory of prefix, both will be found.

3) copy_absolute() sets `exec_prefix` to '/'
4) 'lib/python2.7' gets appended to `exec_prefix` using joinpath()
5) 'lib-dynload' gets appended to `exec_prefix` using joinpath()
6) '/lib/python2.7/lib-dynload' exists and the function returns 1 (success)
7) control is returned to calculate_path() which later reduces `exec_prefix` to '/'

During further initialization, sysconfig.py tries to open pyconfig.h, whose path is calculated as {exec_prefix}/include/python2.7/pyconfig.h; thus ending up with the nonexistent path //include/python2.7/pyconfig.h. The correct exec_prefix would be /usr.

Moreover, if argv[0] and/or the current working directory are one level deeper (or more), `exec_prefix` will not be reduced to '/' and search_for_exec_prefix() will proceed to step four:

 * Step 4. Search the directories pointed to by the preprocessor variables
 * PREFIX and EXEC_PREFIX.  These are supplied by the Makefile but can be
 * passed in as options to the configure script.

i.e.: If search_for_exec_prefix() is passed an `argv0_path` with the value '/mnt', step three will only check '/mnt' but not '/', because '/mnt' will be reduced to '' and the `while (exec_prefix[0])` condition will be false.

I see two problems with the behavior I describe above:

1) Step three will skip checking the root directory (/) if argv[0] or the current working directory are one or more levels below / (in other words, not directly under /). Its behavior in this regard is inconsistent.
2) When argv[0] is e.g. '/python2.7' and the current working directory is /, it'll use '/' as the exec_prefix and fail to start. The /lib -> /usr/lib symbolic link should get dereferenced and not used as is.

I'm not sure how this should be fixed, so I only tried to present the issue with as many details as I could. If something is unclear, let me know.

Lastly, search_for_prefix() has very similar code, so any fix will have to be applied there too.

(There is also a downstream bug report @ https://bugs.archlinux.org/task/30812.)

components: Interpreter Core
messages: 170760
nosy: foutrelis
priority: normal
severity: normal
status: open
title: Inconsistent behavior of search_for_exec_prefix() results in startup failure in certain cases
type: crash
versions: Python 2.7, Python 3.2

Python tracker <report at bugs.python.org>

More information about the New-bugs-announce mailing list