Skip to content

bug: Starlark auto-invoked function ignores context cancellation and bypasses the logger #156

Description

@robbyt

Summary

When a Starlark script returns a callable (the "auto-invoke main()" idiom), the evaluator calls it on a bare starlark.Thread with no context-cancellation wiring and no Print handler. A long-running or infinite auto-invoked function ignores ctx deadlines, and its print() output bypasses the configured logger.

Root cause

engines/starlark/evaluator/evaluator.go:210-223:

if callable, ok := result.Value.(starlarkLib.Callable); ok {
	thread := &starlarkLib.Thread{Name: "func"}   // no AfterFunc/Cancel, no Print
	val, err := starlarkLib.Call(thread, callable, nil, nil)
	...
}

The top-level exec path (evaluator.go:97-110) wires both:

thread := &starlarkLib.Thread{Name: "eval", Print: func(...) { logger.InfoContext(...) }}
stop := context.AfterFunc(ctx, func() { thread.Cancel(ctx.Err().Error()) })
defer stop()

The auto-call thread has neither, so thread.Cancel is never invoked when ctx is done.

Reproduction (confirmed — measured)

With a 100 ms timeout context and a returned function running a long loop, the auto-called function ran ~19.5 s to completion and Eval returned success — the expired context was never observed. Control: the same loop at top level (inside prog.Init) aborts at ~100 ms with a cancellation error.

Impact

High — the documented "return a function to run it" pattern is exempt from the timeout and cancellation guarantees the top-level path provides, and its diagnostic output escapes the logger.

Fix

Use the same thread setup on the call path: attach the Print handler and wire context.AfterFunc(ctx, ...) → thread.Cancel(...) with defer stop(). Optionally pre-check ctx.Err() before the call. Add a test asserting a cancelled context aborts an auto-invoked function.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions