bug-gdb
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

gdb/libiberty/vasprintf.c


From: Graeme Peterson
Subject: gdb/libiberty/vasprintf.c
Date: Mon, 15 Apr 2002 13:32:59 -0400 (EDT)

Hi.

I found a bug in gdb/libiberty/vasprintf.c.  Well, actually a
SIGSEGV found it for me.  One of the kernel developers here at 
QNX provided me with the explanation for the fix, which I have
appended.

Here is the change I made to fix it for me.  In vasprintf() I 
have added 2 lines before the return, and changed the va_list
parameter being passed to int_vasprintf():


  int
  vasprintf (result, format, args)
       char **result;
       const char *format;
  #if defined (_BSD_VA_LIST_) && defined (__FreeBSD__)
       _BSD_VA_LIST_ args;
  #else
       va_list args;
  #endif
  {
    /* Handle both array and non-array va_list types. */
    va_list temp;
    va_copy(temp, args);
    return int_vasprintf (result, format, &temp);
  }


Thanks.
Graeme Peterson
QNX Tools Group


Explanation:
============

Consider the following example. All looks good, but on the PPC it won't
print out "2".

=======================================================================
#include <stdio.h>
#include <stdarg.h>

void
handle_foo(char *fmt, va_list *pva) {
        printf("%d\n", va_arg(*pva, int));
}

void
vfoo(char *fmt, va_list va) {
        handle_foo(fmt, &va);
}

void
foo(char *fmt, ...) {
        va_list va;

        va_start(va, fmt);
        vfoo(fmt, va);
        va_end(va);
}

int
main() {
        foo("", 2);
        return 0;
}
=======================================================================

The problem is that sometimes the va_list type is an array (as on the
PPC) and sometimes not (X86, etc). The C standard
says that prototypes such as vfoo() have the array type silently
coerced to be a pointer to a base type. This makes things work when
you pass an array object to the function. An array-typed expression
is converted to a pointer to the first element when used in an rvalued
context, the coercion in the function makes everybody happy. The problem
comes when you then pass the address of the va_list parameter to another
function. It's expecting a pointer to the array, but what it _really_
gets is a pointer to a pointer (because of the original conversion).
Any use of the va_list in the second function won't get the right data.

Here's the example modified so that it works in all cases:

=======================================================================
#include <stdio.h>
#include <stdarg.h>

void
handle_foo(char *fmt, va_list *pva) {
        printf("%d\n", va_arg(*pva, int));
}

void
vfoo(char *fmt, va_list va) {
        va_list temp;

        va_copy(temp, va);
        handle_foo(fmt, &temp);
}

void
foo(char *fmt, ...) {
        va_list va;

        va_start(va, fmt);
        vfoo(fmt, va);
        va_end(va);
}

int
main() {
        foo("", 2);
        return 0;
}
=======================================================================

The use of the va_copy() 'undoes' the coercion that happens in the
parameter list, so that the handle_foo() function now gets the proper
data.
-- 



reply via email to

[Prev in Thread] Current Thread [Next in Thread]