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