离开 c++ 时程序崩溃 功能....你认为它是什么?

发布于 2024-07-30 08:33:20 字数 5532 浏览 3 评论 0原文

我有一个c++代码,我使用MSC9来编译它。 它总是随机崩溃。 例如,如果使用 `` 从 Perl 调用它,它会崩溃,但从命令行或 Ultimate++ 调用它时,它不会崩溃。

我的意思是从 Perl 调用它,例如。 f.exe arg1 arg2 arg3

堆栈跟踪没有显示太多内容。 逐行跟踪程序证明,程序在返回时最后失败了...

所以就像

int funcname()
{
    return 0; <-- crashing after that...
}

我猜测堆栈已损坏,堆栈展开后,它崩溃了..

会导致什么原因? 该程序使用 PCRE、STL 和迭代器。 迭代器可以破坏堆栈吗? 你会如何捕获这样的错误?

这可能是编译器错误吗?

注意:调试版本不会崩溃,只有发布版本才会崩溃...

该错误似乎与此 pvector 类有关。

我有一个与此类似的结构:

struct complexstr
{
 pvector<int> v;
 string v2;
 hash_map<string> hm;
 vector<string> vs; // similar
 int i;
};

它似乎失败了,因为这一行:

complexstr s1;
complexstr s2;

s2=s1; // it seems to fail here, if this is not there... there is no error.

我认为问题在于下面的类...... std::copy 在 pvector operator=(const pvector &pv) 中是正确的,对吗?

pvector 是一个 perl 兼容的向量...它的索引可以大于向量的分配大小。

更新1: 我收到了作业中存在漏洞的建议。 我改变了任务... 这就是它现在的样子:

 pvector& operator=(const pvector &pv)
  {
    delete [] m_rgArray;  
    m_rgArray=new value_type[pv.allocated];
    m_nIndex=pv.m_nIndex;
    allocated=pv.allocated;
    std::copy(pv.m_rgArray, pv.m_rgArray + pv.allocated, m_rgArray);  
    return *this;
  }

注意:通过添加 & 到返回类型,崩溃依然存在。 不过去掉泄漏后,加上delete[] m_rgArray; , 程序不再崩溃。 我不明白。 据我所知有泄漏 不会造成崩溃。 那么问题似乎已经解决了(?)。 问号显示了我的惊讶。 更新2: 这不,问题又回来了。 它只是消失了一段时间。 Update3:我想我已经找到了。 我使用 Microsoft 调试工具中名为 gflags.exe 和 Windbg.exe 的实用程序来查找确切位置。 我使用 gflags.exe /p /enable myprog.exe /full 来打开堆错误的异常。 目前,我认为该错误是由 FindClose(handle); 引起的。 其中句柄是一个随机值,未初始化。

旧版本:

 template<class _Ty>
  class pvector
  {
    public:
    _Ty * m_rgArray; // Declare array
    int m_nIndex; // Index to array
    int allocated;
    _Ty undefvalue;
    typedef _Ty value_type;
    typedef value_type & reference;
    typedef const value_type & const_reference;
    typedef custom_iterator<_Ty> iterator;
    typedef custom_iterator<_Ty> const_iterator;
    typedef int difference_type;
    typedef int size_type;
    //typedef typename pvector_type_traits<_Ty>::default_value default_value;

    pvector() : m_nIndex(0) 
    { // init index to 0
      m_rgArray = new value_type[10];
      allocated = 10;
      fill(0);
    }

    pvector(size_type s) : m_nIndex(0) 
    { // init index to 0
      size_type defsize = 10;
      if (s>10)
      {
        defsize = s;
      }
      m_rgArray = new value_type[defsize];
      allocated = defsize;
      fill(0);
    }
      pvector(pvector const& pv)
    : m_rgArray(new value_type[pv.allocated]),
    m_nIndex(pv.m_nIndex),allocated(pv.allocated)
    {
     std::copy(pv.m_rgArray, pv.m_rgArray + pv.allocated, m_rgArray);     
    }

    pvector operator=(const pvector &pv)
    {
    m_rgArray=new value_type[pv.allocated];
    m_nIndex=pv.m_nIndex;
    allocated=pv.allocated;
    std::copy(pv.m_rgArray, pv.m_rgArray + pv.allocated, m_rgArray);  
    return *this;
    }
    void clear()
    {
       m_nIndex=0; 
       fill(allocated);    
    }

    ~pvector() {
     delete []m_rgArray; 
    }

    size_type size() const
    { // return length of sequence
      return m_nIndex;
    }

    size_type max_size() const
    { // return maximum possible length of sequence
      return 0;
    }

    void fill(size_type si)
    {
      for (size_type i = si;i<allocated;i ++ )
      {
        m_rgArray[i] = pvector_type_traits<_Ty>::default_value();
      }
    }

    bool empty() const
    { // test if sequence is empty
      return (m_nIndex > 0 ? false : true);
    }

    iterator begin()
    { // return iterator for beginning of mutable sequence
      return iterator(&m_rgArray[0]);
    }

    const_iterator begin() const
    {
      return const_iterator(&m_rgArray[0]); 
    }

    iterator end()
    { // return iterator for end of mutable sequence
      return iterator(&m_rgArray[m_nIndex]);
    }

    const_iterator end() const
    {
      return const_iterator(&m_rgArray[m_nIndex]);
    }
    reference operator[](size_type i)
    {
      if (m_nIndex>i)
      {
        return m_rgArray[i];
      }
      else if (i >= allocated)
        {
          resize(i * 2);
        }
        m_nIndex = i + 1;
      return m_rgArray[i];
    } 
    void resize(size_type s)
    {
      value_type * m_rgArray2;
      size_type old_allocated = allocated;
      allocated = s;
      m_rgArray2 = new value_type[allocated];
        //if (allocated>m_nIndex)
        //{
        // m_nIndex=allocated;
       // }
       // cout <<"m_nIndex" << m_nIndex << "allocated" << allocated << endl;
      if (m_nIndex>allocated)
      {
        m_nIndex=allocated;
      }
      for (size_type i = 0;i<m_nIndex;i ++ )
      {
        m_rgArray2[i] = m_rgArray[i];
      }
      delete []m_rgArray;
      m_rgArray = m_rgArray2;
      fill(old_allocated);
    }

    reference back()
    {
      return &m_rgArray[m_nIndex - 1]; 
    }

    const_reference back() const
    {
      return m_rgArray[m_nIndex - 1]; 
    }

    void push_back(const _Ty &_Val)
    { // insert element at end
      if (size() < allocated)
        m_rgArray[m_nIndex ++ ] = _Val;
      else
        {
        resize(allocated * 2);
        m_rgArray[m_nIndex ++ ] = _Val; 
      }
    }

  };

I have a c++ code, I use MSC9 to compile it.
It keeps crashing randomly. For example it crashes if it is called from Perl using `` but it does not crash when It is called from command line or from Ultimate++.

I mean calling it from perl eg. f.exe arg1 arg2 arg3

Stack trace does not show much. Tracing the program line by line proved that the program fails at the end when returning...

So it is like that

int funcname()
{
    return 0; <-- crashing after that...
}

I guess the stack is damaged, and after the stack is unwound, it crashes..

What can cause it?
The program uses pcre, stl and iterators. Can an iterator break the stack?
How would you catch an error like that?

Can it be a compiler bug?

Note: the debug version does not crash, only the release version...

The bug seems to be related this pvector class.

I have a struct similar to this:

struct complexstr
{
 pvector<int> v;
 string v2;
 hash_map<string> hm;
 vector<string> vs; // similar
 int i;
};

It seems to fail because this line:

complexstr s1;
complexstr s2;

s2=s1; // it seems to fail here, if this is not there... there is no error.

I think the problem is with the class below...
std::copy is correct in pvector operator=(const pvector &pv), right?

pvector is a perl compatible vector... Its indexes can be larger than allocated size of the vector.

Update1:
I received suggestions that there is a leak in the assignment.
I changed the assignment...
That is how it looks now:

 pvector& operator=(const pvector &pv)
  {
    delete [] m_rgArray;  
    m_rgArray=new value_type[pv.allocated];
    m_nIndex=pv.m_nIndex;
    allocated=pv.allocated;
    std::copy(pv.m_rgArray, pv.m_rgArray + pv.allocated, m_rgArray);  
    return *this;
  }

Note: by adding & to the return type, the crash still remained.
However, after removing the leak, adding delete [] m_rgArray; ,
the program no longer crashes. I do not understand. As far as I know leaks
do not cause crashes. So the problem seems to be solved(?). The question mark shows my surprise.
Update2:
No, the problem came back. It just disappeared for a while.
Update3: I think I have found it. I used an utility from Microsoft debugging tools called gflags.exe and windbg.exe to find the exact location.
I used gflags.exe /p /enable myprog.exe /full to turn on exceptions for heap bugs..
At the moment, I think the bug was caused by FindClose(handle); where handle was a random value, not initialiased.

Old version:

 template<class _Ty>
  class pvector
  {
    public:
    _Ty * m_rgArray; // Declare array
    int m_nIndex; // Index to array
    int allocated;
    _Ty undefvalue;
    typedef _Ty value_type;
    typedef value_type & reference;
    typedef const value_type & const_reference;
    typedef custom_iterator<_Ty> iterator;
    typedef custom_iterator<_Ty> const_iterator;
    typedef int difference_type;
    typedef int size_type;
    //typedef typename pvector_type_traits<_Ty>::default_value default_value;

    pvector() : m_nIndex(0) 
    { // init index to 0
      m_rgArray = new value_type[10];
      allocated = 10;
      fill(0);
    }

    pvector(size_type s) : m_nIndex(0) 
    { // init index to 0
      size_type defsize = 10;
      if (s>10)
      {
        defsize = s;
      }
      m_rgArray = new value_type[defsize];
      allocated = defsize;
      fill(0);
    }
      pvector(pvector const& pv)
    : m_rgArray(new value_type[pv.allocated]),
    m_nIndex(pv.m_nIndex),allocated(pv.allocated)
    {
     std::copy(pv.m_rgArray, pv.m_rgArray + pv.allocated, m_rgArray);     
    }

    pvector operator=(const pvector &pv)
    {
    m_rgArray=new value_type[pv.allocated];
    m_nIndex=pv.m_nIndex;
    allocated=pv.allocated;
    std::copy(pv.m_rgArray, pv.m_rgArray + pv.allocated, m_rgArray);  
    return *this;
    }
    void clear()
    {
       m_nIndex=0; 
       fill(allocated);    
    }

    ~pvector() {
     delete []m_rgArray; 
    }

    size_type size() const
    { // return length of sequence
      return m_nIndex;
    }

    size_type max_size() const
    { // return maximum possible length of sequence
      return 0;
    }

    void fill(size_type si)
    {
      for (size_type i = si;i<allocated;i ++ )
      {
        m_rgArray[i] = pvector_type_traits<_Ty>::default_value();
      }
    }

    bool empty() const
    { // test if sequence is empty
      return (m_nIndex > 0 ? false : true);
    }

    iterator begin()
    { // return iterator for beginning of mutable sequence
      return iterator(&m_rgArray[0]);
    }

    const_iterator begin() const
    {
      return const_iterator(&m_rgArray[0]); 
    }

    iterator end()
    { // return iterator for end of mutable sequence
      return iterator(&m_rgArray[m_nIndex]);
    }

    const_iterator end() const
    {
      return const_iterator(&m_rgArray[m_nIndex]);
    }
    reference operator[](size_type i)
    {
      if (m_nIndex>i)
      {
        return m_rgArray[i];
      }
      else if (i >= allocated)
        {
          resize(i * 2);
        }
        m_nIndex = i + 1;
      return m_rgArray[i];
    } 
    void resize(size_type s)
    {
      value_type * m_rgArray2;
      size_type old_allocated = allocated;
      allocated = s;
      m_rgArray2 = new value_type[allocated];
        //if (allocated>m_nIndex)
        //{
        // m_nIndex=allocated;
       // }
       // cout <<"m_nIndex" << m_nIndex << "allocated" << allocated << endl;
      if (m_nIndex>allocated)
      {
        m_nIndex=allocated;
      }
      for (size_type i = 0;i<m_nIndex;i ++ )
      {
        m_rgArray2[i] = m_rgArray[i];
      }
      delete []m_rgArray;
      m_rgArray = m_rgArray2;
      fill(old_allocated);
    }

    reference back()
    {
      return &m_rgArray[m_nIndex - 1]; 
    }

    const_reference back() const
    {
      return m_rgArray[m_nIndex - 1]; 
    }

    void push_back(const _Ty &_Val)
    { // insert element at end
      if (size() < allocated)
        m_rgArray[m_nIndex ++ ] = _Val;
      else
        {
        resize(allocated * 2);
        m_rgArray[m_nIndex ++ ] = _Val; 
      }
    }

  };

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(11

人间☆小暴躁 2024-08-06 08:33:20

这可能是缓冲区溢出导致堆栈损坏。 如果在运行函数时在本地定义的缓冲区之外进行写入,则它可以覆盖返回地址,然后从函数返回将触发程序崩溃。

您应该查找使用本地(堆栈分配)变量地址进行操作的语句 - 它们的缓冲区溢出很可能是问题的原因。

It can be a buffer overrun corrupting the stack. If while running the function writes outside the locally defined buffers it can overwrite the return address and then returning from the function will trigger a program crash.

You should look for statements that operate with addresses of local (stack-allocated) variables - buffer overruns on them are most likely the cause of the problem.

鹤舞 2024-08-06 08:33:20

我能想到的可能性:

  • 不同的迭代器/stl 检查项目和它链接到的内容之间的调试设置。 请参阅调试迭代器支持检查迭代器
  • 您的项目及其链接到的任何内容之间的 CRT 设置不同。 使用 Dependency Walker 查看不匹配情况。
  • 由于函数中的错误代码而导致堆栈损坏,例如写入超出数组或字符串的末尾。
  • 导致堆栈或变量损坏的多线程问题。
  • 调用约定不匹配(正如您提到的从 Perl 调用它)

Possibilities I can think of:

  • Different iterator / stl checking debugging settings between your project and whatever it is linking to. See Debug Iterator Support and Checked Iterator.
  • Different CRT settings between your project and whatever it is linking to. Use Dependency Walker to see mismatches.
  • Stack corruption because of bad code in the function, for example writing past the end of an array or string.
  • A multithreading issue causing corruption of the stack or variables.
  • Mismatching calling conventions (as you mentioned calling it from Perl)
沫离伤花 2024-08-06 08:33:20

这段代码有很多错误:

  • 命名 - 我已经指出了 _Ty 的问题,但为什么有些成员以 m_ 开头,而其他成员则不然。 一些局部变量也以m_开头。 不好。

  • 赋值操作不返回引用 - 正如已经指出的。

  • 赋值操作有内存泄漏,在第一行,您分配给 m_rgArray,它已经有内容 - 这些已泄漏。

    赋值操作有内存

这是对于初学者来说的。 这些都不会导致崩溃,但它们都需要修复。 为了解决所有问题,我会重新开始,一次编写一个函数,并对其进行测试。 运行测试,如果有效,则编写下一个函数、下一个测试,依此类推。 像这样的模板类值得投入大量精力,因为如果它们是正确的,那么它们非常有用,但如果错误,则会带来持续的痛苦。

There is a lot wrong with this code:

  • naming - I already pointed out the problem with _Ty, but why do some members begin with m_ and others not. and some local variables also begin with m_. Not good.

  • Assignment op doesn't return a reference - as already pointed out.

  • Assignment op has a memory leak, at the first line, you assign to m_rgArray, which already has contents - these are leaked.

That's for starters. None of these should cause the crash, but they all need fixing. To fix all problems, I would start again, write one function at a time, plus a test for it. Run the test and if it works, write the next function, the next test, and so on. It is worth putting a lot of effort into template classes like this, because if they are right, they are very useful, but if wrong the source of continual pain.

夏天碎花小短裙 2024-08-06 08:33:20

您是否有任何带有非平凡析构函数的基于堆栈的对象? 根据您的调试器,可能很难判断它们何时执行。 除了其他评论中提到的所有内容之外,这可能与此相关。

Do you have any stack-based objects with non-trivial destructors? Depending on your debugger it may be hard to tell when these are executing. It could be something related to that, in addition to everything mentioned in the other comments.

热血少△年 2024-08-06 08:33:20

关于您的操作员的另一条评论=

  • 您没有处理自我分配正确地
  • 在同一个运算符中,我认为您正在泄漏,我建议您使用 boost::scoped_array 而不是普通指针。

我不知道这是否是给您带来问题的原因,但由于您似乎有内存损坏问题,因此可能值得关注。

Another comments about your operator=

  • You are not handling self assignment properly
  • In the same operator I think you are leaking, I would suggest you to use boost::scoped_array instead of a normal pointer.

I don't know if it is this what is giving you problems but due to it seems you have a memory corruption issue it might be something to star with.

蓝海 2024-08-06 08:33:20

我假设以下函数有更多代码

int funcname()
{
    return 0; <-- crashing after that...
}

当函数返回时,任何堆栈变量都将调用其析构函数。 崩溃很可能发生在其中一个析构函数中。

如何追踪它:

在函数中声明的任何变量的析构函数中放置断点。 单步执行每个析构函数。 请记住,当析构函数被调用时,来自基类的一整套析构函数将被自动调用,并且损坏可能发生在其中任何一个析构函数中。

I'm assuming the following function has more code to it

int funcname()
{
    return 0; <-- crashing after that...
}

When the function returns, any stack variables will have their destructors called. It is likely that the crash is happening in one of the destructors.

How to track it down:

Put breakpoints in the destructors of any variables declared in the function. Step through each destructor. Keep in mind that when a destructor gets called, there's a whole chain of destructors from base classes that will automoatically get called and the corruption could be in any one of those.

皇甫轩 2024-08-06 08:33:20

在您的函数 (funcname) 或由 funcname 调用的函数之一中,您可能有一些破坏堆栈的代码。

我遇到的大多数“实践”堆栈损坏是内存复制或字符串复制,当分配的目标缓冲区不适合要复制的数据的大小时(使用 sizeof 和元素数量错误计算大小,不考虑结尾)调整目标缓冲区大小以进行字符串复制时的字符串终止符)。

另一种不太常见的可能性是:指针算术,当引用局部变量或数组并通过该指针更改它们时。

Inside your function (funcname) or in one of the functions called by funcname you might have some code that corrupts the stack.

Most "practiced" stack corruption I encountered are memory copies or string copies, when the allocated target buffer doesn't fit the size of the data to be copied (misscalculation of size using sizeof and number of elements, not considering the end-of-string terminator when sizing the target buffer for string copying).

Another possibility, less often encountered: pointer aritmetics, when refering local variables or arrays and changing them through that pointer.

街角卖回忆 2024-08-06 08:33:20

您的赋值运算符应该返回一个引用:

pvector& operator=(const pvector &pv)  {

我怀疑这会导致问题,但请尝试一下。

Your assignment operator should be returning a reference:

pvector& operator=(const pvector &pv)  {

I doubt that would cause the problem, but give it a shot.

何以心动 2024-08-06 08:33:20

调试器说什么? 在返回行之后,它会遍历所有超出范围的对象的析构函数,其中一个几乎肯定会搞砸。
因此,在返回行处放置一个断点,然后使用调试器单步执行,直到发生崩溃。

What does the debugger say? After the return line, it runs through all the destructors for objects going out of scope, and one of them is almost certainly screwing up.
So put a breakpoint at the return line, and then step through with the debugger until you get to the crash.

反目相谮 2024-08-06 08:33:20

我的猜测是您的 pvector 在调整大小期间超出了数组。 我试图阅读代码来确定这是否属实,但我没有看到任何明显的东西。 如果您真正想要的是一个可以增长以适应所访问的任何索引的向量,那么您不需要自己编写整个内容。 您可以扩展 std::vector 并仅使用 Reserve()/resize() 方法,并让 STL 处理所有复制、内存管理和迭代器。 以下内容应该可以工作:

template<typename StoredType>
class pvector : public std::vector<StoredType>
{
public:
    typedef typename std::vector<StoredType, std::allocator<StoredType> >::reference reference;
    typedef typename std::vector<StoredType, std::allocator<StoredType> >::size_type size_type;

    reference at(size_type n)
    {
        size_type need = n+1;
        if(need > std::vector<StoredType>::capacity())
        {
            std::vector<StoredType>::reserve(need * 2);
            std::vector<StoredType>::resize(need);
        }
        else if(need > std::vector<StoredType>::size())
        {
            std::vector<StoredType>::resize(need);
        }
        return std::vector<StoredType>::at(n);
    }

    reference operator[](size_type n)
    {
        return at(n);
    }
};

我在 Linux 上使用 GCC 4.1.2 对其进行了测试,因此希望它也能在 Windows 上编译。

编辑:这是一个不继承的新版本,因为专家似乎认为这不是一个好主意(我学到了一些新东西,是的)。 您可以实现所需的其余方法并直接传递给 m_vector:

template<typename StoredType>
class pvector
{
public:
    typedef StoredType& reference;
    typedef int size_type;

    reference at(size_type n)
    {
        int need = n+1;
        if(need >= m_vector.capacity())
        {
            m_vector.reserve(need * 2);
            m_vector.resize(need);
        }
        else if(need >= m_vector.size())
        {
            m_vector.resize(need);
        }
        return m_vector.at(n);
    }

    reference operator[](size_type n)
    {
        return at(n);
    }

    size_type capacity() { return m_vector.capacity(); }
    size_type size() { return m_vector.size(); }

private:
    std::vector<StoredType> m_vector;
};

My guess is some problem with your pvector overrunning an array during the resize. I'm trying to read the code to find if that's true, but I don't see anything obvious. If all you really want is a vector that grows to fit whatever index is accessed, you don't need to write the whole thing yourself. You can extend std::vector instead and just use the reserve()/resize() methods and let STL handle all the copying and memory management and iterators. The following should work:

template<typename StoredType>
class pvector : public std::vector<StoredType>
{
public:
    typedef typename std::vector<StoredType, std::allocator<StoredType> >::reference reference;
    typedef typename std::vector<StoredType, std::allocator<StoredType> >::size_type size_type;

    reference at(size_type n)
    {
        size_type need = n+1;
        if(need > std::vector<StoredType>::capacity())
        {
            std::vector<StoredType>::reserve(need * 2);
            std::vector<StoredType>::resize(need);
        }
        else if(need > std::vector<StoredType>::size())
        {
            std::vector<StoredType>::resize(need);
        }
        return std::vector<StoredType>::at(n);
    }

    reference operator[](size_type n)
    {
        return at(n);
    }
};

I tested it with GCC 4.1.2 on Linux, so hopefully it'll compile on Windows too.

Edit: Here's a new version that doesn't inherit, since it seems experts agree it's not a good idea (I learned something new, yay). You can implement the rest of the methods you want and just pass-through to m_vector:

template<typename StoredType>
class pvector
{
public:
    typedef StoredType& reference;
    typedef int size_type;

    reference at(size_type n)
    {
        int need = n+1;
        if(need >= m_vector.capacity())
        {
            m_vector.reserve(need * 2);
            m_vector.resize(need);
        }
        else if(need >= m_vector.size())
        {
            m_vector.resize(need);
        }
        return m_vector.at(n);
    }

    reference operator[](size_type n)
    {
        return at(n);
    }

    size_type capacity() { return m_vector.capacity(); }
    size_type size() { return m_vector.size(); }

private:
    std::vector<StoredType> m_vector;
};
终难愈 2024-08-06 08:33:20

由于您的详细信息并不具体说明崩溃,我建议使用您的 IDE 调试应用程序:
在 ProjectProperties->ConfigurationProperties->Debugging 中将命令和命令参数设置为您的 perl / Ultimate++ 应用程序。 在调试模式下编译并在怀疑崩溃的地方放置断点。 定位问题并就崩溃本身提出有意义的消息应该相当简单。

Since your details are not specific on the crash I would suggest to debug the application using your IDE:
In ProjectProperties->ConfigurationProperties->Debugging set the Command and Command Arguments as your perl / ultimate++ applications. Compile in debug mode and put breakpoints where you suspect the crash. It should fairly simple to locate the problem and come up with a meaningful message on the crash itself.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文