Skip to content

fix: S12.34 drain full lwIP RX pbuf chain, not just the head link#564

Merged
DavidCozens merged 2 commits into
mainfrom
fix/s12.34-lwip-pbuf-chain-rx
Jun 9, 2026
Merged

fix: S12.34 drain full lwIP RX pbuf chain, not just the head link#564
DavidCozens merged 2 commits into
mainfrom
fix/s12.34-lwip-pbuf-chain-rx

Conversation

@DavidCozens

@DavidCozens DavidCozens commented Jun 9, 2026

Copy link
Copy Markdown
Owner

Closes #559.

Problem

LwipRawTcpStream_DrainHeadBytes read only the head link (head->len)
then pbuf_free(head) freed the whole chain — silently losing
tot_len - len tail bytes whenever lwIP delivered a chained pbuf (a received
segment spanning more than one pool pbuf). Memory-safe, but a
network-reachable correctness defect: the advertised TLS-over-LwipRawTcpStream
stack carries real TLS record bytes on _Read, so the truncation corrupts the
handshake/record stream non-deterministically with on-path segmentation.

Slipped through because the unit test only ever fabricated single-link pbufs
(len == tot_len, next == NULL).

Fix

  • Key the drain cursor (RxHeadOffset) and the fully-drained test off
    tot_len, and delegate the chain walk to lwIP's own pbuf_copy_partial
    (walks head->next). pbuf_frees the head — which frees every link — only
    once the whole chain is consumed.
  • Advance the cursor and return by the actual copied count, not the
    requested amount. Under lwIP's tot_len == Σ link->len invariant the two are
    equal; keying off the real copy means a malformed/overstated tot_len
    degrades to would-block (StreamSender recovers) instead of advancing past
    un-copied bytes and reporting stale buffer content into a stacked TLS stream.

Tests (TDD, red→green)

  • ReadDrainsEveryLinkOfAChainedPbuf — full 2-link chain returned across a read.
  • ReadAcrossChainedPbufLinkBoundaryPreservesByteOrder — a read straddling the
    link boundary; chain stays queued until fully drained, freed exactly once.
  • ReadReportsOnlyBytesActuallyCopiedWhenTotLenOverstatesChain — overstated
    tot_len returns only what was copied, never the phantom tail.
  • New pushIncomingChain fixture helper; faithful pbuf_copy_partial added to
    LwipPbufFake so the tests exercise a real multi-link walk.

SolidSyslogLwipRawTcpStreamTest 60 green; SolidSyslogLwipRawDatagramTest
(shares the fake) 36 green; pbuf leak invariant balanced.

Docs

Chained-pbuf contract noted in docs/integrating-lwip.md, including the
warning for integrators supplying their own SolidSyslogStream byte transport.

Out of scope

The MITM-class no-hostname-verification TLS default — already tracked/decided in
S12.28 (#529).

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Fixed an issue where data spanning multiple internal network buffers was not properly drained in TCP streams, preventing potential data loss.
  • Tests

    • Added test coverage for TCP stream handling of chained network buffers and boundary scenarios.
  • Documentation

    • Updated the lwIP integration guide with clarification on proper handling of multi-buffer network segments to ensure data integrity.

DavidCozens and others added 2 commits June 9, 2026 09:03
LwipRawTcpStream_DrainHeadBytes read only the head link (head->len) then
pbuf_free(head) freed the whole chain, silently losing tot_len - len tail
bytes whenever lwIP delivered a chained pbuf. Network-reachable corruption
for the TLS-over-LwipRawTcpStream stack, whose _Read carries TLS record
bytes.

Key the drain off tot_len and delegate the chain walk to lwIP's own
pbuf_copy_partial. Advance the cursor and return by the actual copied
count, not the requested amount, so a malformed/overstated tot_len
degrades to would-block rather than reporting un-copied stale bytes.

Add a faithful pbuf_copy_partial to LwipPbufFake so the chained tests
exercise a real multi-link walk. Note the chained-pbuf contract in
docs/integrating-lwip.md. Move three cast-helper MISRA suppressions to
track the removed <string.h> include.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 23399171-be39-41e6-8aad-a32d6ab0f7f4

📥 Commits

Reviewing files that changed from the base of the PR and between 21dd494 and 97cd357.

📒 Files selected for processing (6)
  • DEVLOG.md
  • Platform/LwipRaw/Source/SolidSyslogLwipRawTcpStream.c
  • Tests/Lwip/SolidSyslogLwipRawTcpStreamTest.cpp
  • Tests/Support/LwipFakes/Source/LwipPbufFake.c
  • docs/integrating-lwip.md
  • misra_suppressions.txt

📝 Walkthrough

Walkthrough

This PR fixes a critical correctness bug where the lwIP raw TCP stream's RX path silently drops tail bytes when a received segment spans multiple pbuf links. The fix rewrites the drain function to use pbuf_copy_partial and track tot_len instead of only the head link's len, validates the fix with new chained-pbuf test cases, and documents the contract to prevent future regressions.

Changes

lwIP pbuf chain RX drain fix

Layer / File(s) Summary
pbuf_copy_partial fake and chained pbuf test support
Tests/Support/LwipFakes/Source/LwipPbufFake.c, Tests/Lwip/SolidSyslogLwipRawTcpStreamTest.cpp
New pbuf_copy_partial fake walks p->next and copies data across chain boundaries; new pushIncomingChain test helper creates two-link pbuf chains for testing.
RX drain rewrite using pbuf_copy_partial
Platform/LwipRaw/Source/SolidSyslogLwipRawTcpStream.c
LwipRawTcpStream_DrainHeadBytes now copies via pbuf_copy_partial keyed to tot_len, advances the cursor by actual copied bytes, and defers freeing until the full chain is consumed; unused <string.h> include removed.
Validation tests for chained pbuf draining
Tests/Lwip/SolidSyslogLwipRawTcpStreamTest.cpp
Three new test cases verify correct byte ordering across links, partial reads spanning boundaries without premature freeing, and correct handling when tot_len overstates available data.
Documentation, dev log, and verification artifacts
docs/integrating-lwip.md, DEVLOG.md, misra_suppressions.txt
Chained pbuf contract documented with integrator warning; fix recorded in DEVLOG with design and verification details; MISRA line numbers updated for refactored drain code.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • DavidCozens/solid-syslog#466: Also modifies the lwIP raw TCP stream's RX draining logic to handle chained pbuf data using tot_len-aware copying behavior.

Poem

🐰 A rabbit whispers soft and clear:
"Those pbuf chains caused data to disappear!
Now tot_len guides us, link by link,
No tail bytes lost in TLS's blink—
The chain flows true from start to end!" 🌿

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 42.86% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The PR title clearly summarizes the main fix: draining the full lwIP RX pbuf chain instead of just the head link, which is the primary objective of this changeset.
Description check ✅ Passed The PR description covers all required template sections: Purpose (Closes #559 with clear problem statement), Change Description (detailed fix approach), Test Evidence (red-green TDD with specific test cases), and Areas Affected (module and docs impacts).
Linked Issues check ✅ Passed All acceptance criteria from issue #559 are met: multi-link pbuf chain draining keyed off tot_len using pbuf_copy_partial [#559], no bytes lost with correct byte ordering [#559], RED-first tests with chained pbuf fabrication [#559], existing behavior preserved with leak/double-free assertions [#559], and docs updated [#559].
Out of Scope Changes check ✅ Passed All changes directly address the linked issue #559 scope: RX draining rewrite, test additions for chained pbufs, pbuf_copy_partial implementation, and docs update are all in-scope; DEVLOG and MISRA suppression updates are supporting changes.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/s12.34-lwip-pbuf-chain-rx

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

github-actions Bot commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

☀️   Quality Summary

   🚦   build-linux-gcc: 100% successful (✔️ 1521 passed)
   🚦   build-freertos-host-tdd-plustcp: 100% successful (✔️ 1872 passed)
   🚦   build-linux-clang: 100% successful (✔️ 1453 passed)
   🚦   sanitize-linux-gcc: 100% successful (✔️ 1453 passed)
   🚦   integration-linux-openssl: 100% successful (✔️ 16 passed)
   🚦   integration-linux-mbedtls: 100% successful (✔️ 14 passed)
   🚦   integration-windows-openssl: 100% successful (✔️ 16 passed)
   🚦   bdd-linux-syslog-ng: 94% successful (✔️ 49 passed, 🙈 3 skipped)
   🚦   bdd-windows-otel: 88% successful (✔️ 46 passed, 🙈 6 skipped)
   🚦   bdd-freertos-qemu-plustcp: 87% successful (✔️ 45 passed, 🙈 7 skipped)
   🚦   bdd-freertos-qemu-lwip: 87% successful (✔️ 45 passed, 🙈 7 skipped)
   🚦   build-windows-msvc: 100% successful (✔️ 1298 passed)
   🚦   build-linux-tunable-override: 100% successful (✔️ 1453 passed)
   ⚠️   Clang-Tidy: No warnings
   ⚠️   CPPCheck: No warnings


Created by Quality Monitor v1.14.0 (#f3859fd). More details are shown in the GitHub Checks Result.

@DavidCozens DavidCozens merged commit 32e358f into main Jun 9, 2026
27 checks passed
@DavidCozens DavidCozens deleted the fix/s12.34-lwip-pbuf-chain-rx branch June 9, 2026 09:14
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.

S12.34: Fix lwIP raw TCP RX path dropping pbuf-chain tail bytes

1 participant