c++ - EXC_BAD_ACCESS 抛出异常

标签 c++ xcode macos

我在使用我们的一位合作伙伴提供的共享库时遇到问题,并将其缩小到这个测试用例:

我的自己测试库编译成libCrashTestLib.dylib:

#include <exception>
#include <iostream>

extern "C" void Test() {
  try {
    throw std::exception{};
  } catch (const std::exception& e) { }
  std::cout << "Success" << std::endl;
}

我的主要可执行文件加载我的库并调用 Test 函数:

#include <string>
#include <dlfcn.h>

int main(int argc, char** argv) {
  std::string lib_path = "/path/to/libCrashTestLib.dylib";

  void* handle = dlopen(lib_path.c_str(), RTLD_NOW | RTLD_GLOBAL);
  void (*test_pointer)() = reinterpret_cast<void(*)()>(dlsym(handle, "Test"));
  test_pointer();
  dlclose(handle);
}

这工作正常并打印 Success

但是,当我只是链接(甚至没有调用)我们的合作伙伴提供的库时,它会给我一个 EXC_BAD_ACCESS,我会在其中抛出异常。

我正在寻找的是以下两种情况之一:

  • 帮助我摆脱这种行为的编译器或链接器开关。
  • 一种创建我自己的库的方法,当我链接它时它会崩溃这个程序,这样我就可以向我们的合作伙伴提供更多需要修改的细节。

为了完整起见,这是我正在使用的 CMakeLists.txt:

cmake_minimum_required(VERSION 3.0)
project(CrashTest CXX)

set(CMAKE_CXX_STANDARD 14)
set(CMAKE_CXX_STANDARD_REQUIRED on)

find_library(VendorApi NAMES vendorapi PATHS ${CMAKE_SOURCE_DIR}) 

add_library(CrashTestLib SHARED lib.cpp)
# Uncomment this line to make it crash:
#target_link_libraries(CrashTestLib VendorApi)

add_executable(CrashTestMain main.cpp)

最佳答案

崩溃的最可能原因是供应商的库是用libstdc++编译的,而你的代码是用libc++编译的。

我可以通过在构建类作为库加载时间的一部分时发出 cout 来很容易地触发崩溃,例如

#include <exception>
#include <iostream>
#include <string>

class bongo {

    public:
    bongo() {
        std::cout << "Log something" << std::endl;
    }
};

static class bongo *boing;

void __attribute__((constructor)) start_something(void) {
    boing = new bongo;
}


extern "C" void Test() {
  try {
    throw std::exception{};
  } catch (const std::exception& e) { }
  std::cout << "Success" << std::endl;
}

加载器代码:

#include <string>
#include <dlfcn.h>

int main(int argc, char** argv) {
  std::string lib_path = "./libCrashTestLib.dylib";

  void* handle = dlopen(lib_path.c_str(), RTLD_NOW | RTLD_GLOBAL);
  void (*test_pointer)() = reinterpret_cast<void(*)()>(dlsym(handle, "Test"));
  test_pointer();
  dlclose(handle);
}

生成文件:

CXXFLAGS += -std=c++11
STDLIB = -stdlib=libstdc++

all: libCrashTestLib.dylib testLib

libCrashTestLib.dylib: CrashTest.cpp
    $(CXX) $(CXXFLAGS) $(STDLIB) -shared -o $@ $<

testLib: testLib.cpp
    $(CXX) $(CXXFLAGS) -o $@ $<

clean:
    rm -f *.dylib testLib

调用:

$ make clean && make STDLIB= && ./testLib
rm -f *.dylib testLib
c++ -std=c++11  -shared -o libCrashTestLib.dylib CrashTest.cpp
c++ -std=c++11 -o testLib testLib.cpp
Log something
Success

调用失败:

$ make clean && make && ./testLib
rm -f *.dylib testLib
c++ -std=c++11 -stdlib=libstdc++ -shared -o libCrashTestLib.dylib CrashTest.cpp
c++ -std=c++11 -o testLib testLib.cpp
Segmentation fault: 11

您可以使用 otool -L 检查链接到二进制文件的 C++ 库的版本:

$ otool -L libCrashTestLib.dylib
libCrashTestLib.dylib:
    libCrashTestLib.dylib (compatibility version 0.0.0, current version 0.0.0)
    /usr/lib/libstdc++.6.dylib (compatibility version 7.0.0, current version 104.1.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1226.10.1)

关于c++ - EXC_BAD_ACCESS 抛出异常,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37193321/

相关文章:

iphone - 在 UINavigationController 内的 UIViewController 之间切换

ios - 如何从我的 UI 测试访问我的 swift 类?

objective-c - 无法在 macOS 应用程序上运行 xctest - 无法加载,因为它已损坏或缺少必要的资源

macos - 有没有办法手动将文件卸载到 iCloud Drive?

c++ - 将 std::variant 转换为另一个具有父类(super class)型集的 std::variant

c++ - C++检测Windows操作系统

c++ - Qt 5.5 构建自定义 QTreeView

c++ - 使用系统 ("./some_program"),如何在 "some_program"死亡时防止父进程终止?

xcode - 如何在 Xcode 中包含 cocos2d-x 模板?

ios - 将源添加到混音器时出现 "throwing -10878"