Merge branch 'main' into aliasperf2

This commit is contained in:
Jeroen Ketema
2024-10-21 16:40:01 +02:00
committed by GitHub
543 changed files with 76384 additions and 55642 deletions

View File

@@ -1,3 +1,10 @@
## 2.0.2
### Minor Analysis Improvements
* Added taint flow model for `fopen` and related functions.
* The `SimpleRangeAnalysis` library (`semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis`) now generates more precise ranges for calls to `fgetc` and `getc`.
## 2.0.1
No user-facing changes.

View File

@@ -0,0 +1,4 @@
---
category: feature
---
* Added classes `RequiresExpr`, `SimpleRequirementExpr`, `TypeRequirementExpr`, `CompoundRequirementExpr`, and `NestedRequirementExpr` to represent C++20 requires expressions and the simple, type, compound, and nested requirements that can occur in `requires` expressions.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* The `SimpleRangeAnalysis` library (`semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis`) now generates more precise ranges for calls to `fgetc` and `getc`.

View File

@@ -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.

View File

@@ -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.

View File

@@ -0,0 +1,6 @@
## 2.0.2
### Minor Analysis Improvements
* Added taint flow model for `fopen` and related functions.
* The `SimpleRangeAnalysis` library (`semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis`) now generates more precise ranges for calls to `fgetc` and `getc`.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 2.0.1
lastReleaseVersion: 2.0.2

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-all
version: 2.0.2-dev
version: 2.0.3-dev
groups: cpp
dbscheme: semmlecode.cpp.dbscheme
extractor: cpp

View File

@@ -6,9 +6,156 @@ import semmle.code.cpp.exprs.Expr
/**
* A C++ requires expression.
*
* For example, with `T` and `U` template parameters:
* ```cpp
* requires (T x, U y) { x + y; };
* ```
*/
class RequiresExpr extends Expr, @requires_expr {
override string toString() { result = "requires ..." }
override string toString() {
if exists(this.getAParameter())
then result = "requires(...) { ... }"
else result = "requires { ... }"
}
override string getAPrimaryQlClass() { result = "RequiresExpr" }
/**
* Gets a requirement in this requires expression.
*/
RequirementExpr getARequirement() { result = this.getAChild() }
/**
* Gets the nth requirement in this requires expression.
*/
RequirementExpr getRequirement(int n) { result = this.getChild(n) }
/**
* Gets the number of requirements in this requires expression.
*/
int getNumberOfRequirements() { result = count(this.getARequirement()) }
/**
* Gets a parameter of this requires expression, if any.
*/
Parameter getAParameter() { result.getRequiresExpr() = underlyingElement(this) }
/**
* Gets the the nth parameter of this requires expression.
*/
Parameter getParameter(int n) {
result.getRequiresExpr() = underlyingElement(this) and result.getIndex() = n
}
/**
* Gets the number of parameters of this requires expression.
*/
int getNumberOfParameters() { result = count(this.getAParameter()) }
}
/**
* A C++ requirement in a requires expression.
*/
class RequirementExpr extends Expr { }
/**
* A C++ simple requirement in a requires expression.
*
* For example, if:
* ```cpp
* requires(T x, U y) { x + y; };
* ```
* with `T` and `U` template parameters, then `x + y;` is a simple requirement.
*/
class SimpleRequirementExpr extends RequirementExpr {
SimpleRequirementExpr() {
this.getParent() instanceof RequiresExpr and
not this instanceof TypeRequirementExpr and
not this instanceof CompoundRequirementExpr and
not this instanceof NestedRequirementExpr
}
override string getAPrimaryQlClass() { result = "SimpleRequirementExpr" }
}
/**
* A C++ type requirement in a requires expression.
*
* For example, if:
* ```cpp
* requires { typename T::a_field; };
* ```
* with `T` a template parameter, then `typename T::a_field;` is a type requirement.
*/
class TypeRequirementExpr extends RequirementExpr, TypeName {
TypeRequirementExpr() { this.getParent() instanceof RequiresExpr }
override string getAPrimaryQlClass() { result = "TypeRequirementExpr" }
}
/**
* A C++ compound requirement in a requires expression.
*
* For example, if:
* ```cpp
* requires(T x) { { x } noexcept -> std::same_as<int>; };
* ```
* with `T` a template parameter, then `{ x } noexcept -> std::same_as<int>;` is
* a compound requirement.
*/
class CompoundRequirementExpr extends RequirementExpr, @compound_requirement {
override string toString() {
if exists(this.getReturnTypeRequirement())
then result = "{ ... } -> ..."
else result = "{ ... }"
}
override string getAPrimaryQlClass() { result = "CompoundRequirementExpr" }
/**
* Gets the expression from the compound requirement.
*/
Expr getExpr() { result = this.getChild(0) }
/**
* Gets the return type requirement from the compound requirement, if any.
*/
Expr getReturnTypeRequirement() { result = this.getChild(1) }
/**
* Holds if the expression from the compound requirement must not be
* potentially throwing.
*/
predicate isNoExcept() { compound_requirement_is_noexcept(underlyingElement(this)) }
}
/**
* A C++ nested requirement in a requires expression.
*
* For example, if:
* ```cpp
* requires { requires std::is_same<T, int>::value; };
* ```
* with `T` a template parameter, then `requires std::is_same<T, int>::value;` is
* a nested requirement.
*/
class NestedRequirementExpr extends Expr, @nested_requirement {
override string toString() { result = "requires ..." }
override string getAPrimaryQlClass() { result = "NestedRequirementExpr" }
/**
* Gets the constraint from the nested requirement.
*/
Expr getConstraint() { result = this.getChild(0) }
}
/**
* A C++ concept id expression.
*/
class ConceptIdExpr extends RequirementExpr, @concept_id {
override string toString() { result = "concept<...>" }
override string getAPrimaryQlClass() { result = "ConceptIdExpr" }
}

View File

@@ -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
@@ -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))

View File

@@ -7,8 +7,8 @@ import semmle.code.cpp.Declaration
private import semmle.code.cpp.internal.ResolveClass
/**
* A C/C++ function parameter or catch block parameter. For example the
* function parameter `p` and the catch block parameter `e` in the following
* A C/C++ function parameter, catch block parameter, or requires expression parameter.
* For example the function parameter `p` and the catch block parameter `e` in the following
* code:
* ```
* void myFunction(int p) {
@@ -20,8 +20,8 @@ private import semmle.code.cpp.internal.ResolveClass
* }
* ```
*
* For catch block parameters, there is a one-to-one correspondence between
* the `Parameter` and its `ParameterDeclarationEntry`.
* For catch block parameters and expression , there is a one-to-one
* correspondence between the `Parameter` and its `VariableDeclarationEntry`.
*
* For function parameters, there is a one-to-many relationship between
* `Parameter` and `ParameterDeclarationEntry`, because one function can
@@ -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 != "")
}
/**
@@ -118,6 +119,12 @@ class Parameter extends LocalScopeVariable, @parameter {
*/
BlockStmt getCatchBlock() { params(underlyingElement(this), unresolveElement(result), _, _) }
/**
* Gets the requires expression to which the parameter belongs, if it is a
* requires expression parameter.
*/
RequiresExpr getRequiresExpr() { params(underlyingElement(this), unresolveElement(result), _, _) }
/**
* Gets the zero-based index of this parameter.
*

View File

@@ -80,6 +80,10 @@ private Declaration getAnEnclosingDeclaration(Locatable ast) {
or
result = ast.(Parameter).getFunction()
or
result = ast.(Parameter).getCatchBlock().getEnclosingFunction()
or
result = ast.(Parameter).getRequiresExpr().getEnclosingFunction()
or
result = ast.(Expr).getEnclosingDeclaration()
or
result = ast.(Initializer).getDeclaration()
@@ -99,7 +103,10 @@ private newtype TPrintAstNode =
stmt.getADeclarationEntry() = entry and
shouldPrintDeclaration(stmt.getEnclosingFunction())
} or
TParametersNode(Function func) { shouldPrintDeclaration(func) } or
TFunctionParametersNode(Function func) { shouldPrintDeclaration(func) } or
TRequiresExprParametersNode(RequiresExpr req) {
shouldPrintDeclaration(getAnEnclosingDeclaration(req))
} or
TConstructorInitializersNode(Constructor ctor) {
ctor.hasEntryPoint() and
shouldPrintDeclaration(ctor)
@@ -303,14 +310,14 @@ class ExprNode extends AstNode {
ExprNode() { expr = ast }
override AstNode getChildInternal(int childIndex) {
result.getAst() = expr.getChild(childIndex)
override PrintAstNode getChildInternal(int childIndex) {
result.(AstNode).getAst() = expr.getChild(childIndex)
or
childIndex = max(int index | exists(expr.getChild(index)) or index = 0) + 1 and
result.getAst() = expr.(ConditionDeclExpr).getInitializingExpr()
result.(AstNode).getAst() = expr.(ConditionDeclExpr).getInitializingExpr()
or
exists(int destructorIndex |
result.getAst() = expr.getImplicitDestructorCall(destructorIndex) and
result.(AstNode).getAst() = expr.getImplicitDestructorCall(destructorIndex) and
childIndex = destructorIndex + max(int index | exists(expr.getChild(index)) or index = 0) + 2
)
}
@@ -329,7 +336,8 @@ class ExprNode extends AstNode {
}
override string getChildAccessorPredicateInternal(int childIndex) {
result = getChildAccessorWithoutConversions(ast, this.getChildInternal(childIndex).getAst())
result =
getChildAccessorWithoutConversions(ast, this.getChildInternal(childIndex).(AstNode).getAst())
}
/**
@@ -409,6 +417,26 @@ class StmtExprNode extends ExprNode {
}
}
/**
* A node representing a `RequiresExpr`
*/
class RequiresExprNode extends ExprNode {
override RequiresExpr expr;
override PrintAstNode getChildInternal(int childIndex) {
result = super.getChildInternal(childIndex)
or
childIndex = -1 and
result.(RequiresExprParametersNode).getRequiresExpr() = expr
}
override string getChildAccessorPredicateInternal(int childIndex) {
result = super.getChildAccessorPredicateInternal(childIndex)
or
childIndex = -1 and result = "<params>"
}
}
/**
* A node representing a `DeclarationEntry`.
*/
@@ -510,6 +538,22 @@ class DeclStmtNode extends StmtNode {
}
}
/**
* A node representing a `Handler`.
*/
class HandlerNode extends ChildStmtNode {
Handler handler;
HandlerNode() { handler = stmt }
override BaseAstNode getChildInternal(int childIndex) {
result = super.getChildInternal(childIndex)
or
childIndex = -1 and
result.getAst() = handler.getParameter()
}
}
/**
* A node representing a `Parameter`.
*/
@@ -552,10 +596,10 @@ class InitializerNode extends AstNode {
/**
* A node representing the parameters of a `Function`.
*/
class ParametersNode extends PrintAstNode, TParametersNode {
class FunctionParametersNode extends PrintAstNode, TFunctionParametersNode {
Function func;
ParametersNode() { this = TParametersNode(func) }
FunctionParametersNode() { this = TFunctionParametersNode(func) }
final override string toString() { result = "" }
@@ -576,6 +620,33 @@ class ParametersNode extends PrintAstNode, TParametersNode {
final Function getFunction() { result = func }
}
/**
* A node representing the parameters of a `RequiresExpr`.
*/
class RequiresExprParametersNode extends PrintAstNode, TRequiresExprParametersNode {
RequiresExpr req;
RequiresExprParametersNode() { this = TRequiresExprParametersNode(req) }
final override string toString() { result = "" }
final override Location getLocation() { result = getRepresentativeLocation(req) }
override AstNode getChildInternal(int childIndex) {
result.getAst() = req.getParameter(childIndex)
}
override string getChildAccessorPredicateInternal(int childIndex) {
exists(this.getChildInternal(childIndex)) and
result = "getParameter(" + childIndex.toString() + ")"
}
/**
* Gets the `RequiresExpr` for which this node represents the parameters.
*/
final RequiresExpr getRequiresExpr() { result = req }
}
/**
* A node representing the initializer list of a `Constructor`.
*/
@@ -679,7 +750,7 @@ class FunctionNode extends FunctionOrGlobalOrNamespaceVariableNode {
override PrintAstNode getChildInternal(int childIndex) {
childIndex = 0 and
result.(ParametersNode).getFunction() = func
result.(FunctionParametersNode).getFunction() = func
or
childIndex = 1 and
result.(ConstructorInitializersNode).getConstructor() = func
@@ -754,6 +825,8 @@ private predicate namedStmtChildPredicates(Locatable s, Element e, string pred)
or
s.(ConstexprIfStmt).getElse() = e and pred = "getElse()"
or
s.(Handler).getParameter() = e and pred = "getParameter()"
or
s.(IfStmt).getInitialization() = e and pred = "getInitialization()"
or
s.(IfStmt).getCondition() = e and pred = "getCondition()"
@@ -901,6 +974,11 @@ private predicate namedExprChildPredicates(Expr expr, Element ele, string pred)
or
expr.(CommaExpr).getRightOperand() = ele and pred = "getRightOperand()"
or
expr.(CompoundRequirementExpr).getExpr() = ele and pred = "getExpr()"
or
expr.(CompoundRequirementExpr).getReturnTypeRequirement() = ele and
pred = "getReturnTypeRequirement()"
or
expr.(ConditionDeclExpr).getVariableAccess() = ele and pred = "getVariableAccess()"
or
expr.(ConstructorFieldInit).getExpr() = ele and pred = "getExpr()"
@@ -921,6 +999,8 @@ private predicate namedExprChildPredicates(Expr expr, Element ele, string pred)
or
expr.(LambdaExpression).getInitializer() = ele and pred = "getInitializer()"
or
expr.(NestedRequirementExpr).getConstraint() = ele and pred = "getConstraint()"
or
expr.(NewOrNewArrayExpr).getAllocatorCall() = ele and pred = "getAllocatorCall()"
or
expr.(NewOrNewArrayExpr).getAlignmentArgument() = ele and pred = "getAlignmentArgument()"
@@ -960,6 +1040,11 @@ private predicate namedExprChildPredicates(Expr expr, Element ele, string pred)
or
expr.(UnaryOperation).getOperand() = ele and pred = "getOperand()"
or
exists(int n |
expr.(RequiresExpr).getRequirement(n) = ele and
pred = "getRequirement(" + n + ")"
)
or
expr.(SizeofExprOperator).getExprOperand() = ele and pred = "getExprOperand()"
or
expr.(StmtExpr).getStmt() = ele and pred = "getStmt()"

View File

@@ -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()
)
)
}
@@ -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
)
}

View File

@@ -181,12 +181,7 @@ class VariableDeclarationEntry extends @var_decl {
string getName() { var_decls(this, _, _, result, _) and result != "" }
}
class Parameter extends LocalScopeVariable, @parameter {
@functionorblock function;
int index;
Parameter() { params(this, function, index, _) }
}
class Parameter extends LocalScopeVariable, @parameter { }
class GlobalOrNamespaceVariable extends Variable, @globalvariable { }

View File

@@ -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)
}

View File

@@ -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
/**
@@ -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()
)
}

View File

@@ -7,7 +7,7 @@ import semmle.code.cpp.models.interfaces.Alias
import semmle.code.cpp.models.interfaces.SideEffect
/** The function `fopen` and friends. */
private class Fopen extends Function, AliasFunction, SideEffectFunction {
private class Fopen extends Function, AliasFunction, SideEffectFunction, TaintFunction {
Fopen() {
this.hasGlobalOrStdName(["fopen", "fopen_s", "freopen"])
or
@@ -47,4 +47,22 @@ private class Fopen extends Function, AliasFunction, SideEffectFunction {
i = 0 and
buffer = true
}
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
(
this.hasGlobalOrStdName(["fopen", "freopen"]) or
this.hasGlobalName(["_wfopen", "_fsopen", "_wfsopen"])
) and
input.isParameterDeref(0) and
output.isReturnValueDeref()
or
// The out parameter is a pointer to a `FILE*`.
this.hasGlobalOrStdName("fopen_s") and
input.isParameterDeref(1) and
output.isParameterDeref(0, 2)
or
this.hasGlobalName(["_open", "_wopen"]) and
input.isParameterDeref(0) and
output.isReturnValue()
}
}

View File

@@ -534,7 +534,7 @@ static_asserts(
#keyset[function, index, type_id]
params(
int id: @parameter,
int function: @functionorblock ref,
int function: @parameterized_element ref,
int index: int ref,
int type_id: @type ref
);
@@ -1791,6 +1791,9 @@ case @expr.kind of
| 388 = @datasizeof
| 389 = @c11_generic
| 390 = @requires_expr
| 391 = @nested_requirement
| 392 = @compound_requirement
| 393 = @concept_id
;
@var_args_expr = @vastartexpr
@@ -1909,6 +1912,10 @@ case @expr.kind of
| @istriviallyrelocatable
;
compound_requirement_is_noexcept(
int expr: @compound_requirement ref
);
new_allocated_type(
unique int expr: @new_expr ref,
int type_id: @type ref
@@ -2168,11 +2175,11 @@ stmt_decl_entry_bind(
int decl_entry: @element ref
);
@functionorblock = @function | @stmt_block;
@parameterized_element = @function | @stmt_block | @requires_expr;
blockscope(
unique int block: @stmt_block ref,
int enclosing: @functionorblock ref
int enclosing: @parameterized_element ref
);
@jump = @stmt_goto | @stmt_break | @stmt_continue;

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
description: Support C++20 requires expressions
compatibility: backwards