-
Notifications
You must be signed in to change notification settings - Fork 97
Invalid offset calculation for some ivars #113
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
ContextI partially know what's going on. First, here's a simpler example that illustrates the problem: // This is the API Swit.Mirror uses under the hood: https://github.com/swiftlang/swift/blob/ff790c6d01edab1695c744d22dad0d8b32f2d749/stdlib/public/core/ReflectionMirror.swift#L42-L46
@_silgen_name("swift_reflectionMirror_recursiveChildOffset")
internal func _getChildOffset(
_: Any.Type,
index: Int
) -> Int
class IncorrectLayout: NSObject {
let ivar1 = AttributedString("ivar1") // Value type
}
let info = try typeInfo(of: IncorrectLayout.self)
let mirrorOffset = _getChildOffset(IncorrectLayout.self, index: 0)
let runtimeOffset = info.properties[0].offset
XCTAssert(mirrorOffset == runtimeOffset) The assertion fails, with Swift API correctly returning 8 bytes but Runtime returning 0. With this example, attempting to ProblemAs far as I can tell the underlying problem here is not Runtime's implementation, but Swift's metadata representation which just happens to be incorrect for some classes. Apple gets away from this bug/limitation by using Objective-C's // FIXME: If the class has ObjC heritage, get the field offset using the ObjC
// metadata, because we don't update the field offsets in the face of
// resilient base classes.
uintptr_t fieldOffset;
if (usesNativeSwiftReferenceCounting(Clazz)) {
fieldOffset = Clazz->getFieldOffsets()[i];
} else {
#if SWIFT_OBJC_INTEROP
Ivar *ivars = class_copyIvarList(
reinterpret_cast<Class>(const_cast<ClassMetadata *>(Clazz)), nullptr);
fieldOffset = ivar_getOffset(ivars[i]);
free(ivars);
#else
swift::crash("Object appears to be Objective-C, but no runtime.");
#endif
} By using the debugger to force As for what type of layout triggers this error I'm not sure. Looking at the different values of According to Apple's source code this means there's something unusual about how the metadata is initialized, but I don't know if/how that could affect the ivar offset calculation. It does seem to affect the number of trailing objects. Next stepsThe easiest workaround could be doing what Apple does and rely on |
Runtime is not able to calculate the correct ivar offsets under some specific circumstances. Take a look at the following example:
Inspecting this type through Runtime gives the following offsets:
But that's not correct as far as I understand. According to
ivar_getOffset
the offsets are off by 8 bytes. Because of that, usingget(from:)
will return an instance pointing to an invalid memory address, resulting in a crash when invoking any method on it. Eg:Additional notes
Attempting to change almost anything from
IncorrectLayout
will likely fix the issue. Eg:NSObject
superclassThe text was updated successfully, but these errors were encountered: