Merge pull request #952 from calumgrant/cs/non-null-functions

C#: Better call analysis using CIL
This commit is contained in:
Tom Hvitved
2019-03-23 10:47:22 +01:00
committed by GitHub
35 changed files with 772 additions and 81 deletions

View File

@@ -37,19 +37,21 @@ namespace Semmle.Extraction.CIL.Entities
if (!def.PublicKey.IsNil)
assemblyName.SetPublicKey(cx.mdReader.GetBlobBytes(def.PublicKey));
ShortId = cx.GetId(assemblyName.FullName) + "#file:///" + cx.assemblyPath.Replace("\\", "/");
ShortId = cx.GetId(FullName) + "#file:///" + cx.assemblyPath.Replace("\\", "/");
file = new File(cx, cx.assemblyPath);
}
static readonly Id suffix = new StringId(";assembly");
string FullName => assemblyName.GetPublicKey() is null ? assemblyName.FullName + ", PublicKeyToken=null" : assemblyName.FullName;
public override IEnumerable<IExtractionProduct> Contents
{
get
{
yield return file;
yield return Tuples.assemblies(this, file, assemblyName.FullName, assemblyName.Name, assemblyName.Version.ToString());
yield return Tuples.assemblies(this, file, FullName, assemblyName.Name, assemblyName.Version.ToString());
if (cx.pdb != null)
{

View File

@@ -17,3 +17,4 @@ import Handler
import ControlFlow
import DataFlow
import Attribute
import Stubs

View File

@@ -0,0 +1,55 @@
/**
* Provides predicates for analysing the return values of callables.
*/
private import CIL
cached
private module Cached {
/** Holds if method `m` always returns null. */
cached
predicate alwaysNullMethod(Method m) { forex(Expr e | m.canReturn(e) | alwaysNullExpr(e)) }
/** Holds if method `m` always returns non-null. */
cached
predicate alwaysNotNullMethod(Method m) { forex(Expr e | m.canReturn(e) | alwaysNotNullExpr(e)) }
/** Holds if method `m` always throws an exception. */
cached
predicate alwaysThrowsMethod(Method m) {
m.hasBody() and
not exists(m.getImplementation().getAnInstruction().(Return))
}
/** Holds if method `m` always throws an exception of type `t`. */
cached
predicate alwaysThrowsException(Method m, Type t) {
alwaysThrowsMethod(m) and
forex(Throw ex | ex = m.getImplementation().getAnInstruction() | t = ex.getExpr().getType())
}
}
import Cached
/** Holds if expression `expr` always evaluates to `null`. */
private predicate alwaysNullExpr(Expr expr) {
expr instanceof NullLiteral
or
alwaysNullMethod(expr.(StaticCall).getTarget())
or
forex(VariableUpdate vu | DefUse::variableUpdateUse(_, vu, expr) |
alwaysNullExpr(vu.getSource())
)
}
/** Holds if expression `expr` always evaluates to non-null. */
private predicate alwaysNotNullExpr(Expr expr) {
expr instanceof Opcodes::Newobj
or
expr instanceof Literal and not expr instanceof NullLiteral
or
alwaysNotNullMethod(expr.(StaticCall).getTarget())
or
forex(VariableUpdate vu | DefUse::variableUpdateUse(_, vu, expr) |
alwaysNotNullExpr(vu.getSource())
)
}

View File

@@ -137,6 +137,6 @@ class TrueFlow extends FlowType, TTrueFlow {
}
/** False control flow. */
class FalseFlow extends FlowType, TTrueFlow {
class FalseFlow extends FlowType, TFalseFlow {
override string toString() { result = "false" }
}

View File

@@ -60,7 +60,7 @@ class Tainted extends TaintType, TTaintedValue { }
private predicate localExactStep(DataFlowNode src, DataFlowNode sink) {
src = sink.(Opcodes::Dup).getAnOperand()
or
DefUse::defUse(_, src, sink)
defUse(_, src, sink)
or
src = sink.(ParameterReadAccess).getTarget()
or
@@ -88,7 +88,7 @@ private predicate localTaintStep(DataFlowNode src, DataFlowNode sink) {
}
cached
private module DefUse {
module DefUse {
/**
* A classification of variable references into reads and writes.
*/
@@ -185,21 +185,26 @@ private module DefUse {
)
}
/** Holds if the update `def` can be used at the read `use`. */
/** Holds if the variable update `vu` can be used at the read `use`. */
cached
predicate defUse(StackVariable target, DataFlowNode def, ReadAccess use) {
exists(VariableUpdate vu | def = vu.getSource() |
defReachesReadWithinBlock(target, vu, use)
or
exists(BasicBlock bb, int i |
exists(refRank(bb, i, target, Read())) and
use = bb.getNode(i) and
defReachesEndOfBlock(bb.getAPredecessor(), vu, target) and
not defReachesReadWithinBlock(target, _, use)
)
predicate variableUpdateUse(StackVariable target, VariableUpdate vu, ReadAccess use) {
defReachesReadWithinBlock(target, vu, use)
or
exists(BasicBlock bb, int i |
exists(refRank(bb, i, target, Read())) and
use = bb.getNode(i) and
defReachesEndOfBlock(bb.getAPredecessor(), vu, target) and
not defReachesReadWithinBlock(target, _, use)
)
}
/** Holds if the update `def` can be used at the read `use`. */
cached
predicate defUse(StackVariable target, Expr def, ReadAccess use) {
exists(VariableUpdate vu | def = vu.getSource() | variableUpdateUse(target, vu, use))
}
}
private import DefUse
abstract library class VariableUpdate extends Instruction {
abstract Expr getSource();

View File

@@ -127,6 +127,9 @@ class FloatLiteral extends Literal, @cil_ldc_r { }
/** An expression that pushes a `null` value onto the stack. */
class NullLiteral extends Literal, @cil_ldnull { }
/** An expression that pushes a string onto the stack. */
class StringLiteral extends Literal, @cil_ldstr { }
/** A branch with one operand. */
class UnaryBranch extends ConditionalBranch, @cil_unary_jump {
override int getPopCount() { result = 1 }

View File

@@ -234,7 +234,7 @@ module Opcodes {
override string getOpcodeName() { result = "nop" }
}
class Ldstr extends Literal, @cil_ldstr {
class Ldstr extends StringLiteral, @cil_ldstr {
override string getOpcodeName() { result = "ldstr" }
override string getExtra() { result = "\"" + getValue() + "\"" }

View File

@@ -50,6 +50,11 @@ class MethodImplementation extends EntryPoint, @cil_method_implementation {
int getStackSize() { cil_method_stack_size(this, result) }
override string toString() { result = getMethod().toString() }
/** Gets a string representing the disassembly of this implementation. */
string getDisassembly() {
result = concat(Instruction i | i = this.getAnInstruction() | i.toString(), ", " order by i.getIndex())
}
}
/**
@@ -63,6 +68,11 @@ class Method extends DotNet::Callable, Element, Member, TypeContainer, DataFlowN
*/
MethodImplementation getAnImplementation() { result.getMethod() = this }
/** Gets the "best" implementation of this method, if any. */
BestImplementation getImplementation() {
result = getAnImplementation()
}
override Method getMethod() { result = this }
override string getName() { cil_method(this, result, _, _) }
@@ -102,7 +112,7 @@ class Method extends DotNet::Callable, Element, Member, TypeContainer, DataFlowN
int getCallPopCount() { result = count(getRawParameter(_)) }
/** Gets a method called by this method. */
Method getACallee() { result = getAnImplementation().getAnInstruction().(Call).getTarget() }
Method getACallee() { result = getImplementation().getAnInstruction().(Call).getTarget() }
/** Holds if this method is `virtual`. */
predicate isVirtual() { cil_virtual(this) }
@@ -168,10 +178,10 @@ class Method extends DotNet::Callable, Element, Member, TypeContainer, DataFlowN
/** Gets a method that overrides this method, if any. */
final Method getAnOverrider() { result.getOverriddenMethod() = this }
override predicate hasBody() { exists(getAnImplementation()) }
override predicate hasBody() { exists(getImplementation()) }
override predicate canReturn(DotNet::Expr expr) {
exists(Return ret | ret.getImplementation().getMethod() = this and expr = ret.getExpr())
exists(Return ret | ret.getImplementation() = this.getImplementation() and expr = ret.getExpr())
}
}
@@ -198,7 +208,7 @@ class InstanceConstructor extends Constructor {
/** A method that always returns the `this` parameter. */
class ChainingMethod extends Method {
ChainingMethod() {
forex(Return ret | ret = getAnImplementation().getAnInstruction() |
forex(Return ret | ret = getImplementation().getAnInstruction() |
ret.getExpr() instanceof ThisAccess
)
}
@@ -232,7 +242,7 @@ class TrivialGetter extends Method {
/** Gets the underlying field of this getter. */
Field getField() {
getAnImplementation().getAnInstruction().(FieldReadAccess).getTarget() = result
getImplementation().getAnInstruction().(FieldReadAccess).getTarget() = result
}
}
@@ -249,7 +259,7 @@ class Setter extends Accessor {
*/
class TrivialSetter extends Method {
TrivialSetter() {
exists(MethodImplementation impl | impl = getAnImplementation() |
exists(MethodImplementation impl | impl = getImplementation() |
impl.getInstruction(0) instanceof ThisAccess and
impl.getInstruction(1).(ParameterReadAccess).getTarget().getIndex() = 1 and
impl.getInstruction(2) instanceof FieldWriteAccess
@@ -258,7 +268,7 @@ class TrivialSetter extends Method {
/** Gets the underlying field of this setter. */
Field getField() {
result = getAnImplementation().getAnInstruction().(FieldWriteAccess).getTarget()
result = getImplementation().getAnInstruction().(FieldWriteAccess).getTarget()
}
}

View File

@@ -0,0 +1,54 @@
/**
* Provides classes and predicates for identifying stub code.
*/
import CIL
/**
* The average number of instructions per method,
* below which an assembly is probably a stub.
*/
private float stubInstructionThreshold() { result = 5.1 }
cached
private module Cached {
/**
* A simple heuristic for determining whether an assembly is a
* reference assembly where the method bodies have dummy implementations.
* Look at the average number of instructions per method.
*/
cached
predicate assemblyIsStubImpl(Assembly asm) {
exists(int totalInstructions, int totalImplementations |
totalInstructions = count(Instruction i | i.getImplementation().getLocation() = asm) and
totalImplementations = count(MethodImplementation i |
i.getImplementation().getLocation() = asm
) and
totalInstructions.(float) / totalImplementations.(float) < stubInstructionThreshold()
)
}
cached
predicate bestImplementation(MethodImplementation mi) {
not assemblyIsStubImpl(mi.getLocation()) and
not exists(MethodImplementation better | mi.getMethod() = better.getMethod() |
mi.getNumberOfInstructions() < better.getNumberOfInstructions()
or
mi.getNumberOfInstructions() = better.getNumberOfInstructions() and
mi.getLocation().getFile().toString() > better.getLocation().getFile().toString()
) and
exists(mi.getAnInstruction())
}
}
private import Cached
predicate assemblyIsStub = assemblyIsStubImpl/1;
/**
* A method implementation that is the "best" one for a particular method,
* if there are several potential implementations to choose between, and
* excludes implementations that are probably from stub/reference assemblies.
*/
class BestImplementation extends MethodImplementation {
BestImplementation() { bestImplementation(this) }
}

View File

@@ -126,11 +126,7 @@ class TypeParameter extends DotNet::TypeParameter, Type, @type_parameter {
/** Gets the constraints on this type parameter, if any. */
TypeParameterConstraints getConstraints() { result.getTypeParameter() = this }
/**
* Holds if this type parameter is guaranteed to always be instantiated
* to a reference type.
*/
predicate isRefType() {
override predicate isRefType() {
exists(TypeParameterConstraints tpc | tpc = getConstraints() |
tpc.hasRefTypeConstraint() or
exists(tpc.getClassConstraint()) or
@@ -139,11 +135,7 @@ class TypeParameter extends DotNet::TypeParameter, Type, @type_parameter {
)
}
/**
* Holds if this type parameter is guaranteed to always be instantiated
* to a value type.
*/
predicate isValueType() {
override predicate isValueType() {
exists(TypeParameterConstraints tpc | tpc = getConstraints() |
tpc.hasValueTypeConstraint() or
tpc.getATypeParameterConstraint().isValueType()

View File

@@ -37,6 +37,12 @@ class Type extends DotNet::Type, Member, TypeContainer, @type {
or
not this instanceof UnboundGenericType and getAChild().containsTypeParameters()
}
/** Holds if this type is a reference type, or a type parameter that is a reference type. */
predicate isRefType() { none() }
/** Holds if this type is a value type, or a type parameter that is a value type. */
predicate isValueType() { none() }
}
/**
@@ -404,7 +410,9 @@ class VoidType extends DotNet::ValueOrRefType, Type, @void_type {
* Either a simple type (`SimpleType`), an `enum` (`Enum`), a `struct` (`Struct`),
* or a nullable type (`NullableType`).
*/
class ValueType extends ValueOrRefType, @value_type { }
class ValueType extends ValueOrRefType, @value_type {
override predicate isValueType() { any() }
}
/**
* A simple type. Simple types in C# are predefined `struct` types.
@@ -659,6 +667,8 @@ class RefType extends ValueOrRefType, @ref_type {
result = (this.getNumberOverridden() * this.getInheritanceDepth()) /
this.getNumberOfCallables().(float)
}
override predicate isRefType() { any() }
}
// Helper predicate to avoid slow "negation_body"

View File

@@ -3,6 +3,8 @@
*/
import csharp
private import cil
private import dotnet
private import ControlFlow::SuccessorTypes
private import semmle.code.csharp.commons.Assertions
private import semmle.code.csharp.commons.ComparisonTest
@@ -11,6 +13,7 @@ private import semmle.code.csharp.controlflow.BasicBlocks
private import semmle.code.csharp.controlflow.internal.Completion
private import semmle.code.csharp.dataflow.Nullness
private import semmle.code.csharp.frameworks.System
private import semmle.code.cil.CallableReturns
/** An abstract value. */
abstract class AbstractValue extends TAbstractValue {
@@ -637,6 +640,15 @@ module Internal {
TMatchValue(CaseStmt cs, boolean b) { b = true or b = false } or
TEmptyCollectionValue(boolean b) { b = true or b = false }
/** A callable that always returns a non-`null` value. */
private class NonNullCallable extends DotNet::Callable {
NonNullCallable() {
exists(CIL::Method m | m.matchesHandle(this) | alwaysNotNullMethod(m) and not m.isVirtual())
or
this = any(SystemObjectClass c).getGetTypeMethod()
}
}
/** Holds if expression `e` is a non-`null` value. */
predicate nonNullValue(Expr e) {
e instanceof ObjectCreation
@@ -644,17 +656,18 @@ module Internal {
e instanceof ArrayCreation
or
e.hasValue() and
not e instanceof NullLiteral
not e instanceof NullLiteral and
not e instanceof DefaultValueExpr
or
e instanceof ThisAccess
or
e instanceof AddExpr and
e.getType() instanceof StringType
or
e = any(MethodCall mc |
mc.getTarget() = any(SystemObjectClass c).getGetTypeMethod() and
not mc.isConditional()
)
e.(DefaultValueExpr).getType().isValueType()
or
e.(Call).getTarget().getSourceDeclaration() instanceof NonNullCallable and
not e.(QualifiableExpr).isConditional()
}
/** Holds if expression `e2` is a non-`null` value whenever `e1` is. */
@@ -1285,9 +1298,7 @@ module Internal {
) {
isGuardedByNode1(guarded, g, sub, v) and
sub = g.getAChildExpr*() and
forall(Ssa::Definition def | def = sub.getAnSsaQualifier(_) |
isGuardedByNode2(guarded, def)
)
forall(Ssa::Definition def | def = sub.getAnSsaQualifier(_) | isGuardedByNode2(guarded, def))
}
/**

View File

@@ -6,6 +6,8 @@
*/
import csharp
private import cil
private import semmle.code.cil.CallableReturns
private import semmle.code.csharp.ExprOrStmtParent
private import semmle.code.csharp.commons.Assertions
private import semmle.code.csharp.frameworks.System
@@ -38,6 +40,13 @@ private class ThrowingCall extends NonReturningCall {
exists(AssertMethod m | m = this.(FailingAssertion).getAssertMethod() |
c.getExceptionClass() = m.getExceptionClass()
)
or
exists(CIL::Method m, CIL::Type ex |
this.getTarget().matchesHandle(m) and
alwaysThrowsException(m, ex) and
c.getExceptionClass().matchesHandle(ex) and
not m.isVirtual()
)
}
override ThrowCompletion getACompletion() { result = c }

View File

@@ -646,7 +646,7 @@ module DataFlow {
sourceDecl.matchesHandle(result.(Callable))
or
// CIL callable without C# implementation in the database
not sourceDecl.matchesHandle(any(Callable k)) and
not sourceDecl.matchesHandle(any(Callable k | k.hasBody())) and
result = sourceDecl
else
// C# callable without C# implementation in the database
@@ -1437,7 +1437,7 @@ module DataFlow {
TExprNode(ControlFlow::Nodes::ElementNode cfn) { cfn.getElement() instanceof Expr } or
TSsaDefinitionNode(Ssa::Definition def) or
TCilParameterNode(CIL::Parameter p) { p.getMethod().hasBody() } or
TCilExprNode(CIL::Expr e) or
TCilExprNode(CIL::Expr e) { e.getImplementation() instanceof CIL::BestImplementation } or
TImplicitDelegateCallNode(DelegateArgumentToLibraryCallable arg) or
TImplicitCapturedArgumentNode(Call c, LocalScopeVariable v) {
exists(Ssa::ExplicitDefinition def | def.isCapturedVariableDefinitionFlowIn(_, c) |

View File

@@ -19,6 +19,7 @@
import csharp
private import ControlFlow
private import internal.CallableReturns
private import semmle.code.csharp.commons.Assertions
private import semmle.code.csharp.commons.ComparisonTest
private import semmle.code.csharp.controlflow.Guards as G
@@ -57,9 +58,26 @@ class AlwaysNullExpr extends Expr {
this.(AssignExpr).getRValue() instanceof AlwaysNullExpr
or
this.(Cast).getExpr() instanceof AlwaysNullExpr
or
this instanceof DefaultValueExpr and this.getType().isRefType()
or
this = any(Ssa::Definition def |
forex(Ssa::Definition u | u = def.getAnUltimateDefinition() | nullDef(u))
).getARead()
or
exists(Callable target |
this.(Call).getTarget() = target and
not target.(Virtualizable).isVirtual() and
alwaysNullCallable(target)
)
}
}
/** Holds if SSA definition `def` is always `null`. */
private predicate nullDef(Ssa::ExplicitDefinition def) {
def.getADefinition().getSource() instanceof AlwaysNullExpr
}
/** An expression that is never `null`. */
class NonNullExpr extends Expr {
NonNullExpr() {
@@ -69,15 +87,24 @@ class NonNullExpr extends Expr {
or
this instanceof G::NullGuardedExpr
or
exists(Ssa::Definition def | nonNullDef(def) | this = def.getARead())
this = any(Ssa::Definition def |
forex(Ssa::Definition u | u = def.getAnUltimateDefinition() | nonNullDef(u))
).getARead()
or
exists(Callable target |
this.(Call).getTarget() = target and
not target.(Virtualizable).isVirtual() and
alwaysNotNullCallable(target) and
not this.(QualifiableExpr).isConditional()
)
}
}
/** Holds if SSA definition `def` is never `null`. */
private predicate nonNullDef(Ssa::Definition v) {
v.(Ssa::ExplicitDefinition).getADefinition().getSource() instanceof NonNullExpr
private predicate nonNullDef(Ssa::ExplicitDefinition def) {
def.getADefinition().getSource() instanceof NonNullExpr
or
exists(AssignableDefinition ad | ad = v.(Ssa::ExplicitDefinition).getADefinition() |
exists(AssignableDefinition ad | ad = def.getADefinition() |
ad instanceof AssignableDefinitions::IsPatternDefinition
or
ad instanceof AssignableDefinitions::TypeCasePatternDefinition

View File

@@ -0,0 +1,59 @@
/**
* Provides predicates for analyzing the return values of callables.
*/
import csharp
private import cil
private import semmle.code.csharp.dataflow.Nullness
private import semmle.code.cil.CallableReturns as CR
private predicate finalCallable(Callable c) {
not c.(Virtualizable).isVirtual() and
not exists(DeclarationWithGetSetAccessors p | c = p.getAnAccessor() and p.isVirtual())
}
/** Holds if callable `c` always returns null. */
predicate alwaysNullCallable(Callable c) {
finalCallable(c) and
(
exists(CIL::Method m | m.matchesHandle(c) | CR::alwaysNullMethod(m))
or
forex(Expr e | c.canReturn(e) | e instanceof AlwaysNullExpr)
)
}
/** Holds if callable `c` always returns a non-null value. */
predicate alwaysNotNullCallable(Callable c) {
finalCallable(c) and
(
exists(CIL::Method m | m.matchesHandle(c) | CR::alwaysNotNullMethod(m))
or
forex(Expr e | c.canReturn(e) | e instanceof NonNullExpr)
)
}
/** Holds if callable 'c' always throws an exception. */
predicate alwaysThrowsCallable(Callable c) {
finalCallable(c) and
(
forex(ControlFlow::Node pre | pre = c.getExitPoint().getAPredecessor() |
pre.getElement() instanceof ThrowElement
)
or
exists(CIL::Method m | m.matchesHandle(c) | CR::alwaysThrowsMethod(m))
)
}
/** Holds if callable `c` always throws exception `ex`. */
predicate alwaysThrowsException(Callable c, Class ex) {
finalCallable(c) and
(
forex(ControlFlow::Node pre | pre = c.getExitPoint().getAPredecessor() |
pre.getElement().(ThrowElement).getThrownExceptionType() = ex
)
or
exists(CIL::Method m, CIL::Type t | m.matchesHandle(c) |
CR::alwaysThrowsException(m, t) and t.matchesHandle(ex)
)
)
}

View File

@@ -0,0 +1,78 @@
stubs
alwaysNull
| System.Object Dataflow.NullMethods.ReturnsNull2() | 0: ldarg.0, 1: call Dataflow.NullMethods.ReturnsNull, 2: ret |
| System.Object Dataflow.NullMethods.ReturnsNull() | 0: ldnull, 1: ret |
| System.Object Dataflow.NullMethods.ReturnsNullIndirect() | 0: ldarg.0, 1: call Dataflow.NullMethods.ReturnsNull, 2: ret |
| System.Object Dataflow.NullMethods.VirtualReturnsNull() | 0: ldnull, 1: ret |
| System.Object Dataflow.NullMethods.get_NullProperty() | 0: ldnull, 1: ret |
| System.Object Dataflow.NullMethods.get_VirtualNullProperty() | 0: ldnull, 1: ret |
| System.Object System.Collections.EmptyReadOnlyDictionaryInternal.get_Item(System.Object) | 0: ldarg.1, 1: brtrue.s 6:, 2: ldstr "key", 3: call System.SR.get_ArgumentNull_Key, 4: newobj System.ArgumentNullException..ctor, 5: throw, 6: ldnull, 7: ret |
alwaysNonNull
| System.ArgumentException System.ThrowHelper.GetAddingDuplicateWithKeyArgumentException(System.Object) |
| System.ArgumentException System.ThrowHelper.GetArgumentException(System.ExceptionResource) |
| System.ArgumentException System.ThrowHelper.GetArgumentException(System.ExceptionResource,System.ExceptionArgument) |
| System.ArgumentException System.ThrowHelper.GetWrongKeyTypeArgumentException(System.Object,System.Type) |
| System.ArgumentException System.ThrowHelper.GetWrongValueTypeArgumentException(System.Object,System.Type) |
| System.ArgumentNullException System.ThrowHelper.GetArgumentNullException(System.ExceptionArgument) |
| System.ArgumentOutOfRangeException System.ThrowHelper.GetArgumentOutOfRangeException(System.ExceptionArgument,System.ExceptionResource) |
| System.ArgumentOutOfRangeException System.ThrowHelper.GetArgumentOutOfRangeException(System.ExceptionArgument,System.Int32,System.ExceptionResource) |
| System.Exception System.ThrowHelper.GetArraySegmentCtorValidationFailedException(System.Array,System.Int32,System.Int32) |
| System.InvalidOperationException System.ThrowHelper.GetInvalidOperationException(System.ExceptionResource) |
| System.Object Dataflow.NonNullMethods.ReturnsNonNull2() |
| System.Object Dataflow.NonNullMethods.ReturnsNonNull() |
| System.Object Dataflow.NonNullMethods.ReturnsNonNullIndirect() |
| System.Object Dataflow.NonNullMethods.get_VirtualNonNull() |
| System.Object Dataflow.NonNullMethods.get_VirtualNonNullProperty() |
| System.String Dataflow.NonNullMethods.get_NonNullProperty2() |
| System.Text.Encoder System.Text.ASCIIEncoding.GetEncoder() |
| System.Text.Encoder System.Text.Encoding.GetEncoder() |
| System.Text.Encoder System.Text.EncodingNLS.GetEncoder() |
| System.Text.Encoder System.Text.UTF7Encoding.GetEncoder() |
| System.Text.Encoder System.Text.UTF8Encoding.GetEncoder() |
| System.Text.Encoder System.Text.UTF32Encoding.GetEncoder() |
| System.Text.Encoder System.Text.UnicodeEncoding.GetEncoder() |
alwaysThrows
| System.Object Dataflow.ThrowingMethods.AlwaysThrows() | System.InvalidOperationException | 0: newobj System.InvalidOperationException..ctor, 1: throw |
| System.Object Dataflow.ThrowingMethods.VirtualThrows() | System.Exception | 0: newobj System.Exception..ctor, 1: throw |
| System.Object Dataflow.ThrowingMethods.get_ThrowProperty() | System.Exception | 0: newobj System.Exception..ctor, 1: throw |
| System.Object Dataflow.ThrowingMethods.get_VirtualThrowProperty() | System.Exception | 0: newobj System.Exception..ctor, 1: throw |
| System.Object System.ValueTuple.get_Item(System.Int32) | System.IndexOutOfRangeException | 0: newobj System.IndexOutOfRangeException..ctor, 1: throw |
| System.Void System.ThrowHelper.ThrowAddingDuplicateWithKeyArgumentException(System.Object) | System.ArgumentException | 0: ldarg.0, 1: call System.ThrowHelper.GetAddingDuplicateWithKeyArgumentException, 2: throw |
| System.Void System.ThrowHelper.ThrowAggregateException(System.Collections.Generic.List<System.Exception>) | System.AggregateException | 0: ldarg.0, 1: newobj System.AggregateException..ctor, 2: throw |
| System.Void System.ThrowHelper.ThrowArgumentException(System.ExceptionResource) | System.ArgumentException | 0: ldarg.0, 1: call System.ThrowHelper.GetArgumentException, 2: throw |
| System.Void System.ThrowHelper.ThrowArgumentException(System.ExceptionResource,System.ExceptionArgument) | System.ArgumentException | 0: ldarg.0, 1: ldarg.1, 2: call System.ThrowHelper.GetArgumentException, 3: throw |
| System.Void System.ThrowHelper.ThrowArgumentException_Argument_InvalidArrayType() | System.ArgumentException | 0: ldc.i4.s 31, 1: call System.ThrowHelper.GetArgumentException, 2: throw |
| System.Void System.ThrowHelper.ThrowArgumentException_DestinationTooShort() | System.ArgumentException | 0: call System.SR.get_Argument_DestinationTooShort, 1: newobj System.ArgumentException..ctor, 2: throw |
| System.Void System.ThrowHelper.ThrowArgumentNullException(System.ExceptionArgument) | System.ArgumentNullException | 0: ldarg.0, 1: call System.ThrowHelper.GetArgumentNullException, 2: throw |
| System.Void System.ThrowHelper.ThrowArgumentNullException(System.ExceptionArgument,System.ExceptionResource) | System.ArgumentNullException | 0: ldarg.0, 1: call System.ThrowHelper.GetArgumentName, 2: ldarg.1, 3: call System.ThrowHelper.GetResourceString, 4: newobj System.ArgumentNullException..ctor, 5: throw |
| System.Void System.ThrowHelper.ThrowArgumentNullException(System.ExceptionResource) | System.ArgumentNullException | 0: ldarg.0, 1: call System.ThrowHelper.GetResourceString, 2: newobj System.ArgumentNullException..ctor, 3: throw |
| System.Void System.ThrowHelper.ThrowArgumentOutOfRangeException() | System.ArgumentOutOfRangeException | 0: newobj System.ArgumentOutOfRangeException..ctor, 1: throw |
| System.Void System.ThrowHelper.ThrowArgumentOutOfRangeException(System.ExceptionArgument) | System.ArgumentOutOfRangeException | 0: ldarg.0, 1: call System.ThrowHelper.GetArgumentName, 2: newobj System.ArgumentOutOfRangeException..ctor, 3: throw |
| System.Void System.ThrowHelper.ThrowArgumentOutOfRangeException(System.ExceptionArgument,System.ExceptionResource) | System.ArgumentOutOfRangeException | 0: ldarg.0, 1: ldarg.1, 2: call System.ThrowHelper.GetArgumentOutOfRangeException, 3: throw |
| System.Void System.ThrowHelper.ThrowArgumentOutOfRangeException(System.ExceptionArgument,System.Int32,System.ExceptionResource) | System.ArgumentOutOfRangeException | 0: ldarg.0, 1: ldarg.1, 2: ldarg.2, 3: call System.ThrowHelper.GetArgumentOutOfRangeException, 4: throw |
| System.Void System.ThrowHelper.ThrowArgumentOutOfRange_IndexException() | System.ArgumentOutOfRangeException | 0: ldc.i4.s 31, 1: ldc.i4.s 31, 2: call System.ThrowHelper.GetArgumentOutOfRangeException, 3: throw |
| System.Void System.ThrowHelper.ThrowArraySegmentCtorValidationFailedExceptions(System.Array,System.Int32,System.Int32) | System.Exception | 0: ldarg.0, 1: ldarg.1, 2: ldarg.2, 3: call System.ThrowHelper.GetArraySegmentCtorValidationFailedException, 4: throw |
| System.Void System.ThrowHelper.ThrowArrayTypeMismatchException() | System.ArrayTypeMismatchException | 0: newobj System.ArrayTypeMismatchException..ctor, 1: throw |
| System.Void System.ThrowHelper.ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count() | System.ArgumentOutOfRangeException | 0: ldc.i4.s 31, 1: ldc.i4.s 31, 2: call System.ThrowHelper.GetArgumentOutOfRangeException, 3: throw |
| System.Void System.ThrowHelper.ThrowIndexArgumentOutOfRange_NeedNonNegNumException() | System.ArgumentOutOfRangeException | 0: ldc.i4.s 31, 1: ldc.i4.4, 2: call System.ThrowHelper.GetArgumentOutOfRangeException, 3: throw |
| System.Void System.ThrowHelper.ThrowIndexOutOfRangeException() | System.IndexOutOfRangeException | 0: newobj System.IndexOutOfRangeException..ctor, 1: throw |
| System.Void System.ThrowHelper.ThrowInvalidOperationException(System.ExceptionResource) | System.InvalidOperationException | 0: ldarg.0, 1: call System.ThrowHelper.GetInvalidOperationException, 2: throw |
| System.Void System.ThrowHelper.ThrowInvalidOperationException(System.ExceptionResource,System.Exception) | System.InvalidOperationException | 0: ldarg.0, 1: call System.ThrowHelper.GetResourceString, 2: ldarg.1, 3: newobj System.InvalidOperationException..ctor, 4: throw |
| System.Void System.ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumEnded() | System.InvalidOperationException | 0: ldc.i4.s 31, 1: call System.ThrowHelper.GetInvalidOperationException, 2: throw |
| System.Void System.ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumFailedVersion() | System.InvalidOperationException | 0: ldc.i4.s 31, 1: call System.ThrowHelper.GetInvalidOperationException, 2: throw |
| System.Void System.ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumNotStarted() | System.InvalidOperationException | 0: ldc.i4.s 31, 1: call System.ThrowHelper.GetInvalidOperationException, 2: throw |
| System.Void System.ThrowHelper.ThrowInvalidOperationException_InvalidOperation_EnumOpCantHappen() | System.InvalidOperationException | 0: ldc.i4.s 31, 1: call System.ThrowHelper.GetInvalidOperationException, 2: throw |
| System.Void System.ThrowHelper.ThrowInvalidTypeWithPointersNotSupported(System.Type) | System.ArgumentException | 0: call System.SR.get_Argument_InvalidTypeWithPointersNotSupported, 1: ldarg.0, 2: call System.SR.Format, 3: newobj System.ArgumentException..ctor, 4: throw |
| System.Void System.ThrowHelper.ThrowKeyNotFoundException() | System.Collections.Generic.KeyNotFoundException | 0: newobj System.Collections.Generic.KeyNotFoundException..ctor, 1: throw |
| System.Void System.ThrowHelper.ThrowLengthArgumentOutOfRange_ArgumentOutOfRange_NeedNonNegNum() | System.ArgumentOutOfRangeException | 0: ldc.i4.s 31, 1: ldc.i4.4, 2: call System.ThrowHelper.GetArgumentOutOfRangeException, 3: throw |
| System.Void System.ThrowHelper.ThrowNotSupportedException() | System.NotSupportedException | 0: newobj System.NotSupportedException..ctor, 1: throw |
| System.Void System.ThrowHelper.ThrowNotSupportedException(System.ExceptionResource) | System.NotSupportedException | 0: ldarg.0, 1: call System.ThrowHelper.GetResourceString, 2: newobj System.NotSupportedException..ctor, 3: throw |
| System.Void System.ThrowHelper.ThrowObjectDisposedException(System.ExceptionResource) | System.ObjectDisposedException | 0: ldnull, 1: ldarg.0, 2: call System.ThrowHelper.GetResourceString, 3: newobj System.ObjectDisposedException..ctor, 4: throw |
| System.Void System.ThrowHelper.ThrowObjectDisposedException(System.String,System.ExceptionResource) | System.ObjectDisposedException | 0: ldarg.0, 1: ldarg.1, 2: call System.ThrowHelper.GetResourceString, 3: newobj System.ObjectDisposedException..ctor, 4: throw |
| System.Void System.ThrowHelper.ThrowRankException(System.ExceptionResource) | System.RankException | 0: ldarg.0, 1: call System.ThrowHelper.GetResourceString, 2: newobj System.RankException..ctor, 3: throw |
| System.Void System.ThrowHelper.ThrowSecurityException(System.ExceptionResource) | System.Security.SecurityException | 0: ldarg.0, 1: call System.ThrowHelper.GetResourceString, 2: newobj System.Security.SecurityException..ctor, 3: throw |
| System.Void System.ThrowHelper.ThrowSerializationException(System.ExceptionResource) | System.Runtime.Serialization.SerializationException | 0: ldarg.0, 1: call System.ThrowHelper.GetResourceString, 2: newobj System.Runtime.Serialization.SerializationException..ctor, 3: throw |
| System.Void System.ThrowHelper.ThrowStartIndexArgumentOutOfRange_ArgumentOutOfRange_Index() | System.ArgumentOutOfRangeException | 0: ldc.i4.s 31, 1: ldc.i4.s 31, 2: call System.ThrowHelper.GetArgumentOutOfRangeException, 3: throw |
| System.Void System.ThrowHelper.ThrowUnauthorizedAccessException(System.ExceptionResource) | System.UnauthorizedAccessException | 0: ldarg.0, 1: call System.ThrowHelper.GetResourceString, 2: newobj System.UnauthorizedAccessException..ctor, 3: throw |
| System.Void System.ThrowHelper.ThrowWrongKeyTypeArgumentException(System.Object,System.Type) | System.ArgumentException | 0: ldarg.0, 1: ldarg.1, 2: call System.ThrowHelper.GetWrongKeyTypeArgumentException, 3: throw |
| System.Void System.ThrowHelper.ThrowWrongValueTypeArgumentException(System.Object,System.Type) | System.ArgumentException | 0: ldarg.0, 1: ldarg.1, 2: call System.ThrowHelper.GetWrongValueTypeArgumentException, 3: throw |

View File

@@ -0,0 +1,38 @@
import cil
import semmle.code.cil.CallableReturns
predicate relevantMethod(CIL::Method m) {
m.getName() = "GetEncoder" and not m.getDeclaringType().getName() = "OSEncoding"
or
m.getName() = "get_Item"
or
m.getDeclaringType().getName() = "ThrowHelper"
or
m.getLocation().(CIL::Assembly).getName() = "DataFlow"
}
// Check that the assembly hasn't been marked as a stub.
query predicate stubs(string str) {
exists(CIL::Assembly asm | CIL::assemblyIsStub(asm) | str = asm.toString())
}
query predicate alwaysNull(string s, string d) {
exists(CIL::Method m |
alwaysNullMethod(m) and
s = m.toStringWithTypes() and
relevantMethod(m) and
d = m.getImplementation().getDisassembly()
)
}
query predicate alwaysNonNull(string s) {
exists(CIL::Method m | alwaysNotNullMethod(m) and s = m.toStringWithTypes() and relevantMethod(m))
}
query predicate alwaysThrows(string s, string ex, string d) {
exists(CIL::Method m, CIL::Type t | alwaysThrowsException(m, t) and relevantMethod(m) |
s = m.toStringWithTypes() and
ex = t.toStringWithTypes() and
d = m.getImplementation().getDisassembly()
)
}

View File

@@ -0,0 +1,2 @@
| dataflow.cs:57:9:57:18 | call to method DeadCode |
| dataflow.cs:65:9:65:18 | call to method DeadCode |

View File

@@ -0,0 +1,6 @@
import csharp
query predicate deadCode(MethodCall c) {
c.getTarget().getName() = "DeadCode" and
not exists(ControlFlow::Node node | node.getElement() = c)
}

View File

@@ -0,0 +1,176 @@
using System;
namespace Dataflow
{
public class NullMethods
{
public object ReturnsNull() => null;
public object ReturnsNull2()
{
var x = ReturnsNull();
return x;
}
// Does not necessarily return null because of virtual method call.
public object NotReturnsNull() => VirtualReturnsNull();
public object ReturnsNullIndirect() => ReturnsNull();
public virtual object VirtualReturnsNull() => null;
public object NullProperty { get => null; }
public virtual object VirtualNullProperty { get => null; }
}
public class NonNullMethods
{
public object ReturnsNonNull() => new object();
public object ReturnsNonNull2()
{
var x = ReturnsNonNull();
return x;
}
public object ReturnsNonNullIndirect() => ReturnsNonNull();
public object NonNullProperty { get => 1; }
public string NonNullProperty2 { get => "not null"; }
public virtual object VirtualNonNull { get => "not null"; }
public bool cond = false;
public string MaybeNull()
{
if (cond)
return null;
else
return "not null";
}
public string MaybeNull2()
{
return cond ? null : "not null";
}
public virtual object VirtualNonNullProperty { get => "non null"; }
}
public class ThrowingMethods
{
public static object AlwaysThrows() => throw new InvalidOperationException();
public object AlwaysThrowsIndirect() => AlwaysThrows();
public virtual object VirtualThrows() => throw new Exception();
public object ThrowProperty { get => throw new Exception(); }
public virtual object VirtualThrowProperty { get => throw new Exception(); }
}
public class DataFlow
{
public object Taint1(object x) => x;
public object Taint2(object x) => Taint5(x);
public string Taint3(string s)
{
var x = s;
Console.WriteLine(s);
return x;
}
public object Taint5(object x) => Taint6(x);
private object Taint6(object x) => x;
}
public class TaintFlow
{
public string Taint1(string a, string b) => a + b;
public int Taint2(int a, int b) => a + b;
public int Taint3(int a) => -a;
public string TaintIndirect(string a, string b) => Taint1(a, b);
}
public class Properties
{
public int TrivialProperty1 { get; set; }
int field;
public int TrivialProperty2
{
get => field;
set { field = value; }
}
}
public class ThisAssemblyIsNotAStub
{
public void F()
{
// Ensure that the assembly isn't tagged as a stub
// Need to bump the average instruction count.
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
Console.WriteLine("This is not a stub assembly");
}
}
}

Binary file not shown.

View File

@@ -1,7 +1,17 @@
| dataflow.cs:16:18:16:26 | "tainted" | dataflow.cs:16:18:16:37 | call to method ToString |
| dataflow.cs:17:27:17:28 | 12 | dataflow.cs:17:18:17:29 | call to method Abs |
| dataflow.cs:18:27:18:27 | 2 | dataflow.cs:18:18:18:31 | call to method Max |
| dataflow.cs:18:30:18:30 | 3 | dataflow.cs:18:18:18:31 | call to method Max |
| dataflow.cs:20:45:20:53 | "tainted" | dataflow.cs:20:18:20:54 | call to method GetFullPath |
| dataflow.cs:27:44:27:46 | 1 | dataflow.cs:27:18:27:52 | call to method IEEERemainder |
| dataflow.cs:27:49:27:51 | 2 | dataflow.cs:27:18:27:52 | call to method IEEERemainder |
| dataflow.cs:18:18:18:26 | "tainted" | dataflow.cs:18:18:18:37 | call to method ToString |
| dataflow.cs:19:27:19:28 | 12 | dataflow.cs:19:18:19:29 | call to method Abs |
| dataflow.cs:20:27:20:27 | 2 | dataflow.cs:20:18:20:31 | call to method Max |
| dataflow.cs:20:30:20:30 | 3 | dataflow.cs:20:18:20:31 | call to method Max |
| dataflow.cs:22:45:22:53 | "tainted" | dataflow.cs:22:18:22:54 | call to method GetFullPath |
| dataflow.cs:29:44:29:46 | 1 | dataflow.cs:29:18:29:52 | call to method IEEERemainder |
| dataflow.cs:29:49:29:51 | 2 | dataflow.cs:29:18:29:52 | call to method IEEERemainder |
| dataflow.cs:40:34:40:37 | "d1" | dataflow.cs:40:18:40:38 | call to method Taint1 |
| dataflow.cs:41:34:41:37 | "d2" | dataflow.cs:41:18:41:38 | call to method Taint2 |
| dataflow.cs:42:34:42:37 | "d3" | dataflow.cs:42:18:42:38 | call to method Taint3 |
| dataflow.cs:46:28:46:32 | "t1a" | dataflow.cs:46:18:46:40 | call to method Taint1 |
| dataflow.cs:46:35:46:39 | "t1b" | dataflow.cs:46:18:46:40 | call to method Taint1 |
| dataflow.cs:49:35:49:38 | "t6" | dataflow.cs:49:18:49:45 | call to method TaintIndirect |
| dataflow.cs:49:41:49:44 | "t6" | dataflow.cs:49:18:49:45 | call to method TaintIndirect |
| dataflow.cs:95:30:95:33 | null | dataflow.cs:89:24:89:51 | ... ? ... : ... |
| dataflow.cs:95:30:95:33 | null | dataflow.cs:101:20:101:33 | call to method IndirectNull |
| dataflow.cs:102:23:102:26 | null | dataflow.cs:89:24:89:51 | ... ? ... : ... |

View File

@@ -0,0 +1,32 @@
alwaysNull
| dataflow.cs:70:21:70:35 | default(...) |
| dataflow.cs:74:21:74:34 | call to method NullFunction |
| dataflow.cs:74:39:74:52 | call to method IndirectNull |
| dataflow.cs:78:21:78:45 | call to method ReturnsNull |
| dataflow.cs:79:21:79:46 | call to method ReturnsNull2 |
| dataflow.cs:80:21:80:44 | access to property NullProperty |
| dataflow.cs:89:31:89:44 | call to method NullFunction |
alwaysNotNull
| dataflow.cs:71:24:71:35 | default(...) |
| dataflow.cs:72:27:72:30 | this access |
| dataflow.cs:72:27:72:40 | call to method GetType |
| dataflow.cs:73:30:73:33 | true |
| dataflow.cs:73:30:73:44 | call to method ToString |
| dataflow.cs:74:21:74:34 | this access |
| dataflow.cs:74:39:74:52 | this access |
| dataflow.cs:77:27:77:52 | object creation of type NullMethods |
| dataflow.cs:78:21:78:31 | access to local variable nullMethods |
| dataflow.cs:79:21:79:31 | access to local variable nullMethods |
| dataflow.cs:80:21:80:31 | access to local variable nullMethods |
| dataflow.cs:83:23:83:51 | object creation of type NonNullMethods |
| dataflow.cs:84:24:84:30 | access to local variable nonNull |
| dataflow.cs:84:24:84:47 | call to method ReturnsNonNull |
| dataflow.cs:85:24:85:30 | access to local variable nonNull |
| dataflow.cs:85:24:85:55 | call to method ReturnsNonNullIndirect |
| dataflow.cs:86:24:86:30 | access to local variable nonNull |
| dataflow.cs:89:24:89:27 | this access |
| dataflow.cs:89:31:89:44 | this access |
| dataflow.cs:89:48:89:51 | this access |
| dataflow.cs:90:24:90:34 | access to local variable nullMethods |
| dataflow.cs:91:24:91:34 | access to local variable nullMethods |
| dataflow.cs:92:26:92:32 | access to local variable nonNull |

View File

@@ -0,0 +1,10 @@
import csharp
import semmle.code.csharp.dataflow.Nullness
query predicate alwaysNull(AlwaysNullExpr expr) {
expr.getEnclosingCallable().getName() = "Nullness"
}
query predicate alwaysNotNull(NonNullExpr expr) {
expr.getEnclosingCallable().getName() = "Nullness"
}

View File

@@ -1,13 +1,28 @@
| dataflow.cs:12:18:12:22 | "123" | dataflow.cs:12:18:12:37 | call to method CompareTo |
| dataflow.cs:12:34:12:36 | "b" | dataflow.cs:12:18:12:37 | call to method CompareTo |
| dataflow.cs:16:18:16:26 | "tainted" | dataflow.cs:16:18:16:37 | call to method ToString |
| dataflow.cs:17:27:17:28 | 12 | dataflow.cs:17:18:17:29 | call to method Abs |
| dataflow.cs:18:27:18:27 | 2 | dataflow.cs:18:18:18:31 | call to method Max |
| dataflow.cs:18:30:18:30 | 3 | dataflow.cs:18:18:18:31 | call to method Max |
| dataflow.cs:20:45:20:53 | "tainted" | dataflow.cs:20:18:20:54 | call to method GetFullPath |
| dataflow.cs:24:37:24:37 | 1 | dataflow.cs:24:18:24:56 | call to method DivRem |
| dataflow.cs:24:40:24:40 | 2 | dataflow.cs:24:18:24:56 | call to method DivRem |
| dataflow.cs:27:44:27:46 | 1 | dataflow.cs:27:18:27:52 | call to method IEEERemainder |
| dataflow.cs:27:49:27:51 | 2 | dataflow.cs:27:18:27:52 | call to method IEEERemainder |
| dataflow.cs:30:60:30:60 | 1 | dataflow.cs:30:18:30:80 | call to method DivRem |
| dataflow.cs:30:63:30:63 | 2 | dataflow.cs:30:18:30:80 | call to method DivRem |
| dataflow.cs:11:18:11:22 | "123" | dataflow.cs:11:18:11:37 | call to method CompareTo |
| dataflow.cs:11:34:11:36 | "b" | dataflow.cs:11:18:11:37 | call to method CompareTo |
| dataflow.cs:18:18:18:26 | "tainted" | dataflow.cs:18:18:18:37 | call to method ToString |
| dataflow.cs:19:27:19:28 | 12 | dataflow.cs:19:18:19:29 | call to method Abs |
| dataflow.cs:20:27:20:27 | 2 | dataflow.cs:20:18:20:31 | call to method Max |
| dataflow.cs:20:30:20:30 | 3 | dataflow.cs:20:18:20:31 | call to method Max |
| dataflow.cs:22:45:22:53 | "tainted" | dataflow.cs:22:18:22:54 | call to method GetFullPath |
| dataflow.cs:26:37:26:37 | 1 | dataflow.cs:26:18:26:56 | call to method DivRem |
| dataflow.cs:26:40:26:40 | 2 | dataflow.cs:26:18:26:56 | call to method DivRem |
| dataflow.cs:29:44:29:46 | 1 | dataflow.cs:29:18:29:52 | call to method IEEERemainder |
| dataflow.cs:29:49:29:51 | 2 | dataflow.cs:29:18:29:52 | call to method IEEERemainder |
| dataflow.cs:32:60:32:60 | 1 | dataflow.cs:32:18:32:80 | call to method DivRem |
| dataflow.cs:32:63:32:63 | 2 | dataflow.cs:32:18:32:80 | call to method DivRem |
| dataflow.cs:40:34:40:37 | "d1" | dataflow.cs:40:18:40:38 | call to method Taint1 |
| dataflow.cs:41:34:41:37 | "d2" | dataflow.cs:41:18:41:38 | call to method Taint2 |
| dataflow.cs:42:34:42:37 | "d3" | dataflow.cs:42:18:42:38 | call to method Taint3 |
| dataflow.cs:46:28:46:32 | "t1a" | dataflow.cs:46:18:46:40 | call to method Taint1 |
| dataflow.cs:46:35:46:39 | "t1b" | dataflow.cs:46:18:46:40 | call to method Taint1 |
| dataflow.cs:47:28:47:28 | 2 | dataflow.cs:47:18:47:32 | call to method Taint2 |
| dataflow.cs:47:31:47:31 | 3 | dataflow.cs:47:18:47:32 | call to method Taint2 |
| dataflow.cs:48:28:48:28 | 1 | dataflow.cs:48:18:48:29 | call to method Taint3 |
| dataflow.cs:49:35:49:38 | "t6" | dataflow.cs:49:18:49:45 | call to method TaintIndirect |
| dataflow.cs:49:41:49:44 | "t6" | dataflow.cs:49:18:49:45 | call to method TaintIndirect |
| dataflow.cs:95:30:95:33 | null | dataflow.cs:74:21:74:52 | ... ?? ... |
| dataflow.cs:95:30:95:33 | null | dataflow.cs:89:24:89:51 | ... ? ... : ... |
| dataflow.cs:95:30:95:33 | null | dataflow.cs:101:20:101:33 | call to method IndirectNull |
| dataflow.cs:102:23:102:26 | null | dataflow.cs:74:21:74:52 | ... ?? ... |
| dataflow.cs:102:23:102:26 | null | dataflow.cs:89:24:89:51 | ... ? ... : ... |

View File

@@ -1,3 +1,5 @@
| Dataflow.Properties.TrivialProperty1 |
| Dataflow.Properties.TrivialProperty2 |
| System.Collections.DictionaryEntry.Key |
| System.Collections.DictionaryEntry.Value |
| System.Reflection.AssemblyName.CodeBase |

View File

@@ -5,4 +5,6 @@ where
prop.getDeclaringType().hasQualifiedName("System.Reflection.AssemblyName")
or
prop.getDeclaringType().hasQualifiedName("System.Collections.DictionaryEntry")
or
prop.getDeclaringType().hasQualifiedName("Dataflow.Properties")
select prop.getQualifiedName()

View File

@@ -6,12 +6,14 @@ class Test
{
static void Main(string[] args)
{
// Indirect call to method
var c1 = "abc".Contains("a"); // Calls string.IndexOf()
var c2 = "123".CompareTo("b"); // Calls string.Compare()
var c3 = Tuple.Create("c", "d", "e"); // Calls Tuple constructor
}
void DataFlowThroughFramework()
{
// Dataflow through call
var f1 = "tainted".ToString();
var f2 = Math.Abs(12);
@@ -30,4 +32,74 @@ class Test
var m1 = System.Math.DivRem(Math.Abs(-1), Math.Max(1, 2), out remainder);
var m2 = "tainted".ToString().Contains("t");
}
void DataFlowThroughAssembly()
{
// Dataflow through test assembly
var dataflow = new Dataflow.DataFlow();
var d1 = dataflow.Taint1("d1");
var d2 = dataflow.Taint2("d2");
var d3 = dataflow.Taint3("d3");
// Taint tracking
var tt = new Dataflow.TaintFlow();
var t1 = tt.Taint1("t1a", "t1b");
var t2 = tt.Taint2(2, 3);
var t3 = tt.Taint3(1);
var t4 = tt.TaintIndirect("t6", "t6");
}
void DeadCode() { }
void CilAlwaysThrows()
{
System.Reflection.Assembly.LoadFrom("", null, System.Configuration.Assemblies.AssemblyHashAlgorithm.SHA1); // Throws NotSupportedException
DeadCode();
}
void Throw() => throw new InvalidCastException();
void CsAlwaysThrows()
{
Throw();
DeadCode();
}
void Nullness()
{
var @null = default(object);
var nonNull1 = default(int);
var nullFromCil = this.GetType().DeclaringMethod;
var nonNullFromCil = true.ToString();
var null2 = NullFunction() ?? IndirectNull();
// Null from dataflow assembly
var nullMethods = new Dataflow.NullMethods();
var null3 = nullMethods.ReturnsNull(); // Null
var null4 = nullMethods.ReturnsNull2();
var null5 = nullMethods.NullProperty;
// NotNull
var nonNull = new Dataflow.NonNullMethods();
var nonNull2 = nonNull.ReturnsNonNull();
var nonNull3 = nonNull.ReturnsNonNullIndirect();
var nonNull4 = nonNull.NonNullProperty;
// The following are not always null:
var notNull1 = cond ? NullFunction() : this;
var notNull2 = nullMethods.VirtualReturnsNull();
var notNull3 = nullMethods.VirtualNullProperty;
var notNonNull = nonNull.VirtualNonNull;
}
object IndirectNull() => null;
bool cond;
object NullFunction()
{
object x = IndirectNull();
if (cond) x = null;
return x;
}
}

View File

@@ -31,11 +31,11 @@
| C:/dev/projects/Sandbox/PortablePdb/Class1.cs:10:4:10:19 | 24: br.s 25: |
| C:/dev/projects/Sandbox/PortablePdb/Class1.cs:11:3:11:4 | 25: ldloc.3 |
| C:/dev/projects/Sandbox/PortablePdb/Class1.cs:11:3:11:4 | 26: ret |
| EmbeddedPdb, Version=1.0.0.0, Culture=neutral | 0: ldarg.0 |
| EmbeddedPdb, Version=1.0.0.0, Culture=neutral | 1: call System.Object..ctor |
| EmbeddedPdb, Version=1.0.0.0, Culture=neutral | 2: nop |
| EmbeddedPdb, Version=1.0.0.0, Culture=neutral | 3: ret |
| PortablePdb, Version=1.0.0.0, Culture=neutral | 0: ldarg.0 |
| PortablePdb, Version=1.0.0.0, Culture=neutral | 1: call System.Object..ctor |
| PortablePdb, Version=1.0.0.0, Culture=neutral | 2: nop |
| PortablePdb, Version=1.0.0.0, Culture=neutral | 3: ret |
| EmbeddedPdb, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null | 0: ldarg.0 |
| EmbeddedPdb, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null | 1: call System.Object..ctor |
| EmbeddedPdb, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null | 2: nop |
| EmbeddedPdb, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null | 3: ret |
| PortablePdb, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null | 0: ldarg.0 |
| PortablePdb, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null | 1: call System.Object..ctor |
| PortablePdb, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null | 2: nop |
| PortablePdb, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null | 3: ret |

View File

@@ -1,4 +1,4 @@
| System.Int32 EmbeddedPdb.Class1.Method() | C:/dev/projects/Sandbox/EmbeddedPdb/Class1.cs:6:3:6:4 | true |
| System.Int32 EmbeddedPdb.Class1.Method() | EmbeddedPdb, Version=1.0.0.0, Culture=neutral | false |
| System.Int32 EmbeddedPdb.Class1.Method() | EmbeddedPdb, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null | false |
| System.Int32 PortablePdb.Class1.Factorial(System.Int32) | C:/dev/projects/Sandbox/PortablePdb/Class1.cs:6:3:6:4 | true |
| System.Int32 PortablePdb.Class1.Factorial(System.Int32) | PortablePdb, Version=1.0.0.0, Culture=neutral | false |
| System.Int32 PortablePdb.Class1.Factorial(System.Int32) | PortablePdb, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null | false |

View File

@@ -0,0 +1,2 @@
| EmbeddedPdb.dll:0:0:0:0 | EmbeddedPdb, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null |
| PdbOnly.dll:0:0:0:0 | PdbOnly, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null |

View File

@@ -0,0 +1,5 @@
import cil::CIL
from Assembly asm
where assemblyIsStub(asm)
select asm

View File

@@ -0,0 +1 @@
// semmle-extractor-options: --cil

View File

@@ -952,6 +952,8 @@
| D.cs:212:18:212:18 | access to local variable n | null | D.cs:211:20:211:23 | null | null |
| D.cs:212:18:212:26 | ... == ... | false | D.cs:212:18:212:18 | access to local variable n | non-null |
| D.cs:212:18:212:26 | ... == ... | true | D.cs:212:18:212:18 | access to local variable n | null |
| D.cs:212:18:212:45 | ... ? ... : ... | non-null | D.cs:212:18:212:26 | ... == ... | true |
| D.cs:212:18:212:45 | ... ? ... : ... | non-null | D.cs:212:30:212:41 | object creation of type Object | non-null |
| D.cs:212:18:212:45 | ... ? ... : ... | null | D.cs:212:18:212:26 | ... == ... | false |
| D.cs:212:18:212:45 | ... ? ... : ... | null | D.cs:212:45:212:45 | access to local variable n | null |
| D.cs:212:45:212:45 | access to local variable n | non-null | D.cs:211:20:211:23 | null | non-null |