Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 3 additions & 50 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,62 +18,15 @@ 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.

### Removed

- **The `docs-site` CI status badge** was removed from the README header in all three
locales (English, `zh-Hans`, `ja`). The published Doxygen site is already linked from
the **API reference** badge, so the separate build-status badge was redundant. The
`docs-site.yml` workflow itself is unchanged. The badge is removed from the
translations in the same change; the `translation-status.md` manifest's two README
rows are marked `stale` here (the English source moved ahead of their pin) and
re-pinned + flipped back to `translated` in a follow-up once this lands on `master`.
Documentation-only; no API change.

### Changed

- **`zh-Hans` / `ja` README translations re-synced to `v1.1.1`.** Carries the English
README's `v1.1.1` deltas into both locales — the `v1.1.1` status badge (and its
release-tag link) and the new `v1.1.1` status paragraph (bug ledger, PR-metadata
policy, `SECURITY.md`, `packaging-smoke` CI, session journal, the roadmap-placement
rule, and the changelog split). The `translation-status.md` manifest's two README
rows are re-pinned to the current source commit (`23fc6c4`) and flipped from `stale`
back to `translated`, clearing the `i18n-freshness` flag the `v1.1.1` release raised.
Documentation-only; no API change.

### Fixed

- **`InstrumentedPool` data race on the growth counter ([BUG-0001](docs/bugs/2026/06/BUG-0001-instrumented-pool-growth-counter-data-race.md)).**
`notify_if_grew()` read and wrote the non-atomic `last_growths_` on the allocation
hot path, while the decorator is documented as safe to drive concurrently over a
thread-safe pool — a data race (UB) under `MUTEX` + dynamic growth. `last_growths_`
is now `std::atomic` and advanced with a `compare_exchange`, so the growth event is
emitted once per growth without a race. A concurrent `InstrumentedPool` case was
added to the ThreadSanitizer stress suite. Header-only; no API change.
- **`InstrumentedPool::deallocate` no longer underflows `live_` ([BUG-0002](docs/bugs/2026/06/BUG-0002-instrumented-pool-live-counter-underflow.md)).**
A foreign or double-freed pointer (a no-op in the core, ADR-0012) used to decrement
the unsigned `live_` counter unconditionally, wrapping it to `SIZE_MAX` and
corrupting `stats()`. The decrement now clamps at zero. The C header's
`memory_pool_free` note was corrected to stop claiming the Decorator *detects*
double-free (it counts but cannot distinguish one). Header/doc-only; no API change.
- **`InstrumentedPool` move-assignment now emits `destroyed` for the replaced pool
([BUG-0003](docs/bugs/2026/06/BUG-0003-instrumented-pool-move-assign-missing-destroyed-event.md)).**
Move-assigning over an instrumented pool released its `Pool` and observers without
notifying `PoolEvent::destroyed`, asymmetric with the destructor. It now notifies
before reassignment. Header-only; no API change.
- **Overflow guard in `grow_pool` ([BUG-0004](docs/bugs/2026/06/BUG-0004-grow-pool-growth-size-overflow.md)).**
The dynamic-growth path computed `total * (grow_factor_ - 1)` before any overflow
check, so that product could wrap `size_t` and feed the downstream `block_size`
guard an already-wrapped value. Added a `would_overflow_product` guard on the
growth-count product first, mirroring the create-path guard; on overflow the pool
falls back to fixed-mode exhaustion. Latent (not runtime-reachable — RAM exhausts
first); no API change.
*Nothing yet.*

## 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.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 |
| [1.0.1](docs/changelog/v1/v1.0.1.md) | 2026-06-14 | Packaging patch — vcpkg port + Conan recipe (byte-identical lib) |
Expand All @@ -85,4 +38,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.1...HEAD
[Unreleased]: https://github.com/danielPoloWork/pbr-cpp-memory-pool/compare/v1.1.2...HEAD
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.1 stable](https://img.shields.io/badge/Status-v1.1.1%20stable-brightgreen.svg)](https://github.com/danielPoloWork/pbr-cpp-memory-pool/releases/tag/v1.1.1)
[![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)

> Part of the **Purpose-Built References (PBR)** series — small, didactic, production-quality C/C++ reference implementations of high-performance building blocks.

Expand Down Expand Up @@ -193,6 +193,8 @@ Reports for other host × compiler combinations (Linux / GCC, Linux / Clang, mac

## Status

`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:

`v1.1.0` — **internationalization & post-release governance** (Milestone 8), the first post-1.0 MINOR. Purely **additive** — the library binary is unchanged from `v1.0.x`. Documentation now ships in **Simplified Chinese (`zh-Hans`) and Japanese (`ja`)** (English stays normative — [`docs/i18n/`](docs/i18n/), [ADR-0032](docs/adr/0032-documentation-i18n-architecture.md)); the spec is English-normative ([ADR-0033](docs/adr/0033-english-as-the-spec-normative-language.md)); a [post-release maintenance protocol](docs/workflow/maintenance.md) ([ADR-0034](docs/adr/0034-post-release-maintenance-protocol.md)) governs the maintained-product phase; and an agent-runnable [`consistency lint`](tools/consistency_lint.py) ([ADR-0035](docs/adr/0035-agent-runnable-consistency-lint.md)) gates cross-artifact congruence in CI and the agent contract. Four new ADRs (0032–0035) bring the total to 35. Release notes: [`docs/releases/v1.1.0.md`](docs/releases/v1.1.0.md). The earlier line:
Expand Down
64 changes: 64 additions & 0 deletions docs/changelog/v1/v1.1.2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Changelog — v1.1.2

> 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.1.2] — 2026-06-15

**Maintenance release.** A **PATCH** fixing four verified, third-party-reported
defects (the first real use of the in-repo bug ledger, [ADR-0039](../../../docs/adr/0039-bug-ledger-and-triage-protocol.md))
plus the accumulated documentation work. The library's **public surface is
unchanged** from `v1.1.1` (no API/ABI change); the fixes are header-only / core
internals. Highlights: an `InstrumentedPool` **data race** on the growth counter
([BUG-0001](../../../docs/bugs/2026/06/BUG-0001-instrumented-pool-growth-counter-data-race.md)),
a `live_` counter **underflow** on foreign/double frees + an over-promising header
note ([BUG-0002](../../../docs/bugs/2026/06/BUG-0002-instrumented-pool-live-counter-underflow.md)),
a missing `destroyed` event on move-assignment
([BUG-0003](../../../docs/bugs/2026/06/BUG-0003-instrumented-pool-move-assign-missing-destroyed-event.md)),
and a latent `grow_pool` overflow guard
([BUG-0004](../../../docs/bugs/2026/06/BUG-0004-grow-pool-growth-size-overflow.md)).

### Removed

- **The `docs-site` CI status badge** was removed from the README header in all three
locales (English, `zh-Hans`, `ja`). The published Doxygen site is already linked from
the **API reference** badge, so the separate build-status badge was redundant. The
`docs-site.yml` workflow itself is unchanged. Documentation-only; no API change.

### Changed

- **`zh-Hans` / `ja` README translations re-synced to `v1.1.1`.** Carries the English
README's `v1.1.1` deltas into both locales — the `v1.1.1` status badge (and its
release-tag link) and the new `v1.1.1` status paragraph (bug ledger, PR-metadata
policy, `SECURITY.md`, `packaging-smoke` CI, session journal, the roadmap-placement
rule, and the changelog split), with the `translation-status.md` manifest re-pinned.
Documentation-only; no API change.

### Fixed

- **`InstrumentedPool` data race on the growth counter ([BUG-0001](../../../docs/bugs/2026/06/BUG-0001-instrumented-pool-growth-counter-data-race.md)).**
`notify_if_grew()` read and wrote the non-atomic `last_growths_` on the allocation
hot path, while the decorator is documented as safe to drive concurrently over a
thread-safe pool — a data race (UB) under `MUTEX` + dynamic growth. `last_growths_`
is now `std::atomic` and advanced with a `compare_exchange`, so the growth event is
emitted once per growth without a race. A concurrent `InstrumentedPool` case was
added to the ThreadSanitizer stress suite. Header-only; no API change.
- **`InstrumentedPool::deallocate` no longer underflows `live_` ([BUG-0002](../../../docs/bugs/2026/06/BUG-0002-instrumented-pool-live-counter-underflow.md)).**
A foreign or double-freed pointer (a no-op in the core, ADR-0012) used to decrement
the unsigned `live_` counter unconditionally, wrapping it to `SIZE_MAX` and
corrupting `stats()`. The decrement now clamps at zero. The C header's
`memory_pool_free` note was corrected to stop claiming the Decorator *detects*
double-free (it counts but cannot distinguish one). Header/doc-only; no API change.
- **`InstrumentedPool` move-assignment now emits `destroyed` for the replaced pool
([BUG-0003](../../../docs/bugs/2026/06/BUG-0003-instrumented-pool-move-assign-missing-destroyed-event.md)).**
Move-assigning over an instrumented pool released its `Pool` and observers without
notifying `PoolEvent::destroyed`, asymmetric with the destructor. It now notifies
before reassignment. Header-only; no API change.
- **Overflow guard in `grow_pool` ([BUG-0004](../../../docs/bugs/2026/06/BUG-0004-grow-pool-growth-size-overflow.md)).**
The dynamic-growth path computed `total * (grow_factor_ - 1)` before any overflow
check, so that product could wrap `size_t` and feed the downstream `block_size`
guard an already-wrapped value. Added a `would_overflow_product` guard on the
growth-count product first, mirroring the create-path guard; on overflow the pool
falls back to fixed-mode exhaustion. Latent (not runtime-reachable — RAM exhausts
first); no API change.

[1.1.2]: https://github.com/danielPoloWork/pbr-cpp-memory-pool/releases/tag/v1.1.2
4 changes: 2 additions & 2 deletions docs/i18n/translation-status.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ Status vocabulary:

| Source page | Source commit | Translated at | Status | Reviewer |
|-------------|:-------------:|:-------------:|:------:|----------|
| [`README.md`](../../README.md) | `6f1aa60` | `6f1aa60` | `translated` | — |
| [`README.md`](../../README.md) | `6f1aa60` | `6f1aa60` | `stale` | — |
| [`docs/specs/01_spec_cpp_memory_pool.md`](../specs/01_spec_cpp_memory_pool.md) | `2e55dfa` | `2e55dfa` | `translated` | — |
| [`docs/patterns/README.md`](../patterns/README.md) | `524f0cc` | `524f0cc` | `translated` | — |

## `ja` (Japanese)

| Source page | Source commit | Translated at | Status | Reviewer |
|-------------|:-------------:|:-------------:|:------:|----------|
| [`README.md`](../../README.md) | `6f1aa60` | `6f1aa60` | `translated` | — |
| [`README.md`](../../README.md) | `6f1aa60` | `6f1aa60` | `stale` | — |
| [`docs/specs/01_spec_cpp_memory_pool.md`](../specs/01_spec_cpp_memory_pool.md) | `612f9d2` | `612f9d2` | `translated` | — |
| [`docs/patterns/README.md`](../patterns/README.md) | `6c6aeb7` | `6c6aeb7` | `translated` | — |

Expand Down
43 changes: 43 additions & 0 deletions docs/releases/v1.1.2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# pbr-cpp-memory-pool v1.1.2 — Maintenance (InstrumentedPool & core bug fixes)

A **maintenance PATCH**. `v1.1.2` fixes four verified, externally-reported defects — the **first real use of the in-repo bug ledger** ([ADR-0039](../adr/0039-bug-ledger-and-triage-protocol.md)) — plus the accumulated documentation work since `v1.1.1`. The library's **public surface is unchanged** (no API/ABI change); the fixes are header-only or core internals.

## Fixed

- **[BUG-0001](../../docs/bugs/2026/06/BUG-0001-instrumented-pool-growth-counter-data-race.md) — `InstrumentedPool` growth-counter data race (high).** `notify_if_grew()` read+wrote the non-atomic `last_growths_` on the allocation hot path, racing under the documented-safe `MUTEX` + dynamic-growth + concurrent configuration (UB). `last_growths_` is now `std::atomic`, advanced with a `compare_exchange` so `grew` fires once per growth without a race. A concurrent `InstrumentedPool` case was added to the ThreadSanitizer stress suite (the coverage gap that hid it).
- **[BUG-0002](../../docs/bugs/2026/06/BUG-0002-instrumented-pool-live-counter-underflow.md) — `live_` counter underflow (medium).** `deallocate()` decremented the unsigned `live_` for any non-null pointer, so a foreign or double-freed pointer (a no-op in the core, [ADR-0012](../adr/0012-foreign-pointer-and-out-of-range-pointer-policy.md)) wrapped it to `SIZE_MAX`. The decrement now clamps at zero. The C header's double-free note was corrected — the Decorator counts deallocations but does **not** detect a double-free.
- **[BUG-0003](../../docs/bugs/2026/06/BUG-0003-instrumented-pool-move-assign-missing-destroyed-event.md) — missing `destroyed` event on move-assignment (low).** Move-assigning over an instrumented pool released its `Pool` and observers without emitting `PoolEvent::destroyed`, asymmetric with the destructor. It now notifies before reassignment.
- **[BUG-0004](../../docs/bugs/2026/06/BUG-0004-grow-pool-growth-size-overflow.md) — unguarded `grow_pool` overflow (low/latent).** `total * (grow_factor_ - 1)` was computed before any overflow check; a `would_overflow_product` guard was added first, mirroring the create path. Not runtime-reachable (RAM exhausts first), so no test — a consistency fix.

## Also in this release

- The redundant **`docs-site` CI badge** was removed from the README header (all three locales); the published Doxygen site is still linked from the **API reference** badge.
- The **`zh-Hans` / `ja` README translations** were re-synced to the `v1.1.1` status.

## Architecture Decision Records

No new ADRs — `v1.1.2` is bug fixes and documentation, governed by existing decisions ([ADR-0034](../adr/0034-post-release-maintenance-protocol.md) maintenance protocol, [ADR-0039](../adr/0039-bug-ledger-and-triage-protocol.md) bug ledger). The running total stays **40**.

## Spec Coverage Map

**No change** — all fifteen rows remain ✅ ([ADR-0029](../adr/0029-spec-compliance-acceptance-audit.md)). The fixes correct decorator/diagnostic behaviour and a latent guard, not a spec requirement.

## What this release does **not** contain

- **No public-API/ABI change** — `Pool`, `TypedPool`, `PoolAllocator`, the C ABI, and the compile-time knobs are unchanged.
- **No double-free *detection*** — `v1.1.2` corrects the over-promising header note; genuine double-free detection in the Decorator remains possible future work (it would be a feature, not a patch).

## Verifying the release

Each platform tarball is the same complete `cmake --install` tree as `v1.1.1` (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.1.2]`](../changelog/v1/v1.1.2.md)
- Bug ledger: [`docs/bugs/`](../../docs/bugs/)
- Maintenance protocol: [`docs/workflow/maintenance.md`](../../docs/workflow/maintenance.md)
- Previous release: [`docs/releases/v1.1.1.md`](v1.1.1.md)
4 changes: 2 additions & 2 deletions src/main/cpp/it/d4np/memorypool/version.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,10 @@ inline constexpr unsigned PBR_MEMORY_POOL_VERSION_MAJOR = 1;
inline constexpr unsigned PBR_MEMORY_POOL_VERSION_MINOR = 1;

/** Patch version component (incremented for hotfixes between milestones). */
inline constexpr unsigned PBR_MEMORY_POOL_VERSION_PATCH = 1;
inline constexpr unsigned PBR_MEMORY_POOL_VERSION_PATCH = 2;

/** Pre-formatted version string, kept in lockstep with the components above. */
inline constexpr const char* PBR_MEMORY_POOL_VERSION_STRING = "1.1.1";
inline constexpr const char* PBR_MEMORY_POOL_VERSION_STRING = "1.1.2";

} // namespace it::d4np::memorypool

Expand Down
8 changes: 4 additions & 4 deletions src/test/cpp/it/d4np/memorypool/pool_smoke_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,12 @@ 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.1 — maintenance PATCH: docs/process/tooling only (bug ledger,
// PR-metadata policy, and the accumulated post-1.1.0 docs/CI entries); the
// library binary is unchanged. These constants move in lockstep with version.hpp.
// 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.
CHECK(mem::PBR_MEMORY_POOL_VERSION_MAJOR == 1U);
CHECK(mem::PBR_MEMORY_POOL_VERSION_MINOR == 1U);
CHECK(mem::PBR_MEMORY_POOL_VERSION_PATCH == 1U);
CHECK(mem::PBR_MEMORY_POOL_VERSION_PATCH == 2U);
}

TEST_CASE("memory_pool_create / _destroy round-trip on valid arguments") {
Expand Down
Loading