Gentoo Websites Logo
Go to: Gentoo Home Documentation Forums Lists Bugs Planet Store Wiki Get Gentoo!
View | Details | Raw Unified | Return to bug 934807
Collapse All | Expand All

(-)a/lib/std/zig/system.zig (-16 / +57 lines)
Lines 983-989 fn detectAbiAndDynamicLinker( Link Here
983
983
984
    // Best case scenario: the executable is dynamically linked, and we can iterate
984
    // Best case scenario: the executable is dynamically linked, and we can iterate
985
    // over our own shared objects and find a dynamic linker.
985
    // over our own shared objects and find a dynamic linker.
986
    const elf_file = blk: {
986
    const elf_file = elf_file: {
987
        // This block looks for a shebang line in /usr/bin/env,
987
        // This block looks for a shebang line in /usr/bin/env,
988
        // if it finds one, then instead of using /usr/bin/env as the ELF file to examine, it uses the file it references instead,
988
        // if it finds one, then instead of using /usr/bin/env as the ELF file to examine, it uses the file it references instead,
989
        // doing the same logic recursively in case it finds another shebang line.
989
        // doing the same logic recursively in case it finds another shebang line.
Lines 995-1003 fn detectAbiAndDynamicLinker( Link Here
995
            // Haiku does not have a /usr root directory.
995
            // Haiku does not have a /usr root directory.
996
            .haiku => "/bin/env",
996
            .haiku => "/bin/env",
997
        };
997
        };
998
        // #! (2) + 255 (max length of shebang line since Linux 5.1) + \n (1)
998
999
        var buffer: [258]u8 = undefined;
999
        // According to `man 2 execve`:
1000
        //
1001
        // The kernel imposes a maximum length on the text
1002
        // that follows the "#!" characters at the start of a script;
1003
        // characters beyond the limit are ignored.
1004
        // Before Linux 5.1, the limit is 127 characters.
1005
        // Since Linux 5.1, the limit is 255 characters.
1006
        //
1007
        // Tests show that bash and zsh consider 255 as total limit,
1008
        // *including* "#!" characters and ignoring newline.
1009
        // For safety, we set max length as 255 + \n (1).
1010
        var buffer: [255 + 1]u8 = undefined;
1000
        while (true) {
1011
        while (true) {
1012
            // Interpreter path can be relative on Linux, but
1013
            // for simplicity we are asserting it is an absolute path.
1001
            const file = fs.openFileAbsolute(file_name, .{}) catch |err| switch (err) {
1014
            const file = fs.openFileAbsolute(file_name, .{}) catch |err| switch (err) {
1002
                error.NoSpaceLeft => unreachable,
1015
                error.NoSpaceLeft => unreachable,
1003
                error.NameTooLong => unreachable,
1016
                error.NameTooLong => unreachable,
Lines 1027-1053 fn detectAbiAndDynamicLinker( Link Here
1027
1040
1028
                else => |e| return e,
1041
                else => |e| return e,
1029
            };
1042
            };
1030
            errdefer file.close();
1043
            var is_elf_file = false;
1031
1044
            defer if (is_elf_file == false) file.close();
1032
            const len = preadAtLeast(file, &buffer, 0, buffer.len) catch |err| switch (err) {
1045
1046
            // Shortest working interpreter path is "#!/i" (4)
1047
            // (interpreter is "/i", assuming all pathes are absolute, like in above comment).
1048
            // ELF magic number length is also 4.
1049
            //
1050
            // If file is shorter than that, it is definitely not ELF file
1051
            // nor file with "shebang" line.
1052
            const min_len: usize = 4;
1053
1054
            const len = preadAtLeast(file, &buffer, 0, min_len) catch |err| switch (err) {
1033
                error.UnexpectedEndOfFile,
1055
                error.UnexpectedEndOfFile,
1034
                error.UnableToReadElfFile,
1056
                error.UnableToReadElfFile,
1035
                => break :blk file,
1057
                => return defaultAbiAndDynamicLinker(cpu, os, query),
1036
1058
1037
                else => |e| return e,
1059
                else => |e| return e,
1038
            };
1060
            };
1039
            const newline = mem.indexOfScalar(u8, buffer[0..len], '\n') orelse break :blk file;
1061
            const content = buffer[0..len];
1040
            const line = buffer[0..newline];
1062
1041
            if (!mem.startsWith(u8, line, "#!")) break :blk file;
1063
            if (mem.eql(u8, content[0..4], std.elf.MAGIC)) {
1042
            var it = mem.tokenizeScalar(u8, line[2..], ' ');
1064
                // It is very likely ELF file!
1043
            file_name = it.next() orelse return defaultAbiAndDynamicLinker(cpu, os, query);
1065
                is_elf_file = true;
1044
            file.close();
1066
                break :elf_file file;
1067
            } else if (mem.eql(u8, content[0..2], "#!")) {
1068
                // We detected shebang, now parse entire line.
1069
1070
                // Trim leading "#!", spaces and tabs.
1071
                const trimmed_line = mem.trimLeft(u8, content[2..], &.{ ' ', '\t' });
1072
1073
                // This line can have:
1074
                // * Interpreter path only,
1075
                // * Interpreter path and arguments, all separated by space, tab or NUL character.
1076
                // And optionally newline at the end.
1077
                const path_maybe_args = mem.trimRight(u8, trimmed_line, "\n");
1078
1079
                // Separate path and args.
1080
                const path_end = mem.indexOfAny(u8, path_maybe_args, &.{ ' ', '\t', 0 }) orelse path_maybe_args.len;
1081
1082
                file_name = path_maybe_args[0..path_end];
1083
                continue;
1084
            } else {
1085
                // Not a ELF file, not a shell script with "shebang line", invalid duck.
1086
                return defaultAbiAndDynamicLinker(cpu, os, query);
1087
            }
1045
        }
1088
        }
1046
    };
1089
    };
1047
    defer elf_file.close();
1090
    defer elf_file.close();
1048
1091
1049
    // If Zig is statically linked, such as via distributed binary static builds, the above
1050
    // trick (block self_exe) won't work. The next thing we fall back to is the same thing, but for elf_file.
1051
    // TODO: inline this function and combine the buffer we already read above to find
1092
    // TODO: inline this function and combine the buffer we already read above to find
1052
    // the possible shebang line with the buffer we use for the ELF header.
1093
    // the possible shebang line with the buffer we use for the ELF header.
1053
    return abiAndDynamicLinkerFromFile(elf_file, cpu, os, ld_info_list, query) catch |err| switch (err) {
1094
    return abiAndDynamicLinkerFromFile(elf_file, cpu, os, ld_info_list, query) catch |err| switch (err) {
Lines 1075-1081 fn detectAbiAndDynamicLinker( Link Here
1075
    };
1116
    };
1076
}
1117
}
1077
1118
1078
fn defaultAbiAndDynamicLinker(cpu: Target.Cpu, os: Target.Os, query: Target.Query) !Target {
1119
fn defaultAbiAndDynamicLinker(cpu: Target.Cpu, os: Target.Os, query: Target.Query) Target {
1079
    const abi = query.abi orelse Target.Abi.default(cpu.arch, os);
1120
    const abi = query.abi orelse Target.Abi.default(cpu.arch, os);
1080
    return .{
1121
    return .{
1081
        .cpu = cpu,
1122
        .cpu = cpu,

Return to bug 934807