[Bug c/94130] New: Unintended result with optimization option when assigning two structures, memset and 0

minzkn at minzkn dot com gcc-bugzilla@gcc.gnu.org
Wed Mar 11 01:47:29 GMT 2020


https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94130

            Bug ID: 94130
           Summary: Unintended result with optimization option when
                    assigning two structures, memset and 0
           Product: gcc
           Version: unknown
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c
          Assignee: unassigned at gcc dot gnu.org
          Reporter: minzkn at minzkn dot com
  Target Milestone: ---

Created attachment 48014
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=48014&action=edit
test source

It seems that there is an optimization bug (-O1) for gcc version 7.4.0 and
above optimization level 1. (Same as gcc 7.5, it seems to occur from 7.x to
latest 9.2.)

The following verification code was written shortly and when compiled with
optimization options such as -O1, -O2, -O3, and -Os instead of -O0, it was
confirmed that the correct result was not produced.

/ *
1. Assign memset to the member of the first structure along with the address of
the second structure.
2. Initialize the second structure to the desired member value. Only reset to 0
3. Call the first structure by passing it to the dump function. This is not
what you want.
4. Put a memory barrier between steps 1 and 2 to avoid the problem.
* /

#include <stdio.h>
#include <memory.h>

struct myreq {
    char m_name[6];
    void *m_data;
};

struct myvalue {
    unsigned int m_type;
    unsigned int m_value;
};

#define mytest_type 1234
#define mytest_value 0 /* only zero case issue */

#define mytest_barrier() __asm__ __volatile__("": : :"memory")

static void myprint(struct myreq *s_myreq)
{
    struct myvalue *s_myvalue = (struct myvalue *)s_myreq->m_data;

    printf(
        "%s: n=%s, cmd=%u, data=%u\n",
        ((s_myvalue->m_type == mytest_type) && (s_myvalue->m_value ==
mytest_value)) ? "NO BUG" : "!! BUG",
        s_myreq->m_name,
        s_myvalue->m_type,
        s_myvalue->m_value
    );
}

static void mytest_with_barrier(void)
{
    struct myreq s_myreq;
    struct myvalue s_myvalue;

    memset(&s_myreq, 0, sizeof(s_myreq));
    strncpy(s_myreq.m_name, "Hello", sizeof(s_myreq.m_name));

    s_myreq.m_data = memset(&s_myvalue, 0, sizeof(s_myvalue));
    /* memory barrier */ mytest_barrier();
    s_myvalue.m_type = mytest_type;
    s_myvalue.m_value = mytest_value;

    myprint(&s_myreq);
}

static void mytest_without_barrier(void)
{
    struct myreq s_myreq;
    struct myvalue s_myvalue;

    memset(&s_myreq, 0, sizeof(s_myreq));
    strncpy(s_myreq.m_name, "Hello", sizeof(s_myreq.m_name));

    s_myreq.m_data = memset(&s_myvalue, 0, sizeof(s_myvalue));
    s_myvalue.m_type = mytest_type;
    s_myvalue.m_value = mytest_value;

    myprint(&s_myreq);
}

int main(void)
{
    mytest_with_barrier();
    mytest_without_barrier();

    return(0);
}


>>> "gcc -O2" OUTPUT
NO BUG: n=Hello, cmd=1234, data=0
!! BUG: n=Hello, cmd=0, data=1819043144


More information about the Gcc-bugs mailing list