Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ae99858

Browse files
committed
C++: Refactor parameter out nodes to not depend on 'ReturnIndirectionInstruction's.
1 parent 39d44ad commit ae99858

5 files changed

Lines changed: 243 additions & 75 deletions

File tree

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowPrivate.qll

Lines changed: 17 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -298,14 +298,13 @@ newtype TPosition =
298298
private newtype TReturnKind =
299299
TNormalReturnKind(int index) {
300300
exists(IndirectReturnNode return |
301-
return.getAddressOperand() = any(ReturnValueInstruction r).getReturnAddressOperand() and
301+
return.isNormalReturn() and
302302
index = return.getIndirectionIndex() - 1 // We subtract one because the return loads the value.
303303
)
304304
} or
305305
TIndirectReturnKind(int argumentIndex, int indirectionIndex) {
306-
exists(IndirectReturnNode return, ReturnIndirectionInstruction returnInd |
307-
returnInd.hasIndex(argumentIndex) and
308-
return.getAddressOperand() = returnInd.getSourceAddressOperand() and
306+
exists(IndirectReturnNode return |
307+
return.isParameterReturn(argumentIndex) and
309308
indirectionIndex = return.getIndirectionIndex()
310309
)
311310
}
@@ -342,42 +341,29 @@ class ReturnNode extends Node instanceof IndirectReturnNode {
342341
abstract ReturnKind getKind();
343342
}
344343

345-
/**
346-
* This predicate represents an annoying hack that we have to do. We use the
347-
* `ReturnIndirectionInstruction` to determine which variables need flow back
348-
* out of a function. However, the IR will unconditionally create those for a
349-
* variable passed to a function even though the variable was never updated by
350-
* the function. And if a function has too many `ReturnNode`s the dataflow
351-
* library lowers its precision for that function by disabling field flow.
352-
*
353-
* So we those eliminate `ReturnNode`s that would have otherwise been created
354-
* by this unconditional `ReturnIndirectionInstruction` by requiring that there
355-
* must exist an SSA definition of the IR variable in the function.
356-
*/
357-
private predicate hasNonInitializeParameterDef(IRVariable v) {
358-
exists(Ssa::Def def |
359-
not def.getValue().asInstruction() instanceof InitializeParameterInstruction and
360-
v = def.getSourceVariable().getBaseVariable().(Ssa::BaseIRVariable).getIRVariable()
361-
)
344+
pragma[nomagic]
345+
private predicate finalParameterNodeHasArgumentAndIndex(
346+
FinalParameterNode node, int argumentIndex, int indirectionIndex
347+
) {
348+
node.getArgumentIndex() = argumentIndex and
349+
node.getIndirectionIndex() = indirectionIndex
362350
}
363351

364352
class ReturnIndirectionNode extends IndirectReturnNode, ReturnNode {
365353
override ReturnKind getKind() {
366-
exists(Operand op, int i |
367-
hasOperandAndIndex(this, pragma[only_bind_into](op), pragma[only_bind_into](i))
354+
exists(Operand op, int indirectionIndex |
355+
hasOperandAndIndex(this, pragma[only_bind_into](op), pragma[only_bind_into](indirectionIndex))
368356
|
369-
exists(int argumentIndex, ReturnIndirectionInstruction returnInd |
370-
op = returnInd.getSourceAddressOperand() and
371-
returnInd.hasIndex(argumentIndex) and
372-
hasNonInitializeParameterDef(returnInd.getIRVariable()) and
373-
result = TIndirectReturnKind(argumentIndex, pragma[only_bind_into](i))
374-
)
375-
or
376357
exists(ReturnValueInstruction return |
377358
op = return.getReturnAddressOperand() and
378-
result = TNormalReturnKind(i - 1)
359+
result = TNormalReturnKind(indirectionIndex - 1)
379360
)
380361
)
362+
or
363+
exists(int argumentIndex, int indirectionIndex |
364+
finalParameterNodeHasArgumentAndIndex(this, argumentIndex, indirectionIndex) and
365+
result = TIndirectReturnKind(argumentIndex, indirectionIndex)
366+
)
381367
}
382368
}
383369

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll

Lines changed: 71 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,12 @@ private newtype TIRDataFlowNode =
4646
} or
4747
TRawIndirectInstruction(Instruction instr, int indirectionIndex) {
4848
Ssa::hasRawIndirectInstruction(instr, indirectionIndex)
49+
} or
50+
TFinalParameterNode(Parameter p, int indirectionIndex) {
51+
exists(Ssa::FinalParameterUse use |
52+
use.getParameter() = p and
53+
use.getIndirectionIndex() = indirectionIndex
54+
)
4955
}
5056

5157
/**
@@ -522,16 +528,35 @@ class IndirectParameterNode extends Node, IndirectInstruction {
522528
* A node representing the indirection of a value that is
523529
* about to be returned from a function.
524530
*/
525-
class IndirectReturnNode extends IndirectOperand {
531+
class IndirectReturnNode extends Node {
526532
IndirectReturnNode() {
527-
this.getOperand() = any(ReturnIndirectionInstruction ret).getSourceAddressOperand()
533+
this instanceof FinalParameterNode
528534
or
529-
this.getOperand() = any(ReturnValueInstruction ret).getReturnAddressOperand()
535+
this.(IndirectOperand).getOperand() = any(ReturnValueInstruction ret).getReturnAddressOperand()
530536
}
531537

532-
Operand getAddressOperand() { result = operand }
533-
534538
override Declaration getEnclosingCallable() { result = this.getFunction() }
539+
540+
/**
541+
* Holds if this node represents the value that is returned to the caller
542+
* through a `return` statement.
543+
*/
544+
predicate isNormalReturn() { this instanceof IndirectOperand }
545+
546+
/**
547+
* Holds if this node represents the value that is returned to the caller
548+
* by writing to the `argumentIndex`'th argument of the call.
549+
*/
550+
predicate isParameterReturn(int argumentIndex) {
551+
this.(FinalParameterNode).getArgumentIndex() = argumentIndex
552+
}
553+
554+
/** Gets the indirection index of this indirect return node. */
555+
int getIndirectionIndex() {
556+
result = this.(FinalParameterNode).getIndirectionIndex()
557+
or
558+
result = this.(IndirectOperand).getIndirectionIndex()
559+
}
535560
}
536561

537562
/**
@@ -722,6 +747,47 @@ class RawIndirectOperand extends Node, TRawIndirectOperand {
722747
}
723748
}
724749

750+
/**
751+
* INTERNAL: do not use.
752+
*
753+
* A node representing the value of an update parameter
754+
* just before reaching the end of a function.
755+
*/
756+
class FinalParameterNode extends Node, TFinalParameterNode {
757+
Parameter p;
758+
int indirectionIndex;
759+
760+
FinalParameterNode() { this = TFinalParameterNode(p, indirectionIndex) }
761+
762+
/** Gets the parameter associated with this final use. */
763+
Parameter getParameter() { result = p }
764+
765+
/** Gets the underlying indirection index. */
766+
int getIndirectionIndex() { result = indirectionIndex }
767+
768+
/** Gets the argument index associated with this final use. */
769+
final int getArgumentIndex() { result = p.getIndex() }
770+
771+
override Function getFunction() { result = p.getFunction() }
772+
773+
override Declaration getEnclosingCallable() { result = this.getFunction() }
774+
775+
override DataFlowType getType() { result = getTypeImpl(p.getUnspecifiedType(), indirectionIndex) }
776+
777+
final override Location getLocationImpl() {
778+
// Parameters can have multiple locations. When there's a unique location we use
779+
// that one, but if multiple locations exist we default to an unknown location.
780+
result = unique( | | p.getLocation())
781+
or
782+
not exists(unique( | | p.getLocation())) and
783+
result instanceof UnknownDefaultLocation
784+
}
785+
786+
override string toStringImpl() {
787+
if indirectionIndex > 1 then result = p.toString() + " indirection" else result = p.toString()
788+
}
789+
}
790+
725791
/**
726792
* The value of an uninitialized local variable, viewed as a node in a data
727793
* flow graph.

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaInternals.qll

Lines changed: 103 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -130,14 +130,39 @@ private newtype TDefOrUseImpl =
130130
Operand iteratorAddress, BaseSourceVariableInstruction container, int indirectionIndex
131131
) {
132132
isIteratorUse(container, iteratorAddress, _, indirectionIndex)
133+
} or
134+
TFinalParameterUse(Parameter p, int indirectionIndex) {
135+
// Avoid creating parameter nodes if there is no definitions of the variable other than the initializaion.
136+
exists(SsaInternals0::Def def |
137+
def.getSourceVariable().getBaseVariable().(BaseIRVariable).getIRVariable().getAst() = p and
138+
not def.getValue().asInstruction() instanceof InitializeParameterInstruction
139+
) and
140+
// If the type is modifiable
141+
exists(CppType cppType |
142+
cppType.hasUnspecifiedType(p.getUnspecifiedType(), _) and
143+
isModifiableAt(cppType, indirectionIndex + 1)
144+
) and
145+
(
146+
exists(Indirection indirection |
147+
indirection.getType() = p.getUnspecifiedType() and
148+
indirectionIndex = [1 .. indirection.getNumberOfIndirections()]
149+
)
150+
or
151+
// Array types don't have indirections. So we need to special case them here.
152+
exists(Cpp::ArrayType arrayType, CppType cppType |
153+
arrayType = p.getUnspecifiedType() and
154+
cppType.hasUnspecifiedType(arrayType, _) and
155+
indirectionIndex = [1 .. countIndirectionsForCppType(cppType)]
156+
)
157+
)
133158
}
134159

135160
abstract private class DefOrUseImpl extends TDefOrUseImpl {
136161
/** Gets a textual representation of this element. */
137162
abstract string toString();
138163

139164
/** Gets the block of this definition or use. */
140-
abstract IRBlock getBlock();
165+
final IRBlock getBlock() { this.hasIndexInBlock(result, _) }
141166

142167
/** Holds if this definition or use has index `index` in block `block`. */
143168
abstract predicate hasIndexInBlock(IRBlock block, int index);
@@ -222,8 +247,6 @@ abstract class DefImpl extends DefOrUseImpl {
222247

223248
override string toString() { result = "DefImpl" }
224249

225-
override IRBlock getBlock() { result = this.getAddressOperand().getUse().getBlock() }
226-
227250
override Cpp::Location getLocation() { result = this.getAddressOperand().getUse().getLocation() }
228251

229252
final override predicate hasIndexInBlock(IRBlock block, int index) {
@@ -258,42 +281,55 @@ private class IteratorDef extends DefImpl, TIteratorDef {
258281
}
259282

260283
abstract class UseImpl extends DefOrUseImpl {
261-
Operand operand;
262284
int ind;
263285

264286
bindingset[ind]
265287
UseImpl() { any() }
266288

267-
Operand getOperand() { result = operand }
289+
/** Gets the node associated with this use. */
290+
abstract Node getNode();
268291

269292
override string toString() { result = "UseImpl" }
270293

271-
final override predicate hasIndexInBlock(IRBlock block, int index) {
272-
operand.getUse() = block.getInstruction(index)
273-
}
294+
/** Gets the indirection index of this use. */
295+
final override int getIndirectionIndex() { result = ind }
274296

275-
final override IRBlock getBlock() { result = operand.getUse().getBlock() }
297+
/** Gets the number of loads that precedence this use. */
298+
abstract int getIndirection();
276299

277-
final override Cpp::Location getLocation() { result = operand.getLocation() }
300+
/**
301+
* Holds if this use is guaranteed to read the
302+
* associated variable.
303+
*/
304+
abstract predicate isCertain();
305+
}
278306

279-
override int getIndirectionIndex() { result = ind }
307+
abstract private class OperandBasedUse extends UseImpl {
308+
Operand operand;
280309

281-
abstract int getIndirection();
310+
bindingset[ind]
311+
OperandBasedUse() { any() }
282312

283-
abstract predicate isCertain();
313+
final override predicate hasIndexInBlock(IRBlock block, int index) {
314+
operand.getUse() = block.getInstruction(index)
315+
}
316+
317+
final override Cpp::Location getLocation() { result = operand.getLocation() }
284318
}
285319

286-
private class DirectUse extends UseImpl, TUseImpl {
320+
private class DirectUse extends OperandBasedUse, TUseImpl {
287321
DirectUse() { this = TUseImpl(operand, ind) }
288322

289323
override int getIndirection() { isUse(_, operand, _, result, ind) }
290324

291325
override BaseSourceVariableInstruction getBase() { isUse(_, operand, result, _, ind) }
292326

293327
override predicate isCertain() { isUse(true, operand, _, _, ind) }
328+
329+
override Node getNode() { nodeHasOperand(result, operand, ind) }
294330
}
295331

296-
private class IteratorUse extends UseImpl, TIteratorUse {
332+
private class IteratorUse extends OperandBasedUse, TIteratorUse {
297333
BaseSourceVariableInstruction container;
298334

299335
IteratorUse() { this = TIteratorUse(operand, container, ind) }
@@ -303,6 +339,49 @@ private class IteratorUse extends UseImpl, TIteratorUse {
303339
override BaseSourceVariableInstruction getBase() { result = container }
304340

305341
override predicate isCertain() { none() }
342+
343+
override Node getNode() { nodeHasOperand(result, operand, ind) }
344+
}
345+
346+
class FinalParameterUse extends UseImpl, TFinalParameterUse {
347+
Parameter p;
348+
349+
FinalParameterUse() { this = TFinalParameterUse(p, ind) }
350+
351+
Parameter getParameter() { result = p }
352+
353+
override Node getNode() {
354+
result.(FinalParameterNode).getParameter() = p and
355+
result.(FinalParameterNode).getIndirectionIndex() = ind
356+
}
357+
358+
override int getIndirection() { result = ind + 1 }
359+
360+
override predicate isCertain() { any() }
361+
362+
override predicate hasIndexInBlock(IRBlock block, int index) {
363+
exists(ReturnInstruction return |
364+
block.getInstruction(index) = return and
365+
return.getEnclosingFunction() = p.getFunction()
366+
)
367+
}
368+
369+
override Cpp::Location getLocation() {
370+
// Parameters can have multiple locations. When there's a unique location we use
371+
// that one, but if multiple locations exist we default to an unknown location.
372+
result = unique( | | p.getLocation())
373+
or
374+
not exists(unique( | | p.getLocation())) and
375+
result instanceof UnknownDefaultLocation
376+
}
377+
378+
override BaseSourceVariableInstruction getBase() {
379+
exists(InitializeParameterInstruction init |
380+
init.getParameter() = p and
381+
// This is always a `VariableAddressInstruction`
382+
result = init.getAnOperand().getDef()
383+
)
384+
}
306385
}
307386

308387
/**
@@ -331,14 +410,7 @@ predicate adjacentDefRead(DefOrUse defOrUse1, UseOrPhi use) {
331410
)
332411
}
333412

334-
private predicate useToNode(UseOrPhi use, Node nodeTo) {
335-
exists(UseImpl useImpl |
336-
useImpl = use.asDefOrUse() and
337-
nodeHasOperand(nodeTo, useImpl.getOperand(), useImpl.getIndirectionIndex())
338-
)
339-
or
340-
nodeTo.(SsaPhiNode).getPhiNode() = use.asPhi()
341-
}
413+
private predicate useToNode(UseOrPhi use, Node nodeTo) { nodeTo = use.getNode() }
342414

343415
pragma[noinline]
344416
predicate outNodeHasAddressAndIndex(
@@ -609,6 +681,8 @@ class Phi extends TPhi, SsaDefOrUse {
609681
final override Location getLocation() { result = phi.getBasicBlock().getLocation() }
610682

611683
override string toString() { result = "Phi" }
684+
685+
SsaPhiNode getNode() { result.getPhiNode() = phi }
612686
}
613687

614688
class UseOrPhi extends SsaDefOrUse {
@@ -621,6 +695,12 @@ class UseOrPhi extends SsaDefOrUse {
621695
final override Location getLocation() {
622696
result = this.asDefOrUse().getLocation() or result = this.(Phi).getLocation()
623697
}
698+
699+
final Node getNode() {
700+
result = this.(Phi).getNode()
701+
or
702+
result = this.asDefOrUse().(UseImpl).getNode()
703+
}
624704
}
625705

626706
class Def extends DefOrUse {

0 commit comments

Comments
 (0)