smlnj / legacy

This project is the old version of Standard ML of New Jersey that continues to support older systems (e.g., 32-bit machines).
BSD 3-Clause "New" or "Revised" License
25 stars 10 forks source link

PackWord64Big.update is nondeterministic #299

Open Skyb0rg007 opened 3 months ago

Skyb0rg007 commented 3 months ago

Version

110.99.4 (Latest)

Operating System

OS Version

Ubuntu 22.04.4 LTS on Windows 10 x86_64

Processor

System Component

Basis Library

Severity

Major

Description

Repeated calls to PackWord64Real.update from outside the current module sometimes return different results.

Transcript

See transcript in the README here: https://github.com/Skyb0rg007/smlnj-bug

Expected Behavior

Execution of PackWord64Big.update is deterministic.

Steps to Reproduce

See files here: https://github.com/Skyb0rg007/smlnj-bug

Additional Information

This bug does not seem to be the issue with PackWord64[Big,Little].update being swapped, since either way they should not be nondeterministic.

Email address

skyler.soss@gmail.com

JohnReppy commented 3 months ago

After some experimentation, here are a couple of things that I have discovered.

  1. I have verified that the problem is not in the reading of the value from the byte array. I made the array a global in the Conv structure and then print its contents when the error is detected. Its contents matches that of w'.

  2. This bug has nothing to do with reals; we can replace the conversion to reals in the Conv structure with the following identity function and get the same bug.

    fun w2w w = (
      PackWord64Big.update (arr, 0, w);
      PackWord64Big.subArr (arr, 0))

Given the non-deterministic nature of the bug, it very likely is related to garbage collection. I suspect that the word value is not being correctly preserved across the garbage collection.

To test this idea, I am using a smaller example function, which will have a GC test on entry and needs to preserve the value of its argument (w) across the collection.

fun f (w : Word64.word) = ref(0w42 * w);