警告 C26861
日期时间对象
var
的字段已修改,且没有适当的闰年检查:expr
此规则是在 Visual Studio 2022 17.8 中添加的。
备注
在公历中,每个能被 4 整除的年份都是闰年,但能被 100 整除的年份除外。 如果百年年份能被 400 整除,那么它们也是闰年。
当软件未考虑此闰年逻辑或使用有缺陷的逻辑时,就会出现闰年 bug。 这可能会影响相关系统的可靠性、可用性甚至安全性。
如果不将闰年考虑在内,那么在日期时间对象的年、月或日字段上加减某些数字并不安全。 例如,此计算通常用于确定证书的到期日期。 对于许多日期,单纯的计算有可能会产生所需的结果。 但是,当结果为 2 月 29 日(一个闰日)而相应年份又不是闰年时,结果将无效。
例如,在 2020 年 1 月 31 日的基础上加上一年将会得到 2021 年 1 月 31 日。 但是,在 2020 年 2 月 29 日的基础上加上一年将得到 2021 年 2 月 29 日,后者不是一个有效的日期,因为 2021 年不是闰年。
在操作表示日期值的变量时要保持谨慎。 请正确处理闰年和闰日,或使用可安全地处理日期算术的 API 或库。
代码分析名称:DATETIME_MANIPULATION_WITHOUT_LEAPYEAR_CHECK
示例
以下代码通过增大表示系统时间的日期时间对象的年字段,将系统时间向后推进一年。 但是,如果修改前日期为 2 月 29 日,则可能会产生无效的日期时间对象,因为明年不是闰年:
SYSTEMTIME st;
GetSystemTime(&st);
st.wYear++; // warning C26861
为了避免由于闰年的原因而创建无效的日期时间对象,请检查得到的日期是否仍然有效并根据需要进行必要的调整,如下例所示:
SYSTEMTIME st;
GetSystemTime(&st);
st.wYear++;
if (st.wMonth == 2 && st.wDay == 29)
{
// move back a day when landing on Feb 29 in a non-leap year
bool isLeapYear = st.wYear % 4 == 0 && (st.wYear % 100 != 0 || st.wYear % 400 == 0);
if (!isLeapYear)
{
st.wDay = 28;
}
}
启发
目前,此规则仅识别 Windows SYSTEMTIME
结构和 C tm
结构。
该规则采用简化的启发式方法来发现可能存在风险的变化,并且除非有相应的闰年或闰日检查,否则会报告警告。 它不会尝试验证是否对修改后的日期时间对象正确执行了闰年或闰日检查。
此规则是一个可自行选择是否启用的规则,这意味着代码分析应使用一个规则集文件,而该规则应显式包含在该规则集文件中,且需要启用才能进行应用。 有关为代码分析创建自定义规则集的详细信息,请参阅使用规则集指定要运行的 C++
规则。