I wrote a program and I'm quite amused by the fact that I'd run it dozens of times -- I've even wrote down results from multiple executions --, and now it does not work.
You might think I'm high as a kite to say so, or that I might have simply changed some lines, but I really do not recall doing any alterations whatsoever on the program.
The problem is a SIGFPE
, that raises up in different executions of the program, according to the input. Happens though the signal is raised while inserting a value in an std::unordered_set<Point<T> *>
.
Here is a snippet of the code where I do such insertion:
std::vector<Point<T> *> _point, _centroid;
std::vector<std::unordered_set<Point<T> *> > _cluster;
// Main procedure -- pseudocode
for (point in _point) {
cluster_id = centroid_with_min_distance(point, _centroid);
has_changed = _change_cluster(point, cluster_id);
}
// Changes from one "point->_cluster's unordered_set" to "c's unordered_set"
bool _change_cluster(Point<T> *point, const unsigned int& c) {
if ((point->_cluster == c) &&
(_cluster[c].find(point) != _cluster[c].end())) {
return false;
}
_cluster[point->_cluster].erase(point);
_cluster[c].insert(point); // Insertion that raises the SIGFPE exception
point->_cluster = c;
return true;
}
Here is a considered-important section of valgrind's output:
==17636== Invalid read of size 8
==17636== at 0x40A758: std::pair<std::__detail::_Hashtable_iterator<
Point<unsigned int>*, true, false>, bool>
std::_Hashtable<Point<unsigned int>*, Point<unsigned int>*,
std::allocator<Point<unsigned int>*>,
std::_Identity<Point<unsigned int>*>,
std::equal_to<Point<unsigned int>*>,
std::hash<Point<unsigned int>*>,
std::__detail::_Mod_range_hashing,
std::__detail::_Default_ranged_hash,
std::__detail::_Prime_rehash_policy, false, true, true>::
_M_insert<Point<unsigned int>* const&>(
Point<unsigned int>* const&&&,
std::integral_constant<bool, true>) (hashtable.h:966)
==17636== by 0x408EDA: std::_Hashtable<Point<unsigned int>*,
Point<unsigned int>*, std::allocator<Point<unsigned int>*>,
std::_Identity<Point<unsigned int>*>,
std::equal_to<Point<unsigned int>*>,
std::hash<Point<unsigned int>*>,
std::__detail::_Mod_range_hashing,
std::__detail::_Default_ranged_hash,
std::__detail::_Prime_rehash_policy, false, true, true>::
insert(Point<unsigned int>* const&) (hashtable.h:400)
==17636== ... (calls from my program) ...
==17636== Address 0x620a028 is not stack'd, malloc'd or (recently) free'd
==17636==
==17636==
==17636== Process terminating with default action of signal 8 (SIGFPE)
==17636== Integer divide by zero at address 0x402D07D7C
==17636== at 0x40252F: std::__detail::_Mod_range_hashing::operator()(
unsigned long, unsigned long) const (hashtable_policy.h:376)
==17636== by 0x40A66C: std::__detail::_Hash_code_base<Point<unsigned int>*,
Point<unsigned int>*, std::_Identity<Point<unsigned int>*>,
std::equal_to<Point<unsigned int>*>,
std::hash<Point<unsigned int>*>,
std::__detail::_Mod_range_hashing,
std::__detail::_Default_ranged_hash, false>::_M_bucket_index(
Point<unsigned int>* const&, unsigned long,
unsigned long) const (hashtable_policy.h:758)
==17636== by 0x40A772: std::pair<std::__detail::_Hashtable_iterator<
Point<unsigned int>*, true, false>, bool>
std::_Hashtable<Point<unsigned int>*, Point<unsigned int>*,
std::allocator<Point<unsigned int>*>,
std::_Identity<Point<unsigned int>*>,
std::equal_to<Point<unsigned int>*>,
std::hash<Point<unsigned int>*>,
std::__detail::_Mod_range_hashing,
std::__detail::_Default_ranged_hash,
std::__detail::_Prime_rehash_policy, false, true, true>::
_M_insert<Point<unsigned int>* const&>(
Point<unsigned int>* const&&&,
std::integral_constant<bool, true>) (hashtable.h:966)
==17636== by 0x408EDA: std::_Hashtable<Point<unsigned int>*,
Point<unsigned int>*, std::allocator<Point<unsigned int>*>,
std::_Identity<Point<unsigned int>*>,
std::equal_to<Point<unsigned int>*>,
std::hash<Point<unsigned int>*>,
std::__detail::_Mod_range_hashing,
std::__detail::_Default_ranged_hash,
std::__detail::_Prime_rehash_policy, false, true, true>::
insert(Point<unsigned int>* const&) (hashtable.h:400)
==17636== ... (calls from my program) ...
The question here is: as I have calculations in my program that may result in divisions by zero -- they are not directly related to this process, though --, is it possible that the bug is being shadowed by the insertion? Or should I do some extra treatment while inserting pointers in an std::unordered_set<T>
?
I'm compiling the program under x86_64 GNU/Linux
, and I'm using g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3
.
I suspect that 'c' is out of the range of _cluster
. Can you replace all of the _cluster[c]
with _cluster.at(c)
, and see if it finds an out of range error.
The valgrind output indicates that it's an invalid read followed by an integer modulus error. Since it's doing hash_code % bucket_count
, I suspect that you accessed out of the range of the vector.
As an aside, naming things that start with _
can be risky, as if it's in the global namespace, it is technically reserved for the implementation.