From 1544625df3fb4732f2cd63d1e7c4c738d1b7d0c0 Mon Sep 17 00:00:00 2001 From: Luuk de Gram Date: Fri, 19 Aug 2022 21:15:16 +0200 Subject: [PATCH] wasm/Object: parse using the correct file size When an object file is being parsed from within an archive file, we provide the object file size to ensure we do not read past the object file. This is because follow up object files can exist there, as well as an LF character to notate the end of the file was reached. Such a character is invalid within the object file. This also fixes a bug in getting the function/global type for defined globals/functions from object files as it was missing the substraction with the import count of the respective type. --- src/link/Wasm.zig | 13 ++++++++----- src/link/Wasm/Archive.zig | 3 ++- src/link/Wasm/Object.zig | 23 +++++++++++++++++++++-- 3 files changed, 31 insertions(+), 8 deletions(-) diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 626f17665215bc3f93f6830ac60a0ce804dc95a0..37e25e436054a746ed0319a73d861079dfe4d2f9 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -378,7 +378,7 @@ fn parseObjectFile(self: *Wasm, path: []const u8) !bool { const file = try fs.cwd().openFile(path, .{}); errdefer file.close(); - var object = Object.create(self.base.allocator, file, path) catch |err| switch (err) { + var object = Object.create(self.base.allocator, file, path, null) catch |err| switch (err) { error.InvalidMagicByte, error.NotObjectFile => return false, else => |e| return e, }; @@ -595,8 +595,8 @@ fn resolveSymbolsInArchives(self: *Wasm) !void { // Parse object and and resolve symbols again before we check remaining // undefined symbols. const object_file_index = @intCast(u16, self.objects.items.len); - const object = try self.objects.addOne(self.base.allocator); - object.* = try archive.parseObject(self.base.allocator, offset.items[0]); + var object = try archive.parseObject(self.base.allocator, offset.items[0]); + try self.objects.append(self.base.allocator, object); try self.resolveSymbolsInObject(object_file_index); // continue loop for any remaining undefined symbols that still exist @@ -860,7 +860,8 @@ fn getGlobalType(self: *const Wasm, loc: SymbolLoc) wasm.GlobalType { if (is_undefined) { return obj.findImport(.global, symbol.index).kind.global; } - return obj.globals[symbol.index].global_type; + const import_global_count = obj.importedCountByKind(.global); + return obj.globals[symbol.index - import_global_count].global_type; } if (is_undefined) { return self.imports.get(loc).?.kind.global; @@ -880,7 +881,9 @@ fn getFunctionSignature(self: *const Wasm, loc: SymbolLoc) wasm.Type { const ty_index = obj.findImport(.function, symbol.index).kind.function; return obj.func_types[ty_index]; } - return obj.func_types[obj.functions[symbol.index].type_index]; + const import_function_count = obj.importedCountByKind(.function); + const type_index = obj.functions[symbol.index - import_function_count].type_index; + return obj.func_types[type_index]; } if (is_undefined) { const ty_index = self.imports.get(loc).?.kind.function; diff --git a/src/link/Wasm/Archive.zig b/src/link/Wasm/Archive.zig index 4a0abb1dfa9bb78fd73dd37c46f7f79f55b9d2ac..c80d26d17d8f99adf9da50d2bcb57502959c792a 100644 --- a/src/link/Wasm/Archive.zig +++ b/src/link/Wasm/Archive.zig @@ -218,6 +218,7 @@ pub fn parseObject(archive: Archive, allocator: Allocator, file_offset: u32) !Ob const object_file = try std.fs.cwd().openFile(archive.name, .{}); errdefer object_file.close(); + const object_file_size = try header.size(); try object_file.seekTo(current_offset); - return Object.create(allocator, object_file, name); + return Object.create(allocator, object_file, name, object_file_size); } diff --git a/src/link/Wasm/Object.zig b/src/link/Wasm/Object.zig index a1308ec0455a2b94362ada864277b110743c47c4..50827ca9fb8174cb97212c6b5f14f0df15783564 100644 --- a/src/link/Wasm/Object.zig +++ b/src/link/Wasm/Object.zig @@ -105,14 +105,33 @@ pub const InitError = error{NotObjectFile} || ParseError || std.fs.File.ReadErro /// Initializes a new `Object` from a wasm object file. /// This also parses and verifies the object file. -pub fn create(gpa: Allocator, file: std.fs.File, name: []const u8) InitError!Object { +/// When a max size is given, will only parse up to the given size, +/// else will read until the end of the file. +pub fn create(gpa: Allocator, file: std.fs.File, name: []const u8, maybe_max_size: ?usize) InitError!Object { var object: Object = .{ .file = file, .name = try gpa.dupe(u8, name), }; var is_object_file: bool = false; - try object.parse(gpa, file.reader(), &is_object_file); + const size = maybe_max_size orelse size: { + errdefer gpa.free(object.name); + const stat = try file.stat(); + break :size @intCast(usize, stat.size); + }; + + const file_contents = try gpa.alloc(u8, size); + defer gpa.free(file_contents); + var file_reader = file.reader(); + var read: usize = 0; + while (read < size) { + const n = try file_reader.read(file_contents[read..]); + std.debug.assert(n != 0); + read += n; + } + var fbs = std.io.fixedBufferStream(file_contents); + + try object.parse(gpa, fbs.reader(), &is_object_file); errdefer object.deinit(gpa); if (!is_object_file) return error.NotObjectFile; -- 2.54.0