【问题标题】:Getting bad_alloc on specific inputs while using C++ strings使用 C++ 字符串时在特定输入上获取 bad_alloc
【发布时间】:2017-03-11 13:22:33
【问题描述】:

我正在尝试创建一个基本程序来为我的网络类实现汉明代码

该程序在大多数情况下都能正常运行,但在某些特定情况下它会因-1073741819 而中断

程序将一串'0'和'1'作为输入

当输入字符串的长度为odd number ^ 2 形式时,会出现错误,给出-1073741819 std::bad_alloc

所有其他情况似乎都有效
示例输入 8 个有效,10 个有效,但 9 个无效。
同样长度为 24 的输入有效,26 有效,但 25 无效

下面是代码
它包括一些不会给出错误的代码,并且我已经标记了无关部分何时开始。

#include<iostream>
#include<cmath>
#include<vector>

using namespace std;

int main(){

string data;
cout<<"Enter data to send => :\n";
cin>>data;

int len = data.length();
int maxPowerOfTwo = log2(len-1) + 1;
int totalLength = len +  maxPowerOfTwo + 1;

vector< int > toSend;
toSend.reserve(totalLength);
toSend[0] = 0;

int l = 0;
int k = 0;

for(int i=0;i<totalLength+1;i++){
    if(l==i){
        toSend[i] = 0;
        if(l==0){
            l++;
        }
        else{
            l*=2;
        }
    }
    else{
        toSend[i] = data[k]-48;
        k++;
    }
}

int currentPower = 0;
int startPosition = 1;

for(;currentPower<maxPowerOfTwo+1;currentPower++){
    int tempSum = 0;
    int tempCounter = 0;
    for(int currentPosition = startPosition;currentPosition<totalLength+1;){
        tempSum = tempSum + toSend[currentPosition];
        tempCounter++;
        if(tempCounter==startPosition){
            currentPosition += startPosition + 1;
            tempCounter = 0;
        }
        else{
            currentPosition++;
        }
    }
    if(tempSum%2!=0){
        toSend[startPosition] = 1;
    }
    else{
        toSend[startPosition] = 0;
    }
    startPosition*=2;
}
string finaltoSend;

for(int i=1;i<=totalLength;i++){ // MARKED LOOP
    if(toSend[i]==0){
        finaltoSend.push_back('0');
    }
    else{
        finaltoSend.push_back('1');
    }
}

/*
==== NOT RELEVANT ====

cout<<"\nData to send => "<<finaltoSend<<'\n';
string received = finaltoSend;
cout<<"\nEnter data received of length "<<totalLength<<'\n';
cin>>received;
int t_len = received.length();
int t_maxPowerOfTwo = log2(t_len-1);
int t_currentPower = 0;
int t_startPosition = 1;
int errorAt = -1;
for(;t_currentPower<t_maxPowerOfTwo+1;t_currentPower++){
    int tempSum = 0;
    int tempCounter = 0;
    for(int currentPosition = t_startPosition;currentPosition<t_len+1;){
        tempSum = tempSum + received[currentPosition-1] - 48;
        tempCounter++;
        if(tempCounter==t_startPosition){
            currentPosition += t_startPosition + 1;
            tempCounter = 0;
        }
        else{
            currentPosition++;
        }
    }
    if(tempSum%2!=0){
        errorAt+=t_startPosition;
    }
    t_startPosition*=2;
}
if(errorAt == -1){
    cout<<"\nNo error";
}
else{
    errorAt++;
    cout<<"\n\nError at \n\n"<<errorAt;
}

==== END ====
*/

return 0;
}

在使用标志和基本调试(打印我所在的位置)进行调试时,我发现程序在标记循环的第二次迭代中中断

**调试时new_allocator.h打开指向 void deallocate(pointer __p, size_type){ ::operator delete(__p); }在程序结束时

我试过了 finaltoSend.append("0") 并且还预先保留了内存,但没有一个选项起作用

任何提示将不胜感激

【问题讨论】:

  • 您会根据目前的观察推测 odd 尺寸似乎会呕吐吗?也许在调试器中使用你知道的测试值运行它,看看事情进展如何,特别是 maxPowerOfTwo 和依赖 totalLength 的计算。
  • @WhozCraig 不仅奇数平方会引发错误。用调试器试过。在调试期间,最后在new_allocator.h 中被void deallocate(pointer __p, size_type) { ::operator delete(__p); } 阻塞
  • 在调试过程中,您对我之前评论的最后一句话有何评价? (在失败的情况下,totalLengthmaxPowerOfTwo 的值与您的预期有何不同?或者是吗?)。您与 reserveresize 工作方式的脱节也是一个相关问题,并在下面的答案中提到。这显然需要解决。

标签: c++ string c++11 memory-management dynamic-memory-allocation


【解决方案1】:

您的代码中实际上有 两个 错误。

第一个是你只为元素保留内存,而不是让它们存在。

这不太可能是您看到的行为的原因(为什么您在技术上写入未使用的内存,该内存不能被其他东西使用,但是当您进一步使用您的向量时,这是一个等待发生的潜在错误;也是因为 @ 987654321@s 是 POD,它们不需要构造函数来调用,因此您不会看到由于未初始化的对象而导致的问题,如果您对其他对象的向量使用相同的错误方法,情况会发生变化。

要真正实现这些整数,请使用resize 而不是reserve

第二个错误是你甚至超出了保留的内存:你为 totalLength 元素保留空间,但随后写入 totalLength+1 元素。最后一个元素写入超出保留空间,并且不太可能覆盖内部用于内存管理的实际数据。给出的错误消息很可能是发生了什么。

请注意,这是黑客用来访问计算机系统的错误类型,方法是找出该位置之外的内容,并通过特制输入将其替换为恶意内容。因此,请认为自己很幸运,您的代码立即显示了问题。

【讨论】:

    【解决方案2】:
    vector< int > toSend;
    toSend.reserve(totalLength);
    
    //...
    
    for(int i=0;i<totalLength+1;i++){
      // Say...what? --------^
      toSend[i] = // different values on the two branches
    

    超出保留长度?

    尝试使用

      toSend.at(i)= // whatever
    

    看看应用程序在运行时会告诉你什么。 (提示:查看atoperator [] 在边界检查方面的区别)。

    (另请参阅why doesn't my program crash when I write past the end of an array? 提示:您可能会损坏您的记忆并在很久以后经历崩溃:请参阅优秀的'fandango on core)。

    【讨论】:

    • 还要注意OP只保留了位置。向量中仍然没有元素,所以即使 toSend[0] 也是 UB。
    • 确实如此。 toSend.at(i) 会在0 咳嗽。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-05-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多