C++: Support sizeof VLAs in the IR

This commit is contained in:
Jeroen Ketema
2025-08-29 17:51:51 +02:00
parent 60845001dd
commit d9320b3c16
3 changed files with 109 additions and 4 deletions

View File

@@ -97,7 +97,12 @@ newtype TInstructionTag =
exists(Stmt s | exists(s.getImplicitDestructorCall(index)))
} or
CoAwaitBranchTag() or
BoolToIntConversionTag()
BoolToIntConversionTag() or
SizeofVlaDimensionTag(int index) {
index = -1
or
exists(VlaDeclStmt v | exists(v.getVlaDimensionStmt(index)))
}
class InstructionTag extends TInstructionTag {
final string toString() { result = getInstructionTagId(this) }

View File

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

View File

@@ -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`.
@@ -4094,6 +4094,103 @@ 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
result = getVlaDeclStmt(expr.(PointerDereferenceExpr).getOperand(), pointerDerefCount - 1)
}
class TranslatedSizeofExpr extends TranslatedNonConstantExpr {
override SizeofExprOperator expr;
VlaDeclStmt vlaDeclStmt;
int pointerDerefCount;
TranslatedSizeofExpr() {
vlaDeclStmt = getVlaDeclStmt(expr.getExprOperand(), pointerDerefCount) and
pointerDerefCount < vlaDeclStmt.getNumberOfVlaDimensionStmts()
}
final override Instruction getFirstInstruction(EdgeKind kind) {
result = this.getInstruction(SizeofVlaDimensionTag(-1)) and
kind instanceof GotoEdge
}
override Instruction getALastInstructionInternal() {
result =
this.getInstruction(SizeofVlaDimensionTag(vlaDeclStmt.getNumberOfVlaDimensionStmts() - 1))
}
final override TranslatedElement getChildInternal(int id) { none() }
final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
opcode instanceof Opcode::Constant and
tag = SizeofVlaDimensionTag(-1) and
resultType = this.getResultType()
or
opcode instanceof Opcode::Mul and
exists(int n | pointerDerefCount <= n and n < vlaDeclStmt.getNumberOfVlaDimensionStmts() |
tag = SizeofVlaDimensionTag(n)
) and
resultType = this.getResultType()
}
final override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) {
tag = SizeofVlaDimensionTag(-1) and
result = this.getInstruction(SizeofVlaDimensionTag(pointerDerefCount)) and
kind instanceof GotoEdge
or
exists(int n | pointerDerefCount <= n and n < vlaDeclStmt.getNumberOfVlaDimensionStmts() - 1 |
tag = SizeofVlaDimensionTag(n) and
result = this.getInstruction(SizeofVlaDimensionTag(n + 1))
) and
kind instanceof GotoEdge
or
tag = SizeofVlaDimensionTag(vlaDeclStmt.getNumberOfVlaDimensionStmts() - 1) and
result = this.getParent().getChildSuccessor(this, kind)
}
override string getInstructionConstantValue(InstructionTag tag) {
tag = SizeofVlaDimensionTag(-1) and
result =
this.getBaseSize(vlaDeclStmt.getVariable().getType(),
vlaDeclStmt.getNumberOfVlaDimensionStmts() - 1).toString()
}
private int getBaseSize(DerivedType type, int n) {
n = 0 and
result = type.getBaseType().getSize()
or
n = [1 .. vlaDeclStmt.getNumberOfVlaDimensionStmts() - 1] and
result = this.getBaseSize(type.getBaseType(), n - 1)
}
override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
exists(int n | pointerDerefCount <= n and n < vlaDeclStmt.getNumberOfVlaDimensionStmts() |
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(SizeofVlaDimensionTag(-1))
)
or
operandTag instanceof RightOperandTag and
result =
getTranslatedExpr(vlaDeclStmt.getVlaDimensionStmt(n).getDimensionExpr()).getResult()
)
)
}
final override Instruction getResult() {
result =
this.getInstruction(SizeofVlaDimensionTag(vlaDeclStmt.getNumberOfVlaDimensionStmts() - 1))
}
}
class TranslatedErrorExpr extends TranslatedSingleInstructionExpr {
override ErrorExpr expr;