我遇到了分段错误,我已经缩小到回调函数中的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)))
有人有什么想法吗?
答案 0 :(得分:3)
一个想法:依赖于你的字符串正好是int
的大小这一事实是非常可怕的。
人们经常尝试做一些聪明的事情,只是在基础假设发生变化时被严重咬伤,例如转移到int
类型为8个字节的平台。
我放弃了那个宏并重写它以使用strcmp
或strncmp
(a)。
还有其他一些事情要做。
首先,在尝试使用它们之前打印出(或使用调试器检查)所有变量。可能是in
为NULL。
或许您尝试调用stop
或sig
之类的NULL命令,或者即使您获得的命令不在您的表中,并且在i
相等时您也会盲目地调用它到4
。这些特殊的可能性在代码中没有显示,循环之后,所以它是纯粹的,尽管我想在我看来受过教育,猜测。
另一种可能性是,您运行的是不允许未对齐访问的体系结构。某些体系结构针对特定边界上的访问进行了优化(例如从32位对齐的地址获取32位值),如果违反该对齐,则运行速度会慢一些。
然而,某些架构根本不允许未对齐的访问,而是在尝试时给出类似BUS错误的内容。
由于您现在已在评论中指出您正在使用ARM,因此几乎可以肯定。有关更多信息,请参阅here。
如果是这种情况,甚至更多理由摆脱棘手的宏并使用更传统的解决方案。
(a):您可能还想在某些时候调查术语“严格别名”,因为这在技术上可能是未定义的行为。
答案 1 :(得分:0)
鉴于这是在ARM上运行,我认为你的问题是它正在进行未对齐的内存访问,这将失败或者非常慢。这不完全是一个错误。 See this question for example,根据建议,-Wcast-align
可能会将其标记为有风险。您可以打开软件解决方法,但这可能比在代码中修复它更慢。
一种选择是使用memcmp
gcc可以编译成几乎与单词读取一样简单的东西,如果它是对齐的。
另一个选择,如果性能至关重要,则将循环展开为由命令的第一个字节切换的case语句。然后只需检查以下字符是否符合预期。
答案 2 :(得分: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;
要始终评估true,因为cmd
现在是指向4字节数组的有效指针 - 其中第一个值为0
。
我将删除宏,因为它可能在某些体系结构上表现不佳。但是,使用C11
的{{1}}功能无法解决这个问题吗?