elf: do not write ELF header if there were errors

This commit is contained in:
Jakub Konka 2023-12-05 13:49:55 +01:00
parent af8621db2d
commit 3f42ed3ca2
2 changed files with 70 additions and 70 deletions

View File

@ -1041,9 +1041,14 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
}
for (positionals.items) |obj| {
var parse_ctx: ParseErrorCtx = .{ .detected_cpu_arch = undefined };
self.parsePositional(obj.path, obj.must_link, &parse_ctx) catch |err|
try self.handleAndReportParseError(obj.path, err, &parse_ctx);
self.parsePositional(obj.path, obj.must_link) catch |err| switch (err) {
error.LinkFail, error.InvalidCpuArch => {}, // already reported
else => |e| try self.reportParseError(
obj.path,
"unexpected error: parsing input file failed with error {s}",
.{@errorName(e)},
),
};
}
var system_libs = std.ArrayList(SystemLib).init(arena);
@ -1122,9 +1127,14 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
}
for (system_libs.items) |lib| {
var parse_ctx: ParseErrorCtx = .{ .detected_cpu_arch = undefined };
self.parseLibrary(lib, false, &parse_ctx) catch |err|
try self.handleAndReportParseError(lib.path, err, &parse_ctx);
self.parseLibrary(lib, false) catch |err| switch (err) {
error.LinkFail, error.InvalidCpuArch => {}, // already reported
else => |e| try self.reportParseError(
lib.path,
"unexpected error: parsing library failed with error {s}",
.{@errorName(e)},
),
};
}
// Finally, as the last input objects we add compiler_rt and CSU postlude (if any).
@ -1140,9 +1150,14 @@ pub fn flushModule(self: *Elf, comp: *Compilation, prog_node: *std.Progress.Node
if (csu.crtn) |v| try positionals.append(.{ .path = v });
for (positionals.items) |obj| {
var parse_ctx: ParseErrorCtx = .{ .detected_cpu_arch = undefined };
self.parsePositional(obj.path, obj.must_link, &parse_ctx) catch |err|
try self.handleAndReportParseError(obj.path, err, &parse_ctx);
self.parsePositional(obj.path, obj.must_link) catch |err| switch (err) {
error.LinkFail, error.InvalidCpuArch => {}, // already reported
else => |e| try self.reportParseError(
obj.path,
"unexpected error: parsing input file failed with error {s}",
.{@errorName(e)},
),
};
}
// Init all objects
@ -1300,9 +1315,14 @@ pub fn flushStaticLib(self: *Elf, comp: *Compilation, module_obj_path: ?[]const
if (module_obj_path) |path| try positionals.append(.{ .path = path });
for (positionals.items) |obj| {
var parse_ctx: ParseErrorCtx = .{ .detected_cpu_arch = undefined };
self.parsePositional(obj.path, obj.must_link, &parse_ctx) catch |err|
try self.handleAndReportParseError(obj.path, err, &parse_ctx);
self.parsePositional(obj.path, obj.must_link) catch |err| switch (err) {
error.LinkFail, error.InvalidCpuArch => {}, // already reported
else => |e| try self.reportParseError(
obj.path,
"unexpected error: parsing input file failed with error {s}",
.{@errorName(e)},
),
};
}
// First, we flush relocatable object file generated with our backends.
@ -1432,9 +1452,14 @@ pub fn flushObject(self: *Elf, comp: *Compilation, module_obj_path: ?[]const u8)
if (module_obj_path) |path| try positionals.append(.{ .path = path });
for (positionals.items) |obj| {
var parse_ctx: ParseErrorCtx = .{ .detected_cpu_arch = undefined };
self.parsePositional(obj.path, obj.must_link, &parse_ctx) catch |err|
try self.handleAndReportParseError(obj.path, err, &parse_ctx);
self.parsePositional(obj.path, obj.must_link) catch |err| switch (err) {
error.LinkFail, error.InvalidCpuArch => {}, // already reported
else => |e| try self.reportParseError(
obj.path,
"unexpected error: parsing input file failed with error {s}",
.{@errorName(e)},
),
};
}
// Init all objects
@ -1770,37 +1795,36 @@ const ParseError = error{
FileSystem,
NotSupported,
InvalidCharacter,
MalformedObject,
} || LdScript.Error || std.os.AccessError || std.os.SeekError || std.fs.File.OpenError || std.fs.File.ReadError;
fn parsePositional(self: *Elf, path: []const u8, must_link: bool, ctx: *ParseErrorCtx) ParseError!void {
fn parsePositional(self: *Elf, path: []const u8, must_link: bool) ParseError!void {
const tracy = trace(@src());
defer tracy.end();
if (try Object.isObject(path)) {
try self.parseObject(path, ctx);
try self.parseObject(path);
} else {
try self.parseLibrary(.{ .path = path }, must_link, ctx);
try self.parseLibrary(.{ .path = path }, must_link);
}
}
fn parseLibrary(self: *Elf, lib: SystemLib, must_link: bool, ctx: *ParseErrorCtx) ParseError!void {
fn parseLibrary(self: *Elf, lib: SystemLib, must_link: bool) ParseError!void {
const tracy = trace(@src());
defer tracy.end();
if (try Archive.isArchive(lib.path)) {
try self.parseArchive(lib.path, must_link, ctx);
try self.parseArchive(lib.path, must_link);
} else if (try SharedObject.isSharedObject(lib.path)) {
try self.parseSharedObject(lib, ctx);
try self.parseSharedObject(lib);
} else {
// TODO if the script has a top-level comment identifying it as GNU ld script,
// then report parse errors. Otherwise return UnknownFileType.
self.parseLdScript(lib, ctx) catch |err| switch (err) {
self.parseLdScript(lib) catch |err| switch (err) {
else => return error.UnknownFileType,
};
}
}
fn parseObject(self: *Elf, path: []const u8, ctx: *ParseErrorCtx) ParseError!void {
fn parseObject(self: *Elf, path: []const u8) ParseError!void {
const tracy = trace(@src());
defer tracy.end();
@ -1818,12 +1842,9 @@ fn parseObject(self: *Elf, path: []const u8, ctx: *ParseErrorCtx) ParseError!voi
const object = self.file(index).?.object;
try object.parse(self);
ctx.detected_cpu_arch = object.header.?.e_machine.toTargetCpuArch().?;
if (ctx.detected_cpu_arch != self.base.options.target.cpu.arch) return error.InvalidCpuArch;
}
fn parseArchive(self: *Elf, path: []const u8, must_link: bool, ctx: *ParseErrorCtx) ParseError!void {
fn parseArchive(self: *Elf, path: []const u8, must_link: bool) ParseError!void {
const tracy = trace(@src());
defer tracy.end();
@ -1846,13 +1867,10 @@ fn parseArchive(self: *Elf, path: []const u8, must_link: bool, ctx: *ParseErrorC
object.alive = must_link;
try object.parse(self);
try self.objects.append(gpa, index);
ctx.detected_cpu_arch = object.header.?.e_machine.toTargetCpuArch().?;
if (ctx.detected_cpu_arch != self.base.options.target.cpu.arch) return error.InvalidCpuArch;
}
}
fn parseSharedObject(self: *Elf, lib: SystemLib, ctx: *ParseErrorCtx) ParseError!void {
fn parseSharedObject(self: *Elf, lib: SystemLib) ParseError!void {
const tracy = trace(@src());
defer tracy.end();
@ -1872,12 +1890,9 @@ fn parseSharedObject(self: *Elf, lib: SystemLib, ctx: *ParseErrorCtx) ParseError
const shared_object = self.file(index).?.shared_object;
try shared_object.parse(self);
ctx.detected_cpu_arch = shared_object.header.?.e_machine.toTargetCpuArch().?;
if (ctx.detected_cpu_arch != self.base.options.target.cpu.arch) return error.InvalidCpuArch;
}
fn parseLdScript(self: *Elf, lib: SystemLib, ctx: *ParseErrorCtx) ParseError!void {
fn parseLdScript(self: *Elf, lib: SystemLib) ParseError!void {
const tracy = trace(@src());
defer tracy.end();
@ -1891,11 +1906,6 @@ fn parseLdScript(self: *Elf, lib: SystemLib, ctx: *ParseErrorCtx) ParseError!voi
defer script.deinit(gpa);
try script.parse(data, self);
if (script.cpu_arch) |cpu_arch| {
ctx.detected_cpu_arch = cpu_arch;
if (ctx.detected_cpu_arch != self.base.options.target.cpu.arch) return error.InvalidCpuArch;
}
const lib_dirs = self.base.options.lib_dirs;
var arena_allocator = std.heap.ArenaAllocator.init(gpa);
@ -1949,11 +1959,17 @@ fn parseLdScript(self: *Elf, lib: SystemLib, ctx: *ParseErrorCtx) ParseError!voi
}
const full_path = test_path.items;
var scr_ctx: ParseErrorCtx = .{ .detected_cpu_arch = undefined };
self.parseLibrary(.{
.needed = scr_obj.needed,
.path = full_path,
}, false, &scr_ctx) catch |err| try self.handleAndReportParseError(full_path, err, &scr_ctx);
}, false) catch |err| switch (err) {
error.LinkFail, error.InvalidCpuArch => {}, // already reported
else => |e| try self.reportParseError(
full_path,
"unexpected error: parsing library failed with error {s}",
.{@errorName(e)},
),
};
}
}
@ -3009,6 +3025,8 @@ fn writePhdrTable(self: *Elf) !void {
}
fn writeElfHeader(self: *Elf) !void {
if (self.misc_errors.items.len > 0) return; // We had errors, so skip flushing to render the output unusable
var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 = undefined;
var index: usize = 0;
@ -6047,33 +6065,6 @@ fn reportMissingLibraryError(
}
}
const ParseErrorCtx = struct {
detected_cpu_arch: std.Target.Cpu.Arch,
};
fn handleAndReportParseError(
self: *Elf,
path: []const u8,
err: ParseError,
ctx: *const ParseErrorCtx,
) error{OutOfMemory}!void {
const cpu_arch = self.base.options.target.cpu.arch;
switch (err) {
error.LinkFail => {}, // already reported
error.UnknownFileType => try self.reportParseError(path, "unknown file type", .{}),
error.InvalidCpuArch => try self.reportParseError(
path,
"invalid cpu architecture: expected '{s}', but found '{s}'",
.{ @tagName(cpu_arch), @tagName(ctx.detected_cpu_arch) },
),
else => |e| try self.reportParseError(
path,
"unexpected error: parsing object failed with error {s}",
.{@errorName(e)},
),
}
}
fn reportParseError(
self: *Elf,
path: []const u8,

View File

@ -54,6 +54,15 @@ pub fn parse(self: *Object, elf_file: *Elf) !void {
self.header = try reader.readStruct(elf.Elf64_Ehdr);
if (elf_file.base.options.target.cpu.arch != self.header.?.e_machine.toTargetCpuArch().?) {
try elf_file.reportParseError2(
self.index,
"invalid cpu architecture: {s}",
.{@tagName(self.header.?.e_machine.toTargetCpuArch().?)},
);
return error.InvalidCpuArch;
}
if (self.header.?.e_shnum == 0) return;
const gpa = elf_file.base.allocator;