Merge pull request #1354 from denislevin/denisl/cpp/MishandlingJapaneseDatesAndLeapYear

C++: Mishandling Japanese Era and Leap Year in calculations
This commit is contained in:
Geoffrey White
2019-06-18 09:26:35 +01:00
committed by GitHub
37 changed files with 1876 additions and 0 deletions

View File

@@ -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");
}

View File

@@ -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. |

View File

@@ -0,0 +1 @@
Likely Bugs/JapaneseEra/ConstructorOrMethodWithExactEraDate.ql

View File

@@ -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;
}

View File

@@ -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. |

View File

@@ -0,0 +1 @@
Likely Bugs/JapaneseEra/StructWithExactEraDate.ql

View File

@@ -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 |

View File

@@ -0,0 +1 @@
Likely Bugs/Leap Year/UncheckedLeapYearAfterYearModification.ql

View File

@@ -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 |

View File

@@ -0,0 +1 @@
Likely Bugs/Leap Year/UncheckedReturnValueForTimeFunctions.ql

View File

@@ -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++;
}
}

View File

@@ -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 |

View File

@@ -0,0 +1 @@
Likely Bugs/Leap Year/Adding365daysPerYear.ql

View File

@@ -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);
}

View File

@@ -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. |

View File

@@ -0,0 +1 @@
Likely Bugs/Leap Year/UnsafeArrayForDaysOfYear.ql

View File

@@ -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;
}