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