Skip to content

Commit 786377d

Browse files
authored
Merge pull request #408 from dave-bartolomeo/dave/NonVirtualDestructorInBaseClass
C++: Fork AV Rule 78 into NonVirtualDestructorInBaseClass
2 parents ba91f3e + 3133bf6 commit 786377d

File tree

7 files changed

+225
-1
lines changed

7 files changed

+225
-1
lines changed
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
class Base {
2+
public:
3+
Resource *p;
4+
Base() {
5+
p = createResource();
6+
}
7+
virtual void f() { //has virtual function
8+
//...
9+
}
10+
//...
11+
~Base() { //wrong: is non-virtual
12+
freeResource(p);
13+
}
14+
};
15+
16+
class Derived: public Base {
17+
public:
18+
Resource *dp;
19+
Derived() {
20+
dp = createResource2();
21+
}
22+
~Derived() {
23+
freeResource2(dp);
24+
}
25+
};
26+
27+
int f() {
28+
Base *b = new Derived(); //creates resources for both Base::p and Derived::dp
29+
//...
30+
31+
//will only call Base::~Base(), leaking the resource dp.
32+
//Change both destructors to virtual to ensure they are both called.
33+
delete b;
34+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
6+
7+
<overview>
8+
<p>
9+
This rule finds classes with virtual functions but no virtual destructor. Deleting a class without a virtual destructor will
10+
only call the destructor of the type of the pointer being deleted. This can cause a defect if the pointer type is a base
11+
type while the object instance is a derived type.
12+
</p>
13+
14+
15+
</overview>
16+
<recommendation>
17+
<p>
18+
Make sure that all classes with virtual functions also have a virtual destructor, especially if other classes derive from them.
19+
</p>
20+
21+
</recommendation>
22+
<example><sample src="NonVirtualDestructorInBaseClass.cpp" />
23+
24+
25+
26+
</example>
27+
<references>
28+
29+
<li>
30+
S. Meyers. <em>Effective C++ 3d ed.</em> pp 40-44. Addison-Wesley Professional, 2005.
31+
</li>
32+
<li>
33+
<a href="http://blogs.msdn.com/b/oldnewthing/archive/2004/05/07/127826.aspx">When should your destructor be virtual?</a>
34+
</li>
35+
36+
37+
</references>
38+
</qhelp>
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/**
2+
* @name Non-virtual destructor in base class
3+
* @description All base classes with a virtual function should define a virtual destructor. If an application attempts to delete a derived class object through a base class pointer, the result is undefined if the base class destructor is non-virtual.
4+
* @kind problem
5+
* @problem.severity warning
6+
* @precision high
7+
* @id cpp/virtual-destructor
8+
* @tags reliability
9+
* readability
10+
* language-features
11+
*/
12+
import cpp
13+
14+
// find classes with virtual functions that have a destructor that is not virtual and for which there exists a derived class
15+
// when calling the destructor of a derived class the destructor in the base class may not be called
16+
17+
from Class c
18+
where exists(VirtualFunction f | f.getDeclaringType() = c)
19+
and exists(Destructor d | d.getDeclaringType() = c and
20+
// Ignore non-public destructors, which prevent an object of the declaring class from being deleted
21+
// directly (except from within the class itself). This is a common pattern in real-world code.
22+
d.hasSpecifier("public") and
23+
not d.isVirtual() and
24+
not d.isDeleted() and
25+
not d.isCompilerGenerated())
26+
and exists(ClassDerivation d | d.getBaseClass() = c)
27+
select c, "A base class with a virtual function should define a virtual destructor."

cpp/ql/src/jsf/4.10 Classes/AV Rule 78.ql

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* @kind problem
55
* @problem.severity warning
66
* @precision high
7-
* @id cpp/virtual-destructor
7+
* @id cpp/jsf/av-rule-78
88
* @tags reliability
99
* readability
1010
* language-features
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
struct HasDtor
2+
{
3+
~HasDtor();
4+
};
5+
6+
struct Base_NonVirtual_NoDtor
7+
{
8+
void NonVirtualFunction();
9+
};
10+
11+
struct Base_NonVirtual_VirtualDtor
12+
{
13+
virtual ~Base_NonVirtual_VirtualDtor();
14+
void NonVirtualFunction();
15+
};
16+
17+
struct Base_NonVirtual_NonVirtualDtor
18+
{
19+
~Base_NonVirtual_NonVirtualDtor();
20+
void NonVirtualFunction();
21+
};
22+
23+
struct Base_NonVirtual_ImplicitDtor
24+
{
25+
HasDtor m_hasDtor;
26+
void NonVirtualFunction();
27+
};
28+
29+
struct Derived_NonVirtual_NoDtor : public Base_NonVirtual_NoDtor
30+
{
31+
};
32+
33+
struct Derived_NonVirtual_VirtualDtor : public Base_NonVirtual_VirtualDtor
34+
{
35+
};
36+
37+
struct Derived_NonVirtual_NonVirtualDtor : public Base_NonVirtual_NonVirtualDtor
38+
{
39+
};
40+
41+
struct Derived_NonVirtual_ImplicitDtor : public Base_NonVirtual_ImplicitDtor
42+
{
43+
};
44+
45+
struct Base_Virtual_NoDtor
46+
{
47+
virtual void VirtualFunction();
48+
};
49+
50+
struct Base_Virtual_VirtualDtor
51+
{
52+
virtual ~Base_Virtual_VirtualDtor();
53+
virtual void VirtualFunction();
54+
};
55+
56+
struct Base_Virtual_NonVirtualDtor
57+
{
58+
~Base_Virtual_NonVirtualDtor();
59+
virtual void VirtualFunction();
60+
};
61+
62+
struct Base_Virtual_ImplicitDtor
63+
{
64+
HasDtor m_hasDtor;
65+
virtual void VirtualFunction();
66+
};
67+
68+
struct Base_Virtual_NonVirtualDtorWithDefinition
69+
{
70+
~Base_Virtual_NonVirtualDtorWithDefinition();
71+
virtual void VirtualFunction();
72+
};
73+
74+
Base_Virtual_NonVirtualDtorWithDefinition::~Base_Virtual_NonVirtualDtorWithDefinition()
75+
{
76+
}
77+
78+
struct Base_Virtual_NonVirtualDtorWithInlineDefinition
79+
{
80+
~Base_Virtual_NonVirtualDtorWithInlineDefinition()
81+
{
82+
}
83+
virtual void VirtualFunction();
84+
};
85+
86+
struct Base_Virtual_ProtectedNonVirtualDtor
87+
{
88+
protected:
89+
~Base_Virtual_ProtectedNonVirtualDtor();
90+
91+
public:
92+
virtual void VirtualFunction();
93+
};
94+
95+
struct Derived_Virtual_NoDtor : public Base_Virtual_NoDtor
96+
{
97+
};
98+
99+
struct Derived_Virtual_VirtualDtor : public Base_Virtual_VirtualDtor
100+
{
101+
};
102+
103+
struct Derived_Virtual_NonVirtualDtor : public Base_Virtual_NonVirtualDtor
104+
{
105+
};
106+
107+
struct Derived_Virtual_ImplicitDtor : public Base_Virtual_ImplicitDtor
108+
{
109+
};
110+
111+
struct Derived_Virtual_NonVirtualDtorWithDefinition: public Base_Virtual_NonVirtualDtorWithDefinition
112+
{
113+
};
114+
115+
struct Derived_Virtual_NonVirtualDtorWithInlineDefinition: public Base_Virtual_NonVirtualDtorWithInlineDefinition
116+
{
117+
};
118+
119+
struct Derived_Virtual_ProtectedNonVirtualDtor : public Base_Virtual_ProtectedNonVirtualDtor
120+
{
121+
};
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
| NonVirtualDestructorInBaseClass.cpp:56:8:56:34 | Base_Virtual_NonVirtualDtor | A base class with a virtual function should define a virtual destructor. |
2+
| NonVirtualDestructorInBaseClass.cpp:68:8:68:48 | Base_Virtual_NonVirtualDtorWithDefinition | A base class with a virtual function should define a virtual destructor. |
3+
| NonVirtualDestructorInBaseClass.cpp:78:8:78:54 | Base_Virtual_NonVirtualDtorWithInlineDefinition | A base class with a virtual function should define a virtual destructor. |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Likely Bugs/OO/NonVirtualDestructorInBaseClass.ql

0 commit comments

Comments
 (0)