微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

c – vector.resize函数在大小太大时破坏内存

发生的事情是我正在读取加密数据包,我遇到一个损坏的数据包,它会返回一个非常大的随机数.
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 :: max_size()几乎总是一个“硬编码”的东西 – 它与系统/库准备动态分配的内存量无关.您的问题似乎是矢量实现中的一个错误,当分配失败时会破坏事物.

“臭虫”可能过于强硬. 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’sSTLPort’s库来获得比VC6更好的STL支持.我还没有这样做,所以我不确定这些库是如何工作的(但我也没有将VC6与STL一起使用).当然,如果您可以选择转移到较新版本的VC,请务必执行此操作.

还有一个编辑:

感谢您的测试计划……

VC6的认分配器的_Allocate()实现(在< xmemory>中)使用signed int来指定要分配的元素数,如果传入的大小是负数(这显然是你正在做的 – 当然在你是测试程序)_Allocate()函数强制请求的分配大小为零并继续.请注意,零大小的分配请求几乎总是成功(不管该向量是否检查失败),因此vector :: resize()函数会愉快地尝试将其内容移动到新块中,这个块不是很大至少可以说.所以堆被破坏了,它可能会打到一个无效的内存页面,而且无论如何 – 你的程序被清除了.

因此,底线是不要求VC6一次性分配多个INT_MAX对象.在大多数情况下(VC6或其他情况)可能不是一个好主意.

此外,您应该记住,当分配失败而不是抛出bad_alloc时,VC6使用从new返回0的预标准习惯用法.

原文地址:https://www.jb51.cc/c/116179.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐