size_t nLengthRemaining = packet.nLength - (packet.m_pSource->GetPosition() - packet.nDataOffset); seckey.SecretValues.m_data.resize(nLengthRemaining);
在这段代码中,m_data是一个std :: vector< unsigned char>. nLengthRemaining由于数据包损坏而过大,因此抛出调整大小函数.问题不在于调整大小(我们处理异常),但调整大小已经损坏了内存,这会导致更多异常.
我想要做的是在调用resize之前知道长度是否太长,然后只有调用resize才可以.我已经尝试在调用resize之前放入此代码:
std::vector<unsigned char>::size_type nMaxSize = seckey.SecretValues.m_data.max_size(); if(seckey.SecretValues.m_data.size() + nLengthRemaining >= nMaxSize) { throw IHPGP::PgpException("corrupted packet: length too big."); } seckey.SecretValues.m_data.resize(nLengthRemaining);
此代码使用std :: vector max_size成员函数来测试nLengthRemaining是否更大.但这肯定不可靠,因为nLengthRemaining仍然小于nMaxSize,但显然仍然足以导致调整大小出现问题(nMaxSize为4xxxxxxxxx且nLengthRemaining为3xxxxxxxxx).
另外,我还没有确定调整大小的异常.它不是std :: length_error,它不是std :: bad_alloc.真正抛出的例外对我来说并不重要,但我很想知道.
顺便说一句,您知道,这段代码在正常情况下可以正常工作.这种损坏数据包的情况是它疯狂的唯一地方.请帮忙!谢谢.
更新:
@迈克尔.现在,如果数据包大于5 MB,我将忽略该数据包.我将与其他团队成员讨论可能验证数据包的问题(它可能已存在,我只是不知道它).我开始认为它确实是我们的STL版本中的一个错误,它抛出的异常甚至不是std :: exception,这让我很惊讶.我将尝试从我的主管那里找出我们正在运行的STL版本(我将如何检查?).
另一个更新:
我只是证明它是我在Visual Studio 6开发机器上使用的STL版本中的一个错误.我写了这个示例应用程序:
// VectorMaxSize.cpp:定义控制台应用程序的入口点.
//
#include "stdafx.h" #include <vector> #include <iostream> #include <math.h> #include <typeinfo> typedef std::vector<unsigned char> vector_unsigned_char; void fill(vector_unsigned_char& v) { for (int i=0; i<100; i++) v.push_back(i); } void oput(vector_unsigned_char& v) { std::cout << "size: " << v.size() << std::endl; std::cout << "capacity: " << v.capacity() << std::endl; std::cout << "max_size: " << v.max_size() << std::endl << std::endl; } void main(int argc,char* argv[]) { { vector_unsigned_char v; fill(v); try{ v.resize(static_cast<size_t>(3555555555)); }catch(std::bad_alloc&) { std::cout << "caught bad alloc exception" << std::endl; }catch(const std::exception& x) { std::cerr << typeid(x).name() << std::endl; }catch(...) { std::cerr << "unknown exception" << std::endl; } oput(v); v.reserve(500); oput(v); v.resize(500); oput(v); } std::cout << "done" << std::endl; }
在我的VS6开发机器上它具有与加密项目相同的行为,它会造成各种破坏.当我在我的Visual Studio 2008机器上构建并运行它时,resize将抛出一个std :: bad_alloc异常,并且矢量不会被破坏,就像我们预期的那样!一些EA体育NCAA足球的时间嘿嘿!
解决方法
“臭虫”可能过于强硬. vector :: resize()是根据vector :: insert()定义的,标准说的是关于vector :: insert():
If an exception is thrown other than by the copy constructor or assignment operator of T there are no effects
所以似乎有时候允许resize()操作来破坏一个向量,但是如果操作是异常安全的话它仍然会很好(我认为期望这个库不会出错.这样做,但也许它比我想象的更难).
你似乎有几个合理的选择:
>更改或更新到没有损坏错误的库(您使用的是哪个编译器/库版本?)
>而不是检查vector :: max_size()将nMaxSize设置为您自己的合理最大值并执行上面的操作,而是使用该阈值.
编辑:
我看到你正在使用VC6 – 在vector :: resize()中肯定存在一个可能与你的问题有关的错误,虽然看着补丁我老实说看不出来(实际上它是向量中的错误: :insert(),但如上所述,resize()调用insert()).我想有必要访问Dinkumwares’ page for bug fixes to VC6并应用修复程序.
这个问题也可能与< xmemory>有关.该页面上的补丁 – 目前还不清楚那里讨论的是什么错误,但是vector :: insert()确实调用_Destroy()和vector<>确定名称_Ty,以便您可能遇到该问题.一件好事 – 您不必担心管理标题的更改,因为Microsoft从未再次触及它们.只需确保补丁使其成为版本控制并记录下来.
请注意,“有效STL”中的Scott Meyers建议使用SGI’s或STLPort’s库来获得比VC6更好的STL支持.我还没有这样做,所以我不确定这些库是如何工作的(但我也没有将VC6与STL一起使用).当然,如果您可以选择转移到较新版本的VC,请务必执行此操作.
还有一个编辑:
感谢您的测试计划……
VC6的默认分配器的_Allocate()实现(在< xmemory>中)使用signed int来指定要分配的元素数,如果传入的大小是负数(这显然是你正在做的 – 当然在你是测试程序)_Allocate()函数强制请求的分配大小为零并继续.请注意,零大小的分配请求几乎总是成功(不管该向量是否检查失败),因此vector :: resize()函数会愉快地尝试将其内容移动到新块中,这个块不是很大至少可以说.所以堆被破坏了,它可能会打到一个无效的内存页面,而且无论如何 – 你的程序被清除了.
因此,底线是不要求VC6一次性分配多个INT_MAX对象.在大多数情况下(VC6或其他情况)可能不是一个好主意.
此外,您应该记住,当分配失败而不是抛出bad_alloc时,VC6使用从new返回0的预标准习惯用法.