odin-lang / Odin

Odin Programming Language
https://odin-lang.org
BSD 3-Clause "New" or "Revised" License
6.77k stars 590 forks source link

Making a dynamic array with capacity and allocator but no length and returning it as a slice causes a compiler segmentation fault #4390

Open amjoshuamichael opened 3 days ago

amjoshuamichael commented 3 days ago

Context

Odin: dev-2024-10 OS: Arch Linux, Linux 6.11.3-arch1-1 CPU: Intel(R) Core(TM) i9-14900HX RAM: 15693 MiB Backend: LLVM 18.1.8

EDIT:

While doing some testing with this bug, which seems to only occur on linux, I've been able to replicate the bug on the following configuration:

Odin: dev-2024-10:af9ae4897 OS: macOS Sequoia 15 (build: 24A335, kernel: 24.0.0) CPU: Apple M2 Max RAM: 32768 MiB Backend: LLVM 18.1.8

[END OF EDIT]

Expected Behavior

Should throw an error complaining that I haven't specified the length of the dynamic array, like so:

Error: Parameter 'len' of type 'int' is missing in procedure call 
       list := make([dynamic]u8, cap = 2, allocator = context.allocato ... 
           ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ... 

This is the behavior when you don't return the dynamic array as a slice.

Current Behavior

Compiler segfaults.

Failure Information (for bugs)

Here's an lldb backtrace on my machine:

frame #0: 0x0000555555627082 odin`check_stmt_internal(CheckerContext*, Ast*, unsigned int) [inlined] base_type(t=0x0000000000000000) at types.cpp:912:10
frame #1: 0x0000555555627082 odin`check_stmt_internal(CheckerContext*, Ast*, unsigned int) [inlined] is_type_array(t=<unavailable>) at types.cpp:1460:6
frame #2: 0x0000555555627082 odin`check_stmt_internal(CheckerContext*, Ast*, unsigned int) [inlined] check_return_stmt(ctx=0x00007fffdbbffbe0, node=0x00007fffd8235790) at check_stmt.cpp:2574:39
frame #3: 0x0000555555626a05 odin`check_stmt_internal(ctx=0x00007fffdbbffbe0, node=0x00007fffd8235790, flags=<unavailable>) at check_stmt.cpp:2651:3
frame #4: 0x000055555561909f odin`check_stmt_list(CheckerContext*, Slice<Ast*> const&, unsigned int) [inlined] check_stmt(ctx=0x00007fffdbbffbe0, node=0x00007fffd8235790, flags=<unavailable>) at check_stmt.cpp:672:2
frame #5: 0x000055555561904a odin`check_stmt_list(ctx=0x00007fffdbbffbe0, stmts=0x00007fffd8235840, flags=<unavailable>) at check_stmt.cpp:108:3
frame #6: 0x000055555561747f odin`check_proc_info(Checker*, ProcInfo*, PtrMap<Ast*, ExprInfo*>*) [inlined] check_proc_body(ctx_=0x00007fffdbbffaa0, token=Token @ 0x00007fffdbbffb90, decl=0x00007fffd8238fd0, type=0x00007fffd82644e0, body=0x00007fffd8235800) at check_decl.cpp:1886:3
frame #7: 0x00005555556171e3 odin`check_proc_info(c=0x00007fffd82319b0, pi=0x00007fffbc4129a0, untyped=<unavailable>) at checker.cpp:5877:26
frame #8: 0x0000555555615eff odin`check_proc_info_worker_proc(data=0x00007fffbc4129a0) at checker.cpp:6053:6
frame #9: 0x0000555555739aa3 odin`internal_thread_proc(void*) [inlined] thread_pool_thread_proc(thread=<unavailable>) at thread_pool.cpp:191:4
frame #10: 0x0000555555739a54 odin`internal_thread_proc(arg=<unavailable>) at threading.cpp:564:2
frame #11: 0x00007fffef8a339d libc.so.6`___lldb_unnamed_symbol3666 + 941
frame #12: 0x00007fffef92849c libc.so.6`___lldb_unnamed_symbol4097 + 7

The error occurs here.

   909          if (t == nullptr) {
   910              break;
   911          }
-> 912          if (t->kind != Type_Named) {
   913              break;
   914          }
   915          if (t == t->Named.base) {

Steps to Reproduce

Here's a minimal program that produces the bug when I run odin build . on my machine.

package oh_no;

main :: proc() {
    numbers := make_numbers();
}

make_numbers :: proc() -> []u8 {
    list := make([dynamic]u8, cap = 2, allocator = context.allocator)
    return list[:];
}

Failure Logs

signal SIGSEGV: address not mapped to object (fault address: 0x0)

Note: I've been loving Odin so far! Thank you to all the contributors for helping to build such a great language.

tf2spi commented 1 day ago

I think I've found the approximate source of the problem.

check_value_decl_stmt (ctx=0x7fffe5c1f7e0, node=0x7fffc9795640, mod_flags=32)
    at src/check_stmt.cpp:2086
2086                    if (e->type == nullptr) {
(gdb) p init_type
$15 = (Type *) 0x0
(gdb) list
2082                    }
2083                    e->flags |= EntityFlag_Visited;
2084
2085                    e->state = EntityState_InProgress;
2086                    if (e->type == nullptr) {
2087                            e->type = init_type;
2088                            e->state = EntityState_Resolved;
2089                    }
2090                    ac.link_name = handle_link_name(ctx, e->token, ac.link_name, ac.link_prefix, ac.link_suffix);
2091
(gdb) p *e
$24 = {kind = Entity_Variable, id = 3021, flags = std::atomic<unsigned long> = { 1 },
  state = std::atomic<EntityState> = { EntityState_InProgress }, token = {kind = Token_Ident,
    flags = 0 '\000', string = {
      text = 0x7fffc9793398 "list := make([dynamic]u8, cap = 2, allocator = context.allocator)\n    return list[:];\n}\n", len = 4}, pos = {file_id = 28, offset = 104, line = 8,
      column = 5}}, scope = 0x7fffcc7b9560, type = 0x0,
// More stuff below

init_type is nullptr here when it probably shouldn't for this local variable.