Skip to content

v3.3.3 — Memory-safe trap/inform sends, flood-calibrated pool, alarm-free on ESP8266 - #7

Open
syntax1269 wants to merge 1 commit into
masterfrom
v3.3.3
Open

v3.3.3 — Memory-safe trap/inform sends, flood-calibrated pool, alarm-free on ESP8266#7
syntax1269 wants to merge 1 commit into
masterfrom
v3.3.3

Conversation

@syntax1269

Copy link
Copy Markdown
Owner

Fork of 0neblock/Arduino_SNMP (last upstream release 2.1.0, ~3 years ago), carried forward as a maintained, hardware-validated line. This upload is v3.3.3.

v3.3.3 — memory-safety release

The long-standing "slot-12 DOUBLE RELEASE" pool alarm (fired once per campaign since v3.1.23) is root-caused and eliminated, together with a latent cross-tick use-after-reuse in the same path.

  • Root cause: SNMPTrap/SNMPInform objects are persistent sketch globals whose pool-backed members (packet tree, varbind containers) outlived the send. The agent's per-tick pool reset flag-freed those slots; once response traffic recycled them, the next trap's teardown struck re-armed slots — mostly a benign stale delete (the alarm), in the worst case a destructor on a live object.
  • Fix: traps and informs are now fully stateless per send — a fresh tree is built on every call and all pool state is released on every exit path. Inform retries rebuild and re-apply the stored request ID (previously a retry could serialise an already-freed tree — possible garbage on the wire).
  • Pool right-sizing: the transient-burst term is reshaped with three anchors — 768 B packet → pool 56 (flood-measured peak 51 + margin 5), 1024 B → pool 72 (campaign-proven, unchanged), 1400 B → pool 78 (generic, unchanged).
  • Verified: host suite 175 assertions / 17 cases (default) + 176/17 (TINY), both ALL GREEN with a new colour-coded per-case summary. ESP8266 hardware: cold-boot startup trap alarm-free for the first time in the campaign; 1-minute 200 ms flood soak (GET/GETNEXT/GETBULK/SET + concurrent traps): 176 ops, 0 failures, 0 UDP losses, 0 pool alarms, 0 reboots, heap flat, pool peak 51/56.

What this fork adds over upstream 2.1.0

  • Memory-safety hardening: pool double-release detection (alarms on true double-destroy), stale-after-bulk-reset deletes stay silent, stateless trap/inform sends — no pool-backed state survives a transmit.
  • Derived, not magic: varbind cap and pool size are computed from the packet budget ((packet − 40) / 160 per-varbind worst case) and the sketch's handler count; a compile-time static_assert rejects mismatched overrides. Boot-time arena lock-in pre-allocates the pool before setup()/WiFi — zero heap-fragmentation exposure on long-running nodes (ESP8266 aborts on a failed new; this removes the time bomb).
  • Loud failure modes (no silent drops): GetBulk above the varbind cap answers tooBig instead of silently truncating; a response that cannot fit the packet budget returns an RFC 3416 tooBig error PDU instead of burning the manager's timeout.
  • Proven on an ESP8266 (1 MB, ~80 KB RAM): 30+ minute soaks and 200 ms flood tests with zero crashes, zero pool alarms, flat heap, ~1% fragmentation.
  • CI-validated: arduino-lint, host Catch2 suite, and an ESP8266 + ESP32 example compile matrix (.github/workflows/test.yml).
  • Docs/examples refreshed: README current, all example and demo sketches compile out-of-the-box on both targets.

…free on ESP8266

Fork of 0neblock/Arduino_SNMP (last upstream release 2.1.0, ~3 years ago), carried forward
as a maintained, hardware-validated line. This upload is **v3.3.3**.

## v3.3.3 — memory-safety release

The long-standing "slot-12 DOUBLE RELEASE" pool alarm (fired once per campaign since
v3.1.23) is root-caused and eliminated, together with a latent cross-tick
use-after-reuse in the same path.

- **Root cause**: `SNMPTrap`/`SNMPInform` objects are persistent sketch globals whose
  pool-backed members (packet tree, varbind containers) outlived the send. The agent's
  per-tick pool reset flag-freed those slots; once response traffic recycled them, the
  next trap's teardown struck re-armed slots — mostly a benign stale delete (the alarm),
  in the worst case a destructor on a live object.
- **Fix**: traps and informs are now fully **stateless per send** — a fresh tree is built
  on every call and all pool state is released on every exit path. Inform retries rebuild
  and re-apply the stored request ID (previously a retry could serialise an already-freed
  tree — possible garbage on the wire).
- **Pool right-sizing**: the transient-burst term is reshaped with three anchors —
  768 B packet → pool 56 (flood-measured peak 51 + margin 5), 1024 B → pool 72
  (campaign-proven, unchanged), 1400 B → pool 78 (generic, unchanged).
- **Verified**: host suite 175 assertions / 17 cases (default) + 176/17 (TINY), both ALL
  GREEN with a new colour-coded per-case summary. ESP-01 hardware: cold-boot startup trap
  **alarm-free for the first time in the campaign**; 1-minute 200 ms flood soak
  (GET/GETNEXT/GETBULK/SET + concurrent traps): 176 ops, **0 failures, 0 UDP losses,
  0 pool alarms, 0 reboots**, heap flat, pool peak 51/56.

## What this fork adds over upstream 2.1.0

- **Memory-safety hardening**: pool double-release detection (alarms on true
  double-destroy), stale-after-bulk-reset deletes stay silent, stateless trap/inform
  sends — no pool-backed state survives a transmit.
- **Derived, not magic**: varbind cap and pool size are *computed* from the packet budget
  (`(packet − 40) / 160` per-varbind worst case) and the sketch's handler count; a
  compile-time `static_assert` rejects mismatched overrides. Boot-time arena lock-in
  pre-allocates the pool before `setup()`/WiFi — zero heap-fragmentation exposure on
  long-running nodes (ESP8266 aborts on a failed `new`; this removes the time bomb).
- **Loud failure modes** (no silent drops): GetBulk above the varbind cap answers
  **tooBig** instead of silently truncating; a response that cannot fit the packet budget
  returns an RFC 3416 tooBig error PDU instead of burning the manager's timeout.
- **Proven on an ESP-01 (1 MB, ~80 KB RAM)**: 30+ minute soaks and 200 ms flood tests with
  zero crashes, zero pool alarms, flat heap, ~1% fragmentation.
- **CI-validated**: arduino-lint, host Catch2 suite, and an ESP8266 + ESP32 example
  compile matrix (`.github/workflows/test.yml`).
- Docs/examples refreshed: README current, all example and demo sketches compile
  out-of-the-box on both targets.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant