// See the file "COPYING" in the main distribution directory for copyright. #include #include "broker/Data.h" #include "Frame.h" #include "Trigger.h" vector g_frame_stack; Frame::Frame(int arg_size, const BroFunc* func, const val_list *fn_args) { size = arg_size; frame = new Val*[size]; function = func; func_args = fn_args; next_stmt = nullptr; break_before_next_stmt = false; break_on_return = false; trigger = nullptr; call = nullptr; delayed = false; closure = nullptr; for (int i = 0; i < size; ++i) frame[i] = nullptr; } Frame::~Frame() { // Deleting a Frame that is a view is a no-op. Unref(trigger); if (closure) Unref(closure); Release(); } void Frame::SetElement(int n, Val* v) { Unref(frame[n]); frame[n] = v; } void Frame::SetElement(const ID* id, Val* v) { if (closure) if ( IsOuterID(id) ) { closure->SetElement(id, v); return; } // do we have an offset for it? if (offset_map.size()) { auto where = offset_map.find(std::string(id->Name())); if ( where != offset_map.end() ) { SetElement(where->second, v); } } SetElement(id->Offset(), v); } Val* Frame::GetElement(const ID* id) const { if (closure) if ( IsOuterID(id) ) { return closure->GetElement(id); } // do we have an offset for it? if ( offset_map.size() ) { auto where = offset_map.find(std::string(id->Name())); if ( where != offset_map.end() ) { return frame[where->second];\ } } return frame[id->Offset()]; } void Frame::Reset(int startIdx) { for ( int i = startIdx; i < size; ++i ) { Unref(frame[i]); frame[i] = 0; } } void Frame::Release() { for ( int i = 0; i < size; ++i ) Unref(frame[i]); delete [] frame; } void Frame::Describe(ODesc* d) const { if ( ! d->IsBinary() ) d->AddSP("frame"); if ( ! d->IsReadable() ) { d->Add(size); for ( int i = 0; i < size; ++i ) { d->Add(frame[i] != 0); d->SP(); } } for ( int i = 0; i < size; ++i ) if ( frame[i] ) frame[i]->Describe(d); else if ( d->IsReadable() ) d->Add(""); } Frame* Frame::Clone() const { Frame* other = new Frame(size, function, func_args); other->offset_map = offset_map; other->CaptureClosure(closure, outer_ids); other->trigger = trigger; if (trigger) Ref(trigger); other->call = call; for (int i = 0; i < size; i++) { other->frame[i] = frame[i] ? frame[i]->Clone() : nullptr; } return other; } Frame* Frame::SelectiveClone(const id_list& selection) const { if (selection.length() == 0) return nullptr; id_list us; // and id_list them; for (const auto& we : selection) { if ( ! IsOuterID(we) ) us.append(we); else them.append(we); } Frame* other = new Frame(size, function, func_args); for (const auto& id : us) { if ( offset_map.size() ) { auto where = offset_map.find(std::string(id->Name())); if ( where != offset_map.end() ) { other->frame[where->second] = frame[where->second]->Clone(); continue; } } if ( ! frame[id->Offset()] ) reporter->InternalError("Attempted to clone an id ('%s') with no associated value.", id->Name()); other->frame[id->Offset()] = frame[id->Offset()]->Clone(); } /** * What to do here depends on what the expected behavior of a copy * operation on a function with a closure is. As we let function's * mutate their closures, it seems reasonable that when cloned, the * clone should continue to mutate the same closure as the function * doesn't **own** the closure. Uncommenting the below if statement * will change that behavior such that the function also copies the * closure frame. */ // if (closure) // other->closure = closure->SelectiveClone(them); // other->outer_ids = outer_ids; if(closure) other->CaptureClosure(closure, outer_ids); other->offset_map = offset_map; return other; } broker::expected Frame::Serialize(const Frame* target, id_list selection) { broker::vector rval; if (selection.length() == 0) return {std::move(rval)}; id_list us; // and id_list them; std::unordered_map new_map(target->offset_map); for (const auto& we : selection) { if ( target->IsOuterID(we) ) them.append(we); else { us.append(we); new_map.insert(std::make_pair(std::string(we->Name()), we->Offset())); } } if (them.length()) { if ( ! target->closure ) reporter->InternalError("Attempting to serialize values from a frame that does not exist."); rval.emplace_back(std::string("ClosureFrame")); auto ids = SerializeIDList(target->outer_ids); if ( ! ids ) return broker::ec::invalid_data; rval.emplace_back(*ids); auto serialized = Frame::Serialize(target->closure, them); if ( ! serialized ) return broker::ec::invalid_data; rval.emplace_back(*serialized); } else rval.emplace_back(std::string("Frame")); auto map = SerializeOffsetMap(new_map); if ( ! map ) return broker::ec::invalid_data; rval.emplace_back(*map); broker::vector body; for (int i = 0; i < target->size; ++i) { body.emplace_back(broker::none()); } for (const auto& id : us) { int location = id->Offset(); auto where = new_map.find(std::string(id->Name())); if (where != new_map.end()) { location = where->second; } Val* val = target->frame[location]; TypeTag tag = val->Type()->Tag(); auto expected = bro_broker::val_to_data(val); if ( ! expected ) return broker::ec::invalid_data; broker::vector val_tuple {std::move(*expected), static_cast(tag)}; body[location] = val_tuple; } rval.emplace_back(body); return {std::move(rval)}; } std::pair Frame::Unserialize(const broker::vector& data) { if (data.size() == 0) return std::make_pair(true, nullptr); id_list outer_ids; std::unordered_map offset_map; Frame* closure = nullptr; auto where = data.begin(); auto has_name = broker::get_if(*where); if ( ! has_name ) return std::make_pair(false, nullptr); std::advance(where, 1); if (*has_name == "ClosureFrame") { auto has_vec = broker::get_if(*where); if ( ! has_vec ) return std::make_pair(false, nullptr); std::advance(where, 1); auto list_pair = UnserializeIDList(*has_vec); if ( ! list_pair.first ) return std::make_pair(false, nullptr); outer_ids = std::move(list_pair.second); has_vec = broker::get_if(*where); if ( ! has_vec ) return std::make_pair(false, nullptr); std::advance(where, 1); auto closure_pair = Frame::Unserialize(*has_vec); if ( ! closure_pair.first ) return std::make_pair(false, nullptr); closure = closure_pair.second; } auto has_vec = broker::get_if(*where); if ( ! has_vec ) return std::make_pair(false, nullptr); std::advance(where, 1); auto map_pair = UnserializeOffsetMap(*has_vec); if ( ! map_pair.first ) return std::make_pair(false, nullptr); offset_map = std::move(map_pair.second); auto has_body = broker::get_if(*where); if ( ! has_body ) return std::make_pair(false, nullptr); broker::vector body = *has_body; int frame_size = body.size(); // We'll associate this frame with a function later. Frame* rf = new Frame(frame_size, nullptr, nullptr); rf->offset_map = std::move(offset_map); rf->outer_ids = std::move(outer_ids); rf->closure = closure; for (int i = 0; i < frame_size; ++i) { auto has_vec = broker::get_if(body[i]); if ( ! has_vec ) continue; broker::vector val_tuple = *has_vec; if (val_tuple.size() != 2) return std::make_pair(false, nullptr); auto has_type = broker::get_if(val_tuple[1]); if ( ! has_type ) return std::make_pair(false, nullptr); broker::integer g = *has_type; BroType t( static_cast(g) ); Val* val = bro_broker::data_to_val(std::move(val_tuple[0]), &t); if ( ! val ) return std::make_pair(false, nullptr); rf->frame[i] = val; } return std::make_pair(true, rf); } void Frame::AddKnownOffsets(const id_list& ids) { std::transform(ids.begin(), ids.end(), std::inserter(offset_map, offset_map.end()), [] (const ID* id) -> std::pair { return std::make_pair( std::string(id->Name()), id->Offset() ); }); } void Frame::CaptureClosure(Frame* c, id_list arg_outer_ids) { if (closure) reporter->InternalError("Attempted to override a closure."); outer_ids = std::move(arg_outer_ids); closure = c; if (closure) Ref(closure); /** * Want to capture closures by copy? * You'll also need to remove the Unref in the destructor. */ // if (c) closure = c->SelectiveClone(outer_ids); } void Frame::SetTrigger(Trigger* arg_trigger) { ClearTrigger(); if ( arg_trigger ) Ref(arg_trigger); trigger = arg_trigger; } void Frame::ClearTrigger() { Unref(trigger); trigger = nullptr; } bool Frame::IsOuterID(const ID* in) const { return std::any_of(outer_ids.begin(), outer_ids.end(), [&in](ID* id)-> bool { return strcmp(id->Name(), in->Name()) == 0; }); } broker::expected Frame::SerializeIDList(const id_list& in) { broker::vector rval; for (const auto& id : in) { // name rval.emplace_back(std::string(id->Name())); // offset rval.emplace_back(id->Offset()); } return {std::move(rval)}; } broker::expected Frame::SerializeOffsetMap(const std::unordered_map& in) { broker::vector rval; std::for_each(in.begin(), in.end(), [&rval] (const std::pair& e) { rval.emplace_back(e.first); rval.emplace_back(e.second);}); return {std::move(rval)}; } std::pair Frame::UnserializeIDList(const broker::vector& data) { id_list rval; if (data.size() % 2 != 0) return std::make_pair(false, std::move(rval)); auto where = data.begin(); while (where < data.end()) { auto has_name = broker::get_if(*where); if ( ! has_name ) return std::make_pair(false, std::move(rval)); ID* id = new ID(has_name->c_str(), SCOPE_FUNCTION, false); std::advance(where, 1); auto has_offset = broker::get_if(*where); if ( ! has_offset ) return std::make_pair(false, std::move(rval)); id->SetOffset(*has_offset); rval.push_back(id); std::advance(where, 1); } return std::make_pair(true, std::move(rval)); } std::pair> Frame::UnserializeOffsetMap(const broker::vector& data) { std::unordered_map rval; for (broker::vector::size_type i = 0; i < data.size(); i += 2) { auto key = broker::get_if(data[i]); if ( ! key ) return std::make_pair(false, std::move(rval)); auto offset = broker::get_if(data[i+1]); if ( ! offset ) return std::make_pair(false, std::move(rval)); rval.insert( {std::move(*key), std::move(*offset)} ); } return std::make_pair(true, std::move(rval)); }