Skip to content

Commit 7c14c68

Browse files
committed
CPP: Add a new, combined Japanese era query.
1 parent b441b65 commit 7c14c68

File tree

2 files changed

+80
-0
lines changed

2 files changed

+80
-0
lines changed
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: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
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/exact-era-date
7+
* @precision medium
8+
* @tags reliability
9+
* japanese-era
10+
*/
11+
12+
import cpp
13+
import semmle.code.cpp.commons.DateTime
14+
15+
predicate assignedYear(Struct s, YearFieldAccess year, int value) {
16+
exists(Operation yearAssignment |
17+
s.getAField().getAnAccess() = year and
18+
yearAssignment.getAnOperand() = year and
19+
yearAssignment.getAnOperand().getValue().toInt() = value
20+
)
21+
}
22+
23+
predicate assignedMonth(Struct s, MonthFieldAccess month, int value) {
24+
exists(Operation monthAssignment |
25+
s.getAField().getAnAccess() = month and
26+
monthAssignment.getAnOperand() = month and
27+
monthAssignment.getAnOperand().getValue().toInt() = value
28+
)
29+
}
30+
31+
predicate assignedDay(Struct s, DayFieldAccess day, int value) {
32+
exists(Operation dayAssignment |
33+
s.getAField().getAnAccess() = day and
34+
dayAssignment.getAnOperand() = day and
35+
dayAssignment.getAnOperand().getValue().toInt() = value
36+
)
37+
}
38+
39+
predicate badStructInitialization(Element target, string message) {
40+
exists(StructLikeClass s, YearFieldAccess year, MonthFieldAccess month, DayFieldAccess day |
41+
assignedYear(s, year, 1989) and
42+
assignedMonth(s, month, 1) and
43+
assignedDay(s, day, 8) and
44+
target = year and
45+
message = "A time struct that is initialized with exact Japanese calendar era start date."
46+
)
47+
}
48+
49+
predicate badCall(Element target, string message) {
50+
exists(Call cc, int i |
51+
cc.getArgument(i).getValue().toInt() = 1989 and
52+
cc.getArgument(i + 1).getValue().toInt() = 1 and
53+
cc.getArgument(i + 2).getValue().toInt() = 8 and
54+
target = cc and
55+
message = "Call that appears to have hard-coded Japanese era start date as parameter."
56+
)
57+
}
58+
59+
from Element target, string message
60+
where
61+
badStructInitialization(target, message) or
62+
badCall(target, message)
63+
select target, message

0 commit comments

Comments
 (0)