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

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • saumya.agarwal@gmail.com

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

    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(&(*st rp)[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 0x00000037d776f c10 in strlen () from /lib64/tls/libc.so.6
    #1 0x00000037d7742 b4b in vfprintf () from /lib64/tls/libc.so.6
    #2 0x00000037d7761 ce4 in vsnprintf () from /lib64/tls/libc.so.6
    #3 0x0000000000496 5a6 in str_vappend (strp=0x7fbfffe 790,
    sizep=0x7fbfffe 788,
    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

  • Insik Park

    #2
    Re: Segmentation fault in vsnprintf() from /lib64/tls/libc.so.6


    saumya.agarwal@ gmail.com 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(&(*st rp)[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 0x00000037d776f c10 in strlen () from /lib64/tls/libc.so.6
    #1 0x00000037d7742 b4b in vfprintf () from /lib64/tls/libc.so.6
    #2 0x00000037d7761 ce4 in vsnprintf () from /lib64/tls/libc.so.6
    #3 0x0000000000496 5a6 in str_vappend (strp=0x7fbfffe 790,
    sizep=0x7fbfffe 788,
    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.

    Comment

    • loic-dev@gmx.net

      #3
      Re: Segmentation fault in vsnprintf() from /lib64/tls/libc.so.6

      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(&(*st rp)[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.

      Comment

      • Chris Torek

        #4
        Re: Segmentation fault in vsnprintf() from /lib64/tls/libc.so.6

        In article <1165255972.273 510.167660@80g2 000cwy.googlegr oups.com>
        saumya.agarwal@ gmail.com <saumya.agarwal @gmail.comwrote :
        >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(&(*st rp)[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 insik.park@gmai l.com
        (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_lo op {
        /* BUG HERE - may fail if the loop runs more than once */
        result = some_vprintf_fu nction(args, ap);
        ...
        }
        va_end(ap);
        }

        you can rewrite it as:

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

        some_sort_of_lo op {
        va_start(ap, fmt);
        result = some_vprintf_fu nction(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_lo op {
        /* BUG HERE */
        result = some_vprintf_fu nction(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_lo op {
        va_copy(ap, copy);
        result = some_vprintf_fu nction(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.

        Comment

        • saumya.agarwal@gmail.com

          #5
          Re: Segmentation fault in vsnprintf() from /lib64/tls/libc.so.6

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

          Chris Torek wrote:
          In article <1165255972.273 510.167660@80g2 000cwy.googlegr oups.com>
          saumya.agarwal@ gmail.com <saumya.agarwal @gmail.comwrote :
          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(&(*st rp)[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 insik.park@gmai l.com
          (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_lo op {
          /* BUG HERE - may fail if the loop runs more than once */
          result = some_vprintf_fu nction(args, ap);
          ...
          }
          va_end(ap);
          }
          >
          you can rewrite it as:
          >
          void foo(const char *fmt, ...) {
          va_list ap;
          >
          some_sort_of_lo op {
          va_start(ap, fmt);
          result = some_vprintf_fu nction(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_lo op {
          /* BUG HERE */
          result = some_vprintf_fu nction(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_lo op {
          va_copy(ap, copy);
          result = some_vprintf_fu nction(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.

          Comment

          Working...