This is quite strange for me, but I’m getting an unexpected and random segmentation fault when I launch my program. Some times it works, some times it crashes.. The debugger of Dev-C++ points me to a line of the file : stl_construct.h
/**
* @if maint
* Constructs an object in existing memory by invoking an allocated
* object's constructor with an initializer.
* @endif
*/
template<typename _T1, typename _T2>
inline void
_Construct(_T1* __p, const _T2& __value)
{
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 402. wrong new expression in [some_]allocator::construct
-> ::new(static_cast<void*>(__p)) _T1(__value);
}
I’m using the STL extensively by the way.. What should i do to detect the origin of the segfault? Are there any tools that can help? What are the reasons that can lead to random crashes like this.
Edit:
My program counts around 5000 lines of code. I don’t know what piece of code I have to show in order to get some help since I have no clue about the origin of the problem, all I got from the debugger is that it has to do with the STL.
Edit:
I moved to Code::Blocks now, here is the call stack:
#0 00464635 std::_Construct<std::pair<double const, int>, std::pair<double const, int> >(__p=0xb543e8, __value=@0x10) (C:/Program Files/CodeBlocks/MinGW/bin/../lib/gcc/mingw32/3.4.5/../../../../include/c++/3.4.5/bits/stl_construct.h:81)
#1 00462306 std::_Rb_tree<double, std::pair<double const, int>, std::_Select1st<std::pair<double const, int> >, std::less<double>, std::allocator<std::pair<double const, int> > >::_M_create_node(this=0x406fe50, __x=@0x10) (C:/Program Files/CodeBlocks/MinGW/bin/../lib/gcc/mingw32/3.4.5/../../../../include/c++/3.4.5/bits/stl_tree.h:367)
#2 00461DA7 std::_Rb_tree<double, std::pair<double const, int>, std::_Select1st<std::pair<double const, int> >, std::less<double>, std::allocator<std::pair<double const, int> > >::_M_clone_node(this=0x406fe50, __x=0x0) (C:/Program Files/CodeBlocks/MinGW/bin/../lib/gcc/mingw32/3.4.5/../../../../include/c++/3.4.5/bits/stl_tree.h:379)
#3 004625C6 std::_Rb_tree<double, std::pair<double const, int>, std::_Select1st<std::pair<double const, int> >, std::less<double>, std::allocator<std::pair<double const, int> > >::_M_copy(this=0x406fe50, __x=0x0, __p=0x406fe54) (C:/Program Files/CodeBlocks/MinGW/bin/../lib/gcc/mingw32/3.4.5/../../../../include/c++/3.4.5/bits/stl_tree.h:1029)
#4 00462A9D std::_Rb_tree<double, std::pair<double const, int>, std::_Select1st<std::pair<double const, int> >, std::less<double>, std::allocator<std::pair<double const, int> > >::_Rb_tree(this=0x406fe50, __x=@0xb59a7c) (C:/Program Files/CodeBlocks/MinGW/bin/../lib/gcc/mingw32/3.4.5/../../../../include/c++/3.4.5/bits/stl_tree.h:559)
#5 0045A928 std::map<double, int, std::less<double>, std::allocator<std::pair<double const, int> > >::map(this=0x406fe50, __x=@0xb59a7c) (C:/Program Files/CodeBlocks/MinGW/bin/../lib/gcc/mingw32/3.4.5/../../../../include/c++/3.4.5/bits/stl_map.h:166)
#6 0040B7E2 VehicleManager::get_vehicles_distances(this=0xb59a50) (C:/Program Files/CodeBlocks/MinGW/projects/AHS/VehicleManager.cpp:232)
#7 00407BDA Supervisor::IsMergeInstruction(id_vehicle=1) (C:/Program Files/CodeBlocks/MinGW/projects/AHS/Supervisor.cpp:77)
#8 00408430 CheckingInstructionsThread(arg=0x476100) (C:/Program Files/CodeBlocks/MinGW/projects/AHS/Supervisor.cpp:264)
#9 00413950 _glfwNewThread@4() (??:??)
#10 75A24911 KERNEL32!AcquireSRWLockExclusive() (C:\Windows\system32\kernel32.dll:??)
#11 00476100 std::__ioinit() (??:??)
#12 0406FFD4 ??() (??:??)
#13 76E5E4B6 ntdll!RtlInitializeNtUserPfn() (C:\Windows\system32\ntdll.dll:??)
#14 00476100 std::__ioinit() (??:??)
#15 70266582 ??() (??:??)
#16 00000000 ??() (??:??)
A few more precisions :
1/ It’s a multi-threaded application.
2/ The method : get_vehicles_distances(); returns a map.
3/ It’s possible that the map isn’t initalised by the time when it’s called by IsMergeInstruction();
Edit:
Apparently the line that is causing the segfault is :
vehicles_distances_.erase(vehicles_distances_.begin(), vehicles_distances_.end());
Where vehicles_distances_ is the Map. This line is a part of the method : VehicleManager::MoveAllVehicles();
void VehicleManager::MoveAllVehicles() {
vehicles_distances_.erase(vehicles_distances_.begin(), vehicles_distances_.end());
vector<Vehicle>::iterator iter_end = VehicleManager::vehicles_.end();
for(vector<Vehicle>::iterator iter = VehicleManager::vehicles_.begin();
iter != iter_end; ++iter) {
(*iter).MoveVehicle();
vehicles_distances_[(*iter).get_vec_vehicle_position().y] = (*iter).get_id_vehicle();
}
}
What is wrong with that ?
Edit:
I tried to use map::clear(); as a replacement to map::erase(); but the same problem occurs!
Edit:
I think i get it… A thread is trying to make a use of vehicles_distances_ while it’s cleared.. (?)
Edit:
Problem solved! So it was coming from the map::erase(); as expected. i bypassed the problem by creating another map variable where the pair <key, value> was inverted so i can update the map. (since the key that i need is the distance, and the distance isn’t unique since it changes everytime but the id_vehicle is unique!). At the end i just took that map, inverted the <key, value> again and transferred it to the original map that can be redeclared in each cycle…
Thanks everyone !
First, for the love of all that is, well, lovable, don’t use Dev-C++. I wish I knew how people keep running into that piece of junk. It hasn’t been maintained for years, and even when it was maintained, it was still a buggy piece of junk that lacked very basic functionality. Ditch it, and go for one of the countless better free alternatives.
Now, onto your question: Your program segfaults randomly because you’ve done something illegal earlier. Don’t do that. 😉
if your program writes out of bounds somewhere, anything might happen. It might hit an unallocated page, in which case you get a segfault. Or it might hit unused data on a page that is allocated to your process in which case it won’t have any practical effect (unless it is properly initialized afterwards, overwriting your first, illegal, write, and you then try to read from it, expecting the original (invalid) value to still be there. Or it might hit data that’s actually in use, in which case you’ll get errors later, when the program tries to read that data.
Pretty much the same scenarios exist when reading data. You can be lucky and get a segfault immediately, or you can hit unused and uninitialized memory, and read garbage data out (which will most likely cause an error later, when that data is used), or you can read from memory addresses that are already in use (which will also give you garbage out).
So yes, these errors are tricky to find. The best advice I can give is to 1) sprinkle asserts all over your code to ensure basic invariants are maintained, and 2) step through the program, and at every step, verify that you’re not reading or writing to addresses that don’t belong to you.
MSVC has a secure SCL option enabled by default which will perform bounds checking on STL code, which can help spotting errors like this.
I believe GCC has an option to do something similar (but it’s not enabled by default).
Segfaults are nasty. Once people have been bitten by an error like this a few times, they tend to become a lot more disciplined with avoiding accessing memory out of bounds. 🙂