awnumar/memguard

Q: panic: <memcall> could not acquire lock

Opened this issue · 8 comments

Hi,
I am just wasting some time so I thought I'd compare performance requirements and I am getting panic from enclave.Open(). Any idea why?

package whatever

import (
	"github.com/awnumar/memguard"
	"testing"
)

func BenchmarkEnclaveOpen(b *testing.B) {
	secret := []byte("secret secret secret")
	e := memguard.NewEnclave(secret)

	for i := 0; i < b.N; i++ {
		e.Open()
	}
}

func BenchmarkEnclaveOpenRead(b *testing.B) {
	secret := []byte("secret secret secret")
	e := memguard.NewEnclave(secret)

	for i := 0; i < b.N; i++ {
		lb, _ := e.Open()
		lb.String()
	}
}

func BenchmarkLBRead(b *testing.B) {
	secret := []byte("secret secret secret")
	lb := memguard.NewBufferFromBytes(secret)

	for i := 0; i < b.N; i++ {
		lb.String()
	}
}

Can you post the trace? I'm not at a computer at the moment but I'll investigate as soon as I can.

$ go test -bench .
goos: windows
goarch: amd64
pkg: ...
BenchmarkEnclaveOpen-4                 0                      NaN ns/op
panic: <memcall> could not acquire lock on 0x2ce1000, limit reached? [Err: Insufficient quota to complete the requested service.]

goroutine 50 [running]:
github.com/awnumar/memguard/core.Panic(0x558020, 0xc000036bf0)
        .../go/src/github.com/awnumar/memguard/core/exit.go:73 +0x127
github.com/awnumar/memguard/core.NewBuffer(0x20, 0x1000, 0x2cd1000, 0xfec)
        .../go/src/github.com/awnumar/memguard/core/buffer.go:75 +0x342
github.com/awnumar/memguard/core.(*Coffer).View(0xc000099fb0, 0x0, 0x0, 0x0)
        .../go/src/github.com/awnumar/memguard/core/coffer.go:96 +0xc5
github.com/awnumar/memguard/core.Open(0xc000004040, 0xc000036bd0, 0x0, 0x0)
        .../go/src/github.com/awnumar/memguard/core/enclave.go:99 +0x67
github.com/awnumar/memguard.(*Enclave).Open(0xc000006008, 0xc000036bd0, 0x0, 0x0)
        .../go/src/github.com/awnumar/memguard/enclave.go:43 +0x39
....BenchmarkEnclaveOpen(0xc0000be1c0)
        ...bench_test.go:13 +0x7f
testing.(*B).runN(0xc0000be1c0, 0x64)
        C:/Go/src/testing/benchmark.go:190 +0xd3
testing.(*B).launch(0xc0000be1c0)
        C:/Go/src/testing/benchmark.go:320 +0x113
created by testing.(*B).doBench
        C:/Go/src/testing/benchmark.go:275 +0x5c
exit status 2
FAIL    ...  0.106s

It looks to me like the benchmarking does its stuff in parallel(though I don't know how) so it tries to access enclave from multiple goroutines at once....

Try ulimit -l unlimited in the same shell before running the benchmarks.

Didn't help. But I am on a Win10 with git's bash so on *nix it could work.

It looks like the process uses up it's allocated mlock limit. This is the amount of memory that the operating system allows each process to lock into volatile memory, preventing it from being swapped out to disk. I'm not sure how to increase this limit on Windows, but if you destroy the LockedBuffer objects that are created after creating them, this issue should disappear.

Please let me know if that fixes the issue, and I'd be interested to see the results of the benchmarks as well alongside your system specs.

You are correct, this worked:

package whatever

import (
	"github.com/awnumar/memguard"
	"testing"
)

func BenchmarkEnclaveOpen(b *testing.B) {
	b.SetParallelism(1)
	secret := []byte("secret secret secret")
	e := memguard.NewEnclave(secret)

	for i := 0; i < b.N; i++ {
		lb, _ := e.Open()
		lb.Destroy()
	}
}

func BenchmarkEnclaveOpenRead(b *testing.B) {
	b.SetParallelism(1)
	secret := []byte("secret secret secret")
	e := memguard.NewEnclave(secret)

	for i := 0; i < b.N; i++ {
		lb, _ := e.Open()
		_ = lb.String()
		lb.Destroy()
	}
}

func BenchmarkLBRead(b *testing.B) {
	b.SetParallelism(1)
	secret := []byte("secret secret secret")
	lb := memguard.NewBufferFromBytes(secret)

	for i := 0; i < b.N; i++ {
		_ = lb.String()
		lb.Destroy()
	}
}

With results:

BenchmarkEnclaveOpen-4              4094            265510 ns/op
BenchmarkEnclaveOpenRead-4          4800            255416 ns/op
BenchmarkLBRead-4               16000704                70.4 ns/op

So it is very important to always destroy the LB. That is good to know :)

Great. Destroying containers is critical. Please familiarise yourself with the documentation: https://godoc.org/github.com/awnumar/memguard