Segmentation fault in vsnprintf() from /lib64/tls/libc.so.6

Discussion in 'C Programming' started by saumya.agarwal@gmail.com, Dec 4, 2006.

  1. Guest

    Hi,

    I am executing a piece of code which continually tries to do the
    sprintf into the allocated buffer on a 64-bit RedHat linux machine.

    Here are the details of the system and the gcc version used -

    bash-3.00$ uname -a
    Linux saumya.foo.com 2.6.9-5.ELsmp #1 SMP Wed Jan 5 19:29:47 EST 2005
    x86_64 x86_64 x86_64 GNU/Linux

    bash-3.00$ gcc -v
    Reading specs from /usr/lib/gcc/x86_64-redhat-linux/3.4.3/specs
    Configured with: ../configure --prefix=/usr --mandir=/usr/share/man
    --infodir=/usr/share/info --enable-shared --enable-threads=posix
    --disable-checking --with-system-zlib --enable-__cxa_atexit
    --disable-libunwind-exceptions --enable-languages=c,c++,objc,java,f77
    --enable-java-awt=gtk --host=x86_64-redhat-linux
    Thread model: posix
    gcc version 3.4.3 20041212 (Red Hat 3.4.3-9.EL4)

    On executing the code (snippet below) I get a segmentation fault at run
    time. The code builds fine. The same code runs fine on a 32-bit linux
    machine.

    if (NULL != *strp) {
    for ( ; NULL != *strp; ) {
    left = *sizep - len - 1;
    if (left > 0) {
    result = vsnprintf(&(*strp)[len], left, format, ap);
    if ((result != -1) && (result < left)) { //vsnprintf
    truncated the output string
    break;
    }
    }
    *sizep *= 2;
    Renew(*strp, *sizep, char); //reallocate sizep amount of
    space to strp
    }
    }

    The crash happens in the second iteration of the for loop. It goes
    through fine in the first iteration.

    Here is the gdb backtrace -

    #0 0x00000037d776fc10 in strlen () from /lib64/tls/libc.so.6
    #1 0x00000037d7742b4b in vfprintf () from /lib64/tls/libc.so.6
    #2 0x00000037d7761ce4 in vsnprintf () from /lib64/tls/libc.so.6
    #3 0x00000000004965a6 in str_vappend (strp=0x7fbfffe790,
    sizep=0x7fbfffe788,
    format=0x4adf1b "%s /%s HTTP/1.1\r\n", ap=0x7fbfffe7e0) at
    str.c:684


    Is this a known issue with vsnprintf() on 64-bit linux platforms? Is
    there a fix or any workaround available?

    Thanks,
    saumya
    , Dec 4, 2006
    #1
    1. Advertising

  2. Insik Park Guest

    wrote:
    > Hi,
    >
    > I am executing a piece of code which continually tries to do the
    > sprintf into the allocated buffer on a 64-bit RedHat linux machine.
    >
    > Here are the details of the system and the gcc version used -
    >
    > bash-3.00$ uname -a
    > Linux saumya.foo.com 2.6.9-5.ELsmp #1 SMP Wed Jan 5 19:29:47 EST 2005
    > x86_64 x86_64 x86_64 GNU/Linux
    >
    > bash-3.00$ gcc -v
    > Reading specs from /usr/lib/gcc/x86_64-redhat-linux/3.4.3/specs
    > Configured with: ../configure --prefix=/usr --mandir=/usr/share/man
    > --infodir=/usr/share/info --enable-shared --enable-threads=posix
    > --disable-checking --with-system-zlib --enable-__cxa_atexit
    > --disable-libunwind-exceptions --enable-languages=c,c++,objc,java,f77
    > --enable-java-awt=gtk --host=x86_64-redhat-linux
    > Thread model: posix
    > gcc version 3.4.3 20041212 (Red Hat 3.4.3-9.EL4)
    >
    > On executing the code (snippet below) I get a segmentation fault at run
    > time. The code builds fine. The same code runs fine on a 32-bit linux
    > machine.
    >
    > if (NULL != *strp) {
    > for ( ; NULL != *strp; ) {
    > left = *sizep - len - 1;
    > if (left > 0) {
    > result = vsnprintf(&(*strp)[len], left, format, ap);
    > if ((result != -1) && (result < left)) { //vsnprintf
    > truncated the output string
    > break;
    > }
    > }
    > *sizep *= 2;
    > Renew(*strp, *sizep, char); //reallocate sizep amount of
    > space to strp
    > }
    > }
    >
    > The crash happens in the second iteration of the for loop. It goes
    > through fine in the first iteration.
    >
    > Here is the gdb backtrace -
    >
    > #0 0x00000037d776fc10 in strlen () from /lib64/tls/libc.so.6
    > #1 0x00000037d7742b4b in vfprintf () from /lib64/tls/libc.so.6
    > #2 0x00000037d7761ce4 in vsnprintf () from /lib64/tls/libc.so.6
    > #3 0x00000000004965a6 in str_vappend (strp=0x7fbfffe790,
    > sizep=0x7fbfffe788,
    > format=0x4adf1b "%s /%s HTTP/1.1\r\n", ap=0x7fbfffe7e0) at
    > str.c:684
    >
    >
    > Is this a known issue with vsnprintf() on 64-bit linux platforms? Is
    > there a fix or any workaround available?
    >
    > Thanks,
    > saumya


    Excerpt from the man page for vsnfprintf:

    The functions vprintf, vfprintf, vsprintf, vsnprintf are
    equivalent to
    the functions printf, fprintf, sprintf, snprintf, respectively,
    except
    that they are called with a va_list instead of a variable
    number of
    arguments. These functions do not call the va_end macro.
    Consequently,
    the value of ap is undefined after the call. The application
    should
    call va_end(ap) itself afterwards.
    Insik Park, Dec 4, 2006
    #2
    1. Advertising

  3. Chris Torek Guest

    In article <>
    <> wrote:
    >On executing the code (snippet below) I get a segmentation fault at run
    >time. ... The crash happens in the second iteration of the for loop.
    >
    > if (NULL != *strp) {
    > for ( ; NULL != *strp; ) {
    > left = *sizep - len - 1;
    > if (left > 0) {
    > result = vsnprintf(&(*strp)[len], left, format, ap);
    > if ((result != -1) && (result < left)) { //vsnprintf
    >truncated the output string
    > break;
    > }
    > }
    > *sizep *= 2;
    > Renew(*strp, *sizep, char); //reallocate sizep amount of
    >space to strp
    > }
    > }


    (I think it is worth pointing out that this code snippet will no
    longer compile due to line-wrapping of "//" comments. C89-style
    comments survive USENET posting better than these C99-specific
    comments.)

    You have already gotten a correct answer from
    (namely, the v*printf family of functions destroy the "ap" parameter,
    at least in theory, and sometimes but not always in practice).

    The snippet above does not have enough information to tell whether
    this can be fixed without using a new C99 feature. If your function
    looks something vaguely like:

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

    va_start(ap, fmt);
    some_sort_of_loop {
    /* BUG HERE - may fail if the loop runs more than once */
    result = some_vprintf_function(args, ap);
    ...
    }
    va_end(ap);
    }

    you can rewrite it as:

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

    some_sort_of_loop {
    va_start(ap, fmt);
    result = some_vprintf_function(args, ap);
    va_end(ap);
    ...
    }
    }

    But in general it is better to write a function like foo() in
    terms of its "vfoo" counterpart:

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

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

    void vfoo(const char *fmt, va_list ap) {

    some_sort_of_loop {
    /* BUG HERE */
    result = some_vprintf_function(args, ap);
    ...
    }
    }

    In this case, there is no way to "va_end" and "re-va_start" inside
    the loop. C99 provides the missing part of the puzzle, using a
    macro[%] spelled "va_copy":

    void vfoo(const char *fmt, va_list ap) {
    va_list copy;

    some_sort_of_loop {
    va_copy(ap, copy);
    result = some_vprintf_function(args, copy);
    va_end(copy);
    ...
    }
    }

    Instead of re-"va_start"-ing, you va_copy the still-valid "ap"
    value, then va_end the copy, inside the loop.
    -----
    [% At least, the C99 draft I have specifies "a macro". If it is
    required to be a macro, you can test for its presence, even in a
    compiler that is not yet fully C99-conformant, with "#ifdef".]
    --
    In-Real-Life: Chris Torek, Wind River Systems
    Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
    email: forget about it http://web.torek.net/torek/index.html
    Reading email is like searching for food in the garbage, thanks to spammers.
    Chris Torek, Dec 4, 2006
    #3
  4. Guest

    Hello,

    > I am executing a piece of code which continually tries to do the
    > sprintf into the allocated buffer on a 64-bit RedHat linux machine.
    >
    > Here are the details of the system and the gcc version used -


    < snip >

    > On executing the code (snippet below) I get a segmentation fault at run
    > time. The code builds fine. The same code runs fine on a 32-bit linux
    > machine.


    This is likely a bug in your code, which didn't pop up on 32-bit
    Linux... This is more a matter of luck than code correctness...

    > if (NULL != *strp) {
    > for ( ; NULL != *strp; ) {
    > left = *sizep - len - 1;
    > if (left > 0) {
    > result = vsnprintf(&(*strp)[len], left, format, ap);
    > if ((result != -1) && (result < left)) { //vsnprintf
    > truncated the output string
    > break;
    > }
    > }
    > *sizep *= 2;
    > Renew(*strp, *sizep, char); //reallocate sizep amount of
    > space to strp
    > }
    > }
    >
    > The crash happens in the second iteration of the for loop. It goes
    > through fine in the first iteration.


    As mentioned by Insik in the man page's excerpt, the ap va_list
    variable will have an undefined value after the call to /vsnprintf()/.
    Hence, you need to reset the va_list by calling /va_end()/ first and
    then /va_start()/ at each iteration of the for(...) loop.


    > Is this a known issue with vsnprintf() on 64-bit linux platforms? Is
    > there a fix or any workaround available?


    I guess, the easiest workaround available is to fix your code ;-)

    Cheers,
    Loic.
    , Dec 4, 2006
    #4
  5. Guest

    Thank you very much! Using va_copy() worked !!

    Chris Torek wrote:
    > In article <>
    > <> wrote:
    > >On executing the code (snippet below) I get a segmentation fault at run
    > >time. ... The crash happens in the second iteration of the for loop.
    > >
    > > if (NULL != *strp) {
    > > for ( ; NULL != *strp; ) {
    > > left = *sizep - len - 1;
    > > if (left > 0) {
    > > result = vsnprintf(&(*strp)[len], left, format, ap);
    > > if ((result != -1) && (result < left)) { //vsnprintf
    > >truncated the output string
    > > break;
    > > }
    > > }
    > > *sizep *= 2;
    > > Renew(*strp, *sizep, char); //reallocate sizep amount of
    > >space to strp
    > > }
    > > }

    >
    > (I think it is worth pointing out that this code snippet will no
    > longer compile due to line-wrapping of "//" comments. C89-style
    > comments survive USENET posting better than these C99-specific
    > comments.)
    >
    > You have already gotten a correct answer from
    > (namely, the v*printf family of functions destroy the "ap" parameter,
    > at least in theory, and sometimes but not always in practice).
    >
    > The snippet above does not have enough information to tell whether
    > this can be fixed without using a new C99 feature. If your function
    > looks something vaguely like:
    >
    > void foo(const char *fmt, ...) {
    > va_list ap;
    >
    > va_start(ap, fmt);
    > some_sort_of_loop {
    > /* BUG HERE - may fail if the loop runs more than once */
    > result = some_vprintf_function(args, ap);
    > ...
    > }
    > va_end(ap);
    > }
    >
    > you can rewrite it as:
    >
    > void foo(const char *fmt, ...) {
    > va_list ap;
    >
    > some_sort_of_loop {
    > va_start(ap, fmt);
    > result = some_vprintf_function(args, ap);
    > va_end(ap);
    > ...
    > }
    > }
    >
    > But in general it is better to write a function like foo() in
    > terms of its "vfoo" counterpart:
    >
    > void foo(const char *fmt, ...) {
    > va_list ap;
    >
    > va_start(fmt, ap);
    > vfoo(fmt, ap);
    > va_end(ap);
    > }
    >
    > void vfoo(const char *fmt, va_list ap) {
    >
    > some_sort_of_loop {
    > /* BUG HERE */
    > result = some_vprintf_function(args, ap);
    > ...
    > }
    > }
    >
    > In this case, there is no way to "va_end" and "re-va_start" inside
    > the loop. C99 provides the missing part of the puzzle, using a
    > macro[%] spelled "va_copy":
    >
    > void vfoo(const char *fmt, va_list ap) {
    > va_list copy;
    >
    > some_sort_of_loop {
    > va_copy(ap, copy);
    > result = some_vprintf_function(args, copy);
    > va_end(copy);
    > ...
    > }
    > }
    >
    > Instead of re-"va_start"-ing, you va_copy the still-valid "ap"
    > value, then va_end the copy, inside the loop.
    > -----
    > [% At least, the C99 draft I have specifies "a macro". If it is
    > required to be a macro, you can test for its presence, even in a
    > compiler that is not yet fully C99-conformant, with "#ifdef".]
    > --
    > In-Real-Life: Chris Torek, Wind River Systems
    > Salt Lake City, UT, USA (40°39.22'N, 111°50.29'W) +1 801 277 2603
    > email: forget about it http://web.torek.net/torek/index.html
    > Reading email is like searching for food in the garbage, thanks to spammers.
    , Dec 5, 2006
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Manju

    Problem with va_start()/vsnprintf()

    Manju, Jan 5, 2007, in forum: C Programming
    Replies:
    8
    Views:
    477
    Randy Howard
    Jan 10, 2007
  2. Replies:
    2
    Views:
    7,039
    Jacek Dziedzic
    Mar 27, 2006
  3. stef

    vsnprintf like

    stef, Aug 20, 2007, in forum: Java
    Replies:
    2
    Views:
    280
    Mark Rafn
    Aug 20, 2007
  4. js
    Replies:
    0
    Views:
    280
  5. Mike Driscoll
    Replies:
    2
    Views:
    367
Loading...

Share This Page