From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2178) id 78ADA3856974; Thu, 15 Jun 2023 17:55:09 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 78ADA3856974 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1686851709; bh=mif4D4PUTQMoGzUuBGHq/BYwh3jr69LUrdJUw2cAEKQ=; h=From:To:Subject:Date:From; b=ZE9QfvlSlFsB8ETm7pes3RA9llrWU4iyjYilyFQVWxX+otK7u7m8gtIgu1fccPQ+v uxcaalrpfJscw9A3jnbN2BpeEUh5/p4xloOpjaxFPP6Lf60jvVN3saaGPGsM6jSDCu 2qM7ASWlYJIl30zaObYxWz7inU4M7WnsYQkaRwB0= Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Florian Weimer To: glibc-cvs@sourceware.org Subject: [glibc/fw/bug30555] string: strerror must not return NULL (bug 30555) X-Act-Checkin: glibc X-Git-Author: Florian Weimer X-Git-Refname: refs/heads/fw/bug30555 X-Git-Oldrev: 388ae538ddcb05c7d8966147b488a5f6e481656e X-Git-Newrev: 1d44530a5be2442e064baa48139adc9fdfb1fc6b Message-Id: <20230615175509.78ADA3856974@sourceware.org> Date: Thu, 15 Jun 2023 17:55:09 +0000 (GMT) List-Id: https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=1d44530a5be2442e064baa48139adc9fdfb1fc6b commit 1d44530a5be2442e064baa48139adc9fdfb1fc6b Author: Florian Weimer Date: Thu Jun 15 12:08:22 2023 +0200 string: strerror must not return NULL (bug 30555) For strerror, this fixes commit 28aff047818eb1726394296d27b ("string: Implement strerror in terms of strerror_l"). This commit avoids returning NULL for strerror_l as well, although POSIX allows this behavior for strerror_l. Reviewed-by: Arjun Shankar Diff: --- string/Makefile | 1 + string/strerror_l.c | 13 +++++--- string/tst-strerror-fail.c | 77 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 87 insertions(+), 4 deletions(-) diff --git a/string/Makefile b/string/Makefile index 0ad276cc6a..d3106d10a9 100644 --- a/string/Makefile +++ b/string/Makefile @@ -178,6 +178,7 @@ tests := \ tst-endian \ tst-inlcall \ tst-memmove-overflow \ + tst-strerror-fail \ tst-strfry \ tst-strlcat \ tst-strlcpy \ diff --git a/string/strerror_l.c b/string/strerror_l.c index 7fe9b1d903..e5c8666198 100644 --- a/string/strerror_l.c +++ b/string/strerror_l.c @@ -43,10 +43,15 @@ __strerror_l (int errnum, locale_t loc) struct tls_internal_t *tls_internal = __glibc_tls_internal (); free (tls_internal->strerror_l_buf); if (__asprintf (&tls_internal->strerror_l_buf, "%s%d", - translate ("Unknown error ", loc), errnum) == -1) - tls_internal->strerror_l_buf = NULL; - - err = tls_internal->strerror_l_buf; + translate ("Unknown error ", loc), errnum) > 0) + err = tls_internal->strerror_l_buf; + else + { + /* The memory was freed above. */ + tls_internal->strerror_l_buf = NULL; + /* Provide a fallback translation. */ + err = (char *) translate ("Unknown error", loc); + } } else err = (char *) translate (err, loc); diff --git a/string/tst-strerror-fail.c b/string/tst-strerror-fail.c new file mode 100644 index 0000000000..e0fa45ab2b --- /dev/null +++ b/string/tst-strerror-fail.c @@ -0,0 +1,77 @@ +/* Check that strerror, strerror_l do not return NULL on failure (bug 30555). + Copyright (C) 2023 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, see + . */ + + +#include +#include +#include +#include +#include +#include +#include + +/* Interposed malloc that can be used to inject allocation failures. */ + +static volatile bool fail_malloc; + +void * +malloc (size_t size) +{ + if (fail_malloc) + return NULL; + + static void *(*original_malloc) (size_t); + if (original_malloc == NULL) + original_malloc = xdlsym (RTLD_NEXT, "malloc"); + return original_malloc (size); +} + +/* Callbacks for the actual tests. Use fork to run both tests with a + clean state. */ + +static void +test_strerror (void *closure) +{ + fail_malloc = true; + const char *s = strerror (999); + fail_malloc = false; + TEST_COMPARE_STRING (s, "Unknown error"); +} + +static void +test_strerror_l (void *closure) +{ + locale_t loc = newlocale (LC_ALL, "C", (locale_t) 0); + TEST_VERIFY (loc != (locale_t) 0); + fail_malloc = true; + const char *s = strerror_l (999, loc); + fail_malloc = false; + TEST_COMPARE_STRING (s, "Unknown error"); + freelocale (loc); +} + +static int +do_test (void) +{ + support_isolate_in_subprocess (test_strerror, NULL); + support_isolate_in_subprocess (test_strerror_l, NULL); + + return 0; +} + +#include