Problem reported by Michael Pyne in: https://savannah.gnu.org/bugs/?47847 * lib/gettext.h (dcpgettext_expr, dcnpgettext_expr): Delay freeing allocated buffer until all pointers to it are no longer used. Spotted by Coverity. --- ChangeLog | 9 +++++++++ lib/gettext.h | 34 ++++++++++++++++++---------------- 2 files changed, 27 insertions(+), 16 deletions(-)
diff --git a/ChangeLog b/ChangeLog index fe747e5..41453d2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,12 @@ +2016-05-09 Daiki Ueno <[email protected]> + + gettext-h: avoid undefined behavior + Problem reported by Michael Pyne in: + https://savannah.gnu.org/bugs/?47847 + * lib/gettext.h (dcpgettext_expr, dcnpgettext_expr): Delay freeing + allocated buffer until all pointers to it are no longer used. + Spotted by Coverity. + 2016-05-08 Paul Eggert <[email protected]> git-version-gen: avoid undefined shift diff --git a/lib/gettext.h b/lib/gettext.h index 3acc6a6..c5c0294 100644 --- a/lib/gettext.h +++ b/lib/gettext.h @@ -213,7 +213,7 @@ dcpgettext_expr (const char *domain, { size_t msgctxt_len = strlen (msgctxt) + 1; size_t msgid_len = strlen (msgid) + 1; - const char *translation; + const char *translation = msgid; #if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS char msg_ctxt_id[msgctxt_len + msgid_len]; #else @@ -225,18 +225,19 @@ dcpgettext_expr (const char *domain, if (msg_ctxt_id != NULL) #endif { + const char *result; memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1); msg_ctxt_id[msgctxt_len - 1] = '\004'; memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len); - translation = dcgettext (domain, msg_ctxt_id, category); + result = dcgettext (domain, msg_ctxt_id, category); + if (result != msg_ctxt_id) + translation = result; + } #if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS - if (msg_ctxt_id != buf) - free (msg_ctxt_id); + if (msg_ctxt_id != buf) + free (msg_ctxt_id); #endif - if (translation != msg_ctxt_id) - return translation; - } - return msgid; + return translation; } #define npgettext_expr(Msgctxt, Msgid, MsgidPlural, N) \ @@ -259,7 +260,7 @@ dcnpgettext_expr (const char *domain, { size_t msgctxt_len = strlen (msgctxt) + 1; size_t msgid_len = strlen (msgid) + 1; - const char *translation; + const char *translation = (n == 1 ? msgid : msgid_plural); #if _LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS char msg_ctxt_id[msgctxt_len + msgid_len]; #else @@ -271,18 +272,19 @@ dcnpgettext_expr (const char *domain, if (msg_ctxt_id != NULL) #endif { + const char *result; memcpy (msg_ctxt_id, msgctxt, msgctxt_len - 1); msg_ctxt_id[msgctxt_len - 1] = '\004'; memcpy (msg_ctxt_id + msgctxt_len, msgid, msgid_len); - translation = dcngettext (domain, msg_ctxt_id, msgid_plural, n, category); + result = dcngettext (domain, msg_ctxt_id, msgid_plural, n, category); + if (!(result == msg_ctxt_id || result == msgid_plural)) + translation = result; + } #if !_LIBGETTEXT_HAVE_VARIABLE_SIZE_ARRAYS - if (msg_ctxt_id != buf) - free (msg_ctxt_id); + if (msg_ctxt_id != buf) + free (msg_ctxt_id); #endif - if (!(translation == msg_ctxt_id || translation == msgid_plural)) - return translation; - } - return (n == 1 ? msgid : msgid_plural); + return translation; } #endif /* _LIBGETTEXT_H */ -- 2.5.5
