SWI-Prolog / swipl-devel

SWI-Prolog Main development repository
http://www.swi-prolog.org
Other
976 stars 176 forks source link

Crash in `thread_exit/1` #1317

Closed eshelyaron closed 2 months ago

eshelyaron commented 2 months ago

Hi,

In Sweep, we have so far been using thread_signal(T, thread_exit(0)) to kill top-level threads. With SWI-Prolog 9.3.10 (and possibly a couple of versions before that), this yields a crash with the following backtrace:

* thread #15, stop reason = EXC_BAD_ACCESS (code=1, address=0xc)
  * frame #0: 0x00000001103508c3 libswipl.9.3.10.dylib`freeRecord(record=0x0000000000000000) at pl-rec.c:1802:8
    frame #1: 0x000000011044df05 libswipl.9.3.10.dylib`PL_erase(r=0x0000000000000000) at pl-fli.c:5379:3
    frame #2: 0x000000011039f89e libswipl.9.3.10.dylib`freeThreadSignals(ld=0x00007fb4ce26fe00) at pl-thread.c:3689:5
    frame #3: 0x000000011039f2b9 libswipl.9.3.10.dylib`freePrologThread(ld=0x00007fb4ce26fe00, after_fork=0) at pl-thread.c:778:5
    frame #4: 0x0000000110395b5f libswipl.9.3.10.dylib`free_prolog_thread(data=0x00007fb4ce26fe00) at pl-thread.c:847:3
  frame #5: 0x00007ff81205b7f2 libsystem_pthread.dylib`_pthread_exit + 53
  frame #6: 0x00007ff812058f18 libsystem_pthread.dylib`pthread_exit + 42
    frame #7: 0x0000000110392b40 libswipl.9.3.10.dylib`pl_thread_exit(retcode=335) at pl-thread.c:2815:3
    frame #8: 0x000000011025b773 libswipl.9.3.10.dylib`PL_next_solution___LD(__PL_ld=0x00007fb4ce26fe00, qid=0x00006000030aac80) at pl-vmi.c:4508:3
    frame #9: 0x0000000110319559 libswipl.9.3.10.dylib`callProlog(module=0x0000600001db7e80, goal=288, flags=8, ex=0x000070000222e998) at pl-pro.c:495:16
    frame #10: 0x000000011039306a libswipl.9.3.10.dylib`executeThreadSignals(sig=34) at pl-thread.c:3651:14
    frame #11: 0x000000011035b112 libswipl.9.3.10.dylib`dispatch_signal(sig=34, sync=1) at pl-setup.c:577:5
    frame #12: 0x000000011035d7ac libswipl.9.3.10.dylib`handleSignals___LD(__PL_ld=0x00007fb4ce26fe00) at pl-setup.c:1224:4
    frame #13: 0x000000011024ec32 libswipl.9.3.10.dylib`PL_next_solution___LD(__PL_ld=0x00007fb4ce26fe00, qid=0x00006000030ab0a0) at pl-vmi.c:1945:2
    frame #14: 0x00000001103189ab libswipl.9.3.10.dylib`query_loop(goal=32133, loop=1) at pl-pro.c:147:12
    frame #15: 0x0000000110319141 libswipl.9.3.10.dylib`pl_break1(goal=32133) at pl-pro.c:224:15
    frame #16: 0x0000000110318fdd libswipl.9.3.10.dylib`pl_break at pl-pro.c:261:10
    frame #17: 0x000000011025b683 libswipl.9.3.10.dylib`PL_next_solution___LD(__PL_ld=0x00007fb4ce26fe00, qid=0x00006000030ab1f0) at pl-vmi.c:4495:3
    frame #18: 0x0000000110319559 libswipl.9.3.10.dylib`callProlog(module=0x0000600001db7e80, goal=22, flags=8, ex=0x000070000223df90) at pl-pro.c:495:16
    frame #19: 0x0000000110392682 libswipl.9.3.10.dylib`start_thread(closure=0x00006000004a5c30) at pl-thread.c:2089:17

Replacing thread_exit/1 with throw/1 seems to circumvent this issue, so I'll perform such a change in Sweep, but I thought I'd report this anyway for visibility.

Also, when trying to debug this crash I stumbled into another crash in initGMP during Sweep initialization. I used the following workaround, but I'm not familiar enough with these areas to be sure it's the right solution:

diff --git a/src/pl-gmp.c b/src/pl-gmp.c
index e98f7e8e7..61f48dce2 100644
--- a/src/pl-gmp.c
+++ b/src/pl-gmp.c
@@ -1191,8 +1191,8 @@ initGMP(void)
     if ( !GD->gmp.keep_alloc_functions )
     { mp_get_memory_functions(&smp_alloc, &smp_realloc, &smp_free);
       mp_set_memory_functions(mp_alloc, mp_realloc, mp_free);
+      DEBUG(0, mp_test_alloc());
     }
-    DEBUG(0, mp_test_alloc());
 #endif

 #if O_GMP
JanWielemaker commented 2 months ago

thread_exit/1 is deprecated as it may deadlock the system when called if the receiving thread holds a lock. The currect way to kill a thread is

(   catch(thread_signal(TID, abort), error(_,_), fail)
->  thread_join(TID, _)
;   true
).