Dataflow: Replace MakeSets with QlBuiltins::InternSets.

This commit is contained in:
Anders Schack-Mulligen
2024-07-15 13:35:57 +02:00
parent a951718f2e
commit da5abc8321
15 changed files with 43 additions and 409 deletions

View File

@@ -239,17 +239,7 @@ class CastNode extends Node {
CastNode() { none() } // stub implementation
}
class DataFlowCallable extends Function {
/** Gets a best-effort total ordering. */
int totalorder() {
this =
rank[result](DataFlowCallable c, string file, int startline, int startcolumn |
c.getLocation().hasLocationInfo(file, startline, startcolumn, _, _)
|
c order by file, startline, startcolumn
)
}
}
class DataFlowCallable extends Function { }
class DataFlowExpr = Expr;
@@ -269,24 +259,12 @@ class DataFlowCall extends Expr instanceof Call {
/** Gets the enclosing callable of this call. */
DataFlowCallable getEnclosingCallable() { result = this.getEnclosingFunction() }
/** Gets a best-effort total ordering. */
int totalorder() {
this =
rank[result](DataFlowCall c, int startline, int startcolumn |
c.getLocation().hasLocationInfo(_, startline, startcolumn, _, _)
|
c order by startline, startcolumn
)
}
}
class NodeRegion instanceof Unit {
string toString() { result = "NodeRegion" }
predicate contains(Node n) { none() }
int totalOrder() { result = 1 }
}
predicate isUnreachableInCall(NodeRegion nr, DataFlowCall call) { none() } // stub implementation

View File

@@ -1060,16 +1060,6 @@ class DataFlowCallable extends TDataFlowCallable {
result = this.asSummarizedCallable() or // SummarizedCallable = Function (in CPP)
result = this.asSourceCallable()
}
/** Gets a best-effort total ordering. */
int totalorder() {
this =
rank[result](DataFlowCallable c, string file, int startline, int startcolumn |
c.getLocation().hasLocationInfo(file, startline, startcolumn, _, _)
|
c order by file, startline, startcolumn
)
}
}
/**
@@ -1167,16 +1157,6 @@ class DataFlowCall extends TDataFlowCall {
* Gets the location of this call.
*/
Location getLocation() { none() }
/** Gets a best-effort total ordering. */
int totalorder() {
this =
rank[result](DataFlowCall c, int startline, int startcolumn |
c.getLocation().hasLocationInfo(_, startline, startcolumn, _, _)
|
c order by startline, startcolumn
)
}
}
/**
@@ -1269,15 +1249,6 @@ module IsUnreachableInCall {
string toString() { result = "NodeRegion" }
predicate contains(Node n) { this = n.getBasicBlock() }
int totalOrder() {
this =
rank[result](IRBlock b, int startline, int startcolumn |
b.getLocation().hasLocationInfo(_, startline, startcolumn, _, _)
|
b order by startline, startcolumn
)
}
}
predicate isUnreachableInCall(NodeRegion block, DataFlowCall call) {

View File

@@ -191,16 +191,6 @@ class DataFlowCallable extends TDataFlowCallable {
or
result = this.asCapturedVariable().getLocation()
}
/** Gets a best-effort total ordering. */
int totalorder() {
this =
rank[result](DataFlowCallable c, string file, int startline, int startcolumn |
c.getLocation().hasLocationInfo(file, startline, startcolumn, _, _)
|
c order by file, startline, startcolumn
)
}
}
/** A call relevant for data flow. */
@@ -244,16 +234,6 @@ abstract class DataFlowCall extends TDataFlowCall {
) {
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets a best-effort total ordering. */
int totalorder() {
this =
rank[result](DataFlowCall c, int startline, int startcolumn |
c.hasLocationInfo(_, startline, startcolumn, _, _)
|
c order by startline, startcolumn
)
}
}
/** A non-delegate C# call relevant for data flow. */

View File

@@ -2379,15 +2379,6 @@ class NodeRegion instanceof ControlFlow::BasicBlock {
string toString() { result = "NodeRegion" }
predicate contains(Node n) { this = n.getControlFlowNode().getBasicBlock() }
int totalOrder() {
this =
rank[result](ControlFlow::BasicBlock b, int startline, int startcolumn |
b.getLocation().hasLocationInfo(_, startline, startcolumn, _, _)
|
b order by startline, startcolumn
)
}
}
/**

View File

@@ -318,16 +318,6 @@ class DataFlowCallable extends TDataFlowCallable {
result = this.asFileScope().getLocation() or
result = getCallableLocation(this.asSummarizedCallable())
}
/** Gets a best-effort total ordering. */
int totalorder() {
this =
rank[result](DataFlowCallable c, string file, int startline, int startcolumn |
c.hasLocationInfo(file, startline, startcolumn, _, _)
|
c order by file, startline, startcolumn
)
}
}
private Location getCallableLocation(Callable c) {
@@ -361,16 +351,6 @@ class DataFlowCall extends Expr {
/** Gets the location of this call. */
Location getLocation() { result = super.getLocation() }
/** Gets a best-effort total ordering. */
int totalorder() {
this =
rank[result](DataFlowCall c, int startline, int startcolumn |
c.getLocation().hasLocationInfo(_, startline, startcolumn, _, _)
|
c order by startline, startcolumn
)
}
}
/** Holds if `e` is an expression that always has the same Boolean value `val`. */
@@ -413,15 +393,6 @@ class NodeRegion instanceof BasicBlock {
string toString() { result = "NodeRegion" }
predicate contains(Node n) { n.getBasicBlock() = this }
int totalOrder() {
this =
rank[result](BasicBlock b, int startline, int startcolumn |
b.hasLocationInfo(_, startline, startcolumn, _, _)
|
b order by startline, startcolumn
)
}
}
/**

View File

@@ -400,21 +400,6 @@ class CastNode extends ExprNode {
}
}
private predicate id_member(Member x, Member y) { x = y }
private predicate idOf_member(Member x, int y) = equivalenceRelation(id_member/2)(x, y)
private int summarizedCallableId(SummarizedCallable c) {
c =
rank[result](SummarizedCallable c0, int b, int i, string s |
b = 0 and idOf_member(c0.asCallable(), i) and s = ""
or
b = 1 and i = 0 and s = c0.asSyntheticCallable()
|
c0 order by b, i, s
)
}
private newtype TDataFlowCallable =
TSrcCallable(Callable c) or
TSummarizedCallable(SummarizedCallable c) or
@@ -448,28 +433,10 @@ class DataFlowCallable extends TDataFlowCallable {
result = this.asSummarizedCallable().getLocation() or
result = this.asFieldScope().getLocation()
}
/** Gets a best-effort total ordering. */
int totalorder() {
this =
rank[result](DataFlowCallable c, int b, int i |
b = 0 and idOf_member(c.asCallable(), i)
or
b = 1 and i = summarizedCallableId(c.asSummarizedCallable())
or
b = 2 and idOf_member(c.asFieldScope(), i)
|
c order by b, i
)
}
}
class DataFlowExpr = Expr;
private predicate id_call(Call x, Call y) { x = y }
private predicate idOf_call(Call x, int y) = equivalenceRelation(id_call/2)(x, y)
private newtype TDataFlowCall =
TCall(Call c) or
TSummaryCall(SummarizedCallable c, FlowSummaryImpl::Private::SummaryNode receiver) {
@@ -502,19 +469,6 @@ class DataFlowCall extends TDataFlowCall {
) {
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets a best-effort total ordering. */
int totalorder() {
this =
rank[result](DataFlowCall c, int b, int i |
b = 0 and idOf_call(c.asCall(), i)
or
b = 1 and // not guaranteed to be total
exists(SummarizedCallable sc | c = TSummaryCall(sc, _) and i = summarizedCallableId(sc))
|
c order by b, i
)
}
}
/** A source call, that is, a `Call`. */
@@ -549,16 +503,10 @@ class SummaryCall extends DataFlowCall, TSummaryCall {
override Location getLocation() { result = c.getLocation() }
}
private predicate id(BasicBlock x, BasicBlock y) { x = y }
private predicate idOf(BasicBlock x, int y) = equivalenceRelation(id/2)(x, y)
class NodeRegion instanceof BasicBlock {
string toString() { result = "NodeRegion" }
predicate contains(Node n) { n.asExpr().getBasicBlock() = this }
int totalOrder() { idOf(this, result) }
}
/** Holds if `e` is an expression that always has the same Boolean value `val`. */

View File

@@ -344,16 +344,6 @@ abstract class DataFlowCallable extends TDataFlowCallable {
/** Gets the location of this dataflow callable. */
abstract Location getLocation();
/** Gets a best-effort total ordering. */
int totalorder() {
this =
rank[result](DataFlowCallable c, string file, int startline, int startcolumn |
c.getLocation().hasLocationInfo(file, startline, startcolumn, _, _)
|
c order by file, startline, startcolumn
)
}
}
/** A callable function. */
@@ -1435,16 +1425,6 @@ abstract class DataFlowCall extends TDataFlowCall {
) {
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets a best-effort total ordering. */
int totalorder() {
this =
rank[result](DataFlowCall c, int startline, int startcolumn |
c.hasLocationInfo(_, startline, startcolumn, _, _)
|
c order by startline, startcolumn
)
}
}
/** A call found in the program source (as opposed to a synthesised call). */

View File

@@ -1025,8 +1025,6 @@ class NodeRegion instanceof Unit {
string toString() { result = "NodeRegion" }
predicate contains(Node n) { none() }
int totalOrder() { result = 1 }
}
//--------

View File

@@ -113,16 +113,6 @@ class DataFlowCallable extends TDataFlowCallable {
this instanceof TLibraryCallable and
result instanceof EmptyLocation
}
/** Gets a best-effort total ordering. */
int totalorder() {
this =
rank[result](DataFlowCallable c, string file, int startline, int startcolumn |
c.getLocation().hasLocationInfo(file, startline, startcolumn, _, _)
|
c order by file, startline, startcolumn
)
}
}
/**
@@ -154,16 +144,6 @@ abstract class DataFlowCall extends TDataFlowCall {
) {
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets a best-effort total ordering. */
int totalorder() {
this =
rank[result](DataFlowCall c, int startline, int startcolumn |
c.hasLocationInfo(_, startline, startcolumn, _, _)
|
c order by startline, startcolumn
)
}
}
/**

View File

@@ -2183,8 +2183,6 @@ class NodeRegion instanceof Unit {
string toString() { result = "NodeRegion" }
predicate contains(Node n) { none() }
int totalOrder() { result = 1 }
}
/**

View File

@@ -76,9 +76,6 @@ signature module InputSig<LocationSig Location> {
Location getLocation();
DataFlowCallable getEnclosingCallable();
/** Gets a best-effort total ordering. */
int totalorder();
}
class DataFlowCallable {
@@ -87,9 +84,6 @@ signature module InputSig<LocationSig Location> {
/** Gets the location of this callable. */
Location getLocation();
/** Gets a best-effort total ordering. */
int totalorder();
}
class ReturnKind {
@@ -266,8 +260,6 @@ signature module InputSig<LocationSig Location> {
class NodeRegion {
/** Holds if this region contains `n`. */
predicate contains(Node n);
int totalOrder();
}
/**

View File

@@ -4,7 +4,6 @@ private import codeql.util.Location
private import codeql.util.Option
private import codeql.util.Unit
private import codeql.util.Option
private import codeql.util.internal.MakeSets
module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
private import Lang
@@ -502,24 +501,21 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
)
}
private module CallSetsInput implements MkSetsInputSig {
class Key = TCallEdge;
class Value = DataFlowCall;
DataFlowCall getAValue(TCallEdge ctxEdge) {
exists(DataFlowCall ctx, DataFlowCallable c |
ctxEdge = TMkCallEdge(ctx, c) and
reducedViableImplInCallContext(result, c, ctx)
)
}
int totalorder(DataFlowCall e) { result = callOrder(e) }
private DataFlowCall getACallWithReducedViableImpl(TCallEdge ctxEdge) {
exists(DataFlowCall ctx, DataFlowCallable c |
ctxEdge = TMkCallEdge(ctx, c) and
reducedViableImplInCallContext(result, c, ctx)
)
}
private module CallSets = MakeSets<CallSetsInput>;
private module CallSets =
QlBuiltins::InternSets<TCallEdge, DataFlowCall, getACallWithReducedViableImpl/1>;
private module CallSetOption = Option<CallSets::ValueSet>;
private class CallSet0 extends CallSets::Set {
string toString() { result = "CallSet" }
}
private module CallSetOption = Option<CallSet0>;
/**
* A set of call sites for which dispatch is affected by the call context.
@@ -528,26 +524,23 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
*/
private class CallSet = CallSetOption::Option;
private module DispatchSetsInput implements MkSetsInputSig {
class Key = TCallEdge;
class Value = TCallEdge;
TCallEdge getAValue(TCallEdge ctxEdge) {
exists(DataFlowCall ctx, DataFlowCallable c, DataFlowCall call, DataFlowCallable tgt |
ctxEdge = mkCallEdge(ctx, c) and
result = mkCallEdge(call, tgt) and
viableImplInCallContextExtIn(call, ctx) = tgt and
reducedViableImplInCallContext(call, c, ctx)
)
}
int totalorder(TCallEdge e) { result = edgeOrder(e) }
private TCallEdge getAReducedViableEdge(TCallEdge ctxEdge) {
exists(DataFlowCall ctx, DataFlowCallable c, DataFlowCall call, DataFlowCallable tgt |
ctxEdge = mkCallEdge(ctx, c) and
result = mkCallEdge(call, tgt) and
viableImplInCallContextExtIn(call, ctx) = tgt and
reducedViableImplInCallContext(call, c, ctx)
)
}
private module DispatchSets = MakeSets<DispatchSetsInput>;
private module DispatchSets =
QlBuiltins::InternSets<TCallEdge, TCallEdge, getAReducedViableEdge/1>;
private module DispatchSetsOption = Option<DispatchSets::ValueSet>;
private class DispatchSet0 extends DispatchSets::Set {
string toString() { result = "DispatchSet" }
}
private module DispatchSetsOption = Option<DispatchSet0>;
/**
* A set of call edges that are allowed in the call context. This applies to
@@ -561,7 +554,7 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
private class DispatchSet = DispatchSetsOption::Option;
private predicate relevantCtx(TCallEdge ctx) {
exists(CallSets::getValueSet(ctx)) or exists(getUnreachableSet(ctx))
exists(CallSets::getSet(ctx)) or exists(getUnreachableSet(ctx))
}
pragma[nomagic]
@@ -570,14 +563,14 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
) {
relevantCtx(ctx) and
(
CallSets::getValueSet(ctx) = calls.asSome()
CallSets::getSet(ctx) = calls.asSome()
or
not exists(CallSets::getValueSet(ctx)) and calls.isNone()
not exists(CallSets::getSet(ctx)) and calls.isNone()
) and
(
DispatchSets::getValueSet(ctx) = tgts.asSome()
DispatchSets::getSet(ctx) = tgts.asSome()
or
not exists(DispatchSets::getValueSet(ctx)) and tgts.isNone()
not exists(DispatchSets::getSet(ctx)) and tgts.isNone()
) and
(
getUnreachableSet(ctx) = unreachable.asSome()
@@ -1515,40 +1508,20 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
newtype TCallEdge =
TMkCallEdge(DataFlowCall call, DataFlowCallable tgt) { viableCallableExt(call) = tgt }
cached
int edgeOrder(TCallEdge edge) {
edge =
rank[result](TCallEdge e, DataFlowCall call, DataFlowCallable tgt |
e = TMkCallEdge(call, tgt)
|
e order by call.totalorder(), tgt.totalorder()
)
private NodeRegion getAnUnreachableRegion(TCallEdge edge) {
exists(DataFlowCall call, DataFlowCallable tgt |
edge = mkCallEdge(call, tgt) and
getNodeRegionEnclosingCallable(result) = tgt and
isUnreachableInCallCached(result, call)
)
}
cached
int callOrder(DataFlowCall call) { result = call.totalorder() }
private module UnreachableSetsInput implements MkSetsInputSig {
class Key = TCallEdge;
class Value = NodeRegion;
NodeRegion getAValue(TCallEdge edge) {
exists(DataFlowCall call, DataFlowCallable tgt |
edge = mkCallEdge(call, tgt) and
getNodeRegionEnclosingCallable(result) = tgt and
isUnreachableInCallCached(result, call)
)
}
int totalorder(NodeRegion nr) { result = nr.totalOrder() }
}
private module UnreachableSets = MakeSets<UnreachableSetsInput>;
private module UnreachableSets =
QlBuiltins::InternSets<TCallEdge, NodeRegion, getAnUnreachableRegion/1>;
/** A set of nodes that is unreachable in some call context. */
cached
class UnreachableSet instanceof UnreachableSets::ValueSet {
class UnreachableSet instanceof UnreachableSets::Set {
cached
string toString() { result = "Unreachable" }
@@ -1562,7 +1535,7 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
}
cached
UnreachableSet getUnreachableSet(TCallEdge edge) { result = UnreachableSets::getValueSet(edge) }
UnreachableSet getUnreachableSet(TCallEdge edge) { result = UnreachableSets::getSet(edge) }
private module UnreachableSetOption = Option<UnreachableSet>;
@@ -1579,7 +1552,7 @@ module MakeImplCommon<LocationSig Location, InputSig<Location> Lang> {
cached
newtype TLocalFlowCallContext =
TAnyLocalCall() or
TSpecificLocalCall(UnreachableSets::ValueSet ns)
TSpecificLocalCall(UnreachableSets::Set ns)
cached
newtype TReturnKindExt =

View File

@@ -1,104 +0,0 @@
/**
* INTERNAL: This module may be replaced without notice.
*
* Provides a module to create first-class representations of sets of values.
*/
/** The input signature for `MakeSets`. */
signature module MkSetsInputSig {
class Key;
class Value;
Value getAValue(Key k);
int totalorder(Value v);
}
/**
* Given a binary predicate `getAValue`, this module groups the `Value` column
* by `Key` and constructs the corresponding sets of `Value`s as single entities.
*
* The output is a functional predicate, `getValueSet`, such that
* `getValueSet(k).contains(v)` is equivalent to `v = getAValue(k)`, and a
* class, `ValueSet`, that canonically represents a set of `Value`s. In
* particular, if two keys `k1` and `k2` relate to the same set of values, then
* `getValueSet(k1) = getValueSet(k2)`.
*
* If the given `totalorder` is not a total order, then the keys for which we
* cannot order the values cannot be given a canonical representation, and
* instead the key is simply reused as the set representation. This provides a
* reasonable fallback where `getValueSet(k).contains(v)` remains equivalent to
* `v = getAValue(k)`.
*/
module MakeSets<MkSetsInputSig Inp> {
private import Inp
private int totalorderExt(Value v) {
result = 0 and v = getAValue(_) and not exists(totalorder(v))
or
result = totalorder(v)
}
private predicate rankedValue(Key k, Value v, int r) {
v = rank[r](Value v0 | v0 = getAValue(k) | v0 order by totalorderExt(v0))
}
private predicate unordered(Key k) {
strictcount(int r | rankedValue(k, _, r)) != strictcount(getAValue(k))
}
private int maxRank(Key k) { result = max(int r | rankedValue(k, _, r)) and not unordered(k) }
private newtype TValList =
TValListNil() or
TValListCons(Value head, int r, TValList tail) { hasValListCons(_, head, r, tail) } or
TValListUnordered(Key k) { unordered(k) }
private predicate hasValListCons(Key k, Value head, int r, TValList tail) {
rankedValue(k, head, r) and
hasValList(k, r - 1, tail)
}
private predicate hasValList(Key k, int r, TValList l) {
exists(getAValue(k)) and r = 0 and l = TValListNil()
or
exists(Value head, TValList tail |
l = TValListCons(head, r, tail) and
hasValListCons(k, head, r, tail)
)
}
private predicate hasValueSet(Key k, TValList vs) {
hasValList(k, maxRank(k), vs) or vs = TValListUnordered(k)
}
/** A set of `Value`s. */
class ValueSet extends TValList {
ValueSet() { hasValueSet(_, this) }
string toString() {
this instanceof TValListCons and result = "ValueSet"
or
this instanceof TValListUnordered and result = "ValueSetUnordered"
}
private predicate sublist(TValListCons l) {
this = l or
this.sublist(TValListCons(_, _, l))
}
/** Holds if this set contains `v`. */
predicate contains(Value v) {
this.sublist(TValListCons(v, _, _))
or
exists(Key k | this = TValListUnordered(k) and v = getAValue(k))
}
}
/**
* Gets the set of values such that `getValueSet(k).contains(v)` is equivalent
* to `v = getAValue(k)`.
*/
ValueSet getValueSet(Key k) { hasValueSet(k, result) }
}

View File

@@ -65,16 +65,6 @@ class DataFlowCallable extends TDataFlowCallable {
Callable::TypeRange getUnderlyingCallable() {
result = this.asSummarizedCallable() or result = this.asSourceCallable()
}
/** Gets a best-effort total ordering. */
int totalorder() {
this =
rank[result](DataFlowCallable c, string file, int startline, int startcolumn |
c.getLocation().hasLocationInfo(file, startline, startcolumn, _, _)
|
c order by file, startline, startcolumn
)
}
}
cached
@@ -130,16 +120,6 @@ class DataFlowCall extends TDataFlowCall {
) {
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
}
/** Gets a best-effort total ordering. */
int totalorder() {
this =
rank[result](DataFlowCall c, int startline, int startcolumn |
c.hasLocationInfo(_, startline, startcolumn, _, _)
|
c order by startline, startcolumn
)
}
}
private class NormalCall extends DataFlowCall, TNormalCall {

View File

@@ -1381,8 +1381,6 @@ class NodeRegion instanceof Unit {
string toString() { result = "NodeRegion" }
predicate contains(Node n) { none() }
int totalOrder() { result = 1 }
}
/**