You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
docs(time-zone): #2185's selected repair cannot meet its own acceptance example
Returned to needs_user, with the measurement rather than an argument. No
production statement changed.
The ticket selects "a vector<shared_ptr<AdjustmentRule>> populated from the year
scan #2181 already performs", and names America/New_York versus America/Havana
as the pair that must stop comparing equal.
MEASUREMENT 1. The #2181 scan samples twelve months at midday on the 15th. For
2025 it produces, for BOTH zones, byte-identical output: same standard offset,
same daylight offset, same daylight MONTHS. They differ only in the transition
HOUR -- Havana switches at local midnight, New_York at 02:00 -- which month
sampling cannot see. Rules derived from that scan would still report the two as
same-rule zones, so a test written against the design would pass while the
finding stood.
MEASUREMENT 2, and the one that matters more. A one-year scan does not
generalise. New_York transitions on 1995-04-02, 2007-03-11 and 2025-03-09,
because the US rule changed in 2007. .NET returns SEVERAL AdjustmentRule objects
with different DateStart/DateEnd ranges precisely for that, and each carries a
RECURRENCE taken from tzdata's RULE records. libc exposes only resolved
instants, never the recurrence.
Consequence: a single rule derived from one year's transitions would be INVENTED
CONTENT in a .NET-named API -- GetAdjustmentRules() would return objects that are
not adjustment rules -- which SA-5 forbids in terms. The finding is not closable
by sampling libc at any granularity; it needs tzdata's own rule structures,
which is materially larger than this ticket describes.
The layout gate the ticket measured (sizeof 160 -> 184) is real but is now the
SMALLER obstacle, and the approval it was blocked on is not what blocks it: the
design is. The failure remains one-directional -- this port can only be too
permissive, never too strict.
Copy file name to clipboardExpand all lines: audit/AUDIT_FINDINGS_INDEX.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -239,7 +239,7 @@ implementation ticket.
239
239
| [SR-AUD-225](modules/time-zone/include/System/TimeZoneInfo.hpp.audit.md#sr-aud-225--medium--createcustomtimezone-accepts-empty-ids-and-offsets-outside-the-managed-range) | medium | remediated | `TimeZoneInfo.hpp`, `TimeZoneInfoTests.cpp` | C++ creates empty-ID and +15-hour zones; .NET rejects them with argument diagnostics. |
240
240
| [SR-AUD-226](modules/time-zone/include/System/TimeZoneInfo.hpp.audit.md#sr-aud-226--medium--adjustmentrule-accepts-an-effective-end-date-before-its-start-date) | medium | remediated | `TimeZoneInfo.hpp`, `AdjustmentRuleTests.cpp` | C++ accepts reversed 2025 date range while current .NET throws ArgumentException. |
241
241
| [SR-AUD-227](modules/time-zone/include/System/TimeZoneInfo.hpp.audit.md#sr-aud-227--medium--zone-equality-is-case-sensitive-while-its-hash-is-case-insensitive-and-net-treats-custom-ids-case-insensitively) | medium | remediated | `TimeZoneInfo.hpp`, `TimeZoneInfoTests.cpp` | C++ Zone/zone equality is false despite lowercased hashes; current .NET custom zones compare true. |
242
-
| [SR-AUD-228](modules/time-zone/include/System/TimeZoneInfo.hpp.audit.md#sr-aud-228--medium--hassamerules-reduces-distinct-adjustment-histories-to-current-offset-plus-a-dst-flag) | medium | confirmed (design-complete) | `TimeZoneInfo.hpp`, `TimeZoneInfo.cpp`, `TimeZoneInfoTests.cpp` | C++ says New York and Havana have same rules because only offset/DST bool match; .NET returns false. |
242
+
| [SR-AUD-228](modules/time-zone/include/System/TimeZoneInfo.hpp.audit.md#sr-aud-228--medium--hassamerules-reduces-distinct-adjustment-histories-to-current-offset-plus-a-dst-flag) | medium | confirmed (design-complete) | `TimeZoneInfo.hpp`, `TimeZoneInfo.cpp`, `TimeZoneInfoTests.cpp` | C++ says New York and Havana have same rules because only offset/DST bool match; .NET returns false. **THE SELECTED REPAIR WAS MEASURED AND CANNOT WORK (2026-08-18, #2185 returned to `needs_user`).** The design was *"a `vector<shared_ptr<AdjustmentRule>>` populated from the year scan #2181 already performs"*, with America/New_York versus America/Havana as the acceptance example. **Measured, the twelve-month scan produces byte-identical output for both zones** — same standard offset, same daylight offset, same daylight *months*; they differ only in the transition **hour**, which month sampling cannot see. A test written against that design would have passed while the finding stood. **And a one-year scan does not generalise**: New_York transitions on 1995-04-02, 2007-03-11 and 2025-03-09, because the US rule changed in 2007 — which is exactly why .NET returns **several** `AdjustmentRule` objects with different `DateStart`/`DateEnd`, each carrying a *recurrence* taken from tzdata's RULE records. libc exposes only resolved instants, never the recurrence, so a rule derived from one year would be **invented content in a .NET-named API**, which SA-5 forbids. The finding is not closable by sampling libc at any granularity; it needs tzdata's own rule structures, which is a different and larger piece of work. The layout gate the ticket measured (`sizeof(TimeZoneInfo)` 160 → 184) is real but is now the *smaller* obstacle, and the approval it was blocked on is **not** what blocks it — the design is. The failure remains one-directional: this port can only be too permissive, never too strict. |
243
243
| [SR-AUD-229](modules/time-zone/include/System/TimeZoneInfo.hpp.audit.md#sr-aud-229--medium--iana-lookup-records-the-current-daylight-offset-as-baseutcoffset-rather-than-the-zones-standard-offset) | medium | remediated | `TimeZoneInfo.hpp`, `TimeZoneInfo.cpp`, `TimeZoneInfoTests.cpp` | C++ records current New York daylight offset -4 as BaseUtcOffset while .NET reports invariant standard -5. |
244
244
| [SR-AUD-230](modules/threading-tasks/include/System/Threading/Tasks/TaskCanceledException.hpp.audit.md#sr-aud-230--high--the-public-task-property-retains-a-dangling-raw-pointer-after-its-source-task-is-destroyed) | high | remediated | `TaskCanceledException.hpp`, `TaskCanceledException.cpp`, `TasksTests.cpp` | Task-taking construction stores a raw non-owning Task pointer; ASan reports stack-use-after-scope when an exception exposes it after a local Task dies. **REMEDIATED (#1970, 2026-08-17), at no public-signature cost.** The constructor still takes `const Task*` and the property still returns `const Task*`; what changed is that the exception now OWNS what it points at. A `Task` in this port is a **handle** over a `std::shared_ptr<State>`, so the exception stores a copy of the handle: the state stays alive for as long as the exception is reachable, **and** stays observed, so a status change after construction is visible through `getTaskProperty()`. That second half is what makes it .NET's contract rather than a safe approximation — `TaskCanceledException.Task` there is a GC-tracked reference to the same object, not a snapshot. `std::shared_ptr<const Task>` rather than `std::optional<Task>` because `Task.hpp` includes this header, so a by-value member would be a circular include. **Layout: `sizeof` 192 → 200**, `alignof` 8 unchanged, no vtable or `noexcept` change; landed under `docs/StandingApprovals.md` SA-3 with the figures pinned as a relationship. **One pre-existing test was INVERTED, and the reason matters**: `TaskCtor_StoresTaskPointer` asserted ADDRESS identity, which is precisely the borrowing this finding reports, and is also the wrong analogue of .NET's contract — there `Task` is a reference type, here it is a value-semantics handle, so the counterpart of *the same object* is *the same state*. +4 tests; the mutation that borrows the caller's pointer again through `shared_ptr`'s aliasing constructor is caught. Downstream measured under SA-2: zero `TaskCanceledException` sites in `cna` or `mobile-eggbert`. `docs/Migration-TaskCanceledExceptionOwnsItsTask.md`. **CCF-019 is NOT closed by this** — the async-capture members (#1959, #2066, #2088, #2134) and the owned-tree members remain open. |
245
245
| [SR-AUD-231](modules/threading-tasks/include/System/Threading/Tasks/Task.hpp.audit.md#sr-aud-231--medium--task-entry-points-accept-empty-delegates-and-defer-a-managed-argument-error-into-an-asynchronous-bad_function_call) | medium | remediated | `Task.hpp`, `TaskFactory.hpp`, `Parallel.hpp`, `TasksTests.cpp` | Empty native action/function/continuation values return a task and fault later with bad_function_call, where current .NET synchronously rejects null delegates. **Remediated (#1965, 2026-08-03, cause TC-A — CCF-011 in a third module).** Enumerated by measurement as **22 public entries, not the two named** (eleven distinct bodies edited; the rest inherit the check by forwarding): every `Task`/`TaskT`/`TaskFactory`/`Parallel` entry now decides emptiness at the public boundary, before any worker is started or continuation registered, with .NET's own parameter name (`action`, `function`, `continuationAction`, `continuationFunction`, `body`). Four premises corrected: (1) **`Parallel`'s failure was catchable** — it already arrived as `System::AggregateException`, so CCF-011's "wrong type" consequence applies only to the sixteen Task/TaskT/TaskFactory entries; (2) **`Parallel::Invoke` is not an `ArgumentNullException` site** — .NET reports a null *element* with a bare `ArgumentException(SR.Parallel_Invoke_ActionNull)`, the same §17.1-shaped trap that caught #1951; (3) the failure was **data-dependent in two shapes the finding does not name** — a zero-length range/empty source ran no iteration, and an already-cancelled token short-circuited before the action, so both returned normally; (4) **`ContinueWith` did register** the empty continuation and returned a faulted task rather than an error. Zero `bad_function_call` and zero deferred aggregates remain reachable from any public entry; ASan+UBSan+LSan 0→0; +37 tests (171→208); no signature, layout, vtable or edge change. |
0 commit comments