Skip to content

Commit 972b81b

Browse files
committed
Util: Allow best-effort total orders with a reasonable fallback.
1 parent b83416f commit 972b81b

File tree

1 file changed

+33
-8
lines changed

1 file changed

+33
-8
lines changed

shared/util/codeql/util/internal/MakeSets.qll

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,21 +24,36 @@ signature module MkSetsInp {
2424
* class, `ValueSet`, that canonically represents a set of `Value`s. In
2525
* particular, if two keys `k1` and `k2` relate to the same set of values, then
2626
* `getValueSet(k1) = getValueSet(k2)`.
27+
*
28+
* If the given `totalorder` is not a total order, then the keys for which we
29+
* cannot order the values cannot be given a canonical representation, and
30+
* instead the key is simply reused as the set representation. This provides a
31+
* reasonable fallback where `getValueSet(k).contains(v)` remains equivalent to
32+
* `v = getAValue(k)`.
2733
*/
2834
module MakeSets<MkSetsInp Inp> {
2935
private import Inp
3036

37+
private int totalorderExt(Value v) {
38+
result = 0 and v = getAValue(_) and not exists(totalorder(v))
39+
or
40+
result = totalorder(v)
41+
}
42+
3143
private predicate rankedValue(Key k, Value v, int r) {
32-
v = rank[r](Value v0 | v0 = getAValue(k) | v0 order by totalorder(v0))
44+
v = rank[r](Value v0 | v0 = getAValue(k) | v0 order by totalorderExt(v0))
3345
}
3446

35-
private int maxRank(Key k) { result = max(int r | rankedValue(k, _, r)) }
47+
private predicate unordered(Key k) {
48+
strictcount(int r | rankedValue(k, _, r)) != strictcount(getAValue(k))
49+
}
3650

37-
predicate consistency(int r, int bs) { bs = strictcount(Value v | totalorder(v) = r) and bs != 1 }
51+
private int maxRank(Key k) { result = max(int r | rankedValue(k, _, r)) and not unordered(k) }
3852

3953
private newtype TValList =
4054
TValListNil() or
41-
TValListCons(Value head, int r, TValList tail) { hasValListCons(_, head, r, tail) }
55+
TValListCons(Value head, int r, TValList tail) { hasValListCons(_, head, r, tail) } or
56+
TValListUnordered(Key k) { exists(getAValue(k)) and unordered(k) }
4257

4358
private predicate hasValListCons(Key k, Value head, int r, TValList tail) {
4459
rankedValue(k, head, r) and
@@ -54,21 +69,31 @@ module MakeSets<MkSetsInp Inp> {
5469
)
5570
}
5671

57-
private predicate hasValueSet(Key k, TValListCons vs) { hasValList(k, maxRank(k), vs) }
72+
private predicate hasValueSet(Key k, TValList vs) {
73+
hasValList(k, maxRank(k), vs) or vs = TValListUnordered(k)
74+
}
5875

5976
/** A set of `Value`s. */
60-
class ValueSet extends TValListCons {
77+
class ValueSet extends TValList {
6178
ValueSet() { hasValueSet(_, this) }
6279

63-
string toString() { result = "ValueSet" }
80+
string toString() {
81+
this instanceof TValListCons and result = "ValueSet"
82+
or
83+
this instanceof TValListUnordered and result = "ValueSetUnordered"
84+
}
6485

6586
private predicate sublist(TValListCons l) {
6687
this = l or
6788
this.sublist(TValListCons(_, _, l))
6889
}
6990

7091
/** Holds if this set contains `v`. */
71-
predicate contains(Value v) { this.sublist(TValListCons(v, _, _)) }
92+
predicate contains(Value v) {
93+
this.sublist(TValListCons(v, _, _))
94+
or
95+
exists(Key k | this = TValListUnordered(k) and v = getAValue(k))
96+
}
7297
}
7398

7499
/**

0 commit comments

Comments
 (0)