QByteArray::data()返回值解析,结构体中char*赋值崩溃

这是一个在使用QByteArray时遇到的bug分析记录

情景

  • 在使用QTcpSocket编程时,使用了自定义的结构体进行数据通信,结构体如下,其中,char* load是消息体的地址。在实际使用过程中,使用readALL读取数据流后,进行分包和组包。在使用char* QByteArray::data 接口对load进行赋值,程序会崩溃。
typedef struct
{
    
    
    unsigned int send_id;       // 发送方的ID(网络的IP、SRIO的ID)
    unsigned int recv_id;       // 接收方的ID(网络的IP、SRIO的ID)
    unsigned int msg_type : 8;  // 消息类型
    unsigned int len : 24;      // 消息长度,字节数
    unsigned int conn_type: 8;  // 连接类型,TCP、UDP等
    unsigned int pkg_num : 8;   // 总的包数(用于组包传输)
    unsigned int pkg_idx : 8;   // 子包索引(用于组包传输),从1计数
    unsigned int rsvd : 8;      // 保留位
    unsigned int check_sum;     // 校验位
    char* load;                 // 消息体地址
} DispCtrlMsg;

测试程序

明明是char* 指针的赋值,但是程序却崩溃了;直接定义一个char*指针进行赋值却失败,

int main(int argc, char *argv[])
{
    
    
    QCoreApplication a(argc, argv);

    const int headLength = sizeof(DispCtrlMsg) - sizeof(char*);

    QByteArray str;
    str.resize(26);
    for(int i=0;i<str.size();i++){
    
    
        str[i]='a';
    }
    DispCtrlMsg *msg = new DispCtrlMsg();
    msg = (DispCtrlMsg*)str.left(headLength).data();

    int len = str.size();
    QByteArray r = str.right(len - headLength);
    cout << r.data() << endl;
    cout <<"1) "<< hex<<&msg->load <<endl;
//    msg->load = new char[1]; //注释这一行即崩溃。
    cout <<"2) "<< hex<<&msg->load <<endl;
    msg->load = r.data();
    cout <<"3) "<< hex<<&msg->load << endl;
    cout <<"4) "<< hex<<msg->load << endl;
    cout <<"5) "<< sizeof(msg->load) <<endl;

    char *c = r.data();
    cout <<"direct char* "<< c <<endl;


    delete msg->load;
    return a.exec();
}
  • 测试结果如图,注释掉,new char[1]后,程序就会崩溃。其中new char[]的长度只要满足大于等于1即可。
    在这里插入图片描述

临时解决方案

  • 在使用结构体中的指针赋值时,采用new或者malloc,对内容进行复制,而不是采用指针赋值,指向源。

msg->load只是个指针而以,它可以指向一个字符,也可以指向一个字符串。但是,所以这个方法会导致资源泄露。因为new char了,确没有使用,并由于msg->load在之后已经不指向这个字符的空间,使之以后都没有机会再被释放掉了,所以这1bit空间就资源泄露了。

添加原因:

在强制类型转换的时候,QByteArray r = str.right(len - headLength);
r的长度小于结构体的长度,因此,结构体中的char* load,没有分配空间,因此,程序非法访问内存,程序崩溃。

解决思路

创建一个结构体对象,或者为结构体指针使用malloc分配空间。读取数据时采用复制的方式。

猜你喜欢

转载自blog.csdn.net/u013894391/article/details/100585221