Commit 1544625df3

Luuk de Gram <luuk@degram.dev>
2022-08-19 21:15:16
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.
1 parent aca911c
Changed files (3)
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);
 }
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;
 
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;