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 {...@@ -378,7 +378,7 @@ fn parseObjectFile(self: *Wasm, path: []const u8) !bool {
378 const file = try fs.cwd().openFile(path, .{});378 const file = try fs.cwd().openFile(path, .{});
379 errdefer file.close();379 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) {
382 error.InvalidMagicByte, error.NotObjectFile => return false,382 error.InvalidMagicByte, error.NotObjectFile => return false,
383 else => |e| return e,383 else => |e| return e,
384 };384 };
...@@ -595,8 +595,8 @@ fn resolveSymbolsInArchives(self: *Wasm) !void {...@@ -595,8 +595,8 @@ fn resolveSymbolsInArchives(self: *Wasm) !void {
595 // Parse object and and resolve symbols again before we check remaining595 // Parse object and and resolve symbols again before we check remaining
596 // undefined symbols.596 // undefined symbols.
597 const object_file_index = @intCast(u16, self.objects.items.len);597 const object_file_index = @intCast(u16, self.objects.items.len);
598 const object = try self.objects.addOne(self.base.allocator);598 var object = try archive.parseObject(self.base.allocator, offset.items[0]);
599 object.* = try archive.parseObject(self.base.allocator, offset.items[0]);599 try self.objects.append(self.base.allocator, object);
600 try self.resolveSymbolsInObject(object_file_index);600 try self.resolveSymbolsInObject(object_file_index);
601601
602 // continue loop for any remaining undefined symbols that still exist602 // continue loop for any remaining undefined symbols that still exist
...@@ -860,7 +860,8 @@ fn getGlobalType(self: *const Wasm, loc: SymbolLoc) wasm.GlobalType {...@@ -860,7 +860,8 @@ fn getGlobalType(self: *const Wasm, loc: SymbolLoc) wasm.GlobalType {
860 if (is_undefined) {860 if (is_undefined) {
861 return obj.findImport(.global, symbol.index).kind.global;861 return obj.findImport(.global, symbol.index).kind.global;
862 }862 }
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;
864 }865 }
865 if (is_undefined) {866 if (is_undefined) {
866 return self.imports.get(loc).?.kind.global;867 return self.imports.get(loc).?.kind.global;
...@@ -880,7 +881,9 @@ fn getFunctionSignature(self: *const Wasm, loc: SymbolLoc) wasm.Type {...@@ -880,7 +881,9 @@ fn getFunctionSignature(self: *const Wasm, loc: SymbolLoc) wasm.Type {
880 const ty_index = obj.findImport(.function, symbol.index).kind.function;881 const ty_index = obj.findImport(.function, symbol.index).kind.function;
881 return obj.func_types[ty_index];882 return obj.func_types[ty_index];
882 }883 }
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];
884 }887 }
885 if (is_undefined) {888 if (is_undefined) {
886 const ty_index = self.imports.get(loc).?.kind.function;889 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...@@ -218,6 +218,7 @@ pub fn parseObject(archive: Archive, allocator: Allocator, file_offset: u32) !Ob
218 const object_file = try std.fs.cwd().openFile(archive.name, .{});218 const object_file = try std.fs.cwd().openFile(archive.name, .{});
219 errdefer object_file.close();219 errdefer object_file.close();
220220
221 const object_file_size = try header.size();
221 try object_file.seekTo(current_offset);222 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);
223}224}
src/link/Wasm/Object.zig+21-2
...@@ -105,14 +105,33 @@ pub const InitError = error{NotObjectFile} || ParseError || std.fs.File.ReadErro...@@ -105,14 +105,33 @@ pub const InitError = error{NotObjectFile} || ParseError || std.fs.File.ReadErro
105105
106/// Initializes a new `Object` from a wasm object file.106/// Initializes a new `Object` from a wasm object file.
107/// This also parses and verifies the object file.107/// 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 {
109 var object: Object = .{111 var object: Object = .{
110 .file = file,112 .file = file,
111 .name = try gpa.dupe(u8, name),113 .name = try gpa.dupe(u8, name),
112 };114 };
113115
114 var is_object_file: bool = false;116 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);
116 errdefer object.deinit(gpa);135 errdefer object.deinit(gpa);
117 if (!is_object_file) return error.NotObjectFile;136 if (!is_object_file) return error.NotObjectFile;
118137