@@ -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
0 commit comments