Zulip Chat Archive

Stream: lean4

Topic: Contradiction?


Markus Himmel (Jan 31 2021 at 05:54):

I belive that I have found a proof of false in the current nightly of Lean 4. Could someone verify that this is indeed the case and I'm not doing something stupid?

theorem proofOfFalse : False := Nat.oneNeZero $ (Nat.modZero 1).symm.trans rfl
#print proofOfFalse
#print axioms proofOfFalse
$ lean --version
Lean (version 4.0.0-nightly-2021-01-31, commit 95ebd58ae95c, Release)
$ lean test.lean
theorem proofOfFalse : False :=
Nat.oneNeZero (Eq.trans (Eq.symm (Nat.modZero 1)) rfl)
'proofOfFalse' does not depend on any axioms

I'm on Ubuntu 20.04 and I'm using the prebuilt binaries from here.

Mario Carneiro (Jan 31 2021 at 06:01):

Here's the bug: https://github.com/leanprover/lean4/blob/master/src/include/lean/lean.h#L1361

(it should return n1 instead of 0 there)

Mario Carneiro (Jan 31 2021 at 06:03):

@Markus Himmel does it work on trust level 0? This bug involves executing C code via @[extern "lean_nat_mod"] that might not be executed at trust 0

Markus Himmel (Jan 31 2021 at 06:04):

Is this the right invocation?

$ lean --trust=0 test.lean
theorem proofOfFalse : False :=
Nat.oneNeZero (Eq.trans (Eq.symm (Nat.modZero 1)) rfl)
'proofOfFalse' does not depend on any axioms

Mario Carneiro (Jan 31 2021 at 06:06):

The bug is repeated in lean_nat_big_mod too

Mario Carneiro (Jan 31 2021 at 06:08):

I think it is lean -t 0

Markus Himmel (Jan 31 2021 at 06:08):

Passing -t 0 doesn't seem to make a difference

Mario Carneiro (Jan 31 2021 at 06:25):

it's also in lean_int_mod; it's not clear if lean_int_big_mod has the bug because it doesn't do a division by zero check, it just calls directly into GMP with a zero divisor, although I didn't manage to get it to crash and I'm not sure what GMP does with that

Mario Carneiro (Jan 31 2021 at 06:28):

from the docs it seems like it deliberately causes a division by zero exception, so maybe lean is catching it?

Markus Himmel (Jan 31 2021 at 06:28):

I have a crash involving big integers and modding by zero:

#eval (2147483648 % 0) + (-0)

crashes Lean 4 with a Floating point exception

Mario Carneiro (Jan 31 2021 at 06:30):

that doesn't look like it uses integers, is the elaborator doing something tricky with default instances?

Markus Himmel (Jan 31 2021 at 06:31):

Why shouldn't it use integers? I think Floating point exception is what you get when you do x % 0 in C/C++ code.

Mario Carneiro (Jan 31 2021 at 06:32):

Yeah, it's because the idiv instruction on x86 yields the SIGFPE fault which is "floating point exception"

Mario Carneiro (Jan 31 2021 at 06:33):

I don't understand why #check (rfl : Int.mod 123456789123456789 0 = 0) works though, even though #eval Int.mod 123456789123456789 0 causes the crash

Mario Carneiro (Jan 31 2021 at 06:34):

The same thing works with Int.div in place of Int.mod but in that case Int.div n 0 = 0 is actually correct

Mario Carneiro (Jan 31 2021 at 06:37):

Markus Himmel said:

Why shouldn't it use integers?

I meant that if you write that in lean 3 it won't use int unless you put a type ascription somewhere

Mario Carneiro (Jan 31 2021 at 06:39):

BTW kudos to the vscode-lean4 extension for being able to restart lean so smoothly after a crash; you can just change the text and the highlights come back

Mario Carneiro (Jan 31 2021 at 06:43):

theorem proofOfFalse : False := Nat.zeroNeOne (Nat.modZero 1)
#print axioms proofOfFalse

:golf:

Marc Huisinga (Jan 31 2021 at 10:30):

Mario Carneiro said:

Markus Himmel does it work on trust level 0? This bug involves executing C code via @[extern "lean_nat_mod"] that might not be executed at trust 0

I'm not sure if you can disable this particular feature, i.e. reduction of closed nat terms (see the bottom of https://leanprover.github.io/lean4/doc/nat.html).

Mario Carneiro said:

BTW kudos to the vscode-lean4 extension for being able to restart lean so smoothly after a crash; you can just change the text and the highlights come back

The watchdog in the server does this, not the extension. The vscode LSP client restarts aren't quite as smooth and tend to run into restart loops (until eventually giving up entirely after 4 retries).

Mario Carneiro (Jan 31 2021 at 10:33):

Is there a way to tell the difference between C code in the TCB from out? I was previously holding the contradictory beliefs that all extern functions were disabled at trust level 0, and operations on the new primitive nat literals are handled directly by the kernel

Marc Huisinga (Jan 31 2021 at 10:37):

It may also be that this does not apply to mod, given that it's in Data/Nat/Div and not Prelude. I'll wait for someone who understands the internals to chime in :)

Mario Carneiro (Jan 31 2021 at 10:44):

From https://github.com/leanprover/lean4/blob/master/src/Lean/Meta/WHNF.lean#L550-L566, it looks like the only trusted replacements are the functions Nat.add, Nat.sub, Nat.mul, Nat.div, Nat.mod, Nat.ble, Nat.beq coming from reduceNat?, plus the more general purpose Lean.reduceBool, Lean.reduceNat coming from reduceNative? (and I think the latter show up in #print axioms)

Mario Carneiro (Jan 31 2021 at 10:47):

This also answers the question of why rfl : Int.mod 123456789123456789 0 = 0 worked, because it's not exercising the bug in lean_int_big_mod because it's evaluating the model instead of the efficient version, but that reduces to Nat.mod big_number 0 which reduces using the bad lean_nat_big_mod since Nat.mod is one of the trusted functions

Leonardo de Moura (Jan 31 2021 at 16:36):

I pushed a fix.
https://github.com/leanprover/lean4/commit/3fa1f355eb4b717a1b1f59e1bb8f1a9d32b45ca6
The bug was due to a mismatch between the Nat.mod definition in Lean and the implementation used in the runtime.
The Lean kernel type checker (implemented in C++) uses some Nat runtime functions to speedup reduction. Recall that I mentioned this new feature during the Lean 4 presentation at Lean Together. The kernel type checker that implements this feature is here:
https://github.com/leanprover/lean4/blob/master/src/kernel/type_checker.cpp#L585-L594
lean::nat_mod is just a wrapper for lean_nat_mod that is fixed by the commit above.

Remarks:

  • The file Lean/Meta/WHNF.lean is not part of the kernel. It implements the whnf operation for the elaborator.
  • The native implementation of the functions at https://github.com/leanprover/lean4/blob/master/src/kernel/type_checker.cpp#L585-L594
    are part of the trusted code base.

  • I will add a flag for disabling this feature.

  • The runtime implementation of Int.mod probably doesn't match the Lean definition too. I haven't checked yet, but it will not affect proofs because lean_int_mod is not used by the kernel type checker.

Last updated: Dec 20 2023 at 11:08 UTC