GH-527: fix ref-counting issues in Frame unserialization

Coverity CIDs 1403968, 1403967
This commit is contained in:
Jon Siwek 2019-08-06 13:17:34 -07:00
parent 3080290a5e
commit 05bc680d3f

View file

@ -33,9 +33,10 @@ Frame::~Frame()
{ {
// Deleting a Frame that is a view is a no-op. // Deleting a Frame that is a view is a no-op.
Unref(trigger); Unref(trigger);
Unref(closure);
if ( closure ) for ( auto& i : outer_ids )
Unref(closure); Unref(i);
Release(); Release();
} }
@ -317,32 +318,57 @@ std::pair<bool, Frame*> Frame::Unserialize(const broker::vector& data)
has_vec = broker::get_if<broker::vector>(*where); has_vec = broker::get_if<broker::vector>(*where);
if ( ! has_vec ) if ( ! has_vec )
{
for ( auto& i : outer_ids )
Unref(i);
return std::make_pair(false, nullptr); return std::make_pair(false, nullptr);
}
std::advance(where, 1); std::advance(where, 1);
auto closure_pair = Frame::Unserialize(*has_vec); auto closure_pair = Frame::Unserialize(*has_vec);
if ( ! closure_pair.first ) if ( ! closure_pair.first )
{
for ( auto& i : outer_ids )
Unref(i);
return std::make_pair(false, nullptr); return std::make_pair(false, nullptr);
}
closure = closure_pair.second; closure = closure_pair.second;
} }
auto has_vec = broker::get_if<broker::vector>(*where); auto has_vec = broker::get_if<broker::vector>(*where);
if ( ! has_vec ) if ( ! has_vec )
{
for ( auto& i : outer_ids )
Unref(i);
return std::make_pair(false, nullptr); return std::make_pair(false, nullptr);
}
std::advance(where, 1); std::advance(where, 1);
auto map_pair = UnserializeOffsetMap(*has_vec); auto map_pair = UnserializeOffsetMap(*has_vec);
if ( ! map_pair.first ) if ( ! map_pair.first )
{
for ( auto& i : outer_ids )
Unref(i);
return std::make_pair(false, nullptr); return std::make_pair(false, nullptr);
}
offset_map = std::move(map_pair.second); offset_map = std::move(map_pair.second);
auto has_body = broker::get_if<broker::vector>(*where); auto has_body = broker::get_if<broker::vector>(*where);
if ( ! has_body ) if ( ! has_body )
{
for ( auto& i : outer_ids )
Unref(i);
return std::make_pair(false, nullptr); return std::make_pair(false, nullptr);
}
broker::vector body = *has_body; broker::vector body = *has_body;
int frame_size = body.size(); int frame_size = body.size();
@ -350,6 +376,7 @@ std::pair<bool, Frame*> Frame::Unserialize(const broker::vector& data)
// We'll associate this frame with a function later. // We'll associate this frame with a function later.
Frame* rf = new Frame(frame_size, nullptr, nullptr); Frame* rf = new Frame(frame_size, nullptr, nullptr);
rf->offset_map = std::move(offset_map); rf->offset_map = std::move(offset_map);
// Frame takes ownership of unref'ing elements in outer_ids
rf->outer_ids = std::move(outer_ids); rf->outer_ids = std::move(outer_ids);
rf->closure = closure; rf->closure = closure;
@ -361,18 +388,27 @@ std::pair<bool, Frame*> Frame::Unserialize(const broker::vector& data)
broker::vector val_tuple = *has_vec; broker::vector val_tuple = *has_vec;
if ( val_tuple.size() != 2 ) if ( val_tuple.size() != 2 )
{
Unref(rf);
return std::make_pair(false, nullptr); return std::make_pair(false, nullptr);
}
auto has_type = broker::get_if<broker::integer>(val_tuple[1]); auto has_type = broker::get_if<broker::integer>(val_tuple[1]);
if ( ! has_type ) if ( ! has_type )
{
Unref(rf);
return std::make_pair(false, nullptr); return std::make_pair(false, nullptr);
}
broker::integer g = *has_type; broker::integer g = *has_type;
BroType t( static_cast<TypeTag>(g) ); BroType t( static_cast<TypeTag>(g) );
Val* val = bro_broker::data_to_val(std::move(val_tuple[0]), &t); Val* val = bro_broker::data_to_val(std::move(val_tuple[0]), &t);
if ( ! val ) if ( ! val )
{
Unref(rf);
return std::make_pair(false, nullptr); return std::make_pair(false, nullptr);
}
rf->frame[i] = val; rf->frame[i] = val;
} }
@ -391,10 +427,14 @@ void Frame::AddKnownOffsets(const id_list& ids)
void Frame::CaptureClosure(Frame* c, id_list arg_outer_ids) void Frame::CaptureClosure(Frame* c, id_list arg_outer_ids)
{ {
if ( closure ) if ( closure || outer_ids.length() )
reporter->InternalError("Attempted to override a closure."); reporter->InternalError("Attempted to override a closure.");
outer_ids = std::move(arg_outer_ids); outer_ids = std::move(arg_outer_ids);
for ( auto& i : outer_ids )
::Ref(i);
closure = c; closure = c;
if ( closure ) if ( closure )
Ref(closure); Ref(closure);
@ -467,16 +507,27 @@ Frame::UnserializeIDList(const broker::vector& data)
{ {
auto has_name = broker::get_if<std::string>(*where); auto has_name = broker::get_if<std::string>(*where);
if ( ! has_name ) if ( ! has_name )
return std::make_pair(false, std::move(rval)); {
for ( auto& i : rval )
Unref(i);
ID* id = new ID(has_name->c_str(), SCOPE_FUNCTION, false); rval = id_list{};
return std::make_pair(false, std::move(rval));
}
std::advance(where, 1); std::advance(where, 1);
auto has_offset = broker::get_if<broker::integer>(*where); auto has_offset = broker::get_if<broker::integer>(*where);
if ( ! has_offset ) if ( ! has_offset )
return std::make_pair(false, std::move(rval)); {
for ( auto& i : rval )
Unref(i);
rval = id_list{};
return std::make_pair(false, std::move(rval));
}
ID* id = new ID(has_name->c_str(), SCOPE_FUNCTION, false);
id->SetOffset(*has_offset); id->SetOffset(*has_offset);
rval.push_back(id); rval.push_back(id);
std::advance(where, 1); std::advance(where, 1);