Argv Redistribution

I looked at the code for the GNU coreutils package, in particular the yes program , when I saw this block of code in main (line 78):

 if (argc <= optind) { optind = argc; argv[argc++] = bad_cast ("y"); } 

How can I expand the argv array this way? Obviously, just removing any piece of code from the context is a really bad idea, so I looked that if argv was changed in advance and it doesn't look like calling initialize_main (&argc, &argv) , which doesn't seem to work accepts an argument for a "new size" or something similar (but in C, as in any language, things are not always what they seem).

I decided to write a simple program to check if I can call realloc() on argv

 char** new_argv = realloc(argv, ++argc * sizeof*argv); 

And it worked (from VS2013 on Windows 10). He returned a pointer to the allocated memory. Of course, this does not mean anything if this behavior is undefined.

So a long story, my question is how argv distributed? Is realloc argv safe?

+4
source share
2 answers
 argv[argc++] = bad_cast ("y"); 

This does not expand the argv array. It simply sets the value of argv[argc] , and then increments argc . This violates the original guarantee that argv[argc] == NULL , but so far the code does not rely on its validity.

The standard ensures that:

The parameters are argc and argv , and the lines pointed to by the argv array must be modified by the program and save their values ​​stored at the last moment between the start of the program and the end of the program.

It does not explicitly guarantee that the char* pointers in the array pointed to by argv are mutable, but this is a reasonable assumption that they are. (Strictly speaking, argv points to the first element of the array, not the array itself, but this sentence has been around for quite some time.)

 char** new_argv = realloc(argv, ++argc * sizeof*argv); 

This behavior is undefined. The first realloc argument must be either a null pointer or a memory pointer allocated by malloc , calloc , realloc , or equivalent. The memory pointed to by argv is allocated in some vague way until main entered. You can make a copy of the array, but you cannot legally free it, which is part of what realloc does. If the realloc call behaved “right” for you, you're just out of luck. (If you were lucky, your program would crash, which would tell you that there is a problem.)

+2
source

First, argv[argc] is defined as NULL .

Secondly, argc++ increments argc , but returns the old value.

Thus, argv[argc++] = ... does not cause undefined behavior; it just assigns a new value earlier to the NULL pointer.

+5
source

All Articles