Skip to content

calvinbeighle/lambda-c-fix

Repository files navigation

lambda.c bug fix

Source file is Justine Tunney's published BLC virtual machine: https://justine.lol/lambda/lambda.c. In the redbean #topics/lambda thread on 2026-04-19 she described it as

mostly works however I think it has a subtle bug I never got around to fixing.

This directory contains the upstream source plus the fix.

The bug

Abs() calls Bye() whenever it encounters an ABS instruction with an empty continuation stack (!contp). Bye() reads mem[ip+2] as an exit code:

void Bye(void) {
  int rc = mem[ip + 2];  // (λ 0) [exitcode]
  if (rc) Error(rc, "CONTINUATIONS EXHAUSTED");
  if (postdump && !rc) Dump(0, end, stderr);
  exit(0);
}

That comment is the assumption: ip is the exit ABS at ROM position 24, where mem[26]=0, so rc=0 and we exit cleanly.

In practice a well-formed program can run out of continuations at other ABS positions. The clearest case in bit mode: after the lazy input list bottoms out via NIL and the wrapper's bit-emission chain is exhausted, control returns to position 14 (the λ.0 wr0 wr1 ABS). At that point mem[14+2] = mem[16] is the span operand of the APP at ROM position 15, which is 4. rc = 4, not zero, so lambda.c reports CONTINUATIONS EXHAUSTED and exits with status 4. Tromp's uni and the AIT reference implementation both exit cleanly on the same input with the same output bytes.

Reproduction

Concatenate take1k.blc (an ASCII-bit BLC program from Tromp's AIT distribution) with a short input:

( cat /tmp/AIT/bin/take1k.blc; printf 'hello world!' ) | ./lambda

Before the fix:

010010110001

ERROR:	CONTINUATIONS EXHAUSTED
   ip:	14
  end:	211
 term:	put
[exit 4]

After the fix:

010010110001
[exit 0]

uni -b produces the same 12 output bytes and exits 0.

The fix

Drop the spurious exit-code reading. Treat empty-contp at any ABS as graceful program completion. This matches the behavior of Tromp's uni and the IOCCC reference. The exit-code mechanism only worked when the program reached one specific ROM position; in normal execution the wrapper never routes there, so removing it changes nothing for well-formed programs and removes the spurious error for programs that terminate elsewhere.

void Bye(void) {
  if (postdump) Dump(0, end, stderr);
  exit(0);
}

The full diff is in this directory; see lambda.c lines 168-185.

Build and test

make            # builds ./lambda
make test       # 4 regression tests including byte-for-byte parity vs uni

The fourth test requires /tmp/AIT/uni and /tmp/AIT/bin/take1k.blc from https://github.com/tromp/AIT; otherwise it is skipped.

Files

The C sources lambda.c, blc.h, vars.c, parse.c, getbit.c, needbit.c, error.c, print.c, debug.c, dump.c, fgetwc.c, fputwc.c, tromp.c, lam2bin.c, Blc.S are all from https://justine.lol/lambda/. Only lambda.c is modified. The change is the rewrite of Bye(). Everything else is verbatim.

reverse.Blc is from the same source, used in the test suite.

About

Bugfix for lambda.c Bye() at non-exit ABS positions

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors