Skip to content

Commit e63e19b

Browse files
committed
Break out query into subcomponents, comments
1 parent aba87c5 commit e63e19b

2 files changed

Lines changed: 137 additions & 3 deletions

File tree

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
/**
2+
* @name Year field changed using an arithmetic operation without checking for leap year (AntiPattern 1)
3+
* @description A field that represents a year is being modified by an arithmetic operation, but no proper check for leap years can be detected afterwards.
4+
* @kind path-problem
5+
* @problem.severity warning
6+
* @id cpp/microsoft/public/leap-year/unchecked-after-arithmetic-year-modification-precise
7+
* @precision medium
8+
* @tags leap-year
9+
* correctness
10+
*/
11+
12+
import cpp
13+
import LeapYear
14+
15+
/**
16+
* The set of expressions which are ignorable; either because they seem to not be part of a year mutation,
17+
* or because they seem to be a conversion pattern of mapping date scalars.
18+
*/
19+
abstract class IgnorableOperationSource extends Expr {}
20+
21+
class IgnorableExprAssignRem extends IgnorableOperationSource instanceof AssignRemExpr{}
22+
class IgnorableExprRem extends IgnorableOperationSource instanceof RemExpr{}
23+
class IgnorableExprUnaryMinus extends IgnorableOperationSource instanceof UnaryMinusExpr{}
24+
/**
25+
* Ignore any operation that is nested inside a larger operation, assume the larger operation is the real source
26+
* */
27+
class IgnorableExprNestedExpr extends IgnorableOperationSource instanceof BinaryArithmeticOperation{
28+
IgnorableExprNestedExpr(){
29+
exists(BinaryArithmeticOperation parentOp |
30+
parentOp.getAChild+() = this
31+
)
32+
}
33+
}
34+
35+
/**
36+
* Anything involving a sub expression with char literal 48, ignore as a likely string conversion
37+
*/
38+
class IgnorableExpr48Mapping extends IgnorableOperationSource{
39+
IgnorableExpr48Mapping(){
40+
exists(SubExpr child | this.(Operation).getAChild*() = child |
41+
child.getRightOperand().(Literal).getValue().toInt() = 48
42+
or
43+
child.getRightOperand().(CharLiteral).getValue().toInt() = 48
44+
)
45+
}
46+
}
47+
48+
/**
49+
* if doing any kind of operation involving multiplying 10, 100, 1000, etc., likely some kind of conversion
50+
* and ignorable
51+
*/
52+
class IgnorableExpr10MulipleComponent extends IgnorableOperationSource{
53+
IgnorableExpr10MulipleComponent(){
54+
this.(Operation).getAChild*().(MulExpr).getAnOperand().(Literal).getValue().toInt() % 10 = 0
55+
or
56+
this.(AssignMulExpr).getRValue().(Literal).getValue().toInt() % 10 = 0
57+
}
58+
}
59+
60+
/*
61+
* linux time conversions expect the year to start from 1900, so subtracting or
62+
* adding 1900 or anything involving 1900 as a generalization is probably
63+
* a conversion that is ignorable
64+
* */
65+
class IgnorableExprExpr1900Mapping extends IgnorableOperationSource instanceof Operation{
66+
IgnorableExprExpr1900Mapping() {
67+
this.(Operation).getAnOperand().getAChild*().(Literal).getValue().toInt() = 1900
68+
}
69+
}
70+
71+
class OperationSource extends Expr {
72+
OperationSource() {
73+
(
74+
this instanceof BinaryArithmeticOperation
75+
or
76+
this instanceof UnaryArithmeticOperation
77+
or
78+
exists(AssignArithmeticOperation a | a.getRValue() = this)
79+
) and
80+
not this instanceof IgnorableOperationSource
81+
}
82+
}
83+
84+
/**
85+
* An assignment to a year field, which will be a sink
86+
*/
87+
abstract class YearFieldAssignment extends Expr{}
88+
89+
/**
90+
* An assignment to x ie `x = a`.
91+
*/
92+
class YearFieldAssignmentAccess extends YearFieldAssignment{
93+
YearFieldAssignmentAccess(){
94+
// TODO: why can't I make this just the L value? Doesn't seem to work
95+
exists(Assignment a |
96+
a.getLValue() instanceof YearFieldAccess and
97+
a.getRValue() = this
98+
)
99+
}
100+
}
101+
102+
/**
103+
*
104+
*/
105+
class YearFieldAssignmentUnary extends YearFieldAssignment instanceof UnaryArithmeticOperation{
106+
YearFieldAssignmentUnary(){
107+
this.getOperand() instanceof YearFieldAccess and
108+
}
109+
}
110+
111+
/**
112+
* A DataFlow configuration for identifying flows from some non trivial access or literal
113+
* to the Year field of a date object.
114+
*/
115+
module OperationToYearAssignmentConfig implements DataFlow::ConfigSig {
116+
predicate isSource(DataFlow::Node n) { n.asExpr() instanceof OperationSource }
117+
118+
predicate isSink(DataFlow::Node n) { n.asExpr() instanceof YearFieldAssignment }
119+
120+
predicate isBarrier(DataFlow::Node n) {
121+
exists(ArrayExpr arr | arr.getArrayOffset() = n.asExpr())
122+
or
123+
n.asExpr().getUnspecifiedType() instanceof PointerType
124+
or
125+
n.asExpr() instanceof IgnorableOperationSource
126+
or
127+
exists(ChecksForLeapYearFunctionCall fc | fc.getAnArgument() = n.asExpr())
128+
}
129+
}
130+
131+
module OperationToYearAssignmentFlow = TaintTracking::Global<OperationToYearAssignmentConfig>;
132+
import OperationToYearAssignmentFlow::PathGraph
133+
134+
from OperationToYearAssignmentFlow::PathNode src, OperationToYearAssignmentFlow::PathNode sink
135+
where OperationToYearAssignmentFlow::flowPath(src, sink)
136+
select sink, src, sink, "TEST"

cpp/ql/test/query-tests/Likely Bugs/Leap Year/UncheckedLeapYearAfterYearModification/test.cpp

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1036,9 +1036,7 @@ FMAPITimeToSysTimeW(LPCWSTR wszTime, SYSTEMTIME *psystime)
10361036
* Modification of SYSTEMTIME struct by copying from another struct, but no arithmetic is performed.
10371037
*/
10381038
bool
1039-
ATime::HrGetSysTime(
1040-
SYSTEMTIME *pst
1041-
) const
1039+
ATime_HrGetSysTime(SYSTEMTIME *pst)
10421040
{
10431041
// if (!FValidSysTime())
10441042
// {

0 commit comments

Comments
 (0)