Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Segmentation Fault with mutual, HashMap, and string interpolation #5188

Open
3 tasks done
ericluap opened this issue Aug 28, 2024 · 3 comments
Open
3 tasks done

Segmentation Fault with mutual, HashMap, and string interpolation #5188

ericluap opened this issue Aug 28, 2024 · 3 comments
Labels
bug Something isn't working depends on new code generator We are currently working on a new compiler (code generator) for Lean. This issue/PR is blocked by it P-high We will work on this issue

Comments

@ericluap
Copy link

Prerequisites

Please put an X between the brackets as you perform the following steps:

Description

The code has a segmentation fault when run.

Context

Here is a discussion on Zulip.

Steps to Reproduce

  1. lake new test
  2. cd test
  3. Modify Main.lean to have the following contents
import Lean.Data.HashMap

mutual
inductive Foo
| Foo (bar : Bar)

inductive Bar
| Foo (foo : Foo)
| Baz (baz : String)
end

mutual
def eToString : Foo → String
| Foo.Foo c => cToString c

def cToString : Bar → String
| Bar.Foo e => eToString e
| Bar.Baz c => c

end
instance : ToString Foo := ⟨eToString⟩
instance : ToString Bar := ⟨cToString⟩

def update (_ : Nat × Nat) (_ : Array String) (w : Lean.HashMap (Nat × Nat) (Array String)) :=
  w.insert (0,0) #[]

def test (x : String) (y : Foo) (z : Lean.HashMap (Nat × Nat) (Array String)): Option (String × (Option String) × (Option String) × String × (Lean.HashMap (Nat × Nat) (Array String))) := do
  pure $ (
    ((toString (← (Array.filter (fun _ => true) #[y])[0]?)).split (· = '0')).getD 0 "",
    none,
    "",
    "",
    update (x.length, x.length) #[s!"{x}", s!"{x}"] z
  )


def main : IO Unit := pure ()
  1. lake build
  2. ./.lake/build/bin/test

Expected behavior: The code should compile and run.

Actual behavior: It produces a segmentation fault.

Versions

"4.10.0" and "4.12.0-nightly-2024-08-27"
macOS Monterey Version 12.4

Impact

Add 👍 to issues you consider important. If others are impacted by this issue, please ask them to add 👍 to it.

@ericluap ericluap added the bug Something isn't working label Aug 28, 2024
@kim-em
Copy link
Collaborator

kim-em commented Aug 28, 2024

I can reproduce. lldb doesn't give much clue:

% lldb ./.lake/build/bin/test 
(lldb) target create "./.lake/build/bin/test"
Current executable set to '/Users/kim/scratch/test/.lake/build/bin/test' (arm64).
(lldb) run
Process 65953 launched: '/Users/kim/scratch/test/.lake/build/bin/test' (arm64)
Process 65953 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x2000000000000)
    frame #0: 0x0000000100003238 test`initialize_Main + 544
test`initialize_Main:
->  0x100003238 <+544>: ldr    w8, [x19]
    0x10000323c <+548>: cmp    w8, #0x1
    0x100003240 <+552>: b.lt   0x10000329c               ; <+644>
    0x100003244 <+556>: add    w8, w8, #0x1
Target 0: (test) stopped.
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x2000000000000)
  * frame #0: 0x0000000100003238 test`initialize_Main + 544
    frame #1: 0x00000001000032cc test`main + 32
    frame #2: 0x000000019e3020e0 dyld`start + 2360
(lldb) 

@hargoniX
Copy link
Contributor

Compiling this with -g as leanc args shows that we crash in this function:

static lean_object* _init_l_test___rarg___closed__6() {
_start:
{
lean_object* x_1; lean_object* x_2; lean_object* x_3; 
x_1 = l_update___rarg___closed__2;
x_2 = lean_unsigned_to_nat(0u);
x_3 = lean_array_fget(x_1, x_2);
return x_3;
}

At the fget call. This is because l_update___rarg___closed__2 is initialized with an Array of size 0 as evident by the code:

static lean_object* _init_l_update___rarg___closed__2() {
_start:
{
lean_object* x_1; lean_object* x_2; 
x_1 = lean_unsigned_to_nat(0u);
x_2 = lean_mk_empty_array_with_capacity(x_1);
return x_2;
}

And the debugger:

(gdb) list
828	_start:
829	{
830	lean_object* x_1; lean_object* x_2; lean_object* x_3;
831	x_1 = l_update___rarg___closed__2;
832	x_2 = lean_unsigned_to_nat(0u);
833	x_3 = lean_array_fget(x_1, x_2);
834	return x_3;
835	}
836	}
837	LEAN_EXPORT lean_object* l_test___rarg(lean_object* x_1, lean_object* x_2) {
(gdb) p ((lean_array_object*)x_1)->m_size
$6 = 0
(gdb) p ((lean_array_object*)x_1)->m_capacity
$7 = 0

@hargoniX
Copy link
Contributor

Looking into the IR the test function contains the following IR prior to closed subterm extraction:

  let _x_4 := Array.mkEmpty _neutral 0;
  let _x_5 := Nat.decLt 0 _x_3;
  Bool.casesOn _x_5
    (let _x_6 := Array.size _neutral _x_4;
    let _x_7 := Nat.decLt 0 _x_6;
    Bool.casesOn _x_7 (none _neutral)
      (let _x_8 := Array.get _neutral _x_4 0;
      @j_1._join _x_8))

What is probably happening here, is that the compiler pulled out Array.get x_4 0 because x_4 is a constant itself. This then gets evaluated in the initialize phase and subsequently crashes. I can offer the following temporary fix:

import Lean.Data.HashMap

mutual
inductive Foo
| Foo (bar : Bar)

inductive Bar
| Foo (foo : Foo)
| Baz (baz : String)
end

mutual
def eToString : Foo → String
| Foo.Foo c => cToString c

def cToString : Bar → String
| Bar.Foo e => eToString e
| Bar.Baz c => c

end
instance : ToString Foo := ⟨eToString⟩
instance : ToString Bar := ⟨cToString⟩

def update (_ : Nat × Nat) (_ : Array String) (w : Lean.HashMap (Nat × Nat) (Array String)) :=
  w.insert (0,0) #[]

set_option compiler.extract_closed false in
def test (x : String) (y : Foo) (z : Lean.HashMap (Nat × Nat) (Array String)): Option (String × (Option String) × (Option String) × String × (Lean.HashMap (Nat × Nat) (Array String))) := do
  pure $ (
    ((toString (← (Array.filter (fun _ => true) #[y])[0]?)).split (· = '0')).getD 0 "",
    none,
    "",
    "",
    update (x.length, x.length) #[s!"{x}", s!"{x}"] z
  )


def main : IO Unit := pure ()

@hargoniX hargoniX added the depends on new code generator We are currently working on a new compiler (code generator) for Lean. This issue/PR is blocked by it label Aug 28, 2024
@leanprover leanprover deleted a comment Aug 28, 2024
@leanprover-bot leanprover-bot added the P-high We will work on this issue label Aug 30, 2024
@kim-em kim-em mentioned this issue Jan 7, 2025
2 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working depends on new code generator We are currently working on a new compiler (code generator) for Lean. This issue/PR is blocked by it P-high We will work on this issue
Projects
None yet
Development

No branches or pull requests

4 participants