withArgs and withProgName permanently modify argv[0]
Summary
The functions withArgs
and withProgName
are meant to temporarily modify the program arguments, either argv[1]
and upwards or argv[0]
. However, they both have the side-effect to permanently modify argv[0]
.
Steps to reproduce
Consider the following example program (full project attached ghc_arg0.tgz ):
module Main where
import Arg0 (getArg0)
import System.Environment (withArgs, withProgName)
main :: IO ()
main = do
before <- getArg0
during <- withProgName "manual" getArg0
-- during <- withArgs [] getArg0
after <- getArg0
putStrLn $ "before " ++ before ++ "\nduring " ++ during ++ "\nafter " ++ after
Observe the following behavior
$ cabal run
before /home/user/ghc_arg0/dist-newstyle/build/x86_64-linux/ghc-8.10.1/ghc-arg0-0.1.0.0/x/ghc-arg0/build/ghc-arg0/ghc-arg0
during manual
after ghc-arg0
I.e. the result of getArg0
is different before and after withProgName
(same with withArgs
).
Expected behavior
withProgName
and withArgs
should fully restore argv[0]
. I.e. the output above should be
before /home/user/ghc_arg0/dist-newstyle/build/x86_64-linux/ghc-8.10.1/ghc-arg0-0.1.0.0/x/ghc-arg0/build/ghc-arg0/ghc-arg0
during manual
after /home/user/ghc_arg0/dist-newstyle/build/x86_64-linux/ghc-8.10.1/ghc-arg0-0.1.0.0/x/ghc-arg0/build/ghc-arg0/ghc-arg0
Environment
- GHC version used: 8.10.1
Optional:
- Operating System: Ubuntu 19.10
- System Architecture: x86_64
Additional context
As pointed out in #3199 (closed) there is no easy access to argv[0]
in GHC. The attached example uses a slight variation of getProgName
that doesn't invoke basename
on the result. Alternatively, there is https://hackage.haskell.org/package/system-argv0-0.1.1.
The motivating use-case is to determine the path by which the program was invoked, see https://github.com/tweag/rules_haskell/pull/1387 for details. Note, this is not necessarily the same as the result of getExecutablePath
as that one uses /proc/self/exe
and resolves symbolic links. The issue was caused by a program calling getProgName
around an optparse-applicative parser to control the program name in error messages generated by optparse-applicative.