@@ -243,3 +243,59 @@ void SWIFT_CC(swiftasync) swift::swift56override_swift_task_future_wait_throwing
243
243
}
244
244
}
245
245
}
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