Skip to content

fix: avoid cctype UB, dedupe msvc-runtime errors, use std::any_of - #203

Open
Wael-MA wants to merge 1 commit into
build-cpp:mainfrom
Wael-MA:main
Open

fix: avoid cctype UB, dedupe msvc-runtime errors, use std::any_of#203
Wael-MA wants to merge 1 commit into
build-cpp:mainfrom
Wael-MA:main

Conversation

@Wael-MA

@Wael-MA Wael-MA commented Aug 13, 2026

Copy link
Copy Markdown

Summary

Three small, behavior-preserving cleanups across the parser/generator:

  1. Avoid UB from <cctype> calls on signed charstd::isdigit, std::isupper, std::isxdigit, std::isalnum, and std::isspace were being passed raw chars, which is undefined behavior for negative (non-ASCII) bytes. Cast to unsigned char at each call site and include <cctype> explicitly in cmake_generator.cpp.

  2. De-duplicate the msvc-runtime error builder — the same "Unknown runtime..." message was built in two places; extracted into a shared msvc_runtime_error() helper that also avoids per-iteration std::string allocations (const char * loop).

  3. Replace manual scan loops with std::any_ofcontains_language_source and has_include now use the standard algorithm, which reads the intent directly and short-circuits identically.

Testing

  • cmake -B build + cmake --build passes cleanly (C++11 target).

Comment thread src/cmake_generator.cpp
#include "fs.hpp"
#include "project_parser.hpp"
#include <algorithm>
#include <cctype> // Wael-MA: we call isspace below, better to include it explicitly

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comments need to go.

Comment thread src/cmake_generator.cpp
return false;
// Wael-MA: swapped the manual scan for std::any_of, behavior is the same
return std::any_of(sources.begin(), sources.end(), [&project_extensions](const std::string &source) {
return project_extensions.count(fs::path(source).extension().string()) > 0;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think this is any easier to read and std::any_of has horrible codegen in debug mode, don't think it's worthwhile.

Comment thread src/cmake_generator.cpp
// Wael-MA: std::any_of does the same scan, just a lot easier to read
using value_type = std::pair<std::string, std::vector<std::string>>;
return std::any_of(includes.begin(), includes.end(),
[](const value_type &itr) { return !itr.second.empty(); });

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comment as above, I don't think this makes the code any easier to read.

Comment thread src/cmake_generator.cpp
// Make sure the file ends in a single newline
while (!generated_cmake.empty() && std::isspace(generated_cmake.back())) {
// Wael-MA: isspace must receive an unsigned char, plain chars can be negative
while (!generated_cmake.empty() && std::isspace(static_cast<unsigned char>(generated_cmake.back()))) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just use a C cast

Comment thread src/project_parser.cpp
@@ -657,7 +664,9 @@ Project::Project(const Project *parent, const std::string &path, bool build) : p

auto is_cmake_arg = [](const std::string &s) {
for (auto c : s) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change this to unsigned char c : s and then you don't have to touch the code below

Comment thread src/project_parser.cpp
@@ -695,7 +704,8 @@ Project::Project(const Project *parent, const std::string &path, bool build) : p
throw_key_error("Empty hash value", argItr.first, argItr.second);
}
for (char c : value) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same as above

Comment thread src/project_parser.cpp
@@ -1308,7 +1312,9 @@ bool Project::cmake_minimum_version(int major, int minor) const {

bool Project::is_condition_name(const std::string &name) {
for (auto ch : name) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

2 participants