ziglang / zig

General-purpose programming language and toolchain for maintaining robust, optimal, and reusable software.
https://ziglang.org
MIT License
34.47k stars 2.52k forks source link

Invalid debug info when linking to system library. #12046

Open ayham-1 opened 2 years ago

ayham-1 commented 2 years ago

Zig Version

0.9.1, on ArtixLinux x64, normal kernel, and hardened.

Steps to Reproduce

build.zig:

const std = @import("std");

pub fn build(b: *std.build.Builder) void {
    const target = b.standardTargetOptions(.{});
    const mode = b.standardReleaseOptions();
    const exe = b.addExecutable("zigample", "src/main.zig");
    exe.setTarget(target);
    exe.setBuildMode(mode);
    exe.linkSystemLibrary("GL");
    exe.linkLibC();
    exe.install();
    const run_cmd = exe.run();
    run_cmd.step.dependOn(b.getInstallStep());
    if (b.args) |args| {
        run_cmd.addArgs(args);
    }
    const run_step = b.step("run", "Run the app");
    run_step.dependOn(&run_cmd.step);
}

main.zig:

const std = @import("std");

pub fn main() !void {
    var testVar = "hello";

    var general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{}){};
    const alloc = general_purpose_allocator.allocator();

    var gameMap = try alloc.alloc(u8, testVar.len);
    std.mem.copy(u8, gameMap, testVar);

    const debug_info = std.debug.getSelfDebugInfo() catch unreachable;
    const module = debug_info.getModuleForAddress(@returnAddress());
    std.log.warn("hello {}", .{module});
    //const builtin = @import("builtin");
    //std.log.warn("hello {}", .{builtin.position_independent_executable});

    std.debug.dumpCurrentStackTrace(@returnAddress());

    _ = general_purpose_allocator.deinit();
}

Command to compile:

zig build run

However, this works:

zig build-exe -lX11 -lGL src/main.zig

but this does not:

zig build-exe -lc -GL src/main

Appears to be happening when linking multiple/both libraries?

Expected Behavior

A bunch of gibberish for the first print, then:

/usr/lib/zig/std/start.zig:561:37: 0x22513a in std.start.callMain (main)
            const result = root.main() catch |err| {
                                    ^
/usr/lib/zig/std/start.zig:495:12: 0x206497 in std.start.callMainWithArgs (main)
    return @call(.{ .modifier = .always_inline }, callMain, .{});
           ^
/usr/lib/zig/std/start.zig:409:17: 0x205594 in std.start.posixCallMainAndExit (main)
    std.os.exit(@call(.{ .modifier = .always_inline }, callMainWithArgs, .{ argc, argv, envp }));
                ^
/usr/lib/zig/std/start.zig:322:5: 0x2053a1 in std.start._start (main)
    @call(.{ .modifier = .never_inline }, posixCallMainAndExit, .{});
    ^
error(gpa): memory address 0x7f64405b6000 leaked:
/data/sisyphus/proj/zigample/src/main.zig:9:34: 0x22b8c6 in main (main)
    var gameMap = try alloc.alloc(u8, testVar.len);
                                 ^
/usr/lib/zig/std/start.zig:561:37: 0x22513a in std.start.callMain (main)
            const result = root.main() catch |err| {
                                    ^
/usr/lib/zig/std/start.zig:495:12: 0x206497 in std.start.callMainWithArgs (main)
    return @call(.{ .modifier = .always_inline }, callMain, .{});
           ^
/usr/lib/zig/std/start.zig:409:17: 0x205594 in std.start.posixCallMainAndExit (main)
    std.os.exit(@call(.{ .modifier = .always_inline }, callMainWithArgs, .{ argc, argv, envp }));

Actual Behavior

warning: hello error.InvalidDebugInfo
???:?:?: 0x22afe7 in ??? (???)
???:?:?: 0x206bf7 in ??? (???)
???:?:?: 0x2069a2 in ??? (???)
error(gpa): memory address 0x7fa8a9429000 leaked:
???:?:?: 0x205e76 in ??? (???)
???:?:?: 0x22afe7 in ??? (???)
???:?:?: 0x206bf7 in ??? (???)
???:?:?: 0x2069a2 in ??? (???)
topolarity commented 2 years ago

Thanks for the report - I was able to repro the problem

The problem is that linking certain libraries will cause the debug info to be output in DWARFv5 (instead of DWARFv4), and Zig 0.9.1 cannot correctly parser DWARFv5 debug info

DWARFv5 support was added in #11173, so this works on 0.10 / master

ayham-1 commented 2 years ago

The problem is that linking certain libraries will cause the debug info to be output in DWARFv5 (instead of DWARFv4), and Zig 0.9.1 cannot correctly parser DWARFv5 debug info

Zig does build GL, but only when it is alone. How does that relate to DWARFv5 support?

topolarity commented 2 years ago

The problem I see on my system is that the system-provided glibc on Arch was built with DWARFv5 debug info, so linking with that libc will generate an executable with DWARFv5 debug info

Can you test with the 0.10.0 master "nightly", and let me know if it resolves the issue? https://ziglang.org/download/

ayham-1 commented 2 years ago

Can you test with the 0.10.0 master "nightly", and let me know if it resolves the issue?

I installed the other Zig package from AUR, 'zig-dev-bin',. I believe version 0.10.0, does work, and surprisingly is stable for a nightly release.

However, it seems like the first trace sometimes does break. I did not find consistency though.

topolarity commented 2 years ago

Hmm, sounds like the parser probably still needs some improvement.

Can you attach a copy of the ELF file that is not parsed correctly?

ayham-1 commented 2 years ago

I do not exactly know how useful this is, but here is a copy of a seg faulting program. 0x0.st upload To get it to segfault and print a stack trace, pass a positive integer as a command line argument.

The faulty stack is not consequential, at least for identifying the problem, though.

topolarity commented 2 years ago

Thanks! Can you also share the faulty stack trace? It'll help me check that the symbols can be looked up properly (I just need the list of addresses printed)

ayham-1 commented 2 years ago
[~/./s/sokoban] $ ./zig-out/bin/sokoban-vis 50
warning: hello generator.GeneratedPuzzle{ .map = map.Map{ .alloc = Allocator{ .ptr = anyopaque@55ab07b13660, .vtable = std.mem.Allocator.VTable{ ... } }, .rows = std.array_list.ArrayListAligned(std.array_list.ArrayListAligned(constants.Textile,null),null){ .items = { ... }, .capacity = 8, .allocator = Allocator{ ... } }, .highestId = 26, .displayed = std.array_list.ArrayListAligned(u8,null){ .items = { ... }, .capacity = 38, .allocator = Allocator{ ... } }, .sizeWidth = 5, .sizeHeight = 5, .workerPos = constants.Pos{ .x = 2, .y = 3 } }, .score = 0.0e+00 }

Segmentation fault at address 0x0
???:?:?: 0x7f77def5ce8d in ??? (???)
/usr/lib/zig/lib/std/fmt.zig:560:31: 0x55ab07acf9d0 in std.fmt.formatType (sokoban-vis)
                try formatType(@field(value, f.name), ANY, options, writer, max_depth - 1);
                              ^
/usr/lib/zig/lib/std/fmt.zig:178:23: 0x55ab07ac40ee in std.fmt.format (sokoban-vis)
        try formatType(
                      ^
/usr/lib/zig/lib/std/fmt.zig:1889:11: 0x55ab07ab8705 in std.fmt.count (sokoban-vis)
    format(counting_writer.writer(), fmt, args) catch |err| switch (err) {};
          ^
/usr/lib/zig/lib/std/fmt.zig:1896:40: 0x55ab07a978d8 in std.fmt.allocPrint (sokoban-vis)
    const size = math.cast(usize, count(fmt, args)) orelse return error.OutOfMemory;
                                       ^
/usr/lib/zig/lib/std/fmt.zig:1906:34: 0x55ab07a9754b in std.fmt.allocPrintZ (sokoban-vis)
    const result = try allocPrint(allocator, fmt ++ "\x00", args);
                                 ^
/data/sisyphus/proj/sokoban/src/log.zig:59:38: 0x55ab07a97470 in log.printAlloc (sokoban-vis)
    const s = try std.fmt.allocPrintZ(allocator, fmt ++ "\n", args);
                                     ^
/data/sisyphus/proj/sokoban/src/log.zig:47:19: 0x55ab07a8bbfc in log.warnAlloc (sokoban-vis)
    try printAlloc(allocator, .warn, fmt, args);
                  ^
/data/sisyphus/proj/sokoban/src/log.zig:19:14: 0x55ab07a83d4a in log.warn (sokoban-vis)
    warnAlloc(fba.allocator(), fmt, args) catch |err| {
             ^
/data/sisyphus/proj/sokoban/src/generator.zig:192:17: 0x55ab07a8321f in generator.Node.evaluationFunction (sokoban-vis)
    fn evaluationFunction(self: *Node) !f32 {
                ^
/data/sisyphus/proj/sokoban/src/generator.zig:177:48: 0x55ab07a825ff in generator.Node.evalBackProp (sokoban-vis)

                                               ^
/data/sisyphus/proj/sokoban/src/generator.zig:163:42: 0x55ab07a79622 in generator.Node.iterate (sokoban-vis)
    }
                                         ^
/data/sisyphus/proj/sokoban/src/visualizer.zig:67:35: 0x55ab07a786ec in main (sokoban-vis)
            try parentNode.iterate();
                                  ^
/usr/lib/zig/lib/std/start.zig:581:37: 0x55ab07a9cdf7 in std.start.callMain (sokoban-vis)
            const result = root.main() catch |err| {
                                    ^
/usr/lib/zig/lib/std/start.zig:515:12: 0x55ab07a7c207 in std.start.callMainWithArgs (sokoban-vis)
    return @call(.{ .modifier = .always_inline }, callMain, .{});
           ^
/usr/lib/zig/lib/std/start.zig:480:12: 0x55ab07a7bfb2 in std.start.main (sokoban-vis)
    return @call(.{ .modifier = .always_inline }, callMainWithArgs, .{ @intCast(usize, c_argc), c_argv, envp });
           ^
zsh: IOT instruction  ./zig-out/bin/sokoban-vis 50
topolarity commented 2 years ago

Looks like the first entry is actually memcpy in libc. Lookup fails because Zig builds libc without debug symbols.

There are ways for Zig to get those debug symbols (by building them into libc, or loading them from usr/lib/debug if it's the system libc), but Zig doesn't do those yet.

I think it's worth tracking a fix for that (in this issue or a new one)