Finding
pad_left and pad_right loop until the string reaches width, growing it by the pad character each pass. An empty pad character never grows it — so the loop never terminates.
lib/string.eigs:33:
# pad_left of [string, width, pad_char] -> string
define pad_left(s, width, ch) as:
loop while (len of s) < width:
s is ch + s
return s
pad_right (:40) has the same shape.
Reproduction
load_file of "lib/string.eigs"
print of pad_left of ["x", 5, ""]
$ timeout 5 ./src/eigenscript probe.eigs
Terminated <- never returns
Control: a non-empty pad char works normally. Only "" hangs.
Invariant violated
A stdlib string helper must terminate on every input. docs/STDLIB.md documents pad_left of [string, width, char] as "Left-pad to width" with no domain restriction on char, so "" is an input a caller can reach — trivially, by passing a variable that happens to be empty.
This is worse than a wrong answer: it's an unkillable spin with no output and no diagnostic. A "" arriving from user input, a config file, or a char_at that fell off the end takes the whole program down with no clue why.
Fix
Guard the degenerate pad and decide the contract deliberately:
define pad_left(s, width, ch) as:
if (len of ch) == 0:
return s # or raise — but never spin
loop while (len of s) < width:
s is ch + s
return s
Returning s unchanged is the honest reading of "pad with nothing". Raising is also defensible. Either is fine; spinning is not. Whatever is chosen, pin it in docs/STDLIB.md.
Worth also considering a multi-character pad: pad_left of ["x", 5, "ab"] currently overshoots to width 7, which is unspecified today. Same guard site.
Test to add
pad_left of ["x", 5, ""] and pad_right of ["x", 5, ""] return (rather than hang), asserted under the suite's normal runner so a regression shows up as a timeout rather than a silent hang.
Found by Grok Build in a delegated read-only stdlib review; reproduced and verified independently before filing.
Finding
pad_leftandpad_rightloop until the string reacheswidth, growing it by the pad character each pass. An empty pad character never grows it — so the loop never terminates.lib/string.eigs:33:pad_right(:40) has the same shape.Reproduction
Control: a non-empty pad char works normally. Only
""hangs.Invariant violated
A stdlib string helper must terminate on every input.
docs/STDLIB.mddocumentspad_left of [string, width, char]as "Left-pad to width" with no domain restriction onchar, so""is an input a caller can reach — trivially, by passing a variable that happens to be empty.This is worse than a wrong answer: it's an unkillable spin with no output and no diagnostic. A
""arriving from user input, a config file, or achar_atthat fell off the end takes the whole program down with no clue why.Fix
Guard the degenerate pad and decide the contract deliberately:
Returning
sunchanged is the honest reading of "pad with nothing". Raising is also defensible. Either is fine; spinning is not. Whatever is chosen, pin it indocs/STDLIB.md.Worth also considering a multi-character pad:
pad_left of ["x", 5, "ab"]currently overshoots to width 7, which is unspecified today. Same guard site.Test to add
pad_left of ["x", 5, ""]andpad_right of ["x", 5, ""]return (rather than hang), asserted under the suite's normal runner so a regression shows up as a timeout rather than a silent hang.Found by Grok Build in a delegated read-only stdlib review; reproduced and verified independently before filing.