Bug 5351 - function pass-by-value structure copy corrupts structure on stack
Summary: function pass-by-value structure copy corrupts structure on stack
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: c (show other bugs)
Version: 3.1
: P3 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords: wrong-code
: 7591 (view as bug list)
Depends on:
Blocks:
 
Reported: 2002-01-10 10:56 UTC by awk
Modified: 2006-12-30 08:33 UTC (History)
4 users (show)

See Also:
Host: i686-pc-linux-gnu
Target: i686-pc-linux-gnu
Build: i686-pc-linux-gnu
Known to work:
Known to fail:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description awk 2002-01-10 10:56:00 UTC
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);
}
Comment 1 awk 2002-01-10 10:56:00 UTC
Fix:
You can work around the problem by adding a dummy variable 
to the contents of the structure logicalifname.
Comment 2 Wolfgang Bangerth 2002-11-05 08:05:52 UTC
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.
Comment 3 Wolfgang Bangerth 2002-11-06 13:00:00 UTC
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
 
 
Comment 4 Joe Buck 2002-11-08 15:17:02 UTC
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
Comment 5 L. Van Warren 2006-12-30 08:33:59 UTC
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);
}