Skip to content

Commit 64cb06f

Browse files
committed
fix-range-error
1 parent e8858f8 commit 64cb06f

File tree

2 files changed

+33
-5
lines changed

2 files changed

+33
-5
lines changed

src/BashEnv.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,15 @@ export class BashEnv {
298298
env: { ...this.state.env, ...options?.env },
299299
};
300300
}
301+
// RangeError occurs when JavaScript call stack is exceeded (deep recursion)
302+
if (error instanceof RangeError) {
303+
return {
304+
stdout: "",
305+
stderr: `bash: ${error.message}\n`,
306+
exitCode: 1,
307+
env: { ...this.state.env, ...options?.env },
308+
};
309+
}
301310
throw error;
302311
}
303312
}

src/overlay-fs/OverlayFs.ts

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -343,9 +343,20 @@ export class OverlayFs implements IFileSystem {
343343
return fromBuffer(buffer, encoding);
344344
}
345345

346-
async readFileBuffer(path: string): Promise<Uint8Array> {
346+
async readFileBuffer(
347+
path: string,
348+
seen: Set<string> = new Set(),
349+
): Promise<Uint8Array> {
347350
const normalized = this.normalizePath(path);
348351

352+
// Detect symlink loops
353+
if (seen.has(normalized)) {
354+
throw new Error(
355+
`ELOOP: too many levels of symbolic links, open '${path}'`,
356+
);
357+
}
358+
seen.add(normalized);
359+
349360
// Check if deleted
350361
if (this.deleted.has(normalized)) {
351362
throw new Error(`ENOENT: no such file or directory, open '${path}'`);
@@ -356,7 +367,7 @@ export class OverlayFs implements IFileSystem {
356367
if (memEntry) {
357368
if (memEntry.type === "symlink") {
358369
const target = this.resolveSymlink(normalized, memEntry.target);
359-
return this.readFileBuffer(target);
370+
return this.readFileBuffer(target, seen);
360371
}
361372
if (memEntry.type !== "file") {
362373
throw new Error(
@@ -377,7 +388,7 @@ export class OverlayFs implements IFileSystem {
377388
if (stat.isSymbolicLink()) {
378389
const target = await fs.promises.readlink(realPath);
379390
const resolvedTarget = this.resolveSymlink(normalized, target);
380-
return this.readFileBuffer(resolvedTarget);
391+
return this.readFileBuffer(resolvedTarget, seen);
381392
}
382393
if (stat.isDirectory()) {
383394
throw new Error(
@@ -451,9 +462,17 @@ export class OverlayFs implements IFileSystem {
451462
return this.existsInOverlay(path);
452463
}
453464

454-
async stat(path: string): Promise<FsStat> {
465+
async stat(path: string, seen: Set<string> = new Set()): Promise<FsStat> {
455466
const normalized = this.normalizePath(path);
456467

468+
// Detect symlink loops
469+
if (seen.has(normalized)) {
470+
throw new Error(
471+
`ELOOP: too many levels of symbolic links, stat '${path}'`,
472+
);
473+
}
474+
seen.add(normalized);
475+
457476
if (this.deleted.has(normalized)) {
458477
throw new Error(`ENOENT: no such file or directory, stat '${path}'`);
459478
}
@@ -464,7 +483,7 @@ export class OverlayFs implements IFileSystem {
464483
// Follow symlinks
465484
if (entry.type === "symlink") {
466485
const target = this.resolveSymlink(normalized, entry.target);
467-
return this.stat(target);
486+
return this.stat(target, seen);
468487
}
469488

470489
let size = 0;

0 commit comments

Comments
 (0)