Make it easy to create a zeroed buffer via calloc(), preventing leaking
sensitive info from the heap.
Benchmarking shows that creating a zeroed buffer is much slower compared
with uninitialized buffer, but much faster compared with manually
initializing the buffer with a loop.
BenchmarkMakeAioBuffer-12 7252674 148.1 ns/op
BenchmarkMakeAioBufferZero-12 262107 4181 ns/op
BenchmarkAioBufferZero-12 17581 68759 ns/op
It is interesting that creating a zeroed buffer is 3 times faster
compared with making a new []byte slice:
BenchmarkMakeAioBufferZero-12 247710 4440 ns/op
BenchmarkMakeByteSlice-12 84117 13733 ns/op
Signed-off-by: Nir Soffer <nsoffer(a)redhat.com>
---
golang/aio_buffer.go | 6 ++++++
golang/libnbd_020_aio_buffer_test.go | 16 ++++++++++++++++
2 files changed, 22 insertions(+)
diff --git a/golang/aio_buffer.go b/golang/aio_buffer.go
index 2cd8ceb2..d2e6e350 100644
--- a/golang/aio_buffer.go
+++ b/golang/aio_buffer.go
@@ -38,20 +38,26 @@ type AioBuffer struct {
P unsafe.Pointer
Size uint
}
// MakeAioBuffer makes a new buffer backed by an uninitialized C allocated
// array.
func MakeAioBuffer(size uint) AioBuffer {
return AioBuffer{C.malloc(C.ulong(size)), size}
}
+// MakeAioBuffer makes a new buffer backed by a C allocated array. The
+// underlying buffer is set to zero.
+func MakeAioBufferZero(size uint) AioBuffer {
+ return AioBuffer{C.calloc(C.ulong(1), C.ulong(size)), size}
+}
+
// FromBytes makes a new buffer backed by a C allocated array, initialized by
// copying the given Go slice.
func FromBytes(buf []byte) AioBuffer {
size := len(buf)
ret := MakeAioBuffer(uint(size))
for i := 0; i < len(buf); i++ {
*ret.Get(uint(i)) = buf[i]
}
return ret
}
diff --git a/golang/libnbd_020_aio_buffer_test.go b/golang/libnbd_020_aio_buffer_test.go
index cec74ddc..b3a2a8d9 100644
--- a/golang/libnbd_020_aio_buffer_test.go
+++ b/golang/libnbd_020_aio_buffer_test.go
@@ -51,20 +51,28 @@ func TestAioBuffer(t *testing.T) {
t.Fatalf("Expected %v, got %v", zeroes, buf.Bytes())
}
/* Create another buffer from Go slice. */
buf2 := FromBytes(zeroes)
defer buf2.Free()
if !bytes.Equal(buf2.Bytes(), zeroes) {
t.Fatalf("Expected %v, got %v", zeroes, buf2.Bytes())
}
+
+ /* Crated a zeroed buffer. */
+ buf3 := MakeAioBufferZero(uint(32))
+ defer buf.Free()
+
+ if !bytes.Equal(buf3.Bytes(), zeroes) {
+ t.Fatalf("Expected %v, got %v", zeroes, buf2.Bytes())
+ }
}
func TestAioBufferFree(t *testing.T) {
buf := MakeAioBuffer(uint(32))
/* Free the underlying C array. */
buf.Free()
/* And clear the pointer. */
if buf.P != nil {
@@ -105,20 +113,28 @@ func TestAioBufferGetAfterFree(t *testing.T) {
const bufferSize uint = 256 * 1024
// Benchmark creating an uninitialized buffer.
func BenchmarkMakeAioBuffer(b *testing.B) {
for i := 0; i < b.N; i++ {
buf := MakeAioBuffer(bufferSize)
buf.Free()
}
}
+// Benchmark creating zeroed buffer.
+func BenchmarkMakeAioBufferZero(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ buf := MakeAioBufferZero(bufferSize)
+ buf.Free()
+ }
+}
+
// Benchmark zeroing a buffer.
func BenchmarkAioBufferZero(b *testing.B) {
for i := 0; i < b.N; i++ {
buf := MakeAioBuffer(bufferSize)
for i := uint(0); i < bufferSize; i++ {
*buf.Get(i) = 0
}
buf.Free()
}
}
--
2.34.1