2009-07-31 118 views
1

我有一个C++代码,我使用MSC9来编译它。 它随机崩溃。例如,如果它是使用``从Perl调用的,但它在从命令行或从Ultimate ++调用它时不会崩溃。程序在离开C++函数时崩溃....你认为它是什么?

我的意思是从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 ::复制在pvector运算符中是正确的=(const pvector & pv),对不对?

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

Update1:​​ 我收到了有关作业泄漏的建议。 我改变了分配...... 这就是现在的样子:

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:我想我已经找到它了。我使用了一个名为gflags.exe和windbg.exe的调试工具的实用程序来查找确切位置。 我使用了gflags.exe/p/enable myprog.exe/full来打开堆错误的例外情况。 目前,我认为这个错误是由FindClose(句柄)引起的。句柄是一个随机值,没有初始化。

旧版本:

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; 
     } 
    } 

    }; 
+4

Ofcourse这是一个编译器错误! :) 这将有助于,如果你张贴功能的一些代码。 – Indy9000 2009-07-31 09:18:55

+2

它可能是任何东西。显示一些代码。捕捉这种错误的最快捷方式通常是非常仔细地通读代码。 – nos 2009-07-31 09:20:31

+0

以下是一些代码 – Aftershock 2009-07-31 11:38:21

回答

12

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

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

3

可能性我能想到的:

  • 不同的迭代器/ STL您的项目,不管它是连接之间检查调试设置。请参阅Debug Iterator SupportChecked Iterator
  • 不同的CRT设置在你的项目之间以及它连接到的任何地方。使用Dependency Walker查看不匹配。
  • 由于函数中的代码错误而导致堆栈损坏,例如写入数组或字符串末尾。
  • 多线程问题导致堆栈或变量损坏。
  • 不匹配的调用约定(至于你提到在Perl调用它)
+0

我没有在堆栈上分配数组,我想因为我在任何地方都使用向量stl类。 – Aftershock 2009-07-31 09:33:04

0

里面你的函数(funcname的)或由funcname的叫你可能有一些代码,破坏了栈的功能之一。

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

另一种可能性,不太经常遇到:当引用局部变量或数组并通过指针改变它们时,指针算法。

2

你有没有任何基于堆栈的对象与非平凡的析构函数?根据您的调试器,可能很难分辨这些执行时间。除了其他评论中提到的所有内容之外,这可能与此有关。

1

我假设下面的函数有更多的代码,它

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

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

如何追查:在函数中声明的任何变量的析构函数

认沽断点。遍历每个析构函数。请记住,当一个析构函数被调用时,会有一系列基类的析构函数,它们将被自动调用并且腐败可能出现在这些函数中的任何一个中。

0

由于您的详细信息不是特定于崩溃,我建议使用IDE调试应用程序: 在ProjectProperties-> ConfigurationProperties-> Debugging中,将命令和命令参数设置为您的perl/ultimate ++应用程序。在调试模式下编译并在怀疑崩溃的位置放置断点。它应该很容易找到问题,并在崩溃本身上提出一个有意义的信息。

0

你的赋值运算符应该返回一个参考:

pvector& operator=(const pvector &pv) { 

我怀疑会引起问题,但给它一个镜头。

0

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

0

我的猜测是你的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; 
}; 
3

有很多错误与此代码:

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

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

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

这是首发。这些都不会导致事故,但他们都需要修理。为了解决所有问题,我会重新开始,一次写一个函数,再加上一个测试。运行测试,如果有效,写下一个函数,下一个测试,等等。这样做值得在模板类中付出很多努力,因为如果它们是正确的,它们是非常有用的,但如果错误是持续痛苦的根源。

1

你的运营商的另一种意见=

  • 您还没有处理self assignment正常
  • 在同一个运营商,我认为你是漏水,我会建议你使用boost :: scoped_array,而不是一个正常的指针。

我不知道是否这是什么给你的问题,但由于它似乎你有一个记忆腐败的问题,它可能是明星的东西。