/usr/bin/env hangs when a variable is set
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
coreutils (Ubuntu) |
New
|
Undecided
|
Unassigned |
Bug Description
/usr/bin/env hangs when a variable is set. To reproduce this, create a file with the following contents:
#!/usr/bin/env A=B python
; !#
(display "wtf")
(newline)
lets say the file was "wtf.sh". Then chmod ugo+x wtf.sh and then execute it: ./wtf.sh This will hang and spin and burn cpu time. Removing the A=B will cause the script to run just fine (and spew errors, because the conents is not valid python, but that's OK. Instead of python, you could say guile. Its valuid guile. Or you could say bash. whatever, it does not matter)
According to gdb, it is stuck in an infinite loop in the dynamic linker-loader, where /usr/bin/env is calling itself over and over.
I can't quite tell if this is a bug in env, or in ld.so or in thelinux kernel. FWIW #!/usr/bin/env python 42 also gives unexpeted results: it searches for the interpreter "python 42" instead of searching for "python" and passing it the argument "42". Also the following does not work: #!/usr/bin/env -i python -- it spews an error about the -i flag.
This is on both trusty and precise
Attaching gdb to the hung pid gives the following:
gdb -p 27957
(gdb) bt
#0 0x00007fa5286c92d0 in _start () from /lib64/
#1 0x0000000000000003 in ?? ()
#2 0x00007fff36b5ac89 in ?? ()
#3 0x00007fff36b5ac96 in ?? ()
#4 0x00007fff36b5aca0 in ?? ()
#5 0x0000000000000000 in ?? ()
(gdb) c
Continuing.
process 27957 is executing new program: /usr/bin/env
process 27957 is executing new program: /usr/bin/env
process 27957 is executing new program: /usr/bin/env
...
ctrl-C
^C__GI_
74 dl-debug.c: No such file or directory.
Quit
(gdb) bt
#0 __GI__dl_
#1 0x00007f7292b3396a in dl_main (phdr=<optimized out>, phdr@entry=
phnum=
user_
at rtld.c:2305
#2 0x00007f7292b47565 in _dl_sysdep_start (
start_
dl_
#3 0x00007f7292b34cf8 in _dl_start_final (arg=0x7fff11ad
#4 _dl_start (arg=0x7fff11ad
#5 0x00007f7292b312d8 in _start () from /lib64/
#6 0x0000000000000003 in ?? ()
#7 0x00007fff11ae0c89 in ?? ()
#8 0x00007fff11ae0c96 in ?? ()
#9 0x00007fff11ae0ca0 in ?? ()
#10 0x0000000000000000 in ?? ()
(gdb) c
Continuing.
process 27957 is executing new program: /usr/bin/env
process 27957 is executing new program: /usr/bin/env
process 27957 is executing new program: /usr/bin/env
process 27957 is executing new program: /usr/bin/env
process 27957 is executing new program: /usr/bin/env
^C__GI_
74 dl-debug.c: No such file or directory.
Quit
(gdb) Quit
(gdb) Quit
(gdb) bt
#0 __GI__dl_
#1 0x00007f990150396a in dl_main (phdr=<optimized out>, phdr@entry=
phnum=
user_
at rtld.c:2305
#2 0x00007f9901517565 in _dl_sysdep_start (
start_
dl_
#3 0x00007f9901504cf8 in _dl_start_final (arg=0x7fff61a9
#4 _dl_start (arg=0x7fff61a9
#5 0x00007f99015012d8 in _start () from /lib64/
#6 0x0000000000000003 in ?? ()
#7 0x00007fff61a97c89 in ?? ()
#8 0x00007fff61a97c96 in ?? ()
#9 0x00007fff61a97ca0 in ?? ()
#10 0x0000000000000000 in ?? ()
workaround: add -S
#! /usr/bin/env -S A=B python environ[ "A"])
import os; print(os.
why?
shebangs have the limitation (or feature)
that you can pass only one argument
so
#! /usr/bin/env A=B python
is parsed as
argv[0] = "/usr/bin/env"
argv[1] = "A=B python"
you can see this with
#! /usr/bin/printf A=B '(%s) ' 1 2 3 4
which prints
A=B '(./test.sh) ' 1 2 3 4
and
#! /usr/bin/env -S printf '(%s) ' 1 2 3 4
prints
(1) (2) (3) (4) (./test.sh)
now the question is,
why does `argv[1] = "A=B python"` lead to infinite recursion?
expected result:
/usr/bin/env: ‘A=B python’: No such file or directory
/usr/bin/env: use -[v]S to pass options in shebang lines
just like
#! /usr/bin/env hello world
throws
/usr/bin/env: ‘hello world’: No such file or directory
/usr/bin/env: use -[v]S to pass options in shebang lines