Last time, I wrote about a problem with printf and size_t. However, I think it is better to say that this is caused by va_args. Because, a program needs to know what type of arguments are there when we use va_args. I think the promotion of arguments is invented to alleviate this problem.
I met an bug as follows recently. This bug only lives in 64bit environment.
Let's assume the following function using va_args.
---
void vafunction(const char* p_name, ...)
{
va_list ap;
va_start(ap, p_name);
while(p_name != 0){
// do something
p_name = va_arg(ap, const char*);
}
va_end(ap);
}
---
If I call this function as
vafunction("This sometimes doesn't work in 64bit.", 0); // (1)
then, this sometimes crashes. This does not always crash. When I traced this bug by a debugger, sometimes p_name never 0, then segmentation fault happens.
But, if I call this as
vafunction("This should always work in 64bit.", NULL); // (2)
always works. The difference here is that the last argument is 0 or NULL only.
Because, the vafunction assumes the arguments are (const char*), however, (1)'s last 0 is 32bit (int)0.
The reason of (2) has no problem is that NULL is defined as 64bit (void *)0. Therefore, this crash only happens in 32bit. In the case of (1), I observed sometimes extra 0 is inserted on the stack, but I think that is just coincident.
I met an bug as follows recently. This bug only lives in 64bit environment.
Let's assume the following function using va_args.
---
void vafunction(const char* p_name, ...)
{
va_list ap;
va_start(ap, p_name);
while(p_name != 0){
// do something
p_name = va_arg(ap, const char*);
}
va_end(ap);
}
---
If I call this function as
vafunction("This sometimes doesn't work in 64bit.", 0); // (1)
then, this sometimes crashes. This does not always crash. When I traced this bug by a debugger, sometimes p_name never 0, then segmentation fault happens.
But, if I call this as
vafunction("This should always work in 64bit.", NULL); // (2)
always works. The difference here is that the last argument is 0 or NULL only.
Because, the vafunction assumes the arguments are (const char*), however, (1)'s last 0 is 32bit (int)0.
The reason of (2) has no problem is that NULL is defined as 64bit (void *)0. Therefore, this crash only happens in 32bit. In the case of (1), I observed sometimes extra 0 is inserted on the stack, but I think that is just coincident.
Comments