mirror of
https://github.com/github/codeql.git
synced 2026-04-30 03:05:15 +02:00
Merge pull request #1354 from denislevin/denisl/cpp/MishandlingJapaneseDatesAndLeapYear
C++: Mishandling Japanese Era and Leap Year in calculations
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
class EraInfo
|
||||
{
|
||||
public:
|
||||
EraInfo() {
|
||||
|
||||
};
|
||||
|
||||
EraInfo(int year, int month, int day) {
|
||||
|
||||
};
|
||||
|
||||
EraInfo(int Era, int foo, int year, int month, int day, const wchar_t * eraName)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static EraInfo * EraInfoFromDate(int Era, int foo, int year, int month, int day, wchar_t * eraName)
|
||||
{
|
||||
return new EraInfo(Era, foo, year, month, day, eraName);
|
||||
}
|
||||
};
|
||||
|
||||
int Main()
|
||||
{
|
||||
|
||||
// BAD: constructor creating a EraInfo with exact Heisei era start date
|
||||
EraInfo * pDateTimeUtil = new EraInfo(1989, 1, 8);
|
||||
|
||||
// BAD: constructor creating a EraInfo with exact Heisei era start date
|
||||
EraInfo * pDateTimeUtil1 = new EraInfo(1, 2, 1989, 1, 8, L"\u5e73\u6210");
|
||||
|
||||
// Good: constructor creating a EraInfo with another date
|
||||
EraInfo * pDateTimeUtil2 = new EraInfo(1, 2, 1900, 1, 1, L"foo");
|
||||
|
||||
// BAD: method call passing exact Haisei era start date as parameters
|
||||
EraInfo * pDateTimeUtil3 = EraInfo::EraInfoFromDate(1, 2, 1989, 1, 8, L"\u5e73\u6210");
|
||||
|
||||
// GOOD: method call with the same parameters in a different order (we only track year, month, day)
|
||||
EraInfo * pDateTimeUtil4 = EraInfo::EraInfoFromDate(1, 2, 8, 1, 1989, L"\u5e73\u6210");
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
| ConstructorOrMethodWithExactDate.cpp:27:31:27:53 | call to EraInfo | Call that appears to have hard-coded Japanese era start date as parameter. |
|
||||
| ConstructorOrMethodWithExactDate.cpp:30:32:30:77 | call to EraInfo | Call that appears to have hard-coded Japanese era start date as parameter. |
|
||||
| ConstructorOrMethodWithExactDate.cpp:36:32:36:55 | call to EraInfoFromDate | Call that appears to have hard-coded Japanese era start date as parameter. |
|
||||
@@ -0,0 +1 @@
|
||||
Likely Bugs/JapaneseEra/ConstructorOrMethodWithExactEraDate.ql
|
||||
@@ -0,0 +1,57 @@
|
||||
typedef unsigned short WORD;
|
||||
|
||||
struct tm
|
||||
{
|
||||
int tm_sec; // seconds after the minute - [0, 60] including leap second
|
||||
int tm_min; // minutes after the hour - [0, 59]
|
||||
int tm_hour; // hours since midnight - [0, 23]
|
||||
int tm_mday; // day of the month - [1, 31]
|
||||
int tm_mon; // months since January - [0, 11]
|
||||
int tm_year; // years since 1900
|
||||
int tm_wday; // days since Sunday - [0, 6]
|
||||
int tm_yday; // days since January 1 - [0, 365]
|
||||
int tm_isdst; // daylight savings time flag
|
||||
};
|
||||
|
||||
typedef struct _SYSTEMTIME {
|
||||
WORD wYear;
|
||||
WORD wMonth;
|
||||
WORD wDayOfWeek;
|
||||
WORD wDay;
|
||||
WORD wHour;
|
||||
WORD wMinute;
|
||||
WORD wSecond;
|
||||
WORD wMilliseconds;
|
||||
} SYSTEMTIME, *PSYSTEMTIME, *LPSYSTEMTIME;
|
||||
|
||||
int main()
|
||||
{
|
||||
// BAD: Creation of tm stuct corresponding to the beginning of Heisei era
|
||||
tm *timeTm = new tm();
|
||||
timeTm->tm_year = 1989;
|
||||
timeTm->tm_mon = 1;
|
||||
timeTm->tm_mday = 8;
|
||||
|
||||
|
||||
// GOOD: Creation of tm stuct with different date
|
||||
tm *timeTm1 = new tm();
|
||||
timeTm1->tm_year = 1988;
|
||||
timeTm1->tm_mon = 1;
|
||||
timeTm1->tm_mday = 1;
|
||||
|
||||
// BAD: Creation of SYSTEMTIME stuct corresponding to the beginning of Heisei era
|
||||
SYSTEMTIME st;
|
||||
st.wDay = 8;
|
||||
st.wMonth = 1;
|
||||
st.wYear = 1989;
|
||||
|
||||
|
||||
// GOOD: Creation of SYSTEMTIME stuct with a different date
|
||||
SYSTEMTIME st1;
|
||||
st1.wDay = 1;
|
||||
st1.wMonth = 1;
|
||||
st1.wYear = 1990;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
| StructWithExactDate.cpp:31:13:31:19 | tm_year | A time struct that is initialized with exact Japanese calendar era start date. |
|
||||
| StructWithExactDate.cpp:46:8:46:12 | wYear | A time struct that is initialized with exact Japanese calendar era start date. |
|
||||
@@ -0,0 +1 @@
|
||||
Likely Bugs/JapaneseEra/StructWithExactEraDate.ql
|
||||
@@ -0,0 +1,11 @@
|
||||
| test.cpp:314:5:314:9 | wYear | Field $@ on variable $@ has been modified, but no appropriate check for LeapYear was found. | test.cpp:12:7:12:11 | wYear | wYear | test.cpp:309:13:309:14 | st | st |
|
||||
| test.cpp:327:5:327:9 | wYear | Field $@ on variable $@ has been modified, but no appropriate check for LeapYear was found. | test.cpp:12:7:12:11 | wYear | wYear | test.cpp:322:13:322:14 | st | st |
|
||||
| test.cpp:338:6:338:10 | wYear | Field $@ on variable $@ has been modified, but no appropriate check for LeapYear was found. | test.cpp:12:7:12:11 | wYear | wYear | test.cpp:333:62:333:63 | st | st |
|
||||
| test.cpp:484:5:484:9 | wYear | Field $@ on variable $@ has been modified, but no appropriate check for LeapYear was found. | test.cpp:12:7:12:11 | wYear | wYear | test.cpp:480:13:480:14 | st | st |
|
||||
| test.cpp:497:5:497:9 | wYear | Field $@ on variable $@ has been modified, but no appropriate check for LeapYear was found. | test.cpp:12:7:12:11 | wYear | wYear | test.cpp:492:13:492:14 | st | st |
|
||||
| test.cpp:509:5:509:9 | wYear | Field $@ on variable $@ has been modified, but no appropriate check for LeapYear was found. | test.cpp:12:7:12:11 | wYear | wYear | test.cpp:505:13:505:14 | st | st |
|
||||
| test.cpp:606:11:606:17 | tm_year | Field $@ on variable $@ has been modified, but no appropriate check for LeapYear was found. | test.cpp:56:6:56:12 | tm_year | tm_year | test.cpp:602:12:602:19 | timeinfo | timeinfo |
|
||||
| test.cpp:634:11:634:17 | tm_year | Field $@ on variable $@ has been modified, but no appropriate check for LeapYear was found. | test.cpp:56:6:56:12 | tm_year | tm_year | test.cpp:628:12:628:19 | timeinfo | timeinfo |
|
||||
| test.cpp:636:11:636:17 | tm_year | Field $@ on variable $@ has been modified, but no appropriate check for LeapYear was found. | test.cpp:56:6:56:12 | tm_year | tm_year | test.cpp:628:12:628:19 | timeinfo | timeinfo |
|
||||
| test.cpp:640:5:640:9 | wYear | Field $@ on variable $@ has been modified, but no appropriate check for LeapYear was found. | test.cpp:12:7:12:11 | wYear | wYear | test.cpp:629:13:629:14 | st | st |
|
||||
| test.cpp:642:5:642:9 | wYear | Field $@ on variable $@ has been modified, but no appropriate check for LeapYear was found. | test.cpp:12:7:12:11 | wYear | wYear | test.cpp:629:13:629:14 | st | st |
|
||||
@@ -0,0 +1 @@
|
||||
Likely Bugs/Leap Year/UncheckedLeapYearAfterYearModification.ql
|
||||
@@ -0,0 +1,3 @@
|
||||
| test.cpp:317:2:317:21 | call to SystemTimeToFileTime | Return value of $@ function should be verified to check for any error because variable $@ is not guaranteed to be safe. | test.cpp:63:1:63:20 | SystemTimeToFileTime | SystemTimeToFileTime | test.cpp:309:13:309:14 | st | st |
|
||||
| test.cpp:330:2:330:21 | call to SystemTimeToFileTime | Return value of $@ function should be verified to check for any error because variable $@ is not guaranteed to be safe. | test.cpp:63:1:63:20 | SystemTimeToFileTime | SystemTimeToFileTime | test.cpp:322:13:322:14 | st | st |
|
||||
| test.cpp:341:2:341:21 | call to SystemTimeToFileTime | Return value of $@ function should be verified to check for any error because variable $@ is not guaranteed to be safe. | test.cpp:63:1:63:20 | SystemTimeToFileTime | SystemTimeToFileTime | test.cpp:333:62:333:63 | st | st |
|
||||
@@ -0,0 +1 @@
|
||||
Likely Bugs/Leap Year/UncheckedReturnValueForTimeFunctions.ql
|
||||
@@ -0,0 +1,658 @@
|
||||
typedef unsigned short WORD;
|
||||
typedef unsigned long DWORD, HANDLE;
|
||||
typedef int BOOL, BOOLEAN, errno_t;
|
||||
typedef char CHAR;
|
||||
typedef short SHORT;
|
||||
typedef long LONG;
|
||||
typedef unsigned short WCHAR; // wc, 16-bit UNICODE character
|
||||
typedef long __time64_t, time_t;
|
||||
#define NULL 0
|
||||
|
||||
typedef struct _SYSTEMTIME {
|
||||
WORD wYear;
|
||||
WORD wMonth;
|
||||
WORD wDayOfWeek;
|
||||
WORD wDay;
|
||||
WORD wHour;
|
||||
WORD wMinute;
|
||||
WORD wSecond;
|
||||
WORD wMilliseconds;
|
||||
} SYSTEMTIME, *PSYSTEMTIME, *LPSYSTEMTIME;
|
||||
|
||||
typedef struct _FILETIME {
|
||||
DWORD dwLowDateTime;
|
||||
DWORD dwHighDateTime;
|
||||
} FILETIME, *PFILETIME, *LPFILETIME;
|
||||
|
||||
typedef struct _TIME_ZONE_INFORMATION {
|
||||
LONG Bias;
|
||||
WCHAR StandardName[32];
|
||||
SYSTEMTIME StandardDate;
|
||||
LONG StandardBias;
|
||||
WCHAR DaylightName[32];
|
||||
SYSTEMTIME DaylightDate;
|
||||
LONG DaylightBias;
|
||||
} TIME_ZONE_INFORMATION, *PTIME_ZONE_INFORMATION, *LPTIME_ZONE_INFORMATION;
|
||||
|
||||
typedef struct _TIME_DYNAMIC_ZONE_INFORMATION {
|
||||
LONG Bias;
|
||||
WCHAR StandardName[32];
|
||||
SYSTEMTIME StandardDate;
|
||||
LONG StandardBias;
|
||||
WCHAR DaylightName[32];
|
||||
SYSTEMTIME DaylightDate;
|
||||
LONG DaylightBias;
|
||||
WCHAR TimeZoneKeyName[128];
|
||||
BOOLEAN DynamicDaylightTimeDisabled;
|
||||
} DYNAMIC_TIME_ZONE_INFORMATION, *PDYNAMIC_TIME_ZONE_INFORMATION;
|
||||
|
||||
struct tm
|
||||
{
|
||||
int tm_sec; // seconds after the minute - [0, 60] including leap second
|
||||
int tm_min; // minutes after the hour - [0, 59]
|
||||
int tm_hour; // hours since midnight - [0, 23]
|
||||
int tm_mday; // day of the month - [1, 31]
|
||||
int tm_mon; // months since January - [0, 11]
|
||||
int tm_year; // years since 1900
|
||||
int tm_wday; // days since Sunday - [0, 6]
|
||||
int tm_yday; // days since January 1 - [0, 365]
|
||||
int tm_isdst; // daylight savings time flag
|
||||
};
|
||||
|
||||
BOOL
|
||||
SystemTimeToFileTime(
|
||||
const SYSTEMTIME* lpSystemTime,
|
||||
LPFILETIME lpFileTime
|
||||
);
|
||||
|
||||
BOOL
|
||||
FileTimeToSystemTime(
|
||||
const FILETIME* lpFileTime,
|
||||
LPSYSTEMTIME lpSystemTime
|
||||
);
|
||||
|
||||
BOOL
|
||||
SystemTimeToTzSpecificLocalTime(
|
||||
const TIME_ZONE_INFORMATION* lpTimeZoneInformation,
|
||||
const SYSTEMTIME* lpUniversalTime,
|
||||
LPSYSTEMTIME lpLocalTime
|
||||
);
|
||||
|
||||
BOOL
|
||||
SystemTimeToTzSpecificLocalTimeEx(
|
||||
const DYNAMIC_TIME_ZONE_INFORMATION* lpTimeZoneInformation,
|
||||
const SYSTEMTIME* lpUniversalTime,
|
||||
LPSYSTEMTIME lpLocalTime
|
||||
);
|
||||
|
||||
BOOL
|
||||
TzSpecificLocalTimeToSystemTime(
|
||||
const TIME_ZONE_INFORMATION* lpTimeZoneInformation,
|
||||
const SYSTEMTIME* lpLocalTime,
|
||||
LPSYSTEMTIME lpUniversalTime
|
||||
);
|
||||
|
||||
BOOL
|
||||
TzSpecificLocalTimeToSystemTimeEx(
|
||||
const DYNAMIC_TIME_ZONE_INFORMATION* lpTimeZoneInformation,
|
||||
const SYSTEMTIME* lpLocalTime,
|
||||
LPSYSTEMTIME lpUniversalTime
|
||||
);
|
||||
|
||||
void GetSystemTime(
|
||||
LPSYSTEMTIME lpSystemTime
|
||||
);
|
||||
|
||||
void GetSystemTimeAsFileTime(
|
||||
LPFILETIME lpSystemTimeAsFileTime
|
||||
);
|
||||
|
||||
__time64_t _mkgmtime64(
|
||||
struct tm* _Tm
|
||||
);
|
||||
|
||||
__time64_t _mkgmtime(
|
||||
struct tm* const _Tm
|
||||
)
|
||||
{
|
||||
return _mkgmtime64(_Tm);
|
||||
}
|
||||
|
||||
__time64_t mktime(
|
||||
struct tm* const _Tm
|
||||
)
|
||||
{
|
||||
return _mkgmtime64(_Tm);
|
||||
}
|
||||
|
||||
__time64_t _time64(
|
||||
__time64_t* _Time
|
||||
);
|
||||
|
||||
__time64_t time(
|
||||
time_t* const _Time
|
||||
)
|
||||
{
|
||||
return _time64(_Time);
|
||||
}
|
||||
|
||||
int gmtime_s(
|
||||
struct tm* _Tm,
|
||||
__time64_t const* _Time
|
||||
);
|
||||
|
||||
BOOL
|
||||
GetFileTime(
|
||||
HANDLE hFile,
|
||||
LPFILETIME lpCreationTime,
|
||||
LPFILETIME lpLastAccessTime,
|
||||
LPFILETIME lpLastWriteTime
|
||||
);
|
||||
|
||||
void Correct_FileTimeToSystemTime(const FILETIME* lpFileTime)
|
||||
{
|
||||
SYSTEMTIME systemTime;
|
||||
|
||||
if (!FileTimeToSystemTime(lpFileTime, &systemTime))
|
||||
{
|
||||
/// handle error
|
||||
return;
|
||||
}
|
||||
|
||||
/// Normal usage
|
||||
}
|
||||
|
||||
void AntiPattern_FileTimeToSystemTime(const FILETIME* lpFileTime)
|
||||
{
|
||||
SYSTEMTIME systemTime;
|
||||
|
||||
// (out-of-scope) GeneralBug
|
||||
FileTimeToSystemTime(lpFileTime, &systemTime);
|
||||
}
|
||||
|
||||
void Correct_SystemTimeToTzSpecificLocalTime(const TIME_ZONE_INFORMATION *lpTimeZoneInformation, const SYSTEMTIME *lpUniversalTime)
|
||||
{
|
||||
SYSTEMTIME localTime;
|
||||
|
||||
if (!SystemTimeToTzSpecificLocalTime(lpTimeZoneInformation, lpUniversalTime, &localTime))
|
||||
{
|
||||
/// handle error
|
||||
return;
|
||||
}
|
||||
|
||||
/// Normal usage
|
||||
}
|
||||
|
||||
void AntiPattern_SystemTimeToTzSpecificLocalTime(const TIME_ZONE_INFORMATION *lpTimeZoneInformation, const SYSTEMTIME *lpUniversalTime)
|
||||
{
|
||||
SYSTEMTIME localTime;
|
||||
|
||||
// (out-of-scope) GeneralBug
|
||||
SystemTimeToTzSpecificLocalTime(lpTimeZoneInformation, lpUniversalTime, &localTime);
|
||||
}
|
||||
|
||||
void Correct_SystemTimeToTzSpecificLocalTimeEx(const DYNAMIC_TIME_ZONE_INFORMATION *lpTimeZoneInformation, const SYSTEMTIME *lpUniversalTime)
|
||||
{
|
||||
SYSTEMTIME localTime;
|
||||
|
||||
if (!SystemTimeToTzSpecificLocalTimeEx(lpTimeZoneInformation, lpUniversalTime, &localTime))
|
||||
{
|
||||
/// handle error
|
||||
return;
|
||||
}
|
||||
|
||||
/// Normal usage
|
||||
}
|
||||
|
||||
void AntiPattern_SystemTimeToTzSpecificLocalTimeEx(const DYNAMIC_TIME_ZONE_INFORMATION *lpTimeZoneInformation, const SYSTEMTIME *lpUniversalTime)
|
||||
{
|
||||
SYSTEMTIME localTime;
|
||||
|
||||
// (out-of-scope) GeneralBug
|
||||
SystemTimeToTzSpecificLocalTimeEx(lpTimeZoneInformation, lpUniversalTime, &localTime);
|
||||
}
|
||||
|
||||
void Correct_TzSpecificLocalTimeToSystemTime(const TIME_ZONE_INFORMATION *lpTimeZoneInformation, const SYSTEMTIME *lpLocalTime)
|
||||
{
|
||||
SYSTEMTIME universalTime;
|
||||
|
||||
if (!TzSpecificLocalTimeToSystemTime(lpTimeZoneInformation, lpLocalTime, &universalTime))
|
||||
{
|
||||
/// handle error
|
||||
return;
|
||||
}
|
||||
|
||||
/// Normal usage
|
||||
}
|
||||
|
||||
void AntiPattern_TzSpecificLocalTimeToSystemTime(const TIME_ZONE_INFORMATION *lpTimeZoneInformation, const SYSTEMTIME *lpLocalTime)
|
||||
{
|
||||
SYSTEMTIME universalTime;
|
||||
|
||||
// (out-of-scope) GeneralBug
|
||||
TzSpecificLocalTimeToSystemTime(lpTimeZoneInformation, lpLocalTime, &universalTime);
|
||||
}
|
||||
|
||||
void Correct_TzSpecificLocalTimeToSystemTimeEx(const DYNAMIC_TIME_ZONE_INFORMATION *lpTimeZoneInformation, const SYSTEMTIME *lpLocalTime)
|
||||
{
|
||||
SYSTEMTIME universalTime;
|
||||
|
||||
if (!TzSpecificLocalTimeToSystemTimeEx(lpTimeZoneInformation, lpLocalTime, &universalTime))
|
||||
{
|
||||
/// handle error
|
||||
return;
|
||||
}
|
||||
|
||||
/// Normal usage
|
||||
}
|
||||
|
||||
void AntiPattern_TzSpecificLocalTimeToSystemTimeEx(const DYNAMIC_TIME_ZONE_INFORMATION *lpTimeZoneInformation, const SYSTEMTIME *lpLocalTime)
|
||||
{
|
||||
SYSTEMTIME universalTime;
|
||||
|
||||
// (out-of-scope) GeneralBug
|
||||
TzSpecificLocalTimeToSystemTimeEx(lpTimeZoneInformation, lpLocalTime, &universalTime);
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
SYSTEMTIME Cases
|
||||
*************************************************/
|
||||
|
||||
void Correct_filetime_conversion_check(SYSTEMTIME& st)
|
||||
{
|
||||
FILETIME ft;
|
||||
|
||||
if (!SystemTimeToFileTime(&st, &ft))
|
||||
{
|
||||
/// Something failed, handle error
|
||||
return;
|
||||
}
|
||||
|
||||
/// SystemTimeToFileTime succeeded
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////
|
||||
|
||||
void AntiPattern_unchecked_filetime_conversion(SYSTEMTIME& st)
|
||||
{
|
||||
FILETIME ft;
|
||||
|
||||
// (out-of-scope) GeneralBug: Unchecked call to SystemTimeToFileTime. this may have failed, but we didn't check the return value!
|
||||
SystemTimeToFileTime(&st, &ft);
|
||||
}
|
||||
|
||||
void AntiPattern_unchecked_filetime_conversion2(SYSTEMTIME* st)
|
||||
{
|
||||
FILETIME ft;
|
||||
|
||||
if (st != NULL)
|
||||
{
|
||||
// (out-of-scope) GeneralBug: Unchecked call to SystemTimeToFileTime. this may have failed, but we didn't check the return value!
|
||||
SystemTimeToFileTime(st, &ft);
|
||||
}
|
||||
}
|
||||
|
||||
void AntiPattern_unchecked_filetime_conversion2()
|
||||
{
|
||||
SYSTEMTIME st;
|
||||
FILETIME ft;
|
||||
GetSystemTime(&st);
|
||||
|
||||
st.wDay++;
|
||||
|
||||
// (out-of-scope) GeneralBug: Not checking is OK, no struct manipulation
|
||||
SystemTimeToFileTime(&st, &ft);
|
||||
}
|
||||
|
||||
void AntiPattern_unchecked_filetime_conversion2a()
|
||||
{
|
||||
SYSTEMTIME st;
|
||||
FILETIME ft;
|
||||
GetSystemTime(&st);
|
||||
|
||||
// BUG - UncheckedLeapYearAfterYearModification
|
||||
st.wYear += 2;
|
||||
|
||||
// BUG - UncheckedReturnValueForTimeFunctions
|
||||
SystemTimeToFileTime(&st, &ft);
|
||||
}
|
||||
|
||||
void AntiPattern_unchecked_filetime_conversion2b()
|
||||
{
|
||||
SYSTEMTIME st;
|
||||
FILETIME ft;
|
||||
GetSystemTime(&st);
|
||||
|
||||
// BUG - UncheckedLeapYearAfterYearModification
|
||||
st.wYear++;
|
||||
|
||||
// BUG - UncheckedReturnValueForTimeFunctions
|
||||
SystemTimeToFileTime(&st, &ft);
|
||||
}
|
||||
|
||||
void AntiPattern_unchecked_filetime_conversion2b(SYSTEMTIME* st)
|
||||
{
|
||||
FILETIME ft;
|
||||
|
||||
// BUG - UncheckedLeapYearAfterYearModification
|
||||
st->wYear++;
|
||||
|
||||
// BUG - UncheckedReturnValueForTimeFunctions
|
||||
SystemTimeToFileTime(st, &ft);
|
||||
}
|
||||
|
||||
void AntiPattern_unchecked_filetime_conversion3()
|
||||
{
|
||||
SYSTEMTIME st;
|
||||
FILETIME ft;
|
||||
GetSystemTime(&st);
|
||||
|
||||
if (st.wMonth < 12)
|
||||
{
|
||||
st.wMonth++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Check for leap year, but...
|
||||
st.wMonth = 1;
|
||||
st.wYear++;
|
||||
}
|
||||
|
||||
// (out-of-scope) GeneralBug: Not checking if newly generated date is valid for conversion
|
||||
SystemTimeToFileTime(&st, &ft);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////
|
||||
void CorrectPattern_check1()
|
||||
{
|
||||
SYSTEMTIME st;
|
||||
GetSystemTime(&st);
|
||||
|
||||
st.wYear++;
|
||||
|
||||
// Guard
|
||||
if (st.wMonth == 2 && st.wDay == 29)
|
||||
{
|
||||
// move back a day when landing on Feb 29 in an non-leap year
|
||||
bool isLeapYear = st.wYear % 4 == 0 && (st.wYear % 100 != 0 || st.wYear % 400 == 0);
|
||||
if (!isLeapYear)
|
||||
{
|
||||
st.wDay = 28;
|
||||
}
|
||||
}
|
||||
|
||||
// Safe to use
|
||||
AntiPattern_unchecked_filetime_conversion(st);
|
||||
}
|
||||
|
||||
void CorrectPattern_check2(int yearsToAdd)
|
||||
{
|
||||
SYSTEMTIME st;
|
||||
GetSystemTime(&st);
|
||||
|
||||
st.wYear += yearsToAdd;
|
||||
|
||||
// Guard
|
||||
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;
|
||||
|
||||
// Safe to use
|
||||
AntiPattern_unchecked_filetime_conversion(st);
|
||||
}
|
||||
|
||||
bool isLeapYear(SYSTEMTIME& st)
|
||||
{
|
||||
return st.wYear % 4 == 0 && (st.wYear % 100 != 0 || st.wYear % 400 == 0);
|
||||
}
|
||||
|
||||
void CorrectPattern_check3()
|
||||
{
|
||||
SYSTEMTIME st;
|
||||
GetSystemTime(&st);
|
||||
|
||||
st.wYear++;
|
||||
|
||||
// Guard
|
||||
if (st.wMonth == 2 && st.wDay == 29 && isLeapYear(st))
|
||||
{
|
||||
// move back a day when landing on Feb 29 in an non-leap year
|
||||
st.wDay = 28;
|
||||
}
|
||||
|
||||
// Safe to use
|
||||
AntiPattern_unchecked_filetime_conversion(st);
|
||||
}
|
||||
|
||||
bool isLeapYear2(int year)
|
||||
{
|
||||
return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
|
||||
}
|
||||
|
||||
bool fixDate(int day, int month, int year)
|
||||
{
|
||||
return (month == 2 && day == 29 && isLeapYear2(year));
|
||||
}
|
||||
|
||||
void CorrectPattern_check4()
|
||||
{
|
||||
SYSTEMTIME st;
|
||||
GetSystemTime(&st);
|
||||
|
||||
///// FP
|
||||
st.wYear++;
|
||||
|
||||
// Guard
|
||||
if (fixDate(st.wDay, st.wMonth, st.wYear))
|
||||
{
|
||||
// move back a day when landing on Feb 29 in an non-leap year
|
||||
st.wDay = 28;
|
||||
}
|
||||
|
||||
// Safe to use
|
||||
AntiPattern_unchecked_filetime_conversion(st);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CorrectPattern_NotManipulated_DateFromAPI_0()
|
||||
{
|
||||
SYSTEMTIME st;
|
||||
GetSystemTime(&st);
|
||||
FILETIME ft;
|
||||
|
||||
// Not checking is OK, no struct manipulation
|
||||
SystemTimeToFileTime(&st, &ft);
|
||||
}
|
||||
|
||||
void CorrectPattern_NotManipulated_DateFromAPI_1(HANDLE hWatchdog)
|
||||
{
|
||||
SYSTEMTIME st;
|
||||
FILETIME ft;
|
||||
|
||||
GetFileTime(hWatchdog, NULL, NULL, &ft);
|
||||
FileTimeToSystemTime(&ft, &st);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////
|
||||
|
||||
void AntiPattern_1_year_addition()
|
||||
{
|
||||
SYSTEMTIME st;
|
||||
GetSystemTime(&st);
|
||||
|
||||
// BUG - UncheckedLeapYearAfterYearModification
|
||||
st.wYear++;
|
||||
|
||||
// Usage of potentially invalid date
|
||||
Correct_filetime_conversion_check(st);
|
||||
}
|
||||
|
||||
void AntiPattern_simple_addition(int yearAddition)
|
||||
{
|
||||
SYSTEMTIME st;
|
||||
|
||||
GetSystemTime(&st);
|
||||
|
||||
// BUG - UncheckedLeapYearAfterYearModification
|
||||
st.wYear += yearAddition;
|
||||
|
||||
// Usage of potentially invalid date
|
||||
Correct_filetime_conversion_check(st);
|
||||
}
|
||||
|
||||
void AntiPattern_IncorrectGuard(int yearsToAdd)
|
||||
{
|
||||
SYSTEMTIME st;
|
||||
GetSystemTime(&st);
|
||||
|
||||
// BUG - UncheckedLeapYearAfterYearModification
|
||||
st.wYear += yearsToAdd;
|
||||
|
||||
// Incorrect Guard
|
||||
if (st.wMonth == 2 && st.wDay == 29)
|
||||
{
|
||||
// Part of a different anti-pattern.
|
||||
// Make sure the guard includes the proper check
|
||||
bool isLeapYear = st.wYear % 4 == 0;
|
||||
if (!isLeapYear)
|
||||
{
|
||||
st.wDay = 28;
|
||||
}
|
||||
}
|
||||
|
||||
// Potentially Unsafe to use
|
||||
Correct_filetime_conversion_check(st);
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
struct tm Cases
|
||||
*************************************************/
|
||||
|
||||
void CorrectUsageOf_mkgmtime(struct tm& timeinfo)
|
||||
{
|
||||
if (_mkgmtime(&timeinfo) == -1)
|
||||
{
|
||||
/// Something failed, handle error
|
||||
return;
|
||||
}
|
||||
|
||||
/// _mkgmtime succeeded
|
||||
}
|
||||
|
||||
void AntiPattern_uncheckedUsageOf_mkgmtime(struct tm& timeinfo)
|
||||
{
|
||||
// (out-of-scope) GeneralBug: Must check return value for _mkgmtime
|
||||
// QLNOTE: Include other related _mkgmtime* functions in the function name pattern
|
||||
_mkgmtime(&timeinfo);
|
||||
// _mktime64(&timeinfo);
|
||||
// _mktime32(&timeinfo);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////
|
||||
|
||||
void Correct_year_addition_struct_tm()
|
||||
{
|
||||
time_t rawtime;
|
||||
struct tm timeinfo;
|
||||
time(&rawtime);
|
||||
// NOTE: Should ideally check return value for this function (not in scope)
|
||||
errno_t err = gmtime_s(&timeinfo, &rawtime);
|
||||
if (err)
|
||||
{
|
||||
/// handle error
|
||||
return;
|
||||
}
|
||||
|
||||
// this is the potentially dangerous part, when not followed up with leap year checks
|
||||
timeinfo.tm_year++;
|
||||
|
||||
// Guard
|
||||
// move back a day when landing on Feb 29 in an non-leap year
|
||||
bool isLeapYear = timeinfo.tm_year % 4 == 0 && (timeinfo.tm_year % 100 != 0 || (timeinfo.tm_year + 1900) % 400 == 0);
|
||||
timeinfo.tm_mday = timeinfo.tm_mon == 1 && timeinfo.tm_mday == 29 && !isLeapYear ? 28 : timeinfo.tm_mday;
|
||||
|
||||
// safe to use
|
||||
AntiPattern_uncheckedUsageOf_mkgmtime(timeinfo);
|
||||
}
|
||||
|
||||
void Correct_LinuxPattern()
|
||||
{
|
||||
time_t rawtime;
|
||||
struct tm timeinfo;
|
||||
time(&rawtime);
|
||||
// NOTE: Should ideally check return value for this function (not in scope)
|
||||
errno_t err = gmtime_s(&timeinfo, &rawtime);
|
||||
|
||||
/* from 1900 -> from 1980 */
|
||||
timeinfo.tm_year -= 80;
|
||||
/* 0~11 -> 1~12 */
|
||||
timeinfo.tm_mon++;
|
||||
/* 0~59 -> 0~29(2sec counts) */
|
||||
timeinfo.tm_sec >>= 1;
|
||||
|
||||
// safe to use
|
||||
AntiPattern_uncheckedUsageOf_mkgmtime(timeinfo);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////
|
||||
|
||||
void AntiPattern_year_addition_struct_tm()
|
||||
{
|
||||
time_t rawtime;
|
||||
struct tm timeinfo;
|
||||
time(&rawtime);
|
||||
gmtime_s(&timeinfo, &rawtime);
|
||||
// BUG - UncheckedLeapYearAfterYearModification
|
||||
timeinfo.tm_year++;
|
||||
|
||||
// Usage of potentially invalid date
|
||||
CorrectUsageOf_mkgmtime(timeinfo);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////
|
||||
|
||||
void FalsePositiveTests(int x)
|
||||
{
|
||||
struct tm timeinfo;
|
||||
SYSTEMTIME st;
|
||||
|
||||
timeinfo.tm_year = x;
|
||||
timeinfo.tm_year = 1970;
|
||||
|
||||
st.wYear = x;
|
||||
st.wYear = 1900 + x;
|
||||
}
|
||||
|
||||
void FalseNegativeTests(int x)
|
||||
{
|
||||
struct tm timeinfo;
|
||||
SYSTEMTIME st;
|
||||
|
||||
timeinfo.tm_year = x;
|
||||
|
||||
// BUG - UncheckedLeapYearAfterYearModification
|
||||
timeinfo.tm_year = x + timeinfo.tm_year;
|
||||
// BUG - UncheckedLeapYearAfterYearModification
|
||||
timeinfo.tm_year = 1970 + timeinfo.tm_year;
|
||||
|
||||
st.wYear = x;
|
||||
// BUG - UncheckedLeapYearAfterYearModification
|
||||
st.wYear = x + st.wYear;
|
||||
// BUG - UncheckedLeapYearAfterYearModification
|
||||
st.wYear = (1986 + st.wYear) - 1;
|
||||
}
|
||||
|
||||
// False positive
|
||||
inline void
|
||||
IncrementMonth(LPSYSTEMTIME pst)
|
||||
{
|
||||
if (pst->wMonth < 12)
|
||||
{
|
||||
pst->wMonth++;
|
||||
}
|
||||
else
|
||||
{
|
||||
pst->wMonth = 1;
|
||||
pst->wYear++;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
| test.cpp:173:29:173:38 | qwLongTime | This arithmetic operation $@ uses a constant value of 365 ends up modifying the date/time located at $@, without considering leap year scenarios. | test.cpp:170:2:170:47 | ... += ... | ... += ... | test.cpp:173:29:173:38 | qwLongTime | qwLongTime |
|
||||
| test.cpp:174:30:174:39 | qwLongTime | This arithmetic operation $@ uses a constant value of 365 ends up modifying the date/time located at $@, without considering leap year scenarios. | test.cpp:170:2:170:47 | ... += ... | ... += ... | test.cpp:174:30:174:39 | qwLongTime | qwLongTime |
|
||||
@@ -0,0 +1 @@
|
||||
Likely Bugs/Leap Year/Adding365daysPerYear.ql
|
||||
@@ -0,0 +1,178 @@
|
||||
typedef unsigned short WORD;
|
||||
typedef unsigned long DWORD, HANDLE;
|
||||
typedef int BOOL, BOOLEAN, errno_t;
|
||||
typedef char CHAR;
|
||||
typedef short SHORT;
|
||||
typedef long LONG;
|
||||
typedef unsigned short WCHAR; // wc, 16-bit UNICODE character
|
||||
typedef long __time64_t, time_t;
|
||||
#define NULL 0
|
||||
|
||||
typedef long long LONGLONG;
|
||||
typedef unsigned long long ULONGLONG;
|
||||
|
||||
|
||||
typedef struct _SYSTEMTIME {
|
||||
WORD wYear;
|
||||
WORD wMonth;
|
||||
WORD wDayOfWeek;
|
||||
WORD wDay;
|
||||
WORD wHour;
|
||||
WORD wMinute;
|
||||
WORD wSecond;
|
||||
WORD wMilliseconds;
|
||||
} SYSTEMTIME, *PSYSTEMTIME, *LPSYSTEMTIME;
|
||||
|
||||
typedef struct _FILETIME {
|
||||
DWORD dwLowDateTime;
|
||||
DWORD dwHighDateTime;
|
||||
} FILETIME, *PFILETIME, *LPFILETIME;
|
||||
|
||||
typedef struct _TIME_ZONE_INFORMATION {
|
||||
LONG Bias;
|
||||
WCHAR StandardName[32];
|
||||
SYSTEMTIME StandardDate;
|
||||
LONG StandardBias;
|
||||
WCHAR DaylightName[32];
|
||||
SYSTEMTIME DaylightDate;
|
||||
LONG DaylightBias;
|
||||
} TIME_ZONE_INFORMATION, *PTIME_ZONE_INFORMATION, *LPTIME_ZONE_INFORMATION;
|
||||
|
||||
typedef struct _TIME_DYNAMIC_ZONE_INFORMATION {
|
||||
LONG Bias;
|
||||
WCHAR StandardName[32];
|
||||
SYSTEMTIME StandardDate;
|
||||
LONG StandardBias;
|
||||
WCHAR DaylightName[32];
|
||||
SYSTEMTIME DaylightDate;
|
||||
LONG DaylightBias;
|
||||
WCHAR TimeZoneKeyName[128];
|
||||
BOOLEAN DynamicDaylightTimeDisabled;
|
||||
} DYNAMIC_TIME_ZONE_INFORMATION, *PDYNAMIC_TIME_ZONE_INFORMATION;
|
||||
|
||||
struct tm
|
||||
{
|
||||
int tm_sec; // seconds after the minute - [0, 60] including leap second
|
||||
int tm_min; // minutes after the hour - [0, 59]
|
||||
int tm_hour; // hours since midnight - [0, 23]
|
||||
int tm_mday; // day of the month - [1, 31]
|
||||
int tm_mon; // months since January - [0, 11]
|
||||
int tm_year; // years since 1900
|
||||
int tm_wday; // days since Sunday - [0, 6]
|
||||
int tm_yday; // days since January 1 - [0, 365]
|
||||
int tm_isdst; // daylight savings time flag
|
||||
};
|
||||
|
||||
BOOL
|
||||
SystemTimeToFileTime(
|
||||
const SYSTEMTIME* lpSystemTime,
|
||||
LPFILETIME lpFileTime
|
||||
);
|
||||
|
||||
BOOL
|
||||
FileTimeToSystemTime(
|
||||
const FILETIME* lpFileTime,
|
||||
LPSYSTEMTIME lpSystemTime
|
||||
);
|
||||
|
||||
BOOL
|
||||
SystemTimeToTzSpecificLocalTime(
|
||||
const TIME_ZONE_INFORMATION* lpTimeZoneInformation,
|
||||
const SYSTEMTIME* lpUniversalTime,
|
||||
LPSYSTEMTIME lpLocalTime
|
||||
);
|
||||
|
||||
BOOL
|
||||
SystemTimeToTzSpecificLocalTimeEx(
|
||||
const DYNAMIC_TIME_ZONE_INFORMATION* lpTimeZoneInformation,
|
||||
const SYSTEMTIME* lpUniversalTime,
|
||||
LPSYSTEMTIME lpLocalTime
|
||||
);
|
||||
|
||||
BOOL
|
||||
TzSpecificLocalTimeToSystemTime(
|
||||
const TIME_ZONE_INFORMATION* lpTimeZoneInformation,
|
||||
const SYSTEMTIME* lpLocalTime,
|
||||
LPSYSTEMTIME lpUniversalTime
|
||||
);
|
||||
|
||||
BOOL
|
||||
TzSpecificLocalTimeToSystemTimeEx(
|
||||
const DYNAMIC_TIME_ZONE_INFORMATION* lpTimeZoneInformation,
|
||||
const SYSTEMTIME* lpLocalTime,
|
||||
LPSYSTEMTIME lpUniversalTime
|
||||
);
|
||||
|
||||
void GetSystemTime(
|
||||
LPSYSTEMTIME lpSystemTime
|
||||
);
|
||||
|
||||
void GetSystemTimeAsFileTime(
|
||||
LPFILETIME lpSystemTimeAsFileTime
|
||||
);
|
||||
|
||||
__time64_t _mkgmtime64(
|
||||
struct tm* _Tm
|
||||
);
|
||||
|
||||
__time64_t _mkgmtime(
|
||||
struct tm* const _Tm
|
||||
)
|
||||
{
|
||||
return _mkgmtime64(_Tm);
|
||||
}
|
||||
|
||||
__time64_t mktime(
|
||||
struct tm* const _Tm
|
||||
)
|
||||
{
|
||||
return _mkgmtime64(_Tm);
|
||||
}
|
||||
|
||||
__time64_t _time64(
|
||||
__time64_t* _Time
|
||||
);
|
||||
|
||||
__time64_t time(
|
||||
time_t* const _Time
|
||||
)
|
||||
{
|
||||
return _time64(_Time);
|
||||
}
|
||||
|
||||
int gmtime_s(
|
||||
struct tm* _Tm,
|
||||
__time64_t const* _Time
|
||||
);
|
||||
|
||||
BOOL
|
||||
GetFileTime(
|
||||
HANDLE hFile,
|
||||
LPFILETIME lpCreationTime,
|
||||
LPFILETIME lpLastAccessTime,
|
||||
LPFILETIME lpLastWriteTime
|
||||
);
|
||||
|
||||
|
||||
void antipattern2()
|
||||
{
|
||||
// get the current time as a FILETIME
|
||||
SYSTEMTIME st; FILETIME ft;
|
||||
GetSystemTime(&st);
|
||||
SystemTimeToFileTime(&st, &ft);
|
||||
|
||||
// convert to a quadword (64-bit integer) to do arithmetic
|
||||
ULONGLONG qwLongTime;
|
||||
qwLongTime = (((ULONGLONG)ft.dwHighDateTime) << 32) + ft.dwLowDateTime;
|
||||
|
||||
// add a year by calculating the ticks in 365 days
|
||||
// (which may be incorrect when crossing a leap day)
|
||||
qwLongTime += 365 * 24 * 60 * 60 * 10000000LLU;
|
||||
|
||||
// copy back to a FILETIME
|
||||
ft.dwLowDateTime = (DWORD)(qwLongTime & 0xFFFFFFFF);
|
||||
ft.dwHighDateTime = (DWORD)(qwLongTime >> 32);
|
||||
|
||||
// convert back to SYSTEMTIME for display or other usage
|
||||
FileTimeToSystemTime(&ft, &st);
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
| test.cpp:17:6:17:10 | items | There is an array or std::vector allocation with a hard-coded set of 365 elements, which may indicate the number of days in a year without considering leap year scenarios. |
|
||||
| test.cpp:25:15:25:26 | new[] | There is an array or std::vector allocation with a hard-coded set of 365 elements, which may indicate the number of days in a year without considering leap year scenarios. |
|
||||
| test.cpp:52:20:52:23 | call to vector | There is an array or std::vector allocation with a hard-coded set of 365 elements, which may indicate the number of days in a year without considering leap year scenarios. |
|
||||
@@ -0,0 +1 @@
|
||||
Likely Bugs/Leap Year/UnsafeArrayForDaysOfYear.ql
|
||||
@@ -0,0 +1,70 @@
|
||||
template <class T>
|
||||
class vector {
|
||||
private:
|
||||
T _x;
|
||||
public:
|
||||
vector(int size)
|
||||
{
|
||||
}
|
||||
|
||||
T& operator[](int idx) { return _x; }
|
||||
const T& operator[](int idx) const { return _x; }
|
||||
};
|
||||
|
||||
void ArrayOfDays_Bug(int dayOfYear, int x)
|
||||
{
|
||||
// BUG
|
||||
int items[365];
|
||||
|
||||
items[dayOfYear - 1] = x;
|
||||
}
|
||||
|
||||
void ArrayOfDays_Bug2(int dayOfYear, int x)
|
||||
{
|
||||
// BUG
|
||||
int *items = new int[365];
|
||||
|
||||
items[dayOfYear - 1] = x;
|
||||
delete items;
|
||||
}
|
||||
|
||||
|
||||
void ArrayOfDays_Correct(unsigned long year, int dayOfYear, int x)
|
||||
{
|
||||
bool isLeapYear = year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
|
||||
int *items = new int[isLeapYear ? 366 : 365];
|
||||
|
||||
items[dayOfYear - 1] = x;
|
||||
|
||||
delete[] items;
|
||||
}
|
||||
|
||||
void ArrayOfDays_FalsePositive(int dayOfYear, int x)
|
||||
{
|
||||
int items[366];
|
||||
|
||||
items[dayOfYear - 1] = x;
|
||||
}
|
||||
|
||||
void VectorOfDays_Bug(int dayOfYear, int x)
|
||||
{
|
||||
// BUG
|
||||
vector<int> items(365);
|
||||
|
||||
items[dayOfYear - 1] = x;
|
||||
}
|
||||
|
||||
void VectorOfDays_Correct(unsigned long year, int dayOfYear, int x)
|
||||
{
|
||||
bool isLeapYear = year % 4 == 0 && (year % 100 != 0 || year % 400 == 0);
|
||||
vector<int> items(isLeapYear ? 366 : 365);
|
||||
|
||||
items[dayOfYear - 1] = x;
|
||||
}
|
||||
|
||||
void VectorOfDays_FalsePositive(int dayOfYear, int x)
|
||||
{
|
||||
vector<int> items(366);
|
||||
|
||||
items[dayOfYear - 1] = x;
|
||||
}
|
||||
Reference in New Issue
Block a user