-
-
Notifications
You must be signed in to change notification settings - Fork 2.7k
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
Debug breakpoint is hit when it shouldn't be #19443
Comments
I think this is an manifestation of the slightly weird issue that when a block is skipped, debuggers will indicate us first jumping to the block's last line, and then we appear to enter the following code. |
You might be onto something. If the code is changed to: const std = @import("std");
pub fn main() !void {
var i: usize = 0;
while (i < 100) : (i += 1) {
if (i == 90) {
std.debug.print("It's 90!", .{});
} else if (i == 50) {
const foo: usize = i + 10;
var bar: usize = foo + 20;
std.debug.print("It's inner {d}!", .{bar});
bar += 1;
std.debug.print("It's inner plus one {d}!", .{bar});
std.debug.print("It's 50!", .{});
}
}
} And breakpoint is in the middle of the block, then it behaves as expected: (lldb) b main.zig:11
Breakpoint 2: where = repro`main.main + 320 at main.zig:11:28, address = 0x00000001000008a8
(lldb) run
Process 5813 launched: '~/zig/repro/zig-out/bin/repro' (arm64)
Process 5813 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 2.1
frame #0: 0x00000001000008a8 repro`main.main at main.zig:11:28
8 } else if (i == 50) {
9 const foo: usize = i + 10;
10 var bar: usize = foo + 20;
-> 11 std.debug.print("It's inner {d}!", .{bar});
12 bar += 1;
13 std.debug.print("It's inner plus one {d}!", .{bar});
14 std.debug.print("It's 50!", .{});
Target 0: (repro) stopped.
(lldb) var i
(unsigned long) i = 50 Would this mean zig cannot do anything and it's the issue of a debugger? |
does this reproduce on 0.12.0-dev.3439+31a7f22b8 ? |
Tried reproducing same with c++: mkdir repro-cpp
cd repro-cpp
cat <<EOF > main.cpp
#include <iostream>
int main()
{
int i = 0;
while (i < 100)
{
if (i == 90) {
std::cout << "It's 90!\n";
}
else if (i == 50) {
std::cout << "It's 50!\n";
}
i += 1;
}
}
EOF
g++ -g main.cpp
lldb a.out and then in debugger (lldb) b main.cpp:12
Breakpoint 1: where = a.out`main + 124 at main.cpp:12:23, address = 0x0000000100003128
(lldb) run
Process 6746 launched: '~/zig/repro/repro-cpp/a.out' (arm64)
Process 6746 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
frame #0: 0x0000000100003128 a.out`main at main.cpp:12:23
9 std::cout << "It's 90!\n";
10 }
11 else if (i == 50) {
-> 12 std::cout << "It's 50!\n";
13 }
14 i += 1;
15 }
Target 0: (a.out) stopped.
(lldb) var i
(int) i = 50 seems to work fine, so it's probably not a debugger issue? |
@nektro tested on |
No, this is still a Zig bug. I might try and take a look later today. |
Reset the line number to its previous state after genBodyDebugScope, so that instructions between its end and the next dbg_stmt do not wander inside the block. This core fix is very simple, but surfaces a secondary issue: the LLVM codegecn generates blocks in a different order than Clang would for the same CFG in C, which ultimately results in GDB skipping the loop header altogether. So we need to reorder some basic blocks too.
Reset the line number to its previous state after genBodyDebugScope, so that instructions between its end and the next dbg_stmt do not wander inside the block. This core fix is very simple, but surfaces a secondary issue: the LLVM codegen generates blocks in a different order than Clang would for the same CFG in C, which ultimately results in GDB skipping the loop header altogether. So we need to reorder some basic blocks too.
Reset the line number to its previous state after genBodyDebugScope, so that instructions between its end and the next dbg_stmt do not wander inside the block. This core fix is very simple, but surfaces a secondary issue: the LLVM codegen generates blocks in a different order than Clang would for the same CFG in C, which ultimately results in GDB skipping the loop header altogether. So we need to reorder some basic blocks too.
Reset the line number to its previous state after genBodyDebugScope, so that instructions between its end and the next dbg_stmt do not wander inside the block. This core fix is very simple, but surfaces a secondary issue: the LLVM codegen generates blocks in a different order than Clang would for the same CFG in C, which ultimately results in GDB skipping the loop header altogether. So we need to reorder some basic blocks too.
Reset the line number to its previous state after genBodyDebugScope, so that instructions between its end and the next dbg_stmt do not wander inside the block. This core fix is very simple, but surfaces a secondary issue: the LLVM codegen generates blocks in a different order than Clang would for the same CFG in C, which ultimately results in GDB skipping the loop header altogether. So we need to reorder some basic blocks too.
Reset the line number to its previous state after genBodyDebugScope, so that instructions between its end and the next dbg_stmt do not wander inside the block. This core fix is very simple, but surfaces a secondary issue: the LLVM codegen generates blocks in a different order than Clang would for the same CFG in C, which ultimately results in GDB skipping the loop header altogether. So we need to reorder some basic blocks too.
Reset the line number to its previous state after genBodyDebugScope, so that instructions between its end and the next dbg_stmt do not wander inside the block. This core fix is very simple, but surfaces a secondary issue: the LLVM codegen generates blocks in a different order than Clang would for the same CFG in C, which ultimately results in GDB skipping the loop header altogether. So we need to reorder some basic blocks too.
Your example is little bit verbose, const std = @import("std");
pub fn main() !void {
var argslen = std.os.argv.len; // or std.crypto.random.int(u8)
if (argslen == 0xFEED) {
std.debug.print("you are not on the end", .{});
argslen += 0x69;
}
} When tracing such problem you must walk instruction by instruction and look $ llvm-objdump --disassemble-symbols=main.main -S ./zig-out/bin/zig-test --disassembler-color=on | less -R
.
.
.
; if (argslen == 0xFEED) {
104b10c: f85f83a8 ldur x8, [x29, #-0x8]
104b110: 529fdda9 mov w9, #0xfeed // =65261
104b114: eb090108 subs x8, x8, x9
104b118: 540000c0 b.eq 0x104b130 <main.main+0x44>
104b11c: 1400000d b 0x104b150 <main.main+0x64> // not equal? jump to 104b150
104b120: 2a1f03e0 mov w0, wzr // So i jumped inside the source code if statement to jump
to the next instruction Also lldb have outputted warning: "Note: this address is compiler-generated code in function main.main that has no source code associated with it."
; argslen += 0x69;
104b124: a9427bfd ldp x29, x30, [sp, #0x20] // Wow we are back inside the if statement
104b128: 9100c3ff add sp, sp, #0x30
104b12c: d65f03c0 ret // and return cool
104b130: f9400be0 ldr x0, [sp, #0x10]
; std.debug.print("you are not on the end", .{});
104b134: 9400000d bl 0x104b168 <debug.print__anon_1693>
; argslen += 0x69;
104b138: f85f83a8 ldur x8, [x29, #-0x8]
104b13c: b101a508 adds x8, x8, #0x69
104b140: f90007e8 str x8, [sp, #0x8]
104b144: 1a9f37e8 cset w8, hs
104b148: 37000068 tbnz w8, #0x0, 0x104b154 <main.main+0x68>
104b14c: 14000004 b 0x104b15c <main.main+0x70>
104b150: 17fffff4 b 0x104b120 <main.main+0x34> // great another jump wait a second why are we inside the source code if statement weird, okay i will jump to 104b120
104b154: f9400be0 ldr x0, [sp, #0x10]
; argslen += 0x69;
104b158: 94000069 bl 0x104b2fc <debug.FullPanic((function 'defaultPanic')).integerOverflow>
104b15c: f94007e8 ldr x8, [sp, #0x8]
; argslen += 0x69;
104b160: f81f83a8 stur x8, [x29, #-0x8]
104b164: 17ffffef b 0x104b120 <main.main+0x34> These what i gathered for today Footnotes
|
Zig Version
0.12.0-dev.2809+f3bd177720.12.0-dev.3439+31a7f22b8
Steps to Reproduce and Observed Behavior
Create a simple repro by running:
Then in lldb console:
Notice how the breakpoint gets hit every cycle, even though the
i == 50
should happen only once. Reading thei
variable it prints0
,1
, etc.Expected Behavior
Breakpoint should hit only once when
i == 50
.The text was updated successfully, but these errors were encountered: