diff options
author | 2023-09-24 11:09:45 +0800 | |
---|---|---|
committer | 2023-09-23 20:09:45 -0700 | |
commit | a5908e9f2704f801587115007c2bec5788bd718a (patch) | |
tree | 5ef841abad46365ac826135291b011d43694b1dd | |
parent | 72f9017b21cbb6de83d054a0b985e9fe9a7708f3 (diff) | |
download | bun-a5908e9f2704f801587115007c2bec5788bd718a.tar.gz bun-a5908e9f2704f801587115007c2bec5788bd718a.tar.zst bun-a5908e9f2704f801587115007c2bec5788bd718a.zip |
fix(lockfile): ensure all bytes of union are initialized before serialization. (#5957)
-rw-r--r-- | src/install/bin.zig | 41 | ||||
-rw-r--r-- | test/cli/install/bun-update.test.ts | 65 |
2 files changed, 87 insertions, 19 deletions
diff --git a/src/install/bin.zig b/src/install/bin.zig index 0a8d62c8c..7c429f5d0 100644 --- a/src/install/bin.zig +++ b/src/install/bin.zig @@ -20,7 +20,7 @@ pub const Bin = extern struct { tag: Tag = Tag.none, _padding_tag: [3]u8 = .{0} ** 3, - value: Value = Value{ .none = {} }, + value: Value = std.mem.zeroes(Value), pub fn verify(this: *const Bin, extern_strings: []const ExternalString) void { if (comptime !Environment.allow_assert) @@ -67,36 +67,41 @@ pub const Bin = extern struct { } pub fn clone(this: *const Bin, buf: []const u8, prev_external_strings: []const ExternalString, all_extern_strings: []ExternalString, extern_strings_slice: []ExternalString, comptime StringBuilder: type, builder: StringBuilder) Bin { - return switch (this.tag) { - .none => Bin{ .tag = .none, .value = .{ .none = {} } }, - .file => Bin{ - .tag = .file, - .value = .{ .file = builder.append(String, this.value.file.slice(buf)) }, + var cloned: Bin = Bin{}; + @memset(std.mem.asBytes(&cloned), 0); + + switch (this.tag) { + .none => { + cloned.tag = .none; + cloned.value.none = {}; + }, + .file => { + cloned.tag = .file; + cloned.value = .{ .file = builder.append(String, this.value.file.slice(buf)) }; }, - .named_file => Bin{ - .tag = .named_file, - .value = .{ + .named_file => { + cloned.tag = .named_file; + cloned.value = .{ .named_file = [2]String{ builder.append(String, this.value.named_file[0].slice(buf)), builder.append(String, this.value.named_file[1].slice(buf)), }, - }, + }; }, - .dir => Bin{ - .tag = .dir, - .value = .{ .dir = builder.append(String, this.value.dir.slice(buf)) }, + .dir => { + cloned.tag = .dir; + cloned.value = .{ .dir = builder.append(String, this.value.dir.slice(buf)) }; }, .map => { for (this.value.map.get(prev_external_strings), 0..) |extern_string, i| { extern_strings_slice[i] = builder.append(ExternalString, extern_string.slice(buf)); } - return .{ - .tag = .map, - .value = .{ .map = ExternalStringList.init(all_extern_strings, extern_strings_slice) }, - }; + cloned.tag = .map; + cloned.value = .{ .map = ExternalStringList.init(all_extern_strings, extern_strings_slice) }; }, - }; + } + return cloned; } pub const Value = extern union { diff --git a/test/cli/install/bun-update.test.ts b/test/cli/install/bun-update.test.ts index ff8e22c37..8434ca470 100644 --- a/test/cli/install/bun-update.test.ts +++ b/test/cli/install/bun-update.test.ts @@ -1,7 +1,7 @@ import { file, listen, Socket, spawn } from "bun"; import { afterAll, afterEach, beforeAll, beforeEach, expect, it } from "bun:test"; import { bunExe, bunEnv as env } from "harness"; -import { access, mkdir, readlink, realpath, rm, writeFile } from "fs/promises"; +import { readFile, access, mkdir, readlink, realpath, rm, writeFile } from "fs/promises"; import { join } from "path"; import { dummyAfterAll, @@ -257,3 +257,66 @@ it("should update to latest versions of dependencies", async () => { }); await access(join(package_dir, "bun.lockb")); }); + +it("lockfile should not be modified when there are no version changes, issue#5888", async () => { + // Install packages + const urls: string[] = []; + const registry = { + "0.0.3": { + bin: { + "baz-run": "index.js", + }, + }, + latest: "0.0.3", + }; + setHandler(dummyRegistry(urls, registry)); + await writeFile( + join(package_dir, "package.json"), + JSON.stringify({ + name: "foo", + dependencies: { + baz: "0.0.3", + }, + }), + ); + const { stdout, stderr, exited } = spawn({ + cmd: [bunExe(), "install"], + cwd: package_dir, + stdout: null, + stdin: "pipe", + stderr: "pipe", + env, + }); + expect(await exited).toBe(0); + const err1 = await new Response(stderr).text(); + expect(err1).not.toContain("error:"); + expect(err1).toContain("Saved lockfile"); + expect(stdout).toBeDefined(); + const out1 = await new Response(stdout).text(); + expect(out1.replace(/\s*\[[0-9\.]+m?s\]\s*$/, "").split(/\r?\n/)).toEqual([ + " + baz@0.0.3", + "", + " 1 packages installed", + ]); + + // Test if the lockb has been modified by `bun update`. + const getLockbContent = async () => { + const { exited } = spawn({ + cmd: [bunExe(), "update"], + cwd: package_dir, // package.json is not changed + stdout: null, + stdin: "pipe", + stderr: "pipe", + env, + }); + expect(await exited).toBe(0); + return await readFile(join(package_dir, "bun.lockb")); + }; + + let prev = await getLockbContent(); + for (let i = 0; i < 5; i++) { + const content = await getLockbContent(); + expect(prev).toStrictEqual(content); + prev = content; + } +}); |