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
This commit is contained in:
Mark Johnston committed 2025-06-20 16:39:22 +00:00
1 parent 41399ce61b
commit 770fba248d
4 files changed
+18 -3

No files matched your search

+1 -1
View File
@@ -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
+1 -1
View File
@@ -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);
+1 -1
View File
@@ -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
+15
View File
@@ -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__)