[Libguestfs] [PATCH libnbd v2 4/9] golang: aio_buffer.go: Add MakeAioBufferZero()

Nir Soffer nsoffer at redhat.com
Fri Feb 11 01:21:24 UTC 2022


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 at 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




More information about the Libguestfs mailing list