警告 C26864
日付/時刻オブジェクト
var
の日フィールドは、適切な閏年のチェックを使用せずに、年間 365 日を想定して変更されました。expr
この規則は、Visual Studio 2022 17.8 で追加されました。
解説
グレゴリオ暦では、毎年 4 で正確に割り切れる年は閏年です。ただし、100 で正確に割り切れる年を除きます。 百年も閏年は、400 で正確に割り切れる場合です。
閏年のバグは、ソフトウェアがこの閏年ロジックを考慮しない場合、または欠陥のあるロジックを使用する場合に発生します。 信頼性、可用性、または影響を受けるシステムのセキュリティに影響を与える可能性があります。
日付を表す変数に対して算術演算を実行するときは、閏年を考慮する必要があります。 1 年が 365 日であると仮定しても安全ではありません。 閏年は、2 月の 29 日として "閏日" が追加されたため、366 日です。
年を正しく進めるには、期間に閏日が含まれているかどうかを判断し、正しい日数を使用して計算を実行します。 結果の日付に適切な閏日がチェック、年を直接進める方が良いです。 または、閏年を正しく処理する、確立されたライブラリ ルーチンを使用します。
コード分析名: DATETIME_MANIPULATION_ASSUMING_365_DAYS_WITHOUT_LEAPYEAR_CHECK
例
次のコードでは、現在のシステム時刻を取得し、日フィールドに 365 日を追加し、閏年規則ごとの日付を調整することで、1 年進みます。 ただし、結果が次の年の同じ月/日に該当しない場合があります。
#include <Windows.h>
void foo()
{
SYSTEMTIME st;
GetSystemTime(&st);
// Advance a year by adding 365 days
st.wDay += 365; // C26864
}
この問題を解決するには、年フィールドを直接進め、閏年ルールに従って日付を調整します。
#include <Windows.h>
void foo()
{
SYSTEMTIME st;
GetSystemTime(&st);
st.wYear++; // Advance a year
// Adjust the date
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
構造体のみが認識されます。
日付フィールドが直接 365 日変更された場合、この規則が適用されます。 日付フィールドの値が別の変数に割り当てられ、操作されているかどうかは考慮されないため、同等の間違いを見逃す可能性があります。
このルールはオプトイン ルールです。つまり、コード分析ではルール セット ファイルを使用し、ルールをルール セット ファイルに明示的に含め、適用できるように設定する必要があります。 コード分析用のカスタム ルールセットの作成の詳細については、「ルール セットを使用して実行するルールをC++
指定する」を参照してください。