Use a placeholder for unknown errors in ERR_*_error_string.
Change-Id: I3a16fa731cfa7c92e5fec19f78ae48650921f626
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/47104
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/crypto/err/err.c b/crypto/err/err.c
index 7973a0e..4aab75b 100644
--- a/crypto/err/err.c
+++ b/crypto/err/err.c
@@ -368,84 +368,6 @@
errno = 0;
}
-char *ERR_error_string(uint32_t packed_error, char *ret) {
- static char buf[ERR_ERROR_STRING_BUF_LEN];
-
- if (ret == NULL) {
- // TODO(fork): remove this.
- ret = buf;
- }
-
-#if !defined(NDEBUG)
- // This is aimed to help catch callers who don't provide
- // |ERR_ERROR_STRING_BUF_LEN| bytes of space.
- OPENSSL_memset(ret, 0, ERR_ERROR_STRING_BUF_LEN);
-#endif
-
- return ERR_error_string_n(packed_error, ret, ERR_ERROR_STRING_BUF_LEN);
-}
-
-char *ERR_error_string_n(uint32_t packed_error, char *buf, size_t len) {
- char lib_buf[64], reason_buf[64];
- const char *lib_str, *reason_str;
- unsigned lib, reason;
-
- if (len == 0) {
- return NULL;
- }
-
- lib = ERR_GET_LIB(packed_error);
- reason = ERR_GET_REASON(packed_error);
-
- lib_str = ERR_lib_error_string(packed_error);
- reason_str = ERR_reason_error_string(packed_error);
-
- if (lib_str == NULL) {
- BIO_snprintf(lib_buf, sizeof(lib_buf), "lib(%u)", lib);
- lib_str = lib_buf;
- }
-
- if (reason_str == NULL) {
- BIO_snprintf(reason_buf, sizeof(reason_buf), "reason(%u)", reason);
- reason_str = reason_buf;
- }
-
- BIO_snprintf(buf, len, "error:%08" PRIx32 ":%s:OPENSSL_internal:%s",
- packed_error, lib_str, reason_str);
-
- if (strlen(buf) == len - 1) {
- // output may be truncated; make sure we always have 5 colon-separated
- // fields, i.e. 4 colons.
- static const unsigned num_colons = 4;
- unsigned i;
- char *s = buf;
-
- if (len <= num_colons) {
- // In this situation it's not possible to ensure that the correct number
- // of colons are included in the output.
- return buf;
- }
-
- for (i = 0; i < num_colons; i++) {
- char *colon = strchr(s, ':');
- char *last_pos = &buf[len - 1] - num_colons + i;
-
- if (colon == NULL || colon > last_pos) {
- // set colon |i| at last possible position (buf[len-1] is the
- // terminating 0). If we're setting this colon, then all whole of the
- // rest of the string must be colons in order to have the correct
- // number.
- OPENSSL_memset(last_pos, ':', num_colons - i);
- break;
- }
-
- s = colon + 1;
- }
- }
-
- return buf;
-}
-
// err_string_cmp is a compare function for searching error values with
// |bsearch| in |err_string_lookup|.
static int err_string_cmp(const void *a, const void *b) {
@@ -530,7 +452,7 @@
"User defined functions", // ERR_LIB_USER
};
-const char *ERR_lib_error_string(uint32_t packed_error) {
+static const char *err_lib_error_string(uint32_t packed_error) {
const uint32_t lib = ERR_GET_LIB(packed_error);
if (lib >= ERR_NUM_LIBS) {
@@ -539,11 +461,16 @@
return kLibraryNames[lib];
}
+const char *ERR_lib_error_string(uint32_t packed_error) {
+ const char *ret = err_lib_error_string(packed_error);
+ return ret == NULL ? "unknown library" : ret;
+}
+
const char *ERR_func_error_string(uint32_t packed_error) {
return "OPENSSL_internal";
}
-const char *ERR_reason_error_string(uint32_t packed_error) {
+static const char *err_reason_error_string(uint32_t packed_error) {
const uint32_t lib = ERR_GET_LIB(packed_error);
const uint32_t reason = ERR_GET_REASON(packed_error);
@@ -579,6 +506,86 @@
kOpenSSLReasonValuesLen, kOpenSSLReasonStringData);
}
+const char *ERR_reason_error_string(uint32_t packed_error) {
+ const char *ret = err_reason_error_string(packed_error);
+ return ret == NULL ? "unknown error" : ret;
+}
+
+char *ERR_error_string(uint32_t packed_error, char *ret) {
+ static char buf[ERR_ERROR_STRING_BUF_LEN];
+
+ if (ret == NULL) {
+ // TODO(fork): remove this.
+ ret = buf;
+ }
+
+#if !defined(NDEBUG)
+ // This is aimed to help catch callers who don't provide
+ // |ERR_ERROR_STRING_BUF_LEN| bytes of space.
+ OPENSSL_memset(ret, 0, ERR_ERROR_STRING_BUF_LEN);
+#endif
+
+ return ERR_error_string_n(packed_error, ret, ERR_ERROR_STRING_BUF_LEN);
+}
+
+char *ERR_error_string_n(uint32_t packed_error, char *buf, size_t len) {
+ if (len == 0) {
+ return NULL;
+ }
+
+ unsigned lib = ERR_GET_LIB(packed_error);
+ unsigned reason = ERR_GET_REASON(packed_error);
+
+ const char *lib_str = err_lib_error_string(packed_error);
+ const char *reason_str = err_reason_error_string(packed_error);
+
+ char lib_buf[64], reason_buf[64];
+ if (lib_str == NULL) {
+ BIO_snprintf(lib_buf, sizeof(lib_buf), "lib(%u)", lib);
+ lib_str = lib_buf;
+ }
+
+ if (reason_str == NULL) {
+ BIO_snprintf(reason_buf, sizeof(reason_buf), "reason(%u)", reason);
+ reason_str = reason_buf;
+ }
+
+ BIO_snprintf(buf, len, "error:%08" PRIx32 ":%s:OPENSSL_internal:%s",
+ packed_error, lib_str, reason_str);
+
+ if (strlen(buf) == len - 1) {
+ // output may be truncated; make sure we always have 5 colon-separated
+ // fields, i.e. 4 colons.
+ static const unsigned num_colons = 4;
+ unsigned i;
+ char *s = buf;
+
+ if (len <= num_colons) {
+ // In this situation it's not possible to ensure that the correct number
+ // of colons are included in the output.
+ return buf;
+ }
+
+ for (i = 0; i < num_colons; i++) {
+ char *colon = strchr(s, ':');
+ char *last_pos = &buf[len - 1] - num_colons + i;
+
+ if (colon == NULL || colon > last_pos) {
+ // set colon |i| at last possible position (buf[len-1] is the
+ // terminating 0). If we're setting this colon, then all whole of the
+ // rest of the string must be colons in order to have the correct
+ // number.
+ OPENSSL_memset(last_pos, ':', num_colons - i);
+ break;
+ }
+
+ s = colon + 1;
+ }
+ }
+
+ return buf;
+}
+
void ERR_print_errors_cb(ERR_print_errors_callback_t callback, void *ctx) {
char buf[ERR_ERROR_STRING_BUF_LEN];
char buf2[1024];
diff --git a/crypto/err/err_test.cc b/crypto/err/err_test.cc
index 41bcc78..b41f8dd 100644
--- a/crypto/err/err_test.cc
+++ b/crypto/err/err_test.cc
@@ -283,3 +283,13 @@
// A buffer length of zero should not touch the buffer.
ERR_error_string_n(err, nullptr, 0);
}
+
+// Error-printing functions should return something with unknown errors.
+TEST(ErrTest, UnknownError) {
+ uint32_t err = ERR_PACK(0xff, 0xfff);
+ EXPECT_TRUE(ERR_lib_error_string(err));
+ EXPECT_TRUE(ERR_reason_error_string(err));
+ char buf[128];
+ ERR_error_string_n(err, buf, sizeof(buf));
+ EXPECT_NE(0u, strlen(buf));
+}
diff --git a/include/openssl/err.h b/include/openssl/err.h
index 0960d80..572340c 100644
--- a/include/openssl/err.h
+++ b/include/openssl/err.h
@@ -223,11 +223,12 @@
size_t len);
// ERR_lib_error_string returns a string representation of the library that
-// generated |packed_error|.
+// generated |packed_error|, or a placeholder string is the library is
+// unrecognized.
OPENSSL_EXPORT const char *ERR_lib_error_string(uint32_t packed_error);
// ERR_reason_error_string returns a string representation of the reason for
-// |packed_error|.
+// |packed_error|, or a placeholder string if the reason is unrecognized.
OPENSSL_EXPORT const char *ERR_reason_error_string(uint32_t packed_error);
// ERR_print_errors_callback_t is the type of a function used by