From 9d513d8f0570602abdd7cd65d1df62d259190ed1 Mon Sep 17 00:00:00 2001 From: Gunnar Beutner Date: Tue, 7 Aug 2018 13:55:41 +0200 Subject: [PATCH] Implement support for modifying frozen attributes --- lib/base/array.cpp | 54 ++++++++++++++++++++++----------------- lib/base/array.hpp | 22 ++++++++-------- lib/base/dictionary.cpp | 27 ++++++++++++-------- lib/base/dictionary.hpp | 10 ++++---- lib/base/object.cpp | 2 +- lib/base/object.hpp | 2 +- lib/base/reference.cpp | 2 +- lib/config/expression.cpp | 14 ++++++++-- lib/config/expression.hpp | 7 +++++ lib/config/vmops.hpp | 4 +-- 10 files changed, 86 insertions(+), 58 deletions(-) diff --git a/lib/base/array.cpp b/lib/base/array.cpp index 30cf7eba3..011f3cc8f 100644 --- a/lib/base/array.cpp +++ b/lib/base/array.cpp @@ -62,13 +62,14 @@ Value Array::Get(SizeType index) const * * @param index The index. * @param value The value. + * @param overrideFrozen Whether to allow modifying frozen arrays. */ -void Array::Set(SizeType index, const Value& value) +void Array::Set(SizeType index, const Value& value, bool overrideFrozen) { ObjectLock olock(this); - if (m_Frozen) - BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified.")); + if (m_Frozen && !overrideFrozen) + BOOST_THROW_EXCEPTION(std::invalid_argument("Value in array must not be modified.")); m_Data.at(index) = value; } @@ -78,12 +79,13 @@ void Array::Set(SizeType index, const Value& value) * * @param index The index. * @param value The value. + * @param overrideFrozen Whether to allow modifying frozen arrays. */ -void Array::Set(SizeType index, Value&& value) +void Array::Set(SizeType index, Value&& value, bool overrideFrozen) { ObjectLock olock(this); - if (m_Frozen) + if (m_Frozen && !overrideFrozen) BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified.")); m_Data.at(index).Swap(value); @@ -93,12 +95,13 @@ void Array::Set(SizeType index, Value&& value) * Adds a value to the array. * * @param value The value. + * @param overrideFrozen Whether to allow modifying frozen arrays. */ -void Array::Add(Value value) +void Array::Add(Value value, bool overrideFrozen) { ObjectLock olock(this); - if (m_Frozen) + if (m_Frozen && !overrideFrozen) BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified.")); m_Data.push_back(std::move(value)); @@ -162,14 +165,15 @@ bool Array::Contains(const Value& value) const * * @param index The index * @param value The value to add + * @param overrideFrozen Whether to allow modifying frozen arrays. */ -void Array::Insert(SizeType index, Value value) +void Array::Insert(SizeType index, Value value, bool overrideFrozen) { ObjectLock olock(this); ASSERT(index <= m_Data.size()); - if (m_Frozen) + if (m_Frozen && !overrideFrozen) BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified.")); m_Data.insert(m_Data.begin() + index, std::move(value)); @@ -179,12 +183,13 @@ void Array::Insert(SizeType index, Value value) * Removes the specified index from the array. * * @param index The index. + * @param overrideFrozen Whether to allow modifying frozen arrays. */ -void Array::Remove(SizeType index) +void Array::Remove(SizeType index, bool overrideFrozen) { ObjectLock olock(this); - if (m_Frozen) + if (m_Frozen && !overrideFrozen) BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified.")); m_Data.erase(m_Data.begin() + index); @@ -194,42 +199,43 @@ void Array::Remove(SizeType index) * Removes the item specified by the iterator from the array. * * @param it The iterator. + * @param overrideFrozen Whether to allow modifying frozen arrays. */ -void Array::Remove(Array::Iterator it) +void Array::Remove(Array::Iterator it, bool overrideFrozen) { ASSERT(OwnsLock()); - if (m_Frozen) + if (m_Frozen && !overrideFrozen) BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified.")); m_Data.erase(it); } -void Array::Resize(SizeType newSize) +void Array::Resize(SizeType newSize, bool overrideFrozen) { ObjectLock olock(this); - if (m_Frozen) + if (m_Frozen && !overrideFrozen) BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified.")); m_Data.resize(newSize); } -void Array::Clear() +void Array::Clear(bool overrideFrozen) { ObjectLock olock(this); - if (m_Frozen) + if (m_Frozen && !overrideFrozen) BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified.")); m_Data.clear(); } -void Array::Reserve(SizeType newSize) +void Array::Reserve(SizeType newSize, bool overrideFrozen) { ObjectLock olock(this); - if (m_Frozen) + if (m_Frozen && !overrideFrozen) BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified.")); m_Data.reserve(newSize); @@ -288,11 +294,11 @@ Array::Ptr Array::Reverse() const return result; } -void Array::Sort() +void Array::Sort(bool overrideFrozen) { ObjectLock olock(this); - if (m_Frozen) + if (m_Frozen && !overrideFrozen) BOOST_THROW_EXCEPTION(std::invalid_argument("Array must not be modified.")); std::sort(m_Data.begin(), m_Data.end()); @@ -342,7 +348,7 @@ Value Array::GetFieldByName(const String& field, bool sandboxed, const DebugInfo return Get(index); } -void Array::SetFieldByName(const String& field, const Value& value, const DebugInfo& debugInfo) +void Array::SetFieldByName(const String& field, const Value& value, bool overrideFrozen, const DebugInfo& debugInfo) { ObjectLock olock(this); @@ -352,9 +358,9 @@ void Array::SetFieldByName(const String& field, const Value& value, const DebugI BOOST_THROW_EXCEPTION(ScriptError("Array index '" + Convert::ToString(index) + "' is out of bounds.", debugInfo)); if (static_cast(index) >= GetLength()) - Resize(index + 1); + Resize(index + 1, overrideFrozen); - Set(index, value); + Set(index, value, overrideFrozen); } Array::Iterator icinga::begin(const Array::Ptr& x) diff --git a/lib/base/array.hpp b/lib/base/array.hpp index 62bcf7e2e..d6f7fcdfc 100644 --- a/lib/base/array.hpp +++ b/lib/base/array.hpp @@ -55,9 +55,9 @@ public: Array(std::initializer_list init); Value Get(SizeType index) const; - void Set(SizeType index, const Value& value); - void Set(SizeType index, Value&& value); - void Add(Value value); + void Set(SizeType index, const Value& value, bool overrideFrozen = false); + void Set(SizeType index, Value&& value, bool overrideFrozen = false); + void Add(Value value, bool overrideFrozen = false); Iterator Begin(); Iterator End(); @@ -65,14 +65,14 @@ public: size_t GetLength() const; bool Contains(const Value& value) const; - void Insert(SizeType index, Value value); - void Remove(SizeType index); - void Remove(Iterator it); + void Insert(SizeType index, Value value, bool overrideFrozen = false); + void Remove(SizeType index, bool overrideFrozen = false); + void Remove(Iterator it, bool overrideFrozen = false); - void Resize(SizeType newSize); - void Clear(); + void Resize(SizeType newSize, bool overrideFrozen = false); + void Clear(bool overrideFrozen = false); - void Reserve(SizeType newSize); + void Reserve(SizeType newSize, bool overrideFrozen = false); void CopyTo(const Array::Ptr& dest) const; Array::Ptr ShallowClone() const; @@ -108,7 +108,7 @@ public: Array::Ptr Reverse() const; - void Sort(); + void Sort(bool overrideFrozen = false); String ToString() const override; @@ -116,7 +116,7 @@ public: void Freeze(); Value GetFieldByName(const String& field, bool sandboxed, const DebugInfo& debugInfo) const override; - void SetFieldByName(const String& field, const Value& value, const DebugInfo& debugInfo) override; + void SetFieldByName(const String& field, const Value& value, bool overrideFrozen, const DebugInfo& debugInfo) override; private: std::vector m_Data; /**< The data for the array. */ diff --git a/lib/base/dictionary.cpp b/lib/base/dictionary.cpp index a64540404..99fd5591f 100644 --- a/lib/base/dictionary.cpp +++ b/lib/base/dictionary.cpp @@ -89,13 +89,14 @@ bool Dictionary::Get(const String& key, Value *result) const * * @param key The key. * @param value The value. + * @param overrideFrozen Whether to allow modifying frozen dictionaries. */ -void Dictionary::Set(const String& key, Value value) +void Dictionary::Set(const String& key, Value value, bool overrideFrozen) { ObjectLock olock(this); - if (m_Frozen) - BOOST_THROW_EXCEPTION(std::invalid_argument("Dictionary must not be modified.")); + if (m_Frozen && !overrideFrozen) + BOOST_THROW_EXCEPTION(std::invalid_argument("Value in dictionary must not be modified.")); m_Data[key] = std::move(value); } @@ -157,12 +158,13 @@ Dictionary::Iterator Dictionary::End() * Removes the item specified by the iterator from the dictionary. * * @param it The iterator. + * @param overrideFrozen Whether to allow modifying frozen dictionaries. */ -void Dictionary::Remove(Dictionary::Iterator it) +void Dictionary::Remove(Dictionary::Iterator it, bool overrideFrozen) { ASSERT(OwnsLock()); - if (m_Frozen) + if (m_Frozen && !overrideFrozen) BOOST_THROW_EXCEPTION(std::invalid_argument("Dictionary must not be modified.")); m_Data.erase(it); @@ -172,12 +174,13 @@ void Dictionary::Remove(Dictionary::Iterator it) * Removes the specified key from the dictionary. * * @param key The key. + * @param overrideFrozen Whether to allow modifying frozen dictionaries. */ -void Dictionary::Remove(const String& key) +void Dictionary::Remove(const String& key, bool overrideFrozen) { ObjectLock olock(this); - if (m_Frozen) + if (m_Frozen && !overrideFrozen) BOOST_THROW_EXCEPTION(std::invalid_argument("Dictionary must not be modified.")); Dictionary::Iterator it; @@ -191,12 +194,14 @@ void Dictionary::Remove(const String& key) /** * Removes all dictionary items. + * + * @param overrideFrozen Whether to allow modifying frozen dictionaries. */ -void Dictionary::Clear() +void Dictionary::Clear(bool overrideFrozen) { ObjectLock olock(this); - if (m_Frozen) + if (m_Frozen && !overrideFrozen) BOOST_THROW_EXCEPTION(std::invalid_argument("Dictionary must not be modified.")); m_Data.clear(); @@ -288,9 +293,9 @@ Value Dictionary::GetFieldByName(const String& field, bool, const DebugInfo& deb return GetPrototypeField(const_cast(this), field, false, debugInfo); } -void Dictionary::SetFieldByName(const String& field, const Value& value, const DebugInfo&) +void Dictionary::SetFieldByName(const String& field, const Value& value, bool overrideFrozen, const DebugInfo&) { - Set(field, value); + Set(field, value, overrideFrozen); } bool Dictionary::HasOwnField(const String& field) const diff --git a/lib/base/dictionary.hpp b/lib/base/dictionary.hpp index 97ca81b78..9523528a6 100644 --- a/lib/base/dictionary.hpp +++ b/lib/base/dictionary.hpp @@ -58,7 +58,7 @@ public: Value Get(const String& key) const; bool Get(const String& key, Value *result) const; - void Set(const String& key, Value value); + void Set(const String& key, Value value, bool overrideFrozen = false); bool Contains(const String& key) const; Iterator Begin(); @@ -66,11 +66,11 @@ public: size_t GetLength() const; - void Remove(const String& key); + void Remove(const String& key, bool overrideFrozen = false); - void Remove(Iterator it); + void Remove(Iterator it, bool overrideFrozen = false); - void Clear(); + void Clear(bool overrideFrozen = false); void CopyTo(const Dictionary::Ptr& dest) const; Dictionary::Ptr ShallowClone() const; @@ -86,7 +86,7 @@ public: void Freeze(); Value GetFieldByName(const String& field, bool sandboxed, const DebugInfo& debugInfo) const override; - void SetFieldByName(const String& field, const Value& value, const DebugInfo& debugInfo) override; + void SetFieldByName(const String& field, const Value& value, bool overrideFrozen, const DebugInfo& debugInfo) override; bool HasOwnField(const String& field) const override; bool GetOwnField(const String& field, Value *result) const override; diff --git a/lib/base/object.cpp b/lib/base/object.cpp index b1fff79d2..e3ec8f7aa 100644 --- a/lib/base/object.cpp +++ b/lib/base/object.cpp @@ -138,7 +138,7 @@ Value Object::GetFieldByName(const String& field, bool sandboxed, const DebugInf return GetField(fid); } -void Object::SetFieldByName(const String& field, const Value& value, const DebugInfo& debugInfo) +void Object::SetFieldByName(const String& field, const Value& value, bool overrideFrozen, const DebugInfo& debugInfo) { Type::Ptr type = GetReflectionType(); diff --git a/lib/base/object.hpp b/lib/base/object.hpp index 7836d2644..9d64d4af3 100644 --- a/lib/base/object.hpp +++ b/lib/base/object.hpp @@ -183,7 +183,7 @@ public: virtual void SetField(int id, const Value& value, bool suppress_events = false, const Value& cookie = Empty); virtual Value GetField(int id) const; virtual Value GetFieldByName(const String& field, bool sandboxed, const DebugInfo& debugInfo) const; - virtual void SetFieldByName(const String& field, const Value& value, const DebugInfo& debugInfo); + virtual void SetFieldByName(const String& field, const Value& value, bool overrideFrozen, const DebugInfo& debugInfo); virtual bool HasOwnField(const String& field) const; virtual bool GetOwnField(const String& field, Value *result) const; virtual void ValidateField(int id, const Lazy& lvalue, const ValidationUtils& utils); diff --git a/lib/base/reference.cpp b/lib/base/reference.cpp index 53f6e9e2e..855b60115 100644 --- a/lib/base/reference.cpp +++ b/lib/base/reference.cpp @@ -41,7 +41,7 @@ Value Reference::Get() const void Reference::Set(const Value& value) { - m_Parent->SetFieldByName(m_Index, value, DebugInfo()); + m_Parent->SetFieldByName(m_Index, value, false, DebugInfo()); } Object::Ptr Reference::GetParent() const diff --git a/lib/config/expression.cpp b/lib/config/expression.cpp index 94a966375..af3a7399e 100644 --- a/lib/config/expression.cpp +++ b/lib/config/expression.cpp @@ -608,7 +608,7 @@ ExpressionResult SetExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) } } - VMOps::SetField(parent, index, operand2.GetValue(), m_DebugInfo); + VMOps::SetField(parent, index, operand2.GetValue(), m_OverrideFrozen, m_DebugInfo); if (psdhint) { psdhint->AddMessage("=", m_DebugInfo); @@ -620,6 +620,11 @@ ExpressionResult SetExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) return Empty; } +void SetExpression::SetOverrideFrozen() +{ + m_OverrideFrozen = true; +} + ExpressionResult ConditionalExpression::DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const { ExpressionResult condition = m_Condition->Evaluate(frame, dhint); @@ -699,7 +704,7 @@ bool IndexerExpression::GetReference(ScriptFrame& frame, bool init_dict, Value * Value old_value = VMOps::GetField(vparent, vindex, frame.Sandboxed, m_Operand1->GetDebugInfo()); if (old_value.IsEmpty() && !old_value.IsString()) - VMOps::SetField(vparent, vindex, new Dictionary(), m_Operand1->GetDebugInfo()); + VMOps::SetField(vparent, vindex, new Dictionary(), m_OverrideFrozen, m_Operand1->GetDebugInfo()); } *parent = VMOps::GetField(vparent, vindex, frame.Sandboxed, m_DebugInfo); @@ -725,6 +730,11 @@ bool IndexerExpression::GetReference(ScriptFrame& frame, bool init_dict, Value * return true; } +void IndexerExpression::SetOverrideFrozen() +{ + m_OverrideFrozen = true; +} + void icinga::BindToScope(std::unique_ptr& expr, ScopeSpecifier scopeSpec) { auto *dexpr = dynamic_cast(expr.get()); diff --git a/lib/config/expression.hpp b/lib/config/expression.hpp index ff25519b7..4a7e9b0c8 100644 --- a/lib/config/expression.hpp +++ b/lib/config/expression.hpp @@ -644,11 +644,14 @@ public: : BinaryExpression(std::move(operand1), std::move(operand2), debugInfo), m_Op(op) { } + void SetOverrideFrozen(); + protected: ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; private: CombinedSetOp m_Op; + bool m_OverrideFrozen{false}; friend void BindToScope(std::unique_ptr& expr, ScopeSpecifier scopeSpec); }; @@ -739,7 +742,11 @@ public: : BinaryExpression(std::move(operand1), std::move(operand2), debugInfo) { } + void SetOverrideFrozen(); + protected: + bool m_OverrideFrozen{false}; + ExpressionResult DoEvaluate(ScriptFrame& frame, DebugHint *dhint) const override; bool GetReference(ScriptFrame& frame, bool init_dict, Value *parent, String *index, DebugHint **dhint) const override; diff --git a/lib/config/vmops.hpp b/lib/config/vmops.hpp index 503381730..24224af0a 100644 --- a/lib/config/vmops.hpp +++ b/lib/config/vmops.hpp @@ -244,12 +244,12 @@ public: return object->GetFieldByName(field, sandboxed, debugInfo); } - static inline void SetField(const Object::Ptr& context, const String& field, const Value& value, const DebugInfo& debugInfo = DebugInfo()) + static inline void SetField(const Object::Ptr& context, const String& field, const Value& value, bool overrideFrozen, const DebugInfo& debugInfo = DebugInfo()) { if (!context) BOOST_THROW_EXCEPTION(ScriptError("Cannot set field '" + field + "' on a value that is not an object.", debugInfo)); - return context->SetFieldByName(field, value, debugInfo); + return context->SetFieldByName(field, value, overrideFrozen, debugInfo); } private: -- 2.40.0