将char数组强制转换为结构时出现Segfault
Segfault when casting char array to struct
当我使用g++4.7编译并运行时,我试图将char数组强制转换为结构,并接收segfault,但当我使用clang 3.3编译并运行程序时,我没有。
这是消息结构描述:
typedef struct {
char code[4];
char nickname[24];
struct in_addr addr;
int port;
int seqNum;
char body[MESSAGE_MAX_LENGTH - (sizeof(char) * 28) - (sizeof(int) * 2) - sizeof(struct in_addr)];
} Message;
这是导致分段故障的线路:
Message *recvMsg = (Message *)packet.buffer;
数据包对象的类型如下:
class UDPPacket {
public:
static const size_t maxBufferSize = MESSAGE_MAX_LENGTH;
uint8_t buffer[maxBufferSize];
size_t length;
struct in_addr addr;
int port;
UDPPacket();
UDPPacket(struct in_addr addr, int port);
std::string getRemoteAddrString();
std::string getDataAsString();
};
这是gdb:产生的回溯
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x7ffff67f5700 (LWP 22753)]
0x00007ffff79787f7 in ?? () from /usr/lib64/libstdc++.so.6
(gdb) backtrace
#0 0x00007ffff79787f7 in ?? () from /usr/lib64/libstdc++.so.6
#1 0x00007ffff7978850 in std::basic_string<char, std::char_traits<char>, std::allocator<char> >::~basic_string() () from /usr/lib64/libstdc++.so.6
#2 0x0000000000411cb7 in SendMessage () at /home1/user123/ugh/final-project/main.cpp:189
#3 0x00000000004172df in std::_Bind_simple<void (*())()>::_M_invoke<>(std::_Index_tuple<>) (
this=0x620310) at /usr/include/c++/4.7/functional:1598
#4 0x000000000041722f in std::_Bind_simple<void (*())()>::operator()() (this=0x620310)
at /usr/include/c++/4.7/functional:1586
#5 0x00000000004171c8 in std::thread::_Impl<std::_Bind_simple<void (*())()> >::_M_run() (
this=0x6202f8) at /usr/include/c++/4.7/thread:115
#6 0x00007ffff796f340 in ?? () from /usr/lib64/libstdc++.so.6
#7 0x00007ffff7bc6e0f in start_thread () from /lib64/libpthread.so.0
#8 0x00007ffff70e044d in clone () from /lib64/libc.so.6
我不知道为什么当我用g++编译而不是用clang编译时会出现分段错误?
编辑:这就是SendMessage((的样子:
56 void SendMessage() {
57 while(true){
58 std::cout << "> ";
59 std::string input;
60 std::getline(std::cin, input);
61
62 if(input.length() > 140){
63 std::cout << "[Message is too long and was not sent]" << std::endl;
64 continue;
65 }
66
67 Message sendMsg;
68 ::strncpy(sendMsg.code, "SEND", 4);
69 ::strncpy(sendMsg.body, input.c_str(), MESSAGE_MAX_LENGTH - 28);
70
71 if(isLeader){
72 // Leader Code
73 ::strncpy(sendMsg.nickname, lState->name.c_str(), lState->name.length());
74 sendMsg.addr = lState->ownAddr.addr;
75 sendMsg.port = lState->ownAddr.port;
76
77 sendMsg.seqNum = lState->seqNum;
78 broadcast(lState->allClients, &sendMsg);
*lines 79 to 187 commented out*
187 lState->seqNum += 1;
188 }
189 } //end of while loop
190 }
不能保证结构的实际大小是结构中每个成员的标称大小之和。
由于填充或其他编译器和/或平台特定的问题,实际大小可能是更大。
以下是更多详细信息:
为什么不是';t结构的sizeof等于每个成员的sizeof之和?
设置
忽略sizeof(Message)
可能不是您所认为的(尽管它可能是!(,您将Message sendMsg
放在堆栈上。
假定标准的类型宽度,sendMsg.body
具有用于[MESSAGE_MAX_LENGTH - 36 - sizeof(in_addr)]
个字符的空间。
问题
然后您将看到::strncpy(sendMsg.body, input.c_str(), MESSAGE_MAX_LENGTH - 28);
,它可能会写入比空间多得多的字符!这可以保持写入超过sendMsg
的末尾,以及堆栈上它旁边发生的任何事情,这可能因编译器而异。也许你的叮当汇编&输入越来越幸运(尽管仍然不正确(。
一旦覆盖了无辜的堆栈变量,像segfault这样的Bad Things(tm(随时都可能发生。
预防
假设您不需要以null终止的char数组(可能是这样(,请确保复制的数据永远不会超过您的空间。
::strncpy(sendMsg.code, "SEND", sizeof(sendMsg.code));
::strncpy(sendMsg.body, input.c_str(), sizeof(sendMsg.body));
::strncpy(sendMsg.nickname, lState->name.c_str(), sizeof(sendMsg.nickname));
请记住,这可能仍然是丢弃信息,而不是null终止,但至少它不会践踏您的堆栈。
- 如何循环打印顶点结构
- 通过方法访问结构
- 使用不带参数的函数访问结构元素
- 预处理器:插入结构名称中的前一个行号
- 为什么在没有显式默认构造函数的情况下,将另一个结构封装在联合中作为成员的结构不能编译
- 孤立代码块在结构中引发异常
- 有什么方法可以遍历结构吗
- 如何在 C# 中映射双 C 结构指针?
- 如何在C++中使用结构生成映射
- 无法将结构注册为增强几何体3D点
- 多成员Constexpr结构初始化
- C++中带有List类的迭代器Segfault
- C++将文本文件中的数据读取到结构数组中
- 如何重构类层次结构以避免菱形问题
- 如何在C++中序列化结构数据
- std::vector的包装器,使数组的结构看起来像结构的数组
- 没有为自己的结构调用列表推回方法
- 结构segfault的结构
- 调用结构的虚函数时出现segfault
- 将char数组强制转换为结构时出现Segfault