Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Limiting script execution time reliably #70

Open
sigmonsays opened this issue Feb 7, 2017 · 3 comments
Open

Limiting script execution time reliably #70

sigmonsays opened this issue Feb 7, 2017 · 3 comments

Comments

@sigmonsays
Copy link

I'm struggling to find a good solution to implementing a reliable mechanism to limit how long a script is allowed to run.

A lot of examples show using debug.sethook to check if a timer has elapsed every 100k instructions or so but this is not that reliable as a C call can block.

Another solution is to use alarm system call or setrlimit on lua in a new thread/process but that has its own set of drawbacks.

Has a script timeout been considered before as something we can set on the VM before executing a pcall?

@fbogsany
Copy link
Member

fbogsany commented Feb 7, 2017

go-lua was written before the context package was a thing. It would be ideal if most of its exported functions took a ctx context.Context argument, and then you could simply use the context.WithTimeout(...) pattern. That's not possible in general, but in a controlled environment workarounds are possible. For Shopify's genghis tool, we override sleep, for example, to allow context cancellation from the function that invokes the script:

func registerSleep(ctx context.Context, l *lua.State) {
	l.Register("sleep", func(l *lua.State) int {
		ns := lua.CheckNumber(l, 1)
		childCtx, _ := context.WithTimeout(ctx, time.Nanosecond*time.Duration(ns))
		<-childCtx.Done()
		// Check whether the run was terminated or the timeout expired.
		select {
		case <-ctx.Done():
			// Run was terminated.
			lua.Errorf(l, ctx.Err().Error())
		default:
		}
		return 0
	})

	// Override time.sleep from goluago.
	l.PushGlobalTable()
	l.Field(-1, "package")
	l.Field(-1, "loaded")
	l.Field(-1, "goluago/time")
	l.Field(-4, "sleep")
	l.SetField(-2, "sleep")
	l.Pop(4) // Pop the tables.
}

Our most common blocking native functions also take an outer context.

@sigmonsays
Copy link
Author

That seems reasonable and was the approach I took for now. It seems easier to control everything a script does which allows being timed out.

@ainar-g
Copy link

ainar-g commented Feb 4, 2020

While we're at it, some mechanism to limit the VM's RAM usage would be appreciated as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants