Merge pull request #6679 from andersfugmann/relax_memberMayBeVarSize

Improve precision on OverflowStatic query.
This commit is contained in:
Mathias Vorreiter Pedersen
2021-09-15 17:24:10 +01:00
committed by GitHub
6 changed files with 81 additions and 21 deletions

View File

@@ -2,17 +2,18 @@ import cpp
import semmle.code.cpp.dataflow.DataFlow
/**
* Holds if `v` is a member variable of `c` that looks like it might be variable sized in practice. For
* example:
* Holds if `v` is a member variable of `c` that looks like it might be variable sized
* in practice. For example:
* ```
* struct myStruct { // c
* int amount;
* char data[1]; // v
* };
* ```
* This requires that `v` is an array of size 0 or 1, and `v` is the last member of `c`. In addition,
* there must be at least one instance where a `c` pointer is allocated with additional space. For
* example, holds for `c` if it occurs as
* This requires that `v` is an array of size 0 or 1, and `v` is the last member of `c`.
* In addition, if the size of the structure is taken, there must be at least one instance
* where a `c` pointer is allocated with additional space.
* For example, holds for `c` if it occurs as
* ```
* malloc(sizeof(c) + 100 * sizeof(char))
* ```
@@ -27,27 +28,25 @@ predicate memberMayBeVarSize(Class c, MemberVariable v) {
i = max(int j | c.getCanonicalMember(j) instanceof Field | j) and
v = c.getCanonicalMember(i) and
// v is an array of size at most 1
v.getUnspecifiedType().(ArrayType).getArraySize() <= 1
v.getUnspecifiedType().(ArrayType).getArraySize() <= 1 and
not c instanceof Union
) and
// If the size is taken, then arithmetic is performed on the result at least once
(
// `sizeof(c)` is not taken
not exists(SizeofOperator so |
so.(SizeofTypeOperator).getTypeOperand().getUnspecifiedType() = c or
so.(SizeofExprOperator).getExprOperand().getUnspecifiedType() = c
)
or
// or `sizeof(c)` is taken
exists(SizeofOperator so |
// `sizeof(c)` is taken
so.(SizeofTypeOperator).getTypeOperand().getUnspecifiedType() = c or
so.(SizeofExprOperator).getExprOperand().getUnspecifiedType() = c
|
// arithmetic is performed on the result
// and arithmetic is performed on the result
so.getParent*() instanceof AddExpr
)
or
exists(AddressOfExpr aoe |
// `&(c.v)` is taken
aoe.getAddressable() = v
)
or
exists(BuiltInOperationBuiltInOffsetOf oo |
// `offsetof(c, v)` using a builtin
oo.getAChild().(VariableAccess).getTarget() = v
)
)
}
@@ -61,6 +60,10 @@ int getBufferSize(Expr bufferExpr, Element why) {
result = bufferVar.getUnspecifiedType().(ArrayType).getSize() and
why = bufferVar and
not memberMayBeVarSize(_, bufferVar) and
not exists(Union bufferType |
bufferType.getAMemberVariable() = why and
bufferVar.getUnspecifiedType().(ArrayType).getSize() <= 1
) and
not result = 0 // zero sized arrays are likely to have special usage, for example
or
// behaving a bit like a 'union' overlapping other fields.
@@ -82,6 +85,13 @@ int getBufferSize(Expr bufferExpr, Element why) {
parentPtr.getTarget().getUnspecifiedType().(PointerType).getBaseType() = parentClass and
result = getBufferSize(parentPtr, _) + bufferVar.getType().getSize() - parentClass.getSize()
)
or
exists(Union bufferType |
bufferType.getAMemberVariable() = why and
why = bufferVar and
bufferVar.getUnspecifiedType().(ArrayType).getSize() <= 1 and
result = bufferType.getSize()
)
)
or
// buffer is a fixed size dynamic allocation