From Saumya.Agarwal at netapp.com Mon Dec 4 18:11:02 2006 From: Saumya.Agarwal at netapp.com (Agarwal, Saumya) Date: Mon, 4 Dec 2006 23:41:02 +0530 Subject: Segmentation fault in vsnprintf() from /lib64/tls/libc.so.6 Message-ID: <7026BCCA258BA2438F885772CA0B431304C52B18@exbtc01.hq.netapp.com> 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 -------------- next part -------------- An HTML attachment was scrubbed... URL: From jakub at redhat.com Mon Dec 4 18:54:39 2006 From: jakub at redhat.com (Jakub Jelinek) Date: Mon, 4 Dec 2006 13:54:39 -0500 Subject: Segmentation fault in vsnprintf() from /lib64/tls/libc.so.6 In-Reply-To: <7026BCCA258BA2438F885772CA0B431304C52B18@exbtc01.hq.netapp.com> References: <7026BCCA258BA2438F885772CA0B431304C52B18@exbtc01.hq.netapp.com> Message-ID: <20061204185439.GE6570@devserv.devel.redhat.com> On Mon, Dec 04, 2006 at 11:41:02PM +0530, Agarwal, Saumya wrote: > 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. No wonder, this is clearly invalid code, see ISO C99, 7.15(3): The type declared is va_list which is an object type suitable for holding information needed by the macros va_start, va_arg, va_end, and va_copy. If access to the varying arguments is desired, the called function shall declare an object (generally referred to as ap in this subclause) having type va_list. The object ap may be passed as an argument to another function; if that function invokes the va_arg macro with parameter ap, the value of ap in the calling function is indeterminate and shall be passed to the va_end macro prior to any further reference to ap. As vsnprintf uses va_arg on the 4th argument passed to it (ap), you really need to va_copy before you call vsnprintf (and don't forget to pass it to va_end afterwards). The va_copy man page should explain it too. Jakub From Saumya.Agarwal at netapp.com Tue Dec 5 18:01:49 2006 From: Saumya.Agarwal at netapp.com (Agarwal, Saumya) Date: Tue, 5 Dec 2006 23:31:49 +0530 Subject: Segmentation fault in vsnprintf() from /lib64/tls/libc.so.6 Message-ID: <7026BCCA258BA2438F885772CA0B431304C534AD@exbtc01.hq.netapp.com> Thanks Jakub! It worked with va_copy. -----Original Message----- From: Jakub Jelinek [mailto:jakub at redhat.com] Sent: Tuesday, December 05, 2006 12:25 AM To: Agarwal, Saumya Cc: amd64-list at redhat.com Subject: Re: Segmentation fault in vsnprintf() from /lib64/tls/libc.so.6 On Mon, Dec 04, 2006 at 11:41:02PM +0530, Agarwal, Saumya wrote: > 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. No wonder, this is clearly invalid code, see ISO C99, 7.15(3): The type declared is va_list which is an object type suitable for holding information needed by the macros va_start, va_arg, va_end, and va_copy. If access to the varying arguments is desired, the called function shall declare an object (generally referred to as ap in this subclause) having type va_list. The object ap may be passed as an argument to another function; if that function invokes the va_arg macro with parameter ap, the value of ap in the calling function is indeterminate and shall be passed to the va_end macro prior to any further reference to ap. As vsnprintf uses va_arg on the 4th argument passed to it (ap), you really need to va_copy before you call vsnprintf (and don't forget to pass it to va_end afterwards). The va_copy man page should explain it too. Jakub