Last evening I spent hours debugging a problem that turned out to be a wrong type parameter passed to variadic function.
The way variadic arguments work is that the type of the variable determines how it is stored in the parameter array (the implementations between different platforms and ABIs differ here, there’s no single solution). You then read the parameters in the actual function implementation with va_arg(va, type).
Where things fall apart is that there is no way to perform argument type checking (sure there is a attribute ((format)) which helps with certain specific function types that have format specifiers, but this is not a generic solution).
This gets messy when the type of the argument is isn’t explicitly specified. Imagine this example:
#include <stdio.h>
#include <stdarg.h>
void func(int foo, …)
{
va_list va;
va_start(va, foo);
long long arg = va_arg(va, long long);
printf(“%lld\n”, arg);
va_end(va);
}
int main(void)
{
func(1, 2);
}
That gives no warnings at all. It also fails terribly on many platforms where 32-bit value is placed in argument and then 64-bits is read from it. Needless to say this is a recipe for hard to find bugs.
What you have to do here is to ensure that the caller is explicit about the types of the arguments. So, for example the following work correctly:
func(1, 2LL);
func(1, (long long) 2);
long long a = 2;
func(1, a);
#programming #C
So what was the bug I was looking for?
We recently switched off_t from 32-bit to 64-bit. Once this change was made, suddenly the “ar” tool would start to generate corrupt archives when objects were deleted from the archive.
It took quite a long time to find out that this snippet in the open function was the root cause:
if (!error && (mode & O_TRUNC))
{
syscall(SYS_ftruncate, fd, 0);
Needless to say, ftruncate was getting a very large length argument passed to it, resulting in the underlying filesystem outright refusing to perform any action -> O_TRUNC would not truncate existing files -> ar generated a corrupt archive when the file shrank.
It’s obvious now, but believe me it wasn’t easy to find it.
#bugstories