Skip to content

Commit

Permalink
Merge pull request #15934 from MathiasVP/ir-models-for-iterators
Browse files Browse the repository at this point in the history
C++: Add alias and side-effect models to `begin` and `end` functions
  • Loading branch information
MathiasVP authored Mar 18, 2024
2 parents a13391b + 0be329d commit e0476b5
Show file tree
Hide file tree
Showing 7 changed files with 28,488 additions and 28,084 deletions.
22 changes: 21 additions & 1 deletion cpp/ql/lib/semmle/code/cpp/models/implementations/Iterator.qll
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ import cpp
import semmle.code.cpp.models.interfaces.Taint
import semmle.code.cpp.models.interfaces.DataFlow
import semmle.code.cpp.models.interfaces.Iterator
import semmle.code.cpp.models.interfaces.Alias
import semmle.code.cpp.models.interfaces.SideEffect

/**
* An instantiation of the `std::iterator_traits` template.
Expand Down Expand Up @@ -438,7 +440,9 @@ private class IteratorAssignmentMemberOperatorModel extends IteratorAssignmentMe
* A `begin` or `end` member function, or a related member function, that
* returns an iterator.
*/
private class BeginOrEndFunction extends MemberFunction, TaintFunction, GetIteratorFunction {
private class BeginOrEndFunction extends MemberFunction, TaintFunction, GetIteratorFunction,
AliasFunction, SideEffectFunction
{
BeginOrEndFunction() {
this.hasName([
"begin", "cbegin", "rbegin", "crbegin", "end", "cend", "rend", "crend", "before_begin",
Expand All @@ -456,6 +460,22 @@ private class BeginOrEndFunction extends MemberFunction, TaintFunction, GetItera
input.isQualifierObject() and
output.isReturnValue()
}

override predicate parameterNeverEscapes(int index) { index = -1 }

override predicate parameterEscapesOnlyViaReturn(int index) { none() }

override predicate hasOnlySpecificReadSideEffects() { any() }

override predicate hasOnlySpecificWriteSideEffects() { any() }

override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
none()
}

override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = -1 and buffer = false
}
}

/**
Expand Down
16,283 changes: 8,233 additions & 8,050 deletions cpp/ql/test/library-tests/ir/ir/PrintAST.expected

Large diffs are not rendered by default.

14,421 changes: 7,235 additions & 7,186 deletions cpp/ql/test/library-tests/ir/ir/aliased_ir.expected

Large diffs are not rendered by default.

89 changes: 68 additions & 21 deletions cpp/ql/test/library-tests/ir/ir/ir.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1055,28 +1055,75 @@ void Lambda(int x, const String& s) {
lambda_inits(6);
}

template<typename T>
struct vector {
namespace std {
template<class T>
struct remove_const { typedef T type; };

template<class T>
struct remove_const<const T> { typedef T type; };

// `remove_const_t<T>` removes any `const` specifier from `T`
template<class T>
using remove_const_t = typename remove_const<T>::type;

struct ptrdiff_t;

template<class I> struct iterator_traits;

template <class Category,
class value_type,
class difference_type = ptrdiff_t,
class pointer_type = value_type*,
class reference_type = value_type&>
struct iterator {
T* p;
iterator& operator++();
T& operator*() const;
typedef Category iterator_category;

iterator();
iterator(iterator<Category, remove_const_t<value_type> > const &other); // non-const -> const conversion constructor

iterator &operator++();
iterator operator++(int);
iterator &operator--();
iterator operator--(int);
bool operator==(iterator other) const;
bool operator!=(iterator other) const;
reference_type operator*() const;
pointer_type operator->() const;
iterator operator+(int);
iterator operator-(int);
iterator &operator+=(int);
iterator &operator-=(int);
int operator-(iterator);
reference_type operator[](int);
};

struct input_iterator_tag {};
struct forward_iterator_tag : public input_iterator_tag {};
struct bidirectional_iterator_tag : public forward_iterator_tag {};
struct random_access_iterator_tag : public bidirectional_iterator_tag {};

struct output_iterator_tag {};

bool operator!=(iterator right) const;
template<typename T>
struct vector {
vector(T);
~vector();

using iterator = std::iterator<random_access_iterator_tag, T>;
using const_iterator = std::iterator<random_access_iterator_tag, const T>;

iterator begin() const;
iterator end() const;
};

vector(T);
~vector();
iterator begin() const;
iterator end() const;
};
template<typename T>
bool operator==(typename vector<T>::iterator left, typename vector<T>::iterator right);
template<typename T>
bool operator!=(typename vector<T>::iterator left, typename vector<T>::iterator right);

template<typename T>
bool operator==(typename vector<T>::iterator left, typename vector<T>::iterator right);
template<typename T>
bool operator!=(typename vector<T>::iterator left, typename vector<T>::iterator right);
}

void RangeBasedFor(const vector<int>& v) {
void RangeBasedFor(const std::vector<int>& v) {
for (int e : v) {
if (e > 0) {
continue;
Expand Down Expand Up @@ -2151,21 +2198,21 @@ void initialization_with_destructor(bool b, char c) {
}

ClassWithDestructor x;
for(vector<ClassWithDestructor> ys(x); ClassWithDestructor y : ys)
for(std::vector<ClassWithDestructor> ys(x); ClassWithDestructor y : ys)
y.set_x('a');

for(vector<ClassWithDestructor> ys(x); ClassWithDestructor y : ys) {
for(std::vector<ClassWithDestructor> ys(x); ClassWithDestructor y : ys) {
y.set_x('a');
if (y.get_x() == 'b')
return;
}

for(vector<int> ys(1); int y : ys) {
for(std::vector<int> ys(1); int y : ys) {
if (y == 1)
return;
}

for(vector<ClassWithDestructor> ys(x); ClassWithDestructor y : ys) {
for(std::vector<ClassWithDestructor> ys(x); ClassWithDestructor y : ys) {
ClassWithDestructor z1;
ClassWithDestructor z2;
}
Expand Down Expand Up @@ -2243,7 +2290,7 @@ void ForDestructors() {
String s2;
}

for(String s : vector<String>(String("hello"))) {
for(String s : std::vector<String>(String("hello"))) {
String s2;
}

Expand Down
Loading

0 comments on commit e0476b5

Please sign in to comment.