Segmentation fault when profiling #165

Closed
opened 2025-12-29 15:26:00 +01:00 by adam · 12 comments
Owner

Originally created by @sidmani on GitHub (Sep 10, 2017).

In ObjectObserver.swift (line 325) and ListMonitor.swift (line 714), ObjectType.cs_fromRaw(object: rawObject) causes a segfault, but only when profiling, not regular building. The strange thing is I can't replicate the issue in the demo project. Do you have any idea what causes this? Commenting out the callback invocation fixes the problem.

Originally created by @sidmani on GitHub (Sep 10, 2017). In ObjectObserver.swift (line 325) and ListMonitor.swift (line 714), ` ObjectType.cs_fromRaw(object: rawObject)` causes a segfault, but only when profiling, not regular building. The strange thing is I can't replicate the issue in the demo project. Do you have any idea what causes this? Commenting out the callback invocation fixes the problem.
adam added the fixed label 2025-12-29 15:26:00 +01:00
adam closed this issue 2025-12-29 15:26:00 +01:00
Author
Owner

@sidmani commented on GitHub (Sep 10, 2017):

Here's the output:

0  swift                    0x0000000111dba42a PrintStackTraceSignalHandler(void*) + 42
1  swift                    0x0000000111db9866 SignalHandler(int) + 662
2  libsystem_platform.dylib 0x00007fff8bd33b3a _sigtramp + 26
3  libsystem_platform.dylib 0x00007fff51543998 _sigtramp + 3313565304
4  swift                    0x000000010e8541ad swift::irgen::emitDynamicTypeOfOpaqueHeapObject(swift::irgen::IRGenFunction&, llvm::Value*) + 61
5  swift                    0x000000010e835a44 emitDirectTypeMetadataRef(swift::irgen::IRGenFunction&, swift::CanType) + 868
6  swift                    0x000000010e8356b4 swift::irgen::IRGenFunction::emitTypeMetadataRef(swift::CanType) + 100
7  swift                    0x000000010e7905b2 swift::irgen::emitCheckedCast(swift::irgen::IRGenFunction&, swift::irgen::Address, swift::CanType, swift::irgen::Address, swift::CanType, swift::CastConsumptionKind, swift::irgen::CheckedCastMode) + 178
8  swift                    0x000000010e8cf92f swift::SILVisitor<(anonymous namespace)::IRGenSILFunction, void>::visit(swift::ValueBase*) + 25039
9  swift                    0x000000010e8c6f90 swift::irgen::IRGenModule::emitSILFunction(swift::SILFunction*) + 9152
10 swift                    0x000000010e7d3da0 swift::irgen::IRGenerator::emitLazyDefinitions() + 6560
11 swift                    0x000000010e8a6f53 swift::performIRGeneration(swift::IRGenOptions&, swift::ModuleDecl*, std::__1::unique_ptr<swift::SILModule, std::__1::default_delete<swift::SILModule> >, llvm::StringRef, llvm::LLVMContext&, llvm::GlobalVariable**) + 1971
12 swift                    0x000000010e72f77a performCompile(swift::CompilerInstance&, swift::CompilerInvocation&, llvm::ArrayRef<char const*>, int&, swift::FrontendObserver*, swift::UnifiedStatsReporter*) + 17018
13 swift                    0x000000010e729c94 swift::performFrontend(llvm::ArrayRef<char const*>, char const*, void*, swift::FrontendObserver*) + 7716
14 swift                    0x000000010e6debb8 main + 12248
15 libdyld.dylib            0x00007fff8bb24235 start + 1

...

While emitting IR SIL function "@_T09CoreStore13ObjectMonitorC08registerC12Notification33_B8CAAE954A642D1B0EFF89F2B4488993LLySV_So14NSNotificationC4NameV4nameyXl10toObserveryACyxG_xtc8callbacktFy10Foundation0F0VcfU_So09NSManagedC0C_Tg5Tf4ngn_n".
 for expression at [.../Pods/CoreStore/Sources/ObjectMonitor.swift:317:26 - line:326:17] RangeText="{ [weak self] (note) in

                    guard let `self` = self,
                        let userInfo = note.userInfo,
                        let object = userInfo[String(describing: NSManagedObject.self)] as! NSManagedObject? else {

                            return
                    }
                    callback(self, ObjectType.cs_fromRaw(object: object))
                }"
@sidmani commented on GitHub (Sep 10, 2017): Here's the output: ``` 0 swift 0x0000000111dba42a PrintStackTraceSignalHandler(void*) + 42 1 swift 0x0000000111db9866 SignalHandler(int) + 662 2 libsystem_platform.dylib 0x00007fff8bd33b3a _sigtramp + 26 3 libsystem_platform.dylib 0x00007fff51543998 _sigtramp + 3313565304 4 swift 0x000000010e8541ad swift::irgen::emitDynamicTypeOfOpaqueHeapObject(swift::irgen::IRGenFunction&, llvm::Value*) + 61 5 swift 0x000000010e835a44 emitDirectTypeMetadataRef(swift::irgen::IRGenFunction&, swift::CanType) + 868 6 swift 0x000000010e8356b4 swift::irgen::IRGenFunction::emitTypeMetadataRef(swift::CanType) + 100 7 swift 0x000000010e7905b2 swift::irgen::emitCheckedCast(swift::irgen::IRGenFunction&, swift::irgen::Address, swift::CanType, swift::irgen::Address, swift::CanType, swift::CastConsumptionKind, swift::irgen::CheckedCastMode) + 178 8 swift 0x000000010e8cf92f swift::SILVisitor<(anonymous namespace)::IRGenSILFunction, void>::visit(swift::ValueBase*) + 25039 9 swift 0x000000010e8c6f90 swift::irgen::IRGenModule::emitSILFunction(swift::SILFunction*) + 9152 10 swift 0x000000010e7d3da0 swift::irgen::IRGenerator::emitLazyDefinitions() + 6560 11 swift 0x000000010e8a6f53 swift::performIRGeneration(swift::IRGenOptions&, swift::ModuleDecl*, std::__1::unique_ptr<swift::SILModule, std::__1::default_delete<swift::SILModule> >, llvm::StringRef, llvm::LLVMContext&, llvm::GlobalVariable**) + 1971 12 swift 0x000000010e72f77a performCompile(swift::CompilerInstance&, swift::CompilerInvocation&, llvm::ArrayRef<char const*>, int&, swift::FrontendObserver*, swift::UnifiedStatsReporter*) + 17018 13 swift 0x000000010e729c94 swift::performFrontend(llvm::ArrayRef<char const*>, char const*, void*, swift::FrontendObserver*) + 7716 14 swift 0x000000010e6debb8 main + 12248 15 libdyld.dylib 0x00007fff8bb24235 start + 1 ... While emitting IR SIL function "@_T09CoreStore13ObjectMonitorC08registerC12Notification33_B8CAAE954A642D1B0EFF89F2B4488993LLySV_So14NSNotificationC4NameV4nameyXl10toObserveryACyxG_xtc8callbacktFy10Foundation0F0VcfU_So09NSManagedC0C_Tg5Tf4ngn_n". for expression at [.../Pods/CoreStore/Sources/ObjectMonitor.swift:317:26 - line:326:17] RangeText="{ [weak self] (note) in guard let `self` = self, let userInfo = note.userInfo, let object = userInfo[String(describing: NSManagedObject.self)] as! NSManagedObject? else { return } callback(self, ObjectType.cs_fromRaw(object: object)) }" ```
Author
Owner

@JohnEstropia commented on GitHub (Sep 10, 2017):

Which CoreStore branch are you using?

@JohnEstropia commented on GitHub (Sep 10, 2017): Which CoreStore branch are you using?
Author
Owner

@sidmani commented on GitHub (Sep 10, 2017):

prototype/swift_4

@sidmani commented on GitHub (Sep 10, 2017): prototype/swift_4
Author
Owner

@JohnEstropia commented on GitHub (Sep 10, 2017):

Thanks, will look into it

@JohnEstropia commented on GitHub (Sep 10, 2017): Thanks, will look into it
Author
Owner

@sidmani commented on GitHub (Sep 12, 2017):

@JohnEstropia I made a mistake, the [weak self] is to blame. Both that and [unowned self] cause a segfault. I still don't know why though.

@sidmani commented on GitHub (Sep 12, 2017): @JohnEstropia I made a mistake, the `[weak self]` is to blame. Both that and `[unowned self]` cause a segfault. I still don't know why though.
Author
Owner

@JohnEstropia commented on GitHub (Sep 12, 2017):

@sidmani Are those [weak self] and [unowned self] within CoreStore's source file? If it's in external code, can you show an example pattern this occurs?

@JohnEstropia commented on GitHub (Sep 12, 2017): @sidmani Are those [weak self] and [unowned self] within CoreStore's source file? If it's in external code, can you show an example pattern this occurs?
Author
Owner

@sidmani commented on GitHub (Sep 12, 2017):

Yeah, they're in CoreStore's source (line 317 in ObjectMonitor.swift, for example). I'm debugging this right now, and by replacing the callback at line 325 with a function call to a temporary function:

    func debugSegfault(_ monitor: ObjectMonitor<ObjectType>, object: ObjectType) {

    }

    
    private func registerObjectNotification(_ notificationKey: UnsafeRawPointer, name: Notification.Name, toObserver observer: AnyObject, callback: @escaping (_ monitor: ObjectMonitor<ObjectType>, _ object: ObjectType) -> Void) {
        
        cs_setAssociatedRetainedObject(
            NotificationObserver(
                notificationName: name,
                object: self,
                closure: { [weak self] (note) in

                    guard let `self` = self,
                        let userInfo = note.userInfo,
                        let object = userInfo[String(describing: NSManagedObject.self)] as! NSManagedObject? else {

                            return
                    }

                    self.debugSegfault(self, object: object)
                  //  callback(strongSelf, ObjectType.cs_fromRaw(object: object))
                }
            ),
            forKey: notificationKey,
            inObject: observer
        )
    }

I get the compiler error: Cannot convert value of type 'ObjectMonitor<D>' to expected argument type 'ObjectMonitor<_>'. In theory there should be no difference between calling a closure and a function with the same input and return types, so I think this is the issue. Not sure how to fix yet.

@sidmani commented on GitHub (Sep 12, 2017): Yeah, they're in CoreStore's source (line 317 in ObjectMonitor.swift, for example). I'm debugging this right now, and by replacing the callback at line 325 with a function call to a temporary function: ``` func debugSegfault(_ monitor: ObjectMonitor<ObjectType>, object: ObjectType) { } private func registerObjectNotification(_ notificationKey: UnsafeRawPointer, name: Notification.Name, toObserver observer: AnyObject, callback: @escaping (_ monitor: ObjectMonitor<ObjectType>, _ object: ObjectType) -> Void) { cs_setAssociatedRetainedObject( NotificationObserver( notificationName: name, object: self, closure: { [weak self] (note) in guard let `self` = self, let userInfo = note.userInfo, let object = userInfo[String(describing: NSManagedObject.self)] as! NSManagedObject? else { return } self.debugSegfault(self, object: object) // callback(strongSelf, ObjectType.cs_fromRaw(object: object)) } ), forKey: notificationKey, inObject: observer ) } ``` I get the compiler error: `Cannot convert value of type 'ObjectMonitor<D>' to expected argument type 'ObjectMonitor<_>'`. In theory there should be no difference between calling a closure and a function with the same input and return types, so I think this is the issue. Not sure how to fix yet.
Author
Owner

@SoyArpad commented on GitHub (Sep 21, 2017):

any update on this @JohnEstropia? im getting the same error while I'm trying to Archive, Thanks

@SoyArpad commented on GitHub (Sep 21, 2017): any update on this @JohnEstropia? im getting the same error while I'm trying to Archive, Thanks
Author
Owner

@SoyArpad commented on GitHub (Sep 21, 2017):

it seems that ObjectType.cs_fromRaw (object: object) was doing weird casting and the compiler does not like when is archiving or profiling, so I think we can check if the object implements the ObjectType in the guard.

private func registerObjectNotification(_ notificationKey: UnsafeRawPointer, name: Notification.Name, toObserver observer: AnyObject, callback: @escaping (_ monitor: ObjectMonitor<ObjectType>, _ object: ObjectType) -> Void) {
        
        cs_setAssociatedRetainedObject(
            NotificationObserver(
                notificationName: name,
                object: self,
                closure: { [weak self] (note) in
                    
                    guard let `self` = self,
                        let userInfo = note.userInfo,
                        let object = userInfo[String(describing: NSManagedObject.self)] as? ObjectType else {
                            
                            return
                    }
                    callback(self, object)
                }
            ),
            forKey: notificationKey,
            inObject: observer
        )
    }

The same for ListMonitor

internal func registerObjectNotification(_ notificationKey: UnsafeRawPointer, name: Notification.Name, toObserver observer: AnyObject, callback: @escaping (_ monitor: ListMonitor<ObjectType>, _ object: ObjectType, _ indexPath: IndexPath?, _ newIndexPath: IndexPath?) -> Void) {
        
        cs_setAssociatedRetainedObject(
            NotificationObserver(
                notificationName: name,
                object: self,
                closure: { [weak self] (note) -> Void in
                    
                    guard let `self` = self,
                        let userInfo = note.userInfo,
                        let rawObject = userInfo[String(describing: NSManagedObject.self)] as? ObjectType else {
                            
                            return
                    }
                    callback(
                        self,
                        rawObject,
                        userInfo[String(describing: IndexPath.self)] as? IndexPath,
                        userInfo["\(String(describing: IndexPath.self)).New"] as? IndexPath
                    )
                }
            ),
            forKey: notificationKey,
            inObject: observer
        )
    }

after the correction my app is archiving successfully @sidmani, just I want to know @JohnEstropia if this is a valid fix and doesn't affect to something else, it seems that my app runs perfect but I'm not using ListObserver or MonitorObserver, so just let me know any comment

@SoyArpad commented on GitHub (Sep 21, 2017): it seems that ObjectType.cs_fromRaw (object: object) was doing weird casting and the compiler does not like when is archiving or profiling, so I think we can check if the object implements the ObjectType in the guard. ``` swift private func registerObjectNotification(_ notificationKey: UnsafeRawPointer, name: Notification.Name, toObserver observer: AnyObject, callback: @escaping (_ monitor: ObjectMonitor<ObjectType>, _ object: ObjectType) -> Void) { cs_setAssociatedRetainedObject( NotificationObserver( notificationName: name, object: self, closure: { [weak self] (note) in guard let `self` = self, let userInfo = note.userInfo, let object = userInfo[String(describing: NSManagedObject.self)] as? ObjectType else { return } callback(self, object) } ), forKey: notificationKey, inObject: observer ) } ``` The same for ListMonitor ``` swift internal func registerObjectNotification(_ notificationKey: UnsafeRawPointer, name: Notification.Name, toObserver observer: AnyObject, callback: @escaping (_ monitor: ListMonitor<ObjectType>, _ object: ObjectType, _ indexPath: IndexPath?, _ newIndexPath: IndexPath?) -> Void) { cs_setAssociatedRetainedObject( NotificationObserver( notificationName: name, object: self, closure: { [weak self] (note) -> Void in guard let `self` = self, let userInfo = note.userInfo, let rawObject = userInfo[String(describing: NSManagedObject.self)] as? ObjectType else { return } callback( self, rawObject, userInfo[String(describing: IndexPath.self)] as? IndexPath, userInfo["\(String(describing: IndexPath.self)).New"] as? IndexPath ) } ), forKey: notificationKey, inObject: observer ) } ``` after the correction my app is archiving successfully @sidmani, just I want to know @JohnEstropia if this is a valid fix and doesn't affect to something else, it seems that my app runs perfect but I'm not using ListObserver or MonitorObserver, so just let me know any comment
Author
Owner

@JohnEstropia commented on GitHub (Sep 22, 2017):

Thanks for investigating this. I hit this problem in the one of my projects as well and I'm still looking for an actual fix inside the cs_fromRaw() method. The issue is that the compiler doesn't like it when you cast an object to it's own type (which happens on optimized builds due to inlining). @SoyArpad 's code above works because of the extra type-check, which prevents the optimizer from inlining. We can do that for all cs_fromRaw() calls but other usage of the method might still break.

If I can't find a better workaround by the end of the week we'll go with the workaround above.

@JohnEstropia commented on GitHub (Sep 22, 2017): Thanks for investigating this. I hit this problem in the one of my projects as well and I'm still looking for an actual fix inside the `cs_fromRaw()` method. The issue is that the compiler doesn't like it when you cast an object to it's own type (which happens on optimized builds due to inlining). @SoyArpad 's code above works because of the extra type-check, which prevents the optimizer from inlining. We can do that for all `cs_fromRaw()` calls but other usage of the method might still break. If I can't find a better workaround by the end of the week we'll go with the workaround above.
Author
Owner

@JohnEstropia commented on GitHub (Sep 22, 2017):

@sidmani @SoyArpad I made an edit and it's on the prototype/Swift_3_2 and prototype/Swift_4_0 branches. Let me know how it works for you.

@JohnEstropia commented on GitHub (Sep 22, 2017): @sidmani @SoyArpad I made an edit and it's on the `prototype/Swift_3_2` and `prototype/Swift_4_0` branches. Let me know how it works for you.
Author
Owner

@SoyArpad commented on GitHub (Sep 23, 2017):

it works, thank you @JohnEstropia

@SoyArpad commented on GitHub (Sep 23, 2017): it works, thank you @JohnEstropia
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/CoreStore#165