Skip to content
This repository was archived by the owner on May 1, 2026. It is now read-only.

feat: KSUID_NIL_INIT / KSUID_MAX_INIT static-storage initializer macros#9

Merged
justinjoy merged 2 commits intomainfrom
feature/issue-1-init-macros
Apr 30, 2026
Merged

feat: KSUID_NIL_INIT / KSUID_MAX_INIT static-storage initializer macros#9
justinjoy merged 2 commits intomainfrom
feature/issue-1-init-macros

Conversation

@justinjoy
Copy link
Copy Markdown
Contributor

Closes #1.

Summary

Adds two aggregate-initializer macros to the public header so callers can write

static const ksuid_t my_global = KSUID_NIL_INIT;

at static storage on every platform — including Windows DLL consumers, where KSUID_PUBLIC expands to __declspec(dllimport) and the existing symbol form (= KSUID_NIL) is not a constant expression in user TUs.

Series — two atomic commits

Commit Purpose
6019054 feat: New macros + _Static_assert (C++ -gated as static_assert for extern "C" consumers) + doc block above the sentinels + tests covering both static-link and shared-link scenarios
62c6dfe refactor: Collapse KSUID_NIL / KSUID_MAX definitions in libksuid/ksuid.c to derive from the new macros — single source of truth

Pipeline that ran

Per the global GitHub-issue resolution workflow rule:

  1. Architect study — atomic-commit-sized plan, double-brace { { 0 } } form (C89-clean, MSVC-clean), 2-commit split with .c refactor as commit 2.
  2. Critic study — eight-item risk register: brace dialect divergence, single-source-of-truth tension, gst-indent on multi-line macros, byte-equivalence test, ABI / _Static_assert, -Wmissing-braces, doc contract, CI parity gap (R8: existing tests link the static archive, never exercise the Windows DLL dllimport path).
  3. Synthesize — adopted the 2-commit split. Mitigations applied for every R1..R8: _Static_assert(sizeof(ksuid_t) == KSUID_BYTES), doc block above sentinels, new tests/test_init_shared.c linking the SHARED library with KSUID_BUILDING undefined (closes Critic R8 — the only test that actually exercises the consumer-as-DLL-importer codepath issue Provide KSUID_NIL_INIT / KSUID_MAX_INIT initializer macros for static storage #1 was filed against).
  4. Implementer round 1 — commits 4f53bc6 + a704ab6.
  5. Reviewer round 1 — NEEDS CHANGES: HIGH severity finding — _Static_assert inside extern "C" block is C-only and breaks every C++ consumer (g++ -std=c++17 -I. -Ibuild fails to compile the header).
  6. Implementer rewound (soft reset) and reconstituted into 6019054 + 62c6dfe, folding the #ifdef __cplusplus gate into commit 1 (C++ branch uses static_assert, C branch uses _Static_assert).
  7. Reviewer round 2 — PASS. C++11/17/20 smoke build of a consumer that uses the macros at static storage compiles clean under -Wpedantic. 12/12 tests, clang-tidy 0 findings, gst-indent clean.
  8. Architect meta round 2 — SIGN-OFF.
  9. Critic meta round 2 — SIGN-OFF (additionally verified meson dist end-to-end + nm -D on the shared library to confirm Linux visibility path is exercised by test_init_shared).

What gates this PR

  • gst-indent + clang-tidy 22 (lint phase)
  • Build/test on Ubuntu GCC + Clang, macOS Clang, Windows MSVC (the platform issue Provide KSUID_NIL_INIT / KSUID_MAX_INIT initializer macros for static storage #1 was filed against)
  • DESTDIR install verification (header + license artifacts)
  • ASan + UBSan on Linux + macOS
  • meson dist round-trip on Ubuntu
  • New: test_init_shared linked against the shared library with KSUID_BUILDING undefined — exercises __declspec(dllimport) on Windows and visibility("default") consumer semantics on Linux/macOS

Test plan

  • lint phase green
  • build matrix green on all four OS+compiler lanes (especially Windows MSVC)
  • DESTDIR install lays down ${prefix}/include/libksuid/ksuid.h with the new macros
  • sanitizers green
  • meson dist round-trip green
  • test_init_shared green on every matrix lane — proves the Windows DLL bug is actually fixed

Closes #1 (commit 1 of 2 in the series).

Adds two aggregate-initializer macros next to the existing const
sentinels in libksuid/ksuid.h, so callers can write

    static const ksuid_t my_global = KSUID_NIL_INIT;

at static storage on every platform -- including Windows DLL
consumers, where KSUID_PUBLIC expands to __declspec(dllimport) and
the symbol form (`= KSUID_NIL`) is not a constant expression.

Macro spelling is `{ { 0 } }` / `{ { 0xff, ... } }` (double-brace,
no designated initializers): C89-clean, MSVC-clean, and quiet under
warning_level=3 (-Wmissing-braces / -Wmissing-field-initializers).
Designated `{ .b = { 0 } }` would be C99+ and would be rejected by
older MSVC modes the project does not need to alienate.

Surface added:

  libksuid/ksuid.h
    - Compile-time assertion sizeof(ksuid_t) == KSUID_BYTES so a
      future field added to ksuid_t breaks the build instead of
      silently zero-initialising past the macro's reach. Spelling
      gates on __cplusplus: C uses _Static_assert (C11 keyword),
      C++ uses static_assert (C++11 keyword) -- the assertion
      lives inside the extern "C" block, where _Static_assert is a
      C-only token that g++ rejects.
    - KSUID_NIL_INIT, KSUID_MAX_INIT.
    - Doc block above the sentinels stating the contract: use the
      symbol form for runtime comparison, the macro form for static
      initialization. Calls out the Windows DLL constraint by name.

  tests/test_smoke.c
    - File-scope kStaticNilInit / kStaticMaxInit declared from the
      macros: this is the codepath the issue is about; if the TU
      compiles, the macro really is a constant expression.
    - test_init_macros_match_symbols asserts byte-for-byte parity
      with the runtime symbols and exercises both file-scope and
      block-scope static storage paths.

  tests/test_init_shared.c (NEW)
    - Companion TU that links against the SHARED library
      (ksuid_lib.get_shared_lib()) with KSUID_BUILDING explicitly
      undefined. On Windows this exercises __declspec(dllimport)
      -- the very codepath issue #1 was filed against, which the
      static-archive-linked tests do not reach. Linux / macOS
      runs the same TU through visibility("default") export
      semantics for uniform coverage.
    - tests/meson.build wires it up with c_args : ['-UKSUID_BUILDING']
      (or '/UKSUID_BUILDING' on MSVC) and link_with :
      ksuid_lib.get_shared_lib().

12/12 tests pass on Linux GCC; clang-tidy 22 still reports zero
findings on the slimmed surface; gst-indent leaves the working tree
unchanged. A C++17 smoke build (g++ -std=c++17 -Wpedantic) of a
consumer that uses the new macros at static storage compiles
cleanly.

The .c symbol definitions still spell their bytes by hand. Commit 2
in this series collapses them to derive from the new macros so the
two forms can never drift.
Closes #1 (commit 2 of 2 in the series).

Pure refactor: collapses the hand-written aggregate initializers in
libksuid/ksuid.c so both definitions derive from the public
KSUID_NIL_INIT / KSUID_MAX_INIT macros that landed in commit 1.

  KSUID_PUBLIC const ksuid_t KSUID_NIL = KSUID_NIL_INIT;
  KSUID_PUBLIC const ksuid_t KSUID_MAX = KSUID_MAX_INIT;

Two consequences:

  1. Single source of truth. The 20 0xff bytes that make up KSUID_MAX
     now live in exactly one place (libksuid/ksuid.h's KSUID_MAX_INIT).
     A future contributor cannot accidentally diverge the macro and
     the symbol.

  2. The macro form is exercised at the library's own build site, not
     just in the consumer's TU. If KSUID_NIL_INIT / KSUID_MAX_INIT
     ever fail to compile -- e.g. because someone added a field to
     ksuid_t and forgot to update the macro -- the library itself
     fails to build, before any test even runs.

No public-API or ABI delta; no test changes. The existing
test_nil_is_all_zero, test_max_is_all_ff, and the new
test_init_macros_match_symbols all pass unchanged, proving the
refactor is observationally a no-op.

12/12 tests pass; clang-tidy 22 still reports zero findings.
@justinjoy justinjoy merged commit cd84a7c into main Apr 30, 2026
10 checks passed
@justinjoy justinjoy deleted the feature/issue-1-init-macros branch April 30, 2026 05:54
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Provide KSUID_NIL_INIT / KSUID_MAX_INIT initializer macros for static storage

1 participant