@@ -1377,8 +1377,15 @@ class ReflectionContext
1377
1377
return std::string (" failure reading allocation pool contents" );
1378
1378
auto Pool = reinterpret_cast <const PoolRange *>(PoolBytes.get ());
1379
1379
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
+
1380
1387
auto TrailerPtr = Pool->Begin + Pool->Remaining ;
1381
- while (TrailerPtr) {
1388
+ while (TrailerPtr && LoopCount++ < LoopLimit ) {
1382
1389
auto TrailerBytes = getReader ()
1383
1390
.readBytes (RemoteAddress (TrailerPtr), sizeof (PoolTrailer));
1384
1391
if (!TrailerBytes)
@@ -1426,8 +1433,15 @@ class ReflectionContext
1426
1433
if (!BacktraceListNextPtr)
1427
1434
return llvm::None;
1428
1435
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
+
1429
1443
auto BacktraceListNext = BacktraceListNextPtr->getResolvedAddress ();
1430
- while (BacktraceListNext) {
1444
+ while (BacktraceListNext && LoopCount++ < LoopLimit ) {
1431
1445
auto HeaderBytes = getReader ().readBytes (
1432
1446
RemoteAddress (BacktraceListNext),
1433
1447
sizeof (MetadataAllocationBacktraceHeader<Runtime>));
@@ -1473,30 +1487,40 @@ class ReflectionContext
1473
1487
// provide the whole thing as one big chunk.
1474
1488
size_t HeaderSize =
1475
1489
llvm::alignTo (sizeof (*Slab), llvm::Align (MaximumAlignment));
1476
- AsyncTaskAllocationChunk Chunk;
1477
1490
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;
1481
1503
1482
1504
// Total slab size is the slab's capacity plus the header.
1483
1505
StoredPointer SlabSize = Slab->Capacity + HeaderSize;
1484
1506
1485
- return {llvm::None, {Slab->Next , SlabSize, {Chunk}}};
1507
+ return {llvm::None,
1508
+ {Slab->Next , SlabSize, {NextPtrChunk, AllocatedSpaceChunk}}};
1486
1509
}
1487
1510
1488
1511
std::pair<llvm::Optional<std::string>, AsyncTaskInfo>
1489
- asyncTaskInfo (StoredPointer AsyncTaskPtr) {
1512
+ asyncTaskInfo (StoredPointer AsyncTaskPtr, unsigned ChildTaskLimit,
1513
+ unsigned AsyncBacktraceLimit) {
1490
1514
loadTargetPointers ();
1491
1515
1492
1516
if (supportsPriorityEscalation)
1493
1517
return asyncTaskInfo<
1494
1518
AsyncTask<Runtime, ActiveTaskStatusWithEscalation<Runtime>>>(
1495
- AsyncTaskPtr);
1519
+ AsyncTaskPtr, ChildTaskLimit, AsyncBacktraceLimit );
1496
1520
else
1497
1521
return asyncTaskInfo<
1498
1522
AsyncTask<Runtime, ActiveTaskStatusWithoutEscalation<Runtime>>>(
1499
- AsyncTaskPtr);
1523
+ AsyncTaskPtr, ChildTaskLimit, AsyncBacktraceLimit );
1500
1524
}
1501
1525
1502
1526
std::pair<llvm::Optional<std::string>, ActorInfo>
@@ -1588,7 +1612,8 @@ class ReflectionContext
1588
1612
1589
1613
template <typename AsyncTaskType>
1590
1614
std::pair<llvm::Optional<std::string>, AsyncTaskInfo>
1591
- asyncTaskInfo (StoredPointer AsyncTaskPtr) {
1615
+ asyncTaskInfo (StoredPointer AsyncTaskPtr, unsigned ChildTaskLimit,
1616
+ unsigned AsyncBacktraceLimit) {
1592
1617
auto AsyncTaskObj = readObj<AsyncTaskType>(AsyncTaskPtr);
1593
1618
if (!AsyncTaskObj)
1594
1619
return {std::string (" failure reading async task" ), {}};
@@ -1620,8 +1645,9 @@ class ReflectionContext
1620
1645
Info.RunJob = getRunJob (AsyncTaskObj.get ());
1621
1646
1622
1647
// Find all child tasks.
1648
+ unsigned ChildTaskLoopCount = 0 ;
1623
1649
auto RecordPtr = AsyncTaskObj->PrivateStorage .Status .Record ;
1624
- while (RecordPtr) {
1650
+ while (RecordPtr && ChildTaskLoopCount++ < ChildTaskLimit ) {
1625
1651
auto RecordObj = readObj<TaskStatusRecord<Runtime>>(RecordPtr);
1626
1652
if (!RecordObj)
1627
1653
break ;
@@ -1661,7 +1687,8 @@ class ReflectionContext
1661
1687
// Walk the async backtrace.
1662
1688
if (Info.HasIsRunning && !Info.IsRunning ) {
1663
1689
auto ResumeContext = AsyncTaskObj->ResumeContextAndReserved [0 ];
1664
- while (ResumeContext) {
1690
+ unsigned AsyncBacktraceLoopCount = 0 ;
1691
+ while (ResumeContext && AsyncBacktraceLoopCount++ < AsyncBacktraceLimit) {
1665
1692
auto ResumeContextObj = readObj<AsyncContext<Runtime>>(ResumeContext);
1666
1693
if (!ResumeContextObj)
1667
1694
break ;
0 commit comments