75

I was wandering in SO and saw this question. Then I started wondering if I can overflow argc.

Standard says that argv[argc] must be a null pointer but this will be false if argc overflow.

(I wrote a small C program and a python script to test it but got a MemoryError.)

Thanks!


Rationale for International Standard — Programming Languages — C §5.1.2.2.1 Program startup

The specification of argc and argv as arguments to main recognizes extensive prior practice. argv[argc] is required to be a null pointer to provide a redundant check for the end of the list, also on the basis of common practice.

Community
  • 1
  • 1
Bora M. Alper
  • 3,538
  • 1
  • 24
  • 35
  • 13
    `Standard says that argv[argc] must be a null pointer but this will be false if argc overflow` -- I read this as "Don't let argc overflow." ("Doctor, it hurts when I do this") – Robert Harvey Jan 21 '15 at 19:33
  • 4
    On POSIX and on most Linux systems, the initial stack of `main` -as installed by `execve`-, including its arguments (i.e. `argv`), is much more limited (typically, a few megabytes). So `argc` is less than a few milions and I never heard of an OS where `argc` could be near `INT_MAX` – Basile Starynkevitch Jan 21 '15 at 19:35
  • 1
    @BasileStarynkevitch: If `int` is 16 bits, it could overflow. – SLaks Jan 21 '15 at 19:37
  • 6
    arguably the implementation will in such case have system specific limit that makes it impossible to pass 2^15 arguments to a program – nos Jan 21 '15 at 19:40
  • 14
    Well, I'm certainly not typing them in:) – Martin James Jan 21 '15 at 20:17
  • 1
    How exactly would you pass a number of arguments to a process that would, effectively, exceed the process memory space all by itself, not even counting the executable *taking* those arguments? – DevSolar Jan 22 '15 at 09:25
  • 1
    @DevSolar: the quotation is speaking of unusual corner cases, I wouldn't be too surprised if there's an implementation out there where `int` is smaller than the process memory space. Even if there isn't one, it's the kind of hypothetical that the standards folks fret about while considering the rationales for their decisions. After all, they decided not to ban it. – Steve Jessop Jan 22 '15 at 09:44
  • 3
    Hang on a second, what do I mean "I wouldn't be surprised". Any LP64 or LLP64 architecture fits the bill, so Windows or Linux. You'd need a lot of RAM, though. I suppose that if starting from scratch, `argc` should have type `size_t`. – Steve Jessop Jan 22 '15 at 10:43
  • @SteveJessop: That's what you get for playing it through only for the *old* and *small* architectures. You're right, of course. – DevSolar Jan 22 '15 at 11:04

4 Answers4

78

According to the standard

So, from your quote:

argv[argc] is required to be a null pointer

Therefore, argc cannot overflow, because then the above statement would not be true.

In practice

In practice, the total size of the arguments passed to a program is limited.

On my Linux/x64 system:

$ getconf ARG_MAX
2097152

Therefore, the total argument size is about 2 megabytes, and argc cannot overflow. I believe this limit measures a combination of the total data in argv and the environment. If you exceed this limit when you try to run a command, exec() will fail with E2BIG. From man 2 execve:

E2BIG  The total number of bytes in the environment (envp) and argument
       list (argv) is too large.

I believe the ~2 megabyte limit on my system is relatively generous compared to other systems. My OS X system reports a limit of ~260KB.

But what if ARG_MAX were really big?

Okay, let's suppose you're on an old/weird system, so int is 16 bits, and ARG_MAX is well over 215, which is otherwise quite reasonable. Now, suppose you invoke execve() with more than 215 arguments. The implementation has two options.

  1. It can allow argc to overflow... basically, throwing away your data, ensuring that the program you're running executes in some unexpected and probably erroneous manner, and violating the C standard. Worst of all, the error is silent, so you might never know.

  2. Or, it can simply return EOVERFLOW from execve(), informing you that it simply can't run an image with that many parameters. Now, the POSIX / SUS standards don't mention anything about this error result... but, I suspect this is simply because the standard writers never expected ARG_MAX to be larger than INT_MAX.

Option #2 is the only reasonable option. If your system somehow chooses option #1, then it is broken and you should file a bug report.

Alternatively, you could be trying to run an old program compiled for a 16-bit system, but you're running it through some kind of emulator or compatibility layer. I'd expect that the emulator or compatibility layer would give an error message if you tried to pass more than 215 parameters to a program.

Jens Timmerman
  • 9,316
  • 1
  • 42
  • 48
Dietrich Epp
  • 205,541
  • 37
  • 345
  • 415
  • But imagine you are on a system where the ARG_MAX thing is pretty big (for what reasons ever) and it could happen. What kind of failure would it be? As it is still respecting the standard, it can be called C compatible, but it also could occur a undefined behaving, where the programmer has no option to prevent. What kind of error is it? – dhein Jan 22 '15 at 12:40
  • I think the Standard has undefined behaviour, there, as signed overflow is not defined. – Sebastian Mach Jan 22 '15 at 14:16
  • 1
    @zaibis The requirement for `argv[argc]` to be a null pointer implies a requirement to set `ARG_MAX` small enough that `argc` *cannot* overflow. – zwol Jan 22 '15 at 16:38
17

In practice, no, you can't. Most systems place a relatively low limit on the total combined size of argv and envp. Limits in the tens to low hundreds of KB aren't uncommon; see http://www.in-ulm.de/~mascheck/various/argmax/ for a reasonably comprehensive listing of the limits on various OSes.

  • 1
    That list have no data for Windows but there is [question on SO](http://stackoverflow.com/questions/3205027/maximum-length-of-command-line-string) with some numbers. – PTwr Jan 22 '15 at 07:49
11

I tried this:

test.c :

 ⚡⚡⚡  more test.c 
#include <stdio.h>
int main(int argc, char **argv)
{
    printf("argc = %d\n", argc);
    printf("Size of argc = %d\n", sizeof(argc));
    return 0;
}

Then used a big zipfile

 ⚡⚡⚡  ls -h bigfile 
-rw-r--r-- 1 ehwas ehwas 355M Jan 22 16:54 bigfile

Then read the file as parameters to the test program:

⚡⚡⚡  ./test $(more bigfile)

Result:

5 minutes nothing happend, then everything froze

Then I tried a smaller file:

 ⚡⚡⚡  ls -h notsobigfile 
-rw-r--r-- 1 ehwas ehwas 6.7M Jan 22 17:04 notsobigfile

And:

 ⚡⚡⚡  ./test $(more notsobigfile)
bash: ./test: Argument list too long
ehwas
  • 248
  • 1
  • 9
2

As indicated by the standard, argv[argc] must be a valid value.

So if the run-time environment is in a situation such that it cannot guarantee that, it should not start the program.