Skip to content

Commit c7f9de9

Browse files
StaticInitializer: CodeQL port of C28651 (#156)
* WIP C28651 * Codeql port of C28651 * remove TODOs
1 parent 2a7c167 commit c7f9de9

File tree

4 files changed

+702
-0
lines changed

4 files changed

+702
-0
lines changed
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
<!DOCTYPE qhelp PUBLIC "-//Semmle//qhelp//EN" "qhelp.dtd">
2+
<qhelp>
3+
<overview>
4+
<p>
5+
Static initializers of global or static const variables can often
6+
be fully evaluated at compile time, thus generated in RDATA.
7+
However if any initializer is a pointer-to-member-function where
8+
it is a non-static function, the entire initialier may be placed
9+
in copy-on-write pages, which has a performance cost.
10+
</p>
11+
</overview>
12+
<recommendation>
13+
<p>
14+
For binaries which require fast loading and minimizing copy on
15+
write pages, consider making sure all function pointer in the
16+
static initializer are not pointer-to-member-function. If a
17+
pointer-to-member-function is required, write a simple static
18+
member function that wraps a call to the actual member function.
19+
</p>
20+
</recommendation>
21+
<example>
22+
<p>
23+
Code which triggers this query:
24+
</p>
25+
<sample language="c"> <![CDATA[
26+
class MyClass
27+
{
28+
...
29+
bool memberFunc();
30+
...
31+
};
32+
const StructType MyStruct[] = {
33+
...
34+
&MyClass::memberFunc,
35+
...
36+
};
37+
]]>
38+
</sample>
39+
<p>
40+
Good code:
41+
</p>
42+
<sample language="c"> <![CDATA[
43+
class MyClass
44+
{
45+
...
46+
bool memberFunc();
47+
static bool memberFuncWrap(MyClass *thisPtr)
48+
{ return thisPtr->memberFunc(); }
49+
...
50+
};
51+
const StructType MyStruct[] = {
52+
...
53+
&MyClass::memberFuncWrap,
54+
...
55+
};
56+
]]>
57+
</sample>
58+
</example>
59+
<semmleNotes>
60+
<p>
61+
62+
</p>
63+
</semmleNotes>
64+
<references>
65+
<li>
66+
<a href="https://learn.microsoft.com/en-us/windows-hardware/drivers/devtest/28651-member-function-pointers-cause-write-pages-copy">
67+
C28651
68+
</a>
69+
</li>
70+
</references>
71+
</qhelp>
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
// Copyright (c) Microsoft Corporation.
2+
// Licensed under the MIT license.
3+
/**
4+
* @id cpp/drivers/static-initializer
5+
* @kind problem
6+
* @name Static Initializer
7+
* @description Static initializers of global or static const variables can often
8+
* be fully evaluated at compile time, thus generated in RDATA.
9+
* However if any initializer is a pointer-to-member-function where
10+
* it is a non-static function, the entire initialier may be placed
11+
* in copy-on-write pages, which has a performance cost.
12+
* @platform Desktop
13+
* @feature.area Multiple
14+
* @impact Insecure Coding Practice
15+
* @repro.text For binaries which require fast loading and minimizing copy on
16+
* write pages, consider making sure all function pointer in the
17+
* static initializer are not pointer-to-member-function. If a
18+
* pointer-to-member-function is required, write a simple static
19+
* member function that wraps a call to the actual member function.
20+
* @owner.email: [email protected]
21+
* @opaqueid CQLD-C28651
22+
* @problem.severity warning
23+
* @precision medium
24+
* @tags performance
25+
* @scope domainspecific
26+
* @query-version v1
27+
*/
28+
29+
import cpp
30+
31+
// Initalizer that is a pointer to a member function that is a non-static function
32+
from Initializer i, FunctionAccess f
33+
where
34+
f.getParent*() = i.getExpr() and
35+
f.getTarget() instanceof MemberFunction and
36+
not f.getTarget().getADeclarationEntry().getDeclaration().isStatic() and
37+
(
38+
i.getDeclaration() instanceof GlobalVariable
39+
or
40+
(i.getDeclaration().isStatic() and i.getDeclaration().(Variable).isConst())
41+
)
42+
//global or static const
43+
select f, "Static initializer causes copy on write pages due to member function pointer(s): $@", f.getTarget(), f.getTarget().getName()

0 commit comments

Comments
 (0)