@@ -48,10 +48,15 @@ const (
4848type Status string
4949
5050const (
51- StatusOK Status = "OK"
52- StatusTimeout Status = "TIMEOUT"
51+ StatusOK Status = "OK"
52+ StatusTimeout Status = "TIMEOUT"
53+ StatusOutputLimitExceeded Status = "OUTPUT_LIMIT_EXCEEDED"
5354)
5455
56+ var errOutputLimitExceeded = errors .New ("output limit exceeded" )
57+
58+ const outputLimit = 1 << 20 // 1 MiB
59+
5560type runtimeConfig struct {
5661 binaryPath string
5762 installDir string
@@ -190,18 +195,33 @@ func Run(ctx context.Context, rt Runtime, tmpDir, entryFile string) (Result, err
190195
191196 var stdoutBuf , stderrBuf , combined bytes.Buffer
192197
193- if err := drainPipes (ctx , stdoutR , stderrR , & stdoutBuf , & stderrBuf , & combined ); err != nil {
198+ drainErr := drainPipes (ctx , cmd .Process , stdoutR , stderrR , & stdoutBuf , & stderrBuf , & combined )
199+ if drainErr != nil && ! errors .Is (drainErr , errOutputLimitExceeded ) {
194200 _ = cmd .Wait ()
195201 _ = stdoutR .Close ()
196202 _ = stderrR .Close ()
197203 _ = logR .Close ()
198- return Result {}, fmt .Errorf ("sandbox execution failed: %w" , err )
204+ return Result {}, fmt .Errorf ("sandbox execution failed: %w" , drainErr )
199205 }
206+ outputLimitHit := errors .Is (drainErr , errOutputLimitExceeded )
200207
201208 _ = stdoutR .Close ()
202209 _ = stderrR .Close ()
203210
204211 waitErr := cmd .Wait ()
212+
213+ if outputLimitHit {
214+ _ = logR .Close ()
215+ return Result {
216+ Stdout : "" ,
217+ Stderr : "" ,
218+ Output : "" ,
219+ ExitCode : - 1 ,
220+ Status : StatusOutputLimitExceeded ,
221+ Signal : nil ,
222+ }, nil
223+ }
224+
205225 if ctx .Err () != nil {
206226 _ = logR .Close ()
207227 return Result {}, ctx .Err ()
@@ -250,7 +270,7 @@ func Run(ctx context.Context, rt Runtime, tmpDir, entryFile string) (Result, err
250270// pipes are ready simultaneously, stdout is processed first. The poll
251271// timeout is derived from ctx's deadline so that the execution timeout
252272// and client disconnects are respected promptly.
253- func drainPipes (ctx context.Context , stdoutR , stderrR * os.File , stdoutBuf , stderrBuf , combined * bytes.Buffer ) error {
273+ func drainPipes (ctx context.Context , proc * os. Process , stdoutR , stderrR * os.File , stdoutBuf , stderrBuf , combined * bytes.Buffer ) error {
254274 type pipe struct {
255275 file * os.File
256276 buf * bytes.Buffer
@@ -312,6 +332,10 @@ func drainPipes(ctx context.Context, stdoutR, stderrR *os.File, stdoutBuf, stder
312332 if nr > 0 {
313333 pipes [i ].buf .Write (buf [:nr ])
314334 combined .Write (buf [:nr ])
335+ if combined .Len () > outputLimit {
336+ _ = proc .Kill ()
337+ return errOutputLimitExceeded
338+ }
315339 }
316340 if readErr != nil {
317341 if readErr == io .EOF {
0 commit comments