我非常意外的行为

memcpy extremely unexpected behavior

本文关键字:意外 非常      更新时间:2023-10-16

我使用memcpy将信息从一个正在写入磁盘的数组中复制到这个数组中。我存储一个256字节的char*(名称数组)*3个长数字,和一个短数字。我以为它会正常工作,直到我尝试了它,它没有。将信息保存到磁盘时,一切似乎都很正常。但是,当试图读取信息时,memcpy就会出现故障,将变量直接留在名称数组后面为0的位置,当我的程序需要它来加载其他内容时,就会出现segfault。

起初我认为当写入磁盘时,信息可能已经损坏,或者当从它加载时,但我找不到保存或加载过程的任何大问题,所以我接下来做的是打印出数组上的每一个字节(与Qt的qDebug),看看我是否能发现任何错误。

不用说,它没有按计划工作,因为qDebug只打印非空字符,而"name数组"有很多这样的字符,但它做了一些令人惊讶的事情:它以某种方式使memcpy工作而不工作,因为现在它会成功地复制第一个长数字,但它会破坏第二个长数字。问题是,整件事几乎毫无关联!

            char* block = new char[FreeBlock::TablaMTD_v]; //3958 bytes long
            fRead.seekg(toLoad, ios::beg); //toLoad being an unsigned long file pointer, fRead being a working ifstream
            fRead.read(block, FreeBlock::TablaMTD_v); //reading all 3958 bytes to block
            fRead.close();
            short bsize = 0, pos = 0;
            memcpy(&bsize, block, 2);
            pos+=2;
            for(short i = 0; i < bsize; i++){
                char* tname = new char[257];
                unsigned long ptrmtd = 0, ptrdt = 0, ptrind = 0;
                unsigned short indmtd = 0;
                memcpy(tname, &block[pos], 256);
                tname[256] = 0;
                pos+=256;
                memcpy(&ptrmtd, &block[pos], 8); //without qdebug loop, stays at 0. otherwise, has correct value
                pos+=8;
                memcpy(&ptrdt, &block[pos], 8); //with qdebug loop, stays at 0. otherwise, has correct value
                pos+=8;
                memcpy(&ptrind, &block[pos], 8);
                pos+=8;
                memcpy(&indmtd, &block[pos], 2);
                pos+=2;
                for(int i = 0; i < FreeBlock::TablaMTD_v; i++){
                    qDebug()<<block[i]; //miracle solution, somehow
                }
                CampoMTDB* cmtd = nextCampoMTDB(ptrmtd, true); //based on ptrmtd, which if 0, returns null pointer
                unsigned long nextcmtdb = cmtd->next; //seg fault due to null pointer

因为for循环是我唯一添加的东西,注释/取消注释它实际上改变了整个过程的结果,我真的很困惑。在"意外行为"方面创下了我的新纪录。

考虑到我对c++有点陌生,直到最近我才听说我在这里使用的随机危险实践显然是我不应该使用的,我仍然不明白在memcpy操作之后添加随机for循环如何或为什么会对这些操作产生任何影响,或者为什么memcpy一开始就不能像它应该的那样工作。

还请注意,在我保存文件之后,我没有再碰它,它根本没有改变,但是读取它的输出改变了。

如果它有助于知道,我在Qt 5.3中使用VC2013, x64 Windows 7

由于您在Windows 7下使用VC2013,因此unsigned long的大小为4字节(而不是8字节)。

在任何情况下,为了您自己的安全,您应该使用sizeof而不是那些恒定值8和2。

改变:

memcpy(&ptrmtd, &block[pos], 8);
pos+=8;
memcpy(&ptrdt, &block[pos], 8);
pos+=8;
memcpy(&ptrind, &block[pos], 8);
pos+=8;
memcpy(&indmtd, &block[pos], 2);
pos+=2;

:

memcpy(&ptrmtd, &block[pos], sizeof(ptrmtd));
pos+=sizeof(ptrmtd);
memcpy(&ptrdt, &block[pos], sizeof(ptrdt));
pos+=sizeof(ptrdt);
memcpy(&ptrind, &block[pos], sizeof(ptrind));
pos+=sizeof(ptrind);
memcpy(&indmtd, &block[pos], sizeof(indmtd));
pos+=sizeof(indmtd);

由于sizeof(unsigned long) == 4在您的系统上,memcpy(&ptrmtd, &block[pos], 8);可以修改不属于您的内存。这是非常危险的,所以千万不要这样做。