Skip to content

feat: S13.4 Winsock UDP transport (resolver + datagram)#149

Merged
DavidCozens merged 6 commits into
mainfrom
feat/s13.4-winsock-udp
Apr 17, 2026
Merged

feat: S13.4 Winsock UDP transport (resolver + datagram)#149
DavidCozens merged 6 commits into
mainfrom
feat/s13.4-winsock-udp

Conversation

@DavidCozens

@DavidCozens DavidCozens commented Apr 17, 2026

Copy link
Copy Markdown
Owner

Summary

  • Windows-side SolidSyslogResolver + SolidSyslogDatagram implementations, parallel to the POSIX GetAddrInfoResolver / PosixDatagram. Brings up UDP syslog delivery on MSVC and validates the platform-abstraction layer put in place by S13.6 – S13.11.
  • New WinsockFake test support library + SolidSyslogWinsockResolverTest / SolidSyslogWinsockDatagramTest on the msvc-debug preset, using CppUTest UT_PTR_SET to swap Winsock function-pointer seams at setup (MSVC does not support the POSIX SocketFake's symbol-override approach).
  • Platform/Windows/Interface/SolidSyslogAddress.h companion to the POSIX opaque-address header. Layout-compatible sockaddr_in means the S13.11 static-assert still holds.

Closes #128.

Design notes

  • No #ifdef _WIN32 — platform selection lives entirely in CMake. SOLIDSYSLOG_WINSOCK option auto-detects from check_symbol_exists(sendto "winsock2.h" ...). Link to ws2_32 and install Windows-side Interface headers when enabled.
  • Per-consumer function-pointer seam — each translation unit owns its pointers via a sibling *Internal.h in Platform/Windows/Source/:
    • WinsockResolver owns Winsock_getaddrinfo, Winsock_freeaddrinfo
    • WinsockDatagram owns Winsock_socket, Winsock_sendto, Winsock_closesocket
  • Preconditions documented in header — caller is responsible for WSAStartup / WSACleanup, consistent with how POSIX callers don't need socket_init().
  • WSAGetLastError / TCP (S13.9) deliberately out of scope.

Test plan

  • debug (gcc): 534 tests ✓
  • clang-debug: 534 tests ✓
  • sanitize (ASan + UBSan): 534 tests ✓
  • coverage: 99.9% lines, 100% functions ✓
  • tidy: clean ✓
  • cppcheck: clean ✓
  • format: clean ✓
  • msvc-debug (windows-build-and-test): validated by CI — 13 WinsockResolver + 18 WinsockDatagram + 11 WinsockFake tests run on MSVC for the first time here

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Optional Windows Winsock support (SOLIDSYSLOG_WINSOCK) with Winsock-backed resolver, UDP datagram, and public address storage/type.
  • Tests

    • Added comprehensive Winsock test harness, fakes, and unit tests validating resolver and datagram behaviors and failure paths.
  • Chores

    • Build system updated to conditionally include Windows platform code, headers, tests, and fakes when Winsock support is enabled.

Windows-side implementations of the Resolver and Datagram abstractions,
bringing up UDP syslog delivery on Windows. Mirrors the POSIX side
(GetAddrInfoResolver, PosixDatagram) with Winsock semantics (SOCKET,
INVALID_SOCKET, closesocket, SOCKET_ERROR).

Injection for unit tests uses CppUTest's UT_PTR_SET rather than GCC-style
weak/strong symbol override (MSVC does not support the latter). Each
production translation unit owns its Winsock function-pointer seam via a
library-internal header in Platform/Windows/Source/; tests swap the
pointers for WinsockFake_* at setup.

The WinsockAddress companion (header + internal + .c) is literally
identical to the POSIX version aside from the <netinet/in.h> /
<winsock2.h> header swap — struct sockaddr_in is layout-compatible, so
the SOLIDSYSLOG_ADDRESS_SIZE static assert from S13.11 holds unchanged.

Closes #128.

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

coderabbitai Bot commented Apr 17, 2026

Copy link
Copy Markdown
Contributor

Warning

Rate limit exceeded

@DavidCozens has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 0 minutes and 53 seconds before requesting another review.

Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 0 minutes and 53 seconds.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 32429e57-5b2d-4385-b3c7-dc2642b69142

📥 Commits

Reviewing files that changed from the base of the PR and between facf9ba and 907ba74.

📒 Files selected for processing (2)
  • Source/CMakeLists.txt
  • Tests/Support/WinsockFake.c
📝 Walkthrough

Walkthrough

Adds optional Windows Winsock support: CMake detection and SOLIDSYSLOG_WINSOCK option, opaque Windows address storage and cast helpers, Winsock-backed resolver and UDP datagram implementations, test seams/fakes for Winsock APIs, and new unit tests and CMake gating for those tests.

Changes

Cohort / File(s) Summary
Top-level CMake & test gating
CMakeLists.txt, Tests/CMakeLists.txt
Detect sendto via winsock2.hHAVE_WINSOCK; add option(SOLIDSYSLOG_WINSOCK ...); gate Platform/Windows on HAVE_WINDOWS_INTERLOCKED OR SOLIDSYSLOG_WINSOCK; enable Winsock tests and link WinsockFakes when SOLIDSYSLOG_WINSOCK.
Platform/Windows CMake
Platform/Windows/CMakeLists.txt
Make atomic source conditional on HAVE_WINDOWS_INTERLOCKED; add Winsock-specific sources, ws2_32 link, and install Interface/*.h only when SOLIDSYSLOG_WINSOCK is enabled.
Address abstraction (public)
Platform/Windows/Interface/SolidSyslogAddress.h
Add fixed-size opaque SolidSyslogAddressStorage (128 bytes) and SolidSyslogAddress_FromStorage() declaration.
Winsock public interfaces
Platform/Windows/Interface/SolidSyslogWinsockDatagram.h, Platform/Windows/Interface/SolidSyslogWinsockResolver.h
Add Create/Destroy declarations for Winsock-backed Datagram and Resolver; document caller-managed Winsock lifecycle (no WSAStartup/WSACleanup performed).
Address implementation & internals
Platform/Windows/Source/SolidSyslogAddress.c, Platform/Windows/Source/SolidSyslogAddressInternal.h
Implement FromStorage as a cast; add static inline helpers and compile-time assertion to treat storage as sockaddr_in.
Winsock implementations & internals
Platform/Windows/Source/SolidSyslogWinsockDatagram.c, Platform/Windows/Source/SolidSyslogWinsockDatagramInternal.h, Platform/Windows/Source/SolidSyslogWinsockResolver.c, Platform/Windows/Source/SolidSyslogWinsockResolverInternal.h
Add Winsock-based Datagram and Resolver implementations; expose function-pointer test seams for socket/sendto/closesocket and getaddrinfo/freeaddrinfo; implement Open/SendTo/Close and Resolve logic using opaque address storage.
Test support CMake & fakes
Tests/Support/CMakeLists.txt, Tests/Support/WinsockFake.h, Tests/Support/WinsockFake.c
Make Posix fakes conditional; add WinsockFakes static lib and comprehensive Winsock fake implementation/header with reset/config/accessors and fake Winsock entry points.
Tests
Tests/WinsockFakeTest.cpp, Tests/SolidSyslogWinsockDatagramTest.cpp, Tests/SolidSyslogWinsockResolverTest.cpp
Add CppUTest suites exercising Winsock fake, datagram lifecycle/send/close behavior, and resolver behavior (host/port, transport mapping, freeaddrinfo calls), including failure injections.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant Resolver as SolidSyslogWinsockResolver
    participant Winsock as Winsock API
    participant Storage as SolidSyslogAddressStorage

    Client->>Resolver: Resolve(storage)
    Resolver->>Resolver: call getHost(), call getPort()
    Resolver->>Winsock: getaddrinfo(host, NULL, hints)
    alt Success
        Winsock-->>Resolver: addrinfo* (ai_addr = sockaddr_in)
        Resolver->>Storage: copy ai_addr → storage
        Resolver->>Resolver: set sin_port = htons(port)
        Resolver->>Winsock: freeaddrinfo(addrinfo*)
        Resolver-->>Client: true
    else Failure
        Winsock-->>Resolver: error
        Resolver-->>Client: false
    end
Loading
sequenceDiagram
    participant Client
    participant Datagram as SolidSyslogWinsockDatagram
    participant Winsock as Winsock API
    participant Storage as SolidSyslogAddressStorage

    Client->>Datagram: Open()
    Datagram->>Winsock: socket(AF_INET, SOCK_DGRAM, 0)
    alt Success
        Winsock-->>Datagram: SOCKET fd
        Datagram-->>Client: true
    else Failure
        Winsock-->>Datagram: INVALID_SOCKET
        Datagram-->>Client: false
    end

    Client->>Datagram: SendTo(buf, len, storage)
    Datagram->>Storage: cast storage → sockaddr_in*
    Datagram->>Winsock: sendto(fd, buf, len, 0, sockaddr_in*, sizeof)
    alt Success
        Winsock-->>Datagram: bytes_sent
        Datagram-->>Client: true
    else Failure
        Winsock-->>Datagram: SOCKET_ERROR
        Datagram-->>Client: false
    end

    Client->>Datagram: Close()
    alt fd != INVALID_SOCKET
        Datagram->>Winsock: closesocket(fd)
        Winsock-->>Datagram: 0
        Datagram->>Datagram: fd = INVALID_SOCKET
    end
    Datagram-->>Client: (void)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~30 minutes

Possibly related issues

Possibly related PRs

Poem

🐰
I hop through winsock fields with glee,
I hide addresses in storage snug and free,
UDP leaps, resolver sniffs the route,
Fakes and tests make errors mute,
A tiny rabbit ships a winsock spree.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 14.71% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: S13.4 Winsock UDP transport (resolver + datagram)' clearly summarizes the main change: adding Winsock UDP transport implementations for both resolver and datagram components.
Description check ✅ Passed The pull request description provides comprehensive coverage of the Purpose (closing #128, enabling UDP syslog on Windows), Change Description (Winsock implementations, function-pointer seams, CMake auto-detection), Test Evidence (534 tests on gcc/clang/sanitize/coverage, plus msvc-debug tests), and Areas Affected (Windows platform, CMake build, test infrastructure).

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/s13.4-winsock-udp

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

@github-actions

Copy link
Copy Markdown
Contributor

☀️   Quality Summary

   🚦   Unit Tests (GCC): 99% successful (✔️ 531 passed, 🙈 3 skipped)
   🚦   Unit Tests (Clang): 99% successful (✔️ 498 passed, 🙈 3 skipped)
   🚦   Unit Tests (Sanitize): 99% successful (✔️ 498 passed, 🙈 3 skipped)
   🚦   BDD Tests: 100% successful (✔️ 31 passed)
   🚦   Unit Tests (MSVC): 100% successful (✔️ 338 passed, 🙈 1 skipped)
   ⚠️   Clang-Tidy: No warnings
   ⚠️   CPPCheck: No warnings


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

Post-format pass on the two files the CI `format` check flagged that my
local sweep missed (I had run the format check before adding the later
test files). No behaviour change.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

☀️   Quality Summary

   🚦   Unit Tests (GCC): 99% successful (✔️ 531 passed, 🙈 3 skipped)
   🚦   Unit Tests (Clang): 99% successful (✔️ 498 passed, 🙈 3 skipped)
   🚦   Unit Tests (Sanitize): 99% successful (✔️ 498 passed, 🙈 3 skipped)
   🚦   BDD Tests: 100% successful (✔️ 31 passed)
   🚦   Unit Tests (MSVC): 100% successful (✔️ 338 passed, 🙈 1 skipped)
   ⚠️   Clang-Tidy: No warnings
   ⚠️   CPPCheck: No warnings


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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
Platform/Windows/Source/SolidSyslogWinsockDatagramInternal.h (1)

18-20: Rename seam globals to camelCase for guideline compliance.

These globals are variables, so underscore-based names (Winsock_socket, Winsock_sendto, Winsock_closesocket) miss the repository camelCase rule.

♻️ Suggested rename
-    extern WinsockSocketFn      Winsock_socket;
-    extern WinsockSendToFn      Winsock_sendto;
-    extern WinsockCloseSocketFn Winsock_closesocket;
+    extern WinsockSocketFn      winsockSocket;
+    extern WinsockSendToFn      winsockSendto;
+    extern WinsockCloseSocketFn winsockClosesocket;

As per coding guidelines, **/*.{c,cpp,h,hpp,cc,cxx} variables must use camelCase naming convention.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Platform/Windows/Source/SolidSyslogWinsockDatagramInternal.h` around lines 18
- 20, The three extern globals use underscore_case; rename them to camelCase to
match repo rules: change Winsock_socket -> winsockSocket, Winsock_sendto ->
winsockSendTo, and Winsock_closesocket -> winsockCloseSocket. Update the extern
declarations (WinsockSocketFn Winsock_socket, WinsockSendToFn Winsock_sendto,
WinsockCloseSocketFn Winsock_closesocket) and every definition and use-site
across the codebase to the new names, and run a build to ensure no remaining
references; keep types and signatures unchanged.
Tests/SolidSyslogWinsockResolverTest.cpp (1)

57-70: Consider camelCase for test helper methods.

The helper methods Resolve() and Result() use PascalCase. Per coding guidelines, C++ methods should use camelCase (e.g., resolve(), result()). This is a minor naming consistency concern.

💅 Optional naming adjustment
-    bool Resolve(enum SolidSyslogTransport transport = SOLIDSYSLOG_TRANSPORT_UDP)
+    bool resolve(enum SolidSyslogTransport transport = SOLIDSYSLOG_TRANSPORT_UDP)
     {
         struct SolidSyslogAddress* address = SolidSyslogAddress_FromStorage(&resultStorage);
         return resolver->Resolve(resolver, transport, address);
     }

     // NOLINTNEXTLINE(modernize-use-nodiscard) -- used through accessor syntax in tests
-    const struct sockaddr_in* Result() const
+    const struct sockaddr_in* result() const
     {

As per coding guidelines: "C++ methods must use camelCase naming convention".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Tests/SolidSyslogWinsockResolverTest.cpp` around lines 57 - 70, Rename the
helper methods Resolve() and Result() to camelCase (resolve() and result())
throughout this test class and any tests that call them; update the definitions
that call SolidSyslogAddress_FromStorage(&resultStorage) and return the
sockaddr_in pointer (currently using the bytes reinterpret_cast and returning
reinterpret_cast<const struct sockaddr_in*>(bytes)) to the new names and
preserve the existing NOLINT comments and behavior; also update any uses of
resolver->Resolve to avoid name conflicts (ensure calls to the resolver object
keep its Resolve method intact) and run tests to confirm all call sites were
updated.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@CMakeLists.txt`:
- Around line 69-70: The check_symbol_exists call for sendto in winsock2.h can
fail because the ws2_32 library isn't specified for the linkage check; set
CMAKE_REQUIRED_LIBRARIES to ws2_32 before calling check_symbol_exists and
restore/clear it afterward so the check_symbol_exists("sendto" "winsock2.h"
HAVE_WINSOCK) correctly links on Windows and option(SOLIDSYSLOG_WINSOCK ...)
reflects the real result.

In `@Tests/Support/WinsockFake.c`:
- Around line 226-232: Guard against negative len and NULL/too-small address
pointers before copying in the sendto capture logic: validate that len >= 0
before casting to size_t and computing copySize for lastBufCopy, and validate
that to != NULL and tolen >= sizeof(struct sockaddr_in) before dereferencing
into lastAddr; if validation fails, set lastLen/lastAddrLen/lastFlags to safe
defaults and avoid the memcpy and address copy to prevent undefined behavior
(update the block that writes lastBufCopy, lastLen, lastFlags, lastAddr,
lastAddrLen accordingly).

---

Nitpick comments:
In `@Platform/Windows/Source/SolidSyslogWinsockDatagramInternal.h`:
- Around line 18-20: The three extern globals use underscore_case; rename them
to camelCase to match repo rules: change Winsock_socket -> winsockSocket,
Winsock_sendto -> winsockSendTo, and Winsock_closesocket -> winsockCloseSocket.
Update the extern declarations (WinsockSocketFn Winsock_socket, WinsockSendToFn
Winsock_sendto, WinsockCloseSocketFn Winsock_closesocket) and every definition
and use-site across the codebase to the new names, and run a build to ensure no
remaining references; keep types and signatures unchanged.

In `@Tests/SolidSyslogWinsockResolverTest.cpp`:
- Around line 57-70: Rename the helper methods Resolve() and Result() to
camelCase (resolve() and result()) throughout this test class and any tests that
call them; update the definitions that call
SolidSyslogAddress_FromStorage(&resultStorage) and return the sockaddr_in
pointer (currently using the bytes reinterpret_cast and returning
reinterpret_cast<const struct sockaddr_in*>(bytes)) to the new names and
preserve the existing NOLINT comments and behavior; also update any uses of
resolver->Resolve to avoid name conflicts (ensure calls to the resolver object
keep its Resolve method intact) and run tests to confirm all call sites were
updated.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 06286230-38a5-4bdb-bfd9-ea67788a7a8c

📥 Commits

Reviewing files that changed from the base of the PR and between 17b76a7 and 9c199aa.

📒 Files selected for processing (18)
  • CMakeLists.txt
  • Platform/Windows/CMakeLists.txt
  • Platform/Windows/Interface/SolidSyslogAddress.h
  • Platform/Windows/Interface/SolidSyslogWinsockDatagram.h
  • Platform/Windows/Interface/SolidSyslogWinsockResolver.h
  • Platform/Windows/Source/SolidSyslogAddress.c
  • Platform/Windows/Source/SolidSyslogAddressInternal.h
  • Platform/Windows/Source/SolidSyslogWinsockDatagram.c
  • Platform/Windows/Source/SolidSyslogWinsockDatagramInternal.h
  • Platform/Windows/Source/SolidSyslogWinsockResolver.c
  • Platform/Windows/Source/SolidSyslogWinsockResolverInternal.h
  • Tests/CMakeLists.txt
  • Tests/SolidSyslogWinsockDatagramTest.cpp
  • Tests/SolidSyslogWinsockResolverTest.cpp
  • Tests/Support/CMakeLists.txt
  • Tests/Support/WinsockFake.c
  • Tests/Support/WinsockFake.h
  • Tests/WinsockFakeTest.cpp

Comment thread CMakeLists.txt
Comment thread Tests/Support/WinsockFake.c Outdated
- CMakeLists.txt: set CMAKE_REQUIRED_LIBRARIES=ws2_32 before the
  check_symbol_exists(sendto "winsock2.h" HAVE_WINSOCK) call, save/restore
  the previous value. Some MSVC toolchains return false-negatives without
  it because symbol resolution happens at link time.
- Tests/Support/WinsockFake.c: guard WinsockFake_sendto against negative
  len, NULL buf and short/NULL addr before copying. Protects the fake
  against theoretical UB; unaffected by current callers which always pass
  valid inputs.

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

Copy link
Copy Markdown
Owner Author

@coderabbitai — responses to the two nitpicks in the review summary:

Nitpick 1 — Winsock_socket / _sendto / _closesocket extern vars → camelCase. Leaving as-is. These are function-pointer seams deliberately named after the Winsock functions they replace; the underscore preserves the visual link to socket()/sendto()/closesocket() at the UT_PTR_SET call sites. Renaming to winsockSocket etc. would break that cue without a corresponding clarity gain.

Nitpick 2 — Test helper methods Resolve() / Result() → camelCase. Leaving as-is. The existing SolidSyslogGetAddrInfoResolverTest.cpp uses the same PascalCase convention; changing only the Winsock mirror would lose the symmetry with its POSIX counterpart. If we want to update the guideline or sweep the POSIX tests, that's a separate change.

@coderabbitai

coderabbitai Bot commented Apr 17, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

@DavidCozens: Understood on both counts — the rationale is clear and well-grounded in each case.

  1. Winsock_socket / _sendto / _closesocket — the underscore-prefixed naming as a direct mirror of the Winsock API names makes the UT_PTR_SET seam pattern immediately legible; noted.
  2. Resolve() / Result() PascalCase — preserving symmetry with SolidSyslogGetAddrInfoResolverTest.cpp is the right call; a naming sweep (if ever desired) should cover both sides together.

I'll record both decisions to avoid re-raising them in future reviews.


✏️ Learnings added
Learnt from: DavidCozens
URL: https://github.com/DavidCozens/solid-syslog/pull/149

Timestamp: 2026-04-17T19:45:13.648Z
Learning: In `DavidCozens/solid-syslog`, the extern function-pointer seam variables in `Platform/Windows/Source/SolidSyslogWinsockDatagramInternal.h` and `Platform/Windows/Source/SolidSyslogWinsockResolverInternal.h` (`Winsock_socket`, `Winsock_sendto`, `Winsock_closesocket`, `Winsock_getaddrinfo`, `Winsock_freeaddrinfo`) intentionally use underscore-based naming (mirroring the real Winsock API names) to preserve visual clarity at `UT_PTR_SET` call sites. Do not flag these names as non-camelCase in future reviews.

Learnt from: DavidCozens
URL: https://github.com/DavidCozens/solid-syslog/pull/149

Timestamp: 2026-04-17T19:45:13.648Z
Learning: In `DavidCozens/solid-syslog`, the test helper methods `Resolve()` and `Result()` in `Tests/SolidSyslogWinsockResolverTest.cpp` intentionally use PascalCase to mirror the convention in the POSIX counterpart `Tests/SolidSyslogGetAddrInfoResolverTest.cpp`. Do not flag PascalCase test helper methods in Winsock or POSIX resolver tests in future reviews.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: DavidCozens
Repo: DavidCozens/solid-syslog PR: 124
File: CMakeLists.txt:12-14
Timestamp: 2026-04-15T06:15:20.788Z
Learning: In `CMakeLists.txt` of `DavidCozens/solid-syslog`, the MSVC suppression `/wd4297` (exception thrown from `extern "C"` function) is intentional and permanent test-infrastructure design: C fakes require C linkage, and `TestAssert_Fail` throws to propagate failures through CppUTest. Issue `#125` will add an inline comment documenting this justification. Do not flag `/wd4297` as an unjustified suppression in future reviews.

Learnt from: DavidCozens
Repo: DavidCozens/solid-syslog PR: 124
File: CMakeLists.txt:12-14
Timestamp: 2026-04-15T06:15:20.788Z
Learning: In `CMakeLists.txt` of `DavidCozens/solid-syslog`, the `_CRT_SECURE_NO_WARNINGS` compile definition is a known temporary stopgap for MSVC CRT deprecation warnings in test fakes. Issue `#126` (S13.3) will introduce a `SafeString` abstraction (Windows impl wraps `_s` variants; POSIX falls through to standard functions); once test fakes migrate, this suppression is removed. Production code is already SDL-clean. Do not flag this definition as an unjustified suppression in future reviews.

Learnt from: DavidCozens
Repo: DavidCozens/solid-syslog PR: 137
File: Interface/SolidSyslogResolverDefinition.h:12-12
Timestamp: 2026-04-15T21:12:31.145Z
Learning: In `Interface/SolidSyslogResolverDefinition.h` (and the corresponding `Source/SolidSyslogResolver.c`), the `Resolve` function pointer returns `void` intentionally. This is a direct extraction of the pre-existing behaviour in `SolidSyslogUdpSender` and `SolidSyslogTcpSender`, neither of which checked resolution success before PR `#137`. Adding a boolean/error return to `Resolve` and propagating failures through sender create/connect paths is deferred to the error-handling epic (Epic `#31`). Do not flag the `void` return on `SolidSyslogResolver.Resolve` as a contract gap in future reviews.

Learnt from: DavidCozens
Repo: DavidCozens/solid-syslog PR: 131
File: Tests/Support/SafeStringWindows.c:5-8
Timestamp: 2026-04-15T15:53:38.455Z
Learning: In `Tests/Support/SafeStringWindows.c` of `DavidCozens/solid-syslog`, the `SafeString_Copy` Windows implementation intentionally omits a `destSize == 0` guard (unlike `SafeStringStandard.c`). The design goal is to let `strncpy_s` invoke the MSVC invalid parameter handler on misuse, acting as a fail-fast mechanism in test code. Do not flag this asymmetry as a defect in future reviews.

Learnt from: DavidCozens
Repo: DavidCozens/solid-syslog PR: 124
File: CMakeLists.txt:12-14
Timestamp: 2026-04-15T06:15:20.788Z
Learning: In `CMakeLists.txt` of `DavidCozens/solid-syslog`, the MSVC suppression `/wd4200` (flexible array member) is a known stopgap. Issue `#125` (S13.2) will replace `char buffer[]` with the `char buffer[1]` pre-C99 idiom and remove this suppression. Do not flag `/wd4200` in future reviews of this file.

Learnt from: DavidCozens
Repo: DavidCozens/solid-syslog PR: 140
File: Source/SolidSyslogPosixTcpStream.c:31-36
Timestamp: 2026-04-17T07:50:51.607Z
Learning: In `Source/SolidSyslogPosixTcpStream.c`, `SolidSyslogPosixTcpStream_Destroy()` intentionally does not close the socket fd before nulling the vtable pointers. Through the only supported API path (TcpSender → Stream), every successful `Open` is guaranteed to be matched by a `Close` — either via `TcpSender_Destroy` (when `connected == true`), `SendData` failure recovery, or `Open`'s own connect-failure self-recovery (`OpenClosesSocketOnConnectFailure` test). Standalone "Destroy-without-Close" usage is not a supported scenario; adding defensive cleanup without a driving test would violate the project's "no untested production code" discipline. Formalising this contract (with tests) is deferred to Epic `#31` (error-handling / robustness). Do not flag missing fd cleanup in `SolidSyslogPosixTcpStream_Destroy` in future reviews.

Learnt from: DavidCozens
Repo: DavidCozens/solid-syslog PR: 137
File: Source/SolidSyslogUdpSender.c:0-0
Timestamp: 2026-04-15T21:12:56.960Z
Learning: In `Source/SolidSyslogUdpSender.c`, NULL checks for `config` and `config->resolver` in `SolidSyslogUdpSender_Create` are intentionally deferred to the error-handling epic (Epic `#31`). The function currently calls `SolidSyslogResolver_Resolve()` dispatch (not the vtable directly) and includes `SolidSyslogResolver.h`. Do not flag missing NULL guards on config/resolver in this function in future reviews.

Learnt from: DavidCozens
Repo: DavidCozens/solid-syslog PR: 91
File: Source/SolidSyslogTcpSender.c:42-50
Timestamp: 2026-04-09T20:59:05.891Z
Learning: In `Source/SolidSyslogTcpSender.c` (and the matching `SolidSyslogUdpSender`), the singleton `Create()` function does not close/clean up a previously opened file descriptor on a repeated call. This is intentional: double-`Create()` is considered a misuse of the singleton pattern, and proper guard/cleanup is deferred to a dedicated error-handling epic. Do not flag this as a bug in future reviews of these files.

Learnt from: DavidCozens
Repo: DavidCozens/solid-syslog PR: 113
File: Interface/SolidSyslogFormatter.h:11-11
Timestamp: 2026-04-13T22:11:33.428Z
Learning: In `Interface/SolidSyslogFormatter.h`, `SolidSyslogFormatterStorage` is intentionally typedef'd as `size_t` (not `unsigned char`) to guarantee alignment matching `struct SolidSyslogFormatter`'s leading `size_t` fields followed by a flexible `char[]` array. The cast from `SolidSyslogFormatterStorage*` to `struct SolidSyslogFormatter*` is the standard C opaque-handle/caller-owned-storage pattern; the `_Static_assert` in `Source/SolidSyslogFormatter.c` guards layout compatibility. Do not flag this typedef or the associated cast as a strict-aliasing violation or suggest switching to `unsigned char` in future reviews.

Learnt from: DavidCozens
Repo: DavidCozens/solid-syslog PR: 103
File: Source/SolidSyslogFileStore.c:124-128
Timestamp: 2026-04-11T22:49:26.725Z
Learning: In `Source/SolidSyslogFileStore.c`, the return values of `OpenWriteFile()` and `OpenReadFile()` are intentionally unchecked in `SolidSyslogFileStore_Create` (around lines 124–128) and `RotateToNextFile` (around lines 394–400). Guarding against open failures and aborting the create/rotation flow is deferred to the error-handling epic, tracked in `project_robustness_backlog.md` under "FileStore error handling (PR `#103`)". Do not flag missing open-failure guards in these functions in future reviews.

Learnt from: DavidCozens
Repo: DavidCozens/solid-syslog PR: 91
File: Source/SolidSyslogTcpSender.c:57-71
Timestamp: 2026-04-09T20:59:09.391Z
Learning: In `Source/SolidSyslogTcpSender.c`, error handling for `connect()` failure and `send()` failure (including partial writes, SIGPIPE mitigation, and reconnection logic) is intentionally deferred to story S15.2. In the current implementation (S15.1), `tcp->connected` is set to `true` unconditionally after `connect()`, and `send()` return values are ignored. S15.2 will test-drive: connect failure → return false (and do NOT set `tcp->connected = true`), send failure → close socket and reconnect, and a `SendAll()` helper that retries on partial writes.

@github-actions

Copy link
Copy Markdown
Contributor

☀️   Quality Summary

   🚦   Unit Tests (GCC): 99% successful (✔️ 531 passed, 🙈 3 skipped)
   🚦   Unit Tests (Clang): 99% successful (✔️ 498 passed, 🙈 3 skipped)
   🚦   Unit Tests (Sanitize): 99% successful (✔️ 498 passed, 🙈 3 skipped)
   🚦   BDD Tests: 100% successful (✔️ 31 passed)
   🚦   Unit Tests (MSVC): No test results available
   ⚠️   Clang-Tidy: No warnings
   ⚠️   CPPCheck: No warnings


🚧   Error Messages

Quality Monitor Errors:
No matching report files found when using pattern '**/junit-msvc/cpputest_*.xml'! Configuration error for 'Unit Tests (MSVC)'?

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
Tests/Support/WinsockFake.c (1)

240-243: ⚠️ Potential issue | 🟡 Minor

Reset lastAddr when to is invalid to avoid stale captures.

At Line 240, lastAddr is only updated on valid to/tolen; otherwise prior state is retained and can leak into later assertions in the same test.

Proposed fix
     if (to != NULL && tolen >= (int) sizeof(struct sockaddr_in))
     {
         lastAddr = *(const struct sockaddr_in*) to;
     }
+    else
+    {
+        lastAddr = (struct sockaddr_in) {0};
+    }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Tests/Support/WinsockFake.c` around lines 240 - 243, The test helper leaves
stale data in lastAddr when the incoming to/tolen are invalid; update the
conditional around the assignment to set lastAddr to a zeroed/invalid struct
when to is NULL or tolen is too small so prior captures cannot leak into later
assertions—i.e., in the same block that currently does "if (to != NULL && tolen
>= (int) sizeof(struct sockaddr_in)) { lastAddr = *(const struct sockaddr_in*)
to; }" add an else branch that clears lastAddr (e.g., zeroes the struct or sets
sin_family to 0) so callers can detect no-valid-address was captured.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Tests/Support/WinsockFake.c`:
- Around line 254-266: In WinsockFake_getaddrinfo, guard against a NULL res and
check inet_pton's return before using its output: first if (res == NULL) return
EAI_FAIL (or an appropriate EAI_*), then only call inet_pton when node is
non-NULL and inspect its return value; if inet_pton returns 1 proceed to copy
into fakeResolvedAddr.sin_addr and set *res = &fakeAddrInfo, otherwise return
EAI_NONAME (or another suitable getaddrinfo error) so invalid or unparsable node
strings don't produce silent failures; keep the existing getAddrInfoFails
short-circuit behavior using getAddrInfoFails and preserve
lastGetAddrInfoSocktype/hostname bookkeeping.

---

Duplicate comments:
In `@Tests/Support/WinsockFake.c`:
- Around line 240-243: The test helper leaves stale data in lastAddr when the
incoming to/tolen are invalid; update the conditional around the assignment to
set lastAddr to a zeroed/invalid struct when to is NULL or tolen is too small so
prior captures cannot leak into later assertions—i.e., in the same block that
currently does "if (to != NULL && tolen >= (int) sizeof(struct sockaddr_in)) {
lastAddr = *(const struct sockaddr_in*) to; }" add an else branch that clears
lastAddr (e.g., zeroes the struct or sets sin_family to 0) so callers can detect
no-valid-address was captured.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: f318bf91-bb40-44f3-a201-7588f9908ff4

📥 Commits

Reviewing files that changed from the base of the PR and between fa8cf15 and 55c7469.

📒 Files selected for processing (2)
  • CMakeLists.txt
  • Tests/Support/WinsockFake.c
🚧 Files skipped from review as they are similar to previous changes (1)
  • CMakeLists.txt

Comment thread Tests/Support/WinsockFake.c
MSVC's /WX turns C4232 into an error: taking the address of a
__declspec(dllimport) function for static pointer initialisation is a
"nonstandard extension" because the address isn't a compile-time
constant. Introduce file-local WSAAPI forwarders (CallSocket, CallSendTo
etc.) whose addresses are compile-time-constant, and point each seam at
its forwarder instead of the raw Winsock symbol. No runtime behaviour
change — the forwarder is a one-line call that the compiler usually
inlines; the seam still points UT_PTR_SET at the fake.

This surfaced after the earlier check_symbol_exists fix: before that
fix, HAVE_WINSOCK was silently false on MSVC (the probe couldn't link
sendto without ws2_32), so SOLIDSYSLOG_WINSOCK was OFF and the Winsock
sources were never compiled on windows-latest — 362 Windows tests ran
instead of the expected ~500. Now both the detection and the compile
succeed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

☀️   Quality Summary

   🚦   Unit Tests (GCC): 99% successful (✔️ 531 passed, 🙈 3 skipped)
   🚦   Unit Tests (Clang): 99% successful (✔️ 498 passed, 🙈 3 skipped)
   🚦   Unit Tests (Sanitize): 99% successful (✔️ 498 passed, 🙈 3 skipped)
   🚦   BDD Tests: 100% successful (✔️ 31 passed)
   🚦   Unit Tests (MSVC): No test results available
   ⚠️   Clang-Tidy: No warnings
   ⚠️   CPPCheck: No warnings


🚧   Error Messages

Quality Monitor Errors:
No matching report files found when using pattern '**/junit-msvc/cpputest_*.xml'! Configuration error for 'Unit Tests (MSVC)'?

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

…nsock

SolidSyslogDatagram.c and SolidSyslogResolver.c are pure vtable
dispatchers with no platform dependency — they just forward to the
instance's Open/SendTo/Close/Resolve hooks. They were gated on
SOLIDSYSLOG_POSIX, so on Windows the Winsock datagram tests linked
against undefined SolidSyslogDatagram_Open / _SendTo / _Close (LNK2019).

Split the guard: dispatchers compile when either platform is enabled;
Stream / UdpSender / TcpSender stay POSIX-only until S13.9 adds the
Winsock stream counterpart.

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

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Platform/Windows/Source/SolidSyslogWinsockResolver.c`:
- Around line 67-72: The code dereferences info->ai_addr and blindly casts
resolver->getPort() to uint16_t; add defensive checks after Winsock_getaddrinfo
succeeds: ensure info != NULL, info->ai_addr != NULL and info->ai_addrlen is at
least sizeof(struct sockaddr_in) before casting/assigning to the sockaddr_in
from SolidSyslogAddress_AsSockaddrIn(result); validate resolver->getPort() is
within 0..65535 before calling htons((uint16_t) resolver->getPort()) and handle
out-of-range or NULL cases by cleaning up with Winsock_freeaddrinfo(info) and
returning/propagating a failure code or logging an error instead of proceeding;
use the existing symbols Winsock_getaddrinfo, info, info->ai_addr,
info->ai_addrlen, SolidSyslogAddress_AsSockaddrIn, resolver->getPort and
Winsock_freeaddrinfo to locate where to add these checks.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 68a05b44-95e8-4bad-a8af-148d0a42e3d8

📥 Commits

Reviewing files that changed from the base of the PR and between 55c7469 and facf9ba.

📒 Files selected for processing (2)
  • Platform/Windows/Source/SolidSyslogWinsockDatagram.c
  • Platform/Windows/Source/SolidSyslogWinsockResolver.c

Comment on lines +67 to +72
if (Winsock_getaddrinfo(resolver->getHost(), NULL, &hints, &info) == GETADDRINFO_SUCCESS)
{
struct sockaddr_in* sin = SolidSyslogAddress_AsSockaddrIn(result);
*sin = *(struct sockaddr_in*) info->ai_addr;
sin->sin_port = htons((uint16_t) resolver->getPort());
Winsock_freeaddrinfo(info);

@coderabbitai coderabbitai Bot Apr 17, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify whether resolver tests already cover malformed addrinfo + out-of-range ports.
rg -nP --type=cpp -C3 'SolidSyslogWinsockResolverTest|ai_addrlen|ai_addr|getPort|65535|negative|invalid port' Tests
rg -nP --type=c -C3 'Winsock_getaddrinfo|ai_addrlen|htons\(|getPort\(' Platform/Windows/Source/SolidSyslogWinsockResolver.c

Repository: DavidCozens/solid-syslog

Length of output: 8774


🏁 Script executed:

fd -i winsock.*resolver.*test Tests/

Repository: DavidCozens/solid-syslog

Length of output: 108


🏁 Script executed:

find Tests -name '*Winsock*Resolver*' -type f

Repository: DavidCozens/solid-syslog

Length of output: 108


🏁 Script executed:

find Tests -name '*Resolver*' -type f | head -20

Repository: DavidCozens/solid-syslog

Length of output: 153


🏁 Script executed:

cat -n Tests/SolidSyslogWinsockResolverTest.cpp

Repository: DavidCozens/solid-syslog

Length of output: 5488


🏁 Script executed:

find Tests -name 'WinsockFake*' -type f

Repository: DavidCozens/solid-syslog

Length of output: 149


🏁 Script executed:

cat -n Tests/Support/WinsockFake.c | head -100

Repository: DavidCozens/solid-syslog

Length of output: 3326


🏁 Script executed:

cat -n Tests/Support/WinsockFake.c | tail -n +100

Repository: DavidCozens/solid-syslog

Length of output: 4753


🏁 Script executed:

grep -n "SetGetAddrInfo\|fakeAddrInfo\|ai_addr\|ai_addrlen" Tests/Support/WinsockFake.c

Repository: DavidCozens/solid-syslog

Length of output: 437


🏁 Script executed:

grep -n "getPort\|getHost" Platform/Windows/Source/SolidSyslogWinsockResolver.c

Repository: DavidCozens/solid-syslog

Length of output: 577


🏁 Script executed:

grep -n "int getPort\|const char.*getHost" Interface/SolidSyslogResolverDefinition.h

Repository: DavidCozens/solid-syslog

Length of output: 50


🏁 Script executed:

find . -name 'SolidSyslogResolverDefinition.h' -type f

Repository: DavidCozens/solid-syslog

Length of output: 111


🏁 Script executed:

cat -n Interface/SolidSyslogResolverDefinition.h

Repository: DavidCozens/solid-syslog

Length of output: 579


🏁 Script executed:

cat -n Platform/POSIX/Source/SolidSyslogGetAddrInfoResolver.c

Repository: DavidCozens/solid-syslog

Length of output: 154


🏁 Script executed:

find . -name '*GetAddrInfoResolver*' -type f

Repository: DavidCozens/solid-syslog

Length of output: 231


🏁 Script executed:

fd -i getaddrinfo.*resolver Platform/

Repository: DavidCozens/solid-syslog

Length of output: 180


🏁 Script executed:

cat -n Platform/Posix/Source/SolidSyslogGetAddrInfoResolver.c

Repository: DavidCozens/solid-syslog

Length of output: 2696


🏁 Script executed:

cat -n Tests/SolidSyslogGetAddrInfoResolverTest.cpp

Repository: DavidCozens/solid-syslog

Length of output: 5483


🏁 Script executed:

grep -rn "65535\|UINT16_MAX\|port.*range\|port.*valid" Platform/Windows/Source/ Platform/Posix/Source/

Repository: DavidCozens/solid-syslog

Length of output: 50


🏁 Script executed:

grep -rn "getPort\|resolver->getPort" Tests/ | head -20

Repository: DavidCozens/solid-syslog

Length of output: 1752


🏁 Script executed:

cat -n Platform/Windows/Source/SolidSyslogWinsockResolver.c

Repository: DavidCozens/solid-syslog

Length of output: 3743


🏁 Script executed:

grep -rn "ai_addr\|ai_addrlen" Platform/ Interface/ | grep -v ".o\|Binary"

Repository: DavidCozens/solid-syslog

Length of output: 50


🏁 Script executed:

rg -n "uint16_t.*port|port.*uint16_t|htons" Platform/Windows/Source/ Platform/Posix/Source/

Repository: DavidCozens/solid-syslog

Length of output: 327


Validate resolver response and port range bounds.

At lines 70–71, the code dereferences info->ai_addr without NULL validation and casts getPort() to uint16_t without range checking. Negative ports cause undefined behavior; ports exceeding 65535 silently wrap. Neither scenario is tested in the current suite, and the WinsockFake seam always returns well-formed responses, masking the gap.

Add bounds validation for port ∈ [0, 65535] and defensive checks for info, info->ai_addr, and info->ai_addrlen before use.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Platform/Windows/Source/SolidSyslogWinsockResolver.c` around lines 67 - 72,
The code dereferences info->ai_addr and blindly casts resolver->getPort() to
uint16_t; add defensive checks after Winsock_getaddrinfo succeeds: ensure info
!= NULL, info->ai_addr != NULL and info->ai_addrlen is at least sizeof(struct
sockaddr_in) before casting/assigning to the sockaddr_in from
SolidSyslogAddress_AsSockaddrIn(result); validate resolver->getPort() is within
0..65535 before calling htons((uint16_t) resolver->getPort()) and handle
out-of-range or NULL cases by cleaning up with Winsock_freeaddrinfo(info) and
returning/propagating a failure code or logging an error instead of proceeding;
use the existing symbols Winsock_getaddrinfo, info, info->ai_addr,
info->ai_addrlen, SolidSyslogAddress_AsSockaddrIn, resolver->getPort and
Winsock_freeaddrinfo to locate where to add these checks.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Leaving as-is, intentionally. This resolver is a byte-for-byte mirror of Platform/Posix/Source/SolidSyslogGetAddrInfoResolver.c — same *(struct sockaddr_in*) info->ai_addr dereference and same unchecked (uint16_t) getPort() cast. The resolver deliberately trusts its injected getHost / getPort callbacks (SRP); range validation belongs at the config layer. Fixing only the Windows side would break symmetry with the POSIX mirror. If we want to add port-range + ai_addr NULL checks, that's a separate, coordinated change across both resolvers — not scope for S13.4.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DavidCozens, understood — the symmetry with the POSIX resolver and the SRP argument are clear. I'll record this so the same observation isn't raised again on either resolver.


✏️ Learnings added
Learnt from: DavidCozens
Repo: DavidCozens/solid-syslog PR: 149
File: Platform/Windows/Source/SolidSyslogWinsockResolver.c:67-72
Timestamp: 2026-04-17T20:07:36.721Z
Learning: In `Platform/Windows/Source/SolidSyslogWinsockResolver.c` (and its POSIX mirror `Platform/Posix/Source/SolidSyslogGetAddrInfoResolver.c`), the dereference of `info->ai_addr` without NULL/addrlen validation, and the unchecked cast of `getPort()` to `uint16_t` before `htons()`, are intentional. The resolver trusts its injected `getHost`/`getPort` callbacks by design (SRP); port-range and `ai_addr` defensive checks belong at the config/caller layer. Any future hardening must be a coordinated change across both resolvers together. Do not flag these as bugs or missing validation in future reviews of either resolver file.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: DavidCozens
Repo: DavidCozens/solid-syslog PR: 137
File: Interface/SolidSyslogResolverDefinition.h:12-12
Timestamp: 2026-04-15T21:12:31.145Z
Learning: In `Interface/SolidSyslogResolverDefinition.h` (and the corresponding `Source/SolidSyslogResolver.c`), the `Resolve` function pointer returns `void` intentionally. This is a direct extraction of the pre-existing behaviour in `SolidSyslogUdpSender` and `SolidSyslogTcpSender`, neither of which checked resolution success before PR `#137`. Adding a boolean/error return to `Resolve` and propagating failures through sender create/connect paths is deferred to the error-handling epic (Epic `#31`). Do not flag the `void` return on `SolidSyslogResolver.Resolve` as a contract gap in future reviews.

Learnt from: DavidCozens
Repo: DavidCozens/solid-syslog PR: 137
File: Source/SolidSyslogUdpSender.c:0-0
Timestamp: 2026-04-15T21:12:56.960Z
Learning: In `Source/SolidSyslogUdpSender.c`, NULL checks for `config` and `config->resolver` in `SolidSyslogUdpSender_Create` are intentionally deferred to the error-handling epic (Epic `#31`). The function currently calls `SolidSyslogResolver_Resolve()` dispatch (not the vtable directly) and includes `SolidSyslogResolver.h`. Do not flag missing NULL guards on config/resolver in this function in future reviews.

Learnt from: DavidCozens
Repo: DavidCozens/solid-syslog PR: 0
File: :0-0
Timestamp: 2026-04-17T19:45:13.648Z
Learning: In `DavidCozens/solid-syslog`, the test helper methods `Resolve()` and `Result()` in `Tests/SolidSyslogWinsockResolverTest.cpp` intentionally use PascalCase to mirror the convention in the POSIX counterpart `Tests/SolidSyslogGetAddrInfoResolverTest.cpp`. Do not flag PascalCase test helper methods in Winsock or POSIX resolver tests in future reviews.

Learnt from: DavidCozens
Repo: DavidCozens/solid-syslog PR: 0
File: :0-0
Timestamp: 2026-04-17T19:45:13.648Z
Learning: In `DavidCozens/solid-syslog`, the extern function-pointer seam variables in `Platform/Windows/Source/SolidSyslogWinsockDatagramInternal.h` and `Platform/Windows/Source/SolidSyslogWinsockResolverInternal.h` (`Winsock_socket`, `Winsock_sendto`, `Winsock_closesocket`, `Winsock_getaddrinfo`, `Winsock_freeaddrinfo`) intentionally use underscore-based naming (mirroring the real Winsock API names) to preserve visual clarity at `UT_PTR_SET` call sites. Do not flag these names as non-camelCase in future reviews.

Learnt from: DavidCozens
Repo: DavidCozens/solid-syslog PR: 109
File: Example/Common/ExampleCommandLine.c:83-88
Timestamp: 2026-04-13T09:52:59.823Z
Learning: In `Example/Common/ExampleCommandLine.c`, the `strtol`-without-endptr/sign-validation pattern for `OPT_MAX_FILES` and `OPT_MAX_FILE_SIZE` (around lines 83–88) is a known pre-existing deferral. The values are clamped downstream in `SolidSyslogFileStore_Create`, so there is no runtime safety issue. Parse-time validation (endptr + non-negative check, returning 1 on bad input) is backlogged for a follow-up PR after PR `#109` merges. Do not re-flag this as a new issue in future reviews of these two `case` branches.

Learnt from: DavidCozens
Repo: DavidCozens/solid-syslog PR: 140
File: Source/SolidSyslogPosixTcpStream.c:31-36
Timestamp: 2026-04-17T07:50:51.607Z
Learning: In `Source/SolidSyslogPosixTcpStream.c`, `SolidSyslogPosixTcpStream_Destroy()` intentionally does not close the socket fd before nulling the vtable pointers. Through the only supported API path (TcpSender → Stream), every successful `Open` is guaranteed to be matched by a `Close` — either via `TcpSender_Destroy` (when `connected == true`), `SendData` failure recovery, or `Open`'s own connect-failure self-recovery (`OpenClosesSocketOnConnectFailure` test). Standalone "Destroy-without-Close" usage is not a supported scenario; adding defensive cleanup without a driving test would violate the project's "no untested production code" discipline. Formalising this contract (with tests) is deferred to Epic `#31` (error-handling / robustness). Do not flag missing fd cleanup in `SolidSyslogPosixTcpStream_Destroy` in future reviews.

Learnt from: DavidCozens
Repo: DavidCozens/solid-syslog PR: 131
File: Tests/Support/SafeStringWindows.c:5-8
Timestamp: 2026-04-15T15:53:38.455Z
Learning: In `Tests/Support/SafeStringWindows.c` of `DavidCozens/solid-syslog`, the `SafeString_Copy` Windows implementation intentionally omits a `destSize == 0` guard (unlike `SafeStringStandard.c`). The design goal is to let `strncpy_s` invoke the MSVC invalid parameter handler on misuse, acting as a fail-fast mechanism in test code. Do not flag this asymmetry as a defect in future reviews.

Learnt from: DavidCozens
Repo: DavidCozens/solid-syslog PR: 103
File: Tests/FileFake.c:336-339
Timestamp: 2026-04-11T21:59:17.489Z
Learning: In `Tests/FileFake.c`, the bounds checks `(fake->position + count) <= fake->active->fileSize` and `(fake->position + count) <= FILEFAKE_MAX_SIZE` do not risk `size_t` overflow in practice: `position` is bounded by `FILEFAKE_MAX_SIZE` (4096) and `count` is bounded by record overhead plus `SOLIDSYSLOG_MAX_MESSAGE_SIZE` (517). Do not flag these additions as overflow risks.

Learnt from: DavidCozens
Repo: DavidCozens/solid-syslog PR: 91
File: Source/SolidSyslogTcpSender.c:57-71
Timestamp: 2026-04-09T20:59:09.391Z
Learning: In `Source/SolidSyslogTcpSender.c`, error handling for `connect()` failure and `send()` failure (including partial writes, SIGPIPE mitigation, and reconnection logic) is intentionally deferred to story S15.2. In the current implementation (S15.1), `tcp->connected` is set to `true` unconditionally after `connect()`, and `send()` return values are ignored. S15.2 will test-drive: connect failure → return false (and do NOT set `tcp->connected = true`), send failure → close socket and reconnect, and a `SendAll()` helper that retries on partial writes.

Learnt from: DavidCozens
Repo: DavidCozens/solid-syslog PR: 103
File: Source/SolidSyslogFileStore.c:124-128
Timestamp: 2026-04-11T22:49:26.725Z
Learning: In `Source/SolidSyslogFileStore.c`, the return values of `OpenWriteFile()` and `OpenReadFile()` are intentionally unchecked in `SolidSyslogFileStore_Create` (around lines 124–128) and `RotateToNextFile` (around lines 394–400). Guarding against open failures and aborting the create/rotation flow is deferred to the error-handling epic, tracked in `project_robustness_backlog.md` under "FileStore error handling (PR `#103`)". Do not flag missing open-failure guards in these functions in future reviews.

Learnt from: DavidCozens
Repo: DavidCozens/solid-syslog PR: 91
File: Source/SolidSyslogTcpSender.c:42-50
Timestamp: 2026-04-09T20:59:05.891Z
Learning: In `Source/SolidSyslogTcpSender.c` (and the matching `SolidSyslogUdpSender`), the singleton `Create()` function does not close/clean up a previously opened file descriptor on a repeated call. This is intentional: double-`Create()` is considered a misuse of the singleton pattern, and proper guard/cleanup is deferred to a dedicated error-handling epic. Do not flag this as a bug in future reviews of these files.

Learnt from: DavidCozens
Repo: DavidCozens/solid-syslog PR: 113
File: Interface/SolidSyslogFormatter.h:11-11
Timestamp: 2026-04-13T22:11:33.428Z
Learning: In `Interface/SolidSyslogFormatter.h`, `SolidSyslogFormatterStorage` is intentionally typedef'd as `size_t` (not `unsigned char`) to guarantee alignment matching `struct SolidSyslogFormatter`'s leading `size_t` fields followed by a flexible `char[]` array. The cast from `SolidSyslogFormatterStorage*` to `struct SolidSyslogFormatter*` is the standard C opaque-handle/caller-owned-storage pattern; the `_Static_assert` in `Source/SolidSyslogFormatter.c` guards layout compatibility. Do not flag this typedef or the associated cast as a strict-aliasing violation or suggest switching to `unsigned char` in future reviews.

Learnt from: DavidCozens
Repo: DavidCozens/solid-syslog PR: 124
File: CMakeLists.txt:12-14
Timestamp: 2026-04-15T06:15:20.788Z
Learning: In `CMakeLists.txt` of `DavidCozens/solid-syslog`, the `_CRT_SECURE_NO_WARNINGS` compile definition is a known temporary stopgap for MSVC CRT deprecation warnings in test fakes. Issue `#126` (S13.3) will introduce a `SafeString` abstraction (Windows impl wraps `_s` variants; POSIX falls through to standard functions); once test fakes migrate, this suppression is removed. Production code is already SDL-clean. Do not flag this definition as an unjustified suppression in future reviews.

Learnt from: DavidCozens
Repo: DavidCozens/solid-syslog PR: 124
File: CMakeLists.txt:12-14
Timestamp: 2026-04-15T06:15:20.788Z
Learning: In `CMakeLists.txt` of `DavidCozens/solid-syslog`, the MSVC suppression `/wd4200` (flexible array member) is a known stopgap. Issue `#125` (S13.2) will replace `char buffer[]` with the `char buffer[1]` pre-C99 idiom and remove this suppression. Do not flag `/wd4200` in future reviews of this file.

Learnt from: DavidCozens
Repo: DavidCozens/solid-syslog PR: 124
File: CMakeLists.txt:12-14
Timestamp: 2026-04-15T06:15:20.788Z
Learning: In `CMakeLists.txt` of `DavidCozens/solid-syslog`, the MSVC suppression `/wd4297` (exception thrown from `extern "C"` function) is intentional and permanent test-infrastructure design: C fakes require C linkage, and `TestAssert_Fail` throws to propagate failures through CppUTest. Issue `#125` will add an inline comment documenting this justification. Do not flag `/wd4297` as an unjustified suppression in future reviews.

@github-actions

Copy link
Copy Markdown
Contributor

☀️   Quality Summary

   🚦   Unit Tests (GCC): 99% successful (✔️ 531 passed, 🙈 3 skipped)
   🚦   Unit Tests (Clang): 99% successful (✔️ 498 passed, 🙈 3 skipped)
   🚦   Unit Tests (Sanitize): 99% successful (✔️ 498 passed, 🙈 3 skipped)
   🚦   BDD Tests: 100% successful (✔️ 31 passed)
   🚦   Unit Tests (MSVC): 100% successful (✔️ 382 passed, 🙈 1 skipped)
   ⚠️   Clang-Tidy: No warnings
   ⚠️   CPPCheck: No warnings


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

Mirror the sendto guard pattern from 55c7469: return EAI_FAIL when node
or res is NULL, and when inet_pton cannot parse the node as an IPv4
literal, instead of dereferencing unconditionally. Matches the real
getaddrinfo / inet_pton contract and keeps the fake honest against
future tests that exercise error paths.

Addresses CodeRabbit review comment.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown
Contributor

☀️   Quality Summary

   🚦   Unit Tests (GCC): 99% successful (✔️ 531 passed, 🙈 3 skipped)
   🚦   Unit Tests (Clang): 99% successful (✔️ 498 passed, 🙈 3 skipped)
   🚦   Unit Tests (Sanitize): 99% successful (✔️ 498 passed, 🙈 3 skipped)
   🚦   BDD Tests: 100% successful (✔️ 31 passed)
   🚦   Unit Tests (MSVC): 100% successful (✔️ 382 passed, 🙈 1 skipped)
   ⚠️   Clang-Tidy: No warnings
   ⚠️   CPPCheck: No warnings


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

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.

S13.04: WinsockResolver + WinsockDatagram — Windows UDP transport

1 participant