Skip to content

Commit 16e817c

Browse files
authored
Merge pull request github#12356 from MathiasVP/use-phi-reads
C++: Include "phi reads" in `DataFlow::Node`
2 parents 7f9b856 + 959237e commit 16e817c

File tree

5 files changed

+84
-29
lines changed

5 files changed

+84
-29
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ class Node0Impl extends TIRDataFlowNode0 {
4343
/**
4444
* Gets the type of this node.
4545
*
46-
* If `asInstruction().isGLValue()` holds, then the type of this node
46+
* If `isGLValue()` holds, then the type of this node
4747
* should be thought of as "pointer to `getType()`".
4848
*/
4949
DataFlowType getType() { none() } // overridden in subclasses

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -498,7 +498,14 @@ class SsaPhiNode extends Node, TSsaPhiNode {
498498

499499
override Declaration getFunction() { result = phi.getBasicBlock().getEnclosingFunction() }
500500

501-
override DataFlowType getType() { result = this.getAnInput().getType().getUnspecifiedType() }
501+
override DataFlowType getType() {
502+
exists(Ssa::SourceVariable sv |
503+
this.getPhiNode().definesAt(sv, _, _, _) and
504+
result = sv.getType()
505+
)
506+
}
507+
508+
override predicate isGLValue() { phi.getSourceVariable().isGLValue() }
502509

503510
final override Location getLocationImpl() { result = phi.getBasicBlock().getLocation() }
504511

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

Lines changed: 53 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,16 @@ private module SourceVariables {
4848
* indirections) of this source variable.
4949
*/
5050
abstract BaseSourceVariable getBaseVariable();
51+
52+
/** Holds if this variable is a glvalue. */
53+
predicate isGLValue() { none() }
54+
55+
/**
56+
* Gets the type of this source variable. If `isGLValue()` holds, then
57+
* the type of this source variable should be thought of as "pointer
58+
* to `getType()`".
59+
*/
60+
abstract DataFlowType getType();
5161
}
5262

5363
class SourceIRVariable extends SourceVariable, TSourceIRVariable {
@@ -66,6 +76,12 @@ private module SourceVariables {
6676
ind > 0 and
6777
result = this.getIRVariable().toString() + " indirection"
6878
}
79+
80+
override predicate isGLValue() { ind = 0 }
81+
82+
override DataFlowType getType() {
83+
if ind = 0 then result = var.getType() else result = getTypeImpl(var.getType(), ind - 1)
84+
}
6985
}
7086

7187
class CallVariable extends SourceVariable, TCallVariable {
@@ -84,6 +100,8 @@ private module SourceVariables {
84100
ind > 0 and
85101
result = "Call indirection"
86102
}
103+
104+
override DataFlowType getType() { result = getTypeImpl(call.getResultType(), ind) }
87105
}
88106
}
89107

@@ -530,15 +548,15 @@ predicate adjacentDefRead(DefOrUse defOrUse1, UseOrPhi use) {
530548
exists(IRBlock bb1, int i1, SourceVariable v |
531549
defOrUse1.asDefOrUse().hasIndexInBlock(bb1, i1, v)
532550
|
533-
exists(IRBlock bb2, int i2, Definition def |
534-
adjacentDefRead(pragma[only_bind_into](def), pragma[only_bind_into](bb1),
551+
exists(IRBlock bb2, int i2, DefinitionExt def |
552+
adjacentDefReadExt(pragma[only_bind_into](def), pragma[only_bind_into](bb1),
535553
pragma[only_bind_into](i1), pragma[only_bind_into](bb2), pragma[only_bind_into](i2)) and
536554
def.getSourceVariable() = v and
537555
use.asDefOrUse().(UseImpl).hasIndexInBlock(bb2, i2, v)
538556
)
539557
or
540558
exists(PhiNode phi |
541-
lastRefRedef(_, bb1, i1, phi) and
559+
lastRefRedefExt(_, bb1, i1, phi) and
542560
use.asPhi() = phi and
543561
phi.getSourceVariable() = pragma[only_bind_into](v)
544562
)
@@ -550,11 +568,18 @@ predicate adjacentDefRead(DefOrUse defOrUse1, UseOrPhi use) {
550568
* flows to `useOrPhi`.
551569
*/
552570
private predicate globalDefToUse(GlobalDef globalDef, UseOrPhi useOrPhi) {
553-
exists(IRBlock bb1, int i1, IRBlock bb2, int i2, SourceVariable v |
554-
globalDef.hasIndexInBlock(bb1, i1, v) and
555-
adjacentDefRead(_, pragma[only_bind_into](bb1), pragma[only_bind_into](i1),
556-
pragma[only_bind_into](bb2), pragma[only_bind_into](i2)) and
557-
useOrPhi.asDefOrUse().hasIndexInBlock(bb2, i2, v)
571+
exists(IRBlock bb1, int i1, SourceVariable v | globalDef.hasIndexInBlock(bb1, i1, v) |
572+
exists(IRBlock bb2, int i2 |
573+
adjacentDefReadExt(_, pragma[only_bind_into](bb1), pragma[only_bind_into](i1),
574+
pragma[only_bind_into](bb2), pragma[only_bind_into](i2)) and
575+
useOrPhi.asDefOrUse().hasIndexInBlock(bb2, i2, v)
576+
)
577+
or
578+
exists(PhiNode phi |
579+
lastRefRedefExt(_, bb1, i1, phi) and
580+
useOrPhi.asPhi() = phi and
581+
phi.getSourceVariable() = pragma[only_bind_into](v)
582+
)
558583
)
559584
}
560585

@@ -666,17 +691,17 @@ private predicate ssaFlowImpl(SsaDefOrUse defOrUse, Node nodeFrom, Node nodeTo,
666691
* Holds if `def` is the corresponding definition of
667692
* the SSA library's `definition`.
668693
*/
669-
private Definition ssaDefinition(Def def) {
694+
private DefinitionExt ssaDefinition(Def def) {
670695
exists(IRBlock block, int i, SourceVariable sv |
671696
def.hasIndexInBlock(block, i, sv) and
672-
result.definesAt(sv, block, i)
697+
result.definesAt(sv, block, i, _)
673698
)
674699
}
675700

676701
/** Gets a node that represents the prior definition of `node`. */
677702
private Node getAPriorDefinition(SsaDefOrUse defOrUse) {
678-
exists(IRBlock bb, int i, SourceVariable sv, Definition def, DefOrUse defOrUse0 |
679-
SsaCached::lastRefRedef(pragma[only_bind_into](def), pragma[only_bind_into](bb),
703+
exists(IRBlock bb, int i, SourceVariable sv, DefinitionExt def, DefOrUse defOrUse0 |
704+
lastRefRedefExt(pragma[only_bind_into](def), pragma[only_bind_into](bb),
680705
pragma[only_bind_into](i), ssaDefinition(defOrUse)) and
681706
def.getSourceVariable() = sv and
682707
defOrUse0.hasIndexInBlock(bb, i, sv) and
@@ -702,7 +727,7 @@ pragma[nomagic]
702727
private predicate fromPhiNodeToUse(PhiNode phi, SourceVariable sv, IRBlock bb1, int i1, UseOrPhi use) {
703728
exists(IRBlock bb2, int i2 |
704729
use.asDefOrUse().hasIndexInBlock(bb2, i2, sv) and
705-
adjacentDefRead(pragma[only_bind_into](phi), pragma[only_bind_into](bb1),
730+
adjacentDefReadExt(pragma[only_bind_into](phi), pragma[only_bind_into](bb1),
706731
pragma[only_bind_into](i1), pragma[only_bind_into](bb2), pragma[only_bind_into](i2))
707732
)
708733
}
@@ -711,13 +736,13 @@ private predicate fromPhiNodeToUse(PhiNode phi, SourceVariable sv, IRBlock bb1,
711736
predicate fromPhiNode(SsaPhiNode nodeFrom, Node nodeTo) {
712737
exists(PhiNode phi, SourceVariable sv, IRBlock bb1, int i1, UseOrPhi use |
713738
phi = nodeFrom.getPhiNode() and
714-
phi.definesAt(sv, bb1, i1) and
739+
phi.definesAt(sv, bb1, i1, _) and
715740
useToNode(use, nodeTo)
716741
|
717742
fromPhiNodeToUse(phi, sv, bb1, i1, use)
718743
or
719744
exists(PhiNode phiTo |
720-
lastRefRedef(phi, _, _, phiTo) and
745+
lastRefRedefExt(phi, _, _, phiTo) and
721746
nodeTo.(SsaPhiNode).getPhiNode() = phiTo
722747
)
723748
)
@@ -796,8 +821,8 @@ module SsaCached {
796821
* path between them without any read of `def`.
797822
*/
798823
cached
799-
predicate adjacentDefRead(Definition def, IRBlock bb1, int i1, IRBlock bb2, int i2) {
800-
SsaImpl::adjacentDefRead(def, bb1, i1, bb2, i2)
824+
predicate adjacentDefReadExt(DefinitionExt def, IRBlock bb1, int i1, IRBlock bb2, int i2) {
825+
SsaImpl::adjacentDefReadExt(def, _, bb1, i1, bb2, i2)
801826
}
802827

803828
/**
@@ -806,8 +831,8 @@ module SsaCached {
806831
* without passing through another read or write.
807832
*/
808833
cached
809-
predicate lastRefRedef(Definition def, IRBlock bb, int i, Definition next) {
810-
SsaImpl::lastRefRedef(def, bb, i, next)
834+
predicate lastRefRedefExt(DefinitionExt def, IRBlock bb, int i, DefinitionExt next) {
835+
SsaImpl::lastRefRedefExt(def, _, bb, i, next)
811836
}
812837
}
813838

@@ -818,8 +843,8 @@ private newtype TSsaDefOrUse =
818843
or
819844
// Like in the pruning stage, we only include definition that's live after the
820845
// write as the final definitions computed by SSA.
821-
exists(Definition def, SourceVariable sv, IRBlock bb, int i |
822-
def.definesAt(sv, bb, i) and
846+
exists(DefinitionExt def, SourceVariable sv, IRBlock bb, int i |
847+
def.definesAt(sv, bb, i, _) and
823848
defOrUse.(DefImpl).hasIndexInBlock(bb, i, sv)
824849
)
825850
} or
@@ -967,9 +992,14 @@ class Def extends DefOrUse {
967992

968993
private module SsaImpl = SsaImplCommon::Make<SsaInput>;
969994

970-
class PhiNode = SsaImpl::PhiNode;
995+
class PhiNode extends SsaImpl::DefinitionExt {
996+
PhiNode() {
997+
this instanceof SsaImpl::PhiNode or
998+
this instanceof SsaImpl::PhiReadNode
999+
}
1000+
}
9711001

972-
class Definition = SsaImpl::Definition;
1002+
class DefinitionExt = SsaImpl::DefinitionExt;
9731003

9741004
class UncertainWriteDefinition = SsaImpl::UncertainWriteDefinition;
9751005

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

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -225,8 +225,8 @@ private newtype TSsaDefOrUse =
225225
or
226226
// If `defOrUse` is a definition we only include it if the
227227
// SSA library concludes that it's live after the write.
228-
exists(Definition def, SourceVariable sv, IRBlock bb, int i |
229-
def.definesAt(sv, bb, i) and
228+
exists(DefinitionExt def, SourceVariable sv, IRBlock bb, int i |
229+
def.definesAt(sv, bb, i, _) and
230230
defOrUse.(DefImpl).hasIndexInBlock(bb, i, sv)
231231
)
232232
} or
@@ -301,6 +301,11 @@ class Def extends DefOrUse {
301301

302302
private module SsaImpl = SsaImplCommon::Make<SsaInput>;
303303

304-
class PhiNode = SsaImpl::PhiNode;
304+
class PhiNode extends SsaImpl::DefinitionExt {
305+
PhiNode() {
306+
this instanceof SsaImpl::PhiNode or
307+
this instanceof SsaImpl::PhiReadNode
308+
}
309+
}
305310

306-
class Definition = SsaImpl::Definition;
311+
class DefinitionExt = SsaImpl::DefinitionExt;

cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -615,3 +615,16 @@ void test_flow_through_void_double_pointer(int *p) // $ ast-def=p
615615
void* q = (void*)&p;
616616
sink(**(int**)q); // $ ir MISSING: ast
617617
}
618+
619+
void use(int *);
620+
621+
void test_def_via_phi_read(bool b)
622+
{
623+
static int buffer[10]; // This is missing an initialisation in IR dataflow
624+
if (b)
625+
{
626+
use(buffer);
627+
}
628+
intPointerSource(buffer);
629+
sink(buffer); // $ ast,ir
630+
}

0 commit comments

Comments
 (0)