diff --git a/gpgme.go b/gpgme.go index 62a095c12..1da874ab8 100644 --- a/gpgme.go +++ b/gpgme.go @@ -144,7 +144,16 @@ func (e Error) Code() ErrorCode { } func (e Error) Error() string { - return C.GoString(C.gpgme_strerror(e.err)) + // gpgme_error_t, aka gpg_error_t, is a single 32-bit integer, so it does not include + // strings of arbitrary length + // (compare https://git.gnupg.org/cgi-bin/gitweb.cgi?p=libgpg-error.git;a=blob;f=src/err-codes.h.in;hb=HEAD ). + // + // So, a medium-size hard-coded buffer is sufficient. + var buf [1024]C.char + _ = C.gpgme_strerror_r(e.err, &buf[0], C.size_t(len(buf))) + buf[len(buf)-1] = 0 // If gpgme_strerror_r returns ERANGE, the buffer is not guaranteed to be null-terminated + + return C.GoString(&buf[0]) } func handleError(err C.gpgme_error_t) error { diff --git a/gpgme_test.go b/gpgme_test.go index 1e1cd0865..523cf078c 100644 --- a/gpgme_test.go +++ b/gpgme_test.go @@ -68,6 +68,29 @@ func TestMain(m *testing.M) { os.Exit(m.Run()) } +func TestHandleError(t *testing.T) { + // Smoke-test that error reporting, at least, does not crash. + + ctx, err := New() + checkError(t, err) + // Use a non-existent engine, and a non-existent key, to trigger an error without many side-effects + testProto := ProtocolOpenPGP + testFN := "/dev/null/this/does/not/exist" + testHomeDir := "/dev/null/this/does/not/exist" + checkError(t, ctx.SetEngineInfo(testProto, testFN, testHomeDir)) + plain, err := NewDataBytes([]byte(testData)) + checkError(t, err) + var dest bytes.Buffer + sig, err := NewDataWriter(&dest) + checkError(t, err) + err = ctx.Sign(nil, plain, sig, SigModeNormal) + if err == nil { + t.Fatal("Expected error, got nil") + } + _ = err.(Error).Code() + _ = err.Error() +} + func compareEngineInfo(t *testing.T, info *EngineInfo, proto Protocol, fileName, homeDir string) { for info != nil && info.Protocol() != proto { info = info.Next()