authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-08-19 21:15:16+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-08-20 14:50:11+02:00
log1544625df3fb4732f2cd63d1e7c4c738d1b7d0c0
tree9daf0a93df0113b19f2f0747ca7a645b2123feec
parentaca911ca18d43fddcc3d36f44d3750d07b53fb56
signaturelock-open Commit is signed but in an unrecognized format.

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.

3 files changed, 31 insertions(+), 8 deletions(-)

src/link/Wasm.zig+8-5
......@@ -378,7 +378,7 @@ fn parseObjectFile(self: *Wasm, path: []const u8) !bool {
378378 const file = try fs.cwd().openFile(path, .{});
379379 errdefer file.close();
380380
381 var object = Object.create(self.base.allocator, file, path) catch |err| switch (err) {
381 var object = Object.create(self.base.allocator, file, path, null) catch |err| switch (err) {
382382 error.InvalidMagicByte, error.NotObjectFile => return false,
383383 else => |e| return e,
384384 };
......@@ -595,8 +595,8 @@ fn resolveSymbolsInArchives(self: *Wasm) !void {
595595 // Parse object and and resolve symbols again before we check remaining
596596 // undefined symbols.
597597 const object_file_index = @intCast(u16, self.objects.items.len);
598 const object = try self.objects.addOne(self.base.allocator);
599 object.* = try archive.parseObject(self.base.allocator, offset.items[0]);
598 var object = try archive.parseObject(self.base.allocator, offset.items[0]);
599 try self.objects.append(self.base.allocator, object);
600600 try self.resolveSymbolsInObject(object_file_index);
601601
602602 // continue loop for any remaining undefined symbols that still exist
......@@ -860,7 +860,8 @@ fn getGlobalType(self: *const Wasm, loc: SymbolLoc) wasm.GlobalType {
860860 if (is_undefined) {
861861 return obj.findImport(.global, symbol.index).kind.global;
862862 }
863 return obj.globals[symbol.index].global_type;
863 const import_global_count = obj.importedCountByKind(.global);
864 return obj.globals[symbol.index - import_global_count].global_type;
864865 }
865866 if (is_undefined) {
866867 return self.imports.get(loc).?.kind.global;
......@@ -880,7 +881,9 @@ fn getFunctionSignature(self: *const Wasm, loc: SymbolLoc) wasm.Type {
880881 const ty_index = obj.findImport(.function, symbol.index).kind.function;
881882 return obj.func_types[ty_index];
882883 }
883 return obj.func_types[obj.functions[symbol.index].type_index];
884 const import_function_count = obj.importedCountByKind(.function);
885 const type_index = obj.functions[symbol.index - import_function_count].type_index;
886 return obj.func_types[type_index];
884887 }
885888 if (is_undefined) {
886889 const ty_index = self.imports.get(loc).?.kind.function;
src/link/Wasm/Archive.zig+2-1
......@@ -218,6 +218,7 @@ pub fn parseObject(archive: Archive, allocator: Allocator, file_offset: u32) !Ob
218218 const object_file = try std.fs.cwd().openFile(archive.name, .{});
219219 errdefer object_file.close();
220220
221 const object_file_size = try header.size();
221222 try object_file.seekTo(current_offset);
222 return Object.create(allocator, object_file, name);
223 return Object.create(allocator, object_file, name, object_file_size);
223224}
src/link/Wasm/Object.zig+21-2
......@@ -105,14 +105,33 @@ pub const InitError = error{NotObjectFile} || ParseError || std.fs.File.ReadErro
105105
106106/// Initializes a new `Object` from a wasm object file.
107107/// This also parses and verifies the object file.
108pub fn create(gpa: Allocator, file: std.fs.File, name: []const u8) InitError!Object {
108/// When a max size is given, will only parse up to the given size,
109/// else will read until the end of the file.
110pub fn create(gpa: Allocator, file: std.fs.File, name: []const u8, maybe_max_size: ?usize) InitError!Object {
109111 var object: Object = .{
110112 .file = file,
111113 .name = try gpa.dupe(u8, name),
112114 };
113115
114116 var is_object_file: bool = false;
115 try object.parse(gpa, file.reader(), &is_object_file);
117 const size = maybe_max_size orelse size: {
118 errdefer gpa.free(object.name);
119 const stat = try file.stat();
120 break :size @intCast(usize, stat.size);
121 };
122
123 const file_contents = try gpa.alloc(u8, size);
124 defer gpa.free(file_contents);
125 var file_reader = file.reader();
126 var read: usize = 0;
127 while (read < size) {
128 const n = try file_reader.read(file_contents[read..]);
129 std.debug.assert(n != 0);
130 read += n;
131 }
132 var fbs = std.io.fixedBufferStream(file_contents);
133
134 try object.parse(gpa, fbs.reader(), &is_object_file);
116135 errdefer object.deinit(gpa);
117136 if (!is_object_file) return error.NotObjectFile;
118137