Skip to content

Commit a388544

Browse files
committed
Warn for signed values passed as scanf targets with "x" conversion
1 parent 9c8b0c2 commit a388544

File tree

2 files changed

+20
-8
lines changed

2 files changed

+20
-8
lines changed

lib/checkio.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -728,7 +728,8 @@ void CheckIO::checkFormatString(const Token * const tok,
728728
if (!Token::Match(argInfo.typeToken, "char|short|int|long")) {
729729
if (argInfo.typeToken->isStandardType() || !argInfo.element)
730730
invalidScanfArgTypeError_int(tok, numFormat, specifier, &argInfo, true);
731-
} else if (!argInfo.isArrayOrPointer() ||
731+
} else if (!argInfo.typeToken->isUnsigned() ||
732+
!argInfo.isArrayOrPointer() ||
732733
argInfo.typeToken->strAt(-1) == "const") {
733734
invalidScanfArgTypeError_int(tok, numFormat, specifier, &argInfo, true);
734735
} else {

test/testio.cpp

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1006,6 +1006,7 @@ class TestIO : public TestFixture {
10061006

10071007
TEST_SCANF_WARN("%lx","unsigned long","bool");
10081008
TEST_SCANF_WARN("%lx","unsigned long","char");
1009+
TEST_SCANF_WARN("%lx","unsigned long","signed long");
10091010
TEST_SCANF_NOWARN("%lx","unsigned long","unsigned long");
10101011
TEST_SCANF_WARN("%lx","unsigned long","void *");
10111012
TEST_SCANF_WARN_AKA("%lx","unsigned long","size_t","unsigned long","unsigned long long");
@@ -1049,7 +1050,7 @@ class TestIO : public TestFixture {
10491050

10501051
TEST_SCANF_WARN("%llx","unsigned long long","bool");
10511052
TEST_SCANF_WARN("%llx","unsigned long long","char");
1052-
//TODO TEST_SCANF_WARN("%llx","unsigned long long","signed long long");
1053+
TEST_SCANF_WARN("%llx","unsigned long long","signed long long");
10531054
TEST_SCANF_NOWARN("%llx","unsigned long long","unsigned long long");
10541055
TEST_SCANF_WARN("%llx","unsigned long long","void *");
10551056
TEST_SCANF_WARN_AKA("%llx","unsigned long long","size_t", "unsigned long", "unsigned long long");
@@ -1092,7 +1093,7 @@ class TestIO : public TestFixture {
10921093

10931094
TEST_SCANF_WARN("%hx", "unsigned short", "bool");
10941095
TEST_SCANF_WARN("%hx", "unsigned short", "char");
1095-
// TODO TEST_SCANF_WARN("%hx", "unsigned short", "signed short");
1096+
TEST_SCANF_WARN("%hx", "unsigned short", "signed short");
10961097
TEST_SCANF_NOWARN("%hx", "unsigned short", "unsigned short");
10971098
TEST_SCANF_WARN("%hx", "unsigned short", "void *");
10981099
TEST_SCANF_WARN_AKA("%hx", "unsigned short", "std::intptr_t", "signed long", "signed long long");
@@ -1138,6 +1139,8 @@ class TestIO : public TestFixture {
11381139
TEST_SCANF_WARN_AKA("%hhu", "unsigned char", "std::uintptr_t", "unsigned long", "unsigned long long");
11391140

11401141
TEST_SCANF_WARN("%hhx", "unsigned char", "bool");
1142+
TEST_SCANF_WARN("%hhx", "unsigned char", "char");
1143+
TEST_SCANF_WARN("%hhx", "unsigned char", "signed char");
11411144
TEST_SCANF_NOWARN("%hhx", "unsigned char", "unsigned char");
11421145
TEST_SCANF_WARN("%hhx", "unsigned char", "void *");
11431146
TEST_SCANF_WARN_AKA("%hhx", "unsigned char", "std::intptr_t", "signed long", "signed long long");
@@ -1179,6 +1182,7 @@ class TestIO : public TestFixture {
11791182
// TODO TEST_SCANF_WARN_AKA("%Lu", "unsigned long long", "std::uintptr_t", "unsigned long", "unsigned long long");
11801183

11811184
TEST_SCANF_WARN("%Lx", "unsigned long long", "bool");
1185+
TEST_SCANF_WARN("%Lx", "unsigned long long", "signed long long");
11821186
TEST_SCANF_NOWARN("%Lx", "unsigned long long", "unsigned long long");
11831187
TEST_SCANF_WARN("%Lx", "unsigned long long", "void *");
11841188
TEST_SCANF_WARN_AKA_WIN32("%Lx", "unsigned long long", "size_t", "unsigned long");
@@ -1332,7 +1336,7 @@ class TestIO : public TestFixture {
13321336

13331337
TEST_SCANF_WARN("%tx", "unsigned ptrdiff_t", "long double");
13341338
TEST_SCANF_WARN("%tx", "unsigned ptrdiff_t", "void *");
1335-
// TODO TEST_SCANF_WARN_AKA("%tx", "unsigned ptrdiff_t", "ptrdiff_t", "signed long", "signed long long");
1339+
TEST_SCANF_WARN_AKA("%tx", "unsigned ptrdiff_t", "ptrdiff_t", "signed long", "signed long long");
13361340
TEST_SCANF_WARN_AKA("%tx", "unsigned ptrdiff_t", "intmax_t", "signed long", "signed long long");
13371341
TEST_SCANF_NOWARN("%tx", "unsigned ptrdiff_t", "unsigned ptrdiff_t");
13381342

@@ -1402,10 +1406,11 @@ class TestIO : public TestFixture {
14021406
TEST_SCANF_WARN("%I64x", "unsigned __int64", "unsigned char");
14031407
TEST_SCANF_WARN("%I64x", "unsigned __int64", "void *");
14041408
//TODO TEST_SCANF_WARN("%I64x", "unsigned __int64", "size_t");
1405-
TEST_SCANF_WARN_AKA_WIN32("%I64x", "unsigned __int64", "intmax_t", "signed long");
1406-
TEST_SCANF_WARN_AKA_WIN32("%I64x", "unsigned __int64", "ssize_t", "signed long");
1407-
TEST_SCANF_WARN_AKA_WIN32("%I64x", "unsigned __int64", "ptrdiff_t", "signed long");
1409+
TEST_SCANF_WARN_AKA("%I64x", "unsigned __int64", "intmax_t", "signed long", "signed long long");
1410+
TEST_SCANF_WARN_AKA("%I64x", "unsigned __int64", "ssize_t", "signed long", "signed long long");
1411+
TEST_SCANF_WARN_AKA("%I64x", "unsigned __int64", "ptrdiff_t", "signed long", "signed long long");
14081412
TEST_SCANF_NOWARN("%I64x", "unsigned __int64", "unsigned __int64");
1413+
// TODO TEST_SCANF_WARN("%I64x", "unsigned __int64", "__int64");
14091414

14101415
TEST_SCANF_WARN("%I64d", "__int64", "bool");
14111416
TEST_SCANF_WARN("%I64d", "__int64", "signed char");
@@ -1449,7 +1454,7 @@ class TestIO : public TestFixture {
14491454
TEST_SCANF_WARN("%I32x", "unsigned __int32", "unsigned char");
14501455
TEST_SCANF_WARN("%I32x", "unsigned __int32", "signed short");
14511456
TEST_SCANF_WARN("%I32x", "unsigned __int32", "unsigned short");
1452-
//TODO TEST_SCANF_WARN("%I32x", "unsigned __int32", "signed int");
1457+
TEST_SCANF_WARN("%I32x", "unsigned __int32", "signed int");
14531458
TEST_SCANF_NOWARN("%I32x", "unsigned __int32", "unsigned int");
14541459
TEST_SCANF_WARN("%I32x", "unsigned __int32", "signed long");
14551460
TEST_SCANF_WARN("%I32x", "unsigned __int32", "unsigned long");
@@ -3023,9 +3028,12 @@ class TestIO : public TestFixture {
30233028
"}", false, true, Settings::Win32A);
30243029
ASSERT_EQUALS("[test.cpp:8]: (portability) %Id in format string (no. 1) requires 'ptrdiff_t *' but the argument type is 'size_t * {aka unsigned long *}'.\n"
30253030
"[test.cpp:9]: (portability) %Iu in format string (no. 2) requires 'size_t *' but the argument type is 'ptrdiff_t * {aka signed long *}'.\n"
3031+
"[test.cpp:9]: (portability) %Ix in format string (no. 3) requires 'size_t *' but the argument type is 'ptrdiff_t * {aka signed long *}'.\n"
30263032
"[test.cpp:10]: (portability) %I32u in format string (no. 2) requires 'unsigned __int32 *' but the argument type is '__int32 * {aka signed int *}'.\n"
3033+
"[test.cpp:10]: (portability) %I32x in format string (no. 3) requires 'unsigned __int32 *' but the argument type is '__int32 * {aka signed int *}'.\n"
30273034
"[test.cpp:11]: (portability) %I32d in format string (no. 1) requires '__int32 *' but the argument type is 'unsigned __int32 * {aka unsigned int *}'.\n"
30283035
"[test.cpp:12]: (portability) %I64u in format string (no. 2) requires 'unsigned __int64 *' but the argument type is '__int64 * {aka signed long long *}'.\n"
3036+
"[test.cpp:12]: (portability) %I64x in format string (no. 3) requires 'unsigned __int64 *' but the argument type is '__int64 * {aka signed long long *}'.\n"
30293037
"[test.cpp:13]: (portability) %I64d in format string (no. 1) requires '__int64 *' but the argument type is 'unsigned __int64 * {aka unsigned long long *}'.\n", errout.str());
30303038

30313039
check("void foo() {\n"
@@ -3044,9 +3052,12 @@ class TestIO : public TestFixture {
30443052
"}", false, true, Settings::Win64);
30453053
ASSERT_EQUALS("[test.cpp:8]: (portability) %Id in format string (no. 1) requires 'ptrdiff_t *' but the argument type is 'size_t * {aka unsigned long long *}'.\n"
30463054
"[test.cpp:9]: (portability) %Iu in format string (no. 2) requires 'size_t *' but the argument type is 'ptrdiff_t * {aka signed long long *}'.\n"
3055+
"[test.cpp:9]: (portability) %Ix in format string (no. 3) requires 'size_t *' but the argument type is 'ptrdiff_t * {aka signed long long *}'.\n"
30473056
"[test.cpp:10]: (portability) %I32u in format string (no. 2) requires 'unsigned __int32 *' but the argument type is '__int32 * {aka signed int *}'.\n"
3057+
"[test.cpp:10]: (portability) %I32x in format string (no. 3) requires 'unsigned __int32 *' but the argument type is '__int32 * {aka signed int *}'.\n"
30483058
"[test.cpp:11]: (portability) %I32d in format string (no. 1) requires '__int32 *' but the argument type is 'unsigned __int32 * {aka unsigned int *}'.\n"
30493059
"[test.cpp:12]: (portability) %I64u in format string (no. 2) requires 'unsigned __int64 *' but the argument type is '__int64 * {aka signed long long *}'.\n"
3060+
"[test.cpp:12]: (portability) %I64x in format string (no. 3) requires 'unsigned __int64 *' but the argument type is '__int64 * {aka signed long long *}'.\n"
30503061
"[test.cpp:13]: (portability) %I64d in format string (no. 1) requires '__int64 *' but the argument type is 'unsigned __int64 * {aka unsigned long long *}'.\n", errout.str());
30513062

30523063
check("void foo() {\n"

0 commit comments

Comments
 (0)