I've encountered a reproducible crash in CLIPS, presumably caused be accessing memory after it's been freed. Specifically the code is trying to perform a retract, but one of the "binds" is dangling pointer. I bypassed CLIPS memory manager to route everything through malloc so I could use OS X memory debugging tools and here is what I found:
=================================================================
==23327==ERROR: AddressSanitizer: heap-use-after-free on address 0x603000805fc0 at pc 0x00010196a65e bp 0x00011428cb30 sp 0x00011428cb28
READ of size 8 at 0x603000805fc0 thread T21
#0 0x10196a65d in PartialMatchDefunct retract.c:438
#1 0x1019690d3 in FindNextConflictingMatch retract.c:350
#2 0x101967a81 in NegEntryRetractBeta retract.c:198
#3 0x101964187 in NegEntryRetractAlpha retract.c:177
#4 0x1019649ce in PosEntryRetractBeta retract.c:266
#5 0x101963372 in PosEntryRetractAlpha retract.c:129
#6 0x101962a2f in NetworkRetract retract.c:94
#7 0x101a02aff in EnvRetract factmngr.c:597
#8 0x101317827 in RetractCommand factcom.c:347
#9 0x1022b93a1 in EvaluateExpression evaluatn.c:187
#10 0x1015dcd9a in PrognFunction prcdrfun.c:600
#11 0x1022bc5f1 in EvaluateExpression evaluatn.c:389
#12 0x102335d5f in EvaluateProcActions prccode.c:888
#13 0x1023e6c7c in EnvRun engine.c:353
[redacted]
0x603000805fc0 is located 0 bytes inside of 32-byte region [0x603000805fc0,0x603000805fe0)
freed by thread T21 here:
#0 0x100086d05 in wrap_free (/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/6.2.0/lib/darwin/libclang_rt.asan_osx_dynamic.dylib+0x40d05)
#1 0x10224bca4 in genfree memalloc.c:167
#2 0x10224d826 in rm memalloc.c:386
#3 0x101965d95 in ReturnPartialMatch retract.c:528
#4 0x1019674f5 in FlushGarbagePartialMatches retract.c:651
#5 0x1023e7ff1 in EnvRun engine.c:421
[redacted]
previously allocated by thread T21 here:
#0 0x100086b5c in wrap_malloc (/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/6.2.0/lib/darwin/libclang_rt.asan_osx_dynamic.dylib+0x40b5c)
#1 0x10224a0bf in genalloc memalloc.c:103
#2 0x10166a20b in CreateAlphaMatch reteutil.c:672
#3 0x1019dbfd1 in ProcessFactAlphaMatch factmch.c:545
#4 0x1019d7ae2 in FactPatternMatch factmch.c:199
#5 0x101a0b6f9 in EnvAssert factmngr.c:833
#6 0x101316c50 in AssertCommand factcom.c:259
#7 0x1022bc5f1 in EvaluateExpression evaluatn.c:389
#8 0x1015dcd9a in PrognFunction prcdrfun.c:600
#9 0x1022bc5f1 in EvaluateExpression evaluatn.c:389
#10 0x102335d5f in EvaluateProcActions prccode.c:888
#11 0x10160f13d in CallDeffunction dffnxexe.c:152
#12 0x102380855 in EvaluateDeffunctionCall dffnxfun.c:690
#13 0x1022be1e0 in EvaluateExpression evaluatn.c:462
#14 0x102326c9a in PutProcBind prccode.c:1233
#15 0x1022be1e0 in EvaluateExpression evaluatn.c:462
#16 0x1015dcd9a in PrognFunction prcdrfun.c:600
#17 0x1022bc5f1 in EvaluateExpression evaluatn.c:389
#18 0x102335d5f in EvaluateProcActions prccode.c:888
#19 0x1023e6c7c in EnvRun engine.c:353
[redacted]
Thread T21 created by T12 here:
<empty stack=""></empty>
Thread T12 created by T8 here:
<empty stack=""></empty>
Thread T8 created by T2 here:
<empty stack=""></empty>
Thread T2 created by T0 here:
<empty stack=""></empty>
SUMMARY: AddressSanitizer: heap-use-after-free retract.c:438 PartialMatchDefunct
Shadow bytes around the buggy address:
0x1c0600100ba0: 00 fa fa fa fd fd fd fa fa fa fd fd fd fa fa fa
0x1c0600100bb0: 00 00 00 00 fa fa fd fd fd fd fa fa fd fd fd fd
0x1c0600100bc0: fa fa fd fd fd fa fa fa fd fd fd fa fa fa fd fd
0x1c0600100bd0: fd fd fa fa fd fd fd fa fa fa fd fd fd fa fa fa
0x1c0600100be0: fd fd fd fa fa fa fd fd fd fa fa fa fd fd fd fa
=>0x1c0600100bf0: fa fa fd fd fd fa fa fa[fd]fd fd fd fa fa fd fd
0x1c0600100c00: fd fa fa fa fd fd fd fd fa fa 00 00 00 fa fa fa
0x1c0600100c10: 00 00 00 00 fa fa 00 00 00 00 fa fa fd fd fd fa
0x1c0600100c20: fa fa fd fd fd fa fa fa fd fd fd fa fa fa fd fd
0x1c0600100c30: fd fa fa fa fd fd fd fa fa fa fd fd fd fa fa fa
0x1c0600100c40: fd fd fd fa fa fa fd fd fd fa fa fa fd fd fd fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Heap right redzone: fb
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack partial redzone: f4
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
==23327==ABORTING
Can you attach the code you used for reproducing the issue? I will need to step through the code to determine what is causing the issue. Also, are you using the latest revision of the code?
Going to try extracting it into something that’s only CLIPS code so I can send it to you. Most other applications of the engine work perfectly, but this one retracts facts in a (do-for-all-facts) loop and I’ve seen that cause problems. That’s a separate issue and I can suggest a patch for it in a different ticket. I only bring it up in case you want to tell me “don’t ever do that”.
In the CLIPS IDE, on OS X, load the constructs file crashing_rules.clp, then load the batch file crashing_cmds.tst
It should crash immediately.
Last edit: Chad Woolf 2015-03-09
I can reproduce the issue. The fix described in ticket #6 prevents the crash, but only in the IDE. It still crashes in the console version of CLIPS. The fix is valid, but there's another issue that's unrelated to the query function that I'm working on now.
Fixes checked in to the repository with revision 252.
Works perfectly. Thank you!