Skip to content

Commit 40e02c0

Browse files
authored
Merge pull request #63525 from rjmccall/initial-context-size-compat-fix-5.8
[5.8] Round the initial context size of tasks up to 32 on 64-bit <=5.6 runtimes
2 parents 3c050e1 + 879e644 commit 40e02c0

File tree

3 files changed

+79
-0
lines changed

3 files changed

+79
-0
lines changed

stdlib/toolchain/Compatibility56/Concurrency/Task.cpp

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,3 +243,59 @@ void SWIFT_CC(swiftasync) swift::swift56override_swift_task_future_wait_throwing
243243
}
244244
}
245245
}
246+
247+
//===--- swift_task_create_common -----------------------------------------===//
248+
249+
// NOTE: this function is currently only installed as an override on
250+
// 64-bit targets. The fix in it has been written to work correctly
251+
// on any target, though, so if you need to use it for a more general
252+
// fix, you should be able to just define and install it unconditionally.
253+
#if __POINTER_WIDTH__ == 64
254+
255+
AsyncTaskAndContext SWIFT_CC(swift)
256+
swift::swift56override_swift_task_create_common(
257+
size_t rawTaskCreateFlags,
258+
TaskOptionRecord *options,
259+
const Metadata *futureResultType,
260+
TaskContinuationFunction *function, void *closureContext,
261+
size_t initialContextSize,
262+
TaskCreateCommon_t *original) {
263+
264+
// The <=5.6 versions of this function pointlessly initialize the
265+
// defunct Flags field in the initial context. This initialization
266+
// is mostly harmless because the initial function has no expectations
267+
// about the non-header contents of the initial context on entry.
268+
// However, if the initial context doesn't include space for the Flags
269+
// field, and it ends up at the end of an allocation, this write can
270+
// go past the end of the allocation.
271+
//
272+
// The initial context is always at the end of the allocation for
273+
// Tasks that lack a preallocated buffer, i.e. any Task that is not
274+
// an async let.
275+
//
276+
// On 32-bit targets, the Flags field was at offset 8. Since context
277+
// sizes are always rounded up to a multiple of MaximumAlignment,
278+
// initialContextSize is guaranteed to be >= 16, so the store to
279+
// Flags will always fall within it. On 64-bit targets, however,
280+
// Flags was at offset 16. We therefore need to ensure the initial
281+
// context is large enough for the unnecessary write to Flags.
282+
//
283+
// We could handle this in the compiler by ensuring that all
284+
// functions request at least 32 bytes of context, but that would
285+
// introduce a permanent overhead on thunks and other functions that
286+
// don't need any temporary scratch space. We really only need to work
287+
// around this one store when creating tasks, and fortunately, that
288+
// always flows through this one function. Since this hook receives
289+
// the initial function and context size directly instead of as an
290+
// async function pointer, it's painless for us to just change the
291+
// requested initial context size.
292+
#if __POINTER_WIDTH__ == 64
293+
if (initialContextSize < 32) initialContextSize = 32;
294+
#endif
295+
296+
return original(rawTaskCreateFlags, options,
297+
futureResultType, function, closureContext,
298+
initialContextSize);
299+
}
300+
301+
#endif

stdlib/toolchain/Compatibility56/Overrides.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,9 @@ struct ConcurrencyOverrideSection {
4242
ConcurrencyOverrideSection Swift56ConcurrencyOverrides
4343
__attribute__((used, section("__DATA,__s_async_hook"))) = {
4444
.version = 0,
45+
#if __POINTER_WIDTH__ == 64
46+
.task_create_common = swift56override_swift_task_create_common,
47+
#endif
4548
.task_future_wait = swift56override_swift_task_future_wait,
4649
.task_future_wait_throwing = swift56override_swift_task_future_wait_throwing,
4750
};

stdlib/toolchain/Compatibility56/Overrides.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,13 @@ struct OpaqueValue;
2323
class AsyncContext;
2424
class AsyncTask;
2525

26+
using TaskCreateCommon_t = SWIFT_CC(swift) AsyncTaskAndContext(
27+
size_t rawTaskCreateFlags,
28+
TaskOptionRecord *options,
29+
const Metadata *futureResultType,
30+
TaskContinuationFunction *function, void *closureContext,
31+
size_t initialContextSize);
32+
2633
using TaskFutureWait_t = SWIFT_CC(swiftasync) void(
2734
OpaqueValue *result,
2835
SWIFT_ASYNC_CONTEXT AsyncContext *callerContext,
@@ -54,4 +61,17 @@ void SWIFT_CC(swiftasync) swift56override_swift_task_future_wait_throwing(
5461
ThrowingTaskFutureWaitContinuationFunction *,
5562
AsyncContext *,
5663
TaskFutureWaitThrowing_t *original);
64+
65+
#if __POINTER_WIDTH__ == 64
66+
__attribute__((weak, visibility("hidden")))
67+
AsyncTaskAndContext SWIFT_CC(swift)
68+
swift56override_swift_task_create_common(
69+
size_t rawTaskCreateFlags,
70+
TaskOptionRecord *options,
71+
const Metadata *futureResultType,
72+
TaskContinuationFunction *function, void *closureContext,
73+
size_t initialContextSize,
74+
TaskCreateCommon_t *original);
75+
#endif
76+
5777
} // namespace swift

0 commit comments

Comments
 (0)