Skip to content

MatchTimeout setting is not respected #91

@rexagod

Description

@rexagod

👋🏼 Hello, thank you for your work here!

I think there's something up with regexp2.MatchTimeout. I should mention that I've read the section on Catastrophic Backtracking and Timeouts but that doesn't seem to explain why the following takes increasingly longer time to run as I increase the string length, rather than timing out after an interval (with reasonable buffer).

For the following snippet, where N:

func TestCatastrophicBacktrackTimeout(t *testing.T) {
	r, err := regexp.Compile("(.+)*\\?", 0)
	if err != nil {
		t.Fatal(err)
	}
	var exp = "Lorem ipsum dolor sit amet, consectetur adipiscing elit?"
	for range N {
		exp += exp
	}

	timeout := time.Second
	t.Run(fmt.Sprint(timeout), func(t *testing.T) {
		r.MatchTimeout = timeout
		start := time.Now()
		m, err := r.FindStringMatch(exp)
		elapsed := time.Since(start)
		t.Log("m == nil", m == nil)
		t.Log("err == nil", err == nil)
		t.Log("elapsed", elapsed)
	})
}

is 10 (elapsed is less than timeout):

┌[rexagod@fedora] [/dev/pts/0] [2594 ⚡] 
└[~/repositories/work/kube-state-metrics]> go test -v -timeout 5s -run ^TestCatastrophicBacktrackTimeout$ k8s.io/kube-state-metrics/v2/pkg/allowdenylist
zsh: correct 'test' to 'tests' [nyae]? n
=== RUN   TestCatastrophicBacktrackTimeout
=== RUN   TestCatastrophicBacktrackTimeout/1s
    allowdenylist_test.go:311: m == nil false
    allowdenylist_test.go:312: err == nil true
    allowdenylist_test.go:313: elapsed 555.744µs
--- PASS: TestCatastrophicBacktrackTimeout (0.00s)
    --- PASS: TestCatastrophicBacktrackTimeout/1s (0.00s)
PASS
ok      k8s.io/kube-state-metrics/v2/pkg/allowdenylist  0.007s

is 22 (elapsed is more than timeout):

┌[rexagod@fedora] [/dev/pts/0] [2594 ⚡] [1]
└[~/repositories/work/kube-state-metrics]> go test -v -timeout 5s -run ^TestCatastrophicBacktrackTimeout$ k8s.io/kube-state-metrics/v2/pkg/allowdenylist
zsh: correct 'test' to 'tests' [nyae]? n
=== RUN   TestCatastrophicBacktrackTimeout
=== RUN   TestCatastrophicBacktrackTimeout/1s
    allowdenylist_test.go:311: m == nil false
    allowdenylist_test.go:312: err == nil true
    allowdenylist_test.go:313: elapsed 2.92970801s
--- PASS: TestCatastrophicBacktrackTimeout (3.75s)
    --- PASS: TestCatastrophicBacktrackTimeout/1s (2.93s)
PASS
ok      k8s.io/kube-state-metrics/v2/pkg/allowdenylist  3.911s

is 25 (elapsed is more than test timeout):

┌[rexagod@fedora] [/dev/pts/0] [2594 ⚡] 
└[~/repositories/work/kube-state-metrics]> go test -v -timeout 5s -run ^TestCatastrophicBacktrackTimeout$ k8s.io/kube-state-metrics/v2/pkg/allowdenylist
zsh: correct 'test' to 'tests' [nyae]? n
=== RUN   TestCatastrophicBacktrackTimeout
panic: test timed out after 5s
        running tests:
                TestCatastrophicBacktrackTimeout (5s)

goroutine 34 [running]:
testing.(*M).startAlarm.func1()
        /home/rexagod/.g/go/src/testing/testing.go:2373 +0x385
created by time.goFunc
        /home/rexagod/.g/go/src/time/sleep.go:215 +0x2d

goroutine 1 [chan receive]:
testing.(*T).Run(0xc0000aeea0, {0x799596?, 0x0?}, 0x7c1348)
        /home/rexagod/.g/go/src/testing/testing.go:1751 +0x3ab
testing.runTests.func1(0xc0000aeea0)
        /home/rexagod/.g/go/src/testing/testing.go:2168 +0x37
testing.tRunner(0xc0000aeea0, 0xc0000cfc70)
        /home/rexagod/.g/go/src/testing/testing.go:1690 +0xf4
testing.runTests(0xc000012408, {0xa54180, 0x6, 0x6}, {0x470a70?, 0x4706da?, 0xa5d600?})
        /home/rexagod/.g/go/src/testing/testing.go:2166 +0x43d
testing.(*M).Run(0xc00018b4a0)
        /home/rexagod/.g/go/src/testing/testing.go:2034 +0x64a
main.main()
        _testmain.go:55 +0x9b

goroutine 8 [running]:
        goroutine running on other thread; stack unavailable
created by testing.(*T).Run in goroutine 1
        /home/rexagod/.g/go/src/testing/testing.go:1743 +0x390
FAIL    k8s.io/kube-state-metrics/v2/pkg/allowdenylist  5.408s
FAIL

I'm trying to replace Go's builtin library in kubernetes/kube-state-metrics#2616 to allow for lookarounds, so a degree of confidence that exponential operations get cut off is needed, thanks!

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