0

I'm trying to access the length of the compiled binary of a program, but it returns -1. Could someone point me on the right track? I'm uncertain as to why the following code isn't producing the correct result.

std::fstream file(argv[0], std::ios::binary | std::ios::ate);
std::cout << file.tellg() << "\n";
Yu Hao
  • 111,229
  • 40
  • 211
  • 267
  • possible duplicate of [Using C++ filestreams (fstream), how can you determine the size of a file?](http://stackoverflow.com/questions/2409504/using-c-filestreams-fstream-how-can-you-determine-the-size-of-a-file) – Tony Hopkinson Jun 29 '13 at 06:08
  • Try one of the answers that seeks then end of the file then does tellg. – Tony Hopkinson Jun 29 '13 at 06:09

2 Answers2

1

A result of -1 indicates that the open failed. You should always test for this:

if (std::fstream file(argv[0], std::ios::binary | std::ios::ate)) {
    std::cout << file.tellg() << "\n";
} else {
    // Report error.
}

The second problem is that if you just want to get its length, you should open it for reading only (this might be why the open is failing):

std::ifstream file(argv[0], …);

The third issue is that argv[0] isn't guaranteed to contain a valid executable name. That's just a widely held assumption. You'll usually get away with it, but you should keep it in mind.

Marcelo Cantos
  • 167,268
  • 37
  • 309
  • 353
  • Ah, thanks. I'll add in a check to make sure it reads the executable, didn't realize it wasn't a guarantee. – user2142343 Jun 29 '13 at 06:47
  • 1
    Related to this problem is that, even if `argv[0]` contains a meaningful filename, it might still not resolve correctly when passed to `ifstream`. For instance, if your program foobar is found on the path and isn't in the current directory, `argv[0]` will contain `foobar`, which will fail to open because there is nothing called foobar in the current directory. – Marcelo Cantos Jun 29 '13 at 07:01
  • 1
    … or if the user executes the program with different permissions from what the shell used to find it, such as with `sudo someuser`. There are countless things to go wrong. C++ doesn't even guarantee there's a filesystem on the machine at all. And of course the program might not be stored in a file, even if there is a filesystem. – Potatoswatter Jun 29 '13 at 08:52
  • I'm now trying to write to the file, so I added std::ios::out to the flags. However, tellg() once again produces -1 indicating the open failed. Are you not allowed to use a single fstream for both reading and writing? – user2142343 Jun 29 '13 at 19:31
  • 1
    @user2142343: Yes, but if you took my advice to use `std::ifstream`, then you've essentially stipulate that you only want to read. Even if you fix this, you may not be permitted to write to the binary of a running program. You certainly can't in Windows; Linux is less restrictive, but you may still encounter problems. – Marcelo Cantos Jun 30 '13 at 03:45
  • 1
    @user2142343: You'll probably get a much more helpful response from SO if you provide some background information. Why do want to do this? What are you trying to achieve? This will reduce the risk of stumbling over [the XY problem](http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem). – Marcelo Cantos Jun 30 '13 at 03:47
  • Essentially, I need a binary that rewrites itself to turn certain probe points on and off (being used for always-on profiling to improve parallel performance on a network). Right now, I'm trying to just open the binary, and insert a jump to a function pointer at a probe point. Later on I'll worry about creating calling conventions and not seg faulting. – user2142343 Jun 30 '13 at 04:37
  • Also, I ended up using fopen with "rb", as I need to use fseek to insert code at the probe point. In this case, I believe I need "r+b" (for both read/right), but again, the file doesn't open when I want write capabilities. – user2142343 Jun 30 '13 at 04:40
1

Simply adding std::ios::in to the open mode flags makes it work for me. (The constructor was failing to open the file. According to the Standard, you must specify one of in, out, or app.)

Changing the stream type to std::istream also works, but the resulting binary is 8 bytes larger.

Potatoswatter
  • 126,977
  • 21
  • 238
  • 404
  • Ah, thanks so much. Changing the stream type actually broke it for me, but with the ios::in specification it worked fine. Odd that istream would increase filesize by so much though. – user2142343 Jun 29 '13 at 06:46