This is the mail archive of the
libffi-discuss@sourceware.org
mailing list for the libffi project.
Corrupted stack on Sparc with Python CFFI
- From: Vincent Bernat <bernat at luffy dot cx>
- To: libffi-discuss at sourceware dot org
- Date: Sun, 22 Dec 2013 00:20:26 +0100
- Subject: Corrupted stack on Sparc with Python CFFI
- Authentication-results: sourceware.org; auth=none
Hi!
I have run into the following problem with Python CFFI when running on
Sparc V8. The platform is the following:
- Linux smetana 2.6.32-5-sparc64-smp #1 SMP Mon Feb 25 02:19:08 UTC 2013 sparc64 GNU/Linux
- libffi 3.0.13
- python-cffi 0.8.1 (also tried with Mercurial repository)
- 32bit userspace, latest Debian unstable
Here is a simple Python program to trigger the bug:
#+begin_src python
#!/usr/bin/python
from cffi import FFI
import cffi.verifier
cffi.verifier._FORCE_GENERIC_ENGINE = True
ffi = FFI()
ffi.cdef("""
typedef struct { ...; } myhandle_t;
myhandle_t foo(void);
""")
lib = ffi.verify("""
typedef short myhandle_t;
myhandle_t foo(void) { return 42; }
""", extra_compile_args=["-g", "-O0"])
print lib.foo()
#+end_src
If you are not familiar with python cffi, testing for the bug is quite
easy, download cffi from here:
https://pypi.python.org/pypi/cffi
Run "python setup.py build_ext -i", copy the above file in the current
directory and execute it with python. You get an illegal instruction
error.
The generated code contains the following bits:
#+begin_src c
typedef short myhandle_t;
myhandle_t foo(void) { return 42; }
myhandle_t _cffi_f_foo(void)
{
return foo();
}
#+end_src
When the illegal instruction occurs, I have this in gdb:
#+begin_example
(gdb) bt
#0 _cffi_f_foo () at __pycache__/_cffi__gc12d9a91xdd04fb9c.c:48
#1 0xf7ff401c in ?? ()
#2 0xf7ff4020 in ?? ()
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
(gdb) disassemble 0xf7ff4008,+30
Dump of assembler code from 0xf7ff4008 to 0xf7ff4026:
0xf7ff4008: mov %i7, %l7
0xf7ff400c: mov %o7, %i7
0xf7ff4010: sethi %hi(0xf78d0400), %g1
0xf7ff4014: call %g1 + 0x228 ! 0xf78d0628 <_cffi_f_foo>
0xf7ff4018: nop
0xf7ff401c: illtrap 0x2
0xf7ff4020: ret
0xf7ff4024: mov %l7, %i7
#+end_example
So, the code seems the one generated in `ffi.c`. I don't know if it is
expected that the return pointer is set on the illtrap instruction and
the next one on ret.
When executing step by step the code before the stacks become corrupt
after calling _cffi_f_foo:
#+begin_example
(gdb) bt 2
#0 0xf7ff400c in ?? ()
#1 0xf7af5b38 in ffi_call_v8 () at ../src/sparc/v8.S:89
(More stack frames follow...)
(gdb) si
0xf7ff4010 in ?? ()
(gdb) bt 2
#0 0xf7ff4010 in ?? ()
#1 0xf7af5b38 in ffi_call_v8 () at ../src/sparc/v8.S:89
(More stack frames follow...)
(gdb) si
0xf7ff4014 in ?? ()
(gdb) bt 2
#0 0xf7ff4014 in ?? ()
#1 0xf7af5b38 in ffi_call_v8 () at ../src/sparc/v8.S:89
(More stack frames follow...)
(gdb) si
0xf7ff4018 in ?? ()
(gdb) bt 2
#0 0xf7ff4018 in ?? ()
#1 0xf7ff4020 in ?? ()
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
(gdb) si
_cffi_f_foo () at __pycache__/_cffi__gc12d9a91xdd04fb9c.c:47
47 {
(gdb) bt 4
#0 _cffi_f_foo () at __pycache__/_cffi__gc12d9a91xdd04fb9c.c:47
#1 0xf7ff401c in ?? ()
#2 0xf7ff4020 in ?? ()
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
#+end_example
I absolutely don't know how the Sparc ABI should work (and I have a hard
time even understanding what the illtrap/unimp instruction is used
for). Is there something that could explain this behaviour?
_cffi_f_foo is like this:
#+begin_src asm
Dump of assembler code for function _cffi_f_foo:
0xf78d0628 <+0>: save %sp, -96, %sp
0xf78d062c <+4>: call 0xf78d05c0 <foo>
0xf78d0630 <+8>: nop
0xf78d0634 <+12>: mov %o0, %g1
=> 0xf78d0638 <+16>: sll %g1, 0x10, %g1
0xf78d063c <+20>: sra %g1, 0x10, %g1
0xf78d0640 <+24>: mov %g1, %i0
0xf78d0644 <+28>: rett %i7 + 8
0xf78d0648 <+32>: nop
#+end_src
After returning, I got to the illtrap instruction and get a SIGILL.
--
printk(KERN_WARNING "%s: Short circuit detected on the lobe\n",
dev->name);
2.4.0-test2 /usr/src/linux/drivers/net/tokenring/lanstreamer.c