Zulip Chat Archive

Stream: lean4

Topic: Nondeterminism during compilation


Henrik Böving (Mar 30 2022 at 23:38):

In my mathlib4 fork to port SlimCheck to Lean 4 I'm experiencing some weird issues, if I comment the following line out: https://github.com/hargoniX/mathlib4/blob/slim_check/Mathlib/Testing/SlimCheck/Testable.lean#L374 the LSP will sometimes hang on this and sometimes produce proper output (I reload the file with C-c C-d in emacs to achieve this effect), example:
successful run: image.png
hanging run: image.png
Lake and thus the compiler are rather consistently convinced this code is broken image.png so my question would be...what on earth is going on?

Mario Carneiro (Mar 30 2022 at 23:47):

It sounds like your random number generator is nondeterministic

Mario Carneiro (Mar 30 2022 at 23:48):

if the state is not being stored in the environment then this is expected

Mario Carneiro (Mar 30 2022 at 23:49):

that is, every time the command is elaborated you will get new random numbers

Henrik Böving (Mar 30 2022 at 23:52):

Pinning the randomSeed does indeed help the consistency so I guess I'll start to look around for where im doing too much recursion then

Mario Carneiro (Mar 30 2022 at 23:53):

recursion?

Henrik Böving (Mar 30 2022 at 23:53):

Well its complaining that there might be a stackoverflow during execution no?

Mario Carneiro (Mar 30 2022 at 23:54):

oh I see

Henrik Böving (Mar 30 2022 at 23:55):

I can in fact already pin point it to a certain instance from above that is misbehaving so I'll keep digging there, thanks!

Henrik Böving (Mar 31 2022 at 00:09):

Huh, I did include one of the failing seeds (Testable.check (∀ (x y z a : Nat) (h1 : 3 < x) (h2 : 3 < y), x - y = y - x) { Configuration.verbose with randomSeed := some 1000}) in a binary and it segfaulted

Henrik Böving (Mar 31 2022 at 00:09):

after running for a little at least

Henrik Böving (Mar 31 2022 at 00:10):

How does one debug segfaults in Lean generated code the best way?

Leonardo de Moura (Mar 31 2022 at 00:11):

I use gdb and then bt to print the stack trace.

Leonardo de Moura (Mar 31 2022 at 00:12):

The function names are mangled, but readable.

Henrik Böving (Mar 31 2022 at 00:13):

(gdb) bt
#0  0x00000000029a4d74 in lean_apply_1 ()
#1  0x00000000006ea373 in l_SlimCheck_TestResult_combine___rarg ()
#2  0x00000000006eb7cf in l_SlimCheck_TestResult_imp___rarg ()
#3  0x00000000006ebb9c in l_SlimCheck_TestResult_addInfo___rarg ()
#4  0x0000000000667feb in l_SlimCheck_Testable_runSuiteAux___at_main___spec__4___lambda__5 ()
#5  0x000000000066881e in l_SlimCheck_Testable_runSuiteAux___at_main___spec__4___lambda__6 ()
#6  0x0000000000668dd1 in l_SlimCheck_Testable_runSuiteAux___at_main___spec__4___lambda__7 ()
#7  0x000000000066b2a7 in l_SlimCheck_Testable_runSuiteAux___at_main___spec__7___lambda__2 ()
#8  0x000000000066bac9 in l_SlimCheck_Testable_runSuiteAux___at_main___spec__7___lambda__3 ()
#9  0x00000000029a519c in lean_apply_1 ()
#10 0x00000000006fbbc1 in l_SlimCheck_retry___rarg ()
#11 0x000000000066bbb3 in l_SlimCheck_Testable_runSuiteAux___at_main___spec__7___lambda__4 ()
#12 0x000000000066c21d in l_SlimCheck_Testable_runSuiteAux___at_main___spec__7 ()
#13 0x000000000066be01 in l_SlimCheck_Testable_runSuiteAux___at_main___spec__7___lambda__4 ()
#14 0x000000000066c21d in l_SlimCheck_Testable_runSuiteAux___at_main___spec__7 ()
#15 0x000000000066be01 in l_SlimCheck_Testable_runSuiteAux___at_main___spec__7___lambda__4 ()
#16 0x000000000066c21d in l_SlimCheck_Testable_runSuiteAux___at_main___spec__7 ()
#17 0x000000000066be01 in l_SlimCheck_Testable_runSuiteAux___at_main___spec__7___lambda__4 ()
#18 0x000000000066c21d in l_SlimCheck_Testable_runSuiteAux___at_main___spec__7 ()
#19 0x000000000066be01 in l_SlimCheck_Testable_runSuiteAux___at_main___spec__7___lambda__4 ()
#20 0x000000000066c21d in l_SlimCheck_Testable_runSuiteAux___at_main___spec__7 ()
#21 0x000000000066be01 in l_SlimCheck_Testable_runSuiteAux___at_main___spec__7___lambda__4 ()
#22 0x000000000066c21d in l_SlimCheck_Testable_runSuiteAux___at_main___spec__7 ()
#23 0x000000000066c300 in l_SlimCheck_Testable_runSuite___at_main___spec__6 ()
#24 0x00000000029a4e80 in lean_apply_1 ()
#25 0x000000000077cf2e in l_IO_runRandWith___rarg ()
#26 0x000000000066c417 in l_SlimCheck_Testable_checkIO___at_main___spec__2 ()
#27 0x000000000066c471 in l_SlimCheck_Testable_check___at_main___spec__1 ()
#28 0x000000000066cb75 in _lean_main ()
#29 0x000000000066d77e in main ()

So apparently: https://github.com/hargoniX/mathlib4/blob/slim_check/Mathlib/Testing/SlimCheck/Testable.lean#L55 this one is evil...but only for certain inputs of course?

Leonardo de Moura (Mar 31 2022 at 00:14):

For "panic" messages, I use LEAN_ABORT_ON_PANIC=1 gdb <path-to-build-dir>/stage1/bin/lean, run file.lean, bt.

Henrik Böving (Mar 31 2022 at 00:18):

(gdb) list
693     {
694     lean_object* x_9; lean_object* x_10; lean_object* x_11;
695     x_9 = lean_ctor_get(x_2, 0);
696     lean_inc(x_9);
697     lean_dec(x_2);
698     x_10 = lean_apply_1(x_5, x_9);
699     x_11 = lean_alloc_ctor(1, 1, 0);
700     lean_ctor_set(x_11, 0, x_10);
701     return x_11;
702     }
(gdb) info locals
x_9 = 0x1
x_10 = 0x7ffff7bd80c8
x_11 = 0x7fffffffb580
x_5 = 0x1
x_6 = 1 '\001'
(gdb)

I'm certainly not well versed with how lean does stuff in C under the hood but applying 0x1 to 0x1 does not sound like something that should be happening right? (line 698 is the line that is the exit point according to a build with debug info)

Leonardo de Moura (Mar 31 2022 at 00:21):

combine looks harmless. Try to take a look at the other functions on the stack. dbg_trace is also helpful in this kind situation.

Leonardo de Moura (Mar 31 2022 at 00:22):

I'm certainly not well versed with how lean does stuff in C under the hood but applying 0x1 to 0x1 does not sound like something that should be happening right?

Yes, the memory looks corrupted at this point.

Henrik Böving (Mar 31 2022 at 00:27):

Here's the trace with debug info so one can see the arguments...it seems like this 0x1 value is first introduced in the call from #8 to #7?

#0  0x00000000029922b4 in lean_apply_1 ()
#1  0x00000000006e4a53 in l_SlimCheck_TestResult_combine___rarg (x_1=0x7ffff7bd80c8, x_2=0x7ffff7bd8118) at ./../mathlib4/./build/ir/Mathlib/Testing/SlimCheck/Testable.c:698
#2  0x00000000006e5dcf in l_SlimCheck_TestResult_imp___rarg (x_1=0x7ffff7bd8108, x_2=0x7ffff7bd80c8) at ./../mathlib4/./build/ir/Mathlib/Testing/SlimCheck/Testable.c:1166
#3  0x00000000006e619c in l_SlimCheck_TestResult_addInfo___rarg (x_1=0x7ffff7bdf178, x_2=0x1, x_3=0x7ffff7bd8108, x_4=0x7ffff7bd80c8) at ./../mathlib4/./build/ir/Mathlib/Testing/SlimCheck/Testable.c:1283
#4  0x0000000000664e9b in l_SlimCheck_Testable_runSuiteAux___at_main___spec__4___lambda__5 (x_1=1 '\001', x_2=0x7ffff7bef268, x_3=0xb, x_4=0xb, x_5=0x1, x_6=0xb, x_7=0x7ffff7a6c5f0) at ./build/ir/Main.c:921
#5  0x00000000006656ce in l_SlimCheck_Testable_runSuiteAux___at_main___spec__4___lambda__6 (x_1=1 '\001', x_2=0x7ffff7bef268, x_3=0xb, x_4=0xb, x_5=0x1, x_6=0xb, x_7=0x7ffff7a6c5f0) at ./build/ir/Main.c:1093
#6  0x0000000000665c81 in l_SlimCheck_Testable_runSuiteAux___at_main___spec__4___lambda__7 (x_1=0x7ffff7bef238, x_2=0xb, x_3=0x7ffff7bef268, x_4=0x7ffff7a6c5d8, x_5=0xb, x_6=0x1, x_7=0xb, x_8=0x7ffff7a6c5f0) at ./build/ir/Main.c:1234
#7  0x0000000000668157 in l_SlimCheck_Testable_runSuiteAux___at_main___spec__7___lambda__2 (x_1=0x7ffff7bef238, x_2=0xb, x_3=0x7ffff7bef268, x_4=0x1, x_5=0xb, x_6=0x7ffff7a6c5f0) at ./build/ir/Main.c:2004
#8  0x0000000000668979 in l_SlimCheck_Testable_runSuiteAux___at_main___spec__7___lambda__3 (x_1=0x7ffff7bef238, x_2=0xb, x_3=0x7ffff7bef268, x_4=0x7ffff7a6c5f0) at ./build/ir/Main.c:2159
#9  0x00000000029926dc in lean_apply_1 ()
#10 0x00000000006f60b1 in l_SlimCheck_retry___rarg (x_1=0x7ffff7bef208, x_2=0x7ffff7bef268, x_3=0x7, x_4=0x7ffff7a6c5f0) at ./../mathlib4/./build/ir/Mathlib/Testing/SlimCheck/Testable.c:7552
#11 0x0000000000668a63 in l_SlimCheck_Testable_runSuiteAux___at_main___spec__7___lambda__4 (x_1=0x7ffff7bef238, x_2=0xb, x_3=0x7ffff7bef268, x_4=0x7ffff7bd80d8, x_5=0xbd, x_6=0x1, x_7=0x7ffff7a6c5f0) at ./build/ir/Main.c:2176
#12 0x00000000006690cd in l_SlimCheck_Testable_runSuiteAux___at_main___spec__7 (x_1=0x7ffff7bef238, x_2=0x7ffff7bef268, x_3=0x7ffff7bd80d8, x_4=0xbf, x_5=0x7ffff7a6c5f0) at ./build/ir/Main.c:2324
#13 0x0000000000668cb1 in l_SlimCheck_Testable_runSuiteAux___at_main___spec__7___lambda__4 (x_1=0x7ffff7bef238, x_2=0x9, x_3=0x7ffff7bef268, x_4=0x7ffff7bd80d8, x_5=0xbf, x_6=0x1, x_7=0x7ffff7a6c5f0) at ./build/ir/Main.c:2235
#14 0x00000000006690cd in l_SlimCheck_Testable_runSuiteAux___at_main___spec__7 (x_1=0x7ffff7bef238, x_2=0x7ffff7bef268, x_3=0x7ffff7bd80d8, x_4=0xc1, x_5=0x7ffff7a6c5f0) at ./build/ir/Main.c:2324
#15 0x0000000000668cb1 in l_SlimCheck_Testable_runSuiteAux___at_main___spec__7___lambda__4 (x_1=0x7ffff7bef238, x_2=0x7, x_3=0x7ffff7bef268, x_4=0x7ffff7bd80d8, x_5=0xc1, x_6=0x1, x_7=0x7ffff7a6c5f0) at ./build/ir/Main.c:2235
#16 0x00000000006690cd in l_SlimCheck_Testable_runSuiteAux___at_main___spec__7 (x_1=0x7ffff7bef238, x_2=0x7ffff7bef268, x_3=0x7ffff7bd80d8, x_4=0xc3, x_5=0x7ffff7a6c5f0) at ./build/ir/Main.c:2324
#17 0x0000000000668cb1 in l_SlimCheck_Testable_runSuiteAux___at_main___spec__7___lambda__4 (x_1=0x7ffff7bef238, x_2=0x5, x_3=0x7ffff7bef268, x_4=0x7ffff7bd80d8, x_5=0xc3, x_6=0x1, x_7=0x7ffff7a6c5f0) at ./build/ir/Main.c:2235
#18 0x00000000006690cd in l_SlimCheck_Testable_runSuiteAux___at_main___spec__7 (x_1=0x7ffff7bef238, x_2=0x7ffff7bef268, x_3=0x7ffff7bd80d8, x_4=0xc5, x_5=0x7ffff7a6c5f0) at ./build/ir/Main.c:2324
#19 0x0000000000668cb1 in l_SlimCheck_Testable_runSuiteAux___at_main___spec__7___lambda__4 (x_1=0x7ffff7bef238, x_2=0x3, x_3=0x7ffff7bef268, x_4=0x7ffff7bd80d8, x_5=0xc5, x_6=0x1, x_7=0x7ffff7a6c5f0) at ./build/ir/Main.c:2235
#20 0x00000000006690cd in l_SlimCheck_Testable_runSuiteAux___at_main___spec__7 (x_1=0x7ffff7bef238, x_2=0x7ffff7bef268, x_3=0x7ffff7bd80d8, x_4=0xc7, x_5=0x7ffff7a6c5f0) at ./build/ir/Main.c:2324
#21 0x0000000000668cb1 in l_SlimCheck_Testable_runSuiteAux___at_main___spec__7___lambda__4 (x_1=0x7ffff7bef238, x_2=0x1, x_3=0x7ffff7bef268, x_4=0x7ffff7bd80f8, x_5=0xc7, x_6=0x1, x_7=0x7ffff7a6c5f0) at ./build/ir/Main.c:2235
#22 0x00000000006690cd in l_SlimCheck_Testable_runSuiteAux___at_main___spec__7 (x_1=0x7ffff7bef238, x_2=0x7ffff7bef268, x_3=0x7ffff7bd80f8, x_4=0xc9, x_5=0x7ffff7a6c5f0) at ./build/ir/Main.c:2324
#23 0x00000000006691b0 in l_SlimCheck_Testable_runSuite___at_main___spec__6 (x_1=0x7ffff7bef238, x_2=0x7ffff7bef268, x_3=0x7ffff7a6c5f0) at ./build/ir/Main.c:2349
#24 0x00000000029923c0 in lean_apply_1 ()
#25 0x0000000000771d9e in l_IO_runRandWith___rarg (x_1=0x7d1, x_2=0x7ffff7bf1000, x_3=0x1) at ./../mathlib4/./build/ir/Mathlib/Control/Random.c:835
#26 0x00000000006692c7 in l_SlimCheck_Testable_checkIO___at_main___spec__2 (x_1=0x7ffff7bef238, x_2=0x7ffff7bef268, x_3=0x1) at ./build/ir/Main.c:2377
#27 0x0000000000669321 in l_SlimCheck_Testable_check___at_main___spec__1 (x_1=0x7ffff7bef238, x_2=0x7ffff7bef268, x_3=0x1) at ./build/ir/Main.c:2420
#28 0x00000000006699e5 in _lean_main (x_1=0x1) at ./build/ir/Main.c:2673
#29 0x000000000066a5ee in main (argc=1, argv=0x7fffffffd638) at ./build/ir/Main.c:2948

so that might be the culprit?

Henrik Böving (Mar 31 2022 at 00:33):

Either way I'm off to bed, if someone wants to investigate further there is a reproducible example over here: https://github.com/hargoniX/lean4-c-bug, maybe I will just wake up and it will be magically fixed :sparkles:

Leonardo de Moura (Mar 31 2022 at 01:10):

@Henrik Böving The problem is that PSum can store data and proofs. Recall that proofs are erased by the code generator. This is where the 0x1 is coming from. An easy fix is to modify apply_* to check its arguments have been erased, but this would impact the performance of all Lean programs that never need this feature. A better fix is to have two sets of apply_* functions: the current one; and another for places that can take proofs and data (e.g., your combine function). We don't have cycles for this kind of modification right now. So, could you please rewrite your code and replace PSum with a type such as

inductive Semidecidable (p : Prop) where
  | isTrue (h : p)
  | unknown

This one would be making clear to Lean that the argument stored there is always a proof. You could also try to rewrite combine as

def combine {p q :  Prop} : PSum Unit (p  q)  PSum Unit p  PSum Unit q
| PSum.inr f, PSum.inr proof => PSum.inr $ f proof
| _, _ => PSum.inl ()

In your current implementation, p and q can be any type.
I did not read your code carefully. So, you might have other places where the code can be used to process proofs and data.
BTW, I think it is worth replacing PSum because it will make the code more readable.

Leonardo de Moura (Mar 31 2022 at 01:20):

Here is a mwe for this issue

def combine : PSum Unit (p  q)  PSum Unit p  PSum Unit q
  | PSum.inr f, PSum.inr proof => PSum.inr $ f proof
  | _, _ => PSum.inl ()

def tst : String :=
  let f : PSum Unit (True  True) := .inr id
  let v : PSum Unit True := .inr .intro
  match combine f v with
  | .inr _ => "inr"
  | .inl _ => "inl"

#evat tst

The crash goes away if add {p q : Prop} to combine. Example:

def combine {p q : Prop} : PSum Unit (p  q)  PSum Unit p  PSum Unit q
  | PSum.inr f, PSum.inr proof => PSum.inr $ f proof
  | _, _ => PSum.inl ()

Leonardo de Moura (Mar 31 2022 at 01:28):

Added an issue for this https://github.com/leanprover/lean4/issues/1087

Leonardo de Moura (Mar 31 2022 at 01:50):

I pushed the "easy" fix for the issue above. I am hoping the performance impact will be small.

Henrik Böving (Mar 31 2022 at 07:51):

It did indeed get magically fixed^^ But the explanation very much makes sense yes, I'll just keep it like combine {p q : Prop} to make this explicit


Last updated: Dec 20 2023 at 11:08 UTC