@@ -13,6 +13,17 @@ import cpp
1313import LeapYear
1414import semmle.code.cpp.controlflow.IRGuards
1515
16+ /**
17+ * Functions whose operations should never be considered a
18+ * source of a dangerous leap year operation.
19+ */
20+ class IgnorableFunction extends Function {
21+ IgnorableFunction ( ) {
22+ // Helper utility in postgres with string time conversions
23+ this .getName ( ) = "DecodeISO8601Interval"
24+ }
25+ }
26+
1627/**
1728 * The set of expressions which are ignorable; either because they seem to not be part of a year mutation,
1829 * or because they seem to be a conversion pattern of mapping date scalars.
@@ -22,14 +33,15 @@ abstract class IgnorableOperation extends Expr { }
2233class IgnorableExprRem extends IgnorableOperation instanceof RemExpr { }
2334
2435/**
25- * Anything involving a sub expression with char literal 48, ignore as a likely string conversion
36+ * Anything involving an operation with 10, 100, 1000, 10000 is often a sign of conversion
37+ * or atoi.
2638 */
2739class IgnorableExpr10MulipleComponent extends IgnorableOperation {
2840 IgnorableExpr10MulipleComponent ( ) {
29- this .( MulExpr ) .getAnOperand ( ) .getValue ( ) .toInt ( ) in [ 10 , 100 , 100 ]
41+ this .( Operation ) .getAnOperand ( ) .getValue ( ) .toInt ( ) in [ 10 , 100 , 1000 , 10000 ]
3042 or
31- exists ( AssignMulExpr a | a .getRValue ( ) = this |
32- a .getRValue ( ) .getValue ( ) .toInt ( ) in [ 10 , 100 , 100 ]
43+ exists ( AssignOperation a | a .getRValue ( ) = this |
44+ a .getRValue ( ) .getValue ( ) .toInt ( ) in [ 10 , 100 , 1000 , 10000 ]
3345 )
3446 }
3547}
@@ -56,28 +68,29 @@ class IgnorableCharLiteralArithmetic extends IgnorableOperation {
5668 }
5769}
5870
59- /*
60- * linux time conversions expect the year to start from 1900, so subtracting or
61- * adding 1900 or anything involving 1900 as a generalization is probably
62- * a conversion that is ignorable
71+ /**
72+ * Constants often used in date conversions (from one date data type to another)
6373 */
64-
74+ bindingset [ c ]
6575predicate isLikelyConversionConstant ( int c ) {
66- c = 146097 or // days in 400-year Gregorian cycle
67- c = 36524 or // days in 100-year Gregorian subcycle
68- c = 1461 or // days in 4-year cycle (incl. 1 leap)
69- c = 32044 or // Fliegel–van Flandern JDN epoch shift
70- c = 1721425 or // JDN of 0001‑01‑01 (Gregorian)
71- c = 1721119 or // alt epoch offset
72- c = 2400000 or // MJD → JDN conversion
73- c = 2400001 or
74- c = 2400000 or
75- c = 2141 or // fixed‑point month/day extraction
76- c = 2000 or
77- c = 65536 or
78- c = 7834 or
79- c = 256 or
80- c = 1900 // struct tm base‑year offset; harmless
76+ exists ( int i | i = c .abs ( ) | i >= 100 )
77+ // c = 146097 or // days in 400-year Gregorian cycle
78+ // c = 36524 or // days in 100-year Gregorian subcycle
79+ // c = 1461 or // days in 4-year cycle (incl. 1 leap)
80+ // c = 32044 or // Fliegel–van Flandern JDN epoch shift
81+ // c = 1721425 or // JDN of 0001‑01‑01 (Gregorian)
82+ // c = 1721119 or // alt epoch offset
83+ // c = 2400000 or // MJD → JDN conversion
84+ // c = 2400001 or // alt MJD → JDN conversion
85+ // c = 2141 or // fixed‑point month/day extraction
86+ // c = 2000 or // observed in some conversions
87+ // c = 65536 or // observed in some conversions
88+ // c = 7834 or // observed in some conversions
89+ // c = 256 or // observed in some conversions
90+ // c = 1900 or // struct tm base‑year offset; harmless
91+ // c = 1899 or // Observed in uses with 1900 to address off by one scenarios
92+ // c = 292275056 or // qdatetime.h Qt Core year range first year constant
93+ // c = 292278994 // qdatetime.h Qt Core year range last year constant
8194}
8295
8396/**
@@ -133,6 +146,7 @@ class IgnorablePointerOrCharArithmetic extends IgnorableOperation {
133146 */
134147predicate isOperationSourceCandidate ( Expr e ) {
135148 not e instanceof IgnorableOperation and
149+ not e .getEnclosingFunction ( ) instanceof IgnorableFunction and
136150 (
137151 e instanceof SubExpr
138152 or
@@ -361,31 +375,25 @@ predicate isUsedInFeb29Check(YearFieldAccess fa) {
361375 )
362376}
363377
364- class MonthEqualityCheck extends EqualityOperation {
365- MonthEqualityCheck ( ) {
366- this .getAnOperand ( ) instanceof MonthFieldAccess
367- }
378+ class MonthEqualityCheck extends EqualityOperation {
379+ MonthEqualityCheck ( ) { this .getAnOperand ( ) instanceof MonthFieldAccess }
368380
369- Expr getExprCompared ( ) {
381+ Expr getExprCompared ( ) {
370382 exists ( Expr e |
371383 e = this .getAnOperand ( ) and
372384 not e instanceof MonthFieldAccess and
373385 result = e
374386 )
375387 }
376388
377- MonthFieldAccess getMonthFieldAccess ( ) {
378- result = this .getAnOperand ( )
379- }
389+ MonthFieldAccess getMonthFieldAccess ( ) { result = this .getAnOperand ( ) }
380390}
381391
382- class MonthEqualityCheckGuard extends GuardCondition instanceof MonthEqualityCheck {
383- MonthEqualityCheckGuard ( ) { any ( ) }
384- }
392+ class MonthEqualityCheckGuard extends GuardCondition instanceof MonthEqualityCheck { }
385393
386394bindingset [ e]
387395pragma [ inline_late]
388- predicate isControlledByMonthEqualityCheckNonFebruary ( Expr e ) {
396+ predicate isControlledByMonthEqualityCheckNonFebruary ( Expr e ) {
389397 exists ( MonthEqualityCheckGuard monthGuard |
390398 monthGuard .controls ( e .getBasicBlock ( ) , true ) and
391399 not monthGuard .( MonthEqualityCheck ) .getExprCompared ( ) .getValueText ( ) = "2"
0 commit comments