1

我正在一个遗留代码库中工作,其中包含大量使用手动保留/释放编写的 Objective-C++。内存使用大量 C++ 进行管理,并在调用包含对象的std::shared_ptr<NSMyCoolObjectiveCPointer>构造时传入了一个合适的删除器。release这似乎很好用;但是,当启用 UBSan 时,它会抱怨指针未对齐,通常是在取消引用 shared_ptrs 以执行某些工作时。

我已经搜索了线索和/或解决方案,但是很难找到有关 Objective-C 对象指针来龙去脉的技术讨论,更难找到有关 Objective-C++ 的任何讨论,所以我在这里。

这是一个完整的 Objective-C++ 程序,它演示了我的问题。当我使用 UBSan 在我的 Macbook 上运行此程序时,我在以下位置遇到了一个未对齐的指针问题shared_ptr::operator*

#import <Foundation/Foundation.h>
#import <memory>

class DateImpl {
public:
    DateImpl(NSDate* date) : _date{[date retain], [](NSDate* date) { [date release]; }} {}

    NSString* description() const { return [&*_date description]; }

private:
    std::shared_ptr<NSDate> _date;
};

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        DateImpl date{[NSDate distantPast]};
        NSLog(@"%@", date.description());
        return 0;
    }
}

我在电话中得到了这个DateImpl::description

runtime error: reference binding to misaligned address 0xe2b7fda734fc266f for type 'std::__1::shared_ptr<NSDate>::element_type' (aka 'NSDate'), which requires 8 byte alignment
0xe2b7fda734fc266f: note: pointer points here
<memory cannot be printed>

怀疑使用&*to “cast” shared_ptr<NSDate>to an 有问题NSDate*。我想我可以通过使用.get()shared_ptr 来解决这个问题,但我真的很好奇发生了什么。感谢您的任何反馈或提示!

4

2 回答 2

1

这里有一些红鲱鱼:shared_ptr,手动保留/释放等。但我最终发现即使是这个非常简单的代码(启用了 ARC)也会导致 ubsan 命中:

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSDate& d = *[NSDate distantPast];
        NSLog(@"%@", &d);
    }
    return 0;
}

这似乎只是一个问题[NSDate distantPast](顺便说一下[NSDate distantFuture],,但不是,例如,[NSDate date])。我得出的结论是,这些必须是在 Foundation 深处某处粗略/未对齐地分配的单例对象,并且当您取消引用它们时,它会导致读取未对齐的指针。

(请注意,当代码只是NSLog(@"%@", &*[NSDate distantPast]).在纯 Objective-C 中没有简单的方法来实现这一点,因为您无法将操作与操作分开,就像在涉及 C++ 引用时一样[通过将临时结果存储在] 中。)&*shared_ptrshared_ptroperator*&**NSDate&

于 2019-08-21T21:11:58.937 回答
1

您不应该使用“裸”NSDate类型。Objective-C 对象应始终与指向对象类型(例如NSDate *)一起使用,并且您永远不应该获得“指针后面的类型”。

特别是,在 64 位平台上,Objective-C 对象指针有时可能不是有效指针,而是“标记指针”,将对象的“值”存储在指针的某些位中,而不是作为实际分配的目的。您必须始终让 Objective-C 运行时机制处理 Objective-C 对象指针。将其取消引用为常规 C/C++ 指针可能会导致未定义的行为。

于 2019-09-02T00:37:04.930 回答