使用zLib删除无效
Invalid delete with zLib
我有代码使用zLib和谷歌的协议缓冲区。问题是,valgrind在同时使用这两种方法的类中检测无效的free。
==1419== Invalid free() / delete / delete[] / realloc()
==1419== at 0x4A06F1C: operator delete[](void*) (vg_replace_malloc.c:515)
==1419== by 0x4C3928F: openstreetmap::cOsmBlob::~cOsmBlob() (cOsmBlob.cc:129)
==1419== by 0x4045DF: void __gnu_cxx::new_allocator<openstreetmap::cOsmBlob>::destroy<openstreetmap::cOsmBlob>(openstreetmap::cOsmBlob*) (new_allocator.h:114)
==1419== by 0x404005: std::deque<openstreetmap::cOsmBlob, std::allocator<openstreetmap::cOsmBlob> >::pop_front() (stl_deque.h:1407)
==1419== by 0x403D39: std::queue<openstreetmap::cOsmBlob, std::deque<openstreetmap::cOsmBlob, std::allocator<openstreetmap::cOsmBlob> > >::pop() (stl_queue.h:240)
==1419== by 0x403BD6: threading::cFifoBuffer<openstreetmap::cOsmBlob>::~cFifoBuffer() (storage.h:86)
==1419== by 0x403A15: main (main.cc:40)
==1419== Address 0x50be390 is 752 bytes inside a block of size 7,152 free'd
==1419== at 0x4A077E6: free (vg_replace_malloc.c:446)
==1419== by 0x37A6209B3A: inflateEnd (inflate.c:1261)
==1419== by 0x4C39156: openstreetmap::cOsmBlob::cOsmBlob(std::basic_ifstream<char, std::char_traits<char> >*) (cOsmBlob.cc:116)
==1419== by 0x4C5B157: openstreetmap::cPbfPipelineFileReader::run(void*) (cPbfPipelineFileReader.cc:158)
==1419== by 0x37A5A07D14: start_thread (pthread_create.c:308)
==1419== by 0x37A4EF246C: clone (clone.S:114)
==1419==
==1419== Invalid free() / delete / delete[] / realloc()
==1419== at 0x4A06F1C: operator delete[](void*) (vg_replace_malloc.c:515)
==1419== by 0x4C3928F: openstreetmap::cOsmBlob::~cOsmBlob() (cOsmBlob.cc:129)
==1419== by 0x4045DF: void __gnu_cxx::new_allocator<openstreetmap::cOsmBlob>::destroy<openstreetmap::cOsmBlob>(openstreetmap::cOsmBlob*) (new_allocator.h:114)
==1419== by 0x404604: std::deque<openstreetmap::cOsmBlob, std::allocator<openstreetmap::cOsmBlob> >::_M_pop_front_aux() (deque.tcc:520)
==1419== by 0x404027: std::deque<openstreetmap::cOsmBlob, std::allocator<openstreetmap::cOsmBlob> >::pop_front() (stl_deque.h:1411)
==1419== by 0x403D39: std::queue<openstreetmap::cOsmBlob, std::deque<openstreetmap::cOsmBlob, std::allocator<openstreetmap::cOsmBlob> > >::pop() (stl_queue.h:240)
==1419== by 0x403BD6: threading::cFifoBuffer<openstreetmap::cOsmBlob>::~cFifoBuffer() (storage.h:86)
==1419== by 0x403A15: main (main.cc:40)
==1419== Address 0x5eb45d0 is not stack'd, malloc'd or (recently) free'd
我不明白,为什么地址没有正确对齐,为什么块被释放两次。
#define MAX_BLOB_HEADERSIZE (64 * 1024)
#define MAX_BLOB_DATASIZE (32 * 1024 * 1024)
cOsmBlob::cOsmBlob(std::ifstream *stream) {
char headerLength[4], *buffer;
pbf::BlobHeader header;
uint32_t length;
pbf::Blob blob;
int retval;
if (stream == NULL)
throw std::exception();
stream->read(headerLength, 4);
length = ntohl(*((uint32_t*)&headerLength));
if (length == 0 || length > MAX_BLOB_HEADERSIZE) {
cerr << "cOsmBlob: invalid blob header size" << endl;
throw exception();
}
/* read the BlobHeader */
buffer = new char[length];
stream->read(buffer, length);
if (header.ParseFromArray(buffer, length) == false) {
cerr << "cOsmBlob: unable to read BlobHeader" << endl;
delete[] buffer;
throw exception();
}
delete[] buffer;
/* read the Blob */
if (header.datasize() == 0 || header.datasize() > MAX_BLOB_DATASIZE) {
cerr << "cOsmBlob: invalid header->datasize()" << endl;
throw exception();
}
buffer = new char[header.datasize()];
stream->read(buffer, header.datasize());
if (blob.ParseFromArray(buffer, header.datasize()) == false) {
cerr << "cOsmBlob: unable to read Blob" << endl;
delete[] buffer;
throw exception();
}
delete[] buffer;
if (header.type() == "OSMHeader") {
this->type = OSM_HEADER;
}
else if (header.type() == "OSMData") {
this->type = OSM_DATA;
}
else {
cerr << "cOsmBlob: Unknown BlobHeader type" << endl;
throw exception();
}
/* extract data */
this->size = 0;
this->rawdata = NULL;
if (blob.has_raw() == true) {
this->rawdata = new char[blob.raw().length()];
memcpy(this->rawdata, blob.raw().data(), blob.raw().length());
this->size = blob.raw().length();
}
else if (blob.has_zlib_data() == true) {
z_stream zlibStream;
this->rawdata = new char[blob.raw_size()];
zlibStream.next_in =
(Bytef*)const_cast<char*>(blob.zlib_data().data());
zlibStream.avail_in = blob.zlib_data().size();
zlibStream.next_out = (Bytef*)this->rawdata;
zlibStream.avail_out = blob.raw_size();
zlibStream.zalloc = Z_NULL;
zlibStream.zfree = Z_NULL;
zlibStream.opaque = Z_NULL;
if (inflateInit(&zlibStream) != Z_OK) {
cerr << "cOsmBlob: " <<
"Unknown or unsupported ZLib version of blob's data" <<
endl;
delete[] buffer;
throw exception();
}
retval = inflate(&zlibStream, Z_FINISH);
if (retval != Z_OK && retval != Z_STREAM_END) {
cerr << "cOsmBlob: Unable to decompress blob's data" << endl;
delete[] buffer;
throw exception();
}
if (inflateEnd(&zlibStream) != Z_OK) {
cerr << "cOsmBlob: " <<
"Unable to finalize decompression of blob's data" << endl;
delete[] buffer;
throw exception();
}
this->size = blob.raw_size();
}
}
cOsmBlob::~cOsmBlob(void) {
if (this->rawdata != NULL)
delete[] this->rawdata;
this->rawdata = NULL;
}
从你的评论来看,你的课似乎违反了三原则。
由于将类的实例存储在容器中,这涉及到复制它们。如果没有自定义复制构造函数和赋值操作符,则使用编译器生成的构造函数和赋值操作符。后者将只获取buffer
指针的副本。当原始对象超出作用域时,它的缓冲区是delete[]
d,给副本留下一个悬空指针。当复制超出作用域时,它将尝试再次delete[]
相同的指针,导致您看到的错误。
需要提供复制构造函数和复制赋值操作符
相关文章:
- 为什么通过 vector<reference_wrapper> 的元素删除引用的值<T>不会使向量无效?
- 在加载 MSHTML 文档之前从 MSHTML 文档中删除无效的 URL
- 删除无效地址时C++引发异常
- 无效删除运算符语法
- 在循环内删除文件时使提升recursive_directory_iterator无效
- 结构sqlite3的sqlite3c++正向声明导致析构函数中删除时出现无效指针错误
- 删除指向类的指针无效
- 为什么删除指向指针向量的指针会导致指针无效
- 模板化的出列无效指针:删除类时失败
- 删除指向派生类的指针时,为RtlValidateHeap指定的地址无效
- 为什么Boost图库在删除顶点时会使所有迭代器无效
- 类型为 std::String&- 的非常量引用的初始化无效 - 如何删除
- C++ 瓦尔格林德无效删除动态数组
- 删除与运算符删除(和无效指针)
- 瓦尔格林德报告无效免费/删除/ realloc
- 删除文件的内容无效
- 删除时指针崩溃无效,但指针不同
- 删除[]指针数组无效
- 使用zLib删除无效
- 删除行时,QModelIndex无效