Toady I upgraded my development machine from Ubuntu 10.04 LTS to Ubuntu 12.04 LTS (or from ghc 6.12.1 to ghc 7.4.1 ), and I came across very strange behavior in my current project.
After a few hours, I reduced it to the following code:
{-# LANGUAGE ForeignFunctionInterface #-} module Main where import Data.Word import Text.Printf import Foreign foreign import ccall "dynamic" code_void :: FunPtr (IO ()) -> (IO ()) main :: IO () main = do entryPtr <- (mallocBytes 2) poke entryPtr (0xc390 :: Word16) -- nop (0x90); ret(0xc3) (little endian order) _ <- printf "entry point: 0x%08x\n" ((fromIntegral $ ptrToIntPtr entryPtr) :: Int) _ <- getLine -- for debugging code_void $ castPtrToFunPtr entryPtr putStrLn "welcome back"
I am trying to create code at runtime, go to it and come back again. Using the Makefile, everything is fine:
$ make ghc --make -Wall -O2 Main.hs -o stackoverflow_segv [1 of 1] Compiling Main ( Main.hs, Main.o ) Linking stackoverflow_segv ... ./stackoverflow_segv entry point: 0x098d77e0 welcome back
However, if I call the binary directly from the shell:
$ ./stackoverflow_segv entry point: 0x092547e0 Segmentation fault (core dumped)
This behavior is reproducible (fortunately?).
Using gdb , objdump and /proc , I realized:
$ gdb -q stackoverflow_segv Reading symbols from /home/lewurm/stackoverflow/stackoverflow_segv...(no debugging symbols found)...done. (gdb) run Starting program: /home/lewurm/stackoverflow/stackoverflow_segv [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/i386-linux-gnu/libthread_db.so.1". entry point: 0x080fc810
before pressing enter, I will switch to the second terminal:
$ cat /proc/`pgrep stackoverflow`/maps [...] 08048000-080ea000 r-xp 00000000 08:01 2492678 /home/lewurm/stackoverflow/stackoverflow_segv 080ea000-080eb000 r--p 000a2000 08:01 2492678 /home/lewurm/stackoverflow/stackoverflow_segv 080eb000-080f1000 rw-p 000a3000 08:01 2492678 /home/lewurm/stackoverflow/stackoverflow_segv 080f1000-08115000 rw-p 00000000 00:00 0 [heap] [...]
and back:
<enter> Program received signal SIGSEGV, Segmentation fault. 0x0804ce3c in s2aV_info ()
Boo. See what this code does:
$ objdump -D stackoverflow_segv | grep -C 3 804ce3c 804ce31: 89 44 24 4c mov %eax,0x4c(%esp) 804ce35: 83 ec 0c sub $0xc,%esp 804ce38: 8b 44 24 4c mov 0x4c(%esp),%eax 804ce3c: ff d0 call *%eax 804ce3e: 83 c4 0c add $0xc,%esp 804ce41: 83 ec 08 sub $0x8,%esp 804ce44: 8b 44 24 54 mov 0x54(%esp),%eax
uhm jumping on *%eax . What was %eax again?
(gdb) info reg eax eax 0x80fc810 135251984
Well, actually this is just a code buffer. A search for /proc/*/maps tells us that this page is not feasible ( rw-p , right?). But, the same situation when doing this in make .
What is wrong here?
btw, code is also available through gist
edit: ghc error report