Hello.
I found that the current protoype of __getmainargs in crt1.c return void.
But according to the official internal.h from microsoft sdk it return int.
The documentation says: return 0 if successful; a negative value if unsuccessful.
I decompiled it from msvcrt.dll for windows xp.
And the only possible return value for error is -1 and is caused because a malloc cannot get memory.
It do a similar to this:
if ( globb ) {
result = __setargv;
} else {
result = _setargv();
}
if ( result >= 0 ) {
*argc = __argc;
*argv = __argv;
*env = _environ;
}
return result;
It only change the values of argc y argv if success the internal function that it call.
This internals functions __setargv and __setargv() ask for memory with malloc and if it is sucess set that pointer in the global variable __argv. if __argv is NULL because the memory cannot allocated on the heap. It return -1. Then __getmainargs check the return, if it is not a negative number it set argc, argv and env to the corresponding global variables: __argc, __argv, __environ.
Also i write a demo that demostrates that __getmainargs left untouched argc and argv if it fails. (attached)
When you run, it ful the heap (warning: it not free it. I tested on a a virtual machine with windows xp with 64 mb).
When you run it print:
Setting argc to -1 and argv to 1.
Content of argc:-1 argv:0x1
Calling __getmainargs.
__getmainargs failed!
Result of __getmainargs: -1
Content of argc:-1 argv:0x1
Beause it, if __getmainargs fails, it not set argv to NULL or argc to 0.
I added a if that check it, and print out a error message. But I not know if this is the recommended way for handle this error. A maybe possibles ways for handle it is:
set argc to 0 and argv to NULL and env to NULL
call to abort()
call to _exit(3)
call to exit(3)
call to ExitProcess(3)
I choose the last, and also I ad a error message, but it is can be optional:
This is the handle that I added:
if (__getmainargs(&argc, &argv, &env, 0, &start_info)) {
// __getmainargs failed because possible few memory on the heap.
fprintf(stderr, "Error getting the main args.");
// terminate with exit code of 3, similar to abort()
ExitProcess(3);
}
The documentation not says nothing about free argv, maybe because on sucess it points to the global variable __argv and maybe because it is global is free with exit functions (but i not know if this is true).
Here I prefer use ExitProcess instead of exit, because internally exit
do some things and in the end it call to ExitProcess.
I think that ExitProcess is more speedy than exit, but maybe it not do the cleans that exit function makes. Exit function maybe deallocate the global variable __argv
Also, I found that avira antivir detect as false positive a executable compiled with tiny c when it not use ExitProcess, then have a crt using ExitProcess in some point avoid a false detection of our executable.
I use this in some crt for bypass a false detection:
/*
This function is never called.
Is used for avoid AntiVir false detection: TR/Crypt.XPACK.Gen
*/
void nothing(void)
{
ExitProcess(0);
}
Because it I choose use ExitProcess for handle the error of __getmainargs function.
Carlos.