Skip to content

abicheck v0.3.0

Latest

Choose a tag to compare

@napetrov napetrov released this 03 Jun 20:43
519e5ed

[0.3.0] — 2026-06-03

Added

Release Recommendation (semver + SONAME)

  • New abicheck/semver.py derives a release recommendation from the
    policy-aware verdict + change set: a semantic-version bump
    (major/minor/patch/none) and a SONAME action
    (bump_required/bump_performed/bump_missing/no_bump_needed).
  • Always emitted in abicheck compare --format json under the additive
    release_recommendation key (also in --stat --format json and leaf mode);
    opt-in for Markdown via the new --recommend flag (works in leaf mode
    too). Policy-aware (honours --policy sdk_vendor/plugin_abi and custom
    policy files).
  • JSON schema bumped to 1.1 (additive): release_recommendation documented
    as an optional object in abicheck/schemas/compare_report.schema.json.
  • New tests: tests/test_semver_recommendation.py,
    tests/test_workflow_scenarios.py (drop-in upgrade, additive minor,
    host↔plugin load contract, policy-scoped decision).

User-Scenario / Flow Catalog (end-to-end scanner validation)

  • New internal user-scenario catalog under tests/scenarios/*.yaml (grouped
    by theme, merged by globbing so it scales past one file): defines real-world
    user flows (CI gate, public-surface compliance scan, SARIF for code
    scanning, release recommendation, suppression, offline snapshots, …) —
    distinct from examples/ (change-type fixtures) and plans/ (backlog).
  • tests/test_scenarios.py drives each automated scenario through the abicheck
    CLI end-to-end (CliRunner on JSON snapshots) and asserts the documented
    outcome, validating abicheck as a scanner tool, not only a change detector.
    Every scenario's validates: is checked against the use-case registry.
  • Captures the missed usage scenario from issue #235 (public-header scoping
    must suppress private ABI breaks) as SC-PUBLIC-SURFACE-SCOPE, now an
    end-to-end regression guard.

Use-Case Coverage Evaluation + machine-checked registry

  • New docs/development/usecase-coverage-evaluation.md maps abicheck against
    the full application/library ABI-API change use-case space and records the
    code/test/example follow-ups (gaps G1–G8).
  • New docs/development/usecase-registry.yaml — the machine-checkable source of
    truth for every use case (status, axis, evidence, gap, next_steps),
    validated by tests/test_usecase_registry.py: coverage claims must cite
    evidence paths that exist, and unfinished items must carry a gap + plan. This
    makes the use cases first-class, extensible, and testable.
  • Cross-platform honesty: docs/reference/platforms.md now states the
    validation reality (Linux = CI-validated baseline; macOS/Windows =
    parser-level/partial), guarded by tests/test_platform_coverage_honesty.py.

JUnit XML Output

  • --format junit for compare and compare-release commands — produces
    JUnit XML reports for CI systems (GitLab CI, Jenkins, Azure DevOps) that
    display ABI check results as standard test results in their dashboards.
  • Each exported symbol/type maps to a <testcase>; breaking changes become
    <failure> elements with severity type and source location.
  • Supports --show-only filtering, suppression files, and policy overrides.
  • New module: abicheck/junit_report.py (stdlib only, no external dependencies).

Binary Fingerprint Rename Detection (Exploratory)

  • Binary fingerprint rename detection (exploratory, ADR-003 extension):
    new binary_fingerprint.py module with compute_function_fingerprints(),
    match_renamed_functions(), and compute_section_summary(). Uses function
    code size and SHA-256 hash from ELF .dynsym + .text to detect likely
    renames when symbol names change but the underlying code is identical.
    New FUNC_LIKELY_RENAMED change kind (verdict: COMPATIBLE_WITH_RISK).
    Integrated as the fingerprint_renames detector — fires only in
    elf_only_mode (stripped binaries without debug info or headers).

Debian Symbols File Adapter

  • abicheck debian-symbols generate — generate Debian symbols files (dpkg-gensymbols
    format) from shared library binaries. Supports C++ demangled (c++) form, ELF symbol
    versioning (@Base / @VERSION_NODE), and automatic SONAME-to-package-name derivation.
    Options: --package, --version, --no-cpp, -o.
  • abicheck debian-symbols validate — validate a Debian symbols file against a binary.
    Reports missing and new symbols. Respects (optional) tag semantics. Exit code 0 = match,
    2 = mismatch.
  • abicheck debian-symbols diff — diff two Debian symbols files showing added, removed,
    and version-changed symbols.
  • Full Debian tag syntax support: (c++), (optional), (arch=...), pipe-separated groups
    ((c++|optional)), and round-trip formatting preservation.
  • New module: abicheck.debian_symbols with Python API for programmatic use
    (generate_symbols_file, validate_symbols, diff_symbols_files, parse_symbols_file).

ELF Symbol-Version Policy Checks

  • symbol_version_node_removed (BREAKING) — detects when an entire version node
    (e.g., LIBFOO_1.0) is removed from the version script, listing affected symbols.
    Deduplicated with symbol_version_defined_removed (the more specific node-level
    change wins).
  • symbol_moved_version_node (COMPATIBLE_WITH_RISK) — detects when a symbol
    migrates between version nodes (e.g., LIBFOO_1.0LIBFOO_2.0).
  • soname_bump_recommended (COMPATIBLE) — post-detector advisory emitted when
    binary-incompatible changes are detected but the SONAME is not bumped. This
    advisory can be escalated to BREAKING via --policy-file with
    soname_bump_recommended: break.
  • soname_bump_unnecessary (COMPATIBLE) — advisory emitted when the SONAME is
    bumped but no binary-incompatible changes are detected.
  • version_script_missing (COMPATIBLE) — advisory emitted when the new library
    exports symbols without a version script (--version-script).
  • New diff_versioning.py module with version-node graph diffing, SONAME bump
    policy check (post-detector), and version-script presence detection.
  • Cross-detector deduplication for SYMBOL_VERSION_NODE_REMOVED vs
    SYMBOL_VERSION_DEFINED_REMOVED.
  • 35 new tests covering all version-policy scenarios and checker integration.

Config-key consistency follow-ups

  • --scope-public-headers/--no-scope-public-headers toggle added to appcompat
    (previously always-on with no control) and to compare-release (toggle form).
  • --severity-preset/--severity-* added to compare-release (aggregated across
    per-library, bundle, and matrix findings, honoring per-library --policy-file
    overrides; removed-library exit 8 still takes precedence) and appcompat
    (full-compare mode only — weak/--check-against keeps the verdict-based exit;
    app-scoped to breaking_for_app, with missing required symbols/versions floored
    as hard breaks).
  • --debug-format {auto,dwarf,btf,ctf} selector on compare/dump; the legacy
    --btf/--ctf/--dwarf flags are hidden from --help but remain functional.
    --compile-db is likewise hidden (still an alias of -p/--build-dir).
  • --report-mode impact (sugar for full + --show-impact).
  • appcompat now warns (instead of silently ignoring) when -H/-I are supplied
    in weak (--check-against) / --list-required-symbols mode.
  • New rationale doc docs/development/config-key-review.md (full CLI/config-key
    surface audit with per-mode inconsistency analysis and implementation status).

Changed

ELF-only function removals are now BREAKING

  • Breaking (verdict change): a removed exported function symbol with no
    header/DWARF confirmation (func_removed_elf_only) is now classified
    BREAKING instead of compatible. Removing a dynamic export breaks old
    binaries that link or dlsym() it regardless of header evidence, matching
    abidiff/ABICC. This can change a compare/compat run from compatible to
    breaking (legacy compare exit 04); the false-positive avalanche this
    could otherwise cause is held back by the shared transitive-runtime symbol
    filter below (those symbols no longer enter a non-runtime library's surface).

Fixed

Windows example-platform metadata matches the validated build surface

  • Corrected the platform declarations for eight advanced C++/template example
    fixtures (case79, case85, case95, case100, case101, case102,
    case110, case111) from Linux/macOS/Windows to Linux/macOS. These cases
    remain in the full catalog, but Windows CI no longer attempts CMake builds
    for fixtures that are not validated on the Windows toolchain.

Transitive stdlib/runtime symbols no longer leak into the ABI surface

  • Centralized ELF ABI-relevance filtering into abicheck/elf_symbol_filter.py
    and shared it across the symbols-only dumper, DWARF snapshot extraction, and
    symbol/type diffing. Previously a weak transitive libstdc++/libc++ export
    could be filtered from symbols-only reports yet re-enter as a PUBLIC DWARF
    function, producing phantom FUNC_REMOVED and type-reachability findings
    (observed on oneTBB libtbbmalloc 2021.5→2021.9, where abidiff was clean).
  • DWARF export indexing and DW_AT_deleted subprograms now consult the same
    filter; libstdc++/libc++ themselves are exempt (they own std::).
  • Project-owned RTTI (_ZTI*/_ZTS* for the library's own types) is preserved;
    only standard-library RTTI prefixes are dropped.

Cross-mode config-key consistency (CLI surface review)

  • Breaking (default change): compare-release now restricts findings to the
    public-header ABI surface by default (--scope-public-headers on), matching
    compare and the Python API. Previously it was off-by-default. Pass
    --no-scope-public-headers to restore the old unscoped output. This can change
    which findings (and therefore exit codes) a release surfaces in CI.
  • Breaking (default change): compare-release -j/--jobs now defaults to 0
    (auto-detect CPU count, i.e. parallel) instead of 1 (serial). Report ordering
    is deterministic regardless of -j (results are emitted in matched-library
    order), so this does not churn snapshots — but multi-library runs now parallelize
    by default.
  • compare --demangle is now tri-state: it defaults on for the text
    formats whose renderer demangles symbols (markdown/review) and off
    for json/sarif/html (HTML symbols are rendered structurally);
    explicit --demangle/--no-demangle still wins.
  • compare prints the active exit-code scheme (legacy verdict vs severity-aware)
    to stderr for human formats, so the previously-silent switch on the first
    --severity-* flag is now visible. Exit-code numbers are unchanged.

Planned

  • --policy-file schema validation improvements
  • Version-stamped typedef suppression (libpng png_libpng_version_X_Y_Z pattern)