Skip to content

Commit 7edc799

Browse files
committed
[6.2][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. rdar://148836760 (cherry picked from commit e305703)
1 parent aa2b4e3 commit 7edc799

File tree

12 files changed

+218
-46
lines changed

12 files changed

+218
-46
lines changed

include/swift/RemoteInspection/ReflectionContext.h

+39-13
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,32 @@ 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+
18201827
Info.ChildTasks.push_back(ChildTask);
18211828

1822-
StoredPointer ChildFragmentAddr = ChildTask + sizeof(*AsyncTaskObj);
1823-
auto ChildFragmentObj =
1824-
readObj<ChildFragment<Runtime>>(ChildFragmentAddr);
1825-
if (ChildFragmentObj)
1826-
ChildTask = ChildFragmentObj->NextChild;
1827-
else
1829+
swift::JobFlags ChildJobFlags(AsyncTaskObj->Flags);
1830+
if (ChildJobFlags.task_isChildTask()) {
1831+
if (asyncTaskSize == 0)
1832+
return {std::string("target async task size unknown, unable to "
1833+
"iterate child tasks"),
1834+
Info};
1835+
1836+
StoredPointer ChildFragmentAddr = ChildTask + asyncTaskSize;
1837+
auto ChildFragmentObj =
1838+
readObj<ChildFragment<Runtime>>(ChildFragmentAddr);
1839+
if (ChildFragmentObj)
1840+
ChildTask = ChildFragmentObj->NextChild;
1841+
else
1842+
ChildTask = 0;
1843+
} else {
1844+
// No child fragment, so we're done iterating.
18281845
ChildTask = 0;
1846+
}
18291847
}
18301848

18311849
RecordPtr = RecordObj->Parent;
@@ -1927,7 +1945,7 @@ class ReflectionContext
19271945
if (setupTargetPointers)
19281946
return;
19291947

1930-
auto getFunc = [&](const std::string &name) -> StoredPointer {
1948+
auto getPointer = [&](const std::string &name) -> StoredPointer {
19311949
auto Symbol = getReader().getSymbolAddress(name);
19321950
if (!Symbol)
19331951
return 0;
@@ -1936,19 +1954,27 @@ class ReflectionContext
19361954
return 0;
19371955
return Pointer->getResolvedAddress().getAddressData();
19381956
};
1957+
target_asyncTaskMetadata =
1958+
getPointer("_swift_concurrency_debug_asyncTaskMetadata");
19391959
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");
1960+
getPointer("_swift_concurrency_debug_non_future_adapter");
1961+
target_future_adapter =
1962+
getPointer("_swift_concurrency_debug_future_adapter");
1963+
target_task_wait_throwing_resume_adapter = getPointer(
1964+
"_swift_concurrency_debug_task_wait_throwing_resume_adapter");
19441965
target_task_future_wait_resume_adapter =
1945-
getFunc("_swift_concurrency_debug_task_future_wait_resume_adapter");
1966+
getPointer("_swift_concurrency_debug_task_future_wait_resume_adapter");
19461967
auto supportsPriorityEscalationAddr = getReader().getSymbolAddress(
19471968
"_swift_concurrency_debug_supportsPriorityEscalation");
19481969
if (supportsPriorityEscalationAddr) {
19491970
getReader().readInteger(supportsPriorityEscalationAddr,
19501971
&supportsPriorityEscalation);
19511972
}
1973+
auto asyncTaskSizeAddr =
1974+
getReader().getSymbolAddress("_swift_concurrency_debug_asyncTaskSize");
1975+
if (asyncTaskSizeAddr) {
1976+
getReader().readInteger(asyncTaskSizeAddr, &asyncTaskSize);
1977+
}
19521978

19531979
setupTargetPointers = true;
19541980
}

include/swift/RemoteInspection/RuntimeInternals.h

+2-5
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/private/SwiftReflectionTest/SwiftReflectionTest.swift

+10
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,7 @@ public enum InstanceKind: UInt8 {
209209
case Enum
210210
case EnumValue
211211
case AsyncTask
212+
case LogString
212213
}
213214

214215
/// Represents a section in a loaded image in this process.
@@ -642,6 +643,15 @@ public func reflect(asyncTask: UInt) {
642643
reflect(instanceAddress: asyncTask, kind: .AsyncTask)
643644
}
644645

646+
/// Log a string to the test's output. Use instead of print, which gets
647+
/// captured by the parent and read as commands.
648+
public func reflectionLog(str: String) {
649+
str.withCString {
650+
let addr = UInt(bitPattern: $0)
651+
reflect(instanceAddress: addr, kind: .LogString);
652+
}
653+
}
654+
645655
/// Call this function to indicate to the parent that there are
646656
/// no more instances to look at.
647657
public func doneReflecting() {

stdlib/public/Concurrency/Debug.h

+4
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

+2
Original file line numberDiff line numberDiff line change
@@ -440,6 +440,8 @@ const void *const swift::_swift_concurrency_debug_jobMetadata =
440440
const void *const swift::_swift_concurrency_debug_asyncTaskMetadata =
441441
static_cast<Metadata *>(&taskHeapMetadata);
442442

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

stdlib/tools/swift-reflection-test/messages.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,6 @@ typedef enum InstanceKind {
2929
Closure,
3030
Enum,
3131
EnumValue,
32-
AsyncTask
32+
AsyncTask,
33+
LogString,
3334
} InstanceKind;

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

+97-13
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,67 @@ 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+
}
874+
875+
int logString(SwiftReflectionContextRef RC, const PipeMemoryReader *Reader) {
876+
#pragma clang diagnostic push
877+
#pragma clang diagnostic ignored "-Wcast-qual"
878+
void *Context = (void *)Reader;
879+
#pragma clang diagnostic pop
880+
881+
swift_addr_t StringPointer = PipeMemoryReader_receiveInstanceAddress(Context);
882+
uint64_t StringLength =
883+
PipeMemoryReader_getStringLength(Context, StringPointer);
884+
885+
void *FreeContext;
886+
// Read length+1 bytes to get the NUL terminator too.
887+
const void *String = PipeMemoryReader_readBytes(
888+
Context, StringPointer, StringLength + 1, &FreeContext);
889+
890+
printf("%s\n", (const char *)String);
891+
PipeMemoryReader_freeBytes(Context, String, FreeContext);
892+
893+
PipeMemoryReader_sendDoneMessage(Context);
894+
return 1;
895+
}
817896

818897
int doDumpHeapInstance(const char *BinaryFilename, PipeMemoryReader *Reader) {
819898
#if defined(_WIN32)
@@ -926,6 +1005,11 @@ int doDumpHeapInstance(const char *BinaryFilename, PipeMemoryReader *Reader) {
9261005
return EXIT_SUCCESS;
9271006
break;
9281007
}
1008+
case LogString: {
1009+
if (!logString(RC, Reader))
1010+
return EXIT_SUCCESS;
1011+
break;
1012+
}
9291013
case None:
9301014
swift_reflection_destroyReflectionContext(RC);
9311015
printf("Done.\n");

0 commit comments

Comments
 (0)