Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions cpp/ql/lib/change-notes/2025-09-02-vla.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
category: feature
---
* Added predicates `getTransitiveNumberOfVlaDimensionStmts`, `getTransitiveVlaDimensionStmt`, and `getParentVlaDecl` to `VlaDeclStmt` for handling `VlaDeclStmt`s whose base type defined in terms of an other `VlaDeclStmt` via a `typedef`.
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,14 @@ newtype TInstructionTag =
exists(Stmt s | exists(s.getImplicitDestructorCall(index)))
} or
CoAwaitBranchTag() or
BoolToIntConversionTag()
BoolToIntConversionTag() or
SizeofVlaBaseSizeTag() or
SizeofVlaConversionTag(int index) {
exists(VlaDeclStmt v | exists(v.getTransitiveVlaDimensionStmt(index)))
} or
SizeofVlaDimensionTag(int index) {
exists(VlaDeclStmt v | exists(v.getTransitiveVlaDimensionStmt(index)))
}

class InstructionTag extends TInstructionTag {
final string toString() { result = getInstructionTagId(this) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,13 +123,16 @@ private predicate ignoreExprAndDescendants(Expr expr) {
// or
ignoreExprAndDescendants(getRealParent(expr)) // recursive case
or
// va_start doesn't evaluate its argument, so we don't need to translate it.
// va_start does not evaluate its argument, so we do not need to translate it.
exists(BuiltInVarArgsStart vaStartExpr |
vaStartExpr.getLastNamedParameter().getFullyConverted() = expr
)
or
// sizeof does not evaluate its argument, so we do not need to translate it.
exists(SizeofExprOperator sizeofExpr | sizeofExpr.getExprOperand().getFullyConverted() = expr)
or
// The children of C11 _Generic expressions are just surface syntax.
exists(C11GenericExpr generic | generic.getAChild() = expr)
exists(C11GenericExpr generic | generic.getAChild().getFullyConverted() = expr)
or
// Do not translate implicit destructor calls for unnamed temporary variables that are
// conditionally constructed (until we have a mechanism for calling these only when the
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ Variable getEnclosingVariable(Expr e) {
}

/**
* The IR translation of the "core" part of an expression. This is the part of
* The IR translation of the "core" part of an expression. This is the part of
* the expression that produces the result value of the expression, before any
* lvalue-to-rvalue conversion on the result. Every expression has a single
* `TranslatedCoreExpr`.
Expand Down Expand Up @@ -4094,6 +4094,155 @@ class TranslatedStmtExpr extends TranslatedNonConstantExpr {
TranslatedStmt getStmt() { result = getTranslatedStmt(expr.getStmt()) }
}

private VlaDeclStmt getVlaDeclStmt(Expr expr, int pointerDerefCount) {
expr.(VariableAccess).getTarget() = result.getVariable() and
pointerDerefCount = 0
or
not expr.(PointerDereferenceExpr).getOperand() instanceof AddressOfExpr and
result = getVlaDeclStmt(expr.(PointerDereferenceExpr).getOperand(), pointerDerefCount - 1)
or
// Skip sequences of the form `*&...`
result =
getVlaDeclStmt(expr.(PointerDereferenceExpr).getOperand().(AddressOfExpr).getOperand(),
pointerDerefCount)
or
result = getVlaDeclStmt(expr.(ArrayExpr).getArrayBase(), pointerDerefCount - 1)
}

/**
* The IR translation of `SizeofExprOperator` when its result is non-constant, i.e.,
* when the operand expression refers to a variable length array.
*/
class TranslatedSizeofExpr extends TranslatedNonConstantExpr {
override SizeofExprOperator expr;
VlaDeclStmt vlaDeclStmt;
int vlaDimensions;
int pointerDerefCount;

TranslatedSizeofExpr() {
vlaDeclStmt = getVlaDeclStmt(expr.getExprOperand(), pointerDerefCount) and
vlaDimensions = vlaDeclStmt.getTransitiveNumberOfVlaDimensionStmts() and
pointerDerefCount < vlaDimensions
}

final override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getInstruction(SizeofVlaBaseSizeTag()) and
kind instanceof GotoEdge
}

override Instruction getALastInstructionInternal() {
result = this.getInstruction(SizeofVlaDimensionTag(vlaDimensions - 1))
}

final override TranslatedElement getChildInternal(int id) { none() }

final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
opcode instanceof Opcode::Constant and
tag = SizeofVlaBaseSizeTag() and
resultType = this.getResultType()
or
exists(int n, Type dimType |
pointerDerefCount <= n and
n < vlaDimensions and
dimType = this.getDimensionExpr(n).getUnderlyingType() and
tag = SizeofVlaConversionTag(n)
|
(
expr.getUnderlyingType() = dimType and
opcode instanceof Opcode::CopyValue
or
not expr.getUnderlyingType() = dimType and
opcode instanceof Opcode::Convert
)
) and
resultType = this.getResultType()
or
opcode instanceof Opcode::Mul and
exists(int n | pointerDerefCount <= n and n < vlaDimensions | tag = SizeofVlaDimensionTag(n)) and
resultType = this.getResultType()
}

final override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) {
tag = SizeofVlaBaseSizeTag() and
result = this.getInstruction(SizeofVlaConversionTag(pointerDerefCount)) and
kind instanceof GotoEdge
or
exists(int n | pointerDerefCount <= n and n < vlaDimensions |
tag = SizeofVlaConversionTag(n) and
result = this.getInstruction(SizeofVlaDimensionTag(n))
) and
kind instanceof GotoEdge
or
exists(int n | pointerDerefCount <= n and n < vlaDimensions - 1 |
tag = SizeofVlaDimensionTag(n) and
result = this.getInstruction(SizeofVlaConversionTag(n + 1))
) and
kind instanceof GotoEdge
or
tag = SizeofVlaDimensionTag(vlaDimensions - 1) and
result = this.getParent().getChildSuccessor(this, kind)
}

override string getInstructionConstantValue(InstructionTag tag) {
tag = SizeofVlaBaseSizeTag() and
result = this.getBaseType(vlaDeclStmt).getSize().toString()
}

private Type getBaseType(VlaDeclStmt v) {
not exists(v.getParentVlaDecl()) and
(
result =
this.getBaseType(v.getVariable().getUnderlyingType(), v.getNumberOfVlaDimensionStmts())
or
result = this.getBaseType(v.getType().getUnderlyingType(), v.getNumberOfVlaDimensionStmts())
)
or
result = this.getBaseType(v.getParentVlaDecl())
}

private Type getBaseType(Type type, int n) {
n = 0 and
result = type
or
result = this.getBaseType(type.(DerivedType).getBaseType(), n - 1)
}

override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
exists(int n | pointerDerefCount <= n and n < vlaDimensions |
tag = SizeofVlaConversionTag(n) and
(
operandTag instanceof UnaryOperandTag and
result = getTranslatedExpr(this.getDimensionExpr(n)).getResult()
)
)
or
exists(int n | pointerDerefCount <= n and n < vlaDimensions |
tag = SizeofVlaDimensionTag(n) and
(
operandTag instanceof LeftOperandTag and
(
n - 1 >= pointerDerefCount and
result = this.getInstruction(SizeofVlaDimensionTag(n - 1))
or
n - 1 < pointerDerefCount and
result = this.getInstruction(SizeofVlaBaseSizeTag())
)
or
operandTag instanceof RightOperandTag and
result = this.getInstruction(SizeofVlaConversionTag(n))
)
)
}

private Expr getDimensionExpr(int n) {
result = vlaDeclStmt.getTransitiveVlaDimensionStmt(n).getDimensionExpr().getFullyConverted()
}

final override Instruction getResult() {
result = this.getInstruction(SizeofVlaDimensionTag(vlaDimensions - 1))
}
}

class TranslatedErrorExpr extends TranslatedSingleInstructionExpr {
override ErrorExpr expr;

Expand Down
54 changes: 54 additions & 0 deletions cpp/ql/lib/semmle/code/cpp/stmts/Stmt.qll
Original file line number Diff line number Diff line change
Expand Up @@ -2355,6 +2355,20 @@ class VlaDeclStmt extends Stmt, @stmt_vla_decl {
)
}

/**
* Gets the number of VLA dimension statements in this VLA declaration
* statement and transitively of the VLA declaration used to define its
* base type. if any.
*/
int getTransitiveNumberOfVlaDimensionStmts() {
not exists(this.getParentVlaDecl()) and
result = this.getNumberOfVlaDimensionStmts()
or
result =
this.getNumberOfVlaDimensionStmts() +
this.getParentVlaDecl().getTransitiveNumberOfVlaDimensionStmts()
}

/**
* Gets the `i`th VLA dimension statement in this VLA
* declaration statement.
Expand All @@ -2367,6 +2381,19 @@ class VlaDeclStmt extends Stmt, @stmt_vla_decl {
)
}

/**
* Gets the `i`th VLA dimension statement in this VLA declaration
* statement or transitively of the VLA declaration used to define
* its base type.
*/
VlaDimensionStmt getTransitiveVlaDimensionStmt(int i) {
i < this.getNumberOfVlaDimensionStmts() and
result = this.getVlaDimensionStmt(i)
or
result =
this.getParentVlaDecl().getTransitiveVlaDimensionStmt(i - this.getNumberOfVlaDimensionStmts())
}

/**
* Gets the type that this VLA declaration statement relates to,
* if any.
Expand All @@ -2378,4 +2405,31 @@ class VlaDeclStmt extends Stmt, @stmt_vla_decl {
* if any.
*/
Variable getVariable() { variable_vla(unresolveElement(result), underlyingElement(this)) }

/**
* Get the VLA declaration used to define the base type of
* this VLA declaration, if any.
*/
VlaDeclStmt getParentVlaDecl() {
exists(Variable v, Type baseType |
v = this.getVariable() and
baseType = this.getBaseType(v.getType(), this.getNumberOfVlaDimensionStmts())
|
result.getType() = baseType
)
or
exists(Type t, Type baseType |
t = this.getType().(TypedefType).getBaseType() and
baseType = this.getBaseType(t, this.getNumberOfVlaDimensionStmts())
|
result.getType() = baseType
)
}

private Type getBaseType(Type type, int n) {
n = 0 and
result = type
or
result = this.getBaseType(type.(DerivedType).getBaseType(), n - 1)
}
}
Loading