]> granicus.if.org Git - icinga2/commitdiff
Implement support for modifying frozen attributes
authorGunnar Beutner <gunnar.beutner@icinga.com>
Tue, 7 Aug 2018 11:55:41 +0000 (13:55 +0200)
committerGunnar Beutner <gunnar.beutner@icinga.com>
Mon, 13 Aug 2018 11:44:31 +0000 (13:44 +0200)
lib/base/array.cpp
lib/base/array.hpp
lib/base/dictionary.cpp
lib/base/dictionary.hpp
lib/base/object.cpp
lib/base/object.hpp
lib/base/reference.cpp
lib/config/expression.cpp
lib/config/expression.hpp
lib/config/vmops.hpp

index 30cf7eba38d4a8c6010354388448510532402ee0..011f3cc8f9131c99da1b16bf1adf4b3094f27225 100644 (file)
@@ -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<size_t>(index) >= GetLength())
-               Resize(index + 1);
+               Resize(index + 1, overrideFrozen);
 
-       Set(index, value);
+       Set(index, value, overrideFrozen);
 }
 
 Array::Iterator icinga::begin(const Array::Ptr& x)
index 62bcf7e2ee9d76e22820d0b56dec963a0be168e8..d6f7fcdfc2f1a4239097326078b334858ac3f41a 100644 (file)
@@ -55,9 +55,9 @@ public:
        Array(std::initializer_list<Value> 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<Value> m_Data; /**< The data for the array. */
index a645404044ce94f1a21c61918928bdc9fccf7a4a..99fd5591fb9ee9271d70c1cbabe66f88d14b9b70 100644 (file)
@@ -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<Dictionary *>(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
index 97ca81b78513082e53fa8e9cace638fcc15d2fe1..9523528a677e67d287877755cf96ed0dba3ad2c6 100644 (file)
@@ -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;
 
index b1fff79d2d77d99a812e57322d9f5521333999f2..e3ec8f7aad2f3ff9463d3175136457beda82317c 100644 (file)
@@ -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();
 
index 7836d2644362902adc0ab221a4de68244a9067bd..9d64d4af318db9bc34d428ea9e36e112b071ed16 100644 (file)
@@ -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<Value>& lvalue, const ValidationUtils& utils);
index 53f6e9e2ebb7d41e5e82af30ad0be9a1c5c7f2f3..855b60115f62a1689a31a131ce048456adecfed7 100644 (file)
@@ -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
index 94a966375ed1dc880164cb4266d1b291a891dafe..af3a7399e2abea4b690eb00caf9080597d376ef4 100644 (file)
@@ -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<Expression>& expr, ScopeSpecifier scopeSpec)
 {
        auto *dexpr = dynamic_cast<DictExpression *>(expr.get());
index ff25519b71407f2c4729942e94f5e6cb7af30937..4a7e9b0c8951b551d845df1878b3c13179a9c1ec 100644 (file)
@@ -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<Expression>& 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;
 
index 50338173000ead3ed3fdcfa70386f0bf77b85716..24224af0a89b7b4b78901f6dc17145022ee6e115 100644 (file)
@@ -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: