Zulip Chat Archive
Stream: general
Topic: Expressing ability to construct any value from UB
l1mey (Sep 09 2025 at 05:34):
I am working on a project to formalise certain rewrite rules in an the integer subset of the LLVM IR, with poison to model UB. In the LLVM LangRef #poison-values, it states that you can replace a possible poison value with any value for that type, even a different value in each different case. I am confused on how I would express this though, as I currently have (this is a minimal working example):
/--
LLVM-style integers with poison value.
-/
inductive iN (bits : Nat) : Type where
| bitvec : BitVec bits → iN bits
| poison : iN bits
export iN (poison bitvec)
instance : OfNat (iN n) val where
ofNat := iN.bitvec (BitVec.ofNat n val)
inductive Cases : (iN n) → Prop where
| one : Cases (12 : iN n)
| two : Cases (poison)
theorem forge12 {n} (x : iN n) (h : Cases x)
: x = 12 := by
cases h
case one => rfl
case two =>
sorry
What could I possibly do here?
William Sørensen (Sep 09 2025 at 06:23):
Is this maybe related to @Tobias Grosser 's LeanMLIR work? @Alex Keizer might be able to help
l1mey (Sep 09 2025 at 06:54):
Not particularly related, just my own small project. I solved the problem though, I was thinking of rewrites completely wrong. A rewrite from x to y isn't an equivalence relation, it's more like a preorder. So you can have poision ~> 12, but you can't coerce 12 ~> poison. Example below:
/--
`Refines x y` means the value `x` can be refined into the concrete value `y`.
This reads like an action: `refine x into y`.
-/
inductive Refines {n} : iN n → iN n → Prop where
/-- A bitvector refines to itself. -/
| bv_refl (v : BitVec n) : Refines (bitvec v) (bitvec v)
/-- Poison can be refined into any bitvector. -/
| poison_forge (v : BitVec n) : Refines poison (bitvec v)
abbrev RefinesReversed {n} (x y : iN n) := Refines y x
abbrev RefinesIff {n} (x y : iN n) := Refines x y ∧ Refines y x
infix:50 " ~> " => Refines
infix:50 " <~ " => RefinesReversed
infix:50 " <~> " => RefinesIff
l1mey (Sep 09 2025 at 06:56):
Though, from here I've got a long road ahead making these definitions amenable to trivial proof.
William Sørensen (Sep 09 2025 at 07:10):
This is quote cool and good luck! I was planning on writing a compiler where one of the arguments for the compilation is that the source code is free of UB, meaning that if there is UB, and you have a compiled result you can just exfalso it, but i havent actually thought about that to any actual detail.
William Sørensen (Sep 09 2025 at 07:11):
but yeah would be cool to see where this project goes
l1mey (Sep 09 2025 at 07:47):
This definition is quite convenient. Here is a formal proof that compilers can rewrite INT32_MAX + 1 to 12:
Alex Keizer (Sep 09 2025 at 12:30):
This is quite similar to how we model poison in LeanMLIR!
l1mey (Sep 15 2025 at 08:24):
Using this definition, I've come into issues with automated proof: #general > Converting goals to be bitblasted like BVDecide. Maybe someone might be able to look at it?
Last updated: Dec 20 2025 at 21:32 UTC