Skip to content

Commit b0ec929

Browse files
Cast between semantically different integer types: HRESULT to/from a Boolean type.
Closing the gap between Semmle and PreFast. Covers C6214, C6215, C6216, C6217, C6230
1 parent 6266d8b commit b0ec929

File tree

7 files changed

+150
-0
lines changed

7 files changed

+150
-0
lines changed

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,7 @@
88
# qltest projects and artifacts
99
*/ql/test/**/*.testproj
1010
*/ql/test/**/*.actual
11+
/.vs/slnx.sqlite
12+
/.vs/ql2/v15/Browse.VC.opendb
13+
/.vs/ql2/v15/Browse.VC.db
14+
/.vs/ProjectSettings.json
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
LPMALLOC pMalloc;
2+
HRESULT hr = CoGetMalloc(1, &pMalloc);
3+
4+
if (!hr)
5+
{
6+
// code ...
7+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
6+
<overview>
7+
<p>This query indicates that an <code>HRESULT</code> is being cast to a boolean type or vice versa.</p>
8+
<p>The typical success value (<code>S_OK</code>) of an <code>HRESULT</code> equals 0. However, 0 indicates failure for a boolean type.</p>
9+
<p>Casting an <code>HRESULT</code> to a boolean type and then using it in a test expression will yield an incorrect result.</p>
10+
</overview>
11+
12+
<recommendation>
13+
<p>To check if a call that returns an HRESULT succeeded use the <code>FAILED</code> macro.</p>
14+
</recommendation>
15+
16+
<example>
17+
<p>In the following example, <code>HRESULT</code> is used in a test expression incorrectly as it may yield an incorrect result.</p>
18+
<sample src="IncorrectTypeConversion.cpp" />
19+
20+
<p>To fix this issue, use the <code>FAILED</code> macro in the test expression.</p>
21+
</example>
22+
23+
<references>
24+
</references>
25+
26+
</qhelp>
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
/**
2+
* @name Cast between semantically different integer types: HRESULT to/from a Boolean type
3+
* @description Cast between semantically different integer types: HRESULT to/from a Boolean type.
4+
* Boolean types indicate success by a non-zero value, whereas success (S_OK) in HRESULT is indicated by a value of 0.
5+
* Casting an HRESULT to/from a Boolean type and then using it in a test expression will yield an incorrect result.
6+
* @kind problem
7+
* @id cpp/incorrect-type-conversion
8+
* @problem.severity error
9+
* @precision high
10+
* @tags security
11+
* external/cwe/cwe-704
12+
* external/microsoft/C6214
13+
* external/microsoft/C6215
14+
* external/microsoft/C6216
15+
* external/microsoft/C6217
16+
* external/microsoft/C6230
17+
*/
18+
import cpp
19+
20+
from Expr e1, Cast e2, string msg
21+
where e2 = e1.getConversion() and
22+
exists ( Type t1, Type t2 |
23+
t1 = e1.getType() and
24+
t2 = e2.getType() and
25+
((t1.hasName("bool") or t1.hasName("BOOL")) and t2.hasName("HRESULT") or
26+
(t2.hasName("bool") or t2.hasName("BOOL")) and t1.hasName("HRESULT")
27+
))
28+
and if e2.isImplicit() then ( msg = "Implicit" )
29+
else ( msg = "Explicit" )
30+
select e1, msg + " conversion from " + e1.getType().toString() + " to " + e2.getType().toString()
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
// winnt.h
2+
typedef long HRESULT;
3+
#define SUCCEEDED(hr) (((HRESULT)(hr)) >= 0)
4+
#define FAILED(hr) (((HRESULT)(hr)) < 0)
5+
6+
// minwindef.h
7+
typedef int BOOL;
8+
#ifndef FALSE
9+
#define FALSE 0
10+
#endif
11+
#ifndef TRUE
12+
#define TRUE 1
13+
#endif
14+
15+
// winerror.h
16+
#define S_OK ((HRESULT)0L)
17+
#define S_FALSE ((HRESULT)1L)
18+
#define _HRESULT_TYPEDEF_(_sc) ((HRESULT)_sc)
19+
#define E_UNEXPECTED _HRESULT_TYPEDEF_(0x8000FFFFL)
20+
21+
HRESULT HresultFunction()
22+
{
23+
return S_OK;
24+
}
25+
26+
BOOL BoolFunction()
27+
{
28+
return FALSE;
29+
}
30+
31+
HRESULT IncorrectHresultFunction()
32+
{
33+
return BoolFunction(); // BUG
34+
}
35+
36+
void IncorrectTypeConversionTest() {
37+
HRESULT hr = HresultFunction();
38+
if ((BOOL)hr) // BUG
39+
{
40+
// ...
41+
}
42+
if (SUCCEEDED(hr)) // Correct Usage
43+
{
44+
// ...
45+
}
46+
47+
if (SUCCEEDED(BoolFunction())) // BUG
48+
{
49+
// ...
50+
}
51+
if (BoolFunction()) // Correct Usage
52+
{
53+
// ...
54+
}
55+
BOOL b = IncorrectHresultFunction(); // BUG
56+
57+
hr = E_UNEXPECTED;
58+
if (!hr) // BUG
59+
{
60+
// ...
61+
}
62+
if (!FAILED(hr)) // Correct Usage
63+
{
64+
// ...
65+
}
66+
67+
hr = S_FALSE;
68+
if (hr) // Should fail
69+
{
70+
// ...
71+
}
72+
if (SUCCEEDED(hr)) // Correct Usage
73+
{
74+
// ...
75+
}
76+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
| IncorrectTypeConversion.cpp:33:9:33:20 | call to BoolFunction | Implicit conversion from BOOL to HRESULT |
2+
| IncorrectTypeConversion.cpp:38:12:38:13 | hr | Explicit conversion from HRESULT to BOOL |
3+
| IncorrectTypeConversion.cpp:47:6:47:30 | (...) | Explicit conversion from BOOL to HRESULT |
4+
| IncorrectTypeConversion.cpp:55:11:55:34 | call to IncorrectHresultFunction | Implicit conversion from HRESULT to BOOL |
5+
| IncorrectTypeConversion.cpp:58:7:58:8 | hr | Implicit conversion from HRESULT to bool |
6+
| IncorrectTypeConversion.cpp:68:6:68:7 | hr | Implicit conversion from HRESULT to bool |
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Security/CWE/CWE-704/incorrectTypeConversion.ql

0 commit comments

Comments
 (0)