virtual void add(ElementPtr element);
/// @brief Removes the element at the given position. If the index is out
- /// of nothing happens.
+ /// of bounds, nothing happens.
/// @param i The index of the element to remove.
virtual void remove(const int i);
}
void add(ElementPtr e) { l.push_back(e); }
using Element::remove;
- void remove(int i) { l.erase(l.begin() + i); }
+ /// @brief Removes the element at the given position.
+ ///
+ /// If the index is out of bounds, nothing happens.
+ void remove(int i) {
+ if (i >= 0 && static_cast<size_t>(i) < l.size()) {
+ l.erase(l.begin() + i);
+ }
+ }
void toJSON(std::ostream& ss,
unsigned level = MAX_NESTING_LEVEL) const;
size_t size() const { return (l.size()); }
EXPECT_ANY_THROW(el->set(3, Element::create(0)));
}
+// Verifies that ListElement::remove() is a no-op for out-of-range indices
+// rather than invoking undefined behavior (Gitlab #4636).
+TEST(Element, listElementRemoveOutOfRange) {
+ ElementPtr el = Element::fromJSON("[ 1, 2 ]");
+ ASSERT_EQ(2, static_cast<int>(el->size()));
+
+ // Index past the end should be a no-op.
+ EXPECT_NO_THROW(el->remove(5));
+ EXPECT_EQ(2, static_cast<int>(el->size()));
+ EXPECT_EQ("[ 1, 2 ]", el->str());
+
+ // Index equal to size should be a no-op.
+ EXPECT_NO_THROW(el->remove(2));
+ EXPECT_EQ(2, static_cast<int>(el->size()));
+ EXPECT_EQ("[ 1, 2 ]", el->str());
+
+ // Negative index should be a no-op.
+ EXPECT_NO_THROW(el->remove(-1));
+ EXPECT_EQ(2, static_cast<int>(el->size()));
+ EXPECT_EQ("[ 1, 2 ]", el->str());
+
+ // Empty list: any remove should be a no-op.
+ ElementPtr empty = Element::createList();
+ EXPECT_NO_THROW(empty->remove(0));
+ EXPECT_TRUE(empty->empty());
+
+ // In-range remove still works.
+ EXPECT_NO_THROW(el->remove(0));
+ EXPECT_EQ(1, static_cast<int>(el->size()));
+ EXPECT_EQ(2, el->get(0)->intValue());
+}
+
TEST(Element, mapElement) {
// this function checks the specific functions for ListElements
ElementPtr el = Element::fromJSON("{ \"name\": \"foo\", "