authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-01-19 14:08:43-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-01-19 14:08:43-07:00
log287f640cc94d7f1cddb30e9ef57a8c921621a5b9
tree0cc87ff3207394d289324c8bf8f2ad4ac900e049
parentd5d0619aacccd5e3b933b3196fba5ab6f8f9da47

stage2: ELF: fix crash when only 1 function and it gets updated


2 files changed, 46 insertions(+), 3 deletions(-)

src/link/Elf.zig+16-3
......@@ -2377,7 +2377,7 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
23772377 const debug_line_sect = &self.sections.items[self.debug_line_section_index.?];
23782378 const src_fn = &decl.fn_link.elf;
23792379 src_fn.len = @intCast(u32, dbg_line_buffer.items.len);
2380 if (self.dbg_line_fn_last) |last| {
2380 if (self.dbg_line_fn_last) |last| not_first: {
23812381 if (src_fn.next) |next| {
23822382 // Update existing function - non-last item.
23832383 if (src_fn.off + src_fn.len + min_nop_size > next.off) {
......@@ -2400,9 +2400,15 @@ pub fn updateDecl(self: *Elf, module: *Module, decl: *Module.Decl) !void {
24002400 src_fn.off = last.off + padToIdeal(last.len);
24012401 }
24022402 } else if (src_fn.prev == null) {
2403 if (src_fn == last) {
2404 // Special case: there is only 1 function and it is being updated.
2405 // In this case there is nothing to do. The function's length has
2406 // already been updated, and the logic below takes care of
2407 // resizing the .debug_line section.
2408 break :not_first;
2409 }
24032410 // Append new function.
24042411 // TODO Look at the free list before appending at the end.
2405 assert(src_fn != last);
24062412 src_fn.prev = last;
24072413 last.next = src_fn;
24082414 self.dbg_line_fn_last = src_fn;
......@@ -2527,7 +2533,7 @@ fn updateDeclDebugInfoAllocation(self: *Elf, text_block: *TextBlock, len: u32) !
25272533
25282534 const debug_info_sect = &self.sections.items[self.debug_info_section_index.?];
25292535 text_block.dbg_info_len = len;
2530 if (self.dbg_info_decl_last) |last| {
2536 if (self.dbg_info_decl_last) |last| not_first: {
25312537 if (text_block.dbg_info_next) |next| {
25322538 // Update existing Decl - non-last item.
25332539 if (text_block.dbg_info_off + text_block.dbg_info_len + min_nop_size > next.dbg_info_off) {
......@@ -2549,6 +2555,13 @@ fn updateDeclDebugInfoAllocation(self: *Elf, text_block: *TextBlock, len: u32) !
25492555 text_block.dbg_info_off = last.dbg_info_off + padToIdeal(last.dbg_info_len);
25502556 }
25512557 } else if (text_block.dbg_info_prev == null) {
2558 if (text_block == last) {
2559 // Special case: there is only 1 .debug_info block and it is being updated.
2560 // In this case there is nothing to do. The block's length has
2561 // already been updated, and logic in writeDeclDebugInfo takes care of
2562 // resizing the .debug_info section.
2563 break :not_first;
2564 }
25522565 // Append new Decl.
25532566 // TODO Look at the free list before appending at the end.
25542567 text_block.dbg_info_prev = last;
test/stage2/test.zig+30
......@@ -1509,4 +1509,34 @@ pub fn addCases(ctx: *TestContext) !void {
15091509 "",
15101510 );
15111511 }
1512
1513 {
1514 var case = ctx.exe("only 1 function and it gets updated", linux_x64);
1515 case.addCompareOutput(
1516 \\export fn _start() noreturn {
1517 \\ asm volatile ("syscall"
1518 \\ :
1519 \\ : [number] "{rax}" (60), // exit
1520 \\ [arg1] "{rdi}" (0)
1521 \\ : "rcx", "r11", "memory"
1522 \\ );
1523 \\ unreachable;
1524 \\}
1525 ,
1526 "",
1527 );
1528 case.addCompareOutput(
1529 \\export fn _start() noreturn {
1530 \\ asm volatile ("syscall"
1531 \\ :
1532 \\ : [number] "{rax}" (231), // exit_group
1533 \\ [arg1] "{rdi}" (0)
1534 \\ : "rcx", "r11", "memory"
1535 \\ );
1536 \\ unreachable;
1537 \\}
1538 ,
1539 "",
1540 );
1541 }
15121542}