From 10642adf8e29cfc557c638e0ce15fd5fcd01e3db Mon Sep 17 00:00:00 2001 From: Koichi Murase Date: Fri, 14 Aug 2026 05:56:45 +0900 Subject: [PATCH] lib/sh/stringvec.c (strvec_{posix,str}cmp): use unsigned char to be consistent with strcmp The present code tries to reduce the call to "strcmp" by comparing the first character of the strings inline, but the comparison is made by char (which is signed in a typical environment). This is inconsistent with strcmp, which compares strings using unsigned char. I'm not sure if I need to show an actual affected case, but it is hard to create a natural case. I'm not sure if this can be robustly reproducible in other systems, but the following demonstrates the issue in my system (Linux, with strcoll(3) from glibc). $ mkdir t $ cd t $ LANG=C $ touch {,a}{$'\1',$'\xA9'}.txt $ LANG=en_US.UTF-8 $ printf '%s\n' *.txt | cat -v a^A.txt aM-).txt M-).txt ^A.txt \x01 and \xA9 are shown by ^A and M-) in the "cat -v" output. Here, we can observe that, when \x01 and \xA9 are the second characters of the filenames, \x01 comes first. However, when they are the first characters of the filenames, \xA9 comes first because it is a negative number (-87) in char. --- lib/sh/stringvec.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/sh/stringvec.c b/lib/sh/stringvec.c index 8017ee63..2d0c9d57 100644 --- a/lib/sh/stringvec.c +++ b/lib/sh/stringvec.c @@ -159,7 +159,9 @@ strvec_posixcmp (char **s1, char **s2) return result; #endif - if ((result = **s1 - **s2) == 0) + /* Use unsigned char for comparison to be consistent with strcmp, which uses + unsigned char. */ + if ((result = (unsigned char)**s1 - (unsigned char)**s2) == 0) result = strcmp (*s1, *s2); return (result); @@ -175,7 +177,9 @@ strvec_strcmp (char **s1, char **s2) #else /* !HAVE_STRCOLL */ int result; - if ((result = **s1 - **s2) == 0) + /* Use unsigned char for comparison to be consistent with strcmp, which uses + unsigned char. */ + if ((result = (unsigned char)**s1 - (unsigned char)**s2) == 0) result = strcmp (*s1, *s2); return (result);