Merge pull request #1406 from taus-semmle/mergeback-rc/1.21

Merge `rc/1.21` into `master`
This commit is contained in:
Max Schaefer
2019-06-05 16:33:50 +01:00
committed by GitHub
55 changed files with 4179 additions and 71 deletions

View File

@@ -13,6 +13,10 @@
* The following C# 8 features are now extracted:
- Range expressions
- Recursive patterns
- Using declaration statements
- `static` modifiers on local functions
- Null-coalescing assignment expressions
* The `unmanaged` type parameter constraint is now extracted.
## Changes to QL libraries
@@ -20,6 +24,7 @@
* The class `Attribute` has two new predicates: `getConstructorArgument()` and `getNamedArgument()`. The first predicate returns arguments to the underlying constructor call and the latter returns named arguments for initializing fields and properties.
* The class `TypeParameterConstraints` has a new predicate `hasUnmanagedTypeConstraint()`, indicating that the type parameter has the `unmanaged` constraint.
* The following QL classes have been added to model C# 8 features:
- Class `AssignCoalesceExpr` models null-coalescing assignment, for example `x ??= y`
- Class `IndexExpr` models from-end index expressions, for example `^1`
- Class `PatternExpr` is an `Expr` that appears in a pattern. It has the new subclasses `DiscardPatternExpr`, `LabeledPatternExpr`, `RecursivePatternExpr`, `TypeAccessPatternExpr`, `TypePatternExpr`, and `VariablePatternExpr`.
- Class `PatternMatch` models a pattern being matched. It has the subclasses `Case` and `IsExpr`.
@@ -31,5 +36,6 @@
- Classes `IsConstantExpr`, `IsTypeExpr` and `IsPatternExpr` are deprecated in favour of `IsExpr`
- Class `Switch` models both `SwitchExpr` and `SwitchStmt`
- Class `Case` models both `CaseStmt` and `SwitchCaseExpr`
- Class `UsingStmt` models both `UsingBlockStmt` and `UsingDeclStmt`
## Changes to autobuilder

View File

@@ -40,7 +40,7 @@
| Expression has no effect | Fewer false-positive results | This rule now treats uses of `Object.defineProperty` more conservatively. |
| Incomplete regular expression for hostnames | More results | This rule now tracks regular expressions for host names further. |
| Incomplete string escaping or encoding | More results | This rule now considers the flow of regular expressions literals, and it no longer flags the removal of trailing newlines. |
| Password in configuration file | Fewer false positive results | This query now excludes passwords that are inserted into the configuration file using a templating mechanism or read from environment variables. |
| Password in configuration file | Fewer false positive results | This query now excludes passwords that are inserted into the configuration file using a templating mechanism or read from environment variables. Results are no longer shown on LGTM by default. |
| Replacement of a substring with itself | More results | This rule now considers the flow of regular expressions literals. |
| Server-side URL redirect | Fewer false-positive results | This rule now treats URLs as safe in more cases where the hostname cannot be tampered with. |
| Type confusion through parameter tampering | Fewer false-positive results | This rule now recognizes additional emptiness checks. |

View File

@@ -71,6 +71,8 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
return ExprKind.ASSIGN_LSHIFT;
case SyntaxKind.GreaterThanGreaterThanEqualsToken:
return ExprKind.ASSIGN_RSHIFT;
case SyntaxKind.QuestionQuestionEqualsToken:
return ExprKind.ASSIGN_COALESCE;
default:
cx.ModelError(syntax, "Unrecognised assignment type " + GetKind(cx, syntax));
return ExprKind.UNKNOWN;
@@ -142,6 +144,8 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
return ExprKind.SUB;
case ExprKind.ASSIGN_XOR:
return ExprKind.BIT_XOR;
case ExprKind.ASSIGN_COALESCE:
return ExprKind.NULL_COALESCING;
default:
cx.ModelError(Syntax, "Couldn't unfold assignment of type " + kind);
return ExprKind.UNKNOWN;

View File

@@ -80,6 +80,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
case SyntaxKind.RightShiftAssignmentExpression:
case SyntaxKind.DivideAssignmentExpression:
case SyntaxKind.ModuloAssignmentExpression:
case SyntaxKind.CoalesceAssignmentExpression:
return Assignment.Create(info);
case SyntaxKind.ObjectCreationExpression:

View File

@@ -1,4 +1,6 @@
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System.Linq;
namespace Semmle.Extraction.CSharp.Entities
{
@@ -39,6 +41,18 @@ namespace Semmle.Extraction.CSharp.Entities
public override void Populate()
{
PopulateMethod();
// There is a "bug" in Roslyn whereby the IMethodSymbol associated with the local function symbol
// is always static, so we need to go to the syntax reference of the local function to see whether
// the "static" modifier is present.
if (symbol.DeclaringSyntaxReferences.SingleOrDefault().GetSyntax() is LocalFunctionStatementSyntax fn)
{
foreach(var modifier in fn.Modifiers)
{
Modifier.HasModifier(Context, this, modifier.Text);
}
}
var originalDefinition = IsSourceDeclaration ? this : Create(Context, symbol.OriginalDefinition);
var returnType = Type.Create(Context, symbol.ReturnType);
Context.Emit(Tuples.local_functions(this, symbol.Name, returnType, originalDefinition));

View File

@@ -6,8 +6,19 @@ namespace Semmle.Extraction.CSharp.Entities.Statements
{
class LocalDeclaration : Statement<LocalDeclarationStatementSyntax>
{
static StmtKind GetKind(LocalDeclarationStatementSyntax declStmt)
{
if (declStmt.UsingKeyword.RawKind != 0)
return StmtKind.USING_DECL;
if (declStmt.IsConst)
return StmtKind.CONST_DECL;
return StmtKind.VAR_DECL;
}
LocalDeclaration(Context cx, LocalDeclarationStatementSyntax declStmt, IStatementParentEntity parent, int child)
: base(cx, declStmt, declStmt.IsConst ? StmtKind.CONST_DECL : StmtKind.VAR_DECL, parent, child) { }
: base(cx, declStmt, GetKind(declStmt), parent, child) { }
public static LocalDeclaration Create(Context cx, LocalDeclarationStatementSyntax node, IStatementParentEntity parent, int child)
{

View File

@@ -112,6 +112,7 @@ namespace Semmle.Extraction.Kinds
RECURSIVE_PATTERN = 115,
PROPERTY_PATTERN = 116,
POSITIONAL_PATTERN = 117,
SWITCH_CASE = 118
SWITCH_CASE = 118,
ASSIGN_COALESCE = 119
}
}

View File

@@ -34,6 +34,7 @@ namespace Semmle.Extraction.Kinds // lgtm[cs/similar-file]
LABEL = 27,
CATCH = 28,
CASE = 29,
LOCAL_FUNCTION = 30
LOCAL_FUNCTION = 30,
USING_DECL = 31
}
}

View File

@@ -903,7 +903,7 @@ class ExplicitConversionOperator extends ConversionOperator {
* }
* ```
*/
class LocalFunction extends Callable, @local_function {
class LocalFunction extends Callable, Modifiable, @local_function {
override string getName() { local_functions(this, result, _, _) }
override LocalFunction getSourceDeclaration() { local_functions(this, _, _, result) }

View File

@@ -1115,40 +1115,16 @@ class LockStmt extends Stmt, @lock_stmt {
}
/**
* A `using` statement, for example
*
* ```
* using (FileStream f = File.Open("settings.xml")) {
* ...
* }
* ```
* A using block or declaration. Either a using declaration (`UsingDeclStmt`) or
* a using block (`UsingBlockStmt`).
*/
class UsingStmt extends Stmt, @using_stmt {
/** Gets the `i`th local variable of this `using` statement. */
LocalVariable getVariable(int i) { result = this.getVariableDeclExpr(i).getVariable() }
/** Gets a local variable of this `using` statement. */
LocalVariable getAVariable() { result = this.getVariable(_) }
/** Gets the `i`th local variable declaration of this `using` statement. */
LocalVariableDeclExpr getVariableDeclExpr(int i) { result = this.getChild(-i - 1) }
LocalVariableDeclExpr getVariableDeclExpr(int i) { none() }
/** Gets a local variable declaration of this `using` statement. */
LocalVariableDeclExpr getAVariableDeclExpr() { result = this.getVariableDeclExpr(_) }
/**
* Gets the expression directly used by this `using` statement, if any. For
* example, `f` on line 2 in
*
* ```
* var f = File.Open("settings.xml");
* using (f) {
* ...
* }
* ```
*/
Expr getExpr() { result = this.getChild(0) }
/**
* Gets an expression that is used in this `using` statement. Either an
* expression assigned to a variable, for example `File.Open("settings.xml")`
@@ -1169,14 +1145,69 @@ class UsingStmt extends Stmt, @using_stmt {
* }
* ```
*/
Expr getAnExpr() {
Expr getAnExpr() { none() }
/**
* DEPRECATED: Use UsingBlockStmt.getExpr() instead.
* Gets the expression directly used by this `using` statement, if any. For
* example, `f` on line 2 in
*
* ```
* var f = File.Open("settings.xml");
* using (f) {
* ...
* }
* ```
*/
deprecated Expr getExpr() { none() }
/**
* DEPRECATED: Use UsingBlockStmt.getBody() instead.
* Gets the body of this `using` statement.
*/
deprecated Stmt getBody() { none() }
}
/**
* A `using` block statement, for example
*
* ```
* using (FileStream f = File.Open("settings.xml")) {
* ...
* }
* ```
*/
class UsingBlockStmt extends UsingStmt, @using_block_stmt {
/** Gets the `i`th local variable of this `using` statement. */
LocalVariable getVariable(int i) { result = this.getVariableDeclExpr(i).getVariable() }
/** Gets a local variable of this `using` statement. */
LocalVariable getAVariable() { result = this.getVariable(_) }
/** Gets the `i`th local variable declaration of this `using` statement. */
override LocalVariableDeclExpr getVariableDeclExpr(int i) { result = this.getChild(-i - 1) }
/**
* Gets the expression directly used by this `using` statement, if any. For
* example, `f` on line 2 in
*
* ```
* var f = File.Open("settings.xml");
* using (f) {
* ...
* }
* ```
*/
override Expr getExpr() { result = this.getChild(0) }
override Expr getAnExpr() {
result = this.getAVariableDeclExpr().getInitializer()
or
result = this.getExpr()
}
/** Gets the body of this `using` statement. */
Stmt getBody() { result.getParent() = this }
override Stmt getBody() { result.getParent() = this }
override string toString() { result = "using (...) {...}" }
}
@@ -1254,6 +1285,29 @@ class LocalConstantDeclStmt extends LocalVariableDeclStmt, @const_decl_stmt {
override string toString() { result = "const ... ...;" }
}
/**
* A `using` declaration statement, for example
*
* ```
* using FileStream f = File.Open("settings.xml");
* ```
*/
class UsingDeclStmt extends LocalVariableDeclStmt, UsingStmt, @using_decl_stmt {
override string toString() { result = "using ... ...;" }
override LocalVariableDeclExpr getAVariableDeclExpr() {
result = LocalVariableDeclStmt.super.getAVariableDeclExpr()
}
override LocalVariableDeclExpr getVariableDeclExpr(int n) {
result = LocalVariableDeclStmt.super.getVariableDeclExpr(n)
}
override Expr getAnExpr() {
result = this.getAVariableDeclExpr().getInitializer()
}
}
/**
* An empty statement, for example line 2 in
*

View File

@@ -468,7 +468,7 @@ module ControlFlow {
override ControlFlowElement getChildElement(int i) {
not this instanceof GeneralCatchClause and
not this instanceof FixedStmt and
not this instanceof UsingStmt and
not this instanceof UsingBlockStmt and
result = this.getChild(i)
or
this = any(GeneralCatchClause gcc | i = 0 and result = gcc.getBlock())
@@ -480,7 +480,7 @@ module ControlFlow {
i = max(int j | exists(fs.getVariableDeclExpr(j))) + 1
)
or
this = any(UsingStmt us |
this = any(UsingBlockStmt us |
if exists(us.getExpr())
then (
result = us.getExpr() and

View File

@@ -230,3 +230,10 @@ class AddEventExpr extends AddOrRemoveEventExpr, @add_event_expr {
class RemoveEventExpr extends AddOrRemoveEventExpr, @remove_event_expr {
override string toString() { result = "... -= ..." }
}
/**
* A null-coalescing assignment operation, for example `x ??= y`.
*/
class AssignCoalesceExpr extends AssignOperation, @assign_coalesce_expr {
override string toString() { result = "... ??= ..." }
}

View File

@@ -526,7 +526,7 @@ specific_type_parameter_constraints(
@modifiable = @modifiable_direct | @event_accessor;
@modifiable_direct = @member | @accessor;
@modifiable_direct = @member | @accessor | @local_function;
modifiers(
unique int id: @modifier,
@@ -798,7 +798,7 @@ case @stmt.kind of
| 18 = @checked_stmt
| 19 = @unchecked_stmt
| 20 = @lock_stmt
| 21 = @using_stmt
| 21 = @using_block_stmt
| 22 = @var_decl_stmt
| 23 = @const_decl_stmt
| 24 = @empty_stmt
@@ -808,11 +808,14 @@ case @stmt.kind of
| 28 = @catch
| 29 = @case_stmt
| 30 = @local_function_stmt
| 31 = @using_decl_stmt
;
@using_stmt = @using_block_stmt | @using_decl_stmt;
@labeled_stmt = @label_stmt | @case;
@decl_stmt = @var_decl_stmt | @const_decl_stmt;
@decl_stmt = @var_decl_stmt | @const_decl_stmt | @using_decl_stmt;
@cond_stmt = @if_stmt | @switch_stmt;
@@ -983,6 +986,7 @@ case @expr.kind of
| 116 = @property_pattern_expr
| 117 = @positional_pattern_expr
| 118 = @switch_case_expr
| 119 = @assign_coalesce_expr
;
@switch = @switch_stmt | @switch_expr;
@@ -995,7 +999,7 @@ case @expr.kind of
| @string_literal_expr | @null_literal_expr;
@assign_expr = @simple_assign_expr | @assign_op_expr | @local_var_decl_expr;
@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr | @assign_event_expr;
@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr | @assign_event_expr | @assign_coalesce_expr;
@assign_event_expr = @add_event_expr | @remove_event_expr;
@assign_arith_expr = @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr

View File

@@ -360,10 +360,14 @@
<v>1854</v>
</e>
<e>
<k>@using_stmt</k>
<k>@using_block_stmt</k>
<v>5815</v>
</e>
<e>
<k>@using_decl_stmt</k>
<v>1000</v>
</e>
<e>
<k>@var_decl_stmt</k>
<v>243866</v>
</e>
@@ -688,6 +692,10 @@
<v>116</v>
</e>
<e>
<k>@assign_coalesce_expr</k>
<v>116</v>
</e>
<e>
<k>@object_init_expr</k>
<v>5320</v>
</e>

View File

@@ -104,6 +104,7 @@
| Assignables.cs:133:15:133:15 | access to local variable x | Assignables.cs:132:13:132:13 | x | read |
| Assignables.cs:133:15:133:15 | access to local variable x | Assignables.cs:132:13:132:13 | x | write |
| Assignables.cs:133:29:133:29 | String s | Assignables.cs:133:29:133:29 | s | write |
| Assignables.cs:138:19:138:19 | access to local variable x | Assignables.cs:138:19:138:19 | x | write |
| Discards.cs:7:9:7:9 | access to parameter x | Discards.cs:5:30:5:30 | x | write |
| Discards.cs:20:32:20:32 | Boolean z | Discards.cs:20:32:20:32 | z | write |
| Discards.cs:25:27:25:30 | access to parameter args | Discards.cs:23:27:23:30 | args | read |

View File

@@ -87,6 +87,7 @@
| Assignables.cs:132:13:132:13 | x | Assignables.cs:132:13:132:17 | Int32 x = ... | Assignables.cs:132:13:132:13 | access to local variable x | Assignables.cs:132:17:132:17 | 0 | certain |
| Assignables.cs:132:13:132:13 | x | Assignables.cs:133:15:133:15 | access to local variable x | Assignables.cs:133:15:133:15 | access to local variable x | Assignables.cs:133:15:133:15 | <none> | certain |
| Assignables.cs:133:29:133:29 | s | Assignables.cs:133:29:133:29 | String s | Assignables.cs:133:29:133:29 | String s | Assignables.cs:133:29:133:29 | <none> | certain |
| Assignables.cs:138:19:138:19 | x | Assignables.cs:138:19:138:50 | MemoryStream x = ... | Assignables.cs:138:19:138:19 | access to local variable x | Assignables.cs:138:23:138:50 | object creation of type MemoryStream | certain |
| Discards.cs:5:30:5:30 | x | Discards.cs:5:30:5:30 | x | Discards.cs:5:30:5:30 | <none> | Discards.cs:5:30:5:30 | <none> | certain |
| Discards.cs:5:30:5:30 | x | Discards.cs:7:9:7:17 | ... = ... | Discards.cs:7:9:7:9 | access to parameter x | Discards.cs:7:13:7:17 | false | certain |
| Discards.cs:19:14:19:14 | x | Discards.cs:19:9:19:29 | ... = ... | Discards.cs:19:9:19:29 | <none> | Discards.cs:19:9:19:29 | <none> | certain |

View File

@@ -86,6 +86,7 @@
| Assignables.cs:132:13:132:17 | Int32 x = ... | Assignables.cs:132:13:132:17 | Int32 x = ... |
| Assignables.cs:133:15:133:15 | access to local variable x | Assignables.cs:133:9:133:30 | delegate call |
| Assignables.cs:133:29:133:29 | String s | Assignables.cs:133:9:133:30 | delegate call |
| Assignables.cs:138:19:138:50 | MemoryStream x = ... | Assignables.cs:138:19:138:50 | MemoryStream x = ... |
| Discards.cs:5:30:5:30 | x | Discards.cs:5:19:5:19 | enter f |
| Discards.cs:7:9:7:17 | ... = ... | Discards.cs:7:9:7:17 | ... = ... |
| Discards.cs:13:9:13:20 | ... = ... | Discards.cs:13:9:13:20 | ... = ... |

View File

@@ -132,4 +132,11 @@ class Assignables
var x = 0;
d(ref x, out string s);
}
void UsingDeclarations()
{
using var x = new System.IO.MemoryStream();
}
}
// semmle-extractor-options: /langversion:8.0

View File

@@ -95,6 +95,7 @@
| Assignables.cs:130:31:130:31 | d |
| Assignables.cs:132:13:132:13 | x |
| Assignables.cs:133:29:133:29 | s |
| Assignables.cs:138:19:138:19 | x |
| Discards.cs:5:6:5:8 | Item1 |
| Discards.cs:5:11:5:16 | Item2 |
| Discards.cs:5:30:5:30 | x |

View File

@@ -37,6 +37,7 @@
| Assignables.cs:125:13:125:13 | s | Assignables.cs:125:17:125:25 | nameof(...) |
| Assignables.cs:125:13:125:13 | s | Assignables.cs:126:13:126:30 | nameof(...) |
| Assignables.cs:132:13:132:13 | x | Assignables.cs:132:17:132:17 | 0 |
| Assignables.cs:138:19:138:19 | x | Assignables.cs:138:23:138:50 | object creation of type MemoryStream |
| Discards.cs:5:30:5:30 | x | Discards.cs:7:13:7:17 | false |
| Finally.cs:7:13:7:13 | i | Finally.cs:7:17:7:17 | 0 |
| Finally.cs:7:13:7:13 | i | Finally.cs:15:17:15:17 | 1 |

View File

@@ -0,0 +1,10 @@
using System;
class NullCoalescingAssignment
{
void NullCoalescing()
{
object o = null;
o ??= this;
}
}

View File

@@ -0,0 +1,4 @@
nullcoalescing
| NullCoalescingAssignment.cs:8:9:8:18 | ... ?? ... |
assignments
| NullCoalescingAssignment.cs:8:9:8:18 | ... ??= ... | NullCoalescingAssignment.cs:8:9:8:18 | ... = ... |

View File

@@ -0,0 +1,7 @@
import csharp
query predicate nullcoalescing(NullCoalescingExpr expr) { any() }
query predicate assignments(AssignCoalesceExpr expr, Expr expanded) {
expanded = expr.getExpandedAssignment()
}

View File

@@ -0,0 +1,11 @@
| NullCoalescingAssignment.cs:5:10:5:23 | enter NullCoalescing | NullCoalescingAssignment.cs:6:5:9:5 | {...} | semmle.label | successor |
| NullCoalescingAssignment.cs:6:5:9:5 | {...} | NullCoalescingAssignment.cs:7:9:7:24 | ... ...; | semmle.label | successor |
| NullCoalescingAssignment.cs:7:9:7:24 | ... ...; | NullCoalescingAssignment.cs:7:20:7:23 | null | semmle.label | successor |
| NullCoalescingAssignment.cs:7:16:7:23 | Object o = ... | NullCoalescingAssignment.cs:8:9:8:19 | ...; | semmle.label | successor |
| NullCoalescingAssignment.cs:7:20:7:23 | null | NullCoalescingAssignment.cs:7:16:7:23 | Object o = ... | semmle.label | successor |
| NullCoalescingAssignment.cs:8:9:8:9 | access to local variable o | NullCoalescingAssignment.cs:8:9:8:18 | ... = ... | semmle.label | non-null |
| NullCoalescingAssignment.cs:8:9:8:9 | access to local variable o | NullCoalescingAssignment.cs:8:15:8:18 | this access | semmle.label | null |
| NullCoalescingAssignment.cs:8:9:8:18 | ... = ... | NullCoalescingAssignment.cs:5:10:5:23 | exit NullCoalescing | semmle.label | successor |
| NullCoalescingAssignment.cs:8:9:8:18 | ... ?? ... | NullCoalescingAssignment.cs:8:9:8:9 | access to local variable o | semmle.label | successor |
| NullCoalescingAssignment.cs:8:9:8:19 | ...; | NullCoalescingAssignment.cs:8:9:8:18 | ... ?? ... | semmle.label | successor |
| NullCoalescingAssignment.cs:8:15:8:18 | this access | NullCoalescingAssignment.cs:8:9:8:18 | ... = ... | semmle.label | successor |

View File

@@ -0,0 +1,10 @@
import csharp
import semmle.code.csharp.controlflow.ControlFlowGraph
query predicate edges(ControlFlow::Node node1, ControlFlow::Node node2, string label, string value) {
label = "semmle.label" and
exists(ControlFlow::SuccessorType t |
node2 = node1.getASuccessorByType(t) and value = t.toString()
)
and node1.getEnclosingCallable().hasName("NullCoalescing")
}

View File

@@ -1,10 +0,0 @@
using System;
class StaticLocalFunction
{
int F()
{
static int G(int x) => x;
return G(12);
}
}

View File

@@ -0,0 +1,13 @@
// semmle-extractor-options: /langversion:8.0
using System;
class StaticLocalFunctions
{
int Fn(int x)
{
static int I(int y) => y;
int J(int y) => x+y;
return I(x) + J(x);
}
}

View File

@@ -0,0 +1 @@
| StaticLocalFunctions.cs:9:9:9:33 | I | static |

View File

@@ -0,0 +1,5 @@
import csharp
from LocalFunction fn, string modifier
where fn.hasModifier(modifier)
select fn, modifier

View File

@@ -0,0 +1,26 @@
| UsingDeclarations.cs:6:10:6:30 | enter TestUsingDeclarations | UsingDeclarations.cs:7:5:16:5 | {...} | semmle.label | successor |
| UsingDeclarations.cs:7:5:16:5 | {...} | UsingDeclarations.cs:8:9:8:116 | using ... ...; | semmle.label | successor |
| UsingDeclarations.cs:8:9:8:116 | using ... ...; | UsingDeclarations.cs:8:49:8:53 | "..." | semmle.label | successor |
| UsingDeclarations.cs:8:26:8:69 | FileStream file1 = ... | UsingDeclarations.cs:8:95:8:99 | "..." | semmle.label | successor |
| UsingDeclarations.cs:8:34:8:69 | object creation of type FileStream | UsingDeclarations.cs:8:26:8:69 | FileStream file1 = ... | semmle.label | successor |
| UsingDeclarations.cs:8:49:8:53 | "..." | UsingDeclarations.cs:8:56:8:68 | access to constant Open | semmle.label | successor |
| UsingDeclarations.cs:8:56:8:68 | access to constant Open | UsingDeclarations.cs:8:34:8:69 | object creation of type FileStream | semmle.label | successor |
| UsingDeclarations.cs:8:72:8:115 | FileStream file2 = ... | UsingDeclarations.cs:10:9:12:9 | using (...) {...} | semmle.label | successor |
| UsingDeclarations.cs:8:80:8:115 | object creation of type FileStream | UsingDeclarations.cs:8:72:8:115 | FileStream file2 = ... | semmle.label | successor |
| UsingDeclarations.cs:8:95:8:99 | "..." | UsingDeclarations.cs:8:102:8:114 | access to constant Open | semmle.label | successor |
| UsingDeclarations.cs:8:102:8:114 | access to constant Open | UsingDeclarations.cs:8:80:8:115 | object creation of type FileStream | semmle.label | successor |
| UsingDeclarations.cs:10:9:12:9 | using (...) {...} | UsingDeclarations.cs:10:49:10:53 | "..." | semmle.label | successor |
| UsingDeclarations.cs:10:26:10:69 | FileStream file3 = ... | UsingDeclarations.cs:10:95:10:99 | "..." | semmle.label | successor |
| UsingDeclarations.cs:10:34:10:69 | object creation of type FileStream | UsingDeclarations.cs:10:26:10:69 | FileStream file3 = ... | semmle.label | successor |
| UsingDeclarations.cs:10:49:10:53 | "..." | UsingDeclarations.cs:10:56:10:68 | access to constant Open | semmle.label | successor |
| UsingDeclarations.cs:10:56:10:68 | access to constant Open | UsingDeclarations.cs:10:34:10:69 | object creation of type FileStream | semmle.label | successor |
| UsingDeclarations.cs:10:72:10:115 | FileStream file4 = ... | UsingDeclarations.cs:11:9:12:9 | {...} | semmle.label | successor |
| UsingDeclarations.cs:10:80:10:115 | object creation of type FileStream | UsingDeclarations.cs:10:72:10:115 | FileStream file4 = ... | semmle.label | successor |
| UsingDeclarations.cs:10:95:10:99 | "..." | UsingDeclarations.cs:10:102:10:114 | access to constant Open | semmle.label | successor |
| UsingDeclarations.cs:10:102:10:114 | access to constant Open | UsingDeclarations.cs:10:80:10:115 | object creation of type FileStream | semmle.label | successor |
| UsingDeclarations.cs:11:9:12:9 | {...} | UsingDeclarations.cs:14:9:15:13 | using (...) {...} | semmle.label | successor |
| UsingDeclarations.cs:14:9:15:13 | using (...) {...} | UsingDeclarations.cs:14:30:14:34 | "..." | semmle.label | successor |
| UsingDeclarations.cs:14:15:14:50 | object creation of type FileStream | UsingDeclarations.cs:15:13:15:13 | ; | semmle.label | successor |
| UsingDeclarations.cs:14:30:14:34 | "..." | UsingDeclarations.cs:14:37:14:49 | access to constant Open | semmle.label | successor |
| UsingDeclarations.cs:14:37:14:49 | access to constant Open | UsingDeclarations.cs:14:15:14:50 | object creation of type FileStream | semmle.label | successor |
| UsingDeclarations.cs:15:13:15:13 | ; | UsingDeclarations.cs:6:10:6:30 | exit TestUsingDeclarations | semmle.label | successor |

View File

@@ -0,0 +1,10 @@
import csharp
import semmle.code.csharp.controlflow.ControlFlowGraph
query predicate edges(ControlFlow::Node node1, ControlFlow::Node node2, string label, string value) {
label = "semmle.label" and
exists(ControlFlow::SuccessorType t |
node2 = node1.getASuccessorByType(t) and value = t.toString()
)
and node1.getEnclosingCallable().hasName("TestUsingDeclarations")
}

View File

@@ -0,0 +1,17 @@
using System;
using System.IO;
class UsingDeclarations
{
void TestUsingDeclarations()
{
using FileStream file1 = new FileStream("...", FileMode.Open), file2 = new FileStream("...", FileMode.Open);
using(FileStream file3 = new FileStream("...", FileMode.Open), file4 = new FileStream("...", FileMode.Open))
{
}
using(new FileStream("...", FileMode.Open))
;
}
}

View File

@@ -0,0 +1,26 @@
localVars
| UsingDeclarations.cs:8:26:8:30 | file1 |
| UsingDeclarations.cs:8:72:8:76 | file2 |
| UsingDeclarations.cs:10:26:10:30 | file3 |
| UsingDeclarations.cs:10:72:10:76 | file4 |
localVariableDeclarations
| UsingDeclarations.cs:8:9:8:116 | using ... ...; | 0 | UsingDeclarations.cs:8:26:8:69 | FileStream file1 = ... |
| UsingDeclarations.cs:8:9:8:116 | using ... ...; | 1 | UsingDeclarations.cs:8:72:8:115 | FileStream file2 = ... |
usingStmts1
| UsingDeclarations.cs:8:9:8:116 | using ... ...; |
| UsingDeclarations.cs:10:9:12:9 | using (...) {...} |
| UsingDeclarations.cs:14:9:15:13 | using (...) {...} |
usingStmts
| UsingDeclarations.cs:8:9:8:116 | using ... ...; | 0 | UsingDeclarations.cs:8:26:8:69 | FileStream file1 = ... |
| UsingDeclarations.cs:8:9:8:116 | using ... ...; | 1 | UsingDeclarations.cs:8:72:8:115 | FileStream file2 = ... |
| UsingDeclarations.cs:10:9:12:9 | using (...) {...} | 0 | UsingDeclarations.cs:10:26:10:69 | FileStream file3 = ... |
| UsingDeclarations.cs:10:9:12:9 | using (...) {...} | 1 | UsingDeclarations.cs:10:72:10:115 | FileStream file4 = ... |
usingDecls
| UsingDeclarations.cs:8:9:8:116 | using ... ...; | 0 | UsingDeclarations.cs:8:26:8:69 | FileStream file1 = ... |
| UsingDeclarations.cs:8:9:8:116 | using ... ...; | 1 | UsingDeclarations.cs:8:72:8:115 | FileStream file2 = ... |
usingExprs
| UsingDeclarations.cs:8:9:8:116 | using ... ...; | UsingDeclarations.cs:8:34:8:69 | object creation of type FileStream |
| UsingDeclarations.cs:8:9:8:116 | using ... ...; | UsingDeclarations.cs:8:80:8:115 | object creation of type FileStream |
| UsingDeclarations.cs:10:9:12:9 | using (...) {...} | UsingDeclarations.cs:10:34:10:69 | object creation of type FileStream |
| UsingDeclarations.cs:10:9:12:9 | using (...) {...} | UsingDeclarations.cs:10:80:10:115 | object creation of type FileStream |
| UsingDeclarations.cs:14:9:15:13 | using (...) {...} | UsingDeclarations.cs:14:15:14:50 | object creation of type FileStream |

View File

@@ -0,0 +1,22 @@
import csharp
query predicate localVars(LocalVariable decl) {
decl.getEnclosingCallable().hasName("TestUsingDeclarations")
}
query predicate localVariableDeclarations(
LocalVariableDeclStmt stmt, int i, LocalVariableDeclExpr decl
) {
decl.getEnclosingCallable().hasName("TestUsingDeclarations") and
decl = stmt.getVariableDeclExpr(i)
}
query predicate usingStmts1(UsingStmt stmt) { any() }
query predicate usingStmts(UsingStmt stmt, int i, LocalVariableDeclExpr decl) {
decl = stmt.getVariableDeclExpr(i)
}
query predicate usingDecls(UsingDeclStmt stmt, int i, Expr e) { e = stmt.getChild(i) }
query predicate usingExprs(UsingStmt stmt, Expr e) { e = stmt.getAnExpr() }

View File

@@ -5,7 +5,7 @@
import csharp
where
forall(UsingStmt s |
forall(UsingBlockStmt s |
exists(s.getAnExpr()) and
exists(s.getBody())
)

View File

@@ -58,6 +58,10 @@ class Test
SqlConnection c1f = new SqlConnection();
Throw2(c1f);
c1f.Dispose();
// GOOD: using declaration
using SqlConnection c2 = new SqlConnection("");
c2.Open();
}
void Throw1(SqlConnection sc)
@@ -71,3 +75,5 @@ class Test
return sc == null ? throw new Exception() : sc;
}
}
// semmle-extractor-options: /langversion:8.0

View File

@@ -78,6 +78,9 @@ class Test
// GOOD: Passed to a library. This is only detected in CIL.
Console.SetOut(new StreamWriter("output.txt"));
// GOOD: Disposed automatically.
using var c2 = new Timer(TimerProc);
return null;
}
@@ -88,3 +91,5 @@ class Test
{
}
}
// semmle-extractor-options: /langversion:8.0

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
description: Support for null-coalescing assignment, static local functions, and using declarations.
compatibility: backwards

View File

@@ -423,6 +423,14 @@ class SwitchCase extends Stmt, @case {
*/
SwitchExpr getSwitchExpr() { result.getACase() = this }
/**
* Gets the expression of the surrounding switch that this case is compared
* against.
*/
Expr getSelectorExpr() {
result = this.getSwitch().getExpr() or result = this.getSwitchExpr().getExpr()
}
/**
* PREVIEW FEATURE in Java 12. Subject to removal in a future release.
*
@@ -625,7 +633,10 @@ class BreakStmt extends Stmt, @breakstmt {
override string pp() {
if this.hasLabel()
then result = "break " + this.getLabel()
else if this.hasValue() then result = "break ..." else result = "break"
else
if this.hasValue()
then result = "break ..."
else result = "break"
}
/** This statement's Halstead ID (used to compute Halstead metrics). */

View File

@@ -93,7 +93,8 @@ class Guard extends ExprParent {
/** Gets the statement containing this guard. */
Stmt getEnclosingStmt() {
result = this.(Expr).getEnclosingStmt() or
result = this.(SwitchCase).getSwitch()
result = this.(SwitchCase).getSwitch() or
result = this.(SwitchCase).getSwitchExpr().getEnclosingStmt()
}
/**
@@ -126,7 +127,7 @@ class Guard extends ExprParent {
branch = true and
bb2.getFirstNode() = sc.getControlFlowNode() and
pred = sc.getControlFlowNode().getAPredecessor() and
pred.(Expr).getParent*() = sc.getSwitch().getExpr() and
pred.(Expr).getParent*() = sc.getSelectorExpr() and
bb1 = pred.getBasicBlock()
)
or
@@ -160,12 +161,12 @@ class Guard extends ExprParent {
}
private predicate switchCaseControls(SwitchCase sc, BasicBlock bb) {
exists(BasicBlock caseblock, SwitchStmt ss |
ss.getACase() = sc and
exists(BasicBlock caseblock, Expr selector |
selector = sc.getSelectorExpr() and
caseblock.getFirstNode() = sc.getControlFlowNode() and
caseblock.bbDominates(bb) and
forall(ControlFlowNode pred | pred = sc.getControlFlowNode().getAPredecessor() |
pred.(Expr).getParent*() = ss.getExpr()
pred.(Expr).getParent*() = selector
)
)
}
@@ -254,7 +255,8 @@ private predicate equalityGuard(Guard g, Expr e1, Expr e2, boolean polarity) {
exists(ConstCase cc |
cc = g and
polarity = true and
cc.getSwitch().getExpr().getProperExpr() = e1 and
cc.getValue() = e2
cc.getSelectorExpr().getProperExpr() = e1 and
cc.getValue() = e2 and
strictcount(cc.getValue(_)) = 1
)
}

View File

@@ -0,0 +1,9 @@
class Test {
void foo(String s) {
int x = switch(s) {
case "a", "b" -> 1;
case "c" -> 2;
default -> 3;
};
}
}

View File

@@ -0,0 +1 @@
| Test.java:5:7:5:17 | stmt | Test.java:3:20:3:20 | s | Test.java:5:12:5:14 | "c" | true | true | Test.java:5:7:5:17 | stmt |

View File

@@ -0,0 +1,8 @@
import java
import semmle.code.java.controlflow.Guards
from Guard g, BasicBlock bb, boolean branch, VarAccess e1, Expr e2, boolean pol
where
g.controls(bb, branch) and
g.isEquality(e1, e2, pol)
select g, e1, e2, pol, branch, bb

View File

@@ -0,0 +1 @@
//semmle-extractor-options: --javac-args --enable-preview -source 12 -target 12

View File

@@ -3,7 +3,7 @@
* @description Storing unencrypted passwords in configuration files is unsafe.
* @kind problem
* @problem.severity warning
* @precision high
* @precision medium
* @id js/password-in-configuration-file
* @tags security
* external/cwe/cwe-256
@@ -12,6 +12,7 @@
*/
import javascript
import semmle.javascript.RestrictedLocations
/**
* Holds if some JSON or YAML file contains a property with name `key`
@@ -45,7 +46,7 @@ predicate exclude(File f) {
f.getExtension().toLowerCase() = "raml"
}
from string key, string val, Locatable valElement
from string key, string val, Locatable valElement, string pwd
where
config(key, val, valElement) and
val != "" and
@@ -53,13 +54,14 @@ where
not val.regexpMatch(Templating::getDelimiterMatchingRegexp()) and
(
key.toLowerCase() = "password" and
pwd = val and
// exclude interpolations of environment variables
not val.regexpMatch("\\$.*|%.*%")
or
key.toLowerCase() != "readme" and
// look for `password=...`, but exclude `password=;`, `password="$(...)"`,
// `password=%s` and `password==`
val.regexpMatch("(?is).*password\\s*=(?!\\s*;)(?!\"?[$`])(?!%s)(?!=).*")
pwd = val.regexpCapture("(?is).*password\\s*=\\s*(?!;|\"?[$`]|%s|=)(\\S+).*", 1)
) and
not exclude(valElement.getFile())
select valElement, "Avoid plaintext passwords in configuration files."
select (FirstLineOf)valElement, "Hard-coded password '" + pwd + "' in configuration file."

View File

@@ -3,6 +3,7 @@
* @description Only keep results in non-framework code
* @kind treemap
* @id js/not-framework-file-metric-filter
* @metricType file
*/
import FilterFrameworks

View File

@@ -5,6 +5,7 @@
* mapping comment.
* @kind treemap
* @id js/not-generated-file-metric-filter
* @metricType file
*/
import semmle.javascript.GeneratedCode

View File

@@ -3,6 +3,7 @@
* @description Only keep results from files that are not minified.
* @kind treemap
* @id js/not-minified-file-metric-filter
* @metricType file
*/
import javascript

View File

@@ -37,6 +37,6 @@ module Templating {
* storing it in its first (and only) capture group.
*/
string getDelimiterMatchingRegexp() {
result = ".*(" + concat("\\Q" + getADelimiter() + "\\E", "|") + ").*"
result = "(?s).*(" + concat("\\Q" + getADelimiter() + "\\E", "|") + ").*"
}
}

View File

@@ -1,2 +1,3 @@
| mysql-config.json:4:16:4:23 | "secret" | Avoid plaintext passwords in configuration files. |
| tst4.json:2:10:2:38 | "script ... ecret'" | Avoid plaintext passwords in configuration files. |
| mysql-config.json:4:16:4:23 | "secret" | Hard-coded password 'secret' in configuration file. |
| tst4.json:2:10:2:38 | "script ... ecret'" | Hard-coded password ''secret'' in configuration file. |
| tst7.yml:2:9:2:6 | \| | Hard-coded password 'abc' in configuration file. |

View File

@@ -1 +1,7 @@
password: $$SOME_VAR
config: |
[mail]
host = smtp.mydomain.com
port = 25
username = sample_admin@mydomain.com
password = abc

View File

@@ -0,0 +1,6 @@
config: |
[mail]
host = smtp.mydomain.com
port = 25
username = {{username}}
password = {{pwd}}

View File

@@ -57,15 +57,37 @@ predicate ok_to_fail(ImportExpr ie) {
os_specific_import(ie) != get_os()
}
class VersionTest extends @py_flow_node {
VersionTest() {
exists(string name |
name.matches("%version%") and
this.(CompareNode).getAChild+().pointsTo(Module::named("sys").attr(name))
)
}
string toString() {
result = "VersionTest"
}
}
/** A guard on the version of the Python interpreter */
class VersionGuard extends ConditionBlock {
VersionGuard() {
this.getLastNode() instanceof VersionTest
}
}
from ImportExpr ie
where not ie.refersTo(_) and
exists(Context c | c.appliesTo(ie.getAFlowNode())) and
not ok_to_fail(ie) and
not exists(VersionGuard guard |
if guard.isTrue() then
guard.controls(ie.getAFlowNode().getBasicBlock(), false)
else
guard.controls(ie.getAFlowNode().getBasicBlock(), true)
guard.controls(ie.getAFlowNode().getBasicBlock(), _)
)
select ie, "Unable to resolve import of '" + ie.getImportedModuleName() + "'."