The branch stable/14 has been updated by markj: URL: https://cgit.FreeBSD.org/src/commit/?id=d162d59c393dacdcd6867e5ed7af2edc5cc0cddf
commit d162d59c393dacdcd6867e5ed7af2edc5cc0cddf Author: Mark Johnston <ma...@freebsd.org> AuthorDate: 2025-06-20 16:10:37 +0000 Commit: Mark Johnston <ma...@freebsd.org> CommitDate: 2025-07-09 00:42:52 +0000 localedef: Use consistent sorting order In several modules we build up an RB tree keyed by wide characters. wchar_t has different signedness on different platforms, so iteration over such a tree results in platform-dependent ordering. The ctype module uses this ordering when writing the output file, which creates reproducibility problems when comparing the results of cross builds and native builds (e.g., native amd64 vs. cross-building on arm64). Modify such comparisons to always be unsigned. Introduce a helper function for this purpose. In the other modules I believe the sort order does not affect program output. On systems with signed wchar_t, of the files in /usr/share/locale this only affects zh_CN.GB18030/LC_CTYPE. MFC after: 2 weeks Sponsored by: The FreeBSD Foundation Sponsored by: Klara, Inc. Differential Revision: https://reviews.freebsd.org/D50756 (cherry picked from commit 770fba248daff6cc72ce0bfbd1f2a941c90dc99a) --- usr.bin/localedef/charmap.c | 2 +- usr.bin/localedef/collate.c | 2 +- usr.bin/localedef/ctype.c | 2 +- usr.bin/localedef/localedef.h | 15 +++++++++++++++ 4 files changed, 18 insertions(+), 3 deletions(-) diff --git a/usr.bin/localedef/charmap.c b/usr.bin/localedef/charmap.c index 1da4d8921ecb..a36d4ccd174e 100644 --- a/usr.bin/localedef/charmap.c +++ b/usr.bin/localedef/charmap.c @@ -236,7 +236,7 @@ cmap_compare_wc(const void *n1, const void *n2) const charmap_t *c1 = n1; const charmap_t *c2 = n2; - return ((c1->wc < c2->wc) ? -1 : (c1->wc > c2->wc) ? 1 : 0); + return (wchar_cmp(c1->wc, c2->wc)); } void diff --git a/usr.bin/localedef/collate.c b/usr.bin/localedef/collate.c index da3f26b4d0ba..39f1ba250be6 100644 --- a/usr.bin/localedef/collate.c +++ b/usr.bin/localedef/collate.c @@ -422,7 +422,7 @@ collchar_compare(const void *n1, const void *n2) wchar_t k1 = ((const collchar_t *)n1)->wc; wchar_t k2 = ((const collchar_t *)n2)->wc; - return (k1 < k2 ? -1 : k1 > k2 ? 1 : 0); + return (wchar_cmp(k1, k2)); } RB_GENERATE_STATIC(collchars, collchar, entry, collchar_compare); diff --git a/usr.bin/localedef/ctype.c b/usr.bin/localedef/ctype.c index ab7b76e57b2d..f86a267b0b32 100644 --- a/usr.bin/localedef/ctype.c +++ b/usr.bin/localedef/ctype.c @@ -93,7 +93,7 @@ ctype_compare(const void *n1, const void *n2) const ctype_node_t *c1 = n1; const ctype_node_t *c2 = n2; - return (c1->wc < c2->wc ? -1 : c1->wc > c2->wc ? 1 : 0); + return (wchar_cmp(c1->wc, c2->wc)); } void diff --git a/usr.bin/localedef/localedef.h b/usr.bin/localedef/localedef.h index 4b141ac8dc09..25e75eab8a7b 100644 --- a/usr.bin/localedef/localedef.h +++ b/usr.bin/localedef/localedef.h @@ -38,6 +38,7 @@ #include <stdarg.h> #include <stdio.h> #include <stdlib.h> +#include <wchar.h> extern int com_char; extern int esc_char; @@ -173,5 +174,19 @@ void werr(const char *, ...); const char *get_wide_encoding(void); int max_wide(void); +/* + * A helper function to compare wide characters when sorting. Forcibly cast to + * an unsigned type to help ensure that output is consistent no matter the + * signedness of wchar_t. + */ +static inline int +wchar_cmp(const wchar_t a, const wchar_t b) +{ + return ((uint32_t)a < (uint32_t)b ? -1 : + ((uint32_t)a > (uint32_t)b ? 1 : 0)); +} +_Static_assert(sizeof(wchar_t) == sizeof(uint32_t), + "wchar_t must be 32 bits wide"); + //#define _(x) gettext(x) #define INTERR fprintf(stderr,"internal fault (%s:%d)\n", __FILE__, __LINE__)