review(Driver.AbLegacy): fix Bit write 1-byte/2-byte encode-decode mismatch (Medium)
Re-review at 7286d320. -014 (Medium): Bit EncodeValue (no bitIndex) wrote SetInt8 while
DecodeValue read GetInt16 on a 16-bit B-file element, so a false write could round-trip
as true (stale high byte). Fix: SetInt16 + TDD. -015: tests pass CancellationToken.
This commit is contained in:
@@ -4,8 +4,8 @@
|
||||
|---|---|
|
||||
| Module | `src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.AbLegacy` |
|
||||
| Reviewer | Claude Code |
|
||||
| Review date | 2026-05-22 |
|
||||
| Commit reviewed | `76d35d1` |
|
||||
| Review date | 2026-06-19 |
|
||||
| Commit reviewed | `7286d320` |
|
||||
| Status | Reviewed |
|
||||
| Open findings | 0 |
|
||||
|
||||
@@ -16,7 +16,7 @@ a category produced nothing rather than leaving it blank.
|
||||
|
||||
| # | Category | Result |
|
||||
|---|---|---|
|
||||
| 1 | Correctness & logic bugs | Driver.AbLegacy-001, Driver.AbLegacy-002, Driver.AbLegacy-003, Driver.AbLegacy-004 |
|
||||
| 1 | Correctness & logic bugs | Driver.AbLegacy-001, Driver.AbLegacy-002, Driver.AbLegacy-003, Driver.AbLegacy-004, Driver.AbLegacy-014 |
|
||||
| 2 | OtOpcUa conventions | Driver.AbLegacy-005 |
|
||||
| 3 | Concurrency & thread safety | Driver.AbLegacy-006, Driver.AbLegacy-007, Driver.AbLegacy-008 |
|
||||
| 4 | Error handling & resilience | Driver.AbLegacy-009, Driver.AbLegacy-010 |
|
||||
@@ -24,7 +24,7 @@ a category produced nothing rather than leaving it blank.
|
||||
| 6 | Performance & resource management | Driver.AbLegacy-011 |
|
||||
| 7 | Design-document adherence | Driver.AbLegacy-012 |
|
||||
| 8 | Code organization & conventions | Driver.AbLegacy-013 |
|
||||
| 9 | Testing coverage | No issues found |
|
||||
| 9 | Testing coverage | Driver.AbLegacy-015 |
|
||||
| 10 | Documentation & comments | No issues found |
|
||||
|
||||
## Findings
|
||||
@@ -394,3 +394,89 @@ regression tests in `AbLegacyDisposeAndResolveHostTests` pin each branch of the
|
||||
the PCCC-file-as-array gap, notes the consistency with the PR-staged scope in
|
||||
`docs/v2/driver-specs.md`, and points to the Modbus `ArrayCount` flow as the pattern
|
||||
to mirror when multi-element addressing lands.
|
||||
|
||||
---
|
||||
|
||||
## Re-review 2026-06-19 (commit 7286d320)
|
||||
|
||||
New code since 76d35d1 adds: multi-element PCCC file (array) read support
|
||||
(`DecodeArray`, `ElementCount` in `AbLegacyTagCreateParams`), equipment-tag reference
|
||||
resolution via `EquipmentTagRefResolver<AbLegacyTagDefinition>` + `AbLegacyEquipmentTagParser`,
|
||||
B/I/O-file bit RMW (`WriteBitInWordAsync` extended), the `AbLegacyDriverProbe`
|
||||
Test-Connect (two-phase TCP + libplctag PCCC session), extraction of
|
||||
`AbLegacyDriverOptions` / `AbLegacyDataType` / `AbLegacyPlcFamilyProfile` into a
|
||||
`.Contracts` project, and the `AbLegacyDriverFactoryExtensions` factory. All 13
|
||||
prior findings confirmed Resolved. Two new findings recorded (Driver.AbLegacy-014,
|
||||
-015).
|
||||
|
||||
#### Re-review checklist
|
||||
|
||||
| # | Category | Result |
|
||||
|---|---|---|
|
||||
| 1 | Correctness & logic bugs | Driver.AbLegacy-014 |
|
||||
| 2 | OtOpcUa conventions | No issues found |
|
||||
| 3 | Concurrency & thread safety | No issues found |
|
||||
| 4 | Error handling & resilience | No issues found |
|
||||
| 5 | Security | No issues found |
|
||||
| 6 | Performance & resource management | No issues found |
|
||||
| 7 | Design-document adherence | No issues found |
|
||||
| 8 | Code organization & conventions | No issues found |
|
||||
| 9 | Testing coverage | Driver.AbLegacy-015 |
|
||||
| 10 | Documentation & comments | No issues found |
|
||||
|
||||
### Driver.AbLegacy-014
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| Severity | Medium |
|
||||
| Category | Correctness & logic bugs |
|
||||
| Location | `LibplctagLegacyTagRuntime.cs:145` |
|
||||
| Status | Resolved |
|
||||
|
||||
**Description:** The fix for Driver.AbLegacy-004 corrected the *decode* path for a
|
||||
`Bit`-typed tag with no bit-index suffix (`DecodeValue` now calls `GetInt16(0) & 1`
|
||||
instead of `GetInt8(0)`), but the symmetric *encode* path was not updated:
|
||||
`EncodeValue` for `Bit` with `bitIndex == null` still calls
|
||||
`_tag.SetInt8(0, (sbyte)0/1)`. A PCCC B-file element is a 16-bit word; `SetInt8`
|
||||
writes only the low byte (8 bits), leaving bits 8–15 of the tag buffer unchanged from
|
||||
the previous read. On a round-trip, `DecodeValue` reads the full 16-bit word via
|
||||
`GetInt16(0)`, so the high byte that `SetInt8` did not overwrite contributes to the
|
||||
decoded value. In the worst case, writing `false` (`SetInt8(0, 0)`) clears byte 0 but
|
||||
leaves byte 1 intact, so `GetInt16(0)` may decode a non-zero value and the node
|
||||
reports `true` after a `false` write. The encode and decode paths are asymmetric.
|
||||
|
||||
**Recommendation:** Replace `_tag.SetInt8(0, …)` with `_tag.SetInt16(0, …)` so the
|
||||
encode writes the full 16-bit word, matching the 16-bit decode. This makes `SetInt16(0, 1)`
|
||||
and `GetInt16(0) & 1` a symmetric pair.
|
||||
|
||||
**Resolution:** Resolved 2026-06-19 — `EncodeValue` for `Bit` with no `bitIndex` changed
|
||||
from `SetInt8(0, …)` to `SetInt16(0, (short)0/(short)1)`, making the encode symmetric
|
||||
with `DecodeValue`'s `GetInt16(0) & 1` decode. A regression test
|
||||
`Bit_tag_without_suffix_writes_via_EncodeValue_not_RMW` in `AbLegacyReadWriteTests`
|
||||
pins the encode routing (no parent-word runtime created, tag's own runtime receives
|
||||
the write) and that `EncodeValue` is called with the correct value.
|
||||
|
||||
### Driver.AbLegacy-015
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| Severity | Low |
|
||||
| Category | Testing coverage |
|
||||
| Location | `AbLegacyCapabilityTests.cs:92`, `AbLegacyCapabilityTests.cs:174` |
|
||||
| Status | Resolved |
|
||||
|
||||
**Description:** Two `Task.Delay` calls in `AbLegacyCapabilityTests` use
|
||||
`CancellationToken.None` (implicit, no argument) rather than
|
||||
`TestContext.Current.CancellationToken`, triggering xUnit1051 analyzer warnings
|
||||
("Calls to methods which accept CancellationToken should use
|
||||
TestContext.Current.CancellationToken to allow test cancellation to be more
|
||||
responsive"). Under test-runner cancellation (timeout or `dotnet test --cancel`) the
|
||||
300 ms and 200 ms delays in `Unsubscribe_halts_polling` and
|
||||
`Probe_disabled_when_ProbeAddress_is_null` would run to completion instead of
|
||||
aborting immediately, making the test suite slower to cancel.
|
||||
|
||||
**Recommendation:** Pass `TestContext.Current.CancellationToken` to both `Task.Delay`
|
||||
calls.
|
||||
|
||||
**Resolution:** Resolved 2026-06-19 — both `Task.Delay` calls updated to pass
|
||||
`TestContext.Current.CancellationToken`; xUnit1051 warnings no longer emitted.
|
||||
|
||||
Reference in New Issue
Block a user