What | Removed | Added |
---|---|---|
Assignee | zypp-maintainers@forge.provo.novell.com | schwab@suse.com |
Summary | zypper dup core dumps | vasprintf(&dest, "%s", str) doesn't always fill whole destination |
Thanks for the initial analysis. I agree that this is a bug in vasprintf(), and indeed it only seems to happen on some hardware (or needs very specific environments to occur). I can reproduce the problem on rancid.arch.suse.de with this testcase: ------------ snip ------------------ #define _GNU_SOURCE #include <stdio.h> #include <stdarg.h> #include <stdlib.h> #include <string.h> #define N 200000 int main() { char *src, *dest; //for (int N = 0; N < 300000; N++) { src = malloc(N+1); memset (src, 'x', N); src[N] = 0; //dest = form ("%s", src); asprintf(&dest, "%s", src); if (strlen (dest) != strlen(src)) printf("%d: failed\n", N); /*else if (!(N & 63)) printf("%d: passed\n", N);*/ free (dest); free (src); //} return 0; } ---------------- snap ------------------ When the bug occurs (with 200000 chars on that machine always), then the destination string is only 102300 characters long. The _allocated_ length of the destination block is 200001, though, as one can see when tracing the thing in gdb. It's also the case that the destination buffer holds more 'x' characters after some intermediate zeros: (The last malloc done from within IO_str_overflow): Breakpoint 2, 0x00007ffff7a9da50 in malloc () from /lib64/libc.so.6 (gdb) p $rdi $19 = 204700 So it's now allocating a buffer of 204700 bytes (before that all mallocs ultimately were too small to contain the input string). Then breaking at the final realloc that supposedly sizes the returned buffer to the exact length necessary, in vasprintf: Breakpoint 3, 0x00007ffff7a9e1f0 in realloc () from /lib64/libc.so.6 (gdb) p $rdi $31 = 140737353601040 (gdb) p/x $rdi $32 = 0x7ffff7f7d010 (gdb) p $rsi $33 = 200001 So, %rdi is the returned string, it's allocated size will be 200001, now looking at content: (gdb) p ((char*)$rdi)[102300]@100 $44 = "x", '\000' <repeats 83 times>, 'x' <repeats 16 times> So, [102300] still has an 'x', then follows some zeros (ultimately making the string length less than the allocated size), then more 'x' (in fact until the end, though I haven't checked if there are more intermediate blocks of zeros). So something is going amiss when copying the string buffers I believe.