在不检查闰年的情况下,使用算术运算更改了年份字段¶
ID: cpp/leap-year/unchecked-after-arithmetic-year-modification
Kind: problem
Security severity:
Severity: warning
Precision: medium
Tags:
- leap-year
- correctness
Query suites:
- cpp-security-and-quality.qls
格里高利历的闰年规则(已成为国际公认的民用历法)是:能被 4 整除的年份是闰年,能被 100 整除的年份除外,但如果这些世纪年份能被 400 整除,则它们也是闰年。
当软件(以任何语言编写)在编写时没有考虑闰年逻辑,或者使用有缺陷的逻辑来计算闰年时,就会出现闰年错误;这通常会导致错误的结果。
这些错误的影响可能从几乎不明显的错误(例如日期错误)到影响受影响系统的可靠性、可用性甚至安全性的严重错误。
对表示年份的变量执行算术运算时,必须考虑到结果值可能不是有效日期。
典型的例子是在不考虑结果值是否为有效日期的情况下进行简单的年份算术运算(即 date.year++
)。
建议¶
修改日期结构上的年份字段时,请验证结果年份是否为闰年。
示例¶
在本例中,我们为当前日期添加了 1 年。这在大多数情况下都有效,但在任何 2 月 29 日,结果值都将无效。
SYSTEMTIME st;
FILETIME ft;
GetSystemTime(&st);
// Flawed logic may result in invalid date
st.wYear++;
// The following code may fail
SystemTimeToFileTime(&st, &ft);
要修复此错误,请检查结果是否为闰年。
SYSTEMTIME st;
FILETIME ft;
GetSystemTime(&st);
// Flawed logic may result in invalid date
st.wYear++;
// Check for leap year, and adjust the date accordingly
bool isLeapYear = st.wYear % 4 == 0 && (st.wYear % 100 != 0 || st.wYear % 400 == 0);
st.wDay = st.wMonth == 2 && st.wDay == 29 && !isLeapYear ? 28 : st.wDay;
if (!SystemTimeToFileTime(&st, &ft))
{
// handle error
}
参考¶
美国宇航局/戈达德太空飞行中心 - 日历
维基百科 - 闰年错误
Microsoft Azure 博客 - 您的代码准备好迎接闰年了吗?