| author | |
| committer | |
| log | 1544625df3fb4732f2cd63d1e7c4c738d1b7d0c0 |
| tree | 9daf0a93df0113b19f2f0747ca7a645b2123feec |
| parent | aca911ca18d43fddcc3d36f44d3750d07b53fb56 |
| signature |
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(); |
| 380 | 380 | ||
| 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 remaining | 595 | // 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); |
| 601 | 601 | ||
| 602 | // continue loop for any remaining undefined symbols that still exist | 602 | // 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(); |
| 220 | 220 | ||
| 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 |
| 105 | 105 | ||
| 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. |
| 108 | pub 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. | ||
| 110 | pub 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 | }; |
| 113 | 115 | ||
| 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; |
| 118 | 137 |