Traps.GetName Misses Last Procedure

Report any suspected bugs that you find
Locked
gray
Posts: 115
Joined: Tue Feb 12, 2019 2:59 am
Location: Mauritius

Traps.GetName Misses Last Procedure

Post by gray » Mon Dec 11, 2023 11:44 pm

I have been working on catching run-time errors in module bodies during the start-up of programs. To test, I have injected artificial errors, such as 'ASSERT(FALSE)', and the first obvious place was Main.Init, right at the end, after module Traps and the Terminal output have been initialised. Which resulted in wrong stack traces. The addresses and line numbers reported were correct, but not the last module and procedure names.

I have isolated the problem into the following (hopefully minimal) test code to use with Astrobe's stock libraries.

Code: Select all

MODULE M0;
  PROCEDURE init;
  BEGIN
    ASSERT(FALSE)
  END init;
BEGIN
  init
END M0.

MODULE M1;
  IMPORT Main, M0;
END M1.
This produces:

Code: Select all

Assertion #0
M0.init  @0800251AH, Line: 5
M1.M1    @08002522H, Line: 9
As said, addresses and line numbers are correct, but the last item should read 'M0..init'. Hence, the stack trace is created correctly, but the name lookup via 'Traps.GetName' fails.

I think I have isolated the issue with 'Traps.GetName', which looks up the module and procedure names in the resource section of the program code. However, my analysis is solely based on reading the code in Traps as well as module ResData, and the resource section of the assembly listing of my test programs. I may have missed edge cases due to my limited understanding of the structure of the resource data.

This section of 'Traps.GetName' misses the last procedure entry of a module.

Code: Select all

(* ... *)
 WHILE i < nItems DO
    ResData.GetInt(r, index, recType);
    ResData.GetInt(r, index + 5, addr);
    IF (recType = 0) THEN
      modIdx := i
    ELSIF (addr > target) THEN
      foundIdx := i - 1;
      i := nItems
    END;
    index := index + itemSize;
    INC(i)
  END;
  (* ... *)
The address comparison only happens with procedure entries ('recType' > 0), not the modules ('recType' = 0), so when 'addr > target' becomes true when looking for a module's last procedure entry, 'modIdx := i' has already been set to the subsequent module entry, and 'foundIdx := i - 1;' will point right back at this module entry, hence 'M1.M1'.

Here's a proposal for a correction (with the above caveats):

Code: Select all

  (* ... *)
  WHILE i < nItems DO
    ResData.GetInt(r, index, recType);
    ResData.GetInt(r, index + 5, addr);
    IF addr > target THEN
      foundIdx := i - 1;
      i := nItems
    ELSIF recType = 0 THEN
      modIdx := i
    END;
    index := index + itemSize;
    INC(i)
  END;
  (* ... *)
Here we do the address comparison also for module entries, and so we'll catch the last procedure entry, which is right before the subsequent module entry in the resource section.

Now wet get the correct:

Code: Select all

Assertion #0
M0.init  @0800251AH, Line: 5
M0..init @08002522H, Line: 9

Locked