diff --git a/CHANGELOG.md b/CHANGELOG.md index 533a7d4..11d1967 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,98 +18,13 @@ under *Changed* or *Removed*. The `Unreleased` block accumulates entries during development and is rolled into a dated version block (`## [X.Y.Z] — YYYY-MM-DD`) when a release PR closes a milestone. -### Added - -- **Benchmark extension — tail-latency percentiles and optional jemalloc/tcmalloc baselines.** - The pool-vs-malloc microbenchmark gains an opt-in `--percentiles` mode that emits a separate - per-operation **p50/p90/p99/p999** table — the dynamic-pool growth row surfaces the - microsecond-scale growth spike the aggregate median hides — and **jemalloc** / **tcmalloc** - baselines measured the safe way, by re-running the bench under **`LD_PRELOAD`** (those - allocators take over global `malloc` on load, so they cannot be linked or `dlopen`'d beside - the system allocator without crashing). A `# allocator:` header line discloses which allocator - each run measured; the bench carries no allocator-specific code, so the default build stays - zero-external-dependency (spec §3.3). Both are strictly additive: the - [ADR-0014](docs/adr/0014-microbenchmark-methodology-pool-vs-malloc.md) aggregate ns/op table - and its committed numbers are unchanged. A Linux `bench-baselines` CI cell installs both - allocators and exercises the new paths (non-asserting on numbers, per ADR-0014 §8). - [ADR-0045](docs/adr/0045-benchmark-percentiles-and-external-baselines.md). Closes #111. -- **Coverage-guided fuzzing harness for the pool surface.** A new - [`pool_fuzz.cpp`](src/test/cpp/it/d4np/memorypool/pool_fuzz.cpp) drives randomized - `alloc` / `free(valid)` / `free(NULL)` / `free(foreign)` sequences — over both fixed and - dynamic-growth pools — through a stateful opcode interpreter, asserting the no-alias, - per-block-canary, foreign/NULL-no-op ([ADR-0012](docs/adr/0012-foreign-pointer-and-out-of-range-pointer-policy.md)), - and `InstrumentedPool` accounting invariants against a shadow oracle so a corruption becomes - a saved reproducer. One engine-agnostic source yields the Clang-only libFuzzer target - `pool_fuzz` (opt-in `PBR_MEMORY_POOL_BUILD_FUZZERS`; a `fuzz` preset builds it under - `-fsanitize=fuzzer,address,undefined`, and a dedicated CI job replays the seed corpus and - fuzzes for a bounded time on every PR) and an always-built standalone `pool_fuzz_replay` that - makes the seed corpus a portable regression gate everywhere — including MSVC, where libFuzzer - is unavailable. Test-only and additive; the release build and the benchmark numbers are - untouched. [ADR-0044](docs/adr/0044-coverage-guided-fuzzing-harness.md). Closes #108. -- **Opt-in debug hardening — freed-block poisoning, a guard word, and free-list - safe-linking.** A compile-time knob `PBR_MEMORY_POOL_HARDENING` (OFF by default; a `harden` - CMake preset turns it on) hardens the intrusive free list against the classic - use-after-free / pointer-corruption primitives an in-band next-link exposes: freed blocks are - **poisoned** (`0xDE`) and verified on the next allocation (use-after-free), a per-slot - trailing **guard word** detects a contiguous write past `block_size` (buffer overflow) and a - repeated free (double-free — the [ADR-0012](docs/adr/0012-foreign-pointer-and-out-of-range-pointer-policy.md) - gap), and the next-link is stored with glibc-style **safe-linking** - (`ptr XOR (slot_addr >> 12)`) so a leaked/overwritten link is neither usable nor silently - followed. On detection a swappable `HardeningViolationHandler` - ([`pool_hardening.hpp`](src/main/cpp/it/d4np/memorypool/pool_hardening.hpp)) fires — the - default prints a diagnostic and `abort()`s. The guard lives in *added* slot stride, so the - user-visible `block_size` and the [ADR-0009](docs/adr/0009-free-list-layout-block-size-constraints-and-alignment-guarantee.md) - alignment guarantee are unchanged, and the default build is byte-for-byte and cycle-for-cycle - unchanged (the knob is fully compiled out). Works with fixed and dynamic pools across all - three thread-safety policies. Purely additive and ABI-compatible; a hardened build is - deliberately not layout-compatible with a non-hardened one (never mix configurations). - [ADR-0043](docs/adr/0043-opt-in-debug-hardening.md). Closes #109. -- **`std::pmr::memory_resource` adapter — `PoolMemoryResource`.** A new header-only Adapter - ([`pool_memory_resource.hpp`](src/main/cpp/it/d4np/memorypool/pool_memory_resource.hpp)) - binds one `Pool` behind the runtime `std::pmr::memory_resource` interface, so a single - resource can back any `std::pmr` container through `std::pmr::polymorphic_allocator` without - the per-type `PoolAllocator` rebind — the "door left open" in ADR-0018. Deterministic - `(bytes, alignment)` routing to the pool (over-sized / over-aligned requests fall back to a - configurable upstream resource; exhaustion throws `std::bad_alloc`), `is_equal` by - `(pool, upstream)` identity, gated behind `PBR_MEMORY_POOL_HAS_PMR` where `` - is available. Purely additive and ABI-compatible — the frozen C ABI and existing C++ types - are unchanged; opens roadmap Milestone 9 (a `v1.2.0` candidate). - [ADR-0042](docs/adr/0042-pmr-memory-resource-adapter.md). Closes #107. -- **C4 component diagram of the pool internals** in the specification - ([`docs/specs/01_spec_cpp_memory_pool.md`](docs/specs/01_spec_cpp_memory_pool.md), §4.2), - authored in Mermaid. [ADR-0041](docs/adr/0041-mermaid-diagram-tooling.md) records Mermaid - as the in-repo diagram tooling — C4 levels are drawn as flowcharts with `subgraph` - boundaries, and PlantUML, checked-in images, and Mermaid's experimental `C4Component` DSL - were considered and rejected. Closes the last open item of the specification review. - Documentation-only; no API change. Refs #105. - -### Changed - -- **`zh-Hans` / `ja` README translations re-synced to `v1.1.2`.** Carries the English - README's `v1.1.2` deltas into both locales — the `v1.1.2` status badge (and its - release-tag link) and the new `v1.1.2` status paragraph (the four BUG-0001…0004 - fixes, the `docs-site` badge removal, and the translation re-sync). The - `translation-status.md` manifest's two README rows are re-pinned to the current - source commit (`d38b598`) and flipped from `stale` back to `translated`, clearing - the `i18n-freshness` flag the `v1.1.2` release raised. Documentation-only; no API change. -- **Specification reconciled with the as-built system.** - [`docs/specs/01_spec_cpp_memory_pool.md`](docs/specs/01_spec_cpp_memory_pool.md) was the - original greenfield brief and had drifted from the delivered (`v1.0.0`-frozen) library. It - now cross-links the realizing ADRs, formalizes the `§2`/`§3` subsection anchors already - referenced across the ADR set, disambiguates the `§2.2` dynamic-growth model (non-contiguous - chunk-linking; ADR-0022/0023/0024), documents the `§4.1` - block-size/alignment/strict-aliasing constraints (ADR-0009), the `§5.3` error semantics - (ADR-0012/0016) and `§5.4` introspection (ADR-0015/0025), and adds a `§7` spec→ADR map plus - the explicitly deferred items (#107 `pmr`, #108 fuzzing, #109 hardening). The - `zh-Hans`/`ja` spec translation rows are marked `stale` pending a follow-up re-sync. - Documentation-only; no API change. Refs #105. - ## Released versions Each released version is an **immutable** entry under [`docs/changelog/`](docs/changelog/) — one file per release, newest first ([ADR-0038](docs/adr/0038-changelog-version-split.md)). They are never edited after release; only the `Unreleased` block above changes during development. | Version | Date | Highlights | |---------|------|------------| +| [1.2.0](docs/changelog/v1/v1.2.0.md) | 2026-07-09 | Milestone 9 — std::pmr adapter, opt-in hardening, fuzzing harness, benchmark percentiles + jemalloc/tcmalloc baselines | | [1.1.2](docs/changelog/v1/v1.1.2.md) | 2026-06-15 | Maintenance — InstrumentedPool/core bug fixes (BUG-0001…0004) + docs | | [1.1.1](docs/changelog/v1/v1.1.1.md) | 2026-06-15 | Maintenance — bug ledger, PR-metadata policy, journal split, SECURITY.md, CI Node bump | | [1.1.0](docs/changelog/v1/v1.1.0.md) | 2026-06-14 | Internationalization (zh-Hans / ja) & post-release governance | @@ -122,4 +37,4 @@ Each released version is an **immutable** entry under [`docs/changelog/`](docs/c | [0.2.0](docs/changelog/v0/v0.2.0.md) | 2026-06-11 | Core memory pool — single-threaded O(1) MVP | | [0.1.0](docs/changelog/v0/v0.1.0.md) | 2026-06-10 | Build system & project skeleton | -[Unreleased]: https://github.com/danielPoloWork/pbr-cpp-memory-pool/compare/v1.1.2...HEAD +[Unreleased]: https://github.com/danielPoloWork/pbr-cpp-memory-pool/compare/v1.2.0...HEAD diff --git a/README.md b/README.md index ac1cd40..3af4238 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![API reference](https://img.shields.io/badge/API%20reference-Doxygen-1f6feb.svg)](https://danielpolowork.github.io/pbr-cpp-memory-pool/) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) [![Standard: C++17 / ANSI C](https://img.shields.io/badge/Standard-C%2B%2B17%20%2F%20ANSI%20C-blue.svg)](docs/specs/01_spec_cpp_memory_pool.md) -[![Status: v1.1.2 stable](https://img.shields.io/badge/Status-v1.1.2%20stable-brightgreen.svg)](https://github.com/danielPoloWork/pbr-cpp-memory-pool/releases/tag/v1.1.2) +[![Status: v1.2.0 stable](https://img.shields.io/badge/Status-v1.2.0%20stable-brightgreen.svg)](https://github.com/danielPoloWork/pbr-cpp-memory-pool/releases/tag/v1.2.0) > Part of the **Purpose-Built References (PBR)** series — small, didactic, production-quality C/C++ reference implementations of high-performance building blocks. @@ -193,6 +193,8 @@ Reports for other host × compiler combinations (Linux / GCC, Linux / Clang, mac ## Status +`v1.2.0` — **Milestone 9 (Ergonomics, Hardening & Tooling)**, the first post-`v1.0.0` MINOR. A wave of **additive, ABI-compatible** capabilities on top of the frozen public surface — the shipped library is byte-for-byte what `v1.1.x` produced in a default build. Adds a [`std::pmr::memory_resource` adapter](docs/adr/0042-pmr-memory-resource-adapter.md) (`PoolMemoryResource`, #107), **opt-in debug hardening** — freed-block poisoning, a guard word, and free-list safe-linking behind the `PBR_MEMORY_POOL_HARDENING` knob ([ADR-0043](docs/adr/0043-opt-in-debug-hardening.md), #109), a **coverage-guided fuzzing harness** ([ADR-0044](docs/adr/0044-coverage-guided-fuzzing-harness.md), #108), and a **benchmark extension** — p99 tail latency + `LD_PRELOAD` jemalloc/tcmalloc baselines ([ADR-0045](docs/adr/0045-benchmark-percentiles-and-external-baselines.md), #111). Every new feature is header-only, behind an opt-in knob, or test/bench-only; the `v1.0.0` C ABI and C++ types are unchanged. Five new ADRs (0041–0045) bring the total to 45. Release notes: [`docs/releases/v1.2.0.md`](docs/releases/v1.2.0.md). The earlier line: + `v1.1.2` — **maintenance** (bug fixes + documentation), a PATCH over `v1.1.1`. The public surface is unchanged — no API/ABI change. Fixes four verified, externally-reported defects (the first use of the in-repo [bug ledger](docs/bugs/), [ADR-0039](docs/adr/0039-bug-ledger-and-triage-protocol.md)): an `InstrumentedPool` growth-counter **data race** (BUG-0001), a `live_` counter **underflow** on foreign/double frees (BUG-0002), a missing `destroyed` event on move-assignment (BUG-0003), and a latent `grow_pool` **overflow** guard (BUG-0004). Also removes the redundant `docs-site` README badge and re-syncs the `zh-Hans`/`ja` translations. Release notes: [`docs/releases/v1.1.2.md`](docs/releases/v1.1.2.md). The earlier line: `v1.1.1` — **maintenance** (documentation / process / tooling), the first post-`v1.1.0` PATCH. The shipped library is byte-identical to `v1.1.0` — no API/ABI/behaviour change. Adds the in-repo [bug ledger](docs/bugs/) + triage protocol ([ADR-0039](docs/adr/0039-bug-ledger-and-triage-protocol.md)), a [PR-metadata policy](docs/adr/0040-pull-request-metadata-policy.md), a [`SECURITY.md`](SECURITY.md), `packaging-smoke` CI for the vcpkg/Conan recipes, the [session journal](docs/journal/) ([ADR-0036](docs/adr/0036-session-journal-extraction.md)), the new-feature roadmap-placement rule ([ADR-0037](docs/adr/0037-new-feature-roadmap-placement.md)), and the per-release changelog split ([ADR-0038](docs/adr/0038-changelog-version-split.md)). Five new ADRs (0036–0040) bring the total to 40. Release notes: [`docs/releases/v1.1.1.md`](docs/releases/v1.1.1.md). The earlier line: @@ -214,6 +216,7 @@ Reports for other host × compiler combinations (Linux / GCC, Linux / Clang, mac | 6 | Observability & Decorators | ✅ complete | | 7 | Release & Polish | ✅ complete | | 8 | i18n & Post-Release Governance | ✅ complete | +| 9 | Ergonomics, Hardening & Tooling | ✅ complete | See [`ROADMAP.md`](ROADMAP.md) for the per-task breakdown and the Spec Coverage Map at the bottom (traceability from spec sections to roadmap items). diff --git a/ROADMAP.md b/ROADMAP.md index 923aed8..1e63d76 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -140,6 +140,7 @@ Goal: a coherent, post-`v1.0.0` wave of **additive, ABI-compatible** capabilitie - [x] 9.2 **Opt-in debug hardening** — freed-block poisoning, canaries, and free-list safe-linking (which also yields double-free detection); zero cost when the gate is off (issue #109). Decided in [ADR-0043](docs/adr/0043-opt-in-debug-hardening.md); implemented in [`memory_pool.cpp`](src/main/cpp/it/d4np/memorypool/memory_pool.cpp) behind the compile-time `PBR_MEMORY_POOL_HARDENING` knob (a `harden` CMake preset), with the swappable violation-handler surface in [`pool_hardening.hpp`](src/main/cpp/it/d4np/memorypool/pool_hardening.hpp) and [`pool_hardening_test.cpp`](src/test/cpp/it/d4np/memorypool/pool_hardening_test.cpp) (CTest `pool_hardening`). The "canary" is realized as one trailing **guard word** living in *added* slot stride — so the user-visible `block_size` and the ADR-0009 alignment guarantee are unchanged and the default build is byte-for-byte unchanged (the mechanism is fully compiled out). Poisoning (`0xDE`) catches use-after-free on the next allocation, the guard word catches a write past `block_size` and a double-free, and glibc-style safe-linking (`ptr XOR (slot_addr >> 12)`) protects the in-band next-link. A `harden` CI matrix cell builds and tests the hardened configuration on each Tier-1 platform. Works with fixed and dynamic pools across all three thread-safety policies. - [x] 9.3 **Coverage-guided fuzzing harness** for the pool surface — a libFuzzer target, time-boxed in CI (issue #108). Decided in [ADR-0044](docs/adr/0044-coverage-guided-fuzzing-harness.md); implemented in [`pool_fuzz.cpp`](src/test/cpp/it/d4np/memorypool/pool_fuzz.cpp) as a stateful opcode interpreter with a shadow oracle that asserts the no-alias, canary-intact, foreign/NULL-no-op ([ADR-0012](docs/adr/0012-foreign-pointer-and-out-of-range-pointer-policy.md)) and `InstrumentedPool` accounting invariants across fixed and dynamic pools. One engine-agnostic source yields both the Clang-only libFuzzer target `pool_fuzz` (opt-in `PBR_MEMORY_POOL_BUILD_FUZZERS`, a `fuzz` preset under `-fsanitize=fuzzer,address,undefined`) and the always-built standalone [`pool_fuzz_replay`](src/test/cpp/it/d4np/memorypool/pool_fuzz_corpus/) target that replays the seed corpus as a portable regression gate (CTest `pool_fuzz_replay`) on every platform, including MSVC. A dedicated `fuzz` CI job replays the corpus and fuzzes for a bounded time on every PR; a crash is filed in the bug ledger ([ADR-0039](docs/adr/0039-bug-ledger-and-triage-protocol.md)). Test-only and additive — the release build and the benchmark numbers are untouched. - [x] 9.4 **Benchmark extension** — external allocator baselines (jemalloc / tcmalloc) and p99 tail-latency reporting (issue #111). Decided in [ADR-0045](docs/adr/0045-benchmark-percentiles-and-external-baselines.md) (extends [ADR-0014](docs/adr/0014-microbenchmark-methodology-pool-vs-malloc.md)); implemented in [`pool_vs_malloc_bench.cpp`](src/bench/cpp/it/d4np/memorypool/pool_vs_malloc_bench.cpp). An opt-in `--percentiles` mode adds a separate per-operation p50/p90/p99/p999 table (the dynamic-pool growth row surfaces the amortized-growth spike the median hides); jemalloc / tcmalloc baselines are measured by re-running the bench under `LD_PRELOAD` (they take over global `malloc` on load, so they cannot be linked or `dlopen`'d beside the system allocator without crashing — an in-process attempt was tried and rejected); a `# allocator:` header discloses which allocator each run measured. The bench carries no allocator-specific code, so the default build keeps zero external dependencies (spec §3.3) and the [ADR-0014](docs/adr/0014-microbenchmark-methodology-pool-vs-malloc.md) aggregate table and its committed numbers are unchanged. A Linux `bench-baselines` CI cell re-runs the bench under each allocator's preload and asserts the disclosure + percentile table (non-asserting on numbers). +- [x] 9.5 **Close Milestone 9 → `v1.2.0`**: bump [`version.hpp`](src/main/cpp/it/d4np/memorypool/version.hpp) (`MINOR` 1→2, `PATCH` 2→0, `PBR_MEMORY_POOL_VERSION_STRING` `"1.2.0"`) with the `pool_smoke` version-check updated in lockstep; roll [`CHANGELOG.md`](CHANGELOG.md) `[Unreleased]` into the sealed [`docs/changelog/v1/v1.2.0.md`](docs/changelog/v1/v1.2.0.md) `## [1.2.0] — 2026-07-09` block (fresh empty `[Unreleased]`, table row + `compare/v1.2.0...HEAD` link); draft [`docs/releases/v1.2.0.md`](docs/releases/v1.2.0.md); refresh the README status badge (`v1.1.2` → `v1.2.0`), status paragraph, and milestone table (Milestone 9 → ✅ complete); mark the two `README.md` translation rows `stale` (re-synced in a post-release follow-up — the M8.8 / [ADR-0042](docs/adr/0042-pmr-memory-resource-adapter.md) i18n dance). Classified **MINOR** (additive surface, no API/ABI/behaviour change). The maintainer reviews and merges this PR, then the agent tags `v1.2.0` from `master` ([ADR-0008](docs/adr/0008-delegate-tag-creation-and-push-to-the-agent.md)) → `release.yml` drafts the GitHub Release → the maintainer clicks *Publish*. **This closes Milestone 9.** --- diff --git a/docs/changelog/v1/v1.2.0.md b/docs/changelog/v1/v1.2.0.md new file mode 100644 index 0000000..d41f769 --- /dev/null +++ b/docs/changelog/v1/v1.2.0.md @@ -0,0 +1,95 @@ +# Changelog — v1.2.0 + +> Immutable release entry — part of the [project changelog](../../../CHANGELOG.md). One file per release; format and rationale in [ADR-0038](../../adr/0038-changelog-version-split.md). Released entries are never edited. + +## [1.2.0] — 2026-07-09 + +**Milestone 9 — Ergonomics, Hardening & Tooling.** The first post-`v1.0.0` +**MINOR**: a coherent wave of **additive, ABI-compatible** capabilities on top of +the frozen public surface. The `v1.0.0` C ABI and C++ types are **unchanged** — a +default build is byte-for-byte and cycle-for-cycle what `v1.1.x` shipped; every new +capability is either header-only, behind an opt-in compile-time knob, or test/bench-only. +Four features: a `std::pmr::memory_resource` **adapter** +([ADR-0042](../../adr/0042-pmr-memory-resource-adapter.md)), opt-in **debug hardening** +([ADR-0043](../../adr/0043-opt-in-debug-hardening.md)), a coverage-guided **fuzzing +harness** ([ADR-0044](../../adr/0044-coverage-guided-fuzzing-harness.md)), and a +**benchmark extension** ([ADR-0045](../../adr/0045-benchmark-percentiles-and-external-baselines.md)) — +plus the specification's C4 component diagram +([ADR-0041](../../adr/0041-mermaid-diagram-tooling.md)). Five new ADRs (0041–0045) bring +the total to **45**. + +### Added + +- **`std::pmr::memory_resource` adapter — `PoolMemoryResource`.** A new header-only Adapter + ([`pool_memory_resource.hpp`](../../../src/main/cpp/it/d4np/memorypool/pool_memory_resource.hpp)) + binds one `Pool` behind the runtime `std::pmr::memory_resource` interface, so a single + resource can back any `std::pmr` container through `std::pmr::polymorphic_allocator` without + the per-type `PoolAllocator` rebind — the "door left open" in ADR-0018. Deterministic + `(bytes, alignment)` routing to the pool (over-sized / over-aligned requests fall back to a + configurable upstream resource; exhaustion throws `std::bad_alloc`), `is_equal` by + `(pool, upstream)` identity, gated behind `PBR_MEMORY_POOL_HAS_PMR` where `` + is available. Purely additive and ABI-compatible. + [ADR-0042](../../adr/0042-pmr-memory-resource-adapter.md). Closes #107. +- **Opt-in debug hardening — freed-block poisoning, a guard word, and free-list + safe-linking.** A compile-time knob `PBR_MEMORY_POOL_HARDENING` (OFF by default; a `harden` + CMake preset turns it on) hardens the intrusive free list against the classic + use-after-free / pointer-corruption primitives an in-band next-link exposes: freed blocks are + **poisoned** (`0xDE`) and verified on the next allocation (use-after-free), a per-slot + trailing **guard word** detects a contiguous write past `block_size` (buffer overflow) and a + repeated free (double-free — the [ADR-0012](../../adr/0012-foreign-pointer-and-out-of-range-pointer-policy.md) + gap), and the next-link is stored with glibc-style **safe-linking** (`ptr XOR (slot_addr >> 12)`). + On detection a swappable `HardeningViolationHandler` + ([`pool_hardening.hpp`](../../../src/main/cpp/it/d4np/memorypool/pool_hardening.hpp)) fires — the + default prints a diagnostic and `abort()`s. The guard lives in *added* slot stride, so the + user-visible `block_size` and the [ADR-0009](../../adr/0009-free-list-layout-block-size-constraints-and-alignment-guarantee.md) + alignment guarantee are unchanged and the default build is fully compiled out. Works with fixed + and dynamic pools across all three thread-safety policies. A `harden` CI cell builds and tests + it on each Tier-1 platform. Purely additive and ABI-compatible; a hardened build is deliberately + not layout-compatible with a non-hardened one. + [ADR-0043](../../adr/0043-opt-in-debug-hardening.md). Closes #109. +- **Coverage-guided fuzzing harness for the pool surface.** + [`pool_fuzz.cpp`](../../../src/test/cpp/it/d4np/memorypool/pool_fuzz.cpp) drives randomized + `alloc` / `free(valid)` / `free(NULL)` / `free(foreign)` sequences — over both fixed and + dynamic-growth pools — through a stateful opcode interpreter, asserting the no-alias, + per-block-canary, foreign/NULL-no-op ([ADR-0012](../../adr/0012-foreign-pointer-and-out-of-range-pointer-policy.md)), + and `InstrumentedPool` accounting invariants against a shadow oracle so a corruption becomes a + saved reproducer. One engine-agnostic source yields the Clang-only libFuzzer target `pool_fuzz` + (opt-in `PBR_MEMORY_POOL_BUILD_FUZZERS`; a `fuzz` preset builds it under + `-fsanitize=fuzzer,address,undefined`, and a dedicated CI job replays the seed corpus and + fuzzes for a bounded time on every PR) and an always-built standalone `pool_fuzz_replay` that + makes the seed corpus a portable regression gate everywhere — including MSVC, where libFuzzer + is unavailable. Test-only and additive. + [ADR-0044](../../adr/0044-coverage-guided-fuzzing-harness.md). Closes #108. +- **Benchmark extension — tail-latency percentiles and jemalloc/tcmalloc baselines.** + The pool-vs-malloc microbenchmark gains an opt-in `--percentiles` mode that emits a separate + per-operation **p50/p90/p99/p999** table — the dynamic-pool growth row surfaces the + microsecond-scale growth spike the aggregate median hides. **jemalloc** / **tcmalloc** + baselines are measured the safe way, by re-running the bench under **`LD_PRELOAD`** (those + allocators take over global `malloc` on load, so they cannot be linked or `dlopen`'d beside the + system allocator without crashing); a `# allocator:` header line discloses which allocator each + run measured. The bench carries no allocator-specific code, so the default build stays + zero-external-dependency (spec §3.3), and the + [ADR-0014](../../adr/0014-microbenchmark-methodology-pool-vs-malloc.md) aggregate ns/op table and + its committed numbers are unchanged. A Linux `bench-baselines` CI cell exercises the new paths + (non-asserting on numbers, per ADR-0014 §8). + [ADR-0045](../../adr/0045-benchmark-percentiles-and-external-baselines.md). Closes #111. +- **C4 component diagram of the pool internals** in the specification + ([`docs/specs/01_spec_cpp_memory_pool.md`](../../../docs/specs/01_spec_cpp_memory_pool.md), §4.2), + authored in Mermaid. [ADR-0041](../../adr/0041-mermaid-diagram-tooling.md) records Mermaid as the + in-repo diagram tooling. Closes the last open item of the specification review. + Documentation-only; no API change. Refs #105. + +### Changed + +- **`zh-Hans` / `ja` README translations re-synced to `v1.1.2`.** Carries the English README's + `v1.1.2` deltas into both locales (the `v1.1.2` status badge and paragraph), with the + `translation-status.md` manifest re-pinned. Documentation-only; no API change. +- **Specification reconciled with the as-built system.** + [`docs/specs/01_spec_cpp_memory_pool.md`](../../../docs/specs/01_spec_cpp_memory_pool.md) now + cross-links the realizing ADRs, formalizes the `§2`/`§3` subsection anchors already referenced + across the ADR set, disambiguates the `§2.2` dynamic-growth model, and adds a `§7` spec→ADR map. + The Milestone 9 features (`§4.1`/`§5.3` hardening, `§6.3` benchmark percentiles + baselines, + `§6.4` fuzzing) were folded into the map as they shipped. Documentation-only; no API change. + Refs #105. + +[1.2.0]: https://github.com/danielPoloWork/pbr-cpp-memory-pool/releases/tag/v1.2.0 diff --git a/docs/i18n/translation-status.md b/docs/i18n/translation-status.md index 226d9e9..6ece84e 100644 --- a/docs/i18n/translation-status.md +++ b/docs/i18n/translation-status.md @@ -16,7 +16,7 @@ Status vocabulary: | Source page | Source commit | Translated at | Status | Reviewer | |-------------|:-------------:|:-------------:|:------:|----------| -| [`README.md`](../../README.md) | `d38b598` | `d38b598` | `translated` | — | +| [`README.md`](../../README.md) | `d38b598` | `d38b598` | `stale` | — | | [`docs/specs/01_spec_cpp_memory_pool.md`](../specs/01_spec_cpp_memory_pool.md) | `2e55dfa` | `2e55dfa` | `stale` | — | | [`docs/patterns/README.md`](../patterns/README.md) | `524f0cc` | `524f0cc` | `translated` | — | @@ -24,7 +24,7 @@ Status vocabulary: | Source page | Source commit | Translated at | Status | Reviewer | |-------------|:-------------:|:-------------:|:------:|----------| -| [`README.md`](../../README.md) | `d38b598` | `d38b598` | `translated` | — | +| [`README.md`](../../README.md) | `d38b598` | `d38b598` | `stale` | — | | [`docs/specs/01_spec_cpp_memory_pool.md`](../specs/01_spec_cpp_memory_pool.md) | `612f9d2` | `612f9d2` | `stale` | — | | [`docs/patterns/README.md`](../patterns/README.md) | `6c6aeb7` | `6c6aeb7` | `translated` | — | diff --git a/docs/releases/v1.2.0.md b/docs/releases/v1.2.0.md new file mode 100644 index 0000000..51946a8 --- /dev/null +++ b/docs/releases/v1.2.0.md @@ -0,0 +1,42 @@ +# pbr-cpp-memory-pool v1.2.0 — Milestone 9 (Ergonomics, Hardening & Tooling) + +The first post-`v1.0.0` **MINOR**. `v1.2.0` closes **Milestone 9** — a coherent wave of **additive, ABI-compatible** capabilities on top of the frozen public surface. The `v1.0.0` C ABI and C++ types are **unchanged**: a default build is byte-for-byte and cycle-for-cycle what `v1.1.x` shipped. Every new capability is header-only, behind an opt-in compile-time knob, or test/bench-only — so nothing here can perturb an existing consumer that does not ask for it. + +## Added + +- **[#107] `std::pmr::memory_resource` adapter — `PoolMemoryResource`** ([ADR-0042](../adr/0042-pmr-memory-resource-adapter.md)). A header-only Adapter that binds one `Pool` behind the runtime `std::pmr::memory_resource` interface, so any `std::pmr` container can draw from it through `std::pmr::polymorphic_allocator` without the per-type `PoolAllocator` rebind — the "door left open" in ADR-0018. Deterministic `(bytes, alignment)` routing; over-sized / over-aligned requests fall back to a configurable upstream resource; exhaustion throws `std::bad_alloc`; `is_equal` by `(pool, upstream)` identity. Gated behind `PBR_MEMORY_POOL_HAS_PMR` where `` exists. +- **[#109] Opt-in debug hardening** ([ADR-0043](../adr/0043-opt-in-debug-hardening.md)). A compile-time knob `PBR_MEMORY_POOL_HARDENING` (OFF by default; a `harden` preset turns it on) hardens the intrusive free list: freed-block **poisoning** (`0xDE`) catches use-after-free on the next allocation; a per-slot trailing **guard word** catches a write past `block_size` (buffer overflow) and a repeated free (double-free — the [ADR-0012](../adr/0012-foreign-pointer-and-out-of-range-pointer-policy.md) gap); and glibc-style **safe-linking** (`ptr XOR (slot_addr >> 12)`) protects the in-band next-link. A swappable `HardeningViolationHandler` reports violations (the default aborts). The guard lives in *added* slot stride, so `block_size` and the ADR-0009 alignment guarantee are unchanged and the default build is fully compiled out. A `harden` CI cell builds and tests it on each Tier-1 platform (including MSVC, where ASan is unavailable). +- **[#108] Coverage-guided fuzzing harness** ([ADR-0044](../adr/0044-coverage-guided-fuzzing-harness.md)). [`pool_fuzz.cpp`](../../src/test/cpp/it/d4np/memorypool/pool_fuzz.cpp) drives randomized `alloc`/`free` sequences through a stateful opcode interpreter, asserting no-alias, per-block-canary, foreign/NULL-no-op, and `InstrumentedPool` accounting invariants against a shadow oracle. One engine-agnostic source yields the Clang-only libFuzzer target `pool_fuzz` (opt-in, run bounded on every PR by a dedicated `fuzz` CI job) and an always-built standalone `pool_fuzz_replay` that gates the seed corpus everywhere — including MSVC, where libFuzzer is unavailable. +- **[#111] Benchmark extension — tail-latency percentiles + external baselines** ([ADR-0045](../adr/0045-benchmark-percentiles-and-external-baselines.md), extends [ADR-0014](../adr/0014-microbenchmark-methodology-pool-vs-malloc.md)). An opt-in `--percentiles` mode emits a per-operation **p50/p90/p99/p999** table; the dynamic-pool growth row surfaces the microsecond-scale growth spike the aggregate median hides. **jemalloc / tcmalloc** are measured by re-running the bench under `LD_PRELOAD` (they take over global `malloc` on load, so they cannot be linked or `dlopen`'d beside the system allocator — an in-process attempt was tried and rejected); a `# allocator:` header discloses which allocator each run measured. The bench carries no allocator-specific code, so the aggregate ns/op table and its committed numbers are unchanged. +- **[#105] C4 component diagram** of the pool internals in the specification (§4.2), authored in Mermaid ([ADR-0041](../adr/0041-mermaid-diagram-tooling.md)) — closing the last open item of the specification review. + +## Changed + +- The **specification** was reconciled with the as-built system (cross-linked realizing ADRs, formalized subsection anchors, a `§7` spec→ADR map), and the Milestone 9 features were folded into it as they shipped. The **`zh-Hans` / `ja` README translations** were re-synced to the `v1.1.2` status. Documentation-only; no API change. + +## Architecture Decision Records + +Five new ADRs — [0041](../adr/0041-mermaid-diagram-tooling.md) (Mermaid diagram tooling), [0042](../adr/0042-pmr-memory-resource-adapter.md) (pmr adapter), [0043](../adr/0043-opt-in-debug-hardening.md) (debug hardening), [0044](../adr/0044-coverage-guided-fuzzing-harness.md) (fuzzing harness), and [0045](../adr/0045-benchmark-percentiles-and-external-baselines.md) (benchmark percentiles + baselines) — bring the running total to **45**. + +## Spec Coverage Map + +**No regression** — all rows remain ✅ ([ADR-0029](../adr/0029-spec-compliance-acceptance-audit.md)). The new features realize previously-deferred §4.1/§5.3 (hardening), §6.3 (percentiles + baselines), and §6.4 (fuzzing) items, now mapped in the spec's §7. + +## What this release does **not** contain + +- **No public-API/ABI change.** `Pool`, `TypedPool`, `PoolAllocator`, `InstrumentedPool`, the C ABI, and the existing compile-time knobs are unchanged. `PoolMemoryResource` is a new additive type; `PBR_MEMORY_POOL_HARDENING` / `PBR_MEMORY_POOL_BUILD_FUZZERS` are new opt-in build knobs, OFF by default. +- **No behaviour change in a default build.** Hardening, the fuzzer, and the benchmark additions are all opt-in or test/bench-only. + +## Verifying the release + +Each platform tarball is the same complete `cmake --install` tree as `v1.1.x` (full headers + static archive + CMake package config + pkg-config `.pc`). SHA-256 checksums are in `SHA256SUMS`: + +```bash +sha256sum --check SHA256SUMS +``` + +## Links + +- Changelog entry: [`CHANGELOG.md` — `[1.2.0]`](../changelog/v1/v1.2.0.md) +- Roadmap: [`ROADMAP.md` — Milestone 9](../../ROADMAP.md) +- Previous release: [`docs/releases/v1.1.2.md`](v1.1.2.md) diff --git a/src/main/cpp/it/d4np/memorypool/version.hpp b/src/main/cpp/it/d4np/memorypool/version.hpp index b01d1e2..d307268 100644 --- a/src/main/cpp/it/d4np/memorypool/version.hpp +++ b/src/main/cpp/it/d4np/memorypool/version.hpp @@ -20,13 +20,13 @@ namespace it::d4np::memorypool { inline constexpr unsigned PBR_MEMORY_POOL_VERSION_MAJOR = 1; /** Minor version component (incremented with each closed milestone pre-1.0). */ -inline constexpr unsigned PBR_MEMORY_POOL_VERSION_MINOR = 1; +inline constexpr unsigned PBR_MEMORY_POOL_VERSION_MINOR = 2; /** Patch version component (incremented for hotfixes between milestones). */ -inline constexpr unsigned PBR_MEMORY_POOL_VERSION_PATCH = 2; +inline constexpr unsigned PBR_MEMORY_POOL_VERSION_PATCH = 0; /** Pre-formatted version string, kept in lockstep with the components above. */ -inline constexpr const char* PBR_MEMORY_POOL_VERSION_STRING = "1.1.2"; +inline constexpr const char* PBR_MEMORY_POOL_VERSION_STRING = "1.2.0"; } // namespace it::d4np::memorypool diff --git a/src/test/cpp/it/d4np/memorypool/pool_smoke_test.cpp b/src/test/cpp/it/d4np/memorypool/pool_smoke_test.cpp index 131168a..165b691 100644 --- a/src/test/cpp/it/d4np/memorypool/pool_smoke_test.cpp +++ b/src/test/cpp/it/d4np/memorypool/pool_smoke_test.cpp @@ -56,12 +56,14 @@ TEST_CASE("version constants are consistent with the project version") { const std::string_view ver{mem::PBR_MEMORY_POOL_VERSION_STRING}; CHECK(ver.find('.') != std::string_view::npos); - // v1.1.2 — maintenance PATCH: fixes four InstrumentedPool/core defects - // (BUG-0001..0004) plus the accumulated docs entries; the library's public - // surface is unchanged. These constants move in lockstep with version.hpp. + // v1.2.0 — Milestone 9 (Ergonomics, Hardening & Tooling): the additive, + // ABI-compatible new-feature wave — std::pmr adapter, opt-in debug + // hardening, a fuzzing harness, and the benchmark extension. The frozen + // v1.0.0 public surface is unchanged, so this is a SemVer MINOR. These + // constants move in lockstep with version.hpp. CHECK(mem::PBR_MEMORY_POOL_VERSION_MAJOR == 1U); - CHECK(mem::PBR_MEMORY_POOL_VERSION_MINOR == 1U); - CHECK(mem::PBR_MEMORY_POOL_VERSION_PATCH == 2U); + CHECK(mem::PBR_MEMORY_POOL_VERSION_MINOR == 2U); + CHECK(mem::PBR_MEMORY_POOL_VERSION_PATCH == 0U); } TEST_CASE("memory_pool_create / _destroy round-trip on valid arguments") {