From owner-freebsd-bugs@FreeBSD.ORG Thu Apr 4 13:50:01 2013 Return-Path: Delivered-To: freebsd-bugs@smarthost.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by hub.freebsd.org (Postfix) with ESMTP id 826B95DB for ; Thu, 4 Apr 2013 13:50:01 +0000 (UTC) (envelope-from gnats@FreeBSD.org) Received: from freefall.freebsd.org (freefall.freebsd.org [IPv6:2001:1900:2254:206c::16:87]) by mx1.freebsd.org (Postfix) with ESMTP id 738C3292 for ; Thu, 4 Apr 2013 13:50:01 +0000 (UTC) Received: from freefall.freebsd.org (localhost [127.0.0.1]) by freefall.freebsd.org (8.14.6/8.14.6) with ESMTP id r34Do0ip061477 for ; Thu, 4 Apr 2013 13:50:00 GMT (envelope-from gnats@freefall.freebsd.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.14.6/8.14.6/Submit) id r34Do0a4061476; Thu, 4 Apr 2013 13:50:00 GMT (envelope-from gnats) Date: Thu, 4 Apr 2013 13:50:00 GMT Message-Id: <201304041350.r34Do0a4061476@freefall.freebsd.org> To: freebsd-bugs@FreeBSD.org Cc: From: Bruce Evans Subject: Re: misc/177624: Swapcontext can get compiled incorrectly X-BeenThere: freebsd-bugs@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list Reply-To: Bruce Evans List-Id: Bug reports List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 04 Apr 2013 13:50:01 -0000 The following reply was made to PR misc/177624; it has been noted by GNATS. From: Bruce Evans To: Brian Demsky Cc: freebsd-gnats-submit@FreeBSD.org, freebsd-bugs@FreeBSD.org Subject: Re: misc/177624: Swapcontext can get compiled incorrectly Date: Fri, 5 Apr 2013 00:46:32 +1100 (EST) This message is in MIME format. The first part should be readable text, while the remaining parts are likely unreadable without MIME-aware tools. --0-2020526060-1365083192=:1025 Content-Type: TEXT/PLAIN; charset=X-UNKNOWN; format=flowed Content-Transfer-Encoding: QUOTED-PRINTABLE On Thu, 4 Apr 2013, Brian Demsky wrote: >> Description: > Here is the code for swap context: > > int > swapcontext(ucontext_t *oucp, const ucontext_t *ucp) > { > int ret; > > if ((oucp =3D=3D NULL) || (ucp =3D=3D NULL)) { > errno =3D EINVAL; > return (-1); > } > oucp->uc_flags &=3D ~UCF_SWAPPED; > ret =3D getcontext(oucp); > if ((ret =3D=3D 0) && !(oucp->uc_flags & UCF_SWAPPED)) { > oucp->uc_flags |=3D UCF_SWAPPED; > ret =3D setcontext(ucp); > } > return (ret); > } > On the OS X port of libc in Mac OSX 10.7.5, this gets compiled as: > ... > 0x00007fff901e870b : pop %rbx > 0x00007fff901e870c : pop %r14 > 0x00007fff901e870e : jmpq 0x7fff90262855 > > The problem is that rbx is callee saved by compiled version of swapcontex= t and then reused before getcontext is called. Getcontext then stores the = wrong value for rbx and setcontext later restores the wrong value for rbx. = If the caller had any value in rbx, it has been trashed at this point. Later you wrote: > The analysis is a little wrong about the problem. Ultimately, the tail c= all to set context trashes the copies of bx and r14 on the stack=85. The bug seems to be in setcontext(). It must preserve the callee-saved registers, not restore them. This would happen automatically if more were written in C. But setcontext() can't be written entirely in C, since it must save all callee-saved registers including ones not used and therefore not normally saved by any C function that it might be in, and possibly also including callee-saved registers for nonstandard or non-C ABIs. In FreeBSD, it is apparently always a syscall. In FreeBSD, this bug doesn't occur on at least amd64 or i386 because the C version of swapcontext() has never been used on these arches. swapcontext() is a syscall too. If setcontext() is a syscall, then it has a minor problem even knowing what the ABI's callee-saved registers are. At least the FreeBSD amd64 version doesn't know anything about this. It uses much the same code as for asynchronous signal handling, so it just restores all registers, including scratch ones that don't need to be preserved. It even restores the return register to the trap frame, although it can't return this to userland. This can probably be fixed a library wrapper. In FreeBSD on amd64, getcontext(), setcontext() and swapcontext() are all syscalls, but their documenation is misplaced in a section 3 man page. swapcontext() is misplaced together with makecontext(), which actually is library function. Oops, not quite. getcontext() is actually a small wrapper around an undocumented setcontext() syscall (this is needed to adjust the instruction pointer register). Only makecontext() is in C, and not a wrapper. I don't count the wrappers that just make a syscall as library functions, since the corresponding syscalls can be made easily without using the C library and this should be documented. Bruce --0-2020526060-1365083192=:1025--