Skip to content

Commit 67cb852

Browse files
authored
Merge pull request github#3082 from dbartol/dbartol/VarArgIR
C++: Model varargs in IR, Part I
2 parents deb20fc + 74f61dc commit 67cb852

File tree

15 files changed

+370
-70
lines changed

15 files changed

+370
-70
lines changed

cpp/ql/src/semmle/code/cpp/exprs/Call.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,7 @@ class FunctionCall extends Call, @funbindexpr {
196196
* constructor calls, this predicate instead gets the `Class` of the constructor
197197
* being called.
198198
*/
199-
private Type getTargetType() { result = Call.super.getType().stripType() }
199+
Type getTargetType() { result = Call.super.getType().stripType() }
200200

201201
/**
202202
* Gets the expected return type of the function called by this call.

cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,16 @@ class IRThrowVariable extends IRTempVariable {
213213
final override string getBaseString() { result = "#throw" }
214214
}
215215

216+
/**
217+
* A temporary variable generated to hold the contents of all arguments passed to the `...` of a
218+
* function that accepts a variable number of arguments.
219+
*/
220+
class IREllipsisVariable extends IRTempVariable {
221+
IREllipsisVariable() { tag = EllipsisTempVar() }
222+
223+
final override string toString() { result = "#ellipsis" }
224+
}
225+
216226
/**
217227
* A variable generated to represent the contents of a string literal. This variable acts much like
218228
* a read-only global variable.

cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,16 @@ class IRThrowVariable extends IRTempVariable {
213213
final override string getBaseString() { result = "#throw" }
214214
}
215215

216+
/**
217+
* A temporary variable generated to hold the contents of all arguments passed to the `...` of a
218+
* function that accepts a variable number of arguments.
219+
*/
220+
class IREllipsisVariable extends IRTempVariable {
221+
IREllipsisVariable() { tag = EllipsisTempVar() }
222+
223+
final override string toString() { result = "#ellipsis" }
224+
}
225+
216226
/**
217227
* A variable generated to represent the contents of a string literal. This variable acts much like
218228
* a read-only global variable.

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,7 @@ newtype TTranslatedElement =
402402
translateFunction(func)
403403
)
404404
} or
405+
TTranslatedEllipsisParameter(Function func) { translateFunction(func) and func.isVarargs() } or
405406
TTranslatedReadEffects(Function func) { translateFunction(func) } or
406407
// The read side effects in a function's return block
407408
TTranslatedReadEffect(Parameter param) {

cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedFunction.qll

Lines changed: 120 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,39 @@ private import TranslatedElement
1010
private import TranslatedExpr
1111
private import TranslatedInitialization
1212
private import TranslatedStmt
13+
private import VarArgs
1314

1415
/**
1516
* Gets the `TranslatedFunction` that represents function `func`.
1617
*/
1718
TranslatedFunction getTranslatedFunction(Function func) { result.getAST() = func }
1819

20+
/**
21+
* Gets the size, in bytes, of the variable used to represent the `...` parameter in a varargs
22+
* function. This is determined by finding the total size of all of the arguments passed to the
23+
* `...` in each call in the program, and choosing the maximum of those, with a minimum of 8 bytes.
24+
*/
25+
private int getEllipsisVariableByteSize() {
26+
result =
27+
max(int variableSize |
28+
variableSize =
29+
max(Call call, int callSize |
30+
callSize =
31+
sum(int argIndex |
32+
isEllipsisArgumentIndex(call, argIndex)
33+
|
34+
call.getArgument(argIndex).getType().getSize()
35+
)
36+
|
37+
callSize
38+
)
39+
or
40+
variableSize = 8
41+
|
42+
variableSize
43+
)
44+
}
45+
1946
/**
2047
* Represents the IR translation of a function. This is the root elements for
2148
* all other elements associated with this function.
@@ -60,6 +87,9 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction {
6087

6188
final private TranslatedParameter getParameter(int index) {
6289
result = getTranslatedParameter(func.getParameter(index))
90+
or
91+
index = getEllipsisParameterIndexForFunction(func) and
92+
result = getTranslatedEllipsisParameter(func)
6393
}
6494

6595
final override Instruction getFirstInstruction() { result = getInstruction(EnterFunctionTag()) }
@@ -113,7 +143,9 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction {
113143
final override Instruction getChildSuccessor(TranslatedElement child) {
114144
exists(int paramIndex |
115145
child = getParameter(paramIndex) and
116-
if exists(func.getParameter(paramIndex + 1))
146+
if
147+
exists(func.getParameter(paramIndex + 1)) or
148+
getEllipsisParameterIndexForFunction(func) = paramIndex + 1
117149
then result = getParameter(paramIndex + 1).getFirstInstruction()
118150
else result = getConstructorInitList().getFirstInstruction()
119151
)
@@ -237,10 +269,18 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction {
237269
result = getReturnVariable()
238270
}
239271

272+
final override predicate needsUnknownOpaqueType(int byteSize) {
273+
byteSize = getEllipsisVariableByteSize()
274+
}
275+
240276
final override predicate hasTempVariable(TempVariableTag tag, CppType type) {
241277
tag = ReturnValueTempVar() and
242278
hasReturnValue() and
243279
type = getTypeForPRValue(getReturnType())
280+
or
281+
tag = EllipsisTempVar() and
282+
func.isVarargs() and
283+
type = getUnknownOpaqueType(getEllipsisVariableByteSize())
244284
}
245285

246286
/**
@@ -316,34 +356,29 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction {
316356
}
317357

318358
/**
319-
* Gets the `TranslatedParameter` that represents parameter `param`.
359+
* Gets the `TranslatedPositionalParameter` that represents parameter `param`.
320360
*/
321-
TranslatedParameter getTranslatedParameter(Parameter param) { result.getAST() = param }
361+
TranslatedPositionalParameter getTranslatedParameter(Parameter param) { result.getAST() = param }
322362

323363
/**
324-
* Represents the IR translation of a function parameter, including the
325-
* initialization of that parameter with the incoming argument.
364+
* Gets the `TranslatedEllipsisParameter` for function `func`, if one exists.
326365
*/
327-
class TranslatedParameter extends TranslatedElement, TTranslatedParameter {
328-
Parameter param;
329-
330-
TranslatedParameter() { this = TTranslatedParameter(param) }
331-
332-
final override string toString() { result = param.toString() }
333-
334-
final override Locatable getAST() { result = param }
366+
TranslatedEllipsisParameter getTranslatedEllipsisParameter(Function func) {
367+
result.getFunction() = func
368+
}
335369

336-
final override Function getFunction() {
337-
result = param.getFunction() or
338-
result = param.getCatchBlock().getEnclosingFunction()
339-
}
370+
/**
371+
* The IR translation of a parameter to a function. This can be either a user-declared parameter
372+
* (`TranslatedPositionParameter`) or the synthesized parameter used to represent a `...` in a
373+
* varargs function (`TranslatedEllipsisParameter`).
374+
*/
375+
abstract class TranslatedParameter extends TranslatedElement {
376+
final override TranslatedElement getChild(int id) { none() }
340377

341378
final override Instruction getFirstInstruction() {
342379
result = getInstruction(InitializerVariableAddressTag())
343380
}
344381

345-
final override TranslatedElement getChild(int id) { none() }
346-
347382
final override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
348383
kind instanceof GotoEdge and
349384
(
@@ -368,16 +403,16 @@ class TranslatedParameter extends TranslatedElement, TTranslatedParameter {
368403
final override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
369404
tag = InitializerVariableAddressTag() and
370405
opcode instanceof Opcode::VariableAddress and
371-
resultType = getTypeForGLValue(getVariableType(param))
406+
resultType = getGLValueType()
372407
or
373408
tag = InitializerStoreTag() and
374409
opcode instanceof Opcode::InitializeParameter and
375-
resultType = getTypeForPRValue(getVariableType(param))
410+
resultType = getPRValueType()
376411
or
377412
hasIndirection() and
378413
tag = InitializerIndirectAddressTag() and
379414
opcode instanceof Opcode::Load and
380-
resultType = getTypeForPRValue(getVariableType(param))
415+
resultType = getPRValueType()
381416
or
382417
hasIndirection() and
383418
tag = InitializerIndirectStoreTag() and
@@ -391,7 +426,7 @@ class TranslatedParameter extends TranslatedElement, TTranslatedParameter {
391426
tag = InitializerVariableAddressTag() or
392427
tag = InitializerIndirectStoreTag()
393428
) and
394-
result = getIRUserVariable(getFunction(), param)
429+
result = getIRVariable()
395430
}
396431

397432
final override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
@@ -416,13 +451,74 @@ class TranslatedParameter extends TranslatedElement, TTranslatedParameter {
416451
result = getInstruction(InitializerIndirectAddressTag())
417452
}
418453

419-
predicate hasIndirection() {
454+
abstract predicate hasIndirection();
455+
456+
abstract CppType getGLValueType();
457+
458+
abstract CppType getPRValueType();
459+
460+
abstract IRAutomaticVariable getIRVariable();
461+
}
462+
463+
/**
464+
* Represents the IR translation of a function parameter, including the
465+
* initialization of that parameter with the incoming argument.
466+
*/
467+
class TranslatedPositionalParameter extends TranslatedParameter, TTranslatedParameter {
468+
Parameter param;
469+
470+
TranslatedPositionalParameter() { this = TTranslatedParameter(param) }
471+
472+
final override string toString() { result = param.toString() }
473+
474+
final override Locatable getAST() { result = param }
475+
476+
final override Function getFunction() {
477+
result = param.getFunction() or
478+
result = param.getCatchBlock().getEnclosingFunction()
479+
}
480+
481+
final override predicate hasIndirection() {
420482
exists(Type t | t = param.getUnspecifiedType() |
421483
t instanceof ArrayType or
422484
t instanceof PointerType or
423485
t instanceof ReferenceType
424486
)
425487
}
488+
489+
final override CppType getGLValueType() { result = getTypeForGLValue(getVariableType(param)) }
490+
491+
final override CppType getPRValueType() { result = getTypeForPRValue(getVariableType(param)) }
492+
493+
final override IRAutomaticUserVariable getIRVariable() {
494+
result = getIRUserVariable(getFunction(), param)
495+
}
496+
}
497+
498+
/**
499+
* The IR translation of the synthesized parameter used to represent the `...` in a varargs
500+
* function.
501+
*/
502+
class TranslatedEllipsisParameter extends TranslatedParameter, TTranslatedEllipsisParameter {
503+
Function func;
504+
505+
TranslatedEllipsisParameter() { this = TTranslatedEllipsisParameter(func) }
506+
507+
final override string toString() { result = "..." }
508+
509+
final override Locatable getAST() { result = func }
510+
511+
final override Function getFunction() { result = func }
512+
513+
final override predicate hasIndirection() { any() }
514+
515+
final override CppType getGLValueType() { result = getTypeForGLValue(any(UnknownType t)) }
516+
517+
final override CppType getPRValueType() {
518+
result = getUnknownOpaqueType(getEllipsisVariableByteSize())
519+
}
520+
521+
final override IREllipsisVariable getIRVariable() { result.getEnclosingFunction() = func }
426522
}
427523

428524
private TranslatedConstructorInitList getTranslatedConstructorInitList(Function func) {
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/**
2+
* Utilities for determining which parameters and arguments correspond to the `...` parameter for
3+
* varargs functions.
4+
*/
5+
6+
private import cpp
7+
8+
/**
9+
* Gets the index of the `...` parameter, if any. If present, the value will always be equal to
10+
* `func.getNumberOfParameters()`.
11+
*/
12+
int getEllipsisParameterIndexForFunction(Function func) {
13+
func.isVarargs() and result = func.getNumberOfParameters()
14+
}
15+
16+
/**
17+
* Gets the index of the `...` parameter, if any.
18+
*/
19+
int getEllipsisParameterIndexForRoutineType(RoutineType type) {
20+
// Since the extractor doesn't record this information directly, we look for routine types whose
21+
// last parameter type is `UnknownType`.
22+
type.getParameterType(result) instanceof UnknownType and
23+
result = strictcount(type.getAParameterType()) - 1
24+
}
25+
26+
/**
27+
* Gets the index of the `...` parameter, if any. This will be one greater than the index of the
28+
* last declared positional parameter.
29+
*/
30+
int getEllipsisParameterIndex(Call call) {
31+
exists(FunctionCall funcCall |
32+
funcCall = call and
33+
if funcCall.getTargetType() instanceof RoutineType
34+
then result = getEllipsisParameterIndexForRoutineType(funcCall.getTargetType())
35+
else result = getEllipsisParameterIndexForFunction(funcCall.getTarget())
36+
)
37+
or
38+
exists(ExprCall exprCall |
39+
exprCall = call and
40+
result = getEllipsisParameterIndexForRoutineType(exprCall.getExpr().getType().stripType())
41+
)
42+
}
43+
44+
/**
45+
* Gets the index of the parameter that will be initialized with the value of the argument
46+
* specified by `argIndex`. For ordinary positional parameters, the argument and parameter indices
47+
* will be equal. For a call to a varargs function, all arguments passed to the `...` will be
48+
* mapped to the index returned by `getEllipsisParameterIndex()`.
49+
*/
50+
int getParameterIndexForArgument(Call call, int argIndex) {
51+
exists(call.getArgument(argIndex)) and
52+
if argIndex >= getEllipsisParameterIndex(call)
53+
then result = getEllipsisParameterIndex(call)
54+
else result = argIndex
55+
}
56+
57+
/**
58+
* Holds if the argument specified by `index` is an argument to the `...` of a varargs function.
59+
*/
60+
predicate isEllipsisArgumentIndex(Call call, int index) {
61+
exists(call.getArgument(index)) and index >= getEllipsisParameterIndex(call)
62+
}

cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,16 @@ class IRThrowVariable extends IRTempVariable {
213213
final override string getBaseString() { result = "#throw" }
214214
}
215215

216+
/**
217+
* A temporary variable generated to hold the contents of all arguments passed to the `...` of a
218+
* function that accepts a variable number of arguments.
219+
*/
220+
class IREllipsisVariable extends IRTempVariable {
221+
IREllipsisVariable() { tag = EllipsisTempVar() }
222+
223+
final override string toString() { result = "#ellipsis" }
224+
}
225+
216226
/**
217227
* A variable generated to represent the contents of a string literal. This variable acts much like
218228
* a read-only global variable.

cpp/ql/src/semmle/code/cpp/ir/internal/TempVariableTag.qll

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ newtype TTempVariableTag =
22
ConditionValueTempVar() or
33
ReturnValueTempVar() or
44
ThrowTempVar() or
5-
LambdaTempVar()
5+
LambdaTempVar() or
6+
EllipsisTempVar()
67

78
string getTempVariableTagId(TTempVariableTag tag) {
89
tag = ConditionValueTempVar() and result = "CondVal"
@@ -12,4 +13,6 @@ string getTempVariableTagId(TTempVariableTag tag) {
1213
tag = ThrowTempVar() and result = "Throw"
1314
or
1415
tag = LambdaTempVar() and result = "Lambda"
16+
or
17+
tag = EllipsisTempVar() and result = "Ellipsis"
1518
}

0 commit comments

Comments
 (0)