Skip to content

Commit 83ec5f1

Browse files
authored
Merge pull request #1354 from denislevin/denisl/cpp/MishandlingJapaneseDatesAndLeapYear
C++: Mishandling Japanese Era and Leap Year in calculations
2 parents f408a6d + 6a05c84 commit 83ec5f1

37 files changed

+1876
-0
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
<overview>
6+
<p>
7+
When eras change, date and time conversions that rely on a hard-coded era start date need to be reviewed. Conversions relying on Japanese dates in the current era can produce an ambiguous date.
8+
The values for the current Japanese era dates should be read from a source that will be updated, such as the Windows registry.
9+
</p>
10+
</overview>
11+
12+
<references>
13+
<li>
14+
<a href="https://blogs.msdn.microsoft.com/shawnste/2018/04/12/the-japanese-calendars-y2k-moment/">The Japanese Calendar’s Y2K Moment</a>.
15+
</li>
16+
</references>
17+
</qhelp>
18+
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/**
2+
* @name Hard-coded Japanese era start date
3+
* @description Japanese era changes can lead to code behaving differently. Avoid hard-coding Japanese era start dates.
4+
* @kind problem
5+
* @problem.severity warning
6+
* @id cpp/japanese-era/constructor-or-method-with-exact-era-date
7+
* @precision medium
8+
* @tags reliability
9+
* japanese-era
10+
*/
11+
12+
import cpp
13+
from Call cc, int i
14+
where cc.getArgument(i).getValue().toInt() = 1989 and
15+
cc.getArgument(i+1).getValue().toInt() = 1 and
16+
cc.getArgument(i+2).getValue().toInt() = 8
17+
select cc, "Call that appears to have hard-coded Japanese era start date as parameter."
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
<overview>
6+
<p>
7+
When eras change, date and time conversions that rely on a hard-coded era start date need to be reviewed. Conversions relying on Japanese dates in the current era can produce an ambiguous date.
8+
The values for the current Japanese era dates should be read from a source that will be updated, such as the Windows registry.
9+
</p>
10+
</overview>
11+
12+
<references>
13+
<li>
14+
<a href="https://blogs.msdn.microsoft.com/shawnste/2018/04/12/the-japanese-calendars-y2k-moment/">The Japanese Calendar’s Y2K Moment</a>.
15+
</li>
16+
</references>
17+
</qhelp>
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/**
2+
* @name Hard-coded Japanese era start date
3+
* @description Japanese era changes can lead to code behaving differently. Avoid hard-coding Japanese era start dates.
4+
* @kind problem
5+
* @problem.severity warning
6+
* @id cpp/japanese-era/struct-with-exact-era-date
7+
* @precision medium
8+
* @tags reliability
9+
* japanese-era
10+
*/
11+
12+
import cpp
13+
14+
import semmle.code.cpp.commons.DateTime
15+
16+
from StructLikeClass s, YearFieldAccess year, MonthFieldAccess month, DayFieldAccess day, Operation yearAssignment, Operation monthAssignment, Operation dayAssignment
17+
where s.getAField().getAnAccess () = year and yearAssignment.getAnOperand() = year and yearAssignment.getAnOperand().getValue().toInt() = 1989 and
18+
s.getAField().getAnAccess () = month and monthAssignment.getAnOperand() = month and monthAssignment.getAnOperand().getValue().toInt() = 1 and
19+
s.getAField().getAnAccess () = day and dayAssignment.getAnOperand() = day and dayAssignment.getAnOperand().getValue().toInt() = 8
20+
select year, "A time struct that is initialized with exact Japanese calendar era start date."
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
<overview>
6+
<include src="LeapYear.qhelp" />
7+
8+
<p>When performing arithmetic operations on a variable that represents a date, leap years must be taken into account.
9+
It is not safe to assume that a year is 365 days long.</p>
10+
</overview>
11+
12+
<recommendation>
13+
<p>Determine whether the time span in question contains a leap day, then perform the calculation using the correct number
14+
of days. Alternatively, use an established library routine that already contains correct leap year logic.</p>
15+
</recommendation>
16+
17+
<references>
18+
<include src="LeapYearReferences.qhelp" />
19+
</references>
20+
</qhelp>
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/**
2+
* @name Year field changed using an arithmetic operation is used on an unchecked time conversion function
3+
* @description A year field changed using an arithmetic operation is used on a time conversion function, but the return value of the function is not checked for success or failure.
4+
* @kind problem
5+
* @problem.severity error
6+
* @id cpp/leap-year/adding-365-days-per-year
7+
* @precision high
8+
* @tags security
9+
* leap-year
10+
*/
11+
12+
import cpp
13+
import LeapYear
14+
import semmle.code.cpp.dataflow.DataFlow
15+
16+
from Expr source, Expr sink, PossibleYearArithmeticOperationCheckConfiguration config
17+
where config.hasFlow(DataFlow::exprNode(source), DataFlow::exprNode(sink))
18+
select sink, "This arithmetic operation $@ uses a constant value of 365 ends up modifying the date/time located at $@, without considering leap year scenarios."
19+
, source, source.toString()
20+
, sink, sink.toString()
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
<fragment>
6+
<p>The leap year rule for the Gregorian calendar, which has become the internationally accepted civil calendar, is: every year that is exactly divisible by four is a leap year, except for years that are exactly divisible by 100, but these centurial years are leap years if they are exactly divisible by 400.</p>
7+
<p>A leap year bug occurs when software (in any language) is written without consideration of leap year logic, or with flawed logic to calculate leap years; which typically results in incorrect results.</p>
8+
<p>The impact of these bugs may range from almost unnoticeable bugs such as an incorrect date, to severe bugs that affect reliability, availability or even the security of the affected system.</p>
9+
</fragment>
10+
</qhelp>

0 commit comments

Comments
 (0)