larcenists / larceny

Larceny Scheme implementation
Other
203 stars 32 forks source link

ARM uncaught exception when (/ 7 0) #757

Closed KenDickey closed 8 years ago

KenDickey commented 8 years ago

larceny Larceny v0.99a1 (alpha test) (May 12 2016 14:38:31, precise:Linux:split) larceny.heap, built on Thu May 12 14:40:09 PDT 2016

(/ 7 0) Larceny Panic: handle_sigfpe() returned.

lars-t-hansen commented 8 years ago

Indeed, this is true even in v0.98. We configure the build with EXPLICIT_DIVZ_CHECK and the test at the start of mc_div() (generated from arithmetic.mac) therefore invokes mc_exception() as it should, but that call returns and we fall into the division anyway, generating the fault. So something is wonky with the exception handling machinery (and the test suite needs another test :)

WillClinger commented 8 years ago

Changeset 10eb0f9c2bc42d590a9d8571175170764af1a6f2 added tests that should help to debug this.

WillClinger commented 8 years ago

The Fence/ARM version contains nine calls to the C function mc_exception. Four of those nine calls are in the millicode procedures fmc_global_exception, fmc_invoke_exception, fmc_global_invoke_exception, and fmc_argc_exception; those four calls are working fine.

The other five, all within src/Rts/Shared/arithmetic.c, call mc_exception in response to a divide-by-zero in the code for /, quotient, and remainder.

The Fence/ARM version of mc_exception always returns. That's okay when it's returning to Scheme code, because mc_exception calls mc_scheme_callout to set up the registers appropriately for a return to Scheme code.

That's not okay when mc_exception is returning to the C code in arithmetic.c. We need a longjmp in there somewhere to avoid returning to code that will divide by zero.

The IAssassin version of mc_scheme_callout performs a longjmp if its continuation argument k is zero. In IAssassin, I believe that argument will be zero if and only if mc_scheme_callout was called from mc_exception, so k is doing double duty as a flag to tell mc_scheme_callout whether it needs to do a longjmp.

The Fence/ARM version never does a longjmp, and it doesn't look as though the k hack will be easy to restore because the Fence/ARM version always passes zero for that argument when calling from Scheme to millicode, relying on availability of the return address in the globals area.

So I know what the problem is, but I haven't yet decided on the best way to fix it. Changing the Fence/ARM version to pass a return address would make it more like IAssassin, but that's just a hack and I'm nervous about the number of changes that would be required. Adding an extra argument to mc_scheme_callout to tell it whether to do a longjmp would be less of a hack, but it would require changes to code shared by all versions of Larceny, which makes me even more nervous.

WillClinger commented 8 years ago

Fixed by changeset 5d76120555c7fe2bbecd55920a3aa90bb3415960