Skip to content

Commit ab3ad20

Browse files
authored
Merge pull request #20319 from jketema/ir-vla-sizeof
C++: Support `sizeof` VLAs in the IR
2 parents 17d23a9 + 8de1ed0 commit ab3ad20

File tree

9 files changed

+1252
-4
lines changed

9 files changed

+1252
-4
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: feature
3+
---
4+
* 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`.

cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/InstructionTag.qll

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,14 @@ newtype TInstructionTag =
9797
exists(Stmt s | exists(s.getImplicitDestructorCall(index)))
9898
} or
9999
CoAwaitBranchTag() or
100-
BoolToIntConversionTag()
100+
BoolToIntConversionTag() or
101+
SizeofVlaBaseSizeTag() or
102+
SizeofVlaConversionTag(int index) {
103+
exists(VlaDeclStmt v | exists(v.getTransitiveVlaDimensionStmt(index)))
104+
} or
105+
SizeofVlaDimensionTag(int index) {
106+
exists(VlaDeclStmt v | exists(v.getTransitiveVlaDimensionStmt(index)))
107+
}
101108

102109
class InstructionTag extends TInstructionTag {
103110
final string toString() { result = getInstructionTagId(this) }

cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -123,13 +123,16 @@ private predicate ignoreExprAndDescendants(Expr expr) {
123123
// or
124124
ignoreExprAndDescendants(getRealParent(expr)) // recursive case
125125
or
126-
// va_start doesn't evaluate its argument, so we don't need to translate it.
126+
// va_start does not evaluate its argument, so we do not need to translate it.
127127
exists(BuiltInVarArgsStart vaStartExpr |
128128
vaStartExpr.getLastNamedParameter().getFullyConverted() = expr
129129
)
130130
or
131+
// sizeof does not evaluate its argument, so we do not need to translate it.
132+
exists(SizeofExprOperator sizeofExpr | sizeofExpr.getExprOperand().getFullyConverted() = expr)
133+
or
131134
// The children of C11 _Generic expressions are just surface syntax.
132-
exists(C11GenericExpr generic | generic.getAChild() = expr)
135+
exists(C11GenericExpr generic | generic.getAChild().getFullyConverted() = expr)
133136
or
134137
// Do not translate implicit destructor calls for unnamed temporary variables that are
135138
// conditionally constructed (until we have a mechanism for calling these only when the

cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll

Lines changed: 150 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ Variable getEnclosingVariable(Expr e) {
187187
}
188188

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

4097+
private VlaDeclStmt getVlaDeclStmt(Expr expr, int pointerDerefCount) {
4098+
expr.(VariableAccess).getTarget() = result.getVariable() and
4099+
pointerDerefCount = 0
4100+
or
4101+
not expr.(PointerDereferenceExpr).getOperand() instanceof AddressOfExpr and
4102+
result = getVlaDeclStmt(expr.(PointerDereferenceExpr).getOperand(), pointerDerefCount - 1)
4103+
or
4104+
// Skip sequences of the form `*&...`
4105+
result =
4106+
getVlaDeclStmt(expr.(PointerDereferenceExpr).getOperand().(AddressOfExpr).getOperand(),
4107+
pointerDerefCount)
4108+
or
4109+
result = getVlaDeclStmt(expr.(ArrayExpr).getArrayBase(), pointerDerefCount - 1)
4110+
}
4111+
4112+
/**
4113+
* The IR translation of `SizeofExprOperator` when its result is non-constant, i.e.,
4114+
* when the operand expression refers to a variable length array.
4115+
*/
4116+
class TranslatedSizeofExpr extends TranslatedNonConstantExpr {
4117+
override SizeofExprOperator expr;
4118+
VlaDeclStmt vlaDeclStmt;
4119+
int vlaDimensions;
4120+
int pointerDerefCount;
4121+
4122+
TranslatedSizeofExpr() {
4123+
vlaDeclStmt = getVlaDeclStmt(expr.getExprOperand(), pointerDerefCount) and
4124+
vlaDimensions = vlaDeclStmt.getTransitiveNumberOfVlaDimensionStmts() and
4125+
pointerDerefCount < vlaDimensions
4126+
}
4127+
4128+
final override Instruction getFirstInstruction(EdgeKind kind) {
4129+
result = this.getInstruction(SizeofVlaBaseSizeTag()) and
4130+
kind instanceof GotoEdge
4131+
}
4132+
4133+
override Instruction getALastInstructionInternal() {
4134+
result = this.getInstruction(SizeofVlaDimensionTag(vlaDimensions - 1))
4135+
}
4136+
4137+
final override TranslatedElement getChildInternal(int id) { none() }
4138+
4139+
final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
4140+
opcode instanceof Opcode::Constant and
4141+
tag = SizeofVlaBaseSizeTag() and
4142+
resultType = this.getResultType()
4143+
or
4144+
exists(int n, Type dimType |
4145+
pointerDerefCount <= n and
4146+
n < vlaDimensions and
4147+
dimType = this.getDimensionExpr(n).getUnderlyingType() and
4148+
tag = SizeofVlaConversionTag(n)
4149+
|
4150+
(
4151+
expr.getUnderlyingType() = dimType and
4152+
opcode instanceof Opcode::CopyValue
4153+
or
4154+
not expr.getUnderlyingType() = dimType and
4155+
opcode instanceof Opcode::Convert
4156+
)
4157+
) and
4158+
resultType = this.getResultType()
4159+
or
4160+
opcode instanceof Opcode::Mul and
4161+
exists(int n | pointerDerefCount <= n and n < vlaDimensions | tag = SizeofVlaDimensionTag(n)) and
4162+
resultType = this.getResultType()
4163+
}
4164+
4165+
final override Instruction getInstructionSuccessorInternal(InstructionTag tag, EdgeKind kind) {
4166+
tag = SizeofVlaBaseSizeTag() and
4167+
result = this.getInstruction(SizeofVlaConversionTag(pointerDerefCount)) and
4168+
kind instanceof GotoEdge
4169+
or
4170+
exists(int n | pointerDerefCount <= n and n < vlaDimensions |
4171+
tag = SizeofVlaConversionTag(n) and
4172+
result = this.getInstruction(SizeofVlaDimensionTag(n))
4173+
) and
4174+
kind instanceof GotoEdge
4175+
or
4176+
exists(int n | pointerDerefCount <= n and n < vlaDimensions - 1 |
4177+
tag = SizeofVlaDimensionTag(n) and
4178+
result = this.getInstruction(SizeofVlaConversionTag(n + 1))
4179+
) and
4180+
kind instanceof GotoEdge
4181+
or
4182+
tag = SizeofVlaDimensionTag(vlaDimensions - 1) and
4183+
result = this.getParent().getChildSuccessor(this, kind)
4184+
}
4185+
4186+
override string getInstructionConstantValue(InstructionTag tag) {
4187+
tag = SizeofVlaBaseSizeTag() and
4188+
result = this.getBaseType(vlaDeclStmt).getSize().toString()
4189+
}
4190+
4191+
private Type getBaseType(VlaDeclStmt v) {
4192+
not exists(v.getParentVlaDecl()) and
4193+
(
4194+
result =
4195+
this.getBaseType(v.getVariable().getUnderlyingType(), v.getNumberOfVlaDimensionStmts())
4196+
or
4197+
result = this.getBaseType(v.getType().getUnderlyingType(), v.getNumberOfVlaDimensionStmts())
4198+
)
4199+
or
4200+
result = this.getBaseType(v.getParentVlaDecl())
4201+
}
4202+
4203+
private Type getBaseType(Type type, int n) {
4204+
n = 0 and
4205+
result = type
4206+
or
4207+
result = this.getBaseType(type.(DerivedType).getBaseType(), n - 1)
4208+
}
4209+
4210+
override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
4211+
exists(int n | pointerDerefCount <= n and n < vlaDimensions |
4212+
tag = SizeofVlaConversionTag(n) and
4213+
(
4214+
operandTag instanceof UnaryOperandTag and
4215+
result = getTranslatedExpr(this.getDimensionExpr(n)).getResult()
4216+
)
4217+
)
4218+
or
4219+
exists(int n | pointerDerefCount <= n and n < vlaDimensions |
4220+
tag = SizeofVlaDimensionTag(n) and
4221+
(
4222+
operandTag instanceof LeftOperandTag and
4223+
(
4224+
n - 1 >= pointerDerefCount and
4225+
result = this.getInstruction(SizeofVlaDimensionTag(n - 1))
4226+
or
4227+
n - 1 < pointerDerefCount and
4228+
result = this.getInstruction(SizeofVlaBaseSizeTag())
4229+
)
4230+
or
4231+
operandTag instanceof RightOperandTag and
4232+
result = this.getInstruction(SizeofVlaConversionTag(n))
4233+
)
4234+
)
4235+
}
4236+
4237+
private Expr getDimensionExpr(int n) {
4238+
result = vlaDeclStmt.getTransitiveVlaDimensionStmt(n).getDimensionExpr().getFullyConverted()
4239+
}
4240+
4241+
final override Instruction getResult() {
4242+
result = this.getInstruction(SizeofVlaDimensionTag(vlaDimensions - 1))
4243+
}
4244+
}
4245+
40974246
class TranslatedErrorExpr extends TranslatedSingleInstructionExpr {
40984247
override ErrorExpr expr;
40994248

cpp/ql/lib/semmle/code/cpp/stmts/Stmt.qll

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2355,6 +2355,20 @@ class VlaDeclStmt extends Stmt, @stmt_vla_decl {
23552355
)
23562356
}
23572357

2358+
/**
2359+
* Gets the number of VLA dimension statements in this VLA declaration
2360+
* statement and transitively of the VLA declaration used to define its
2361+
* base type. if any.
2362+
*/
2363+
int getTransitiveNumberOfVlaDimensionStmts() {
2364+
not exists(this.getParentVlaDecl()) and
2365+
result = this.getNumberOfVlaDimensionStmts()
2366+
or
2367+
result =
2368+
this.getNumberOfVlaDimensionStmts() +
2369+
this.getParentVlaDecl().getTransitiveNumberOfVlaDimensionStmts()
2370+
}
2371+
23582372
/**
23592373
* Gets the `i`th VLA dimension statement in this VLA
23602374
* declaration statement.
@@ -2367,6 +2381,19 @@ class VlaDeclStmt extends Stmt, @stmt_vla_decl {
23672381
)
23682382
}
23692383

2384+
/**
2385+
* Gets the `i`th VLA dimension statement in this VLA declaration
2386+
* statement or transitively of the VLA declaration used to define
2387+
* its base type.
2388+
*/
2389+
VlaDimensionStmt getTransitiveVlaDimensionStmt(int i) {
2390+
i < this.getNumberOfVlaDimensionStmts() and
2391+
result = this.getVlaDimensionStmt(i)
2392+
or
2393+
result =
2394+
this.getParentVlaDecl().getTransitiveVlaDimensionStmt(i - this.getNumberOfVlaDimensionStmts())
2395+
}
2396+
23702397
/**
23712398
* Gets the type that this VLA declaration statement relates to,
23722399
* if any.
@@ -2378,4 +2405,31 @@ class VlaDeclStmt extends Stmt, @stmt_vla_decl {
23782405
* if any.
23792406
*/
23802407
Variable getVariable() { variable_vla(unresolveElement(result), underlyingElement(this)) }
2408+
2409+
/**
2410+
* Get the VLA declaration used to define the base type of
2411+
* this VLA declaration, if any.
2412+
*/
2413+
VlaDeclStmt getParentVlaDecl() {
2414+
exists(Variable v, Type baseType |
2415+
v = this.getVariable() and
2416+
baseType = this.getBaseType(v.getType(), this.getNumberOfVlaDimensionStmts())
2417+
|
2418+
result.getType() = baseType
2419+
)
2420+
or
2421+
exists(Type t, Type baseType |
2422+
t = this.getType().(TypedefType).getBaseType() and
2423+
baseType = this.getBaseType(t, this.getNumberOfVlaDimensionStmts())
2424+
|
2425+
result.getType() = baseType
2426+
)
2427+
}
2428+
2429+
private Type getBaseType(Type type, int n) {
2430+
n = 0 and
2431+
result = type
2432+
or
2433+
result = this.getBaseType(type.(DerivedType).getBaseType(), n - 1)
2434+
}
23812435
}

0 commit comments

Comments
 (0)