Skip to content
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

fix dangling pointer to state buffer in state registry #190

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 22 additions & 2 deletions src/search/state_registry.cc
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,12 @@ State StateRegistry::lookup_state(StateID id) const {
return task_proxy.create_state(*this, id, buffer);
}

State StateRegistry::lookup_state(
StateID id, vector<int> &&state_values) const {
const PackedStateBin *buffer = state_data_pool[id.value];
return task_proxy.create_state(*this, id, buffer, move(state_values));
}

const State &StateRegistry::get_initial_state() {
if (!cached_initial_state) {
int num_bins = get_bins_per_state();
Expand All @@ -64,6 +70,12 @@ const State &StateRegistry::get_initial_state() {
// operating on state buffers (PackedStateBin *).
State StateRegistry::get_successor_state(const State &predecessor, const OperatorProxy &op) {
assert(!op.is_axiom());
/*
TODO: ideally, we would not modify state_data_pool here and in
insert_id_or_pop_state, but only at one place, to avoid errors like
buffer becoming a dangling pointer. This used to be a bug before being
fixed in https://issues.fast-downward.org/issue1115.
*/
state_data_pool.push_back(predecessor.get_buffer());
PackedStateBin *buffer = state_data_pool[state_data_pool.size() - 1];
/* Experiments for issue348 showed that for tasks with axioms it's faster
Expand All @@ -81,17 +93,25 @@ State StateRegistry::get_successor_state(const State &predecessor, const Operato
for (size_t i = 0; i < new_values.size(); ++i) {
state_packer.set(buffer, i, new_values[i]);
}
/*
NOTE: insert_id_or_pop_state possibly invalidates buffer, hence
we use lookup_state to retrieve the state using the correct buffer.
*/
StateID id = insert_id_or_pop_state();
return task_proxy.create_state(*this, id, buffer, move(new_values));
return lookup_state(id, move(new_values));
} else {
for (EffectProxy effect : op.get_effects()) {
if (does_fire(effect, predecessor)) {
FactPair effect_pair = effect.get_fact().get_pair();
state_packer.set(buffer, effect_pair.var, effect_pair.value);
}
}
/*
NOTE: insert_id_or_pop_state possibly invalidates buffer, hence
we use lookup_state to retrieve the state using the correct buffer.
*/
StateID id = insert_id_or_pop_state();
return task_proxy.create_state(*this, id, buffer);
return lookup_state(id);
}
}

Expand Down
7 changes: 7 additions & 0 deletions src/search/state_registry.h
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,13 @@ class StateRegistry : public subscriber::SubscriberService<StateRegistry> {
*/
State lookup_state(StateID id) const;

/*
Like lookup_state above, but creates a state with unpacked data,
moved in via state_values. It is the caller's responsibility that
the unpacked data matches the state's data.
*/
State lookup_state(StateID id, std::vector<int> &&state_values) const;

/*
Returns a reference to the initial state and registers it if this was not
done before. The result is cached internally so subsequent calls are cheap.
Expand Down