Skip to content

Commit

Permalink
Merge branch 'main' into rust-saa-additions
Browse files Browse the repository at this point in the history
  • Loading branch information
paldepind committed Oct 21, 2024
2 parents 76e1885 + ce53964 commit 85e59c9
Show file tree
Hide file tree
Showing 111 changed files with 2,276 additions and 1,053 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* The function call target resolution algorithm has been improved to resolve more calls through function pointers. As a result, dataflow queries may have more results.
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
category: feature
---
* Added a new predicate `DataFlow::getARuntimeTarget` for getting a function that may be invoked by a `Call` expression. Unlike `Call.getTarget` this new predicate may also resolve function pointers.
21 changes: 15 additions & 6 deletions cpp/ql/lib/semmle/code/cpp/Element.qll
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ class Element extends ElementBase {
* or certain kinds of `Statement`.
*/
Element getParentScope() {
// result instanceof class
// result instanceof Class
exists(Declaration m |
m = this and
result = m.getDeclaringType() and
Expand All @@ -138,31 +138,40 @@ class Element extends ElementBase {
or
exists(TemplateClass tc | this = tc.getATemplateArgument() and result = tc)
or
// result instanceof namespace
// result instanceof Namespace
exists(Namespace n | result = n and n.getADeclaration() = this)
or
exists(FriendDecl d, Namespace n | this = d and n.getADeclaration() = d and result = n)
or
exists(Namespace n | this = n and result = n.getParentNamespace())
or
// result instanceof stmt
// result instanceof Stmt
exists(LocalVariable v |
this = v and
exists(DeclStmt ds | ds.getADeclaration() = v and result = ds.getParent())
)
or
exists(Parameter p | this = p and result = p.getFunction())
exists(Parameter p |
this = p and
(
result = p.getFunction() or
result = p.getCatchBlock().getParent().(Handler).getParent().(TryStmt).getParent() or
result = p.getRequiresExpr().getEnclosingStmt().getParent()
)
)
or
exists(GlobalVariable g, Namespace n | this = g and n.getADeclaration() = g and result = n)
or
exists(TemplateVariable tv | this = tv.getATemplateArgument() and result = tv)
or
exists(EnumConstant e | this = e and result = e.getDeclaringEnum())
or
// result instanceof block|function
// result instanceof Block|Function
exists(BlockStmt b | this = b and blockscope(unresolveElement(b), unresolveElement(result)))
or
exists(TemplateFunction tf | this = tf.getATemplateArgument() and result = tf)
or
// result instanceof stmt
// result instanceof Stmt
exists(ControlStructure s | this = s and result = s.getParent())
or
using_container(unresolveElement(result), underlyingElement(this))
Expand Down
3 changes: 2 additions & 1 deletion cpp/ql/lib/semmle/code/cpp/Parameter.qll
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ class Parameter extends LocalScopeVariable, @parameter {
}

private VariableDeclarationEntry getANamedDeclarationEntry() {
result = this.getAnEffectiveDeclarationEntry() and result.getName() != ""
result = this.getAnEffectiveDeclarationEntry() and
exists(string name | var_decls(unresolveElement(result), _, _, name, _) | name != "")
}

/**
Expand Down
20 changes: 8 additions & 12 deletions cpp/ql/lib/semmle/code/cpp/Variable.qll
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,10 @@ class VariableDeclarationEntry extends DeclarationEntry, @var_decl {
name != "" and result = name
or
name = "" and result = this.getVariable().(LocalVariable).getName()
or
name = "" and
not this instanceof ParameterDeclarationEntry and
result = this.getVariable().(Parameter).getName()
)
)
}
Expand Down Expand Up @@ -295,19 +299,11 @@ class ParameterDeclarationEntry extends VariableDeclarationEntry {

private string getAnonymousParameterDescription() {
not exists(this.getName()) and
exists(string idx |
idx =
((this.getIndex() + 1).toString() + "th")
.replaceAll("1th", "1st")
.replaceAll("2th", "2nd")
.replaceAll("3th", "3rd")
.replaceAll("11st", "11th")
.replaceAll("12nd", "12th")
.replaceAll("13rd", "13th") and
exists(string anon |
anon = "(unnamed parameter " + this.getIndex().toString() + ")" and
if exists(this.getCanonicalName())
then
result = "declaration of " + this.getCanonicalName() + " as anonymous " + idx + " parameter"
else result = "declaration of " + idx + " parameter"
then result = "declaration of " + this.getCanonicalName() + " as " + anon
else result = "declaration of " + anon
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1328,7 +1328,10 @@ predicate lambdaCreation(Node creation, LambdaCallKind kind, DataFlowCallable c)

/** Holds if `call` is a lambda call of kind `kind` where `receiver` is the lambda expression. */
predicate lambdaCall(DataFlowCall call, LambdaCallKind kind, Node receiver) {
call.(SummaryCall).getReceiver() = receiver.(FlowSummaryNode).getSummaryNode() and
(
call.(SummaryCall).getReceiver() = receiver.(FlowSummaryNode).getSummaryNode() or
call.asCallInstruction().getCallTargetOperand() = receiver.asOperand()
) and
exists(kind)
}

Expand Down
14 changes: 14 additions & 0 deletions cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ private import SsaInternals as Ssa
private import DataFlowImplCommon as DataFlowImplCommon
private import codeql.util.Unit
private import Node0ToString
private import DataFlowDispatch as DataFlowDispatch
import ExprNodes

/**
Expand Down Expand Up @@ -2497,3 +2498,16 @@ class AdditionalCallTarget extends Unit {
*/
abstract Declaration viableTarget(Call call);
}

/**
* Gets a function that may be called by `call`.
*
* Note that `call` may be a call to a function pointer expression.
*/
Function getARuntimeTarget(Call call) {
exists(DataFlowCall dfCall | dfCall.asCallInstruction().getUnconvertedResultExpression() = call |
result = DataFlowDispatch::viableCallable(dfCall).asSourceCallable()
or
result = DataFlowImplCommon::viableCallableLambda(dfCall, _).asSourceCallable()
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ uniqueEnclosingCallable
| test.cpp:864:47:864:54 | call to source | Node should have one enclosing callable but has 0. |
| test.cpp:872:46:872:51 | call to source | Node should have one enclosing callable but has 0. |
| test.cpp:872:53:872:56 | 1 | Node should have one enclosing callable but has 0. |
| test.cpp:1126:33:1129:1 | {...} | Node should have one enclosing callable but has 0. |
| test.cpp:1127:3:1127:13 | reads_input | Node should have one enclosing callable but has 0. |
| test.cpp:1128:3:1128:21 | not_does_read_input | Node should have one enclosing callable but has 0. |
uniqueCallEnclosingCallable
| test.cpp:864:47:864:54 | call to source | Call should have one enclosing callable but has 0. |
| test.cpp:872:46:872:51 | call to source | Call should have one enclosing callable but has 0. |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ irFlow
| test.cpp:1069:9:1069:14 | call to source | test.cpp:1074:10:1074:10 | i |
| test.cpp:1069:9:1069:14 | call to source | test.cpp:1081:10:1081:10 | i |
| test.cpp:1117:27:1117:34 | call to source | test.cpp:1117:27:1117:34 | call to source |
| test.cpp:1132:11:1132:16 | call to source | test.cpp:1121:8:1121:8 | x |
| true_upon_entry.cpp:9:11:9:16 | call to source | true_upon_entry.cpp:13:8:13:8 | x |
| true_upon_entry.cpp:17:11:17:16 | call to source | true_upon_entry.cpp:21:8:21:8 | x |
| true_upon_entry.cpp:27:9:27:14 | call to source | true_upon_entry.cpp:29:8:29:8 | x |
Expand Down
16 changes: 16 additions & 0 deletions cpp/ql/test/library-tests/dataflow/dataflow-tests/test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1115,4 +1115,20 @@ void indirect_sink_const_ref(const T&);

void test_temp_with_conversion_from_materialization() {
indirect_sink_const_ref(source()); // $ ir MISSING: ast
}

void reads_input(int x) {
sink(x); // $ ir MISSING: ast
}

void not_does_read_input(int x);

void (*dispatch_table[])(int) = {
reads_input,
not_does_read_input
};

void test_dispatch_table(int i) {
int x = source();
dispatch_table[i](x);
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@
| declarationEntry.cpp:39:7:39:7 | declaration of operator= | declarationEntry.cpp:39:7:39:7 | operator= | yes |
| declarationEntry.cpp:39:7:39:13 | definition of myClass | declarationEntry.cpp:39:7:39:13 | myClass | yes |
| declarationEntry.cpp:42:6:42:21 | definition of myMemberVariable | declarationEntry.cpp:42:6:42:21 | myMemberVariable | yes |
| file://:0:0:0:0 | declaration of 1st parameter | file://:0:0:0:0 | (unnamed parameter 0) | yes |
| file://:0:0:0:0 | declaration of 1st parameter | file://:0:0:0:0 | (unnamed parameter 0) | yes |
| file://:0:0:0:0 | declaration of (unnamed parameter 0) | file://:0:0:0:0 | (unnamed parameter 0) | yes |
| file://:0:0:0:0 | declaration of (unnamed parameter 0) | file://:0:0:0:0 | (unnamed parameter 0) | yes |
| file://:0:0:0:0 | definition of fp_offset | file://:0:0:0:0 | fp_offset | yes |
| file://:0:0:0:0 | definition of gp_offset | file://:0:0:0:0 | gp_offset | yes |
| file://:0:0:0:0 | definition of overflow_arg_area | file://:0:0:0:0 | overflow_arg_area | yes |
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
| file://:0:0:0:0 | declaration of 1st parameter |
| file://:0:0:0:0 | declaration of 1st parameter |
| file://:0:0:0:0 | declaration of 1st parameter |
| file://:0:0:0:0 | declaration of 1st parameter |
| file://:0:0:0:0 | declaration of (unnamed parameter 0) |
| file://:0:0:0:0 | declaration of (unnamed parameter 0) |
| file://:0:0:0:0 | declaration of (unnamed parameter 0) |
| file://:0:0:0:0 | declaration of (unnamed parameter 0) |
| file://:0:0:0:0 | definition of fp_offset |
| file://:0:0:0:0 | definition of gp_offset |
| file://:0:0:0:0 | definition of overflow_arg_area |
Expand Down
16 changes: 8 additions & 8 deletions cpp/ql/test/library-tests/parameters/toStrings/params.expected
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
| test.c:2:8:2:10 | declaration of 1st parameter |
| test.c:2:13:2:15 | declaration of 2nd parameter |
| test.c:2:18:2:20 | declaration of 3rd parameter |
| test.c:2:23:2:25 | declaration of 4th parameter |
| test.c:3:8:3:10 | declaration of y1 as anonymous 1st parameter |
| test.c:3:13:3:15 | declaration of y2 as anonymous 2nd parameter |
| test.c:3:18:3:20 | declaration of y3 as anonymous 3rd parameter |
| test.c:3:23:3:25 | declaration of y4 as anonymous 4th parameter |
| test.c:2:8:2:10 | declaration of (unnamed parameter 0) |
| test.c:2:13:2:15 | declaration of (unnamed parameter 1) |
| test.c:2:18:2:20 | declaration of (unnamed parameter 2) |
| test.c:2:23:2:25 | declaration of (unnamed parameter 3) |
| test.c:3:8:3:10 | declaration of y1 as (unnamed parameter 0) |
| test.c:3:13:3:15 | declaration of y2 as (unnamed parameter 1) |
| test.c:3:18:3:20 | declaration of y3 as (unnamed parameter 2) |
| test.c:3:23:3:25 | declaration of y4 as (unnamed parameter 3) |
| test.c:4:12:4:13 | declaration of x1 |
| test.c:4:20:4:21 | declaration of x2 |
| test.c:4:28:4:29 | declaration of x3 |
Expand Down
9 changes: 8 additions & 1 deletion cpp/ql/test/library-tests/scopes/parents/parents.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,13 @@ namespace foo {
}
}

template<typename T>
T var = 42;


int g() {
requires(int l) { l; };

return var<int>;
}

// semmle-extractor-options: -std=c++20
7 changes: 7 additions & 0 deletions cpp/ql/test/library-tests/scopes/parents/parents.expected
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
| 0 | file://:0:0:0:0 | (global namespace) | file://:0:0:0:0 | __va_list_tag |
| 0 | file://:0:0:0:0 | (global namespace) | parents.cpp:2:11:2:13 | foo |
| 0 | file://:0:0:0:0 | (global namespace) | parents.cpp:18:3:18:3 | var |
| 0 | file://:0:0:0:0 | (global namespace) | parents.cpp:18:7:18:7 | var |
| 0 | file://:0:0:0:0 | (global namespace) | parents.cpp:20:5:20:5 | g |
| 1 | file://:0:0:0:0 | __va_list_tag | file://:0:0:0:0 | fp_offset |
| 1 | file://:0:0:0:0 | __va_list_tag | file://:0:0:0:0 | gp_offset |
| 1 | file://:0:0:0:0 | __va_list_tag | file://:0:0:0:0 | operator= |
Expand All @@ -14,7 +17,11 @@
| 1 | parents.cpp:4:10:4:10 | f | parents.cpp:4:19:13:5 | { ... } |
| 1 | parents.cpp:4:19:13:5 | { ... } | parents.cpp:5:11:5:11 | j |
| 1 | parents.cpp:4:19:13:5 | { ... } | parents.cpp:6:11:10:7 | { ... } |
| 1 | parents.cpp:4:19:13:5 | { ... } | parents.cpp:11:18:11:18 | e |
| 1 | parents.cpp:4:19:13:5 | { ... } | parents.cpp:11:21:12:7 | { ... } |
| 1 | parents.cpp:6:11:10:7 | { ... } | parents.cpp:7:9:9:9 | for(...;...;...) ... |
| 1 | parents.cpp:6:11:10:7 | { ... } | parents.cpp:7:33:9:9 | { ... } |
| 1 | parents.cpp:7:33:9:9 | { ... } | parents.cpp:8:15:8:15 | k |
| 1 | parents.cpp:18:7:18:7 | var | parents.cpp:17:19:17:19 | T |
| 1 | parents.cpp:20:5:20:5 | g | parents.cpp:20:9:24:1 | { ... } |
| 1 | parents.cpp:20:9:24:1 | { ... } | parents.cpp:21:16:21:16 | l |
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
| file://:0:0:0:0 | declaration of 1st parameter | LibB/libb_internal.h:5:8:5:12 | thing |
| file://:0:0:0:0 | declaration of 1st parameter | LibB/libb_internal.h:5:8:5:12 | thing |
| file://:0:0:0:0 | declaration of (unnamed parameter 0) | LibB/libb_internal.h:5:8:5:12 | thing |
| file://:0:0:0:0 | declaration of (unnamed parameter 0) | LibB/libb_internal.h:5:8:5:12 | thing |
| include.h:3:25:3:33 | num | LibD/libd.h:5:12:5:14 | num |
| main.cpp:8:31:8:31 | call to container | LibC/libc.h:9:3:9:3 | container |
| main.cpp:8:31:8:31 | definition of x | LibB/libb_internal.h:5:8:5:12 | thing |
Expand Down
2 changes: 1 addition & 1 deletion docs/codeql/reusables/supported-versions-compilers.rst
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
Eclipse compiler for Java (ECJ) [6]_",``.java``
Kotlin,"Kotlin 1.5.0 to 2.1.0\ *x*","kotlinc",``.kt``
JavaScript,ECMAScript 2022 or lower,Not applicable,"``.js``, ``.jsx``, ``.mjs``, ``.es``, ``.es6``, ``.htm``, ``.html``, ``.xhtm``, ``.xhtml``, ``.vue``, ``.hbs``, ``.ejs``, ``.njk``, ``.json``, ``.yaml``, ``.yml``, ``.raml``, ``.xml`` [7]_"
Python [8]_,"2.7, 3.5, 3.6, 3.7, 3.8, 3.9, 3.10, 3.11, 3.12",Not applicable,``.py``
Python [8]_,"2.7, 3.5, 3.6, 3.7, 3.8, 3.9, 3.10, 3.11, 3.12, 3.13",Not applicable,``.py``
Ruby [9]_,"up to 3.3",Not applicable,"``.rb``, ``.erb``, ``.gemspec``, ``Gemfile``"
Swift [10]_,"Swift 5.4-5.10","Swift compiler","``.swift``"
TypeScript [11]_,"2.6-5.6",Standard TypeScript compiler,"``.ts``, ``.tsx``, ``.mts``, ``.cts``"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* The AST viewer now shows type parameter declarations in the correct place in the AST.
2 changes: 2 additions & 0 deletions go/ql/lib/semmle/go/AST.qll
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ class AstNode extends @node, Locatable {
kind = "commentgroup" and result = this.(File).getCommentGroup(i)
or
kind = "comment" and result = this.(CommentGroup).getComment(i)
or
kind = "typeparamdecl" and result = this.(TypeParamDeclParent).getTypeParameterDecl(i)
}

/**
Expand Down
5 changes: 1 addition & 4 deletions go/ql/lib/semmle/go/Decls.qll
Original file line number Diff line number Diff line change
Expand Up @@ -212,10 +212,7 @@ class MethodDecl extends FuncDecl {
*
* is `Rectangle`.
*/
NamedType getReceiverBaseType() {
result = this.getReceiverType() or
result = this.getReceiverType().(PointerType).getBaseType()
}
NamedType getReceiverBaseType() { result = lookThroughPointerType(this.getReceiverType()) }

/**
* Gets the receiver variable of this method.
Expand Down
8 changes: 1 addition & 7 deletions go/ql/lib/semmle/go/Scopes.qll
Original file line number Diff line number Diff line change
Expand Up @@ -519,13 +519,7 @@ class Method extends Function {
* Gets the receiver base type of this method, that is, either the base type of the receiver type
* if it is a pointer type, or the receiver type itself if it is not a pointer type.
*/
Type getReceiverBaseType() {
exists(Type recv | recv = this.getReceiverType() |
if recv instanceof PointerType
then result = recv.(PointerType).getBaseType()
else result = recv
)
}
Type getReceiverBaseType() { result = lookThroughPointerType(this.getReceiverType()) }

/** Holds if this method has name `m` and belongs to the method set of type `tp` or `*tp`. */
private predicate isIn(NamedType tp, string m) {
Expand Down
20 changes: 12 additions & 8 deletions go/ql/lib/semmle/go/Types.qll
Original file line number Diff line number Diff line change
Expand Up @@ -446,11 +446,7 @@ class StructType extends @structtype, CompositeType {
if n = ""
then (
isEmbedded = true and
(
name = tp.(NamedType).getName()
or
name = tp.(PointerType).getBaseType().(NamedType).getName()
)
name = lookThroughPointerType(tp).(NamedType).getName()
) else (
isEmbedded = false and
name = n
Expand Down Expand Up @@ -518,9 +514,7 @@ class StructType extends @structtype, CompositeType {
this.hasFieldCand(_, embeddedParent, depth - 1, true) and
result.getName() = name and
(
result.getReceiverBaseType() = embeddedParent.getType()
or
result.getReceiverBaseType() = embeddedParent.getType().(PointerType).getBaseType()
result.getReceiverBaseType() = lookThroughPointerType(embeddedParent.getType())
or
methodhosts(result, embeddedParent.getType())
)
Expand Down Expand Up @@ -644,6 +638,16 @@ class PointerType extends @pointertype, CompositeType {
override string toString() { result = "pointer type" }
}

/**
* Gets the base type if `t` is a pointer type, otherwise `t` itself.
*/
Type lookThroughPointerType(Type t) {
not t instanceof PointerType and
result = t
or
result = t.(PointerType).getBaseType()
}

private newtype TTypeSetTerm =
MkTypeSetTerm(TypeSetLiteralType tslit, int index) { component_types(tslit, index, _, _) }

Expand Down
6 changes: 1 addition & 5 deletions go/ql/lib/semmle/go/controlflow/IR.qll
Original file line number Diff line number Diff line change
Expand Up @@ -358,11 +358,7 @@ module IR {

override predicate reads(ValueEntity v) { v = field }

override Type getResultType() {
if field.getType() instanceof PointerType
then result = field.getType().(PointerType).getBaseType()
else result = field.getType()
}
override Type getResultType() { result = lookThroughPointerType(field.getType()) }

override ControlFlow::Root getRoot() { result.isRootOf(e) }

Expand Down
2 changes: 1 addition & 1 deletion go/ql/src/InconsistentCode/LengthComparisonOffByOne.ql
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ predicate isRegexpMethodCall(DataFlow::MethodCallNode c) {
exists(NamedType regexp, Type recvtp |
regexp.getName() = "Regexp" and recvtp = c.getReceiver().getType()
|
recvtp = regexp or recvtp.(PointerType).getBaseType() = regexp
lookThroughPointerType(recvtp) = regexp
)
}

Expand Down
Loading

0 comments on commit 85e59c9

Please sign in to comment.