@@ -1377,8 +1377,15 @@ class ReflectionContext
13771377 return std::string (" failure reading allocation pool contents" );
13781378 auto Pool = reinterpret_cast <const PoolRange *>(PoolBytes.get ());
13791379
1380+ // Limit how many iterations of this loop we'll do, to avoid potential
1381+ // infinite loops when reading bad data. Limit to 1 million iterations. In
1382+ // normal operation, each pool allocation is 16kB, so that would be ~16GB of
1383+ // metadata which is far more than any normal program should have.
1384+ unsigned LoopCount = 0 ;
1385+ unsigned LoopLimit = 1000000 ;
1386+
13801387 auto TrailerPtr = Pool->Begin + Pool->Remaining ;
1381- while (TrailerPtr) {
1388+ while (TrailerPtr && LoopCount++ < LoopLimit ) {
13821389 auto TrailerBytes = getReader ()
13831390 .readBytes (RemoteAddress (TrailerPtr), sizeof (PoolTrailer));
13841391 if (!TrailerBytes)
@@ -1426,8 +1433,15 @@ class ReflectionContext
14261433 if (!BacktraceListNextPtr)
14271434 return llvm::None;
14281435
1436+ // Limit how many iterations of this loop we'll do, to avoid potential
1437+ // infinite loops when reading bad data. Limit to 1 billion iterations. In
1438+ // normal operation, a program shouldn't have anywhere near 1 billion
1439+ // metadata allocations.
1440+ unsigned LoopCount = 0 ;
1441+ unsigned LoopLimit = 1000000000 ;
1442+
14291443 auto BacktraceListNext = BacktraceListNextPtr->getResolvedAddress ();
1430- while (BacktraceListNext) {
1444+ while (BacktraceListNext && LoopCount++ < LoopLimit ) {
14311445 auto HeaderBytes = getReader ().readBytes (
14321446 RemoteAddress (BacktraceListNext),
14331447 sizeof (MetadataAllocationBacktraceHeader<Runtime>));
@@ -1473,30 +1487,40 @@ class ReflectionContext
14731487 // provide the whole thing as one big chunk.
14741488 size_t HeaderSize =
14751489 llvm::alignTo (sizeof (*Slab), llvm::Align (MaximumAlignment));
1476- AsyncTaskAllocationChunk Chunk;
14771490
1478- Chunk.Start = SlabPtr + HeaderSize;
1479- Chunk.Length = Slab->CurrentOffset ;
1480- Chunk.Kind = AsyncTaskAllocationChunk::ChunkKind::Unknown;
1491+ AsyncTaskAllocationChunk AllocatedSpaceChunk;
1492+ AllocatedSpaceChunk.Start = SlabPtr + HeaderSize;
1493+ AllocatedSpaceChunk.Length = Slab->CurrentOffset ;
1494+ AllocatedSpaceChunk.Kind = AsyncTaskAllocationChunk::ChunkKind::Unknown;
1495+
1496+ // Provide a second chunk just for the Next pointer, so the client knows
1497+ // that there's an allocation there.
1498+ AsyncTaskAllocationChunk NextPtrChunk;
1499+ NextPtrChunk.Start =
1500+ SlabPtr + offsetof (typename StackAllocator::Slab, Next);
1501+ NextPtrChunk.Length = sizeof (Slab->Next );
1502+ NextPtrChunk.Kind = AsyncTaskAllocationChunk::ChunkKind::RawPointer;
14811503
14821504 // Total slab size is the slab's capacity plus the header.
14831505 StoredPointer SlabSize = Slab->Capacity + HeaderSize;
14841506
1485- return {llvm::None, {Slab->Next , SlabSize, {Chunk}}};
1507+ return {llvm::None,
1508+ {Slab->Next , SlabSize, {NextPtrChunk, AllocatedSpaceChunk}}};
14861509 }
14871510
14881511 std::pair<llvm::Optional<std::string>, AsyncTaskInfo>
1489- asyncTaskInfo (StoredPointer AsyncTaskPtr) {
1512+ asyncTaskInfo (StoredPointer AsyncTaskPtr, unsigned ChildTaskLimit,
1513+ unsigned AsyncBacktraceLimit) {
14901514 loadTargetPointers ();
14911515
14921516 if (supportsPriorityEscalation)
14931517 return asyncTaskInfo<
14941518 AsyncTask<Runtime, ActiveTaskStatusWithEscalation<Runtime>>>(
1495- AsyncTaskPtr);
1519+ AsyncTaskPtr, ChildTaskLimit, AsyncBacktraceLimit );
14961520 else
14971521 return asyncTaskInfo<
14981522 AsyncTask<Runtime, ActiveTaskStatusWithoutEscalation<Runtime>>>(
1499- AsyncTaskPtr);
1523+ AsyncTaskPtr, ChildTaskLimit, AsyncBacktraceLimit );
15001524 }
15011525
15021526 std::pair<llvm::Optional<std::string>, ActorInfo>
@@ -1588,7 +1612,8 @@ class ReflectionContext
15881612
15891613 template <typename AsyncTaskType>
15901614 std::pair<llvm::Optional<std::string>, AsyncTaskInfo>
1591- asyncTaskInfo (StoredPointer AsyncTaskPtr) {
1615+ asyncTaskInfo (StoredPointer AsyncTaskPtr, unsigned ChildTaskLimit,
1616+ unsigned AsyncBacktraceLimit) {
15921617 auto AsyncTaskObj = readObj<AsyncTaskType>(AsyncTaskPtr);
15931618 if (!AsyncTaskObj)
15941619 return {std::string (" failure reading async task" ), {}};
@@ -1620,8 +1645,9 @@ class ReflectionContext
16201645 Info.RunJob = getRunJob (AsyncTaskObj.get ());
16211646
16221647 // Find all child tasks.
1648+ unsigned ChildTaskLoopCount = 0 ;
16231649 auto RecordPtr = AsyncTaskObj->PrivateStorage .Status .Record ;
1624- while (RecordPtr) {
1650+ while (RecordPtr && ChildTaskLoopCount++ < ChildTaskLimit ) {
16251651 auto RecordObj = readObj<TaskStatusRecord<Runtime>>(RecordPtr);
16261652 if (!RecordObj)
16271653 break ;
@@ -1661,7 +1687,8 @@ class ReflectionContext
16611687 // Walk the async backtrace.
16621688 if (Info.HasIsRunning && !Info.IsRunning ) {
16631689 auto ResumeContext = AsyncTaskObj->ResumeContextAndReserved [0 ];
1664- while (ResumeContext) {
1690+ unsigned AsyncBacktraceLoopCount = 0 ;
1691+ while (ResumeContext && AsyncBacktraceLoopCount++ < AsyncBacktraceLimit) {
16651692 auto ResumeContextObj = readObj<AsyncContext<Runtime>>(ResumeContext);
16661693 if (!ResumeContextObj)
16671694 break ;
0 commit comments