Merge pull request #189 from geoffw0/wrongtypedef

CPP: Permit more typedefs in WrongTypeFormatArguments.ql
This commit is contained in:
Jonas Jensen
2018-10-03 09:40:06 +02:00
committed by GitHub
11 changed files with 113 additions and 120 deletions

View File

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

View File

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

View File

@@ -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(<expr>) | 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 *' |

View File

@@ -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("%zu", sst); // not ok [NOT DETECTED]
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("%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
}

View File

@@ -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(<expr>) | 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 *' |

View File

@@ -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("%zu", sst); // not ok [NOT DETECTED]
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("%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
}

View File

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

View File

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

View File

@@ -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]
}
// --------------------------------------------------------------

View File

@@ -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(<expr>) | 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 *' |

View File

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