Skip to content

Commit 8b31aa2

Browse files
committed
[libcxx] Work around picolibc argv handling in tests.
This fixes some test failures when the libcxx tests are run against an up-to-date picolibc on embedded Arm, because those tests depend on an unsupported locale but the `hasAnyLocale` preliminary check wrongly concluded that the locale _was_ supported. `hasAnyLocale` passes a set of locale strings to a test program via the command line, and checks if the libc under test reports that any of the locals can be successfully set via setlocale(). In some invocations one of the locale names contains a space, e.g. the Windows-style locale name "English_United States.1252". Unfortunately picolibc's crt0, when running under Arm semihosting, fetches the single command string from the host and then splits it up at spaces without implementing any kind of quoting. So it simply isn't possible to get a space into an argv word. As a result, we end up testing for the locale (in this example) "English_United". In up-to-date versions of picolibc, this is actually accepted, since it contains no objectionable character set specification (or indeed any at all). So the lit check wrongly concludes that libc supports that locale, and enables some locale tests, which fail. This patch works around the issue entirely within `hasAnyLocale()`, by applying URL %-encoding to each locale name to remove spaces and any likely command-line quote characters. Then the test program (included as a string literal within the same Python function) undoes that quoting. This should make no difference in cases where the argv quoting worked anyway: the quoting and unquoting is unnecessary in that situation, but should still be reliable. But in cases where argv handling is extremely simplistic, this works around it.
1 parent 2cb5241 commit 8b31aa2

File tree

1 file changed

+26
-1
lines changed
  • libcxx/utils/libcxx/test

1 file changed

+26
-1
lines changed

libcxx/utils/libcxx/test/dsl.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -274,14 +274,38 @@ def hasAnyLocale(config, locales):
274274
%{exec} -- this means that the command may be executed on a remote host
275275
depending on the %{exec} substitution.
276276
"""
277+
278+
# Some locale names contain spaces, and some embedded use cases
279+
# (in particular picolibc under Arm semihosting) can't support
280+
# spaces in argv words. Work around this by applying URL-style
281+
# %-encoding to the locale names, and undoing it in our test
282+
# program.
283+
percent_encode = lambda s: ''.join(
284+
"%{:02x}".format(c) if c in b' %\\"\'' or c >= 128 else chr(c)
285+
for c in s.encode())
286+
277287
program = """
278288
#include <stddef.h>
279289
#if defined(_LIBCPP_VERSION) && !_LIBCPP_HAS_LOCALIZATION
280290
int main(int, char**) { return 1; }
281291
#else
292+
#include <stdlib.h>
282293
#include <locale.h>
283294
int main(int argc, char** argv) {
284295
for (int i = 1; i < argc; i++) {
296+
// %-decode argv[i] in place
297+
for (char *p = argv[i], *q = argv[i]; *p; p++) {
298+
if (*p == '%') {
299+
char hex[3];
300+
hex[0] = *++p;
301+
hex[1] = *++p;
302+
hex[2] = '\\0';
303+
*q++ = (char)strtoul(hex, NULL, 0);
304+
} else {
305+
*q++ = *p;
306+
}
307+
}
308+
// Try to set the locale
285309
if (::setlocale(LC_ALL, argv[i]) != NULL) {
286310
return 0;
287311
}
@@ -290,7 +314,8 @@ def hasAnyLocale(config, locales):
290314
}
291315
#endif
292316
"""
293-
return programSucceeds(config, program, args=[shlex.quote(l) for l in locales])
317+
return programSucceeds(config, program, args=[
318+
shlex.quote(percent_encode(l)) for l in locales])
294319

295320

296321
@_memoizeExpensiveOperation(lambda c, flags="": (c.substitutions, c.environment, flags))

0 commit comments

Comments
 (0)