analyzer: detect and analyze virtual function calls

2021-08-15  Ankur Saini  <arsenic@sourceware.org>

gcc/analyzer/ChangeLog:
	PR analyzer/97114
	* region-model.cc (region_model::get_rvalue_1): Add case for
	OBJ_TYPE_REF.

gcc/testsuite/ChangeLog:
	PR analyzer/97114
	* g++.dg/analyzer/vfunc-2.C: New test.
	* g++.dg/analyzer/vfunc-3.C: New test.
	* g++.dg/analyzer/vfunc-4.C: New test.
	* g++.dg/analyzer/vfunc-5.C: New test.
This commit is contained in:
Ankur Saini 2021-08-15 19:19:07 +05:30
parent aef703cf98
commit 1b34248527
5 changed files with 212 additions and 0 deletions

View File

@ -1841,6 +1841,11 @@ region_model::get_rvalue_1 (path_var pv, region_model_context *ctxt) const
const region *ref_reg = get_lvalue (pv, ctxt);
return get_store_value (ref_reg, ctxt);
}
case OBJ_TYPE_REF:
{
tree expr = OBJ_TYPE_REF_EXPR (pv.m_tree);
return get_rvalue (expr, ctxt);
}
}
}

View File

@ -0,0 +1,44 @@
#include <cstdio>
#include <cstdlib>
struct A
{
int m_data;
A() {m_data = 0;}
virtual int deallocate (void)
{
return 42;
}
};
struct B: public A
{
int *ptr;
int m_data_b;
B() {m_data_b = 0;}
void allocate ()
{
ptr = (int*)malloc(sizeof(int));
}
int deallocate (void)
{
free(ptr);
return 0;
}
};
void foo(A *a_ptr)
{
printf("%d\n",a_ptr->deallocate());
}
void test()
{
B b;
A a, *aptr;
aptr = &b;
b.allocate();
foo(aptr);
aptr = &a;
foo(aptr);
}

View File

@ -0,0 +1,32 @@
#include <cstdlib>
struct A
{
virtual int foo (void)
{
return 42;
}
};
struct B: public A
{
int *ptr;
void alloc ()
{
ptr = (int*)malloc(sizeof(int));
}
int foo (void)
{
free(ptr); /* { dg-warning "double-'free' of 'b.B::ptr'" } */
return 0;
}
};
int test ()
{
struct B b, *bptr=&b;
b.alloc ();
bptr->foo (); /* { dg-message "\\(6\\) calling 'B::foo' from 'test'" "event 6" } */
/* { dg-message "\\(9\\) returning to 'test' from 'B::foo'" "event 9" { target *-*-* } .-1 } */
return bptr->foo ();
}

View File

@ -0,0 +1,28 @@
#include "../../gcc.dg/analyzer/analyzer-decls.h"
struct A
{
int m_data;
virtual char foo ()
{
return 'A';
}
};
struct B: public A
{
int m_data_b;
char foo ()
{
return 'B';
}
};
void test()
{
A a, *a_ptr = &a;
B b;
__analyzer_eval (a_ptr->foo () == 'A'); /* { dg-warning "TRUE" } */
a_ptr = &b;
__analyzer_eval (a_ptr->foo () == 'B'); /* { dg-warning "TRUE" } */
}

View File

@ -0,0 +1,103 @@
/* { dg-additional-options "-fdiagnostics-show-line-numbers -fdiagnostics-path-format=inline-events -fanalyzer-checker=malloc -fdiagnostics-show-caret" } */
/* { dg-enable-nn-line-numbers "" } */
#include <cstdlib>
struct Base
{
virtual void allocate ();
virtual void deallocate ();
};
struct Derived: public Base
{
int *ptr;
void allocate ()
{
ptr = (int*)malloc(sizeof(int));
}
void deallocate ()
{
free(ptr);
}
};
void test()
{
Derived D;
Base B, *base_ptr;
base_ptr = &D;
D.allocate();
base_ptr->deallocate();
int n = *D.ptr; /* { dg-warning "use after 'free' of 'D.Derived::ptr'" } */
}
/* use after 'free' */
/* { dg-begin-multiline-output "" }
NN | int n = *D.ptr;
| ^
'void test()': events 1-2
|
| NN | void test()
| | ^~~~
| | |
| | (1) entry to 'test'
|......
| NN | D.allocate();
| | ~~~~~~~~~~~~
| | |
| | (2) calling 'Derived::allocate' from 'test'
|
+--> 'virtual void Derived::allocate()': events 3-4
|
| NN | void allocate ()
| | ^~~~~~~~
| | |
| | (3) entry to 'Derived::allocate'
| NN | {
| NN | ptr = (int*)malloc(sizeof(int));
| | ~~~~~~~~~~~~~~~~~~~
| | |
| | (4) allocated here
|
<------+
|
'void test()': events 5-6
|
| NN | D.allocate();
| | ~~~~~~~~~~^~
| | |
| | (5) returning to 'test' from 'Derived::allocate'
| NN | base_ptr->deallocate();
| | ~~~~~~~~~~~~~~~~~~~~~~
| | |
| | (6) calling 'Derived::deallocate' from 'test'
|
+--> 'virtual void Derived::deallocate()': events 7-8
|
| NN | void deallocate ()
| | ^~~~~~~~~~
| | |
| | (7) entry to 'Derived::deallocate'
| NN | {
| NN | free(ptr);
| | ~~~~~~~~~
| | |
| | (8) freed here
|
<------+
|
'void test()': events 9-10
|
| NN | base_ptr->deallocate();
| | ~~~~~~~~~~~~~~~~~~~~^~
| | |
| | (9) returning to 'test' from 'Derived::deallocate'
| NN | int n = *D.ptr;
| | ~
| | |
| | (10) use after 'free' of 'D.Derived::ptr'; freed at (8)
|
{ dg-end-multiline-output "" } */