Avoid signed char-to-int conversions in tolower/toupper calls

These functions document that the arguments must be representable
by `unsigned char`.  In particular, NetBSD is strict about this.

Fixes: #27574
This commit is contained in:
Brad King
2026-02-06 10:39:52 -05:00
parent 71e019d4a4
commit 05ed2af7da
21 changed files with 62 additions and 44 deletions
+1 -1
View File
@@ -116,7 +116,7 @@ int cmCPackInnoSetupGenerator::PackageFiles()
if (cmSystemTools::LowerCase(i) == "english") {
params["MessagesFile"] = "\"compiler:Default.isl\"";
} else {
i[0] = static_cast<char>(std::toupper(i[0]));
i[0] = static_cast<char>(std::toupper(static_cast<unsigned char>(i[0])));
params["MessagesFile"] = cmStrCat("\"compiler:Languages\\", i, ".isl\"");
}
+9 -7
View File
@@ -143,7 +143,7 @@ int cmCPackRPMGenerator::PackageComponents(bool ignoreGroup)
++compIt) {
std::string component(compIt->first);
std::transform(component.begin(), component.end(), component.begin(),
::toupper);
[](unsigned char c) { return std::toupper(c); });
if (this->IsOn("CPACK_RPM_" + compIt->first + "_DEBUGINFO_PACKAGE") ||
this->IsOn("CPACK_RPM_" + component + "_DEBUGINFO_PACKAGE")) {
@@ -157,7 +157,7 @@ int cmCPackRPMGenerator::PackageComponents(bool ignoreGroup)
compGIt != this->ComponentGroups.end(); ++compGIt) {
std::string component(compGIt->first);
std::transform(component.begin(), component.end(), component.begin(),
::toupper);
[](unsigned char c) { return std::toupper(c); });
if (this->IsOn("CPACK_RPM_" + compGIt->first + "_DEBUGINFO_PACKAGE") ||
this->IsOn("CPACK_RPM_" + component + "_DEBUGINFO_PACKAGE")) {
@@ -174,7 +174,8 @@ int cmCPackRPMGenerator::PackageComponents(bool ignoreGroup)
if (!compIt->second.Group) {
std::string component(compIt->first);
std::transform(component.begin(), component.end(),
component.begin(), ::toupper);
component.begin(),
[](unsigned char c) { return std::toupper(c); });
if (this->IsOn("CPACK_RPM_" + compIt->first +
"_DEBUGINFO_PACKAGE") ||
@@ -206,7 +207,8 @@ int cmCPackRPMGenerator::PackageComponents(bool ignoreGroup)
std::string mainComponentUpper(mainComponent);
std::transform(mainComponentUpper.begin(), mainComponentUpper.end(),
mainComponentUpper.begin(), ::toupper);
mainComponentUpper.begin(),
[](unsigned char c) { return std::toupper(c); });
// The default behavior is to have one package by component group
// unless CPACK_COMPONENTS_IGNORE_GROUP is specified.
@@ -218,7 +220,7 @@ int cmCPackRPMGenerator::PackageComponents(bool ignoreGroup)
compGIt != this->ComponentGroups.end(); ++compGIt) {
std::string component(compGIt->first);
std::transform(component.begin(), component.end(), component.begin(),
::toupper);
[](unsigned char c) { return std::toupper(c); });
if (mainComponentUpper == component) {
// main component will be handled last
@@ -240,7 +242,7 @@ int cmCPackRPMGenerator::PackageComponents(bool ignoreGroup)
if (!compIt->second.Group) {
std::string component(compIt->first);
std::transform(component.begin(), component.end(), component.begin(),
::toupper);
[](unsigned char c) { return std::toupper(c); });
if (mainComponentUpper == component) {
// main component will be handled last
@@ -283,7 +285,7 @@ int cmCPackRPMGenerator::PackageComponents(bool ignoreGroup)
++compIt) {
std::string component(compIt->first);
std::transform(component.begin(), component.end(), component.begin(),
::toupper);
[](unsigned char c) { return std::toupper(c); });
if (mainComponentUpper == component) {
// main component will be handled last
+1 -1
View File
@@ -42,7 +42,7 @@ short cmCursesColor::GetColor(char id, short fallback)
if (!initialized) {
if (auto* v = getenv("CCMAKE_COLORS")) {
while (v[0] && v[1] && v[1] == '=') {
auto const n = std::toupper(*v);
auto const n = std::toupper(static_cast<unsigned char>(*v));
char buffer[12];
memset(buffer, 0, sizeof(buffer));
+1 -1
View File
@@ -147,7 +147,7 @@ int form_request_by_name( const char *str )
strncpy(buf,str,sizeof(buf));
while( (i<sizeof(buf)) && (buf[i] != '\0') )
{
buf[i] = toupper((int)(buf[i]));
buf[i] = toupper((unsigned char)(buf[i]));
i++;
}
+4 -2
View File
@@ -3702,7 +3702,8 @@ bool cmCTest::ConvertInstrumentationJSONFileToXML(std::string const& fpath,
bool generating_test_xml = root["role"] == "test";
if (!generating_test_xml) {
std::string element_name = root["role"].asString();
element_name[0] = static_cast<char>(std::toupper(element_name[0]));
element_name[0] = static_cast<char>(
std::toupper(static_cast<unsigned char>(element_name[0])));
xml.StartElement(element_name);
std::vector<std::string> keys = root.getMemberNames();
for (auto const& key : keys) {
@@ -3734,7 +3735,8 @@ bool cmCTest::ConvertInstrumentationJSONFileToXML(std::string const& fpath,
std::vector<std::string> keys = dynamic_information.getMemberNames();
for (auto const& key : keys) {
std::string measurement_name = key;
measurement_name[0] = static_cast<char>(std::toupper(measurement_name[0]));
measurement_name[0] = static_cast<char>(
std::toupper(static_cast<unsigned char>(measurement_name[0])));
xml.StartElement("NamedMeasurement");
xml.Attribute("type", "numeric/double");
+2 -2
View File
@@ -1556,8 +1556,8 @@ std::string cmComputeLinkInformation::NoCaseExpression(std::string const& str)
ret += c;
} else {
ret += '[';
ret += static_cast<char>(tolower(c));
ret += static_cast<char>(toupper(c));
ret += static_cast<char>(tolower(static_cast<unsigned char>(c)));
ret += static_cast<char>(toupper(static_cast<unsigned char>(c)));
ret += ']';
}
}
+1 -1
View File
@@ -349,7 +349,7 @@ void cmFindLibraryHelper::RegexFromLiteral(std::string& out,
out += "\\";
}
if (dirCase == cmSystemTools::DirCase::Insensitive) {
out += static_cast<char>(tolower(ch));
out += static_cast<char>(tolower(static_cast<unsigned char>(ch)));
} else {
out += ch;
}
+7 -4
View File
@@ -127,10 +127,13 @@ void cmGccDepfileLexerHelper::sanitizeContent()
// Unescape the colon following the drive letter.
// Some versions of GNU compilers can escape this character.
// c\:\path must be transformed to c:\path
if (pit->size() >= 3 && std::toupper((*pit)[0]) >= 'A' &&
std::toupper((*pit)[0]) <= 'Z' && (*pit)[1] == '\\' &&
(*pit)[2] == ':') {
pit->erase(1, 1);
if (pit->size() >= 3) {
auto pit0 = static_cast<char>(
std::toupper(static_cast<unsigned char>((*pit)[0])));
if (pit0 >= 'A' && pit0 <= 'Z' && (*pit)[1] == '\\' &&
(*pit)[2] == ':') {
pit->erase(1, 1);
}
}
#endif
++pit;
+7 -3
View File
@@ -170,7 +170,9 @@ std::string ImplBase::GetWorkingDirectoryOnDrive(char letter)
// Use the drive's working directory, if any.
std::string d = this->OS.GetWorkingDirectoryOnDrive(letter);
std::replace(d.begin(), d.end(), '\\', '/');
if (d.size() >= 3 && std::toupper(d[0]) == std::toupper(letter) &&
if (d.size() >= 3 &&
std::toupper(static_cast<unsigned char>(d[0])) ==
std::toupper(static_cast<unsigned char>(letter)) &&
d[1] == ':' && d[2] == '/') {
d[0] = letter;
d.push_back('/');
@@ -179,7 +181,9 @@ std::string ImplBase::GetWorkingDirectoryOnDrive(char letter)
// Use the current working directory if the drive matches.
d = this->OS.GetWorkingDirectory();
if (d.size() >= 3 && std::toupper(d[0]) == std::toupper(letter) &&
if (d.size() >= 3 &&
std::toupper(static_cast<unsigned char>(d[0])) ==
std::toupper(static_cast<unsigned char>(letter)) &&
d[1] == ':' && d[2] == '/') {
d[0] = letter;
d.push_back('/');
@@ -280,7 +284,7 @@ Control Impl<Policy>::ResolveRoot(Root root)
if (Policy::ActualCase == Options::ActualCase::Yes) {
// Normalize the drive letter to upper-case.
P[0] = static_cast<char>(std::toupper(P[0]));
P[0] = static_cast<char>(std::toupper(static_cast<unsigned char>(P[0])));
}
// The root is a drive letter. The root '/' immediately follows.
+1 -1
View File
@@ -99,6 +99,6 @@ std::string cmSbomArguments::GetPackageFileName() const
std::string const pkgNameOnDisk = this->GetPackageDirName();
std::string format = GetSbomFileExtension(this->GetFormat());
std::transform(format.begin(), format.end(), format.begin(),
[](char const c) { return std::tolower(c); });
[](unsigned char c) { return std::tolower(c); });
return cmStrCat(pkgNameOnDisk, format);
}
+3 -2
View File
@@ -14,8 +14,9 @@ bool cmStrCaseEq(cm::string_view s1, cm::string_view s2)
return false;
}
return std::equal(s1.begin(), s1.end(), s2.begin(),
[](char a, char b) { return tolower(a) == tolower(b); });
return std::equal(
s1.begin(), s1.end(), s2.begin(),
[](unsigned char a, unsigned char b) { return tolower(a) == tolower(b); });
}
std::string cmTrimWhitespace(cm::string_view str)
+9 -5
View File
@@ -463,7 +463,8 @@ std::string cmSystemTools::LowerCase(cm::string_view s)
std::string n;
n.resize(s.size());
for (size_t i = 0; i < s.size(); i++) {
n[i] = static_cast<std::string::value_type>(tolower(s[i]));
n[i] = static_cast<std::string::value_type>(
tolower(static_cast<unsigned char>(s[i])));
}
return n;
}
@@ -474,7 +475,8 @@ std::string cmSystemTools::UpperCase(cm::string_view s)
std::string n;
n.resize(s.size());
for (size_t i = 0; i < s.size(); i++) {
n[i] = static_cast<std::string::value_type>(toupper(s[i]));
n[i] = static_cast<std::string::value_type>(
toupper(static_cast<unsigned char>(s[i])));
}
return n;
}
@@ -1362,7 +1364,7 @@ std::string cmSystemTools::GetRealPathResolvingWindowsSubst(
}
// Normalize to upper-case drive letter as cm::PathResolver does.
if (resolved_path.size() > 1 && resolved_path[1] == ':') {
resolved_path[0] = toupper(resolved_path[0]);
resolved_path[0] = toupper(static_cast<unsigned char>(resolved_path[0]));
}
return resolved_path;
#else
@@ -1384,10 +1386,12 @@ std::string cmSystemTools::GetRealPath(std::string const& path,
// limitation to otherwise preserve susbt drives.
if (resolved_path.size() >= 2 && resolved_path[1] == ':' &&
path.size() >= 2 && path[1] == ':' &&
toupper(resolved_path[0]) != toupper(path[0])) {
toupper(static_cast<unsigned char>(resolved_path[0])) !=
toupper(static_cast<unsigned char>(path[0]))) {
// FIXME: Add thread_local or mutex if we use threads.
static std::map<char, std::string> substMap;
char const drive = static_cast<char>(toupper(path[0]));
char const drive =
static_cast<char>(toupper(static_cast<unsigned char>(path[0])));
std::string maybe_subst = cmStrCat(drive, ":/");
auto smi = substMap.find(drive);
if (smi == substMap.end()) {
+2 -2
View File
@@ -47,8 +47,8 @@ int Strucmp(cm::string_view l, cm::string_view r)
cm::string_view::size_type ri = 0;
do {
lc = std::tolower(l[li++]);
rc = std::tolower(r[ri++]);
lc = std::tolower(static_cast<unsigned char>(l[li++]));
rc = std::tolower(static_cast<unsigned char>(r[ri++]));
} while (lc == rc && li < l.size() && ri < r.size());
return lc == rc ? static_cast<int>(l.size() - r.size()) : lc - rc;
+2 -2
View File
@@ -500,8 +500,8 @@ int do_build(int ac, char const* const* av)
};
auto resolvePackagesLambda = [&](std::string const& value) -> bool {
std::string v = value;
std::transform(v.begin(), v.end(), v.begin(), ::tolower);
std::transform(v.begin(), v.end(), v.begin(),
[](unsigned char c) { return std::tolower(c); });
if (v == "on") {
resolveMode = PackageResolveMode::Force;
} else if (v == "only") {
+1 -1
View File
@@ -66,7 +66,7 @@ CM_LOCAL char* lowercase(const char* string)
}
strcpy(new_string, string); /* NOLINT */
for (p = new_string; *p != 0; ++p) {
*p = CM_CAST(char, tolower(*p));
*p = CM_CAST(char, tolower(CM_CAST(unsigned char, *p)));
}
return new_string;
}
+2 -1
View File
@@ -92,7 +92,8 @@ public:
std::string GetWorkingDirectoryOnDrive(char letter) override
{
std::string result;
auto i = this->WorkDirOnDrive.find(std::tolower(letter));
auto i = this->WorkDirOnDrive.find(
std::tolower(static_cast<unsigned char>(letter)));
if (i != this->WorkDirOnDrive.end()) {
result = i->second;
}
+1 -1
View File
@@ -41,7 +41,7 @@ int main(int argc, char** argv)
std::this_thread::sleep_for(std::chrono::milliseconds(12000));
std::string input = getStdin();
for (auto& c : input) {
c = static_cast<char>(std::toupper(c));
c = static_cast<char>(std::toupper(static_cast<unsigned char>(c)));
}
std::cout << input << std::flush;
std::cerr << "2" << std::flush;
+1 -1
View File
@@ -11,7 +11,7 @@ int main(void)
char build_config_name[] = BUILD_CONFIG_NAME;
char* c;
for (c = build_config_name; *c; ++c) {
*c = (char)tolower((int)*c);
*c = (char)tolower((unsigned char)*c);
}
fprintf(stderr, "build_config_name=\"%s\"\n", build_config_name);
#ifdef TEST_CONFIG_DEBUG
+1 -1
View File
@@ -25,7 +25,7 @@ static char const* Getcwd(char* buf, unsigned int len)
}
// make sure the drive letter is capital
if (strlen(buf) > 1 && buf[1] == ':') {
buf[0] = toupper(buf[0]);
buf[0] = toupper((unsigned char)buf[0]);
}
for (p = buf; *p; ++p) {
if (*p == '\\') {
@@ -712,9 +712,9 @@ __la_stat(const char *path, struct stat *st)
char exttype[4];
++ p;
exttype[0] = toupper(*p++);
exttype[1] = toupper(*p++);
exttype[2] = toupper(*p++);
exttype[0] = toupper((unsigned char)*p++);
exttype[1] = toupper((unsigned char)*p++);
exttype[2] = toupper((unsigned char)*p++);
exttype[3] = '\0';
if (!strcmp(exttype, "EXE") || !strcmp(exttype, "CMD") ||
!strcmp(exttype, "BAT") || !strcmp(exttype, "COM"))
+3 -2
View File
@@ -426,8 +426,9 @@ private:
# if defined(_WIN32)
bool is_drive_name(pointer ptr)
{
return std::toupper(ptr[0]) >= 'A' && std::toupper(ptr[0]) <= 'Z' &&
ptr[1] == ':';
auto ptr0 =
static_cast<char>(std::toupper(static_cast<unsigned char>(ptr[0])));
return ptr0 >= 'A' && ptr0 <= 'Z' && ptr[1] == ':';
}
# endif