diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 8726d8a3..20e2ddb9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -432,6 +432,32 @@ jobs: - run: sudo cmake --install build - run: cmake --build build --target check + ubuntu2404_gcc16_aarch64: + name: Ubuntu 24.04, GCC 16, aarch64 + runs-on: ubuntu-24.04-arm + env: + DEBIAN_FRONTEND: noninteractive + CC: gcc-16 + CXX: g++-16 + CFLAGS: -pedantic -Werror -g -fno-omit-frame-pointer -fsanitize=address,undefined -fno-sanitize-recover=address,undefined + CXXFLAGS: -pedantic -Werror -Wno-error=overloaded-virtual -g -fno-omit-frame-pointer -fsanitize=address,undefined -fno-sanitize-recover=address,undefined + UBSAN_OPTIONS: print_stacktrace=1 + steps: + - run: uname -rms + - run: python3 --version + - run: sudo add-apt-repository ppa:ubuntu-toolchain-r/test + - run: sudo apt-get update + - run: sudo apt-get install --no-install-recommends -y g++-16 libfl-dev libxml2-utils python3-pytest + - run: which gcc-16 + - run: which g++-16 + - run: echo "cloning ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY}" + - run: git clone --no-checkout -- ${GITHUB_SERVER_URL}/${GITHUB_REPOSITORY} wd + - run: cd wd && git fetch -- origin ${{ github.event.pull_request.head.sha }} && git checkout FETCH_HEAD + - run: cmake -B build -S wd + - run: cmake --build build + - run: sudo cmake --install build + - run: cmake --build build --target check + macos26_homebrew_x86-64: name: macOS 26, Homebrew, x86-64 runs-on: macos-26-intel diff --git a/rumur/resources/header.c b/rumur/resources/header.c index ac645328..7b4b6c31 100644 --- a/rumur/resources/header.c +++ b/rumur/resources/header.c @@ -35,12 +35,14 @@ } while (0) #endif +/// count leading zeroes, that is not UB for 0 +#define CLZLL(value) \ + ((value) == 0 ? sizeof(unsigned long long) * CHAR_BIT \ + : __builtin_clzll(value)) + #define BITS_TO_BYTES(size) \ ((size) / CHAR_BIT + ((size) % CHAR_BIT == 0 ? 0 : 1)) -#define BITS_FOR(value) \ - ((value) == 0 \ - ? 0 \ - : (sizeof(unsigned long long) * CHAR_BIT - __builtin_clzll(value))) +#define BITS_FOR(value) (sizeof(unsigned long long) * CHAR_BIT - CLZLL(value)) /* The size of the compressed state data in bytes. */ enum { STATE_SIZE_BYTES = BITS_TO_BYTES(STATE_SIZE_BITS) }; @@ -1893,8 +1895,8 @@ handle_narrow(struct handle h, size_t offset, size_t width) { ASSERT(h.offset + offset + width <= h.offset + h.width && "narrowing a handle with values that actually expand it"); - size_t r __attribute__((unused)); - assert(!ADD(h.offset, offset, &r) && "narrowing handle overflows a size_t"); + assert(!ADD(h.offset, offset, &(size_t){0}) && + "narrowing handle overflows a size_t"); return (struct handle){ .base = h.base + (h.offset + offset) / CHAR_BIT, @@ -1923,8 +1925,8 @@ handle_index(const char *NONNULL context, const char *rule_name, expr, rule_name == NULL ? "" : " within ", rule_name == NULL ? "" : rule_name); - size_t r __attribute__((unused)); - assert(!ADD(root.offset, r2, &r) && "indexing handle overflows a size_t"); + assert(!ADD(root.offset, r2, &(size_t){0}) && + "indexing handle overflows a size_t"); return (struct handle){ .base = root.base + (root.offset + r2) / CHAR_BIT, @@ -3295,9 +3297,12 @@ static __attribute__((const)) bool slot_neq(slot_t a, slot_t b) { enum { INITIAL_SET_SIZE_EXPONENT = - sizeof(unsigned long long) * 8 - 1 - - __builtin_clzll(SET_CAPACITY / sizeof(struct state *) / + CLZLL(SET_CAPACITY / sizeof(struct state *) / sizeof(struct state)) != + sizeof(unsigned long long) * CHAR_BIT + ? sizeof(unsigned long long) * CHAR_BIT - 1 - + CLZLL(SET_CAPACITY / sizeof(struct state *) / sizeof(struct state)) + : 0 }; struct set { @@ -3308,6 +3313,7 @@ struct set { /* Some utility functions for dealing with exponents. */ static size_t set_size(const struct set *NONNULL set) { + assert(set->size_exponent < sizeof(size_t) * CHAR_BIT); return ((size_t)1) << set->size_exponent; } diff --git a/rumur/src/generate-stmt.cc b/rumur/src/generate-stmt.cc index e77eb823..dd2dbad3 100644 --- a/rumur/src/generate-stmt.cc +++ b/rumur/src/generate-stmt.cc @@ -32,7 +32,9 @@ static void clear(std::ostream &out, const TypeExpr &t, if (auto a = dynamic_cast(type.get())) { // The number of elements in this array as a C code string - mpz_class ic = a->index_type->count() - 1; + const mpz_class ic_with_undefined = a->index_type->count(); + assert(ic_with_undefined > 0); + const mpz_class ic = ic_with_undefined - 1; const std::string ub = "((size_t)" + ic.get_str() + "ull)"; // The bit size of each array element as a C code string diff --git a/rumur/src/process.cc b/rumur/src/process.cc index cc5b69ba..a13222b0 100644 --- a/rumur/src/process.cc +++ b/rumur/src/process.cc @@ -204,7 +204,7 @@ int run(const std::vector &args, const std::string &input, } // wait for an event - if (select(nfds, &readfds, &writefds, nullptr, nullptr) < 0) { + if (select(nfds + 1, &readfds, &writefds, nullptr, nullptr) < 0) { // if our select call is correct, any “error” should be an interrupt assert(errno == EAGAIN || errno == EINTR); }