关闭优化时 C 库崩溃

C library crashes when optimization is turned off

我正在 Mac OS X 上用 C 编写一个库,使用 XCode 6. 该库基本上是一个由 X-Plane 加载并提供数据的插件通过网络套接字服务器输出。

图书馆反过来使用 libwebsockets library, which I compiled using the the guide from the developers repository documentation, here。简而言之,我检查了 libwebsockets 存储库,创建了一个构建目录和 运行

cmake ..
make

我的插件 100% 正常工作,X-Plane 毫无怨言地加载它...打开优化后!

当我在 XCode 中禁用对我的库的优化时,到 None [-O0],废话击中了风扇,库调用 libwebsockets 函数 libwebsocket_create_context() 时崩溃。

关闭优化后怎么会引入一个bug/crash?通常情况下不是相反吗,在 进行优化,可能会出现问题?

以下是故障点附近的库代码摘录:

PLUGIN_API int XPluginStart(char *outName, char *outSig, char *outDesc) {
    strcpy(outName, "XP Web Socket");
    strcpy(outSig, "sparkbuzz.plugins.xpwebsocket");
    strcpy(outDesc, "Web socket plugin for streaming data to the browser.");

    struct lws_context_creation_info info;
    info.port = port;
    info.iface = NULL;
    info.protocols = protocols;
    info.extensions = libwebsocket_get_internal_extensions();
    info.ssl_cert_filepath = NULL;
    info.ssl_private_key_filepath = NULL;
    info.gid = -1;
    info.uid = -1;
    info.options = opts;

    context = libwebsocket_create_context(&info); // FAILS HERE WITH EXC_BAD_ACCESS

    if (context == NULL) {
        // libwebsockets initialization has failed!
        return -1;
    }

    // Find XPlane datarefs
    gIAS = XPLMFindDataRef("sim/cockpit2/gauges/indicators/airspeed_kts_pilot");

    // Register flight loop callback
    XPLMRegisterFlightLoopCallback(MyFlightLoopCallback, 1.0, NULL);

    return 1;
}

您似乎没有初始化 struct lws_context_creation_info 中的所有字段,导致出现未定义的行为。根据编译器选项和其他不可预测的情况,您的程序实际上可能看起来正常运行......纯属偶然!

您可以通过使用 memset:

清除结构来轻松解决此问题
struct lws_context_creation_info info;
memset(&info, 0, sizeof info);
info.port = port;
info.iface = NULL;
info.protocols = protocols;
info.extensions = libwebsocket_get_internal_extensions();
info.ssl_cert_filepath = NULL;
info.ssl_private_key_filepath = NULL;
info.gid = -1;
info.uid = -1;
info.options = opts;

在 C99 中执行此操作的另一种方法是以这种方式初始化结构:

struct lws_context_creation_info info = {
    .port = port,
    .iface = NULL,
    .protocols = protocols,
    .extensions = libwebsocket_get_internal_extensions(),
    .ssl_cert_filepath = NULL,
    .ssl_private_key_filepath = NULL,
    .gid = -1,
    .uid = -1,
    .options = opts };

任何其他字段将根据类型初始化为 00.0NULL,因此您可以省略 iface、[=19= 的初始化程序] 和 ssl_private_key_filepath.

重要的是始终使用通用方法来初始化具有自动存储的结构,以防止在稍后使用新字段扩展结构时或在您忘记某些初始化器的地方出现难以发现的虚假错误。

另请注意,此函数的前 3 行也有风险:

strcpy(outName, "XP Web Socket");
strcpy(outSig, "sparkbuzz.plugins.xpwebsocket");
strcpy(outDesc, "Web socket plugin for streaming data to the browser.");

输出字符数组的大小未知。可能会发生缓冲区溢出。将缓冲区大小作为参数传递或将其指定为常量并检查内容是否适合。