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:
parent
aef703cf98
commit
1b34248527
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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 ();
|
||||
}
|
|
@ -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" } */
|
||||
}
|
|
@ -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 "" } */
|
||||
|
Loading…
Reference in New Issue