[glibc] time: Fix integer truncation in strftime (bug 34538)
Florian Weimer via Glibc-cvs <[email protected]>
| Newsgroups | gmane.comp.lib.glibc.cvs |
|---|---|
| Message-ID | <[email protected]> |
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=a0faa928b094be829c52d1e493442ba3b48954b1 commit a0faa928b094be829c52d1e493442ba3b48954b1 Author: Florian Weimer <[email protected]> Date: Wed Aug 19 09:33:31 2026 +0200 time: Fix integer truncation in strftime (bug 34538) Extremely large time zone names were not processed correctly. Diff: --- time/Makefile | 1 + time/strftime_l.c | 18 +++++++------- time/tst-strftime5.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 79 insertions(+), 9 deletions(-) diff --git a/time/Makefile b/time/Makefile index b28471cc9e..be92398045 100644 --- a/time/Makefile +++ b/time/Makefile @@ -75,6 +75,7 @@ tests := \ tst-strftime2 \ tst-strftime3 \ tst-strftime4 \ + tst-strftime5 \ tst-strptime \ tst-strptime-whitespace \ tst-strptime2 \ diff --git a/time/strftime_l.c b/time/strftime_l.c index 12bc5794be..9f2917134a 100644 --- a/time/strftime_l.c +++ b/time/strftime_l.c @@ -198,7 +198,7 @@ static const CHAR_T zeroes[16] = /* "0000000000000000" */ # define memset_space(P, Len) \ do { \ - int _len = (Len); \ + size_t _len = (Len); \ \ do \ { \ @@ -206,12 +206,12 @@ static const CHAR_T zeroes[16] = /* "0000000000000000" */ (P) = MEMPCPY ((P), spaces, _this * sizeof (CHAR_T)); \ _len -= _this; \ } \ - while (_len > 0); \ + while (_len != 0); \ } while (0) # define memset_zero(P, Len) \ do { \ - int _len = (Len); \ + size_t _len = (Len); \ \ do \ { \ @@ -219,7 +219,7 @@ static const CHAR_T zeroes[16] = /* "0000000000000000" */ (P) = MEMPCPY ((P), zeroes, _this * sizeof (CHAR_T)); \ _len -= _this; \ } \ - while (_len > 0); \ + while (_len != 0); \ } while (0) #else # ifdef COMPILE_WIDE @@ -234,14 +234,14 @@ static const CHAR_T zeroes[16] = /* "0000000000000000" */ #define add(n, f) \ do \ { \ - int _n = (n); \ - int _delta = width - _n; \ - int _incr = _n + (_delta > 0 ? _delta : 0); \ - if ((size_t) _incr >= maxsize - i) \ + size_t _n = (n); \ + size_t _delta = (width < 0 || (size_t) width < _n) ? 0 : width - _n; \ + size_t _incr = _n + _delta; \ + if (_incr >= maxsize - i) \ return 0; \ if (p) \ { \ - if (_delta > 0) \ + if (_delta != 0) \ { \ if (pad == L_('0')) \ memset_zero (p, _delta); \ diff --git a/time/tst-strftime5.c b/time/tst-strftime5.c new file mode 100644 index 0000000000..e625312731 --- /dev/null +++ b/time/tst-strftime5.c @@ -0,0 +1,69 @@ +/* Test strftime with a large time zone name. + Copyright (C) 2026 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 + <https://www.gnu.org/licenses/>. */ + +#include <time.h> + +#include <libc-diag.h> +#include <limits.h> +#include <stddef.h> +#include <support/blob_repeat.h> +#include <support/check.h> + +static int +do_test (void) +{ + /* 6 is chosen so that the truncated value triggered the original bug. */ + enum { size = (size_t) INT_MAX + 6 }; + struct support_blob_repeat repeat = support_blob_repeat_allocate + ("X", 1, size); + if (repeat.start == NULL) + FAIL_UNSUPPORTED ("could not allocate buffer for time zone name"); + char *tzname = repeat.start; + tzname[size - 1] = '\0'; + + /* Time at the epoch with a fake time zone name. */ + struct tm tmbuf = + { + .tm_mday = 1, + .tm_zone = tzname, + }; + + char buf[10]; + buf[9] = 'A'; + + TEST_COMPARE (strftime (buf, 9, "%Z", &tmbuf), 0); + TEST_COMPARE (buf[9], 'A'); + + /* GCC complains about using a width (3) below with %Z, but it is + supported in the glibc implementation. */ + DIAG_PUSH_NEEDS_COMMENT; + DIAG_IGNORE_NEEDS_COMMENT (0, "-Wformat"); + + TEST_COMPARE (strftime (buf, 9, "%3Z", &tmbuf), 0); + TEST_COMPARE (buf[9], 'A'); + + TEST_COMPARE (strftime (buf, 9, "%03Z", &tmbuf), 0); + TEST_COMPARE (buf[9], 'A'); + + DIAG_POP_NEEDS_COMMENT; + + support_blob_repeat_free (&repeat); + return 0; +} + +#include <support/test-driver.c>