Bug 6743

Summary: Segmentation fault with C test code when using -O2 option
Product: [Runtime] General Runtime Reporter: Yi Zhao <yi.zhao>
Component: General RuntimeAssignee: LiRongQing <rongqing.li>
Status: VERIFIED NOTABUG QA Contact: Lucian Musat <georgex.l.musat>
Severity: normal    
Priority: Medium+ CC: alejandro.hernandez, alexandru.c.georgescu, ke.zou, koen, raj.khem, richard.purdie, rongqing.li, zhangle.yang
Version: 1.7   
Target Milestone: 1.7 M4   
Hardware: x86   
OS: Multiple   
Whiteboard:
OS type for building Yocto: --- Type of Regression: Regression (Used to work)
Verified: Documentation change: No (bug/feature does not impact docs)
Attachments:
Description Flags
test.c none

Description Yi Zhao 2014-09-19 09:22:08 UTC
Created attachment 2130 [details]
test.c

Git rev: master/429802fe6691c8a70ec9735c0db4c6a4e1e1b038

The attachment is a piece of C code.
When compile it with -O2 option, a segfault occurs:
##################
root@qemux86-64:~# gcc -o test test.c
root@qemux86-64:~# ./test 
192.168.1.1
root@qemux86-64:~# 
root@qemux86-64:~# gcc -O2 -o test test.c
root@qemux86-64:~# ./test 
test[893]: segfault at 0 ip 0000000000400944 sp 00007fff87c8f0f0 error 4 in test[400000+1000]
Segmentation fault
root@qemux86-64:~#
##################

gcc version 4.9.1 (GCC)

This issue happens on all qemus and BSPs, regardless the archs.

I test it on Yocto 1.6.1, it works well:
###################
root@qemux86-64:~# gcc -o test test.c 
root@qemux86-64:~# ./test 
192.168.1.1
root@qemux86-64:~# gcc -O2 -o test test.c 
root@qemux86-64:~# ./test 
192.168.1.1
root@qemux86-64:~# 
###################

gcc version 4.8.2 (GCC)


I also test it on some linux distributions, it works well on all of them:
Ubuntu 12.04 x86_64:
gcc version 4.6.3 (Ubuntu/Linaro 4.6.3-1ubuntu5) 

Ubuntu 14.04 x86_64:
gcc version 4.8.2 (Ubuntu 4.8.2-19ubuntu1)

Fedora 20 x86 and x86_64:
gcc version 4.8.3 20140624 (Red Hat 4.8.3-1) (GCC)
Comment 1 Alejandro Hernandez 2014-09-24 23:03:12 UTC
The native compiler produces the same assembly code hence the same error when optimized for any level other than "1", it seems like it is a gcc-4.9 issue.
Comment 2 Khem Raj 2014-09-24 23:41:11 UTC
does this same binary when run on pc segfault too?
Comment 3 Saul Wold 2014-09-25 14:35:14 UTC
Yes the compiled binary segfaults on both the host and target as far as I understand from Alejandro, I will confirm.
Comment 4 Khem Raj 2014-10-04 20:33:10 UTC
Hmm although it crashes but it does not seem like a compiler issue. You might have a coding error in your application. Whats happening is that at -O2 gcc is reordering NULL pointer checks in a way that dereferencing is happening before NULL pointer check.

	strncpy(new, old, cp-old);

here if old is NULL then its undefined behavior which is what you are seeing.
and gcc assumes that old can never be NULL.
Comment 5 Khem Raj 2014-10-04 20:52:15 UTC
This is how you can fix it in your code

--- a.c	2014-10-04 12:28:46.918718452 -0700
+++ a.c.khem	2014-10-04 13:54:41.905347173 -0700
@@ -36,9 +36,11 @@
 		else
 			cp = cp + strlen(cp);
 	}
-
-	strncpy(new, old, cp-old);
-	new[cp-old] = 0;
+	if (old) {
+		strncpy(new, old, cp-old);
+		new[cp-old] = 0;
+	} else
+		new[0] = 0;
 
 	if (cp != old && !*cp)
 		strcat(new, ",");
Comment 6 LiRongQing 2014-10-09 02:28:36 UTC
If the results are different since use different Gcc parameter to building, it should be Gcc bug.

Gcc should keep the same behaviours among different versions, but 4.6.3 and 4.8.2 can work, 4.9.1 did not work...
Comment 7 Khem Raj 2014-10-09 02:35:41 UTC
(In reply to comment #6)
> If the results are different since use different Gcc parameter to building,
> it should be Gcc bug.
> 
> Gcc should keep the same behaviours among different versions, but 4.6.3 and
> 4.8.2 can work, 4.9.1 did not work...

No. A C compiler complies to C standard and where behavior is undefined like this case it has liberty to do whatever it wishes. If your code has been relying on undefined behavior go fix the code, not the compiler.
Comment 8 LiRongQing 2014-10-09 03:06:03 UTC
which line is undefined?  strncpy(new, 0, 0)? no, it should work since the length of strncpy is 0, and src of strncpy will not be used.

I think any change can make these codes work, since any change will make the
gcc optimize to change
Comment 9 Khem Raj 2014-10-09 04:49:32 UTC
(In reply to comment #8)
> which line is undefined?  strncpy(new, 0, 0)? no, it should work since the
> length of strncpy is 0, and src of strncpy will not be used.

I could not infer this from OpenGroup standardIEEE Std 1003.1 where strncpy is defined.
can you kindly show me which standard describes strncpy behavior the way you are mentioning ?

> 
> I think any change can make these codes work, since any change will make the
> gcc optimize to change

Not anything, you have to describe your expected behavior by guarding it with source being valid.
Comment 10 LiRongQing 2014-10-09 05:20:06 UTC
From the test result, strncpy(buf, 0,0) works.
--------------------------------------
#cat aa.c

#include <string.h>
main()
{
	char buf[10];
	strncpy(buf, 0, 0);
}
#

#./sysroots/x86_64-linux/usr/libexec/x86_64-wrs-linux/gcc/x86_64-wrs-linux/4.9.0/x86_64-wrs-linux-gcc -O2 aa.c
#
#./a.out
#
-----------------------------------
but ./sysroots/x86_64-linux/usr/libexec/x86_64-wrs-linux/gcc/x86_64-wrs-linux/4.9.0/x86_64-wrs-linux-gcc -O2 /tmp/test.c
#
#./a.out
Segmentation fault (core dumped)
#
Comment 11 LiRongQing 2014-10-09 05:21:47 UTC
man strncpy, it says:

       A simple implementation of strncpy() might be:

           char *
           strncpy(char *dest, const char *src, size_t n)
           {
               size_t i;

               for (i = 0; i < n && src[i] != '\0'; i++)
                   dest[i] = src[i];
               for ( ; i < n; i++)
                   dest[i] = '\0';

               return dest;
           }
Comment 12 Khem Raj 2014-10-09 05:38:46 UTC
and you think man strcpy is what standards depend upon ?

Please compare the assembly code it will generate for the example you are sighting. Its passing a direct NULL pointer, gcc is smart enough to know that
its no way representative of the original testcase.

I have explained it enough and I do not have more time for it. I am assigning this bug to you and if you feel like fixing it in gcc feel free to. if not you are also welcome to raise this with gcc community.
Comment 13 LiRongQing 2014-10-09 05:47:07 UTC
OK, I will paste it to GCC community
Comment 15 LiRongQing 2014-10-09 07:49:16 UTC
GCC community think this is a testcase bug, same as  Khem Raj.
and Khem Raj's patch works.

Thanks
Comment 16 Lucian Musat 2015-01-15 12:24:09 UTC
This looks like NOTABUG. Setting accordingly.