C++: Make the 'getBufferSize' a lot more like the pre-use-use flow implementation.

This commit is contained in:
Mathias Vorreiter Pedersen
2022-12-16 12:58:45 +00:00
parent 31b4dda7bd
commit c06f7259cf

View File

@@ -73,67 +73,29 @@ private int isSource(Expr bufferExpr, Element why) {
)
}
/**
* Holds if `e2` is an expression that is derived from `e1` such that if `e1[n]` is a
* well-defined expression for some number `n`, then `e2[n + delta]` is also a well-defined
* expression.
*/
private predicate step(Expr e1, Expr e2, int delta) {
getBufferSizeCand0(e1) and
(
exists(Variable bufferVar, Class parentClass, VariableAccess parentPtr, int bufferSize |
e1 = parentPtr
|
bufferVar = e2.(VariableAccess).getTarget() and
// buffer is the parentPtr->bufferVar of a 'variable size struct'
memberMayBeVarSize(parentClass, bufferVar) and
parentPtr = e2.(VariableAccess).getQualifier() and
parentPtr.getTarget().getUnspecifiedType().(PointerType).getBaseType() = parentClass and
(
if exists(bufferVar.getType().getSize())
then bufferSize = bufferVar.getType().getSize()
else bufferSize = 0
) and
delta = bufferSize - parentClass.getSize()
)
or
DataFlow::localExprFlowStep(e1, e2) and
delta = 0
)
}
pragma[nomagic]
private predicate getBufferSizeCand0(Expr e) {
exists(isSource(e, _))
or
exists(Expr e0 |
getBufferSizeCand0(e0) and
step(e0, e, _)
)
}
/**
* Get the size in bytes of the buffer pointed to by an expression (if this can be determined).
*
* NOTE: There can be multiple `(result, why)` for a given `bufferExpr`.
*/
private int getBufferSizeCand(Expr bufferExpr, Element why) {
getBufferSizeCand0(bufferExpr) and
(
result = isSource(bufferExpr, why)
or
exists(Expr e0, int delta, int size |
size = getBufferSizeCand(e0, why) and
step(e0, bufferExpr, delta) and
result = size + delta
)
)
}
/**
* Get the size in bytes of the buffer pointed to by an expression (if this can be determined).
*/
language[monotonicAggregates]
int getBufferSize(Expr bufferExpr, Element why) {
result = max( | | getBufferSizeCand(bufferExpr, _)) and
result = getBufferSizeCand(bufferExpr, why)
result = isSource(bufferExpr, why)
or
exists(Class parentClass, VariableAccess parentPtr, int bufferSize, Variable bufferVar |
bufferVar = bufferExpr.(VariableAccess).getTarget() and
// buffer is the parentPtr->bufferVar of a 'variable size struct'
memberMayBeVarSize(parentClass, bufferVar) and
why = bufferVar and
parentPtr = bufferExpr.(VariableAccess).getQualifier() and
parentPtr.getTarget().getUnspecifiedType().(PointerType).getBaseType() = parentClass and
result = getBufferSize(parentPtr, _) + bufferSize - parentClass.getSize()
|
if exists(bufferVar.getType().getSize())
then bufferSize = bufferVar.getType().getSize()
else bufferSize = 0
)
or
// dataflow (all sources must be the same size)
result = unique(Expr def | DataFlow::localExprFlowStep(def, bufferExpr) | getBufferSize(def, _)) and
// find reason
exists(Expr def | DataFlow::localExprFlowStep(def, bufferExpr) | exists(getBufferSize(def, why)))
}