With the current localtime.c implementation, increasing
TZ_MAX_CHARS from 50 to its maximum value 256 does not allocate
more memory, so there is little point to the limit of 50.
* NEWS, localtime.c: Mention this.
* tzfile.h (TZ_MAX_CHARS): Increase from 50 to 256.
* zic.c (writezone): If -v, warn about going over the old limit.
---
NEWS | 7 +++++++
localtime.c | 4 ++--
tzfile.h | 6 +++---
zic.c | 5 +++++
4 files changed, 17 insertions(+), 5 deletions(-)
diff --git a/NEWS b/NEWS
index 95b1851c..dd592871 100644
--- a/NEWS
+++ b/NEWS
@@ -5,6 +5,7 @@ Unreleased, experimental changes
Briefly:
The "right" TZif files are no longer installed by default.
-DTZ_RUNTIME_LEAPS=0 disables runtime support for leap seconds.
+ TZif files are no longer limited to 50 bytes of abbreviations.
Several integer overflow bugs have been fixed.
Changes to build procedure
@@ -29,6 +30,12 @@ Unreleased, experimental changes
POSIX, shrinks tzcode's attack surface, and is more efficient,
it fails to support Internet RFC 9636's leap seconds.
+ zic now can generate, and localtime.c can now use, TZif files that
+ hold up to 256 bytes of abbreviations, counting trailing NULs.
+ The previous limit was 50 bytes, and some tzdata TZif files were
+ already consuming 40 bytes. zic -v warns if it generates a file
+ that exceeds the old 50-byte limit.
+
localtime.c no longer accesses the posixrules file generated by
zic -p. Hence for obsolete and nonconforming settings like
TZ="AST4ADT" it now typically falls back on US DST rules, rather
diff --git a/localtime.c b/localtime.c
index ed7a32f2..32835d08 100644
--- a/localtime.c
+++ b/localtime.c
@@ -1227,8 +1227,8 @@ tzloadbody(char const *name, struct state *sp, char
tzloadflags,
if (tzparse(&up->buf[1], ts, sp)) {
/* Attempt to reuse existing abbreviations.
- Without this, America/Anchorage would be right on
- the edge after 2037 when TZ_MAX_CHARS is 50, as
+ Without this, America/Anchorage would
+ consume 50 bytes for abbreviations, as
sp->charcnt equals 40 (for LMT AST AWT APT AHST
AHDT YST AKDT AKST) and ts->charcnt equals 10
(for AKST AKDT). Reusing means sp->charcnt can
diff --git a/tzfile.h b/tzfile.h
index 71b60f37..1b1bac4a 100644
--- a/tzfile.h
+++ b/tzfile.h
@@ -95,13 +95,13 @@ struct tzhead {
#ifndef TZ_MAX_TYPES
/* This must be at least 18 for Europe/Vilnius with 'zic -b fat'. */
-# define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */
+# define TZ_MAX_TYPES 256 /* Limited to 256 by Internet RFC 9636. */
#endif /* !defined TZ_MAX_TYPES */
#ifndef TZ_MAX_CHARS
/* This must be at least 40 for America/Anchorage. */
-# define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */
- /* (limited by what unsigned chars can hold) */
+# define TZ_MAX_CHARS 256 /* Maximum number of abbreviation characters */
+ /* (limited to 256 by Internet RFC 9636) */
#endif /* !defined TZ_MAX_CHARS */
#ifndef TZ_MAX_LEAPS
diff --git a/zic.c b/zic.c
index 73155138..1a2f4741 100644
--- a/zic.c
+++ b/zic.c
@@ -2986,6 +2986,11 @@ writezone(const char *const name, const char *const
string, char version,
continue;
}
+ if (pass == 2 && noise && 50 < thischarcnt)
+ warning(_("%s: pre-2026 reference clients mishandle"
+ " more than 50 bytes of abbreviations"),
+ name);
+
/* Output a LO_TIME transition if needed; see limitrange.
But do not go below the minimum representable value
for this pass. */
--
2.51.0