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