Skip to content

Commit c3fb50a

Browse files
committed
[RemoteMirror] Fix AsyncTask child iteration.
Iterating child tasks depends on knowing the size of AsyncTask, and changing the size of the task broke it. Instead of relying on mirroring the full structure in our out-of-process definitions, add a debug variable to libswift_Concurrency that contains the size of AsyncTask. While we're there, add some more validation to child task enumeration. Check each child task's metadata pointer to make sure that it actually points to the AsyncTask metadata, and have the inner loop also increment and check ChildTaskLoopCount to stop runaway iteration in that loop.
1 parent d1cb5d9 commit c3fb50a

File tree

6 files changed

+141
-31
lines changed

6 files changed

+141
-31
lines changed

include/swift/RemoteInspection/ReflectionContext.h

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -134,11 +134,13 @@ class ReflectionContext
134134
std::vector<std::tuple<RemoteAddress, RemoteAddress>> dataRanges;
135135

136136
bool setupTargetPointers = false;
137+
typename super::StoredPointer target_asyncTaskMetadata = 0;
137138
typename super::StoredPointer target_non_future_adapter = 0;
138139
typename super::StoredPointer target_future_adapter = 0;
139140
typename super::StoredPointer target_task_wait_throwing_resume_adapter = 0;
140141
typename super::StoredPointer target_task_future_wait_resume_adapter = 0;
141142
bool supportsPriorityEscalation = false;
143+
typename super::StoredSize asyncTaskSize = 0;
142144

143145
public:
144146
using super::getBuilder;
@@ -1816,16 +1818,39 @@ class ReflectionContext
18161818
ChildTask = RecordObj->FirstChild;
18171819
}
18181820

1819-
while (ChildTask) {
1821+
while (ChildTask && ChildTaskLoopCount++ < ChildTaskLimit) {
1822+
// Read the child task.
1823+
auto ChildTaskObj = readObj<AsyncTaskType>(ChildTask);
1824+
if (!ChildTaskObj)
1825+
return {std::string("found unreadable child task pointer"), Info};
1826+
1827+
// Make sure the task's metadata pointer is what we expect.
1828+
if (stripSignedPointer(ChildTaskObj->HeapObject.Metadata) !=
1829+
target_asyncTaskMetadata)
1830+
return {
1831+
std::string("found child task pointer with incorrect metadata"),
1832+
Info};
1833+
18201834
Info.ChildTasks.push_back(ChildTask);
18211835

1822-
StoredPointer ChildFragmentAddr = ChildTask + sizeof(*AsyncTaskObj);
1823-
auto ChildFragmentObj =
1824-
readObj<ChildFragment<Runtime>>(ChildFragmentAddr);
1825-
if (ChildFragmentObj)
1826-
ChildTask = ChildFragmentObj->NextChild;
1827-
else
1836+
swift::JobFlags ChildJobFlags(AsyncTaskObj->Flags);
1837+
if (ChildJobFlags.task_isChildTask()) {
1838+
if (asyncTaskSize == 0)
1839+
return {std::string("target async task size unknown, unable to "
1840+
"iterate child tasks"),
1841+
Info};
1842+
1843+
StoredPointer ChildFragmentAddr = ChildTask + asyncTaskSize;
1844+
auto ChildFragmentObj =
1845+
readObj<ChildFragment<Runtime>>(ChildFragmentAddr);
1846+
if (ChildFragmentObj)
1847+
ChildTask = ChildFragmentObj->NextChild;
1848+
else
1849+
ChildTask = 0;
1850+
} else {
1851+
// No child fragment, so we're done iterating.
18281852
ChildTask = 0;
1853+
}
18291854
}
18301855

18311856
RecordPtr = RecordObj->Parent;
@@ -1927,7 +1952,7 @@ class ReflectionContext
19271952
if (setupTargetPointers)
19281953
return;
19291954

1930-
auto getFunc = [&](const std::string &name) -> StoredPointer {
1955+
auto getPointer = [&](const std::string &name) -> StoredPointer {
19311956
auto Symbol = getReader().getSymbolAddress(name);
19321957
if (!Symbol)
19331958
return 0;
@@ -1936,19 +1961,27 @@ class ReflectionContext
19361961
return 0;
19371962
return Pointer->getResolvedAddress().getAddressData();
19381963
};
1964+
target_asyncTaskMetadata =
1965+
getPointer("_swift_concurrency_debug_asyncTaskMetadata");
19391966
target_non_future_adapter =
1940-
getFunc("_swift_concurrency_debug_non_future_adapter");
1941-
target_future_adapter = getFunc("_swift_concurrency_debug_future_adapter");
1942-
target_task_wait_throwing_resume_adapter =
1943-
getFunc("_swift_concurrency_debug_task_wait_throwing_resume_adapter");
1967+
getPointer("_swift_concurrency_debug_non_future_adapter");
1968+
target_future_adapter =
1969+
getPointer("_swift_concurrency_debug_future_adapter");
1970+
target_task_wait_throwing_resume_adapter = getPointer(
1971+
"_swift_concurrency_debug_task_wait_throwing_resume_adapter");
19441972
target_task_future_wait_resume_adapter =
1945-
getFunc("_swift_concurrency_debug_task_future_wait_resume_adapter");
1973+
getPointer("_swift_concurrency_debug_task_future_wait_resume_adapter");
19461974
auto supportsPriorityEscalationAddr = getReader().getSymbolAddress(
19471975
"_swift_concurrency_debug_supportsPriorityEscalation");
19481976
if (supportsPriorityEscalationAddr) {
19491977
getReader().readInteger(supportsPriorityEscalationAddr,
19501978
&supportsPriorityEscalation);
19511979
}
1980+
auto asyncTaskSizeAddr =
1981+
getReader().getSymbolAddress("_swift_concurrency_debug_asyncTaskSize");
1982+
if (asyncTaskSizeAddr) {
1983+
getReader().readInteger(asyncTaskSizeAddr, &asyncTaskSize);
1984+
}
19521985

19531986
setupTargetPointers = true;
19541987
}

include/swift/RemoteInspection/RuntimeInternals.h

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ template <typename Runtime> struct ConformanceCacheEntry {
6464

6565
template <typename Runtime>
6666
struct HeapObject {
67-
typename Runtime::StoredPointer Metadata;
67+
typename Runtime::StoredSignedPointer Metadata;
6868
typename Runtime::StoredSize RefCounts;
6969
};
7070

@@ -131,10 +131,7 @@ struct AsyncTask: Job<Runtime> {
131131
// On 64-bit, there's a Reserved64 after ResumeContext.
132132
typename Runtime::StoredPointer ResumeContextAndReserved[
133133
sizeof(typename Runtime::StoredPointer) == 8 ? 2 : 1];
134-
union {
135-
AsyncTaskPrivateStorage<Runtime, ActiveTaskStatus> PrivateStorage;
136-
typename Runtime::StoredPointer PrivateStorageRaw[14];
137-
};
134+
AsyncTaskPrivateStorage<Runtime, ActiveTaskStatus> PrivateStorage;
138135
};
139136

140137
template <typename Runtime>

stdlib/public/Concurrency/Debug.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ const void *const _swift_concurrency_debug_jobMetadata;
3434
SWIFT_EXPORT_FROM(swift_Concurrency)
3535
const void *const _swift_concurrency_debug_asyncTaskMetadata;
3636

37+
/// The size of an AsyncTask, in bytes.
38+
SWIFT_EXPORT_FROM(swift_Concurrency)
39+
const size_t _swift_concurrency_debug_asyncTaskSize;
40+
3741
/// A fake metadata pointer placed at the start of async task slab allocations.
3842
SWIFT_EXPORT_FROM(swift_Concurrency)
3943
const void *const _swift_concurrency_debug_asyncTaskSlabMetadata;

stdlib/public/Concurrency/Task.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,8 @@ const void *const swift::_swift_concurrency_debug_jobMetadata =
441441
const void *const swift::_swift_concurrency_debug_asyncTaskMetadata =
442442
static_cast<Metadata *>(&taskHeapMetadata);
443443

444+
const size_t swift::_swift_concurrency_debug_asyncTaskSize = sizeof(AsyncTask);
445+
444446
const HeapMetadata *swift::jobHeapMetadataPtr =
445447
static_cast<HeapMetadata *>(&jobHeapMetadata);
446448
const HeapMetadata *swift::taskHeapMetadataPtr =

stdlib/tools/swift-reflection-test/swift-reflection-test.c

Lines changed: 70 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <assert.h>
2424
#include <errno.h>
2525
#include <inttypes.h>
26+
#include <stdarg.h>
2627
#include <stdint.h>
2728
#include <stdio.h>
2829
#include <stdlib.h>
@@ -84,6 +85,20 @@ static void errnoAndExit(const char *message) {
8485
#define DEBUG_LOG(fmt, ...) (void)0
8586
#endif
8687

88+
#ifdef __clang__
89+
__attribute((__format__(__printf__, 2, 3)))
90+
#endif
91+
static void
92+
indented_printf(unsigned indentLevel, const char *fmt, ...) {
93+
for (unsigned i = 0; i < indentLevel; i++)
94+
fputs(" ", stdout);
95+
96+
va_list args;
97+
va_start(args, fmt);
98+
vprintf(fmt, args);
99+
va_end(args);
100+
}
101+
87102
static const size_t ReadEnd = 0;
88103
static const size_t WriteEnd = 1;
89104

@@ -774,10 +789,40 @@ int reflectEnumValue(SwiftReflectionContextRef RC,
774789

775790
}
776791

777-
int reflectAsyncTask(SwiftReflectionContextRef RC,
778-
const PipeMemoryReader *Reader) {
779-
uintptr_t AsyncTaskInstance = PipeMemoryReader_receiveInstanceAddress(Reader);
780-
printf("Async task %#" PRIx64 "\n", (uint64_t)AsyncTaskInstance);
792+
static int reflectAsyncTaskInstance(SwiftReflectionContextRef RC,
793+
uintptr_t AsyncTaskInstance,
794+
const PipeMemoryReader *Reader,
795+
unsigned indentLevel) {
796+
indented_printf(indentLevel, "Async task %#" PRIx64 "\n",
797+
(uint64_t)AsyncTaskInstance);
798+
799+
swift_async_task_info_t TaskInfo =
800+
swift_reflection_asyncTaskInfo(RC, AsyncTaskInstance);
801+
if (TaskInfo.Error) {
802+
printf("swift_reflection_asyncTaskInfo failed: %s\n", TaskInfo.Error);
803+
} else {
804+
indented_printf(indentLevel, "id %" PRIu64 "\n", TaskInfo.Id);
805+
indented_printf(indentLevel, "enqueuePriority %u\n",
806+
TaskInfo.EnqueuePriority);
807+
if (TaskInfo.ChildTaskCount > 0) {
808+
indented_printf(indentLevel, "children = {\n");
809+
810+
// The memory for ChildTasks is only valid until the next Remote Mirror
811+
// call, so we need to copy it.
812+
swift_reflection_ptr_t *ChildTasks =
813+
calloc(TaskInfo.ChildTaskCount, sizeof(swift_reflection_ptr_t));
814+
memcpy(ChildTasks, TaskInfo.ChildTasks,
815+
TaskInfo.ChildTaskCount * sizeof(swift_reflection_ptr_t));
816+
817+
for (unsigned i = 0; i < TaskInfo.ChildTaskCount; i++)
818+
reflectAsyncTaskInstance(RC, ChildTasks[i], Reader, indentLevel + 1);
819+
820+
free(ChildTasks);
821+
indented_printf(indentLevel, "}\n");
822+
} else {
823+
indented_printf(indentLevel, "children = {}\n");
824+
}
825+
}
781826

782827
swift_async_task_slab_return_t SlabPtrResult =
783828
swift_reflection_asyncTaskSlabPointer(RC, AsyncTaskInstance);
@@ -787,33 +832,45 @@ int reflectAsyncTask(SwiftReflectionContextRef RC,
787832
} else {
788833
swift_reflection_ptr_t SlabPtr = SlabPtrResult.SlabPtr;
789834
while (SlabPtr) {
790-
printf(" Slab pointer %#" PRIx64 "\n", (uint64_t)SlabPtr);
835+
indented_printf(indentLevel, " Slab pointer %#" PRIx64 "\n",
836+
(uint64_t)SlabPtr);
791837
swift_async_task_slab_allocations_return_t AllocationsResult =
792838
swift_reflection_asyncTaskSlabAllocations(RC, SlabPtr);
793839
if (AllocationsResult.Error) {
794-
printf("swift_reflection_asyncTaskSlabAllocations failed: %s\n",
795-
AllocationsResult.Error);
840+
indented_printf(
841+
indentLevel,
842+
"swift_reflection_asyncTaskSlabAllocations failed: %s\n",
843+
AllocationsResult.Error);
796844
SlabPtr = 0;
797845
} else {
798-
printf(" Slab size %" PRIu64 "\n",
799-
(uint64_t)AllocationsResult.SlabSize);
846+
indented_printf(indentLevel, " Slab size %" PRIu64 "\n",
847+
(uint64_t)AllocationsResult.SlabSize);
800848
for (unsigned i = 0; i < AllocationsResult.ChunkCount; i++) {
801849
swift_async_task_allocation_chunk_t Chunk =
802850
AllocationsResult.Chunks[i];
803-
printf(" Chunk at %#" PRIx64 " length %u kind %u\n",
804-
(uint64_t)Chunk.Start, Chunk.Length, Chunk.Kind);
851+
indented_printf(indentLevel,
852+
" Chunk at %#" PRIx64 " length %u kind %u\n",
853+
(uint64_t)Chunk.Start, Chunk.Length, Chunk.Kind);
805854
}
806855
SlabPtr = AllocationsResult.NextSlab;
807856
}
808857
}
809858
}
810859

811-
printf("\n\n");
812-
PipeMemoryReader_sendDoneMessage(Reader);
860+
if (indentLevel == 0) {
861+
printf("\n\n");
862+
}
813863
fflush(stdout);
814864
return 1;
815865
}
816866

867+
int reflectAsyncTask(SwiftReflectionContextRef RC,
868+
const PipeMemoryReader *Reader) {
869+
uintptr_t AsyncTaskInstance = PipeMemoryReader_receiveInstanceAddress(Reader);
870+
int result = reflectAsyncTaskInstance(RC, AsyncTaskInstance, Reader, 0);
871+
PipeMemoryReader_sendDoneMessage(Reader);
872+
return result;
873+
}
817874

818875
int doDumpHeapInstance(const char *BinaryFilename, PipeMemoryReader *Reader) {
819876
#if defined(_WIN32)

test/Concurrency/Reflection/reflect_task.swift

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,28 @@ func add(_ a: UInt, _ b: UInt) async -> UInt {
4646
}
4747
}
4848

49+
func sleepForever() async -> Int {
50+
if #available(SwiftStdlib 5.7, *) {
51+
try? await Task.sleep(for: .seconds(1_000_000_000))
52+
return 42
53+
} else {
54+
fatalError("This test shouldn't be running against old stdlibs.")
55+
}
56+
}
57+
4958
@main struct Main {
5059
static func main() async {
5160
let n = await add(100, 100)
5261
reflect(any: n)
5362

63+
async let alet1 = sleepForever()
64+
async let alet2 = sleepForever()
65+
reflect(asyncTask: _getCurrentTaskShim())
66+
// CHECK: Async task {{0x[0-9a-fA-F]*}}
67+
// CHECK: children = {
68+
// CHECK: Async task {{0x[0-9a-fA-F]*}}
69+
// CHECK: Async task {{0x[0-9a-fA-F]*}}
70+
// CHECK: }
5471
doneReflecting()
5572
}
5673
}

0 commit comments

Comments
 (0)