From owner-freebsd-current@freebsd.org Fri Aug 25 23:44:52 2017 Return-Path: Delivered-To: freebsd-current@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 6F05CDE412D for ; Fri, 25 Aug 2017 23:44:52 +0000 (UTC) (envelope-from kostikbel@gmail.com) Received: from kib.kiev.ua (kib.kiev.ua [IPv6:2001:470:d5e7:1::1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 171457598D; Fri, 25 Aug 2017 23:44:51 +0000 (UTC) (envelope-from kostikbel@gmail.com) Received: from tom.home (kib@localhost [127.0.0.1]) by kib.kiev.ua (8.15.2/8.15.2) with ESMTPS id v7PNig2G020807 (version=TLSv1.2 cipher=DHE-RSA-AES256-GCM-SHA384 bits=256 verify=NO); Sat, 26 Aug 2017 02:44:42 +0300 (EEST) (envelope-from kostikbel@gmail.com) DKIM-Filter: OpenDKIM Filter v2.10.3 kib.kiev.ua v7PNig2G020807 Received: (from kostik@localhost) by tom.home (8.15.2/8.15.2/Submit) id v7PNigIY020806; Sat, 26 Aug 2017 02:44:42 +0300 (EEST) (envelope-from kostikbel@gmail.com) X-Authentication-Warning: tom.home: kostik set sender to kostikbel@gmail.com using -f Date: Sat, 26 Aug 2017 02:44:42 +0300 From: Konstantin Belousov To: Tijl Coosemans Cc: freebsd-current@FreeBSD.org, gerald@FreeBSD.org Subject: Re: Segfault in _Unwind_* code called from pthread_exit Message-ID: <20170825234442.GO1700@kib.kiev.ua> References: <20170823163707.096f93ab@kalimero.tijl.coosemans.org> <20170824154235.GD1700@kib.kiev.ua> <20170824180830.199885b0@kalimero.tijl.coosemans.org> <20170825173851.09116ddc@kalimero.tijl.coosemans.org> MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline In-Reply-To: <20170825173851.09116ddc@kalimero.tijl.coosemans.org> User-Agent: Mutt/1.8.3 (2017-05-23) X-Spam-Status: No, score=-2.0 required=5.0 tests=ALL_TRUSTED,BAYES_00, DKIM_ADSP_CUSTOM_MED,FREEMAIL_FROM,NML_ADSP_CUSTOM_MED autolearn=no autolearn_force=no version=3.4.1 X-Spam-Checker-Version: SpamAssassin 3.4.1 (2015-04-28) on tom.home X-BeenThere: freebsd-current@freebsd.org X-Mailman-Version: 2.1.23 Precedence: list List-Id: Discussions about the use of FreeBSD-current List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 25 Aug 2017 23:44:52 -0000 On Fri, Aug 25, 2017 at 05:38:51PM +0200, Tijl Coosemans wrote: > So both GCC and LLVM unwinding look up the return address in the CFI > table and fail when the return address is garbage, but LLVM treats this > as an end-of-stack condition while GCC further tries to see if the > return address points to a signal trampoline by testing the instruction > bytes at that address. On amd64 the garbage address is unreadable so it > segfaults. On i386 it is readable, the test fails and GCC returns > end-of-stack. How does llvm unwinder detects that the return address is a garbage ? > > To fix the crash and get predictable behaviour in the other cases I > propose always setting the return address to 0. The attached patch does > this for i386 and amd64. I don't know if other architectures need a > similar patch. > Index: sys/amd64/amd64/vm_machdep.c > =================================================================== > --- sys/amd64/amd64/vm_machdep.c (revision 322802) > +++ sys/amd64/amd64/vm_machdep.c (working copy) > @@ -507,6 +507,9 @@ cpu_set_upcall(struct thread *td, void (*entry)(void * > (((uintptr_t)stack->ss_sp + stack->ss_size - 4) & ~0x0f) - 4; > td->td_frame->tf_rip = (uintptr_t)entry; > > + /* Sentinel return address to stop stack unwinding. */ > + suword32((void *)td->td_frame->tf_rsp, 0); > + > /* Pass the argument to the entry point. */ > suword32((void *)(td->td_frame->tf_rsp + sizeof(int32_t)), > (uint32_t)(uintptr_t)arg); > @@ -529,6 +532,9 @@ cpu_set_upcall(struct thread *td, void (*entry)(void * > td->td_frame->tf_fs = _ufssel; > td->td_frame->tf_gs = _ugssel; > td->td_frame->tf_flags = TF_HASSEGS; > + > + /* Sentinel return address to stop stack unwinding. */ > + suword((void *)td->td_frame->tf_rsp, 0); > > /* Pass the argument to the entry point. */ > td->td_frame->tf_rdi = (register_t)arg; > Index: sys/i386/i386/vm_machdep.c > =================================================================== > --- sys/i386/i386/vm_machdep.c (revision 322802) > +++ sys/i386/i386/vm_machdep.c (working copy) > @@ -524,6 +524,9 @@ cpu_set_upcall(struct thread *td, void (*entry)(void * > (((int)stack->ss_sp + stack->ss_size - 4) & ~0x0f) - 4; > td->td_frame->tf_eip = (int)entry; > > + /* Sentinel return address to stop stack unwinding. */ > + suword((void *)td->td_frame->tf_esp, 0); > + > /* Pass the argument to the entry point. */ > suword((void *)(td->td_frame->tf_esp + sizeof(void *)), > (int)arg); I do not object against this, but I believe that a better solution exists for the system side (putting my change for gcc unwinder to detect the signal frame aside). The thread_start() sentinel in libthr should get proper dwarf annotation of not having the return address. May be normal function attributes of no return are enough to force compilers to generate required unwind data. Might be some more magic with inline asm and .cfi_return_column set to undefined.