Learn how easy it is to sync an existing GitHub or Google Code repo to a SourceForge project! See Demo

Close

segfault with watch all

Help
2009-04-04
2013-04-25
  • Hi,

    The following code snippet causes a segfault with pyclips-1.0.7.348.

    crash.py:
    import clips
    clips.DebugConfig.WatchAll()
    clips.Load("crash.clp")
    t1 = clips.FindTemplate('t1')
    t2 = clips.FindTemplate('t2')
    f2 = t2.BuildFact()
    f2.Assert()

    crash.clp:
    (deftemplate t1 (slot s))
    (deftemplate t2 (slot s) (multislot ms))
    (deffunction fun (?c))

    (defrule r1
      (t1 (s ?i2))
      (t2 (s ?i1 & :(> (- ?i2 ?i1) 1)))
      =>
      )

    (defrule r2
      (t1 (s ?i))
      (t2 (s ?i))
      =>
      (fun nil))

    Here is bt from gdb:

    Program received signal SIGSEGV, Segmentation fault.
    [Switching to Thread 0xb7d5a8c0 (LWP 32698)]
    0xb7b513f1 in EnvRtnArgCount (theEnv=0x9168a20) at ./clipssrc/argacces.c:288
    288       for (argPtr = EvaluationData(theEnv)->CurrentExpression->argList;
    (gdb) bt
    #0  0xb7b513f1 in EnvRtnArgCount (theEnv=0x9168a20) at ./clipssrc/argacces.c:288
    #1  0xb7b51c9b in EnvArgCountCheck (theEnv=0x9168a20, functionName=0xb7bf6bd9 "deftemplate-slot-multip", countRelation=0, expectedNumber=2) at ./clipssrc/argacces.c:319
    #2  0xb7be5d5a in CheckDeftemplateAndSlotArguments (theEnv=0x0, functionName=0xb7bf6bd9 "deftemplate-slot-multip", theDeftemplate=0xbff3a34c) at ./clipssrc/tmpltfun.c:1469
    #3  0xb7be60dd in DeftemplateSlotMultiPFunction (theEnv=0x9168a20) at ./clipssrc/tmpltfun.c:1250
    #4  0xb7bce2aa in PrintAtom (theEnv=0x9168a20, logicalName=0xb7bebe3e "wtrace", type=49352, value=0x21) at ./clipssrc/prntutil.c:181
    #5  0xb7bb814d in PrintMultifield (theEnv=0x9168a20, fileid=0xb7bebe3e "wtrace", segment=0x912c0d8, begin=0, end=1, printParens=0) at ./clipssrc/multifld.c:385
    #6  0xb7be99e3 in PrintTemplateFact (theEnv=0x9168a20, logicalName=0xb7bebe3e "wtrace", theFact=0x912c008, seperateLines=0, ignoreDefaults=0) at ./clipssrc/tmpltutl.c:381
    #7  0xb7b83421 in PrintFact (theEnv=0x9168a20, logicalName=0xb7bebe3e "wtrace", factPtr=0x912c008, seperateLines=0, ignoreDefaults=0) at ./clipssrc/factmngr.c:369
    #8  0xb7b836ac in PrintFactWithIdentifier (theEnv=0x9168a20, logicalName=0xb7bebe3e "wtrace", factPtr=0x912c008) at ./clipssrc/factmngr.c:266
    #9  0xb7b83a35 in EnvAssert (theEnv=0x9168a20, vTheFact=0x912c008) at ./clipssrc/factmngr.c:735
    #10 0xb7b4e80f in g_assertFact (self=0x0, args=0xb7d4472c) at clipsmodule.c:2975
    #11 0x080cea39 in PyEval_EvalFrameEx ()
    #12 0x080cfbf5 in PyEval_EvalFrameEx ()
    #13 0x080d0345 in PyEval_EvalCodeEx ()
    #14 0x080d0557 in PyEval_EvalCode ()
    #15 0x080edf8f in PyRun_FileExFlags ()
    #16 0x080ee25a in PyRun_SimpleFileExFlags ()
    #17 0x080595e7 in Py_Main ()
    #18 0x08058962 in main ()

    I'm trying to debug the problem, but without luck so far. Any ideas?

    - Juha

     
    • Hi,

      I finally managed to debug the problem. The crash is caused because of the following:

      1) f2 = t2.BuildFact() ends up calling factmgr.c:EnvCreateFact, which fills the slots of the fact with empty values of type RVOID (factmgr.c:839). Also the multifield slot ms gets this value.
      2) f2.Assert() ends up calling factmgr.c:EnvAssert, which "Replaces invalid data types in the fact with the symbol nil" on lines 655 and 656. Again also the multifield slot gets this value.
      3) Since Watch All is on, EnvAssert calls PrintFactWithIdentifier, which ends up calling tmplutl.c:PrintTemplateFact.
      4) On tmplutl.c:377, PrintTemplateFact casts the value of the multifield slot to (struct multifield *). This is wrong since the value is not a multifield but symbol nil as set in step 2.

      The crash occurs if the memory near symbol nil contains some random data causing value->multifieldLength to contain something > 0 even though the field is empty. In the end prntutil.c:PrintAtom ends up dereferencing a pointer to a non-existent value causing the segfault.

      The problem is easy to fix by adding f2.AssignSlotDefaults() between BuildFact() and Assert(). I assume it replaces the symbol nil with an empty multifield value. Nevertheless, it would be nice if the documentation clearly stated that leaving multifield slots unassigned is dangerous. Also it is strange that PyCLIPS prohibits assigning empty lists to multifield slots on clipsmodule.c:1786. What is the reason for this?

      - Juha

       
      • Hi Juha,

        I logged on right now, and saw that you found a bug (or a couple of them) and also managed to debug it. I agree with you when you say that the creation of an empty multifield should be allowed - thus, the restriction at clipsmodule.c:1786 should go away: it remained because, as far as I can remember, it was not allowed in previous versions of CLIPS to create empty multifields. I'll remove it in 1.0.8.

        Coming to the actual problem, I'll see if I can create a patch for CLIPS 6.24 to avoid this problem: being Python an interpreted language, it shouldn't be a matter of documenting a possible problem: simply the problem must not exist, and whatever problem has to be reported with an exception. I'll start working on it, although patching CLIPS is not always healthy: patches have to be created specifically for each CLIPS version and sometimes, when you tune CLIPS code in one place, something wrong happens somewhere else! ;-)

        F.