Skip to content

Commit 91b8691

Browse files
committed
[Runtime] Fix rare crash when fixing up dynamic subclasses.
Swift vtables can contain NULL entries. This happens when the compiler is able to prove that a method is never called. When ptrauth is enabled, those NULL entries are still signed. However, there's an inconsistency in the runtime. Most places where we copy a vtable with swift_ptrauth_copy_code_or_data, we accept an unsigned NULL value. But when fixing up a dynamic ObjC subclass with swift_objc_classCopyFixupHandler, we don't. Since the compiler seems to always sign these NULL values, this still works, except in the case where a signed NULL value coincidentally has a ptrauth signature of all zeroes. When that happens, the code to accept an unsigned NULL value sees this NULL with an all-zero signature as an unsigned NULL, and copies it verbatim. Then we really do have an unsigned NULL in the destination. If that class is then dynamically subclassed, we'll call swift_objc_classCopyFixupHandler which does not accept unsigned NULL values, and fail ptrauth. Adjust swift_objc_classCopyFixupHandler to accept unsigned NULL like the rest. These entries should never be called, and any attempt to call them will crash regardless, so it makes little difference. rdar://92800322
1 parent 23e5143 commit 91b8691

File tree

2 files changed

+1064
-1
lines changed

2 files changed

+1064
-1
lines changed

stdlib/public/runtime/Metadata.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -471,7 +471,8 @@ static void swift_objc_classCopyFixupHandler(Class oldClass, Class newClass) {
471471
reinterpret_cast<void *const *>(&src[i]),
472472
descriptors[i].Flags.getExtraDiscriminator(),
473473
!descriptors[i].Flags.isAsync(),
474-
/*allowNull*/ false); // Don't allow NULL for Obj-C classes
474+
/*allowNull*/ true); // NULL allowed for VFE (methods in the vtable
475+
// might be proven unused and null'ed)
475476
}
476477
}
477478

0 commit comments

Comments
 (0)