NetBSD Problem Report #51121
From martin@duskware.de Sat May 7 16:37:33 2016
Return-Path: <martin@duskware.de>
Received: from mail.netbsd.org (mail.netbsd.org [199.233.217.200])
(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
(Client CN "mail.netbsd.org", Issuer "Postmaster NetBSD.org" (verified OK))
by mollari.NetBSD.org (Postfix) with ESMTPS id AD7BF7A3DC
for <gnats-bugs@gnats.NetBSD.org>; Sat, 7 May 2016 16:37:33 +0000 (UTC)
Message-Id: <20160507163731.50133A8019@mail.duskware.de>
Date: Sat, 7 May 2016 18:37:31 +0200 (CEST)
From: martin@NetBSD.org
Reply-To: martin@NetBSD.org
To: gnats-bugs@NetBSD.org
Subject: sparc64 can't build perl
X-Send-Pr-Version: 3.95
>Number: 51121
>Category: toolchain
>Synopsis: sparc64 can't build perl
>Confidential: no
>Severity: critical
>Priority: high
>Responsible: martin
>State: closed
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Sat May 07 16:40:00 +0000 2016
>Closed-Date: Fri Aug 26 08:24:29 +0000 2016
>Last-Modified: Fri Aug 26 08:24:29 +0000 2016
>Originator: Martin Husemann
>Release: NetBSD 7.99.29
>Organization:
The NetBSD Foundation, Inc.
>Environment:
System: NetBSD sunny-weather.duskware.de 7.99.29 NetBSD 7.99.29 (MODULAR) #415: Wed May 4 13:42:17 CEST 2016 martin@night-owl.duskware.de:/usr/src/sys/arch/amd64/compile/NIGHT-OWL sparc64
Architecture: sparc64
Machine: sparc64
>Description:
Trying to build perl from pkgsrc fails on first invocation of miniperl, during
exit/dtor handling by jumping through a NULL pointer.
>How-To-Repeat:
s/a
>Fix:
n/a
>Release-Note:
>Audit-Trail:
From: Martin Husemann <martin@duskware.de>
To: gnats-bugs@NetBSD.org
Cc:
Subject: Re: toolchain/51121: sparc64 can't build perl
Date: Tue, 10 May 2016 12:15:08 +0200
The jump to NULL happens here:
50: 0a 68 00 04 bcs %xcc, 60 <.text.exit+0x60>
54: 82 10 20 00 clr %g1
58: 10 68 00 08 b %xcc, 78 <.text.exit+0x78>
5c: 03 00 00 00 sethi %hi(0), %g1
5c: R_SPARC_GOT22 __deregister_frame_info
60: 9f c0 40 00 call %g1
64: ba 07 60 08 add %i5, 8, %i5
(from /usr/lib/crtbegin.o), which at runtime looks like:
0x34bdcc cmp %i5, %i4
0x34bdd0 bcs %xcc, 0x34bde0
0x34bdd4 clr %g1
0x34bdd8 b %xcc, 0x34bdf8
0x34bddc sethi %hi(0xe000), %g1
0x34bde0 call %g1
0x34bde4 add %i5, 8, %i5
and in this case it %xcc has carry set (which means the DTOR list has been
done) and it branches straight to .text.exit+0x60, with %g1 = 0.
gcc output looks like this:
.LLBB5:
.loc 1 125 0
cmp %i5, %i4
blu,pt %xcc, .LL17
mov 0, %g1
.LLBE5:
.loc 1 131 0
ba,pt %xcc, .LL22
sethi %hi(deregister_frame_info), %g1
.LLVL5:
.LL20:
.LL17:
.LLBB6:
.loc 1 126 0
call %g1, 0
add %i5, 8, %i5
so if the branch at the end of the dtor list to .LL17 is taken, %g1 will be
cleared and we necessarily die jumping to NULL.
Martin
From: "Martin Husemann" <martin@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc:
Subject: PR/51121 CVS commit: src/lib/csu/common
Date: Tue, 10 May 2016 10:23:09 +0000
Module Name: src
Committed By: martin
Date: Tue May 10 10:23:09 UTC 2016
Modified Files:
src/lib/csu/common: Makefile.inc
Log Message:
We need the -O1 hack (for gcc 5.3) for crtbegin.c as well.
Works around PR toolchain/51121.
To generate a diff of this commit:
cvs rdiff -u -r1.30 -r1.31 src/lib/csu/common/Makefile.inc
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
From: Martin Husemann <martin@duskware.de>
To: gnats-bugs@NetBSD.org
Cc:
Subject: Re: toolchain/51121: sparc64 can't build perl
Date: Wed, 11 May 2016 11:06:03 +0200
Suggested by Andrew Pinski in
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=71051
I reworked the crt source slightly and it now works even if compiled wiht -O2
for me.
Suggestions for a better name for the macro hiding the asm() ?
Should we put that somewhere else, in case we need to reuse it elsewhere?
(Linksets?)
Joerg, how does this interact with Clang?
Martin
Index: common/Makefile.inc
===================================================================
RCS file: /cvsroot/src/lib/csu/common/Makefile.inc,v
retrieving revision 1.31
diff -u -p -r1.31 Makefile.inc
--- common/Makefile.inc 10 May 2016 10:23:09 -0000 1.31
+++ common/Makefile.inc 11 May 2016 08:43:43 -0000
@@ -17,14 +17,6 @@ OBJS+= sysident.o
.if ${MKPIC} == "yes"
OBJS+= crtbeginS.o
CFLAGS.crtbegin.c+= -fPIE
-# XXXGCC5 - GCC 5 miscompiles crtbeginS.c on many platforms. on SPARC it
-# XXXGCC5 emits "clr %g1; call %g1", which is effectively jumping to zero.
-. if defined(HAVE_GCC) && ${HAVE_GCC} == 53 && \
- !exists(${ARCHDIR}/crtbegin.S)
-CFLAGS.crt0-common.c+= -O1
-CFLAGS.crtbeginS.c+= -O1
-CFLAGS.crtbegin.c+= -O1
-. endif
.endif
.if ${MACHINE_ARCH} == "alpha"
Index: common/crt0-common.c
===================================================================
RCS file: /cvsroot/src/lib/csu/common/crt0-common.c,v
retrieving revision 1.13
diff -u -p -r1.13 crt0-common.c
--- common/crt0-common.c 31 Jan 2013 22:24:25 -0000 1.13
+++ common/crt0-common.c 11 May 2016 08:43:43 -0000
@@ -89,6 +89,13 @@ do { \
#ifdef HAVE_INITFINI_ARRAY
/*
+ * Make sure the compiler does not know about start/end pointing
+ * to different arrays (so pointer comparison is undefined
+ * behaviour).
+ */
+#define UNALIAS_PTR(PTR) asm("":"+r"(PTR))
+
+/*
* If we are using INIT_ARRAY/FINI_ARRAY and we are linked statically,
* we have to process these instead of relying on RTLD to do it for us.
*
@@ -111,7 +118,12 @@ __weakref_visible const fptr_t fini_arra
static inline void
_preinit(void)
{
- for (const fptr_t *f = preinit_array_start; f < preinit_array_end; f++) {
+ const fptr_t *start = preinit_array_start;
+ const fptr_t *end = preinit_array_end;
+ UNALIAS_PTR(start);
+ UNALIAS_PTR(end);
+
+ for (const fptr_t *f = start; f < end; f++) {
(*f)();
}
}
@@ -119,7 +131,12 @@ _preinit(void)
static inline void
_init(void)
{
- for (const fptr_t *f = init_array_start; f < init_array_end; f++) {
+ const fptr_t *start = init_array_start;
+ const fptr_t *end = init_array_end;
+ UNALIAS_PTR(start);
+ UNALIAS_PTR(end);
+
+ for (const fptr_t *f = start; f < end; f++) {
(*f)();
}
}
@@ -127,7 +144,12 @@ _init(void)
static void
_fini(void)
{
- for (const fptr_t *f = fini_array_start; f < fini_array_end; f++) {
+ const fptr_t *start = fini_array_start;
+ const fptr_t *end = fini_array_end;
+ UNALIAS_PTR(start);
+ UNALIAS_PTR(end);
+
+ for (const fptr_t *f = start; f < end; f++) {
(*f)();
}
}
Index: common/crtbegin.c
===================================================================
RCS file: /cvsroot/src/lib/csu/common/crtbegin.c,v
retrieving revision 1.9
diff -u -p -r1.9 crtbegin.c
--- common/crtbegin.c 6 May 2014 16:02:10 -0000 1.9
+++ common/crtbegin.c 11 May 2016 08:43:43 -0000
@@ -90,7 +90,20 @@ __do_global_ctors_aux(void)
Jv_RegisterClasses(__JCR_LIST__);
#if !defined(HAVE_INITFINI_ARRAY)
- for (const fptr_t *p = __CTOR_LIST_END__; p > __CTOR_LIST__ + 1; ) {
+
+/*
+ * Make sure the compiler does not know about start/end pointing
+ * to different arrays (so pointer comparison is undefined
+ * behaviour).
+ */
+#define UNALIAS_PTR(PTR) asm("":"+r"(PTR))
+
+ const fptr_t *start = __CTOR_LIST__;
+ const fptr_t *end = __CTOR_LIST_END__;
+ UNALIAS_PTR(start);
+ UNALIAS_PTR(end);
+
+ for (const fptr_t *p = end; p > start + 1; ) {
(*(*--p))();
}
#endif
@@ -122,7 +135,12 @@ __do_global_dtors_aux(void)
#endif
#if !defined(HAVE_INITFINI_ARRAY)
- for (const fptr_t *p = __DTOR_LIST__ + 1; p < __DTOR_LIST_END__; ) {
+ const fptr_t *start = __DTOR_LIST__;
+ const fptr_t *end = __DTOR_LIST_END__;
+ UNALIAS_PTR(start);
+ UNALIAS_PTR(end);
+
+ for (const fptr_t *p = start + 1; p < end; ) {
(*(*p++))();
}
#endif
From: "Joerg Sonnenberger" <joerg@netbsd.org>
To: gnats-bugs@gnats.NetBSD.org
Cc:
Subject: PR/51121 CVS commit: src/lib/csu/common
Date: Wed, 1 Jun 2016 21:21:55 +0000
Module Name: src
Committed By: joerg
Date: Wed Jun 1 21:21:55 UTC 2016
Modified Files:
src/lib/csu/common: crtbegin.c
Log Message:
PR toolchain/51121:
__CTOR_LIST__ and __CTOR_LIST_END__ are logically the same object, but
due to the start marker, the former has to be declared as array of fixed
size. Newer GCC versions take the liberty of exploiting the UB of
accessing global objects past the end to unconditionally load zero
values in that case. Two fixes are possible:
(1) Pruning via inline assembler as done by GCC's own CRT copy.
(2) Pruning via weak references as done for linker sets.
Since the second part is known and required to work anyway, prefer this
approach. In theory, the labels could be replaced completely, except
that GNU as doesn't provide start/end symbols for sections containing
dots.
To generate a diff of this commit:
cvs rdiff -u -r1.9 -r1.10 src/lib/csu/common/crtbegin.c
Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.
State-Changed-From-To: open->feedback
State-Changed-By: wiz@NetBSD.org
State-Changed-When: Thu, 02 Jun 2016 07:55:46 +0000
State-Changed-Why:
Fixed?
From: Martin Husemann <martin@duskware.de>
To: gnats-bugs@NetBSD.org
Cc:
Subject: Re: toolchain/51121 (sparc64 can't build perl)
Date: Thu, 2 Jun 2016 22:34:41 +0200
Can't test right now, -current is completely broken.
Martin
Responsible-Changed-From-To: toolchain-manager->martin
Responsible-Changed-By: martin@NetBSD.org
Responsible-Changed-When: Wed, 15 Jun 2016 07:12:24 +0000
Responsible-Changed-Why:
Take
State-Changed-From-To: feedback->closed
State-Changed-By: martin@NetBSD.org
State-Changed-When: Wed, 15 Jun 2016 07:12:24 +0000
State-Changed-Why:
Assume fixed, will re-test when we switch back to gcc 5.4
State-Changed-From-To: closed->open
State-Changed-By: martin@NetBSD.org
State-Changed-When: Wed, 22 Jun 2016 15:20:48 +0000
State-Changed-Why:
This also causes crashes from sshd and postfix on various architectures,
at least VAX and mips64
From: Martin Husemann <martin@duskware.de>
To: gnats-bugs@NetBSD.org
Cc:
Subject: Re: toolchain/51121: undefined behaviour in CSU causes crashes
Date: Wed, 22 Jun 2016 17:27:24 +0200
We see similar fallout on mips64 and VAX with sshd and also sparc64
when compiled with gcc 5.4 for sshd and postfix. This makes it nearly
impossible to debug locally, neeeds assembler review.
Maybe the patch below can help?
Martin
Index: sys/sys/cdefs.h
===================================================================
RCS file: /cvsroot/src/sys/sys/cdefs.h,v
retrieving revision 1.128
diff -u -p -r1.128 cdefs.h
--- sys/sys/cdefs.h 19 Nov 2015 17:04:01 -0000 1.128
+++ sys/sys/cdefs.h 22 Jun 2016 15:00:06 -0000
@@ -607,6 +607,32 @@ static __inline unsigned long long __zer
#define __zeroull() (0ULL)
#endif
+#ifndef __ASSEMBLER__
+/*
+ * __launder_type(): We use this ugly hack to work around the the compiler
+ * noticing that two types may not alias each other and elide tests in code.
+ * We hit this in the CIRCLEQ macros when comparing 'struct name *' and
+ * 'struct type *' (see CIRCLEQ_HEAD()) and also in the lib/csu code.
+ * Comparing pointers besides == and != for different objects (according
+ * to the non-aliasing rules) is undefined behaviour and some compilers
+ * always evaluate such comparisons as !=.
+ *
+ * This hack is only to be used for comparisons and thus can be fully const.
+ * Do not use for assignment.
+ *
+ * If we ever choose to change the ABI of the CIRCLEQ macros, we could fix
+ * this by changing the head/tail sentinal values, but see the note above
+ * this one.
+ */
+static __inline const void * __launder_type(const void *);
+static __inline const void *
+__launder_type(const void *__x)
+{
+ __asm __volatile("" : "+r" (__x));
+ return __x;
+}
+#endif
+
#define __negative_p(x) (!((x) > 0) && ((x) != 0))
#define __type_min_s(t) ((t)((1ULL << (sizeof(t) * NBBY - 1))))
Index: sys/sys/queue.h
===================================================================
RCS file: /cvsroot/src/sys/sys/queue.h,v
retrieving revision 1.70
diff -u -p -r1.70 queue.h
--- sys/sys/queue.h 2 Nov 2015 15:21:23 -0000 1.70
+++ sys/sys/queue.h 22 Jun 2016 15:00:06 -0000
@@ -663,29 +663,6 @@ struct { \
* is discouraged!
*/
-/*
- * __launder_type(): We use this ugly hack to work around the the compiler
- * noticing that two types may not alias each other and elide tests in code.
- * We hit this in the CIRCLEQ macros when comparing 'struct name *' and
- * 'struct type *' (see CIRCLEQ_HEAD()). Modern compilers (such as GCC
- * 4.8) declare these comparisons as always false, causing the code to
- * not run as designed.
- *
- * This hack is only to be used for comparisons and thus can be fully const.
- * Do not use for assignment.
- *
- * If we ever choose to change the ABI of the CIRCLEQ macros, we could fix
- * this by changing the head/tail sentinal values, but see the note above
- * this one.
- */
-static __inline const void * __launder_type(const void *);
-static __inline const void *
-__launder_type(const void *__x)
-{
- __asm __volatile("" : "+r" (__x));
- return __x;
-}
-
#if defined(QUEUEDEBUG)
#define QUEUEDEBUG_CIRCLEQ_HEAD(head, field) \
if ((head)->cqh_first != CIRCLEQ_ENDC(head) && \
Index: lib/csu/common/crt0-common.c
===================================================================
RCS file: /cvsroot/src/lib/csu/common/crt0-common.c,v
retrieving revision 1.14
diff -u -p -r1.14 crt0-common.c
--- lib/csu/common/crt0-common.c 7 Jun 2016 12:07:35 -0000 1.14
+++ lib/csu/common/crt0-common.c 22 Jun 2016 15:00:06 -0000
@@ -96,16 +96,17 @@ do { \
* to make life easier.
*/
extern const fptr_t __preinit_array_start[] __dso_hidden;
-extern const fptr_t __preinit_array_end[] __dso_hidden __weak;
+extern const fptr_t __preinit_array_end[] __dso_hidden;
extern const fptr_t __init_array_start[] __dso_hidden;
-extern const fptr_t __init_array_end[] __dso_hidden __weak;
+extern const fptr_t __init_array_end[] __dso_hidden;
extern const fptr_t __fini_array_start[] __dso_hidden;
-extern const fptr_t __fini_array_end[] __dso_hidden __weak;
+extern const fptr_t __fini_array_end[] __dso_hidden;
static inline void
_preinit(void)
{
- for (const fptr_t *f = __preinit_array_start; f < __preinit_array_end; f++) {
+ const fptr_t end = __launder_type(__preinit_array_end);
+ for (const fptr_t *f = __preinit_array_start; f < end; f++) {
(*f)();
}
}
@@ -113,7 +114,8 @@ _preinit(void)
static inline void
_init(void)
{
- for (const fptr_t *f = __init_array_start; f < __init_array_end; f++) {
+ const fptr_t end = __launder_type(__init_array_end);
+ for (const fptr_t *f = __init_array_start; f < end; f++) {
(*f)();
}
}
@@ -121,7 +123,8 @@ _init(void)
static void
_fini(void)
{
- for (const fptr_t *f = __fini_array_start; f < __fini_array_end; f++) {
+ const fptr_t end = __launder_type(__fini_array_end);
+ for (const fptr_t *f = __fini_array_start; f < end; f++) {
(*f)();
}
}
State-Changed-From-To: open->closed
State-Changed-By: maya@NetBSD.org
State-Changed-When: Fri, 26 Aug 2016 08:24:29 +0000
State-Changed-Why:
confirmed fixed
>Unformatted:
(Contact us)
$NetBSD: query-full-pr,v 1.39 2013/11/01 18:47:49 spz Exp $
$NetBSD: gnats_config.sh,v 1.8 2006/05/07 09:23:38 tsutsui Exp $
Copyright © 1994-2014
The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.