Commit b872e39
authored
* Stabilize async/task-queue unit tests and harden factorial worker lifetime
• Relax VerifyDistributedAsyncCall timing by allowing a per-iteration slack window and wait for Cleanup to be recorded before opcode verification.
• Add explicit completion signaling and queue-drain waits in VerifyWaitForCompletion, VerifySimpleAsyncCall, and VerifyDistributedAsyncCall to avoid threadpool timing races.
• Hold a per-call reference in FactorialWorkerSimple/FactorialWorkerDistributed to prevent UAF during asynchronous callbacks.
• In _VerifyQueueTermination, only wait for counts to settle when termination is non-blocking.
* Fix UAF in test VerifyDuplicateQueueHandle
* Relax test timing in VerifySubmitCallbackWithWait
* Fix data race in AsyncBlockTests with lock-free opcode logging
Access violation crash in `AsyncBlockTests::VerifyAsyncBlockReuse` due to
concurrent `std::vector::push_back` operations on shared `opCodes` member
from overlapping async call lifecycle phases.
The test intentionally reuses `XAsyncBlock` and `FactorialCallData` across
sequential async calls. When the first call's cleanup (invoked from completion
callback) races with the second call's initialization, both threads attempt to
push_back into the same `std::vector`, causing heap corruption during vector
reallocation.
**Crash stack trace:**
```
ucrtbased!_free_dbg (heap corruption during vector realloc)
← std::vector<XAsyncOp>::push_back
← FactorialWorkerSimple (Cleanup opcode from first call)
← AsyncState::~AsyncState
← CompletionCallback
[concurrent with]
← FactorialWorkerSimple (Begin/DoWork from second call)
← VerifyAsyncBlockReuse
```
**Detection:** Heisenbug found after 6-hour soak test under Windows CDB with
page heap enabled (`gflags /p /enable`).
Replace `std::vector<XAsyncOp> opCodes` with fixed-capacity lock-free
append buffer:
- `std::array<std::atomic<XAsyncOp>, 16>` for storage (capacity exceeds max test depth)
- `std::atomic<size_t>` for thread-safe index allocation
- `RecordOp(op)`: atomic fetch-add for index, then `store(memory_order_release)` to array slot
- `GetOpCodes()`: snapshot current state into vector via `load(memory_order_acquire)`
**Why this approach:**
- Aligns with library philosophy of avoiding synchronization primitives
- No dynamic allocation eliminates reallocation races
- Bounded opcode sequences (max ~9 in distributed factorial tests)
- Append-only during async lifecycle, read-only during verification
- Proper release-acquire semantics ensure visibility on ARM/weakly-ordered architectures
- Natural lock-free semantics: each writer gets unique slot via atomic index
- `Tests/UnitTests/Tests/AsyncBlockTests.cpp`:
- Added `#include <array>` for std::array support
- Replaced `std::vector<XAsyncOp> opCodes` with `std::atomic<XAsyncOp>` array buffer
- Updated `FactorialWorkerSimple` and `FactorialWorkerDistributed` to use `RecordOp()`
- Updated all test verification sites to use `GetOpCodes()` snapshot method
- Optimized multi-call sites to snapshot once and reuse
- **Specific test**: `VerifyAsyncBlockReuse` passes 10/10 rapid runs
- **Full suite**: All 23 AsyncBlockTests passed with no regressions
- **Note**: Original heisenbug required 6hr soak to reproduce; single-pass
testing verifies compilation and basic functionality, but extended soak
testing would be needed to fully validate stability under stress
- Test-only change, no production code affected
- Eliminates data race without introducing mutex overhead
- Maintains test semantics and coverage
1 parent b1246b8 commit b872e39
2 files changed
Lines changed: 104 additions & 25 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
7 | 7 | | |
8 | 8 | | |
9 | 9 | | |
| 10 | + | |
10 | 11 | | |
11 | 12 | | |
12 | 13 | | |
| |||
79 | 80 | | |
80 | 81 | | |
81 | 82 | | |
82 | | - | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
83 | 89 | | |
84 | 90 | | |
85 | 91 | | |
86 | 92 | | |
87 | 93 | | |
88 | 94 | | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
89 | 120 | | |
90 | 121 | | |
91 | 122 | | |
| |||
116 | 147 | | |
117 | 148 | | |
118 | 149 | | |
| 150 | + | |
| 151 | + | |
119 | 152 | | |
120 | | - | |
| 153 | + | |
121 | 154 | | |
122 | 155 | | |
123 | 156 | | |
| |||
159 | 192 | | |
160 | 193 | | |
161 | 194 | | |
162 | | - | |
| 195 | + | |
| 196 | + | |
163 | 197 | | |
164 | 198 | | |
165 | 199 | | |
166 | 200 | | |
167 | 201 | | |
| 202 | + | |
| 203 | + | |
168 | 204 | | |
169 | | - | |
| 205 | + | |
170 | 206 | | |
171 | 207 | | |
172 | 208 | | |
| |||
196 | 232 | | |
197 | 233 | | |
198 | 234 | | |
199 | | - | |
| 235 | + | |
| 236 | + | |
200 | 237 | | |
201 | 238 | | |
202 | 239 | | |
203 | 240 | | |
204 | 241 | | |
205 | | - | |
| 242 | + | |
206 | 243 | | |
207 | 244 | | |
208 | 245 | | |
209 | 246 | | |
210 | 247 | | |
211 | 248 | | |
212 | | - | |
| 249 | + | |
213 | 250 | | |
214 | 251 | | |
215 | 252 | | |
216 | 253 | | |
217 | 254 | | |
218 | 255 | | |
219 | 256 | | |
220 | | - | |
| 257 | + | |
| 258 | + | |
221 | 259 | | |
222 | 260 | | |
223 | 261 | | |
| |||
391 | 429 | | |
392 | 430 | | |
393 | 431 | | |
394 | | - | |
| 432 | + | |
| 433 | + | |
| 434 | + | |
| 435 | + | |
| 436 | + | |
| 437 | + | |
| 438 | + | |
| 439 | + | |
395 | 440 | | |
396 | 441 | | |
397 | 442 | | |
| |||
457 | 502 | | |
458 | 503 | | |
459 | 504 | | |
| 505 | + | |
460 | 506 | | |
461 | 507 | | |
462 | 508 | | |
| |||
467 | 513 | | |
468 | 514 | | |
469 | 515 | | |
470 | | - | |
471 | | - | |
| 516 | + | |
| 517 | + | |
| 518 | + | |
472 | 519 | | |
473 | 520 | | |
474 | 521 | | |
| |||
480 | 527 | | |
481 | 528 | | |
482 | 529 | | |
483 | | - | |
| 530 | + | |
| 531 | + | |
| 532 | + | |
| 533 | + | |
| 534 | + | |
| 535 | + | |
| 536 | + | |
| 537 | + | |
484 | 538 | | |
485 | 539 | | |
486 | 540 | | |
| |||
554 | 608 | | |
555 | 609 | | |
556 | 610 | | |
557 | | - | |
558 | | - | |
| 611 | + | |
| 612 | + | |
| 613 | + | |
559 | 614 | | |
560 | 615 | | |
561 | 616 | | |
| |||
587 | 642 | | |
588 | 643 | | |
589 | 644 | | |
590 | | - | |
591 | | - | |
592 | | - | |
| 645 | + | |
| 646 | + | |
| 647 | + | |
| 648 | + | |
593 | 649 | | |
594 | 650 | | |
595 | 651 | | |
| |||
620 | 676 | | |
621 | 677 | | |
622 | 678 | | |
623 | | - | |
624 | | - | |
625 | | - | |
| 679 | + | |
| 680 | + | |
| 681 | + | |
| 682 | + | |
626 | 683 | | |
627 | 684 | | |
628 | 685 | | |
| |||
709 | 766 | | |
710 | 767 | | |
711 | 768 | | |
| 769 | + | |
| 770 | + | |
712 | 771 | | |
713 | 772 | | |
714 | 773 | | |
715 | 774 | | |
716 | 775 | | |
| 776 | + | |
717 | 777 | | |
718 | 778 | | |
719 | 779 | | |
| |||
724 | 784 | | |
725 | 785 | | |
726 | 786 | | |
| 787 | + | |
| 788 | + | |
| 789 | + | |
| 790 | + | |
| 791 | + | |
| 792 | + | |
| 793 | + | |
| 794 | + | |
| 795 | + | |
727 | 796 | | |
728 | 797 | | |
729 | 798 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
216 | 216 | | |
217 | 217 | | |
218 | 218 | | |
219 | | - | |
| 219 | + | |
| 220 | + | |
220 | 221 | | |
221 | 222 | | |
222 | 223 | | |
| |||
456 | 457 | | |
457 | 458 | | |
458 | 459 | | |
459 | | - | |
460 | | - | |
461 | | - | |
462 | | - | |
| 460 | + | |
| 461 | + | |
| 462 | + | |
| 463 | + | |
463 | 464 | | |
464 | 465 | | |
465 | 466 | | |
| |||
917 | 918 | | |
918 | 919 | | |
919 | 920 | | |
| 921 | + | |
| 922 | + | |
| 923 | + | |
| 924 | + | |
| 925 | + | |
| 926 | + | |
| 927 | + | |
| 928 | + | |
| 929 | + | |
920 | 930 | | |
921 | 931 | | |
922 | 932 | | |
| |||
0 commit comments