大小为 4 valgrind 的读取无效
Posted
技术标签:
【中文标题】大小为 4 valgrind 的读取无效【英文标题】:Invalid read of size 4 valgrind 【发布时间】:2020-05-11 17:13:48 【问题描述】:我用 valgrind 运行我的代码并得到一个“无效读取大小 4”的错误。这是我得到的:
==15103== at 0x10F74C: NoeudHydro<noeud*>::GetNumero() const (NoeudHydro.h:97)
==15103== by 0x10ECE1: std::ostream& operator<< <noeud*>(std::ostream&, NoeudHydro<noeud*>) (NoeudHydro.h:191)
==15103== by 0x10E15A: main (main.cpp:71)
==15103== Address 0x5b88450 is 0 bytes inside a block of size 240 free'd
==15103== at 0x4C3123B: operator delete(void*) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==15103== by 0x110943: __gnu_cxx::new_allocator<NoeudHydro<noeud*> >::deallocate(NoeudHydro<noeud*>*, unsigned long) (new_allocator.h:125)
==15103== by 0x1105C1: std::allocator_traits<std::allocator<NoeudHydro<noeud*> > >::deallocate(std::allocator<NoeudHydro<noeud*> >&, NoeudHydro<noeud*>*, unsigned long) (alloc_traits.h:462)
==15103== by 0x10FBE7: std::_Vector_base<NoeudHydro<noeud*>, std::allocator<NoeudHydro<noeud*> > >::_M_deallocate(NoeudHydro<noeud*>*, unsigned long) (stl_vector.h:180)
==15103== by 0x112102: void std::vector<NoeudHydro<noeud*>, std::allocator<NoeudHydro<noeud*> > >::_M_realloc_insert<NoeudHydro<noeud*> >(__gnu_cxx::__normal_iterator<NoeudHydro<noeud*>*, std::vector<NoeudHydro<noeud*>, std::allocator<NoeudHydro<noeud*> > > >, NoeudHydro<noeud*>&&) (vector.tcc:448)
==15103== by 0x111E47: void std::vector<NoeudHydro<noeud*>, std::allocator<NoeudHydro<noeud*> > >::emplace_back<NoeudHydro<noeud*> >(NoeudHydro<noeud*>&&) (vector.tcc:105)
==15103== by 0x111CCF: std::vector<NoeudHydro<noeud*>, std::allocator<NoeudHydro<noeud*> > >::push_back(NoeudHydro<noeud*>&&) (stl_vector.h:954)
==15103== by 0x111AE6: AjoutNoeudHydro(std::vector<NoeudHydro<noeud*>, std::allocator<NoeudHydro<noeud*> > >&, noeud*, char, int, int*) (passerelleRT.cpp:48)
==15103== by 0x1119EC: ParcoursAxe(axe*, std::vector<NoeudHydro<noeud*>, std::allocator<NoeudHydro<noeud*> > >&, int*, int) (passerelleRT.cpp:36)
==15103== by 0x10E0E1: main (main.cpp:68)
==15103== Block was alloc'd at
==15103== at 0x4C3017F: operator new(unsigned long) (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==15103== by 0x1109D3: __gnu_cxx::new_allocator<NoeudHydro<noeud*> >::allocate(unsigned long, void const*) (new_allocator.h:111)
==15103== by 0x110680: std::allocator_traits<std::allocator<NoeudHydro<noeud*> > >::allocate(std::allocator<NoeudHydro<noeud*> >&, unsigned long) (alloc_traits.h:436)
==15103== by 0x10FE55: std::_Vector_base<NoeudHydro<noeud*>, std::allocator<NoeudHydro<noeud*> > >::_M_allocate(unsigned long) (stl_vector.h:172)
==15103== by 0x111FC5: void std::vector<NoeudHydro<noeud*>, std::allocator<NoeudHydro<noeud*> > >::_M_realloc_insert<NoeudHydro<noeud*> >(__gnu_cxx::__normal_iterator<NoeudHydro<noeud*>*, std::vector<NoeudHydro<noeud*>, std::allocator<NoeudHydro<noeud*> > > >, NoeudHydro<noeud*>&&) (vector.tcc:406)
==15103== by 0x111E47: void std::vector<NoeudHydro<noeud*>, std::allocator<NoeudHydro<noeud*> > >::emplace_back<NoeudHydro<noeud*> >(NoeudHydro<noeud*>&&) (vector.tcc:105)
==15103== by 0x111CCF: std::vector<NoeudHydro<noeud*>, std::allocator<NoeudHydro<noeud*> > >::push_back(NoeudHydro<noeud*>&&) (stl_vector.h:954)
==15103== by 0x111AE6: AjoutNoeudHydro(std::vector<NoeudHydro<noeud*>, std::allocator<NoeudHydro<noeud*> > >&, noeud*, char, int, int*) (passerelleRT.cpp:48)
==15103== by 0x1119EC: ParcoursAxe(axe*, std::vector<NoeudHydro<noeud*>, std::allocator<NoeudHydro<noeud*> > >&, int*, int) (passerelleRT.cpp:36)
==15103== by 0x10E0E1: main (main.cpp:68)
这是我的代码:
#include <iostream>
#include "NoeudHydro.h"
#include "passerelleRT.h"
using namespace std;
bool EstNoeudReit(PTNoeud Nd)
PTNoeud Ndsuivant=Nd->suiv;
return SontConfondus(Nd,Ndsuivant);
bool SontConfondus(PTNoeud Nd1, PTNoeud Nd2)
return Nd1->pos[0]==Nd2->pos[0] && Nd1->pos[1]==Nd2->pos[1] && Nd1->pos[2]==Nd2->pos[2];
void ParcoursAxe(PTAxe AxeCourant,vector< NoeudHydro<PTNoeud> >& SysHydro, int TabEqui[],int temps)
PTNoeud NdSRCourant=AxeCourant->premNoeud;
NdSRCourant=NdSRCourant->NdDistSurAxeFils;
while(NdSRCourant!=NULL)
if(NdSRCourant->NdDistSurAxeFils!=NULL) //Si c'est un Nd Ramif/Reit
if(EstNoeudReit(NdSRCourant))
AjoutNoeudHydro(SysHydro,NdSRCourant,'2',temps,TabEqui);
PTNoeud NdTemp=NdSRCourant->suiv;
while(SontConfondus(NdTemp,NdSRCourant))
TabEqui[NdTemp->num]=SysHydro.size()-1; //le numero du NoeudHydro venant d etre ajoute
//est la taille du vecteur -1
SysHydro[SysHydro.size()+1].SetEquivalentSysRac(NdTemp);
NdTemp=NdTemp->suiv;
//end if EstNoeudReit
else //C est un Nd Ramif
AjoutNoeudHydro(SysHydro,NdSRCourant,'1',temps,TabEqui);
//end if Nd Ramif/Reit
else
AjoutNoeudHydro(SysHydro,NdSRCourant,'0',temps,TabEqui);
NdSRCourant=NdSRCourant->suiv;
void AjoutNoeudHydro(vector< NoeudHydro<PTNoeud> >& SysHydro,PTNoeud NdSR, char typeNd, int temps,int TabEqui[])
//Ajout dans le vecteur
SysHydro.push_back(NoeudHydro<PTNoeud> (NdSR,SysHydro.size(),typeNd,temps));
//Relation Pere-Fils
SysHydro.back().SetPere(SysHydro[TabEqui[NdSR->prec->num]]);
SysHydro[TabEqui[NdSR->prec->num]].SetFils(SysHydro.back());
//Equivalences
TabEqui[NdSR->num]=SysHydro.size()-1;
int main()
int tempsTotal=28;
/*-----------------------------------------------------*/
/*SOME CODE THAT DOES WORK AND NEEDED FOR THE NEXT PART*/
/*-----------------------------------------------------*/
cout<<"------------------------------------------"<<endl;
cout<<"-------------------HYDRO------------------"<<endl;
cout<<"------------------------------------------"<<endl;
// //HYDRO
NoeudHydro<PTNoeud> *Nd;
Nd=new NoeudHydro<PTNoeud> (SRG.GetSR()->premAxe->suivant->premNoeud,0,'0',tempsTotal);
vector< NoeudHydro<PTNoeud> > SysHydro;
int TabEqui[27];
TabEqui[0]=-9;
TabEqui[4]=0;
SysHydro.push_back(*Nd);
ParcoursAxe(SRG.GetSR()->premAxe->suivant,SysHydro,TabEqui,tempsTotal);
for(int i=0;i<SysHydro.size();i++)
cout<<SysHydro[i]<<endl;
cout<<endl;
delete Nd;
return 0;
以及出现问题的班级:
#ifndef NOEUDHYDRO
#define NOEUDHYDRO
#include <iostream>
#include <vector>
#include "fonctions_Info_Element.h"
using namespace std;
template <typename T>
class NoeudHydro
private :
int numero; //numero dans l hydro
int typeRacine;
int ordreRamif;
char typeNd; //(noeud simple =0, ramif = 1, reit = 2)
float coordonnes[3]; //coordonnees
double diametre;
int age;
float distanceApex;
double conductAxiale; //conductance axiale entre le pere et lui meme
double conductRadiale;
NoeudHydro<T>* Pere;
vector<NoeudHydro*> Fils; //NoeudHydro suivant. Le premier est le suivant sur la meme racine.
//Les autres sont les NoeudHydro suivant sur les axes fils (s il y a)
vector<T> EquivalentSysRac; //Liste des Noeud/Seg du SysRac equivalents
public :
//CONSTRUCTEURS/DESTRUCTEUR
NoeudHydro(); //par defaut
NoeudHydro(T& Element,int num, char typeNd, int temps);
~NoeudHydro();
//ACCESSEURS
int GetNumero() const;
NoeudHydro<T>* GetPere() const;
NoeudHydro<T>* GetFils(int i) const;
T GetEquivalentSysRac(int i) const;
int GetNbEquivalentSysRac() const;
void SetNumero(int i);
void SetPere(NoeudHydro<T>& Pere);
void SetFils(NoeudHydro<T>& Fils);
;
template <typename T>
NoeudHydro<T>::NoeudHydro(T& Element,int num, char typeNd, int temps)
this->Pere=NULL;
this->numero=num;
this->typeRacine=TypeRacineElement(Element);
this->ordreRamif=OrdreRamifElement(Element);
this->typeNd=typeNd;
for(int i=0;i<3;i++)
this->coordonnes[i]=CoordonneesElement(Element,i);
this->diametre=DiametreElement(Element);
this->age=AgeElement(Element,temps);
this->EquivalentSysRac.push_back(Element);
cout<<"NoeudHydro "<<this->numero<<" cree"<<endl;
template <typename T>
NoeudHydro<T>::~NoeudHydro() cout<<"NoeudHydro "<<this->numero<<" detruit"<<endl;
//ACCESSEURS
template <typename T>
int NoeudHydro<T>::GetNumero() const
return this->numero;
template <typename T>
NoeudHydro<T>* NoeudHydro<T>::GetPere() const
return this->Pere;
template <typename T>
NoeudHydro<T>* NoeudHydro<T>::GetFils(int i) const
return this->Fils[i];
template <typename T>
void NoeudHydro<T>::SetNumero(int i)
this->numero=i;
template <typename T>
void NoeudHydro<T>::SetPere(NoeudHydro& NdPere)
this->Pere=&NdPere;
template <typename T>
void NoeudHydro<T>::SetFils(NoeudHydro& NdFils)
this->Fils.push_back(&NdFils);
//Operateur
template <typename T>
ostream& operator<<(ostream& stream, NoeudHydro<T> Nd)
if(Nd.GetPere()!=NULL)cout<<"Noeud Pere : "<<Nd.GetPere()->GetNumero()<<endl;
for(int i=0;i<Nd.GetNbFils();i++)
cout<<"Fils numero "<<i<<" : noeud "<<Nd.GetFils(i)->GetNumero()<<endl;
return stream;
#endif
错误似乎来自GetNumero(),但如果我这样做没有错误
NoeudHydro<PTNoeud> Nd(parameter needed);
Nd.GetNumero();
只有当我做Nd.GetPere()->GetNumero();
不明白为什么,我也注意到代码确实有效。 (如果我不使用 valgrind,我会继续编写代码)。 有人有话要说吗?
注意:PTNoeud 与 noeud* 相同
【问题讨论】:
不相关:“NB : PTNoeud is the same as noeud*”那何必呢? 定义PTNoeud的部分我没有写,我使用它以便我的同事可以理解 这里的关键信息是“地址 0x5b88450 是大小为 240 的块内的 0 个字节已释放” - 这意味着您所指的数据位于内存中 已经空闲' d。 Valgrind 进一步告诉你该块最初分配的位置。 【参考方案1】:如果不能轻松地追踪错误到行号,就很难准确地说出错误是什么。
不明白为什么,我也注意到代码确实有效。 (如果我不使用 valgrind,我会继续编写代码)。有人有话要说吗?
这就是未定义行为 (UB) 的本质。如果 UB 意味着应用程序总是以一个很好且易于调试的 coredump 崩溃,那就太好了。实际上,UB 意味着几乎任何事情都可能发生。它可以运行多年而没有副作用,然后突然崩溃。
回到问题上来。 Valgrind 告诉您您正在访问已删除的内容。它也告诉你这一切都发生在emplace_back
。这可能意味着正在调整vector
的大小,并且在调整大小的过程中出现了问题。
我的猜测是您的问题出在您的父/子原始指针上。当 vector
调整大小时,这可能会使这些指针无效。如果这是正确的,那么您将需要修改赋值运算符/复制构造函数/移动构造函数,或者只考虑使用智能指针。
【讨论】:
【参考方案2】:非常感谢。我使用了智能指针,它可以工作。我只想问我做得是否正确(你让我发现了智能指针):
void NoeudHydro<T>::SetPere(NoeudHydro& NdPere)
shared_ptr<NoeudHydro<T> >temp (new NoeudHydro<T>(NdPere));
this->Pere=temp;
template <typename T>
void NoeudHydro<T>::SetFils(NoeudHydro& NdFils)
shared_ptr<NoeudHydro<T> >temp (new NoeudHydro<T>(NdFils));
Fils.push_back(temp);
shared_ptr<NoeudHydro<T> > Pere;
和 vector<shared_ptr<NoeudHydro<T>>> Fils;
。
而且我也不明白为什么当调整向量大小时,指针会失效?
【讨论】:
正如我所说,没有调试很难确定。当vector
调整大小时,会分配更大的新内存块,将旧内存复制到新内存的开头并释放旧内存。这意味着在调整大小之后,任何指向旧内存的东西都是无效的。您的共享指针看起来不错,但您应该可以只使用 emplace_back
而不是创建一个临时的并使用 push_back。以上是关于大小为 4 valgrind 的读取无效的主要内容,如果未能解决你的问题,请参考以下文章
wchar_t valgrind 问题 - 大小为 8 的读取无效