Zulip Chat Archive
Stream: lean4
Topic: Can this extern definition be used to prove False?
François G. Dorais (Dec 28 2025 at 16:35):
I'm currently using this definition in some personal projects but I always mark it unsafe (which is fine for my purposes) but I realized I could make it into a plain safe definition with no harm to my code. Is there potential harm in marking it safe?
/-- Returns the first input but forces the compiler to evaluate the second input. -/
@[never_extract, extern c inline "#3"]
def withEffects {α : Type _} {β : Type _} (a : α) (b : @& β) : α := a
theorem withEffects_def {α : Type _} {β : Type _} (a : α) (b : β) :
withEffects a b = a := by rfl
The idea is that withEffects forces the compiler to evaluate b and then returns a unchanged, this is because the compiler doesn't know b isn't used because of the extern so it thinks a might be changed. (This is true if evaluating b has effects on a, as is possible in unsafe code.) When pressed, the kernel doesn't care much, it thinks that withEffects a is just a. The weird thing is that the kernel is correct: withEffects a is really just a!
Can withEffects be used in nefarious ways to make the kernel prove False?
François G. Dorais (Dec 28 2025 at 16:46):
Part of me says no because, in a safe context, b is pure and can't actually have effects so forcing evaluation is meaningless. But I'm still skeptical...
Jason Rute (Dec 28 2025 at 17:06):
When you talk about the kernel being able to prove False, do you mean using native_decide or similar? Because if you mean with just the usual three axioms, that would be really bad, right?
Jason Rute (Dec 28 2025 at 17:06):
And hence seems very doubtful this would be a soundness issue, right?
François G. Dorais (Dec 28 2025 at 17:11):
Using native_decide or similar would be necessary here since it's about an extern definition. These are invisible to the kernel without such trickery.
Jason Rute (Dec 28 2025 at 17:19):
I'm probably misunderstanding, but if this is external, doesn't that already allow it to prove False (again, using native_decide which we already know is unsound)? Just give an external implementation which doesn't match the Lean definition, right?
Jason Rute (Dec 28 2025 at 17:27):
Oh I see. extern c inline "#3" doesn't associate this function with another (arbitrary) external function, but somehow converts it into an external C function.
François G. Dorais (Dec 28 2025 at 17:40):
Yes, the extern c inline "#3" just makes the compiler spit out a but the compiler can't inspect this extern so it assumes that b (the effect) is actually used even though the result is just a.
Robin Arnez (Dec 29 2025 at 20:13):
I'm pretty sure your definition is effectively equivalent to the following:
@[never_extract, noinline]
def withEffects {α : Type _} {β : Type _} (a : α) (b : @& β) : α :=
destruct (a, b)
where
@[noinline]
destruct (x : α × β) : α := x.1
theorem withEffects_def {α : Type _} {β : Type _} (a : α) (b : β) :
withEffects a b = a := by rfl
A regular non-unsafe definition shouldn't have any soundness concerns so anything equivalent to it should not be much different.
Last updated: Feb 28 2026 at 14:05 UTC