Passing a structure containing just an array of characters into a function as a value is corrupt within the function. Included is a gdb trace: [awk@mgmt3 ha_test]$ /home/awk/bin/gdb hat GNU gdb 2001-09-21-cvs (MI_OUT) Copyright 2001 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i686-pc-linux-gnu"... (gdb) main' 12 13 void testfunc(logicalIFName_t ifName) { 14 printf("ifName: %s\n", ifName.logicalIFName); 15 } 16 17 int main() { 18 19 logicalIFName_t ifname; 20 strcpy(ifname.logicalIFName, "this is a test string"); 21 testfunc(ifname); (gdb) b 'main' Breakpoint 1 at 0x8048226: file old.hatest.c, line 20. (gdb) b 'testfunc' Breakpoint 2 at 0x80481fa: file old.hatest.c, line 14. (gdb) l 22 } (gdb) run Starting program: /home/awk/src/ha_test/hat Breakpoint 1, main () at old.hatest.c:20 20 strcpy(ifname.logicalIFName, "this is a test string"); (gdb) n 21 testfunc(ifname); (gdb) p ifname $1 = {logicalIFName = "this is a test string", '\000' <repeats 103 times>, "\224\201\004\b"} (gdb) s memcpy (dstpp=0xbffff680, srcpp=0xbffff700, len=128) at ../sysdeps/generic/memcpy.c:40 40 ../sysdeps/generic/memcpy.c: No such file or directory. in ../sysdeps/generic/memcpy.c (gdb) s 33 in ../sysdeps/generic/memcpy.c (gdb) s 34 in ../sysdeps/generic/memcpy.c (gdb) s 35 in ../sysdeps/generic/memcpy.c (gdb) s 40 in ../sysdeps/generic/memcpy.c (gdb) s 43 in ../sysdeps/generic/memcpy.c (gdb) s 44 in ../sysdeps/generic/memcpy.c (gdb) s 55 in ../sysdeps/generic/memcpy.c (gdb) s 61 in ../sysdeps/generic/memcpy.c (gdb) p dstpp $2 = (void *) 0xbffff680 (gdb) p (char*) dstpp $3 = 0xbffff680 "this is a test string" (gdb) s 63 in ../sysdeps/generic/memcpy.c (gdb) s 64 in ../sysdeps/generic/memcpy.c (gdb) p (char*) dstpp $4 = 0xbffff680 "this is a test string" (gdb) s Breakpoint 2, testfunc (ifName={logicalIFName = "\000÷ÿ¿\224ã\b\b EDTst string", '\000' <repeats 103 times>, "\224\201\004\b"}) at old.hatest.c:14 14 printf("ifName: %s\n", ifName.logicalIFName); (gdb) p ifName $5 = {logicalIFName = "\000÷ÿ¿\224ã\b\b EDTst string", '\000' <repeats 103 times>, "\224\201\004\b"} (gdb) p ifName (gdb) p ifName $6 = (logicalIFName_t *) 0xbffff680 (gdb) quit The program is running. Exit anyway? (y or n) y [awk@mgmt3 ha_test]$ exit Script done on Thu Jan 10 13:33:53 2002 Release: 3.1 20020110 (experimental) Environment: System: Linux mgmt3 2.4.2-2 #1 Sun Apr 8 20:41:30 EDT 2001 i686 unknown Architecture: i686 host: i686-pc-linux-gnu build: i686-pc-linux-gnu target: i686-pc-linux-gnu configured with: ../gcc/configure --prefix=/home/tools/linux/compilers/gcc-3.1-new-spinos --enable-shared --enable-threads=posix --enable-version-specific-runtime-libs --enable-languages=c,c++,java How-To-Repeat: compile and run the follow test example. #include <stdio.h> #include <string.h> #define NAMESIZE 128 struct logicalifname { char logicalIFName[NAMESIZE]; }; typedef struct logicalifname logicalifname; typedef logicalifname logicalIFName_t; void testfunc(logicalIFName_t ifName) { printf("ifName: %s\n", ifName.logicalIFName); } int main() { logicalIFName_t ifname; strcpy(ifname.logicalIFName, "this is a test string"); testfunc(ifname); }
Fix: You can work around the problem by adding a dummy variable to the contents of the structure logicalifname.
State-Changed-From-To: open->analyzed State-Changed-Why: I can reproduce this with 3.2.1pre, but it seems fixed in present CVS. However, since this is a regression w.r.t. 2.95, I leave it open and put it into "high". A reduced testcase is this: ---------------------------------- #include <stdio.h> #include <string.h> struct X { char s[100]; }; void foo(struct X x) { printf("x.s: %s\n", x.s); } int main() { struct X x; strcpy(x.s, "this is a test string"); foo(x); } ------------------------------------- With 3.2.1pre I get tmp/g> /home/bangerth/bin/gcc-3.2.1-pre/bin/gcc x.c tmp/g> ./a.out x.s: Äñÿ¿Ôa@st string This is not what I want to see.
From: Wolfgang Bangerth <bangerth@ticam.utexas.edu> To: gcc-gnats@gcc.gnu.org Cc: Subject: Re: c/5351: function pass-by-value structure copy corrupts structure on stack Date: Wed, 6 Nov 2002 13:00:00 -0600 (CST) This is probably a duplicate of 7591. W. ------------------------------------------------------------------------- Wolfgang Bangerth email: bangerth@ticam.utexas.edu www: http://www.ticam.utexas.edu/~bangerth
State-Changed-From-To: analyzed->closed State-Changed-Why: Fixed by a patch from HJ: http://gcc.gnu.org/ml/gcc-patches/2002-08/msg01170.html
I am running cygwin on Windows XP I am using gcc 3.4.4-3 The bug also manifests itself on my service provider's CPU. All values should be 100.0. Minimal program below. cc -o test test.c My erroneous values: ListA: (x: 100.0 y: 100.0 z: 100.0 w: 100.0) ListB: (x: 100.0 y: 100.0 z: 100.0 w: 100.0) MinA: (x: 0.0 y: 0.0 z: 0.0 w: 100.0) MinB: (x: 0.0 y: 0.0 z: 0.0 w: 0.0) AvgA: (x: 100.0 y: 100.0 z: 100.0 w: 100.0) AvgB: (x: 100.0 y: 100.0 z: 100.0 w: 200.0) Service provider erroneous values: ListA: (x: 100.0 y: 100.0 z: 100.0 w: 100.0) ListB: (x: 100.0 y: 100.0 z: 100.0 w: 100.0) MinA: (x: -0.0 y: 0.0 z: 0.0 w: 100.0) MinB: (x: -0.0 y: 0.0 z: 0.0 w: -0.0) AvgA: (x: 100.0 y: 100.0 z: 100.0 w: 100.0) AvgB: (x: 100.0 y: 100.0 z: 100.0 w: 200.0) ------- test.c code that fails is here: ------------ #include <stdio.h> #define MIN(a,b) (((a)<=(b))?(a):(b)) #define ENTRIES 1 // put whatever in here, it is still broken typedef struct { double x, y, z, w; } Entry; Entry ListA[ENTRIES]; Entry ListB[ENTRIES]; Entry MinA, AvgA; Entry MinB, AvgB; extern void printEntry(Entry fntry, char *label); extern Entry Average(Entry *fntry); extern Entry Minimum(Entry *fntry); main(int argc, char **argv) { int i; for(i = 0; i < ENTRIES; i++) { ListA[i].x = 100; ListA[i].y = 100; ListA[i].z = 100; ListA[i].w = 100; ListB[i].x = 100; ListB[i].y = 100; ListB[i].z = 100; ListB[i].w = 100; } printEntry(ListA[0], "ListA"); printEntry(ListB[0], "ListB"); // should be same, but aren't MinA = Minimum(ListA); printEntry(MinA, "MinA"); MinB = Minimum(ListB); printEntry(MinB, "MinB"); // should be same, but aren't AvgA = Average(ListA); printEntry(AvgA, "AvgA"); AvgB = Average(ListB); printEntry(AvgB, "AvgB"); } void printEntry(Entry fntry, char *label) { printf("%s: (x: %5.1f y: %5.1f z: %5.1f w: %5.1f)\n", label, fntry.x, fntry.y, fntry.z, fntry.w); } Entry Average(Entry *fntry) { int i; Entry average; for (i = 0; i < ENTRIES; i++) { average.x += fntry[i].x; average.y += fntry[i].y; average.z += fntry[i].z; average.w += fntry[i].w; } average.x /= ENTRIES; average.y /= ENTRIES; average.z /= ENTRIES; average.w /= ENTRIES; return(average); } Entry Minimum(Entry *fntry) { int i; Entry minimum; for (i = 0; i < ENTRIES; i++) { minimum.x = MIN(minimum.x, fntry[i].x); minimum.y = MIN(minimum.y, fntry[i].y); minimum.z = MIN(minimum.z, fntry[i].z); minimum.w = MIN(minimum.w, fntry[i].w); } return(minimum); }