0

我遇到了分段错误,我已将其缩小for为回调函数中的循环。这很奇怪,因为该程序以前可以工作,现在不行了!

struct debuggerth_command debuggerth_protocol[] = { /*
    * Note: These strings are NOT null-terminated. The
    * strings are 4 bytes long for memory alignment and
    * integer-cast comparisons.
    */

    { "run ", debuggerth_startprocess },
    { "stop", 0 },
    { "inp ", 0 },
    { "sig ", 0 },
    { 0, 0 }
};

这是代码:

int debuggerth_callback (struct libwebsocket_context * context,
                    struct libwebsocket * wsi,
                    enum libwebsocket_callback_reasons reason,
                    void * user,
                    void * in,
                    size_t len){

switch (reason) {

case LWS_CALLBACK_RECEIVE:

    if (len < 4){
        /* send error */
        return -1;
    }

    /* Getting a segmentation fault
     * within this loop.
     */

    // I used this break to determine where the seg fault starts
    // break

    int i = 0;
    for (; debuggerth_protocol[i].cmd; i++)
        if (cmpcmd (debuggerth_protocol[i].cmd, in)) break;


    //break;

    if (!debuggerth_protocol[i].cmd){
        int byteswritten = sprintf
            (debuggerth_message,
             debuggerth_format,
             debuggerth_headers[0],
             debuggerth_errors [0]);

         libwebsocket_write (wsi, debuggerth_message,
                                      byteswritten,
                                      LWS_WRITE_TEXT);
         return -1;
    }

    break;

这是字符串比较宏:

#define cmpcmd(cmd, str) ((*(int*)(cmd)) == (*(int*)(str)))

有人有想法么?

4

3 回答 3

3

一个想法:依靠你的字符串正好是一个大小的事实int是相当可怕的。

人们经常尝试做类似的聪明事情,但当底层假设发生变化时却被严重咬伤,例如移动到int类型为 8 字节的平台。

我会放弃该宏并将其重写为使用strcmpor strncmp (a)


还有一些其他的事情要做。

首先,在尝试使用之前打印出(或使用调试器检查)所有变量。可能in是NULL。

或者,您可能尝试调用 NULL 命令,例如stopor sig,或者即使您得到一个不在您的表中的命令,并且您在i等于时盲目地调用它4。这些特殊的可能性在代码中没有显示,跟随循环,所以它是纯粹的,虽然我想认为是受过教育的,我的猜测。


另一种可能性是您在不允许未对齐访问的体系结构上运行。一些体系结构针对特定边界的访问进行了优化(例如从 32 位对齐的地址获取 32 位值),如果违反该对齐方式,运行速度会变慢。

但是,某些架构根本不允许未对齐的访问,如果您尝试,则会给出类似 BUS 错误的信息。

由于您现在在评论中指出您正在使用 ARM,因此几乎可以肯定是这种情况。有关更多信息,请参见此处。

如果是这种情况,那就有理由摆脱棘手的宏并使用更传统的解决方案。


(a):您可能还想在某个时候研究“严格别名”一词,因为这在技术上可能是未定义的行为。

于 2013-06-12T04:40:58.917 回答
0

鉴于这是在 ARM 上运行的,我认为您的问题是它正在执行未对齐的内存访问,这将失败或非常慢。这不完全是一个段错误。 例如,请参阅此问题,并且按照建议,-Wcast-align可能会将其标记为有风险的。您可以打开软件解决方法,但这可能比仅在代码中修复它要慢。

一种选择是使用memcmpwhich gcc 可能能够编译成几乎与读取单词一样简单的东西,如果它是对齐的。

如果性能很关键,另一种选择是将循环展开为通过命令的第一个字节切换的 case 语句。然后只需检查以下字符是否符合预期。

于 2013-06-12T05:10:43.357 回答
0

正如@Jonothan Leffler 建议的那样,我查看了我的代码的一些更改。这是我所做的更改:

struct debuggerth_command {
    char * cmd;
    int (*function)(struct debuggerth_session *, char * input);
};

struct debuggerth_command {
    char cmd[4]; // changed this an array
    int (*function)(struct debuggerth_session *, char * input);
};

所以,当我在这里初始化结构时:

struct debuggerth_command debuggerth_protocol[] = { /*
    * Note: These strings are NOT null-terminated. The
    * strings are 4 bytes long for memory alignment and
    * integer-cast comparisons.
    */

    { "run ", debuggerth_startprocess },
    { "stop", 0 },
    { "inp ", 0 },
    { "sig ", 0 },
    { 0, 0 } /* Zero used to be a pointer value,
              * but now it's the first element in a 
              * 4 byte array
              */
};

这改变了for循环的评估:

int i = 0;
for (; debuggerth_protocol[i].cmd; i++)
    if (cmpcmd (debuggerth_protocol[i].cmd, in)) break;

要始终评估为真,因为cmd现在是指向 4 字节数组的有效指针 - 其中,第一个值是0.

我将删除宏,因为它在某些架构上可能表现不佳。但是,这不能通过使用C11'alignas功能来解决吗?

于 2013-06-12T05:32:12.370 回答