Skip to content

Commit fd8bf99

Browse files
authored
Merge pull request #20783 from MathiasVP/fix-cp-in-external-flow
C++: Fix cartesian-like join in `ExternalFlow.qll`
2 parents 267a7f5 + 7b052e2 commit fd8bf99

File tree

3 files changed

+207
-19685
lines changed

3 files changed

+207
-19685
lines changed

cpp/ql/lib/semmle/code/cpp/dataflow/ExternalFlow.qll

Lines changed: 68 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -656,6 +656,7 @@ private string getTypeNameWithoutFunctionTemplates(Function f, int n, int remain
656656
* Normalize the `n`'th parameter of `f` by replacing template names
657657
* with `class:N` (where `N` is the index of the template).
658658
*/
659+
pragma[nomagic]
659660
private string getTypeNameWithoutClassTemplates(Function f, int n, int remaining) {
660661
// If there is a declaring type then we start by expanding the function templates
661662
exists(Class template |
@@ -727,6 +728,7 @@ private string getSignatureWithoutClassTemplateNames(
727728
* - The `remaining` number of template arguments in `partiallyNormalizedSignature`
728729
* with their index in `nameArgs`.
729730
*/
731+
pragma[nomagic]
730732
private string getSignatureWithoutFunctionTemplateNames(
731733
string partiallyNormalizedSignature, string typeArgs, string nameArgs, int remaining
732734
) {
@@ -770,6 +772,7 @@ private string getSignatureWithoutFunctionTemplateNames(
770772
* ```
771773
* In this case, `normalizedSignature` will be `"(const func:0 &,int,class:1,class:0 *)"`.
772774
*/
775+
pragma[nomagic]
773776
private predicate elementSpecWithArguments(
774777
string signature, string type, string name, string normalizedSignature, string typeArgs,
775778
string nameArgs
@@ -789,6 +792,35 @@ private string getSignatureParameterName(string signature, string type, string n
789792
)
790793
}
791794

795+
/**
796+
* Gets a `Function` identified by the `(namespace, type, name)` components.
797+
*
798+
* If `subtypes` is `true` then the result may be an override of the function
799+
* identified by the components.
800+
*/
801+
pragma[nomagic]
802+
private Function getFunction(string namespace, string type, boolean subtypes, string name) {
803+
elementSpec(namespace, type, subtypes, name, _, _) and
804+
(
805+
funcHasQualifiedName(result, namespace, name) and
806+
subtypes = false and
807+
type = ""
808+
or
809+
exists(Class namedClass, Class classWithMethod |
810+
hasClassAndName(classWithMethod, result, name) and
811+
classHasQualifiedName(namedClass, namespace, type)
812+
|
813+
// member declared in the named type or a subtype of it
814+
subtypes = true and
815+
classWithMethod = namedClass.getADerivedClass*()
816+
or
817+
// member declared directly in the named type
818+
subtypes = false and
819+
classWithMethod = namedClass
820+
)
821+
)
822+
}
823+
792824
/**
793825
* Holds if the suffix containing the entries in `signature` starting at entry
794826
* `i` matches the suffix containing the parameters of `func` starting at entry `i`.
@@ -812,13 +844,17 @@ private string getSignatureParameterName(string signature, string type, string n
812844
* is `func:n` then the signature name is compared with the `n`'th name
813845
* in `name`.
814846
*/
815-
private predicate signatureMatches(Function func, string signature, string type, string name, int i) {
847+
pragma[nomagic]
848+
private predicate signatureMatches(
849+
Function func, string namespace, string signature, string type, string name, int i
850+
) {
851+
func = getFunction(namespace, type, _, name) and
816852
exists(string s |
817853
s = getSignatureParameterName(signature, type, name, i) and
818854
s = getParameterTypeName(func, i)
819855
) and
820856
if exists(getParameterTypeName(func, i + 1))
821-
then signatureMatches(func, signature, type, name, i + 1)
857+
then signatureMatches(func, namespace, signature, type, name, i + 1)
822858
else i = count(signature.indexOf(","))
823859
}
824860

@@ -833,7 +869,7 @@ module ExternalFlowDebug {
833869
*
834870
* Exposed for testing purposes.
835871
*/
836-
predicate signatureMatches_debug = signatureMatches/5;
872+
predicate signatureMatches_debug = signatureMatches/6;
837873

838874
/**
839875
* INTERNAL: Do not use.
@@ -883,6 +919,7 @@ private predicate parseParens(string s, string betweenParens) { s = "(" + betwee
883919
* - `signatureWithoutParens` equals `signature`, but with the surrounding
884920
* parentheses removed.
885921
*/
922+
pragma[nomagic]
886923
private predicate elementSpecWithArguments0(
887924
string signature, string type, string name, string signatureWithoutParens, string typeArgs,
888925
string nameArgs
@@ -909,7 +946,7 @@ private predicate elementSpecMatchesSignature(
909946
) {
910947
elementSpec(namespace, pragma[only_bind_into](type), subtypes, pragma[only_bind_into](name),
911948
pragma[only_bind_into](signature), _) and
912-
signatureMatches(func, signature, type, name, 0)
949+
signatureMatches(func, namespace, signature, type, name, 0)
913950
}
914951

915952
/**
@@ -953,7 +990,7 @@ private predicate funcHasQualifiedName(Function func, string namespace, string n
953990
* Holds if `namedClass` is in namespace `namespace` and has
954991
* name `type` (excluding any template parameters).
955992
*/
956-
bindingset[type, namespace]
993+
bindingset[type]
957994
pragma[inline_late]
958995
private predicate classHasQualifiedName(Class namedClass, string namespace, string type) {
959996
exists(string typeWithoutArgs |
@@ -969,17 +1006,14 @@ private predicate classHasQualifiedName(Class namedClass, string namespace, stri
9691006
* are also returned.
9701007
* 3. The element has name `name`
9711008
* 4. If `signature` is non-empty, then the element has a list of parameter types described by `signature`.
972-
*
973-
* NOTE: `namespace` is currently not used (since we don't properly extract modules yet).
9741009
*/
9751010
pragma[nomagic]
9761011
private Element interpretElement0(
9771012
string namespace, string type, boolean subtypes, string name, string signature
9781013
) {
1014+
result = getFunction(namespace, type, subtypes, name) and
9791015
(
9801016
// Non-member functions
981-
funcHasQualifiedName(result, namespace, name) and
982-
subtypes = false and
9831017
type = "" and
9841018
(
9851019
elementSpecMatchesSignature(result, namespace, type, subtypes, name, signature)
@@ -989,52 +1023,36 @@ private Element interpretElement0(
9891023
)
9901024
or
9911025
// Member functions
992-
exists(Class namedClass, Class classWithMethod |
993-
hasClassAndName(classWithMethod, result, name) and
994-
classHasQualifiedName(namedClass, namespace, type)
995-
|
996-
(
997-
elementSpecMatchesSignature(result, namespace, type, subtypes, name, signature)
998-
or
999-
signature = "" and
1000-
elementSpec(namespace, type, subtypes, name, "", _)
1001-
) and
1002-
(
1003-
// member declared in the named type or a subtype of it
1004-
subtypes = true and
1005-
classWithMethod = namedClass.getADerivedClass*()
1006-
or
1007-
// member declared directly in the named type
1008-
subtypes = false and
1009-
classWithMethod = namedClass
1010-
)
1011-
)
1026+
elementSpecMatchesSignature(result, namespace, type, subtypes, name, signature)
10121027
or
1013-
elementSpec(namespace, type, subtypes, name, signature, _) and
1014-
// Member variables
10151028
signature = "" and
1016-
exists(Class namedClass, Class classWithMember, MemberVariable member |
1017-
member.getName() = name and
1018-
member = classWithMember.getAMember() and
1019-
namedClass.hasQualifiedName(namespace, type) and
1020-
result = member
1021-
|
1022-
// field declared in the named type or a subtype of it (or an extension of any)
1023-
subtypes = true and
1024-
classWithMember = namedClass.getADerivedClass*()
1025-
or
1026-
// field declared directly in the named type (or an extension of it)
1027-
subtypes = false and
1028-
classWithMember = namedClass
1029-
)
1029+
elementSpec(namespace, type, subtypes, name, signature, _)
1030+
)
1031+
or
1032+
// Member variables
1033+
elementSpec(namespace, type, subtypes, name, signature, _) and
1034+
signature = "" and
1035+
exists(Class namedClass, Class classWithMember, MemberVariable member |
1036+
member.getName() = name and
1037+
member = classWithMember.getAMember() and
1038+
namedClass.hasQualifiedName(namespace, type) and
1039+
result = member
1040+
|
1041+
// field declared in the named type or a subtype of it (or an extension of any)
1042+
subtypes = true and
1043+
classWithMember = namedClass.getADerivedClass*()
10301044
or
1031-
// Global or namespace variables
1032-
elementSpec(namespace, type, subtypes, name, signature, _) and
1033-
signature = "" and
1034-
type = "" and
1045+
// field declared directly in the named type (or an extension of it)
10351046
subtypes = false and
1036-
result = any(GlobalOrNamespaceVariable v | v.hasQualifiedName(namespace, name))
1047+
classWithMember = namedClass
10371048
)
1049+
or
1050+
// Global or namespace variables
1051+
elementSpec(namespace, type, subtypes, name, signature, _) and
1052+
signature = "" and
1053+
type = "" and
1054+
subtypes = false and
1055+
result = any(GlobalOrNamespaceVariable v | v.hasQualifiedName(namespace, name))
10381056
}
10391057

10401058
cached

0 commit comments

Comments
 (0)