Size of an executable at runtime in C/C++ on Linux without /proc/self/exe?
dl_iterate_phdr
https://linux.die.net/man/3/dl_iterate_phdr
This solved it! Thanks @o11c!
What could break /proc/self/exe?
So the cause turned out to be UPX (executable compressor). I hadn't thought of it earlier because it was included in my build pipeline. Apparently, on some systems it doesn't extract to memory but uses a temp file, which caused this error. Am still puzzled why the trace output doesn't show a rename, but alas.
How do I find the location of the executable in C? [duplicate]
To summarize:
On Unixes with
/proc
really straight and realiable way is to:readlink("/proc/self/exe", buf, bufsize)
(Linux)readlink("/proc/curproc/file", buf, bufsize)
(FreeBSD)readlink("/proc/self/path/a.out", buf, bufsize)
(Solaris)
On Unixes without
/proc
(i.e. if above fails):If argv[0] starts with "/" (absolute path) this is the path.
Otherwise if argv[0] contains "/" (relative path) append it to cwd
(assuming it hasn't been changed yet).Otherwise search directories in
$PATH
for executableargv[0]
.
Afterwards it may be reasonable to check whether the executable isn't actually a symlink.
If it is resolve it relative to the symlink directory.This step is not necessary in /proc method (at least for Linux).
There the proc symlink points directly to executable.Note that it is up to the calling process to set
argv[0]
correctly.
It is right most of the times however there are occasions when the calling process cannot be trusted (ex. setuid executable).On Windows: use
GetModuleFileName(NULL, buf, bufsize)
Getting length of /proc/self/exe symlink
In practice, I would tend to use a reasonable size (e.g. 256 or 1024, or PATH_MAX
) for readlink
of /proc/*/exe
(or /proc/self/exe
)
The point is that almost always, executables are supposed to be started by humans, so either the PATH
(for execvp(3) or some shell) or the entire file path is human friendly. I don't know any people who explicitly uses very long filenames (not fitting in width in some terminal screen). I never heard of executable programs (or scripts) whose filename exceeds a hundred of bytes.
So just use a local buffer of some reasonable size (and perhaps strdup
it on success if so needed). And readlink(2) returns the number of meaningful bytes in its buffer (so if you really care, grow the buffer and make a loop till it fits).
For readlink
of /proc/self/exe
, I would do it into a 256 bytes buffer at initialization, and abort (with a meaningful error message) if it does not fit (or fail, e.g. because /proc/
is not mounted).
How to handle readlink() of /proc/self/exe when executable is replaced during execution?
Instead of using readlink
to discover the path to your own executable, you can directly call open
on /proc/self/exe
. Since the kernel already has an open fd to processes that are currently executing, this will give you an fd regardless of whether the path has been replaced with a new executable or not.
Next, you can use fexecve
instead of execv
which accepts an fd
parameter instead of a filename
parameter for the executable.
int fd = open("/proc/self/exe", O_RDONLY);
fexecve(fd, argv, envp);
Above code omits error handling for brevity.
Get executable's path (with std::filesystem) [duplicate]
No, there's nothing provided in the standard filesystem facilities to get the path of your executable.
Even using using the 1st argv
argument isn't guaranteed to contain the full path of the executable.
The systems I know will just pass in the string that was used to launch the program.
Considering that this could be resolved using the PATH
environment variable, there's no guarantee, you see a full path there.
There are some OS specific methods to do so though:
- Get path of executable
how to find the location of the executable in C in OS X [duplicate]
Mac OS X implements the functions:
int _NSGetExecutablePath(char * buf, uint32_t * length);
int * _NSGetArgc(void);
char *** _NSGetArgv(void);
The first of these is probably what you want here. The other two are interesting as well, though!
Related Topics
Invalid Operands Error for Addition and Integer Division
Difference Between #Include ≪Filename≫ and #Include "Filename"
What Is the Most Effective Way For Float and Double Comparison
Is It a Good Idea to Typedef Pointers
What Are Rvalues, Lvalues, Xvalues, Glvalues, and Prvalues
How to Tokenize a String in C++
What Are Forward Declarations in C++
What Should Main() Return in C and C++
How to Iterate Over the Words of a String
Resolve Build Errors Due to Circular Dependency Amongst Classes
What Is This Weird Colon-Member (": ") Syntax in the Constructor
How to Remove "Noise" from Gcc/Clang Assembly Output
How to Read and Parse CSV Files in C++
What Is a Lambda Expression in C++11
When to Use Virtual Destructors
Read File Line by Line Using Ifstream in C++
How to Take Input to an Array With Unknown Number of Elements
Take the Address of a One-Past-The-End Array Element Via Subscript: Legal by the C++ Standard or Not