@@ -467,6 +467,19 @@ struct TaskGroupStatus {
467
467
static const uint64_t maskDiscardingPending = 0b0011111111111111111111111111111111111111111111111111111111111111 ;
468
468
static const uint64_t onePendingTask = 0b0000000000000000000000000000000000000000000000000000000000000001 ;
469
469
470
+ // / Depending on kind of task group, we can either support 2^31 or 2^62 pending tasks.
471
+ // /
472
+ // / While a discarding task group's max pending count is unrealistic to be exceeded, the lower
473
+ // / maximum number used in an accumulating task group has potential to be exceeded, and thus we must crash
474
+ // / rather than start overflowing status if this were to happen.
475
+ static uint64_t maximumPendingTasks (TaskGroupBase* group) {
476
+ if (group->isAccumulatingResults ()) {
477
+ return maskAccumulatingPending;
478
+ } else {
479
+ return maskDiscardingPending;
480
+ }
481
+ }
482
+
470
483
uint64_t status;
471
484
472
485
bool isCancelled () {
@@ -525,6 +538,39 @@ struct TaskGroupStatus {
525
538
return TaskGroupStatus{status | (cancel ? cancelled : 0 )};
526
539
}
527
540
541
+ static void reportPendingTaskOverflow (TaskGroupBase* group, TaskGroupStatus status) {
542
+ char *message;
543
+ swift_asprintf (
544
+ &message,
545
+ " error: %sTaskGroup: detected pending task count overflow, in task group %p! Status: %s" ,
546
+ group->isDiscardingResults () ? " Discarding" : " " , group, status.to_string (group).c_str ());
547
+
548
+ if (_swift_shouldReportFatalErrorsToDebugger ()) {
549
+ RuntimeErrorDetails details = {
550
+ .version = RuntimeErrorDetails::currentVersion,
551
+ .errorType = " task-group-violation" ,
552
+ .currentStackDescription = " TaskGroup exceeded supported pending task count" ,
553
+ .framesToSkip = 1 ,
554
+ };
555
+ _swift_reportToDebugger (RuntimeErrorFlagFatal, message, &details);
556
+ }
557
+
558
+ #if defined(_WIN32)
559
+ #define STDERR_FILENO 2
560
+ _write (STDERR_FILENO, message, strlen (message));
561
+ #else
562
+ write (STDERR_FILENO, message, strlen (message));
563
+ #endif
564
+ #if defined(__APPLE__)
565
+ asl_log (nullptr , nullptr , ASL_LEVEL_ERR, " %s" , message);
566
+ #elif defined(__ANDROID__)
567
+ __android_log_print (ANDROID_LOG_FATAL, " SwiftRuntime" , " %s" , message);
568
+ #endif
569
+
570
+ free (message);
571
+ abort ();
572
+ }
573
+
528
574
// / Pretty prints the status, as follows:
529
575
// / If accumulating results:
530
576
// / TaskGroupStatus{ C:{cancelled} W:{waiting task} R:{ready tasks} P:{pending tasks} {binary repr} }
@@ -620,6 +666,11 @@ TaskGroupStatus TaskGroupBase::statusAddPendingTaskAssumeRelaxed(bool unconditio
620
666
std::memory_order_relaxed);
621
667
auto s = TaskGroupStatus{old + TaskGroupStatus::onePendingTask};
622
668
669
+ if (s.pendingTasks (this ) == TaskGroupStatus::maximumPendingTasks (this )) {
670
+ TaskGroupStatus::reportPendingTaskOverflow (this , s);
671
+ llvm_unreachable (); // the above call will abort();
672
+ }
673
+
623
674
if (!unconditionally && s.isCancelled ()) {
624
675
// revert that add, it was meaningless
625
676
auto o = status.fetch_sub (TaskGroupStatus::onePendingTask,
0 commit comments