Hi

I wanted to learn APL and wanted to have a local wasm playground to do some 
exercises, so I asked Opus to compile gnu-apl-2.0 core (libapl) to wasm, in the 
process it found two issues:

1) apl_exec() not catching Command::process_line() which crashes the caller for 
top level error like `←3`, example code to reproduce from python:

```
import ctypes, sys
lib = ctypes.CDLL(sys.argv[1])
lib.init_libapl.argtypes = [ctypes.c_char_p, ctypes.c_int]
lib.apl_exec.argtypes    = [ctypes.c_char_p]
lib.init_libapl(b"apl", 0)
print(">>> apl_exec('2+2')"); sys.stdout.flush()
lib.apl_exec("2+2".encode("utf-8")); sys.stdout.flush()
print(">>> apl_exec('→3')  (a branch at the top level)"); sys.stdout.flush()
lib.apl_exec("→3".encode("utf-8")); sys.stdout.flush()   # →3
print(">>> PYTHON SURVIVED →3")   # only reached if apl_exec is exception-safe
```

It doesnt happen from the apl binary because it goes through other codepath.

The fix it did was basically wrapping apl_exec's process_line() in libapl.cc in 
try catch:
```
   try { Command::process_line(line_ucs, 0); }
   catch (Error & err)
      { if (err.get_print_loc() == 0) err.print_em(UERR, LOC);
        return LIBAPL_error(err.get_error_code()); }
   catch (...) { return LAE_UNKNOWN_ERROR; }
```

2) use after destruction ub

I dont know enough WASM to know if it is bullshitting me, but, it was 
corrupting the vtable and there were deterministic random crashes e.g. ÷2 works 
but  ÷3 crashes ÷4 works and so on.

The fix it did was:

```
do_scalar_B / do_scalar_AB end each job with an explicit destructor call
(job->~PJob_scalar_B()) on Thread_context::get_master().joblist_B's persistent
`current_job` member. The next call's next_job() then does
`current_job = jobs.back()` — copy-assignment INTO an object whose lifetime has
already ended. On native x86 this is benign (the Value_P members were just
cleared), but under WASM's typed call_indirect it corrupts a Cell vtable
pointer after a couple of reuses, trapping the 3rd monadic scalar call with
"null function or function signature mismatch".

Replacing the explicit destructor with assignment of a fresh empty job
releases ownership identically (PJob's destructor only clears its Value_P
members) while leaving `current_job` a valid, assignable object.
--- apl-2.0/src/ScalarFunction.cc
+++ apl-2.0/src/ScalarFunction.cc
@@ -191,7 +191,7 @@
                         ec = (cell_B.*fun)(&cell_Z);
                         if (ec != E_NO_ERROR)
                            {
-                             job_B->~PJob_scalar_B();   // ownership of B, and 
Z
+                             *job_B = PJob_scalar_B();   // ownership of B, 
and Z
                              job_B = 0;
                              return Value_P();
                            }
@@ -200,7 +200,7 @@
                  }
            }
         job_B->value_Z->check_value(LOC);
-        job_B->~PJob_scalar_B();   // give up ownership of B, and Z.
+        *job_B = PJob_scalar_B();   // give up ownership of B, and Z.
         job_B = 0;
       }

@@ -503,7 +503,7 @@
                         if (ec != E_NO_ERROR)
                            {
                              // give up the ownership of A, B, Z.
-                             job_AB->~PJob_scalar_AB();
+                             *job_AB = PJob_scalar_AB();
                              job_AB = 0;
                              return Value_P();
                            }
@@ -512,7 +512,7 @@
                  }
            }
         job_AB->value_Z->check_value(LOC);
-        job_AB->~PJob_scalar_AB();   // give up ownership of A, B, and Z.
+        *job_AB = PJob_scalar_AB();   // give up ownership of A, B, and Z.
         job_AB = 0;
       }
```


I dont know the code enough if this is the best way to fix this, or maybe just 
call job_B->value_B.reset();  job_B->value_Z.reset();.. 

Anyway, now the playground works and I can learn :) https://punkx.org/apl/ if 
you want to try it out. or build it yourself 
https://github.com/jackdoe/gnu-apl-wasm

Thank you for the hard work, and sorry if the bug report was not useful.
I am really not sure if I should've reported it at all given that it is AI 
generated, but I did test it and it does fix the WASM code.

PS: If you want to read its tokens: 
https://github.com/jackdoe/gnu-apl-wasm/tree/master/patches/bug-reports

  • gnu apl wasm: ... borislav
    • Re: gnu a... Dr . Jürgen Sauermann via Bugs and suggestions for GNU APL

Reply via email to