Skip to content

Commit d45b417

Browse files
authored
Merge pull request #1497 from geoffw0/dates-5
CPP: General clean up for the new dates queries
2 parents 31614fd + ac5b62c commit d45b417

File tree

8 files changed

+106
-107
lines changed

8 files changed

+106
-107
lines changed

cpp/ql/src/Likely Bugs/Leap Year/Adding365DaysPerYear.ql

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@
55
* @problem.severity warning
66
* @id cpp/leap-year/adding-365-days-per-year
77
* @precision medium
8-
* @tags security
9-
* leap-year
8+
* @tags leap-year
109
*/
1110

1211
import cpp

cpp/ql/src/Likely Bugs/Leap Year/LeapYear.qll

Lines changed: 30 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/**
2-
* Provides a library for helping create leap year related queries
2+
* Provides a library for helping create leap year related queries.
33
*/
44

55
import cpp
@@ -8,18 +8,18 @@ import semmle.code.cpp.controlflow.Guards
88
import semmle.code.cpp.commons.DateTime
99

1010
/**
11-
* Get the top-level BinaryOperation enclosing the expression e
11+
* Get the top-level `BinaryOperation` enclosing the expression e.
1212
*/
13-
BinaryOperation getATopLevelBinaryOperationExpression(Expr e) {
13+
private BinaryOperation getATopLevelBinaryOperationExpression(Expr e) {
1414
result = e.getEnclosingElement().(BinaryOperation)
1515
or
1616
result = getATopLevelBinaryOperationExpression(e.getEnclosingElement())
1717
}
1818

1919
/**
20-
* Holds if the top-level binary operation for expression `e` includes the operator specified in `operator` with an operand specified by `valueToCheck`
20+
* Holds if the top-level binary operation for expression `e` includes the operator specified in `operator` with an operand specified by `valueToCheck`.
2121
*/
22-
predicate additionalLogicalCheck(Expr e, string operation, int valueToCheck) {
22+
private predicate additionalLogicalCheck(Expr e, string operation, int valueToCheck) {
2323
exists(BinaryLogicalOperation bo | bo = getATopLevelBinaryOperationExpression(e) |
2424
exists(BinaryArithmeticOperation bao | bao = bo.getAChild*() |
2525
bao.getAnOperand().getValue().toInt() = valueToCheck and
@@ -29,13 +29,13 @@ predicate additionalLogicalCheck(Expr e, string operation, int valueToCheck) {
2929
}
3030

3131
/**
32-
* Operation that seems to be checking for leap year
32+
* An `Operation` that seems to be checking for leap year.
3333
*/
3434
class CheckForLeapYearOperation extends Operation {
3535
CheckForLeapYearOperation() {
3636
exists(BinaryArithmeticOperation bo | bo = this |
3737
bo.getAnOperand().getValue().toInt() = 4 and
38-
bo.getOperator().toString() = "%" and
38+
bo.getOperator() = "%" and
3939
additionalLogicalCheck(this.getEnclosingElement(), "%", 100) and
4040
additionalLogicalCheck(this.getEnclosingElement(), "%", 400)
4141
)
@@ -45,12 +45,12 @@ class CheckForLeapYearOperation extends Operation {
4545
}
4646

4747
/**
48-
* abstract class of type YearFieldAccess that would represent an access to a year field on a struct and is used for arguing about leap year calculations
48+
* A `YearFieldAccess` that would represent an access to a year field on a struct and is used for arguing about leap year calculations.
4949
*/
5050
abstract class LeapYearFieldAccess extends YearFieldAccess {
5151
/**
5252
* Holds if the field access is a modification,
53-
* and it involves an arithmetic operation
53+
* and it involves an arithmetic operation.
5454
*/
5555
predicate isModifiedByArithmeticOperation() {
5656
this.isModified() and
@@ -59,8 +59,7 @@ abstract class LeapYearFieldAccess extends YearFieldAccess {
5959
(
6060
op instanceof AssignArithmeticOperation or
6161
exists(BinaryArithmeticOperation bao | bao = op.getAnOperand()) or
62-
op instanceof PostfixCrementOperation or
63-
op instanceof PrefixCrementOperation
62+
op instanceof CrementOperation
6463
)
6564
)
6665
}
@@ -70,8 +69,8 @@ abstract class LeapYearFieldAccess extends YearFieldAccess {
7069
* and it involves an arithmetic operation.
7170
* In order to avoid false positives, the operation does not includes values that are normal for year normalization.
7271
*
73-
* 1900 - struct tm counts years since 1900
74-
* 1980/80 - FAT32 epoch
72+
* 1900 - `struct tm` counts years since 1900
73+
* 1980/80 - FAT32 epoch
7574
*/
7675
predicate isModifiedByArithmeticOperationNotForNormalization() {
7776
this.isModified() and
@@ -117,42 +116,40 @@ abstract class LeapYearFieldAccess extends YearFieldAccess {
117116
)
118117
)
119118
or
120-
op instanceof PostfixCrementOperation
121-
or
122-
op instanceof PrefixCrementOperation
119+
op instanceof CrementOperation
123120
)
124121
)
125122
}
126123

127124
/**
128-
* Holds if the top-level binary operation includes a modulus operator with an operand specified by `valueToCheck`
125+
* Holds if the top-level binary operation includes a modulus operator with an operand specified by `valueToCheck`.
129126
*/
130127
predicate additionalModulusCheckForLeapYear(int valueToCheck) {
131128
additionalLogicalCheck(this, "%", valueToCheck)
132129
}
133130

134131
/**
135-
* Holds if the top-level binary operation includes an addition or subtraction operator with an operand specified by `valueToCheck`
132+
* Holds if the top-level binary operation includes an addition or subtraction operator with an operand specified by `valueToCheck`.
136133
*/
137134
predicate additionalAdditionOrSubstractionCheckForLeapYear(int valueToCheck) {
138135
additionalLogicalCheck(this, "+", valueToCheck) or
139136
additionalLogicalCheck(this, "-", valueToCheck)
140137
}
141138

142139
/**
143-
* Holds true if this object is used on a modulus 4 operation, which would likely indicate the start of a leap year check
140+
* Holds if this object is used on a modulus 4 operation, which would likely indicate the start of a leap year check.
144141
*/
145142
predicate isUsedInMod4Operation() {
146143
not this.isModified() and
147144
exists(BinaryArithmeticOperation bo |
148145
bo.getAnOperand() = this and
149146
bo.getAnOperand().getValue().toInt() = 4 and
150-
bo.getOperator().toString() = "%"
147+
bo.getOperator() = "%"
151148
)
152149
}
153150

154151
/**
155-
* Holds true if this object seems to be used in a valid gregorian calendar leap year check
152+
* Holds if this object seems to be used in a valid gregorian calendar leap year check.
156153
*/
157154
predicate isUsedInCorrectLeapYearCheck() {
158155
// The Gregorian leap year rule is:
@@ -168,17 +165,17 @@ abstract class LeapYearFieldAccess extends YearFieldAccess {
168165
}
169166

170167
/**
171-
* YearFieldAccess for SYSTEMTIME struct
168+
* `YearFieldAccess` for the `SYSTEMTIME` struct.
172169
*/
173170
class StructSystemTimeLeapYearFieldAccess extends LeapYearFieldAccess {
174-
StructSystemTimeLeapYearFieldAccess() { this.toString().matches("wYear") }
171+
StructSystemTimeLeapYearFieldAccess() { this.getTarget().getName() = "wYear" }
175172
}
176173

177174
/**
178-
* YearFieldAccess for struct tm
175+
* `YearFieldAccess` for `struct tm`.
179176
*/
180177
class StructTmLeapYearFieldAccess extends LeapYearFieldAccess {
181-
StructTmLeapYearFieldAccess() { this.toString().matches("tm_year") }
178+
StructTmLeapYearFieldAccess() { this.getTarget().getName() = "tm_year" }
182179

183180
override predicate isUsedInCorrectLeapYearCheck() {
184181
this.isUsedInMod4Operation() and
@@ -198,7 +195,7 @@ class StructTmLeapYearFieldAccess extends LeapYearFieldAccess {
198195
}
199196

200197
/**
201-
* FunctionCall that includes an operation that is checking for leap year
198+
* `FunctionCall` that includes an operation that is checking for leap year.
202199
*/
203200
class ChecksForLeapYearFunctionCall extends FunctionCall {
204201
ChecksForLeapYearFunctionCall() {
@@ -209,8 +206,8 @@ class ChecksForLeapYearFunctionCall extends FunctionCall {
209206
}
210207

211208
/**
212-
* DataFlow::Configuration for finding a variable access that would flow into
213-
* a function call that includes an operation to check for leap year
209+
* `DataFlow::Configuration` for finding a variable access that would flow into
210+
* a function call that includes an operation to check for leap year.
214211
*/
215212
class LeapYearCheckConfiguration extends DataFlow::Configuration {
216213
LeapYearCheckConfiguration() { this = "LeapYearCheckConfiguration" }
@@ -225,7 +222,7 @@ class LeapYearCheckConfiguration extends DataFlow::Configuration {
225222
}
226223

227224
/**
228-
* DataFlow::Configuration for finding an operation w/hardcoded 365 that will flow into a FILEINFO field
225+
* `DataFlow::Configuration` for finding an operation with hardcoded 365 that will flow into a `FILEINFO` field.
229226
*/
230227
class FiletimeYearArithmeticOperationCheckConfiguration extends DataFlow::Configuration {
231228
FiletimeYearArithmeticOperationCheckConfiguration() {
@@ -241,7 +238,7 @@ class FiletimeYearArithmeticOperationCheckConfiguration extends DataFlow::Config
241238

242239
override predicate isSink(DataFlow::Node sink) {
243240
exists(StructLikeClass dds, FieldAccess fa, AssignExpr aexpr, Expr e | e = sink.asExpr() |
244-
dds instanceof FileTimeStruct and
241+
dds instanceof PackedTimeType and
245242
fa.getQualifier().getUnderlyingType() = dds and
246243
fa.isModified() and
247244
aexpr.getAChild() = fa and
@@ -251,7 +248,7 @@ class FiletimeYearArithmeticOperationCheckConfiguration extends DataFlow::Config
251248
}
252249

253250
/**
254-
* DataFlow::Configuration for finding an operation w/hardcoded 365 that will flow into any known date/time field
251+
* `DataFlow::Configuration` for finding an operation with hardcoded 365 that will flow into any known date/time field.
255252
*/
256253
class PossibleYearArithmeticOperationCheckConfiguration extends DataFlow::Configuration {
257254
PossibleYearArithmeticOperationCheckConfiguration() {
@@ -272,7 +269,7 @@ class PossibleYearArithmeticOperationCheckConfiguration extends DataFlow::Config
272269
e = node1.asExpr() and
273270
aexpr = node2.asExpr()
274271
|
275-
(dds instanceof FileTimeStruct or dds instanceof DateDataStruct) and
272+
(dds instanceof PackedTimeType or dds instanceof UnpackedTimeType) and
276273
fa.getQualifier().getUnderlyingType() = dds and
277274
aexpr.getLValue() = fa and
278275
aexpr.getRValue().getAChild*() = e
@@ -281,7 +278,7 @@ class PossibleYearArithmeticOperationCheckConfiguration extends DataFlow::Config
281278

282279
override predicate isSink(DataFlow::Node sink) {
283280
exists(StructLikeClass dds, FieldAccess fa, AssignExpr aexpr | aexpr = sink.asExpr() |
284-
(dds instanceof FileTimeStruct or dds instanceof DateDataStruct) and
281+
(dds instanceof PackedTimeType or dds instanceof UnpackedTimeType) and
285282
fa.getQualifier().getUnderlyingType() = dds and
286283
fa.isModified() and
287284
aexpr.getLValue() = fa

cpp/ql/src/Likely Bugs/Leap Year/UncheckedLeapYearAfterYearModification.ql

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,7 @@
55
* @problem.severity warning
66
* @id cpp/leap-year/unchecked-after-arithmetic-year-modification
77
* @precision medium
8-
* @tags security
9-
* leap-year
8+
* @tags leap-year
109
*/
1110

1211
import cpp

cpp/ql/src/Likely Bugs/Leap Year/UncheckedLeapYearAfterYearModificationGood.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ SYSTEMTIME st;
22
FILETIME ft;
33
GetSystemTime(&st);
44

5-
// Flawed logic will result in invalid date
5+
// Flawed logic may result in invalid date
66
st.wYear++;
77

88
// Check for leap year, and adjust the date accordingly
@@ -12,4 +12,4 @@ st.wDay = st.wMonth == 2 && st.wDay == 29 && !isLeapYear ? 28 : st.wDay;
1212
if (!SystemTimeToFileTime(&st, &ft))
1313
{
1414
// handle error
15-
}
15+
}

cpp/ql/src/Likely Bugs/Leap Year/UncheckedReturnValueForTimeFunctions.ql

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -5,67 +5,66 @@
55
* @problem.severity warning
66
* @id cpp/leap-year/unchecked-return-value-for-time-conversion-function
77
* @precision medium
8-
* @tags security
9-
* leap-year
8+
* @tags leap-year
109
*/
1110

1211
import cpp
1312
import LeapYear
1413

1514
/**
16-
* A YearFieldAccess that is modifying the year by any arithmetic operation
15+
* A `YearFieldAccess` that is modifying the year by any arithmetic operation.
1716
*
1817
* NOTE:
1918
* To change this class to work for general purpose date transformations that do not check the return value,
2019
* make the following changes:
21-
* -> extends FieldAccess (line 27)
22-
* -> this.isModified (line 33)
20+
* - change `extends LeapYearFieldAccess` to `extends FieldAccess`.
21+
* - change `this.isModifiedByArithmeticOperation()` to `this.isModified()`.
2322
* Expect a lower precision for a general purpose version.
2423
*/
2524
class DateStructModifiedFieldAccess extends LeapYearFieldAccess {
2625
DateStructModifiedFieldAccess() {
2726
exists(Field f, StructLikeClass struct |
2827
f.getAnAccess() = this and
2928
struct.getAField() = f and
30-
struct.getUnderlyingType() instanceof DateDataStruct and
29+
struct.getUnderlyingType() instanceof UnpackedTimeType and
3130
this.isModifiedByArithmeticOperation()
3231
)
3332
}
3433
}
3534

3635
/**
37-
* This is a list of APIs that will get the system time, and therefore guarantee that the value is valid
36+
* This is a list of APIs that will get the system time, and therefore guarantee that the value is valid.
3837
*/
3938
class SafeTimeGatheringFunction extends Function {
4039
SafeTimeGatheringFunction() {
41-
this.getQualifiedName().matches("GetFileTime") or
42-
this.getQualifiedName().matches("GetSystemTime") or
43-
this.getQualifiedName().matches("NtQuerySystemTime")
40+
this.getQualifiedName() = "GetFileTime" or
41+
this.getQualifiedName() = "GetSystemTime" or
42+
this.getQualifiedName() = "NtQuerySystemTime"
4443
}
4544
}
4645

4746
/**
48-
* This list of APIs should check for the return value to detect problems during the conversion
47+
* This list of APIs should check for the return value to detect problems during the conversion.
4948
*/
5049
class TimeConversionFunction extends Function {
5150
TimeConversionFunction() {
52-
this.getQualifiedName().matches("FileTimeToSystemTime") or
53-
this.getQualifiedName().matches("SystemTimeToFileTime") or
54-
this.getQualifiedName().matches("SystemTimeToTzSpecificLocalTime") or
55-
this.getQualifiedName().matches("SystemTimeToTzSpecificLocalTimeEx") or
56-
this.getQualifiedName().matches("TzSpecificLocalTimeToSystemTime") or
57-
this.getQualifiedName().matches("TzSpecificLocalTimeToSystemTimeEx") or
58-
this.getQualifiedName().matches("RtlLocalTimeToSystemTime") or
59-
this.getQualifiedName().matches("RtlTimeToSecondsSince1970") or
60-
this.getQualifiedName().matches("_mkgmtime")
51+
this.getQualifiedName() = "FileTimeToSystemTime" or
52+
this.getQualifiedName() = "SystemTimeToFileTime" or
53+
this.getQualifiedName() = "SystemTimeToTzSpecificLocalTime" or
54+
this.getQualifiedName() = "SystemTimeToTzSpecificLocalTimeEx" or
55+
this.getQualifiedName() = "TzSpecificLocalTimeToSystemTime" or
56+
this.getQualifiedName() = "TzSpecificLocalTimeToSystemTimeEx" or
57+
this.getQualifiedName() = "RtlLocalTimeToSystemTime" or
58+
this.getQualifiedName() = "RtlTimeToSecondsSince1970" or
59+
this.getQualifiedName() = "_mkgmtime"
6160
}
6261
}
6362

6463
from FunctionCall fcall, TimeConversionFunction trf, Variable var
6564
where
6665
fcall = trf.getACallToThisFunction() and
6766
fcall instanceof ExprInVoidContext and
68-
var.getUnderlyingType() instanceof DateDataStruct and
67+
var.getUnderlyingType() instanceof UnpackedTimeType and
6968
(
7069
exists(AddressOfExpr aoe |
7170
aoe = fcall.getAnArgument() and

cpp/ql/src/Likely Bugs/Leap Year/UnsafeArrayForDaysOfYear.ql

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,22 +16,26 @@ class LeapYearUnsafeDaysOfTheYearArrayType extends ArrayType {
1616
LeapYearUnsafeDaysOfTheYearArrayType() { this.getArraySize() = 365 }
1717
}
1818

19-
from Element element
19+
from Element element, string allocType
2020
where
2121
exists(NewArrayExpr nae |
2222
element = nae and
23-
nae.getAllocatedType() instanceof LeapYearUnsafeDaysOfTheYearArrayType
23+
nae.getAllocatedType() instanceof LeapYearUnsafeDaysOfTheYearArrayType and
24+
allocType = "an array allocation"
2425
)
2526
or
2627
exists(Variable var |
2728
var = element and
28-
var.getType() instanceof LeapYearUnsafeDaysOfTheYearArrayType
29+
var.getType() instanceof LeapYearUnsafeDaysOfTheYearArrayType and
30+
allocType = "an array allocation"
2931
)
3032
or
3133
exists(ConstructorCall cc |
3234
element = cc and
3335
cc.getTarget().hasName("vector") and
34-
cc.getArgument(0).getValue().toInt() = 365
36+
cc.getArgument(0).getValue().toInt() = 365 and
37+
allocType = "a std::vector allocation"
3538
)
3639
select element,
37-
"There is an array or std::vector allocation with a hard-coded set of 365 elements, which may indicate the number of days in a year without considering leap year scenarios."
40+
"There is " + allocType +
41+
" with a hard-coded set of 365 elements, which may indicate the number of days in a year without considering leap year scenarios."

0 commit comments

Comments
 (0)