mirror of
https://github.com/oven-sh/bun
synced 2026-02-02 15:08:46 +00:00
fix illegal memory reference in bun link (#2147)
This commit is contained in:
@@ -33,7 +33,7 @@ pub const FolderResolution = union(Tag) {
|
||||
return std.hash.Wyhash.hash(0, normalized_path);
|
||||
}
|
||||
|
||||
pub fn NewResolver(comptime tag: Resolution.Tag) type {
|
||||
fn NewResolver(comptime tag: Resolution.Tag) type {
|
||||
return struct {
|
||||
folder_path: string,
|
||||
|
||||
@@ -50,11 +50,10 @@ pub const FolderResolution = union(Tag) {
|
||||
};
|
||||
}
|
||||
|
||||
pub const Resolver = NewResolver(Resolution.Tag.folder);
|
||||
pub const SymlinkResolver = NewResolver(Resolution.Tag.symlink);
|
||||
pub const WorkspaceResolver = NewResolver(Resolution.Tag.workspace);
|
||||
pub const CacheFolderResolver = struct {
|
||||
folder_path: []const u8 = "",
|
||||
const Resolver = NewResolver(Resolution.Tag.folder);
|
||||
const SymlinkResolver = NewResolver(Resolution.Tag.symlink);
|
||||
const WorkspaceResolver = NewResolver(Resolution.Tag.workspace);
|
||||
const CacheFolderResolver = struct {
|
||||
version: Semver.Version,
|
||||
|
||||
pub fn resolve(this: @This(), comptime Builder: type, _: Builder, _: JSAst.Expr) !Resolution {
|
||||
@@ -182,14 +181,18 @@ pub const FolderResolution = union(Tag) {
|
||||
if (entry.found_existing) return entry.value_ptr.*;
|
||||
|
||||
const package: Lockfile.Package = switch (global_or_relative) {
|
||||
.global => readPackageJSONFromDisk(
|
||||
manager,
|
||||
abs,
|
||||
version,
|
||||
Features.link,
|
||||
SymlinkResolver,
|
||||
SymlinkResolver{ .folder_path = non_normalized_path },
|
||||
),
|
||||
.global => brk: {
|
||||
var path: [bun.MAX_PATH_BYTES]u8 = undefined;
|
||||
std.mem.copy(u8, &path, non_normalized_path);
|
||||
break :brk readPackageJSONFromDisk(
|
||||
manager,
|
||||
abs,
|
||||
version,
|
||||
Features.link,
|
||||
SymlinkResolver,
|
||||
SymlinkResolver{ .folder_path = path[0..non_normalized_path.len] },
|
||||
);
|
||||
},
|
||||
.relative => |tag| switch (tag) {
|
||||
.folder => readPackageJSONFromDisk(
|
||||
manager,
|
||||
|
||||
@@ -1,24 +1,35 @@
|
||||
import { spawn } from "bun";
|
||||
import { afterEach, beforeEach, expect, it } from "bun:test";
|
||||
import { afterAll, afterEach, beforeAll, beforeEach, expect, it } from "bun:test";
|
||||
import { bunExe } from "bunExe";
|
||||
import { bunEnv as env } from "bunEnv";
|
||||
import { mkdtemp, realpath, rm, writeFile } from "fs/promises";
|
||||
import { access, mkdtemp, readlink, realpath, rm, writeFile } from "fs/promises";
|
||||
import { basename, join } from "path";
|
||||
import { tmpdir } from "os";
|
||||
import {
|
||||
dummyAfterAll,
|
||||
dummyAfterEach,
|
||||
dummyBeforeAll,
|
||||
dummyBeforeEach,
|
||||
package_dir,
|
||||
readdirSorted,
|
||||
} from "./dummy.registry";
|
||||
|
||||
let package_dir, link_dir;
|
||||
beforeAll(dummyBeforeAll);
|
||||
afterAll(dummyAfterAll);
|
||||
|
||||
let link_dir;
|
||||
|
||||
beforeEach(async () => {
|
||||
link_dir = await mkdtemp(join(await realpath(tmpdir()), "bun-link.test"));
|
||||
package_dir = await mkdtemp(join(await realpath(tmpdir()), "bun-link.pkg"));
|
||||
await dummyBeforeEach();
|
||||
});
|
||||
afterEach(async () => {
|
||||
await rm(link_dir, { force: true, recursive: true });
|
||||
await rm(package_dir, { force: true, recursive: true });
|
||||
await dummyAfterEach();
|
||||
});
|
||||
|
||||
it("should link package", async () => {
|
||||
var link_name = basename(link_dir).slice("bun-link.".length);
|
||||
const link_name = basename(link_dir).slice("bun-link.".length);
|
||||
await writeFile(
|
||||
join(link_dir, "package.json"),
|
||||
JSON.stringify({
|
||||
@@ -114,13 +125,12 @@ it("should link package", async () => {
|
||||
const err4 = await new Response(stderr4).text();
|
||||
expect(err4).toContain(`error: package "${link_name}" is not linked`);
|
||||
expect(stdout4).toBeDefined();
|
||||
const out4 = await new Response(stdout4).text();
|
||||
expect(await new Response(stdout4).text()).toBe("");
|
||||
expect(await exited4).toBe(1);
|
||||
});
|
||||
|
||||
it("should link scoped package", async () => {
|
||||
var link_name = `@${basename(link_dir).slice("bun-link.".length)}/foo`;
|
||||
const link_name = `@${basename(link_dir).slice("bun-link.".length)}/foo`;
|
||||
await writeFile(
|
||||
join(link_dir, "package.json"),
|
||||
JSON.stringify({
|
||||
@@ -216,7 +226,121 @@ it("should link scoped package", async () => {
|
||||
const err4 = await new Response(stderr4).text();
|
||||
expect(err4).toContain(`error: package "${link_name}" is not linked`);
|
||||
expect(stdout4).toBeDefined();
|
||||
const out4 = await new Response(stdout4).text();
|
||||
expect(await new Response(stdout4).text()).toBe("");
|
||||
expect(await exited4).toBe(1);
|
||||
});
|
||||
|
||||
it("should link dependency without crashing", async () => {
|
||||
const link_name = basename(link_dir).slice("bun-link.".length) + "-really-long-name";
|
||||
await writeFile(
|
||||
join(link_dir, "package.json"),
|
||||
JSON.stringify({
|
||||
name: link_name,
|
||||
version: "0.0.1",
|
||||
bin: {
|
||||
[link_name]: `${link_name}.js`,
|
||||
},
|
||||
}),
|
||||
);
|
||||
await writeFile(join(link_dir, `${link_name}.js`), "console.log(42);");
|
||||
await writeFile(
|
||||
join(package_dir, "package.json"),
|
||||
JSON.stringify({
|
||||
name: "foo",
|
||||
version: "0.0.2",
|
||||
dependencies: {
|
||||
[link_name]: `link:${link_name}`,
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
const {
|
||||
stdout: stdout1,
|
||||
stderr: stderr1,
|
||||
exited: exited1,
|
||||
} = spawn({
|
||||
cmd: [bunExe(), "link"],
|
||||
cwd: link_dir,
|
||||
stdout: null,
|
||||
stdin: "pipe",
|
||||
stderr: "pipe",
|
||||
env,
|
||||
});
|
||||
expect(stderr1).toBeDefined();
|
||||
const err1 = await new Response(stderr1).text();
|
||||
expect(err1.replace(/^(.*?) v[^\n]+/, "$1").split(/\r?\n/)).toEqual(["bun link", ""]);
|
||||
expect(stdout1).toBeDefined();
|
||||
expect(await new Response(stdout1).text()).toContain(`Success! Registered \\"${link_name}\\"`);
|
||||
expect(await exited1).toBe(0);
|
||||
|
||||
const {
|
||||
stdout: stdout2,
|
||||
stderr: stderr2,
|
||||
exited: exited2,
|
||||
} = spawn({
|
||||
cmd: [bunExe(), "install", "--config", import.meta.dir + "/basic.toml"],
|
||||
cwd: package_dir,
|
||||
stdout: null,
|
||||
stdin: "pipe",
|
||||
stderr: "pipe",
|
||||
env,
|
||||
});
|
||||
expect(stderr2).toBeDefined();
|
||||
const err2 = await new Response(stderr2).text();
|
||||
expect(err2.replace(/^(.*?) v[^\n]+/, "$1").split(/\r?\n/)).toEqual(["bun install", " Saved lockfile", ""]);
|
||||
expect(stdout2).toBeDefined();
|
||||
const out2 = await new Response(stdout2).text();
|
||||
expect(out2.replace(/\s*\[[0-9\.]+ms\]\s*$/, "").split(/\r?\n/)).toEqual([
|
||||
` + ${link_name}@link:${link_name}`,
|
||||
"",
|
||||
" 1 packages installed",
|
||||
]);
|
||||
expect(await exited2).toBe(0);
|
||||
expect(await readdirSorted(join(package_dir, "node_modules"))).toEqual([".bin", ".cache", link_name].sort());
|
||||
expect(await readdirSorted(join(package_dir, "node_modules", ".bin"))).toEqual([link_name]);
|
||||
expect(await readlink(join(package_dir, "node_modules", ".bin", link_name))).toBe(
|
||||
join("..", link_name, `${link_name}.js`),
|
||||
);
|
||||
expect(await readdirSorted(join(package_dir, "node_modules", link_name))).toEqual(
|
||||
["package.json", `${link_name}.js`].sort(),
|
||||
);
|
||||
await access(join(package_dir, "bun.lockb"));
|
||||
|
||||
const {
|
||||
stdout: stdout3,
|
||||
stderr: stderr3,
|
||||
exited: exited3,
|
||||
} = spawn({
|
||||
cmd: [bunExe(), "unlink"],
|
||||
cwd: link_dir,
|
||||
stdout: null,
|
||||
stdin: "pipe",
|
||||
stderr: "pipe",
|
||||
env,
|
||||
});
|
||||
expect(stderr3).toBeDefined();
|
||||
const err3 = await new Response(stderr3).text();
|
||||
expect(err3.replace(/^(.*?) v[^\n]+/, "$1").split(/\r?\n/)).toEqual(["bun unlink", ""]);
|
||||
expect(stdout3).toBeDefined();
|
||||
expect(await new Response(stdout3).text()).toContain(`success: unlinked package "${link_name}"`);
|
||||
expect(await exited3).toBe(0);
|
||||
|
||||
const {
|
||||
stdout: stdout4,
|
||||
stderr: stderr4,
|
||||
exited: exited4,
|
||||
} = spawn({
|
||||
cmd: [bunExe(), "install"],
|
||||
cwd: package_dir,
|
||||
stdout: null,
|
||||
stdin: "pipe",
|
||||
stderr: "pipe",
|
||||
env,
|
||||
});
|
||||
expect(stderr4).toBeDefined();
|
||||
const err4 = await new Response(stderr4).text();
|
||||
expect(err4).toContain(`error: FileNotFound installing ${link_name}`);
|
||||
expect(stdout4).toBeDefined();
|
||||
expect(await new Response(stdout4).text()).toBe("");
|
||||
expect(await exited4).toBe(0);
|
||||
});
|
||||
|
||||
BIN
test/fixtures/bun-link-to-pkg-fixture/bun.lockb
vendored
BIN
test/fixtures/bun-link-to-pkg-fixture/bun.lockb
vendored
Binary file not shown.
Reference in New Issue
Block a user