Toady Tôi cập nhật máy phát triển của mình từ Ubuntu 10.04 LTS lên Ubuntu 12.04 LTS (hoặc ghc 6.12.1
thành ghc 7.4.1
) và tôi chạy vào một hành vi rất lạ tại dự án currenct của tôi.GHC: lỗi phân đoạn trong điều kiện lạ
Sau vài giờ, tôi giảm nó để đoạn mã sau:
{-# 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"
Tôi đang cố gắng để tạo ra một số mã tại thời gian chạy, nhảy với nó, và trở lại một lần nữa. Sử dụng một Makefile, mọi thứ đều tốt:
$ 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
Tuy nhiên, nếu tôi gọi là nhị phân trực tiếp từ vỏ: (? May mắn)
$ ./stackoverflow_segv
entry point: 0x092547e0
Segmentation fault (core dumped)
Hành vi này là tái sản xuất.
Sử dụng gdb
, objdump
và /proc
tôi đã tìm ra:
$ 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
trước khi nhấn enter, tôi chuyển sang một thiết bị đầu cuối thứ hai:
$ 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]
[...]
và ngược lại:
<enter>
Program received signal SIGSEGV, Segmentation fault.
0x0804ce3c in s2aV_info()
Boo. Hãy xem mã này làm gì:
$ 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, nhảy tới *%eax
. Điều gì đã được %eax
một lần nữa?
(gdb) info reg eax
eax 0x80fc810 135251984
Vâng, thực ra nó chỉ là bộ đệm mã. Tìm kiếm /proc/*/maps
cho chúng tôi biết rằng trang này không thể thực thi (rw-p
, phải không?). Nhưng, đó là tình huống tương tự khi thực hiện trong phạm vi make
.
Có gì sai ở đây?
btw, mã cũng có sẵn thông qua gist
chỉnh sửa: ghc bug report
Hoạt động tốt từ dòng lệnh tại đây (openSUSE 11.4, x86_64). Có thể là lỗi của Ubuntu? Hãy thử với một GHC tự xây dựng nếu bạn có thời gian. –
Cảm ơn bạn đã trả lời! Tôi đã thử nó với gói nhị phân từ [haskell.org] (http://www.haskell.org/ghc): (1) ghc-7.4.1, vẫn còn cùng một vấn đề. (2) ghc-7.2.2 không còn nữa \ o/tốt đẹp! (3) ghc-6.12.1 tương tự. Bạn có nghĩ rằng tôi nên báo cáo rằng đó là một lỗi ở những người GHC? – lewurm
Vani nhị phân (unknown-linux)? Tôi nhận được hành vi tương tự như bạn nếu tôi sử dụng 7.2.2 thay vì 7.4.1, mặc dù. Thực sự kỳ lạ. –