Skip to content

Commit cb18937

Browse files
committed
sed limits
1 parent 29cdd11 commit cb18937

File tree

2 files changed

+66
-28
lines changed

2 files changed

+66
-28
lines changed

src/commands/sed/sed.limits.test.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { describe, expect, it } from "vitest";
22
import { Bash } from "../../Bash.js";
3+
import { ExecutionLimitError } from "../../interpreter/errors.js";
34

45
/**
56
* SED Execution Limits Tests
@@ -17,9 +18,9 @@ describe("SED Execution Limits", () => {
1718
// :label followed by b label creates infinite loop
1819
const result = await env.exec(`echo "test" | sed ':loop; b loop'`);
1920

20-
// Should not hang - sed should have iteration limits
21-
expect(result.stderr.length).toBeGreaterThan(0);
22-
expect(result.exitCode).not.toBe(0);
21+
// Must hit our internal limit with correct exit code
22+
expect(result.stderr).toContain("exceeded maximum iterations");
23+
expect(result.exitCode).toBe(ExecutionLimitError.EXIT_CODE);
2324
});
2425

2526
// TODO: t command with loop needs better substitution tracking
@@ -32,8 +33,8 @@ describe("SED Execution Limits", () => {
3233
`echo "test" | sed ':loop; s/./&/; t loop'`,
3334
);
3435

35-
expect(result.stderr.length).toBeGreaterThan(0);
36-
expect(result.exitCode).not.toBe(0);
36+
expect(result.stderr).toContain("exceeded maximum iterations");
37+
expect(result.exitCode).toBe(ExecutionLimitError.EXIT_CODE);
3738
});
3839

3940
it("should protect against unconditional branch at start", async () => {

src/commands/sed/sed.ts

Lines changed: 60 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { ExecutionLimitError } from "../../interpreter/errors.js";
12
import type { ExecutionLimits } from "../../limits.js";
23
import type { Command, CommandContext, ExecResult } from "../../types.js";
34
import { hasHelpFlag, showHelp, unknownOption } from "../help.js";
@@ -365,16 +366,27 @@ export const sedCommand: Command = {
365366
// Read from files or stdin
366367
if (files.length === 0) {
367368
content = ctx.stdin;
368-
const result = await processContent(content, commands, silent, {
369-
limits: ctx.limits,
370-
fs: ctx.fs,
371-
cwd: ctx.cwd,
372-
});
373-
return {
374-
stdout: result.output,
375-
stderr: "",
376-
exitCode: result.exitCode ?? 0,
377-
};
369+
try {
370+
const result = await processContent(content, commands, silent, {
371+
limits: ctx.limits,
372+
fs: ctx.fs,
373+
cwd: ctx.cwd,
374+
});
375+
return {
376+
stdout: result.output,
377+
stderr: "",
378+
exitCode: result.exitCode ?? 0,
379+
};
380+
} catch (e) {
381+
if (e instanceof ExecutionLimitError) {
382+
return {
383+
stdout: "",
384+
stderr: `sed: ${e.message}\n`,
385+
exitCode: ExecutionLimitError.EXIT_CODE,
386+
};
387+
}
388+
throw e;
389+
}
378390
}
379391

380392
// Handle in-place editing
@@ -390,7 +402,14 @@ export const sedCommand: Command = {
390402
cwd: ctx.cwd,
391403
});
392404
await ctx.fs.writeFile(filePath, result.output);
393-
} catch {
405+
} catch (e) {
406+
if (e instanceof ExecutionLimitError) {
407+
return {
408+
stdout: "",
409+
stderr: `sed: ${e.message}\n`,
410+
exitCode: ExecutionLimitError.EXIT_CODE,
411+
};
412+
}
394413
return {
395414
stdout: "",
396415
stderr: `sed: ${file}: No such file or directory\n`,
@@ -406,7 +425,14 @@ export const sedCommand: Command = {
406425
const filePath = ctx.fs.resolvePath(ctx.cwd, file);
407426
try {
408427
content += await ctx.fs.readFile(filePath);
409-
} catch {
428+
} catch (e) {
429+
if (e instanceof ExecutionLimitError) {
430+
return {
431+
stdout: "",
432+
stderr: `sed: ${e.message}\n`,
433+
exitCode: ExecutionLimitError.EXIT_CODE,
434+
};
435+
}
410436
return {
411437
stdout: "",
412438
stderr: `sed: ${file}: No such file or directory\n`,
@@ -415,16 +441,27 @@ export const sedCommand: Command = {
415441
}
416442
}
417443

418-
const result = await processContent(content, commands, silent, {
419-
limits: ctx.limits,
420-
filename: files.length === 1 ? files[0] : undefined,
421-
fs: ctx.fs,
422-
cwd: ctx.cwd,
423-
});
424-
return {
425-
stdout: result.output,
426-
stderr: "",
427-
exitCode: result.exitCode ?? 0,
428-
};
444+
try {
445+
const result = await processContent(content, commands, silent, {
446+
limits: ctx.limits,
447+
filename: files.length === 1 ? files[0] : undefined,
448+
fs: ctx.fs,
449+
cwd: ctx.cwd,
450+
});
451+
return {
452+
stdout: result.output,
453+
stderr: "",
454+
exitCode: result.exitCode ?? 0,
455+
};
456+
} catch (e) {
457+
if (e instanceof ExecutionLimitError) {
458+
return {
459+
stdout: "",
460+
stderr: `sed: ${e.message}\n`,
461+
exitCode: ExecutionLimitError.EXIT_CODE,
462+
};
463+
}
464+
throw e;
465+
}
429466
},
430467
};

0 commit comments

Comments
 (0)