From 5124b27d355a868a07c51ca694c45b32b10f89b5 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Wed, 20 Jun 2018 10:01:57 -0700 Subject: [PATCH] src: add new error apis to prevent memory leaks This PR creates two new externally-facing APIs, uv_err_name_r() and uv_strerror_r(). In keeping with the precedent set by POSIX, the *_r() suffix of these two new methods indicate that the caller does the memory management and passes in the memory that the output will be stored in, which provides an alternative for the two existent methods (uv_err_name() and uv_strerror()), which, when called with an unknown error code, leak a few bytes of memory. PR-URL: https://github.com/libuv/libuv/pull/1898 Reviewed-By: Ben Noordhuis Reviewed-By: Santiago Gimeno santiago.gimeno@gmail.com --- docs/src/errors.rst | 14 ++++++++++++++ include/uv.h | 3 +++ src/uv-common.c | 25 +++++++++++++++++++++++++ test/test-error.c | 6 ++++++ 4 files changed, 48 insertions(+) diff --git a/docs/src/errors.rst b/docs/src/errors.rst index 7c3f95d7..b8f971f5 100644 --- a/docs/src/errors.rst +++ b/docs/src/errors.rst @@ -335,11 +335,25 @@ API Returns the error message for the given error code. Leaks a few bytes of memory when you call it with an unknown error code. +.. c:function:: char* uv_strerror_r(int err, char* buf, size_t buflen) + + Returns the error message for the given error code. The zero-terminated + message is stored in the user-supplied buffer `buf` of at most `buflen` bytes. + + .. versionadded:: 1.22.0 + .. c:function:: const char* uv_err_name(int err) Returns the error name for the given error code. Leaks a few bytes of memory when you call it with an unknown error code. +.. c:function:: char* uv_err_name_r(int err, char* buf, size_t buflen) + + Returns the error name for the given error code. The zero-terminated + name is stored in the user-supplied buffer `buf` of at most `buflen` bytes. + + .. versionadded:: 1.22.0 + .. c:function:: int uv_translate_sys_error(int sys_errno) Returns the libuv error code equivalent to the given platform dependent error diff --git a/include/uv.h b/include/uv.h index 91451ada..7565769c 100644 --- a/include/uv.h +++ b/include/uv.h @@ -370,7 +370,10 @@ typedef enum { UV_EXTERN int uv_translate_sys_error(int sys_errno); UV_EXTERN const char* uv_strerror(int err); +UV_EXTERN char* uv_strerror_r(int err, char* buf, size_t buflen); + UV_EXTERN const char* uv_err_name(int err); +UV_EXTERN char* uv_err_name_r(int err, char* buf, size_t buflen); #define UV_REQ_FIELDS \ diff --git a/src/uv-common.c b/src/uv-common.c index 1146cfa3..f0aec452 100644 --- a/src/uv-common.c +++ b/src/uv-common.c @@ -155,6 +155,18 @@ static const char* uv__unknown_err_code(int err) { return copy != NULL ? copy : "Unknown system error"; } +#define UV_ERR_NAME_GEN_R(name, _) \ +case UV_## name: \ + snprintf(buf, buflen, "%s", #name); break; +char* uv_err_name_r(int err, char* buf, size_t buflen) { + switch (err) { + UV_ERRNO_MAP(UV_ERR_NAME_GEN_R) + default: snprintf(buf, buflen, "Unknown system error %d", err); + } + return buf; +} +#undef UV_ERR_NAME_GEN_R + #define UV_ERR_NAME_GEN(name, _) case UV_ ## name: return #name; const char* uv_err_name(int err) { @@ -166,6 +178,19 @@ const char* uv_err_name(int err) { #undef UV_ERR_NAME_GEN +#define UV_STRERROR_GEN_R(name, msg) \ +case UV_ ## name: \ + snprintf(buf, buflen, "%s", msg); break; +char* uv_strerror_r(int err, char* buf, size_t buflen) { + switch (err) { + UV_ERRNO_MAP(UV_STRERROR_GEN_R) + default: snprintf(buf, buflen, "Unknown system error %d", err); + } + return buf; +} +#undef UV_STRERROR_GEN_R + + #define UV_STRERROR_GEN(name, msg) case UV_ ## name: return msg; const char* uv_strerror(int err) { switch (err) { diff --git a/test/test-error.c b/test/test-error.c index a2d559a4..7f44f4a1 100644 --- a/test/test-error.c +++ b/test/test-error.c @@ -37,6 +37,8 @@ * See https://github.com/joyent/libuv/issues/210 */ TEST_IMPL(error_message) { + char buf[32]; + /* Cop out. Can't do proper checks on systems with * i18n-ized error messages... */ @@ -49,6 +51,10 @@ TEST_IMPL(error_message) { ASSERT(strcmp(uv_strerror(1337), "Unknown error") == 0); ASSERT(strcmp(uv_strerror(-1337), "Unknown error") == 0); + ASSERT(strstr(uv_strerror_r(UV_EINVAL, buf, sizeof(buf)), "Success") == NULL); + ASSERT(strstr(uv_strerror_r(1337, buf, sizeof(buf)), "1337") != NULL); + ASSERT(strstr(uv_strerror_r(-1337, buf, sizeof(buf)), "-1337") != NULL); + return 0; }