arrrec-field-openarray.mod 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748
  1. MODULE ArrRecFieldOpenArray;
  2. (* Repro: an array field of an array-of-record element passed as an open
  3. array actual. The field's descriptor length word is never initialized
  4. in the static array-of-record data, so the callee reads length 0 and
  5. traps. V3-built compilers miscompile this; gm2-built ones happen to
  6. work. Expected: exit 0. Actual (buggy V3): SIGABRT (134).
  7. Status (2026-10-08): FIXED, both paths.
  8. Small record arrays (data <= 131072 bytes) are expanded per element
  9. by `QbeGen.ArrBodyItems`/`ArrData` (predicate `HasArrayField`, not
  10. just nested ARRAY OF ARRAY), so each inline array field's length word
  11. is in the static data. Larger ones (e.g. AST.arena, 262144 records)
  12. are kept compact and their element length words are set at run time
  13. by a generated init loop (`QbeGen.DeclRecTemplate` +
  14. `QbeGen.InitRecArray`, driven from `Lower`), which is what keeps the
  15. image inside the 4 MiB `QbeGen.sessBuf`.
  16. Regression: compiler/tests/t_arrrecfld.mod (small, exit 42) and
  17. compiler/tests/t_arrrecbig.mod (large, exit 42). *)
  18. TYPE
  19. ProcEnt = RECORD
  20. name : ARRAY [0..63] OF CHAR;
  21. END;
  22. VAR
  23. procs : ARRAY [0..3] OF ProcEnt;
  24. nProcs : CARDINAL;
  25. ExitCode: INTEGER;
  26. PROCEDURE CopyN (src: ARRAY OF CHAR; VAR dst: ARRAY OF CHAR);
  27. VAR i: CARDINAL;
  28. BEGIN
  29. i := 0;
  30. WHILE (i < 63) AND (src[i] # CHR(0)) DO dst[i] := src[i]; INC(i) END;
  31. dst[i] := CHR(0)
  32. END CopyN;
  33. PROCEDURE NoteProc (name: ARRAY OF CHAR);
  34. BEGIN
  35. CopyN(name, procs[nProcs].name);
  36. INC(nProcs)
  37. END NoteProc;
  38. BEGIN
  39. NoteProc("hello");
  40. IF procs[0].name[0] = "h" THEN ExitCode := 0 ELSE ExitCode := 1 END
  41. END ArrRecFieldOpenArray.