当大小太大时,vector.resize 函数会损坏内存

2024-01-11

发生的情况是我正在读取加密数据包,并且遇到一个损坏的数据包,该数据包返回一个非常大的长度随机数。

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。我尝试将此代码放在调用调整大小之前:

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)。

另外,我还没有确定 resize 抛出了什么异常。它不是 std::length_error 也不是 std::bad_alloc。它抛出的异常对我来说确实不太重要,但我很想知道。

顺便说一句,只是让你知道,这段代码在正常情况下确实可以正常工作。这种数据包损坏的情况是唯一让人疯狂的地方。请帮忙!谢谢。

UPDATE:

@迈克尔。现在,如果数据包大于 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 机器上构建并运行它时,调整大小将引发 std::bad_alloc 异常,并且向量不会被损坏,正如我们所期望的那样!是时候来看看 EA Sport NCAA 橄榄球了嘿嘿!


我觉得vector::max_size()几乎总是一个“硬编码”的东西 - 它独立于系统/库准备动态分配多少内存。您的问题似乎是矢量实现中的一个错误,当分配失败时,该错误会破坏事物。

“bug”这个词可能太重了。vector::resize()定义为vector::insert()标准是这样说的vector::insert():

如果除了 T 的复制构造函数或赋值运算符之外抛出异常,则不会产生任何影响

所以看来有时可能resize()操作被允许破坏向量,但如果该操作是异常安全的,那就太好了(我认为期望库这样做不会出格,但也许比我想象的更难)。

您似乎有几个合理的选择:

  • 更改或更新到没有损坏错误的库(您使用什么编译器/库版本?)
  • 而不是检查vector::max_size() set nMaxSize达到您自己合理的最大值,并执行上述操作,但使用该阈值。

Edit:

我发现你正在使用 VC6 - 肯定有一个错误vector::resize()这可能与你的问题有关,尽管查看补丁我真的不明白如何(实际上这是一个错误)vector::insert(),但正如前面提到的,resize() calls insert())。我想这是值得一去的Dinkumwares 的 VC6 错误修复页面 http://www.dinkumware.com/vc_fixes.html并应用修复程序。

该问题也可能与<xmemory>该页面上的补丁 - 目前尚不清楚那里讨论的错误是什么,但是vector::insert()确实打电话_Destroy() and vector<>确实定义了名称_Ty所以你可能会遇到这个问题。一件好事 - 您不必担心管理标头的更改,因为 Microsoft 再也不会触及它们。只需确保补丁进入版本控制并记录下来即可。

请注意,Scott Meyers 在“Effective STL”中建议使用SGI's http://www.sgi.com/tech/stl/download.html or STL端口的 http://www.stlport.org/库以获得比 VC6 附带的更好的 STL 支持。我还没有这样做,所以我不确定这些库的工作效果如何(但我也没有经常使用 VC6 和 STL)。当然,如果您可以选择迁移到较新版本的 VC,请务必这样做。


另一项编辑:

谢谢你的测试程序...

VC6's _Allocate()默认分配器的实现(在<xmemory>)使用有符号 int 来指定要分配的元素数量,如果传入的大小为负数(这显然是您正在做的事情 - 当然是在您所在的测试程序中)_Allocate()函数将请求的分配大小强制为零并继续。请注意,零大小的分配请求几乎总是会成功(并非如此)vector无论如何都会检查失败),所以vector::resize()函数愉快地尝试将其内容移动到新块中,至少可以说,新块还不够大。因此堆被损坏,它可能会遇到无效的内存页,无论如何 - 你的程序被破坏了。

所以底线是永远不要要求 VC6 分配超过INT_MAX一次性对象。在大多数情况下(VC6 或其他)可能不是一个好主意。

另外,您应该记住,VC6 使用了从以下位置返回 0 的前标准习惯用法:new当分配失败而不是抛出时bad_alloc.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

当大小太大时,vector.resize 函数会损坏内存 的相关文章

随机推荐

  • 尝试在 Google App Engine 上部署 node.js 时出错

    我在尝试部署时遇到错误Node js应用程序到 Google App Engine Node js运行时因 require 语句而崩溃 我有什么错吗 目录结构 app 协议 js应用程序 js 在文件 app js 中 var protoc
  • 如何以编程方式获取 iPhone 的 MAC 地址

    如何以编程方式获取 iPhone 的 MAC 地址和 IP 地址 NOTE从 iOS7 开始 您无法再检索设备 MAC 地址 将返回一个固定值而不是实际的 MAC 我不久前偶然发现的一件事 最初是从here http www iphoned
  • 我该如何解决此推送错误 - 从身份验证端点返回的 JSON 无效,但状态代码为 200?

    在这里问同样的问题后我仍然遇到这个问题 从 auth 端点返回的 JSON 无效 但状态代码为 200 https stackoverflow com questions 67082279 json returned from auth e
  • 如何仅从一列中选择不同的值

    我有记录如下 key name 1111 aa 1111 bb 2222 cc 我需要选择key and name当 的时候key价值是独特的 当我尝试时 select distinct key name from table 我得到了所有
  • 在c++中将hdf5文件读取到动态数组

    由于堆栈的大小限制 我正在尝试将大型 3D hdf5 文件读入动态数组 我尝试了几种不同的方法 但由于分段错误而失败 下面是显示我的问题的示例代码 我非常感谢一些帮助 This example was based on several ex
  • RestTemplateBuilder bean

    我的应用程序与不同的休息端点交互 每个端点都需要一个专门的 RestTemplate 对象 我正在使用 RestTemplateBuilder 创建每个 RestTemplate 对象 克隆 Spring Boot 提供的 RestTemp
  • AngularJS module.constant() :如何仅在模块内定义常量?

    在一个页面上 我有几个 Angular 模块 对于每个模块 我定义一个包含模块版本的常量 var module1 angular module module1 constant version 1 2 3 var module2 angul
  • 如何在 C++ 中维护指向父级的弱指针?

    是否有一种标准方法可以在 C 的子对象中维护指向父对象 使用共享指针创建 的弱指针 本质上 我需要实现以下内容 Class B Class A private B m b Class B public void SetParentPtr c
  • 正常关闭 IHostedService

    我正在尝试在 NET Core 中开发一个简单的 API 允许异步处理请求 请求发送至控制器 后台服务 IHostedService 上安排的工作 控制器返回 202 后台服务执行长时间运行的操作 由于应用程序将在 IIS 上运行 因此控制
  • 成员函数模板放在哪里

    C 中经常让我感到沮丧的一个方面是决定模板在头文件 传统上描述接口 和实现 cpp 文件之间的位置 模板通常需要进入标头 公开实现 有时还需要引入以前只需要包含在 cpp 文件中的额外标头 我最近再次遇到这个问题 下面显示了一个简化的示例
  • 如何在android中现有的html内容附加附加文本?

    我正在开发一个应用程序 在其中我将文本附加到存储在 html 文件中的现有文本 html 文件的位置位于我的应用程序的 assets 文件夹中 我知道如何使用 URL 加载 html 但我的问题是附加文本 以下是我的java代码 publi
  • Servlet 3.0 注销不起作用

    我对 Servlet 3 0 的身份验证功能有疑问 在 Servlet v3 中使用此代码 log info request getUserPrincipal log info request getAuthType log info re
  • Laravel 5.3WhereIn 返回唯一结果

    我在这个地方遇到问题 我的代码看起来像这样 arrayKeys 1 2 1 4 5 1 products App Product whereIn id arrayKeys gt select id name outright price d
  • 为 ifeq 出错:意外标记附近出现语法错误

    我正在编写一个在一个地方进行字符串匹配的 Makefile 代码如下 if test then shell scripts fi ifeq DIST TYPE nightly shell scripts endif 这里是第一个if第二个是
  • Access Services 和 SharePoint 2010 - 需要信息

    我被要求研究将 Access 解决方案直接发布到 SharePoint 的能力 如下面的演示所示 http channel9 msdn com shows Access Microsoft Access 2010 Demo http cha
  • 如何设置标题栏的背景?

    我已按照此问题的说明进行操作 如何更改操作栏上的文本 https stackoverflow com questions 3438276 change title bar text in android 我能够成功创建自己的标题栏 但是当我
  • facebook django 应用程序的 oauth 中的 redirect_uri 错误

    我在从 Facebook 获取我正在尝试编写的 Django 应用程序的访问令牌时遇到问题 我的视图设置如下 from django http import HttpResponse HttpResponseRedirect from dj
  • 在 ScalaTest 中对集合元素使用 HavePropertyMatcher?

    我已经使用 ScalaTest 的 FeatureSpec 有几天了 我试图了解是否可以使用内置匹配器定义以下规范 如果不能 我如何编写合适的自定义匹配器 假设我有课本 case class Book val title String va
  • GPC 多边形初始化

    我正在使用 GPC多边形裁剪库 http www cs man ac uk toby alan software并想以编程方式创建多边形 我只看到如何从文件创建一个的代码 如何在我的代码中进行初始化 从您的链接中更好地阅读 找到doc ht
  • 当大小太大时,vector.resize 函数会损坏内存

    发生的情况是我正在读取加密数据包 并且遇到一个损坏的数据包 该数据包返回一个非常大的长度随机数 size t nLengthRemaining packet nLength packet m pSource gt GetPosition p