-
Notifications
You must be signed in to change notification settings - Fork 58
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
deletion_fn() is called too late, resulting in SEGFAULT #80
Comments
Moving I think I'm confused about why this issue occurs when using the static inline symmetric_graph<symmetric_vertex, Wgh> sym_graph_from_edges(
...
return symmetric_graph<symmetric_vertex, Wgh>(v_data, n, m,
[=]() {
gbbs::free_array(v_data, n);
gbbs::free_array(edges, m);
},
(edge_type*)edges);
} Shouldn't the deletion function there be capturing |
You make an excellent point - it really shouldn't matter. The problem happens in the following code (please ignore that the implementation of the algorithm isn't entirely correct yet): #pragma once
#include "gbbs/gbbs.h"
#include "gbbs/contract.h"
#include "benchmarks/LowDiameterDecomposition/MPX13/LowDiameterDecomposition.h"
#include "benchmarks/Spanner/MPXV15/Spanner.h"
#include <iostream>
// LSPES - Low-Stretch Parallel Exponential Shift
namespace gbbs {
namespace LowAvgStretch {
using edge = gbbs::spanner::edge;
template <
template <class W> class vertex, class W,
// This means W(weight) is not defined, thus unweighted graph
typename std::enable_if<std::is_same<W, gbbs::empty>::value, int>::type = 0>
inline parlay::sequence<edge> LSPES(symmetric_graph<vertex, W>& G) {
using cluster_and_parent = gbbs::spanner::cluster_and_parent;
auto edge_list = parlay::sequence<edge>();
while (G.n > 0) {
// Determine clusters + implicit trees within clusters (taken from Spanner.h)
auto cluster_and_parents = gbbs::spanner::LDD_parents(G, 0.2, true);
// Determine edges within clusters (taken from Spanner.h)
auto tree_edges_with_loops = parlay::delayed_seq<edge>(G.n, [&](size_t i) {
return std::make_pair(i, cluster_and_parents[i].parent);
});
auto tree_edges = parlay::filter(tree_edges_with_loops, [&](const edge& e) {
return e.first != e.second;
});
edge_list.append(parlay::make_slice(tree_edges));
// Contract the graph
auto clusters = parlay::map(cluster_and_parents, [](const cluster_and_parent& cp) {
return cp.cluster;
});
size_t num_clusters = contract::RelabelIds(clusters);
auto c_out = contract::contract(G, clusters, num_clusters);
G = std::move(std::get<0>(c_out));
}
return edge_list;
}
}
} The SEGFAULT happens in Graph G is generated using Definition of move/copy constructor/assignment: // Move constructor
symmetric_graph(symmetric_graph&& other) noexcept {
n = other.n;
m = other.m;
v_data = other.v_data;
e0 = other.e0;
vertex_weights = other.vertex_weights;
deletion_fn = std::move(other.deletion_fn);
other.v_data = nullptr;
other.e0 = nullptr;
other.vertex_weights = nullptr;
other.deletion_fn = []() {};
}
// Move assignment
symmetric_graph& operator=(symmetric_graph&& other) noexcept {
n = other.n;
m = other.m;
v_data = other.v_data;
e0 = other.e0;
vertex_weights = other.vertex_weights;
deletion_fn();
deletion_fn = std::move(other.deletion_fn);
other.v_data = nullptr;
other.e0 = nullptr;
other.vertex_weights = nullptr;
other.deletion_fn = []() {};
return *this;
}
// Copy constructor
symmetric_graph(const symmetric_graph& other) {
debug(std::cout << "Copying symmetric graph." << std::endl;);
n = other.n;
m = other.m;
v_data = gbbs::new_array_no_init<vertex_data>(n);
e0 = gbbs::new_array_no_init<edge_type>(m);
parallel_for(0, n, [&](size_t i) { v_data[i] = other.v_data[i]; });
parallel_for(0, m, [&](size_t i) { e0[i] = other.e0[i]; });
deletion_fn = [=]() {
gbbs::free_array(v_data, n);
gbbs::free_array(e0, m);
if (vertex_weights != nullptr) {
gbbs::free_array(vertex_weights, n);
}
};
vertex_weights = nullptr;
if (other.vertex_weights != nullptr) {
vertex_weights = gbbs::new_array_no_init<vertex_weight_type>(n);
parallel_for(
0, n, [&](size_t i) { vertex_weights[i] = other.vertex_weights[i]; });
}
}
~symmetric_graph() { deletion_fn(); } If I pull the |
Hmm I'm not sure what's going on either. I tried running your code snippet on my machine with If you can't figure out what's happening or if you just don't want to spend more time debugging this issue, you can open a PR moving |
Sorry for the late response! I couldn't really figure out what the issue was, so I opened a PR as you said. As mentioned in the PR, I haven't tested the fix with anything besides my custom implementation of a low-stretch spanning tree algorithm, but it shouldn't break any other implementations/algorithms/benchmarks. (But then again, as we discussed above, this shouldn't change anything in the first place, yet it fixes my issue.) |
PR by: dnezam Fixes issue described in #80 by calling `deletion_fn()` at the very beginning. Note that I only tested this fix in the context of my own algorithm implementation. I did not test this for any other benchmark/algorithm provided by gbbs.
Hello,
after compiling my code with
fsanitizer=address
to debug aSEGFAULT
, I found out that the code (which mainly consists of library calls toparlay
andgbbs
) tries to access a freed location. While investigating, it seems that the pointer is freed during the move assignment:To my understanding,
deletion_fn()
(marked with <--) frees the pointer ofother
, and notthis
. At the end of the move, the original data ofthis
is leaked + the current data ofthis
is invalid, which probably leads to theSEGFAULT
in my code. A possible fix would be to move the call to the beginning, i.e.:With this, my code doesn't
SEGFAULT
.In particular, the graph that is being moved in and out is generated by
symmetric_graph<symmetric_vertex, Wgh> sym_graph_from_edges
ingraph.h
:Best,
Daniel
The text was updated successfully, but these errors were encountered: