Menu ▾ ▴

#37 6.4.2 `fetch` lost a subtopic whose level overflowed an int

CLIPS
open
nobody
None
5
2 days ago
2 days ago
Batch Job 1
No

What happened. An external text file whose topic level did not fit an int loaded without complaint, and the topic went into the tree at the wrong place. get-region could not reach it.

Two files, alike except for the second level number:

0MBEGIN-ENTRY-ROOT          0MBEGIN-ENTRY-ROOT
 --  Root Text  --           --  Root Text  --
END-ENTRY                   END-ENTRY
2IBEGIN-ENTRY-SUB           2147483648IBEGIN-ENTRY-SUB
 --  Sub Text  --            --  Sub Text  --
END-ENTRY                   END-ENTRY
(printout t "fetch " (fetch "levels.lis") crlf)
(printout t "root [" (get-region "levels.lis" ROOT) "]" crlf)
(printout t "sub [" (get-region "levels.lis" SUB) "]" crlf)

printed, against the left-hand file,

fetch 2
root [ --  Root Text  --
]
sub [ --  Sub Text  --
]

and against the right-hand file,

fetch 2
root [ --  Root Text  --
]
sub []

Both files loaded two entries and reported no error. In the second, SUB was not under ROOT.

Why it is a fix and not a preference. Section 13.17.1 of the Basic Programming Guide says that "the first parameter, <level-num>, is the level of the hierarchical tree to which the entry belongs", that "the lower the number, the closer to the root level the topic is", and that "subtopics are indicated by making the level number of the current topic larger than the previous entry (which is the parent)". 2147483648 is larger than 0, so SUB belongs under ROOT. It was not there.

What it was instead is what the overflow produced. 2147483648 is not an int; on this host the accumulation arrived at −2147483648, which is lower than 0, and the manual's next sentence covers that case: "entering a number less than that of the previous topic will cause the tree to be searched upwards until a level number is found which is less than the current one" — so SUB became a root of its own.

Where it came from. ParseLine in textpro.c accumulated the level in an int with no bound:

    int theLevel = 0;
    ...
          theLevel = (theLevel * 10) + (theChar - '0');
          digitFound = true;

AllocateEntryNode stores the result in enode->level, which is an int, and AttachLeaf compares it against the previous entry's. TextLookupFetch reads each line with fgets into a 256-byte buffer, so 2147483648M BEGIN-ENTRY-x fits and reaches the accumulation.

The change. theLevel becomes a long long and the accumulation stops once the magnitude would pass 2147483648, which is the magnitude of INT_MIN and so the largest either sign can reach. After the sign is applied, a level outside INT_MIN..INT_MAX returns TP_INVALID_DELIMITER_STRING — the return AllocateEntryNode already reports as

[TEXTPRO5] Line 4 : Invalid delimiter string.

before calling TextLookupToss on the file. fetch then returns FALSE, which section 13.17.2 documents for a file that could not be loaded.

The bound is on the type and is exact in both directions. −2147483648 is a level the field holds and is kept; −2147483649 is not and is rejected.

What was checked. The file with 2147483648 and the file with −2147483649: both report TEXTPRO5 naming line 4, fetch returns FALSE for each, and neither ROOT nor SUB is in the lookup table afterwards. The file with −2147483648 loads its two entries.

Then the levels that must still work: a level of 2 and a level of 2147483647, the largest int. Both load two entries, and in both the level 0 menu is reachable and its subtopic is reachable from it.

Then the whole example of section 13.17.1 — seven entries over levels −1, 0, 1 and 2, including the −1 that makes ROOT3 the leftmost root — and the six print-region calls of section 13.17.3 against it. fetch returns 7, each call reaches the entry the manual says it reaches and returns TRUE, and toss unloads the file.

Present in 7.0? Not checked.

9 Attachments

Discussion

Anonymous
Anonymous

Add attachments
Cancel