Swapcontext is broken on 10.7.5

Originator:bdemsky
Number:rdar://13579306 Date Originated:4/4/2013
Status:Duplicate Resolved:
Product:OS X Product Version:10.7.5
Classification: Reproducible:yes
 
Here is the code for the system library version of swapcontext taken from the apple open source site:
int swapcontext(ucontext_t *oucp, const ucontext_t *ucp)
{
    int ret;
    if ((oucp == NULL) || (ucp == NULL)) {
            errno = EINVAL;
            return (-1);
    }
    oucp->uc_flags &= ~UCF_SWAPPED;
    ret = getcontext(oucp);
    if ((ret == 0) && !(oucp->uc_flags & UCF_SWAPPED)) {
            oucp->uc_flags |= UCF_SWAPPED;
            ret = setcontext(ucp);
    }
    return (ret);
}

On the OS X port of libc in Mac OSX 10.7.5, this gets compiled to:

0x00007fff901e86b2 <swapcontext+0>:     push   %r14
0x00007fff901e86b4 <swapcontext+2>:     push   %rbx
0x00007fff901e86b5 <swapcontext+3>:     sub    $0x8,%rsp
0x00007fff901e86b9 <swapcontext+7>:     test   %rdi,%rdi
0x00007fff901e86bc <swapcontext+10>:    je     0x7fff901e86c6 <swapcontext+20>
0x00007fff901e86be <swapcontext+12>:    mov    %rsi,%rbx
0x00007fff901e86c1 <swapcontext+15>:    test   %rbx,%rbx
0x00007fff901e86c4 <swapcontext+18>:    jne    0x7fff901e86d8 <swapcontext+38>
0x00007fff901e86c6 <swapcontext+20>:    callq  0x7fff90262c88 <__error>
0x00007fff901e86cb <swapcontext+25>:    movl   $0x16,(%rax)
0x00007fff901e86d1 <swapcontext+31>:    mov    $0xffffffff,%eax
0x00007fff901e86d6 <swapcontext+36>:    jmp    0x7fff901e86f3 <swapcontext+65>
0x00007fff901e86d8 <swapcontext+38>:    mov    %rdi,%r14
0x00007fff901e86db <swapcontext+41>:    andb   $0x7f,0x3(%r14)
0x00007fff901e86e0 <swapcontext+46>:    mov    %r14,%rdi
0x00007fff901e86e3 <swapcontext+49>:    callq  0x7fff901e87af <getcontext>
0x00007fff901e86e8 <swapcontext+54>:    test   %eax,%eax
0x00007fff901e86ea <swapcontext+56>:    jne    0x7fff901e86f3 <swapcontext+65>
0x00007fff901e86ec <swapcontext+58>:    mov    (%r14),%ecx
0x00007fff901e86ef <swapcontext+61>:    test   %ecx,%ecx
0x00007fff901e86f1 <swapcontext+63>:    jns    0x7fff901e86fb <swapcontext+73>
0x00007fff901e86f3 <swapcontext+65>:    add    $0x8,%rsp
0x00007fff901e86f7 <swapcontext+69>:    pop    %rbx
0x00007fff901e86f8 <swapcontext+70>:    pop    %r14
0x00007fff901e86fa <swapcontext+72>:    retq
0x00007fff901e86fb <swapcontext+73>:    or     $0x80000000,%ecx
0x00007fff901e8701 <swapcontext+79>:    mov    %ecx,(%r14)
0x00007fff901e8704 <swapcontext+82>:    mov    %rbx,%rdi
0x00007fff901e8707 <swapcontext+85>:    add    $0x8,%rsp
0x00007fff901e870b <swapcontext+89>:    pop    %rbx
0x00007fff901e870c <swapcontext+90>:    pop    %r14
0x00007fff901e870e <swapcontext+92>:    jmpq   0x7fff90262855 <setcontext>

The important thing to note is that rbx and r14 are stored on the stack and therefore not stored by the getcontext call.  This would be okay, but there is a tail call to setcontext after they are popped off.  We next look at setcontext and see:

(gdb) disassemble setcontext
Dump of assembler code for function setcontext:
0x00007fff90262855 <setcontext+0>:      push   %rbx
0x00007fff90262856 <setcontext+1>:      lea    0x38(%rdi),%rbx
0x00007fff9026285a <setcontext+5>:      cmp    0x30(%rdi),%rbx
0x00007fff9026285e <setcontext+9>:      je     0x7fff90262864 <setcontext+15>
0x00007fff90262860 <setcontext+11>:     mov    %rbx,0x30(%rdi)
0x00007fff90262864 <setcontext+15>:     mov    0x4(%rdi),%edi
0x00007fff90262867 <setcontext+18>:     callq  0x7fff90262998 <sigsetmask>
0x00007fff9026286c <setcontext+23>:     mov    %rbx,%rdi
0x00007fff9026286f <setcontext+26>:     pop    %rbx
0x00007fff90262870 <setcontext+27>:     jmpq   0x7fff90262875 <_setcontext>
End of assembler dump.

It begins by pushing rbx to stack and trashing the memory location where r14 was stored.  It then calls sigsetmask which pushes stuff on the stack overwriting the memory location where rbx was stored.  Thus when we revive the saved context, rbx and r14 will both have bogus values when the pop statement are executed in swapcontext.


Steps to Reproduce: Any call to swapcontext in which rbx or r14 stores something important will lose rbx or r14.

Expected Results: rbx and r14 are callee saved registers.  They should be preserved.

Actual Results:

Regression:

Notes:

Comments


Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at bugreport.apple.com before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!