Skip to content

Commit f880669

Browse files
committed
Make deep-unalias computation even more efficient using unpack routines
1 parent 315afd3 commit f880669

File tree

1 file changed

+203
-28
lines changed

1 file changed

+203
-28
lines changed

go/ql/lib/semmle/go/Types.qll

Lines changed: 203 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,92 @@ class ByteSliceType extends SliceType {
459459
ByteSliceType() { this.getElementType() instanceof Uint8Type }
460460
}
461461

462+
// Improve efficiency of matching a struct to its unaliased equivalent
463+
// by unpacking the first 5 fields and tags, allowing a single join
464+
// to strongly constrain the available candidates.
465+
private predicate hasComponentTypeAndTag(StructType s, int i, string name, Type tp, string tag) {
466+
component_types(s, i, name, tp) and component_tags(s, i, tag)
467+
}
468+
469+
private newtype TOptStructComponent =
470+
MkNoComponent() or
471+
MkSomeComponent(string name, Type tp, string tag) { hasComponentTypeAndTag(_, _, name, tp, tag) }
472+
473+
private class OptStructComponent extends TOptStructComponent {
474+
OptStructComponent getWithDeepUnaliasedType() {
475+
this = MkNoComponent() and result = MkNoComponent()
476+
or
477+
exists(string name, Type tp, string tag |
478+
this = MkSomeComponent(name, tp, tag) and
479+
result = MkSomeComponent(name, tp.getDeepUnaliasedType(), tag)
480+
)
481+
}
482+
483+
string toString() { result = "struct component" }
484+
}
485+
486+
private class StructComponent extends MkSomeComponent {
487+
string toString() { result = "struct component" }
488+
489+
predicate isComponentOf(StructType s, int i) {
490+
exists(string name, Type tp, string tag |
491+
hasComponentTypeAndTag(s, i, name, tp, tag) and
492+
this = MkSomeComponent(name, tp, tag)
493+
)
494+
}
495+
}
496+
497+
pragma[nomagic]
498+
predicate unpackStructType(
499+
StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2,
500+
TOptStructComponent c3, TOptStructComponent c4, int nComponents
501+
) {
502+
nComponents = count(int i | component_types(s, i, _, _)) and
503+
(
504+
if nComponents >= 1
505+
then c0 = any(StructComponent sc | sc.isComponentOf(s, 0))
506+
else c0 = MkNoComponent()
507+
) and
508+
(
509+
if nComponents >= 2
510+
then c1 = any(StructComponent sc | sc.isComponentOf(s, 1))
511+
else c1 = MkNoComponent()
512+
) and
513+
(
514+
if nComponents >= 3
515+
then c2 = any(StructComponent sc | sc.isComponentOf(s, 2))
516+
else c2 = MkNoComponent()
517+
) and
518+
(
519+
if nComponents >= 4
520+
then c3 = any(StructComponent sc | sc.isComponentOf(s, 3))
521+
else c3 = MkNoComponent()
522+
) and
523+
(
524+
if nComponents >= 5
525+
then c4 = any(StructComponent sc | sc.isComponentOf(s, 4))
526+
else c4 = MkNoComponent()
527+
)
528+
}
529+
530+
pragma[nomagic]
531+
predicate unpackAndUnaliasStructType(
532+
StructType s, TOptStructComponent c0, TOptStructComponent c1, TOptStructComponent c2,
533+
TOptStructComponent c3, TOptStructComponent c4, int nComponents
534+
) {
535+
exists(
536+
OptStructComponent c0a, OptStructComponent c1a, OptStructComponent c2a, OptStructComponent c3a,
537+
OptStructComponent c4a
538+
|
539+
unpackStructType(s, c0a, c1a, c2a, c3a, c4a, nComponents) and
540+
c0 = c0a.getWithDeepUnaliasedType() and
541+
c1 = c1a.getWithDeepUnaliasedType() and
542+
c2 = c2a.getWithDeepUnaliasedType() and
543+
c3 = c3a.getWithDeepUnaliasedType() and
544+
c4 = c4a.getWithDeepUnaliasedType()
545+
)
546+
}
547+
462548
/** A struct type. */
463549
class StructType extends @structtype, CompositeType {
464550
/**
@@ -598,29 +684,36 @@ class StructType extends @structtype, CompositeType {
598684
)
599685
}
600686

601-
private predicate hasComponentTypeAndTag(int i, string name, Type tp, string tag) {
602-
component_types(this, i, name, tp) and component_tags(this, i, tag)
687+
private StructType getDeepUnaliasedTypeCandidate() {
688+
exists(
689+
OptStructComponent c0, OptStructComponent c1, OptStructComponent c2, OptStructComponent c3,
690+
OptStructComponent c4, int nComponents
691+
|
692+
unpackAndUnaliasStructType(this, c0, c1, c2, c3, c4, nComponents) and
693+
unpackStructType(result, c0, c1, c2, c3, c4, nComponents)
694+
)
603695
}
604696

605697
private predicate isDeepUnaliasedTypeUpTo(StructType unaliased, int i) {
606698
// Note we must use component_types not hasOwnField here because component_types may specify
607699
// interface-in-struct embedding, but hasOwnField does not return such members.
700+
unaliased = this.getDeepUnaliasedTypeCandidate() and
701+
i >= 5 and
608702
(
609-
i = 0 or
703+
i = 5 or
610704
this.isDeepUnaliasedTypeUpTo(unaliased, i - 1)
611705
) and
612-
exists(string name, Type tp, string tag | this.hasComponentTypeAndTag(i, name, tp, tag) |
613-
unaliased.hasComponentTypeAndTag(i, name, tp.getDeepUnaliasedType(), tag)
706+
exists(string name, Type tp, string tag | hasComponentTypeAndTag(this, i, name, tp, tag) |
707+
hasComponentTypeAndTag(unaliased, i, name, tp.getDeepUnaliasedType(), tag)
614708
)
615709
}
616710

617711
override StructType getDeepUnaliasedType() {
712+
result = this.getDeepUnaliasedTypeCandidate() and
618713
exists(int nComponents | nComponents = count(int i | component_types(this, i, _, _)) |
619-
(
620-
this.isDeepUnaliasedTypeUpTo(result, nComponents - 1)
621-
or
622-
nComponents = 0 and result = this
623-
)
714+
this.isDeepUnaliasedTypeUpTo(result, nComponents - 1)
715+
or
716+
nComponents <= 5
624717
)
625718
}
626719

@@ -961,11 +1054,14 @@ class TupleType extends @tupletype, CompositeType {
9611054
}
9621055

9631056
override TupleType getDeepUnaliasedType() {
964-
exists(int nComponents | nComponents = count(int i | exists(this.getComponentType(i))) |
1057+
exists(int nComponents |
1058+
nComponents = count(int i | exists(this.getComponentType(i))) and
1059+
nComponents = count(int i | exists(result.getComponentType(i)))
1060+
|
9651061
this.isDeepUnaliasedTypeUpTo(result, nComponents - 1)
9661062
or
9671063
// I don't think Go allows empty tuples in any context, but this is at least harmless.
968-
nComponents = 0 and result = this
1064+
nComponents = 0
9691065
)
9701066
}
9711067

@@ -978,6 +1074,68 @@ class TupleType extends @tupletype, CompositeType {
9781074
override string toString() { result = "tuple type" }
9791075
}
9801076

1077+
// Reasonably efficiently map from a signature type to its
1078+
// deep-unaliased equivalent, by using a single join for the leading 5 parameters
1079+
// and/or 3 results.
1080+
private newtype TOptType =
1081+
MkNoType() or
1082+
MkSomeType(Type tp)
1083+
1084+
private class OptType extends TOptType {
1085+
OptType getDeepUnaliasedType() {
1086+
exists(Type t | this = MkSomeType(t) | result = MkSomeType(t.getDeepUnaliasedType()))
1087+
or
1088+
this = MkNoType() and result = MkNoType()
1089+
}
1090+
1091+
string toString() {
1092+
exists(Type t | this = MkSomeType(t) | result = t.toString())
1093+
or
1094+
this = MkNoType() and result = "no type"
1095+
}
1096+
}
1097+
1098+
pragma[nomagic]
1099+
private predicate unpackSignatureType(
1100+
SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4,
1101+
int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic
1102+
) {
1103+
nParams = sig.getNumParameter() and
1104+
nResults = sig.getNumResult() and
1105+
(if nParams >= 1 then param0 = MkSomeType(sig.getParameterType(0)) else param0 = MkNoType()) and
1106+
(if nParams >= 2 then param1 = MkSomeType(sig.getParameterType(1)) else param1 = MkNoType()) and
1107+
(if nParams >= 3 then param2 = MkSomeType(sig.getParameterType(2)) else param2 = MkNoType()) and
1108+
(if nParams >= 4 then param3 = MkSomeType(sig.getParameterType(3)) else param3 = MkNoType()) and
1109+
(if nParams >= 5 then param4 = MkSomeType(sig.getParameterType(4)) else param4 = MkNoType()) and
1110+
(if nResults >= 1 then result0 = MkSomeType(sig.getResultType(0)) else result0 = MkNoType()) and
1111+
(if nResults >= 2 then result1 = MkSomeType(sig.getResultType(1)) else result1 = MkNoType()) and
1112+
(if nResults >= 3 then result2 = MkSomeType(sig.getResultType(2)) else result2 = MkNoType()) and
1113+
(if sig.isVariadic() then isVariadic = true else isVariadic = false)
1114+
}
1115+
1116+
pragma[nomagic]
1117+
private predicate unpackAndUnaliasSignatureType(
1118+
SignatureType sig, OptType param0, OptType param1, OptType param2, OptType param3, OptType param4,
1119+
int nParams, OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic
1120+
) {
1121+
exists(
1122+
OptType param0a, OptType param1a, OptType param2a, OptType param3a, OptType param4a,
1123+
OptType result0a, OptType result1a, OptType result2a
1124+
|
1125+
unpackSignatureType(sig, param0a, param1a, param2a, param3a, param4a, nParams, result0a,
1126+
result1a, result2a, nResults, isVariadic)
1127+
|
1128+
param0 = param0a.getDeepUnaliasedType() and
1129+
param1 = param1a.getDeepUnaliasedType() and
1130+
param2 = param2a.getDeepUnaliasedType() and
1131+
param3 = param3a.getDeepUnaliasedType() and
1132+
param4 = param4a.getDeepUnaliasedType() and
1133+
result0 = result0a.getDeepUnaliasedType() and
1134+
result1 = result1a.getDeepUnaliasedType() and
1135+
result2 = result2a.getDeepUnaliasedType()
1136+
)
1137+
}
1138+
9811139
/** A signature type. */
9821140
class SignatureType extends @signaturetype, CompositeType {
9831141
/** Gets the `i`th parameter type of this signature type. */
@@ -995,31 +1153,48 @@ class SignatureType extends @signaturetype, CompositeType {
9951153
/** Holds if this signature type is variadic. */
9961154
predicate isVariadic() { variadic(this) }
9971155

1156+
private SignatureType getDeepUnaliasedTypeCandidate() {
1157+
exists(
1158+
OptType param0, OptType param1, OptType param2, OptType param3, OptType param4, int nParams,
1159+
OptType result0, OptType result1, OptType result2, int nResults, boolean isVariadic
1160+
|
1161+
unpackAndUnaliasSignatureType(this, param0, param1, param2, param3, param4, nParams, result0,
1162+
result1, result2, nResults, isVariadic) and
1163+
unpackSignatureType(result, param0, param1, param2, param3, param4, nParams, result0, result1,
1164+
result2, nResults, isVariadic)
1165+
)
1166+
}
1167+
1168+
// These incremental recursive implementations only apply from parameter 5 or result 3
1169+
// upwards to avoid constructing large squares of candidates -- the initial parameters
1170+
// and results are taken care of by the candidate predicate.
9981171
private predicate hasDeepUnaliasedParameterTypesUpTo(SignatureType unaliased, int i) {
999-
(i = 0 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and
1172+
unaliased = this.getDeepUnaliasedTypeCandidate() and
1173+
i >= 5 and
1174+
(i = 5 or this.hasDeepUnaliasedParameterTypesUpTo(unaliased, i - 1)) and
10001175
unaliased.getParameterType(i) = this.getParameterType(i).getDeepUnaliasedType()
10011176
}
10021177

10031178
private predicate hasDeepUnaliasedResultTypesUpTo(SignatureType unaliased, int i) {
1004-
(i = 0 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and
1179+
unaliased = this.getDeepUnaliasedTypeCandidate() and
1180+
i >= 3 and
1181+
(i = 3 or this.hasDeepUnaliasedResultTypesUpTo(unaliased, i - 1)) and
10051182
unaliased.getResultType(i) = this.getResultType(i).getDeepUnaliasedType()
10061183
}
10071184

10081185
override SignatureType getDeepUnaliasedType() {
1009-
exists(int nParams | nParams = this.getNumParameter() |
1010-
nParams = 0 and result.getNumParameter() = 0
1011-
or
1012-
this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1)
1013-
) and
1014-
exists(int nResults | nResults = this.getNumResult() |
1015-
nResults = 0 and result.getNumResult() = 0
1016-
or
1017-
this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1)
1018-
) and
1019-
(
1020-
this.isVariadic() and result.isVariadic()
1021-
or
1022-
not this.isVariadic() and not result.isVariadic()
1186+
result = this.getDeepUnaliasedTypeCandidate() and
1187+
exists(int nParams, int nResults |
1188+
this.getNumParameter() = nParams and this.getNumResult() = nResults
1189+
|
1190+
(
1191+
nParams <= 5
1192+
or
1193+
this.hasDeepUnaliasedParameterTypesUpTo(result, nParams - 1) and
1194+
nResults <= 3
1195+
or
1196+
this.hasDeepUnaliasedResultTypesUpTo(result, nResults - 1)
1197+
)
10231198
)
10241199
}
10251200

0 commit comments

Comments
 (0)