diff --git a/change-notes/1.19/analysis-cpp.md b/change-notes/1.19/analysis-cpp.md index 5a3340603c87..17cce1a5d529 100644 --- a/change-notes/1.19/analysis-cpp.md +++ b/change-notes/1.19/analysis-cpp.md @@ -13,7 +13,7 @@ | **Query** | **Expected impact** | **Change** | |----------------------------|------------------------|------------------------------------------------------------------| | Resource not released in destructor | Fewer false positive results | Placement new is now excluded from the query. | - +| Wrong type of arguments to formatting function | Fewer false positive results | False positive results involving typedefs have been removed. | ## Changes to QL libraries diff --git a/cpp/ql/src/Likely Bugs/Format/WrongTypeFormatArguments.ql b/cpp/ql/src/Likely Bugs/Format/WrongTypeFormatArguments.ql index 6ff67a1c9dc1..984642d109b9 100644 --- a/cpp/ql/src/Likely Bugs/Format/WrongTypeFormatArguments.ql +++ b/cpp/ql/src/Likely Bugs/Format/WrongTypeFormatArguments.ql @@ -66,30 +66,15 @@ predicate formatOtherArgType(FormattingFunctionCall ffc, int pos, Type expected, class ExpectedType extends Type { ExpectedType() { - formatArgType(_, _, this, _, _) or - formatOtherArgType(_, _, this, _, _) or - exists(ExpectedType t | - this = t.(PointerType).getBaseType() + exists(Type t | + ( + formatArgType(_, _, t, _, _) or + formatOtherArgType(_, _, t, _, _) + ) and this = t.getUnspecifiedType() ) } } -/** - * Gets an 'interesting' type that can be reached from `t` by removing - * typedefs and specifiers. Note that this does not always mean removing - * all typedefs and specifiers as `Type.getUnspecifiedType()` would, for - * example if the interesting type is itself a typedef. - */ -ExpectedType getAnUnderlyingExpectedType(Type t) { - ( - result = t - ) or ( - result = getAnUnderlyingExpectedType(t.(TypedefType).getBaseType()) - ) or ( - result = getAnUnderlyingExpectedType(t.(SpecifiedType).getBaseType()) - ) -} - /** * Holds if it is safe to display a value of type `actual` when `printf` * expects a value of type `expected`. @@ -100,59 +85,48 @@ ExpectedType getAnUnderlyingExpectedType(Type t) { * are converted to `double`. */ predicate trivialConversion(ExpectedType expected, Type actual) { - formatArgType(_, _, expected, _, actual) and - - exists(Type actualU | - actualU = actual.getUnspecifiedType() and + exists(Type exp, Type act | + formatArgType(_, _, exp, _, act) and + expected = exp.getUnspecifiedType() and + actual = act.getUnspecifiedType() + ) and ( ( - ( - // allow a pointer type to be displayed with `%p` - expected instanceof VoidPointerType and actualU instanceof PointerType - ) or ( - // allow a function pointer type to be displayed with `%p` - expected instanceof VoidPointerType and actualU instanceof FunctionPointerType and expected.getSize() = actual.getSize() - ) or ( - // allow an `enum` type to be displayed with `%i`, `%c` etc - expected instanceof IntegralType and actualU instanceof Enum - ) or ( - // allow any `char *` type to be displayed with `%s` - expected instanceof CharPointerType and actualU instanceof CharPointerType - ) or ( - // allow `wchar_t *`, or any pointer to an integral type of the same size, to be displayed - // with `%ws` - expected.(PointerType).getBaseType().hasName("wchar_t") and - exists(Wchar_t t | - actual.getUnspecifiedType().(PointerType).getBaseType().(IntegralType).getSize() = t.getSize() - ) - ) or ( - // allow an `int` (or anything promoted to `int`) to be displayed with `%c` - expected instanceof CharType and actualU instanceof IntType - ) or ( - // allow an `int` (or anything promoted to `int`) to be displayed with `%wc` - expected instanceof Wchar_t and actualU instanceof IntType - ) or ( - expected instanceof UnsignedCharType and actualU instanceof IntType - ) or ( - // allow the underlying type of a `size_t` (e.g. `unsigned long`) for - // `%zu`, since this is the type of a `sizeof` expression - expected instanceof Size_t and - actual.getUnspecifiedType() = expected.getUnspecifiedType() - ) or ( - // allow the underlying type of a `ssize_t` (e.g. `long`) for `%zd` - expected instanceof Ssize_t and - actual.getUnspecifiedType() = expected.getUnspecifiedType() - ) or ( - // allow any integral type of the same size - // (this permits signedness changes) - expected.(IntegralType).getSize() = actualU.(IntegralType).getSize() - ) or ( - // allow a pointer to any integral type of the same size - // (this permits signedness changes) - expected.(PointerType).getBaseType().(IntegralType).getSize() = actualU.(PointerType).getBaseType().(IntegralType).getSize() - ) or ( - // allow expected, or a typedef or specified version of expected - expected = getAnUnderlyingExpectedType(actual) + // allow a pointer type to be displayed with `%p` + expected instanceof VoidPointerType and actual instanceof PointerType + ) or ( + // allow a function pointer type to be displayed with `%p` + expected instanceof VoidPointerType and actual instanceof FunctionPointerType and expected.getSize() = actual.getSize() + ) or ( + // allow an `enum` type to be displayed with `%i`, `%c` etc + expected instanceof IntegralType and actual instanceof Enum + ) or ( + // allow any `char *` type to be displayed with `%s` + expected instanceof CharPointerType and actual instanceof CharPointerType + ) or ( + // allow `wchar_t *`, or any pointer to an integral type of the same size, to be displayed + // with `%ws` + expected.(PointerType).getBaseType().hasName("wchar_t") and + exists(Wchar_t t | + actual.getUnspecifiedType().(PointerType).getBaseType().(IntegralType).getSize() = t.getSize() ) + ) or ( + // allow an `int` (or anything promoted to `int`) to be displayed with `%c` + expected instanceof CharType and actual instanceof IntType + ) or ( + // allow an `int` (or anything promoted to `int`) to be displayed with `%wc` + expected instanceof Wchar_t and actual instanceof IntType + ) or ( + expected instanceof UnsignedCharType and actual instanceof IntType + ) or ( + // allow any integral type of the same size + // (this permits signedness changes) + expected.(IntegralType).getSize() = actual.(IntegralType).getSize() + ) or ( + // allow a pointer to any integral type of the same size + // (this permits signedness changes) + expected.(PointerType).getBaseType().(IntegralType).getSize() = actual.(PointerType).getBaseType().(IntegralType).getSize() + ) or ( + expected = actual ) ) } @@ -164,16 +138,16 @@ int sizeof_IntType() { exists(IntType it | result = it.getSize()) } -from FormattingFunctionCall ffc, int n, Expr arg, ExpectedType expected, Type actual +from FormattingFunctionCall ffc, int n, Expr arg, Type expected, Type actual where ( ( formatArgType(ffc, n, expected, arg, actual) and - not trivialConversion(expected, actual) + not trivialConversion(expected.getUnspecifiedType(), actual.getUnspecifiedType()) ) or ( formatOtherArgType(ffc, n, expected, arg, actual) and - not actual.getUnderlyingType().(IntegralType).getSize() = sizeof_IntType() + not actual.getUnspecifiedType().(IntegralType).getSize() = sizeof_IntType() ) ) and not arg.isAffectedByMacro() diff --git a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_signed_chars/WrongTypeFormatArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_signed_chars/WrongTypeFormatArguments.expected index b7c9985a9c69..568bb88ebeb3 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_signed_chars/WrongTypeFormatArguments.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_signed_chars/WrongTypeFormatArguments.expected @@ -11,14 +11,6 @@ | printf1.h:45:18:45:20 | ull | This argument should be of type 'unsigned int' but is of type 'unsigned long long' | | printf1.h:46:18:46:20 | ull | This argument should be of type 'unsigned int' but is of type 'unsigned long long' | | printf1.h:47:19:47:21 | ull | This argument should be of type 'unsigned int' but is of type 'unsigned long long' | -| printf1.h:68:19:68:21 | sst | This argument should be of type 'size_t' but is of type 'long' | -| printf1.h:70:19:70:20 | ul | This argument should be of type 'ssize_t' but is of type 'unsigned long' | -| printf1.h:71:19:71:20 | st | This argument should be of type 'ssize_t' but is of type 'unsigned long' | -| printf1.h:72:19:72:20 | ST | This argument should be of type 'ssize_t' but is of type 'unsigned long' | -| printf1.h:73:19:73:22 | c_st | This argument should be of type 'ssize_t' but is of type 'unsigned long' | -| printf1.h:74:19:74:22 | C_ST | This argument should be of type 'ssize_t' but is of type 'unsigned long' | -| printf1.h:75:19:75:28 | sizeof() | This argument should be of type 'ssize_t' but is of type 'unsigned long' | -| printf1.h:83:23:83:35 | ... - ... | This argument should be of type 'size_t' but is of type 'long' | | real_world.h:61:21:61:22 | & ... | This argument should be of type 'int *' but is of type 'short *' | | real_world.h:62:22:62:23 | & ... | This argument should be of type 'short *' but is of type 'int *' | | real_world.h:63:22:63:24 | & ... | This argument should be of type 'short *' but is of type 'unsigned int *' | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_signed_chars/printf1.h b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_signed_chars/printf1.h index c93695e0ec5d..824cd2d8aeda 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_signed_chars/printf1.h +++ b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_signed_chars/printf1.h @@ -65,14 +65,14 @@ void g() printf("%zu", c_st); // ok printf("%zu", C_ST); // ok printf("%zu", sizeof(ul)); // ok - printf("%zu", sst); // not ok [NOT DETECTED ON MICROSOFT] - - printf("%zd", ul); // not ok - printf("%zd", st); // not ok - printf("%zd", ST); // not ok - printf("%zd", c_st); // not ok - printf("%zd", C_ST); // not ok - printf("%zd", sizeof(ul)); // not ok + printf("%zu", sst); // not ok [NOT DETECTED] + + printf("%zd", ul); // not ok [NOT DETECTED] + printf("%zd", st); // not ok [NOT DETECTED] + printf("%zd", ST); // not ok [NOT DETECTED] + printf("%zd", c_st); // not ok [NOT DETECTED] + printf("%zd", C_ST); // not ok [NOT DETECTED] + printf("%zd", sizeof(ul)); // not ok [NOT DETECTED] printf("%zd", sst); // ok { char *ptr_a, *ptr_b; @@ -80,8 +80,8 @@ void g() printf("%tu", ptr_a - ptr_b); // ok printf("%td", ptr_a - ptr_b); // ok - printf("%zu", ptr_a - ptr_b); // ok (dubious) [DETECTED ON LINUX ONLY] - printf("%zd", ptr_a - ptr_b); // ok (dubious) [DETECTED ON MICROSOFT ONLY] + printf("%zu", ptr_a - ptr_b); // ok (dubious) + printf("%zd", ptr_a - ptr_b); // ok (dubious) } } @@ -92,3 +92,12 @@ void h(int i, struct some_type *j, int k) // going on. printf("%i %R %i", i, j, k); // GOOD (as far as we can tell) } + +typedef long ptrdiff_t; + +void fun1(unsigned char* a, unsigned char* b) { + ptrdiff_t pdt; + + printf("%td\n", pdt); // GOOD + printf("%td\n", a-b); // GOOD +} diff --git a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_unsigned_chars/WrongTypeFormatArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_unsigned_chars/WrongTypeFormatArguments.expected index b7c9985a9c69..568bb88ebeb3 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_unsigned_chars/WrongTypeFormatArguments.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_unsigned_chars/WrongTypeFormatArguments.expected @@ -11,14 +11,6 @@ | printf1.h:45:18:45:20 | ull | This argument should be of type 'unsigned int' but is of type 'unsigned long long' | | printf1.h:46:18:46:20 | ull | This argument should be of type 'unsigned int' but is of type 'unsigned long long' | | printf1.h:47:19:47:21 | ull | This argument should be of type 'unsigned int' but is of type 'unsigned long long' | -| printf1.h:68:19:68:21 | sst | This argument should be of type 'size_t' but is of type 'long' | -| printf1.h:70:19:70:20 | ul | This argument should be of type 'ssize_t' but is of type 'unsigned long' | -| printf1.h:71:19:71:20 | st | This argument should be of type 'ssize_t' but is of type 'unsigned long' | -| printf1.h:72:19:72:20 | ST | This argument should be of type 'ssize_t' but is of type 'unsigned long' | -| printf1.h:73:19:73:22 | c_st | This argument should be of type 'ssize_t' but is of type 'unsigned long' | -| printf1.h:74:19:74:22 | C_ST | This argument should be of type 'ssize_t' but is of type 'unsigned long' | -| printf1.h:75:19:75:28 | sizeof() | This argument should be of type 'ssize_t' but is of type 'unsigned long' | -| printf1.h:83:23:83:35 | ... - ... | This argument should be of type 'size_t' but is of type 'long' | | real_world.h:61:21:61:22 | & ... | This argument should be of type 'int *' but is of type 'short *' | | real_world.h:62:22:62:23 | & ... | This argument should be of type 'short *' but is of type 'int *' | | real_world.h:63:22:63:24 | & ... | This argument should be of type 'short *' but is of type 'unsigned int *' | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_unsigned_chars/printf1.h b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_unsigned_chars/printf1.h index c93695e0ec5d..824cd2d8aeda 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_unsigned_chars/printf1.h +++ b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Linux_unsigned_chars/printf1.h @@ -65,14 +65,14 @@ void g() printf("%zu", c_st); // ok printf("%zu", C_ST); // ok printf("%zu", sizeof(ul)); // ok - printf("%zu", sst); // not ok [NOT DETECTED ON MICROSOFT] - - printf("%zd", ul); // not ok - printf("%zd", st); // not ok - printf("%zd", ST); // not ok - printf("%zd", c_st); // not ok - printf("%zd", C_ST); // not ok - printf("%zd", sizeof(ul)); // not ok + printf("%zu", sst); // not ok [NOT DETECTED] + + printf("%zd", ul); // not ok [NOT DETECTED] + printf("%zd", st); // not ok [NOT DETECTED] + printf("%zd", ST); // not ok [NOT DETECTED] + printf("%zd", c_st); // not ok [NOT DETECTED] + printf("%zd", C_ST); // not ok [NOT DETECTED] + printf("%zd", sizeof(ul)); // not ok [NOT DETECTED] printf("%zd", sst); // ok { char *ptr_a, *ptr_b; @@ -80,8 +80,8 @@ void g() printf("%tu", ptr_a - ptr_b); // ok printf("%td", ptr_a - ptr_b); // ok - printf("%zu", ptr_a - ptr_b); // ok (dubious) [DETECTED ON LINUX ONLY] - printf("%zd", ptr_a - ptr_b); // ok (dubious) [DETECTED ON MICROSOFT ONLY] + printf("%zu", ptr_a - ptr_b); // ok (dubious) + printf("%zd", ptr_a - ptr_b); // ok (dubious) } } @@ -92,3 +92,12 @@ void h(int i, struct some_type *j, int k) // going on. printf("%i %R %i", i, j, k); // GOOD (as far as we can tell) } + +typedef long ptrdiff_t; + +void fun1(unsigned char* a, unsigned char* b) { + ptrdiff_t pdt; + + printf("%td\n", pdt); // GOOD + printf("%td\n", a-b); // GOOD +} diff --git a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Microsoft/WrongTypeFormatArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Microsoft/WrongTypeFormatArguments.expected index 9594b6afac21..fdafea706aba 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Microsoft/WrongTypeFormatArguments.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Microsoft/WrongTypeFormatArguments.expected @@ -11,7 +11,6 @@ | printf1.h:45:18:45:20 | ull | This argument should be of type 'unsigned int' but is of type 'unsigned long long' | | printf1.h:46:18:46:20 | ull | This argument should be of type 'unsigned int' but is of type 'unsigned long long' | | printf1.h:47:19:47:21 | ull | This argument should be of type 'unsigned int' but is of type 'unsigned long long' | -| printf1.h:70:19:70:20 | ul | This argument should be of type 'ssize_t' but is of type 'unsigned long' | | printf1.h:71:19:71:20 | st | This argument should be of type 'ssize_t' but is of type 'unsigned long long' | | printf1.h:72:19:72:20 | ST | This argument should be of type 'ssize_t' but is of type 'unsigned long long' | | printf1.h:73:19:73:22 | c_st | This argument should be of type 'ssize_t' but is of type 'unsigned long long' | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Microsoft/printf1.h b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Microsoft/printf1.h index c93695e0ec5d..3907977df3f0 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Microsoft/printf1.h +++ b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Microsoft/printf1.h @@ -65,9 +65,9 @@ void g() printf("%zu", c_st); // ok printf("%zu", C_ST); // ok printf("%zu", sizeof(ul)); // ok - printf("%zu", sst); // not ok [NOT DETECTED ON MICROSOFT] + printf("%zu", sst); // not ok [NOT DETECTED] - printf("%zd", ul); // not ok + printf("%zd", ul); // not ok [NOT DETECTED] printf("%zd", st); // not ok printf("%zd", ST); // not ok printf("%zd", c_st); // not ok @@ -80,8 +80,8 @@ void g() printf("%tu", ptr_a - ptr_b); // ok printf("%td", ptr_a - ptr_b); // ok - printf("%zu", ptr_a - ptr_b); // ok (dubious) [DETECTED ON LINUX ONLY] - printf("%zd", ptr_a - ptr_b); // ok (dubious) [DETECTED ON MICROSOFT ONLY] + printf("%zu", ptr_a - ptr_b); // ok (dubious) + printf("%zd", ptr_a - ptr_b); // ok (dubious) [FALSE POSITIVE] } } @@ -92,3 +92,12 @@ void h(int i, struct some_type *j, int k) // going on. printf("%i %R %i", i, j, k); // GOOD (as far as we can tell) } + +typedef long long ptrdiff_t; + +void fun1(unsigned char* a, unsigned char* b) { + ptrdiff_t pdt; + + printf("%td\n", pdt); // GOOD + printf("%td\n", a-b); // GOOD +} diff --git a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Microsoft/real_world.h b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Microsoft/real_world.h index eefb84993e74..e88d0318bb05 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Microsoft/real_world.h +++ b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Microsoft/real_world.h @@ -43,7 +43,7 @@ void someFunction() WCHAR filename[MAX_LONGPATH]; int linenum; - msg_out("Source file: %S @ %d\n", filename, linenum); // GOOD + msg_out("Source file: %S @ %d\n", filename, linenum); // GOOD [FALSE POSITIVE] } // -------------------------------------------------------------- diff --git a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Microsoft_no_wchar/WrongTypeFormatArguments.expected b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Microsoft_no_wchar/WrongTypeFormatArguments.expected index 9594b6afac21..fa245ce45bf5 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Microsoft_no_wchar/WrongTypeFormatArguments.expected +++ b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Microsoft_no_wchar/WrongTypeFormatArguments.expected @@ -11,13 +11,13 @@ | printf1.h:45:18:45:20 | ull | This argument should be of type 'unsigned int' but is of type 'unsigned long long' | | printf1.h:46:18:46:20 | ull | This argument should be of type 'unsigned int' but is of type 'unsigned long long' | | printf1.h:47:19:47:21 | ull | This argument should be of type 'unsigned int' but is of type 'unsigned long long' | -| printf1.h:70:19:70:20 | ul | This argument should be of type 'ssize_t' but is of type 'unsigned long' | | printf1.h:71:19:71:20 | st | This argument should be of type 'ssize_t' but is of type 'unsigned long long' | | printf1.h:72:19:72:20 | ST | This argument should be of type 'ssize_t' but is of type 'unsigned long long' | | printf1.h:73:19:73:22 | c_st | This argument should be of type 'ssize_t' but is of type 'unsigned long long' | | printf1.h:74:19:74:22 | C_ST | This argument should be of type 'ssize_t' but is of type 'unsigned long long' | | printf1.h:75:19:75:28 | sizeof() | This argument should be of type 'ssize_t' but is of type 'unsigned long long' | | printf1.h:84:23:84:35 | ... - ... | This argument should be of type 'ssize_t' but is of type 'long long' | +| real_world.h:46:36:46:43 | filename | This argument should be of type 'wchar_t *' but is of type 'char16_t *' | | real_world.h:61:21:61:22 | & ... | This argument should be of type 'int *' but is of type 'short *' | | real_world.h:62:22:62:23 | & ... | This argument should be of type 'short *' but is of type 'int *' | | real_world.h:63:22:63:24 | & ... | This argument should be of type 'short *' but is of type 'unsigned int *' | diff --git a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Microsoft_no_wchar/printf1.h b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Microsoft_no_wchar/printf1.h index c93695e0ec5d..3907977df3f0 100644 --- a/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Microsoft_no_wchar/printf1.h +++ b/cpp/ql/test/query-tests/Likely Bugs/Format/WrongTypeFormatArguments/Microsoft_no_wchar/printf1.h @@ -65,9 +65,9 @@ void g() printf("%zu", c_st); // ok printf("%zu", C_ST); // ok printf("%zu", sizeof(ul)); // ok - printf("%zu", sst); // not ok [NOT DETECTED ON MICROSOFT] + printf("%zu", sst); // not ok [NOT DETECTED] - printf("%zd", ul); // not ok + printf("%zd", ul); // not ok [NOT DETECTED] printf("%zd", st); // not ok printf("%zd", ST); // not ok printf("%zd", c_st); // not ok @@ -80,8 +80,8 @@ void g() printf("%tu", ptr_a - ptr_b); // ok printf("%td", ptr_a - ptr_b); // ok - printf("%zu", ptr_a - ptr_b); // ok (dubious) [DETECTED ON LINUX ONLY] - printf("%zd", ptr_a - ptr_b); // ok (dubious) [DETECTED ON MICROSOFT ONLY] + printf("%zu", ptr_a - ptr_b); // ok (dubious) + printf("%zd", ptr_a - ptr_b); // ok (dubious) [FALSE POSITIVE] } } @@ -92,3 +92,12 @@ void h(int i, struct some_type *j, int k) // going on. printf("%i %R %i", i, j, k); // GOOD (as far as we can tell) } + +typedef long long ptrdiff_t; + +void fun1(unsigned char* a, unsigned char* b) { + ptrdiff_t pdt; + + printf("%td\n", pdt); // GOOD + printf("%td\n", a-b); // GOOD +}