I'm working on the AVR platform. avr-libc does not provide asprintf()
. A library I'm attempting to bring into my project requires it. Helpfully, that same library includes an implementation (below). Unfortunately, it is providing odd results. Specifically, I've determined that the return code of vsnprintf()
is never correct; rather than random results, I seem to always see the same progression of incorrect values (5, 1, etc.) upon successive calls.
The call to this function is: asprintf(&str, "%s[%d]", name, val);
. str
is a char*
on the stack within the calling function. name
is a simple short text descriptor that I've verified is not null and not zero length. val
is a simple index that is incremented within the loop that calls asprintf()
. The resulting string this call builds should be 7 characters long (not including null terminator). asprintf()
is called throughout the library. My use of the containing library only ever executes it in this single loop (twice). The library does its job as expected if I remove this call and replace the results with dummy values. Execution seemingly crashes at assigning the buffer to the dereferenced ret
pointer within the implementation of asprintf()
.
Despite lots of experiments with buffers, pointer dereferencing, and managing var args I cannot get this function to operate properly. However, cross-compiled on OS X it works just fine.
I know that the behavior of vsnprintf()
is not necessarily identical across all platforms. That said, as far as I can tell this usage should work as expected.
Any ideas? Could it be something outside the function itself? Some kind of stdio initialization or linker library option that is causing the trouble?
int asprintf(char **ret, const char *fmt, ...) {
va_list ap1;
va_list ap2;
int count;
va_start(ap1, fmt);
va_copy(ap2, ap1);
count = vsnprintf(NULL, 0, fmt, ap1);
va_end(ap1);
if(count > 0) {
char* buffer;
if (!(buffer = (char*)malloc(count+1))) {
return -1;
}
count = vsnprintf(buffer, count+1, fmt, ap2);
*ret = buffer;
}
va_end(ap2);
return count;
}
Per previous comments, it turns out that asprintf
was called without having a visible prototype in scope. Adding the necessary declaration prior to the call fixed the issue.
The underlying reason is that C
requires variadic functions to have the proper prototype declared before being used.
This is mentioned for example at Are prototypes required for all functions in C89, C90 or C99?.
any call to a variadic function (like printf or scanf) must have a visible prototype
Some insight as to "why" is given at comp.lang.c FAQ list - Question 15.1.
Q: I heard that you have to #include <stdio.h> before calling printf. Why?
A: So that a proper prototype for printf will be in scope.
A compiler may use a different calling sequence for functions which accept variable-length argument lists. (It might do so if calls using variable-length argument lists were less efficient than those using fixed-length.) Therefore, a prototype (indicating, using the ellipsis notation ``...'', that the argument list is of variable length) must be in scope whenever a varargs function is called, so that the compiler knows to use the varargs calling mechanism.