Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit f6828fa

Browse files
authored
Merge pull request #1053 from hvitved/csharp/dispatch-tweak
C#: `Dispatch.qll` performance tweaks
2 parents 9dccd9f + 7825642 commit f6828fa

13 files changed

Lines changed: 78 additions & 63 deletions

File tree

csharp/extractor/Semmle.Util/FileUtils.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ public static void TryDelete(string file)
5757
/// Finds the path for the program <paramref name="prog"/> based on the
5858
/// <code>PATH</code> environment variable, and in the case of Windows the
5959
/// <code>PATHEXT</code> environment variable.
60-
///
60+
///
6161
/// Returns <code>null</code> of no path can be found.
6262
/// </summary>
6363
public static string FindProgramOnPath(string prog)

csharp/ql/src/Security Features/CWE-134/UncontrolledFormatStringBad.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ public class HttpHandler : IHttpHandler
77
public void ProcessRequest(HttpContext ctx)
88
{
99
string format = ctx.Request.QueryString["nameformat"];
10-
10+
1111
// BAD: Uncontrolled format string.
1212
FormattedName = string.Format(format, Surname, Forenames);
1313
}

csharp/ql/src/semmle/code/csharp/dispatch/Dispatch.qll

Lines changed: 52 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -222,27 +222,55 @@ private module Internal {
222222
}
223223
}
224224

225-
private class FieldOrProperty extends Assignable {
226-
FieldOrProperty() {
227-
this instanceof Field or
228-
this instanceof Property
225+
private class DynamicFieldOrProperty extends Assignable {
226+
DynamicFieldOrProperty() {
227+
(
228+
this instanceof Field or
229+
this instanceof Property
230+
) and
231+
this.getName() = any(DynamicMemberAccess dma).getLateBoundTargetName()
232+
}
233+
234+
predicate isMemberOf(string name, ValueOrRefType t) {
235+
name = this.getName() and t.hasMember(this)
236+
}
237+
}
238+
239+
private class TypeWithDynamicFieldOrProperty extends ValueOrRefType {
240+
DynamicFieldOrProperty fp;
241+
242+
TypeWithDynamicFieldOrProperty() { fp.isMemberOf(_, this) }
243+
244+
predicate isImplicitlyConvertibleTo(string name, Type t) {
245+
name = fp.getName() and
246+
this.isImplicitlyConvertibleTo(t)
229247
}
230248
}
231249

250+
pragma[noinline]
251+
private predicate isPossibleDynamicMemberAccessQualifierType(
252+
DynamicMemberAccess dma, string name, TypeWithDynamicFieldOrProperty t
253+
) {
254+
exists(Type qt, boolean isExact |
255+
qt = getAPossibleType(dma.getQualifier(), isExact) and
256+
name = dma.getLateBoundTargetName()
257+
|
258+
isExact = true and t = qt
259+
or
260+
isExact = false and t.isImplicitlyConvertibleTo(name, qt)
261+
)
262+
}
263+
232264
/**
233265
* Gets a possible type for expression `e`. Simple flow is used to track the
234266
* origin of `e`, and in case `e` is a dynamic member access, only types
235267
* corresponding to the type of a relevant field or property are included.
236268
*/
237269
private Type getAPossibleType(Expr e, boolean isExact) {
238-
exists(ValueOrRefType qualifierType, FieldOrProperty fp, boolean qualifierTypeIsExact |
239-
qualifierType = getAPossibleTypeDynamicMemberAccessQualifier(e, qualifierTypeIsExact, fp)
270+
exists(DynamicFieldOrProperty fp, string name, TypeWithDynamicFieldOrProperty t |
271+
isPossibleDynamicMemberAccessQualifierType(e, name, t) and
272+
fp.isMemberOf(name, t)
240273
|
241-
(
242-
if qualifierTypeIsExact = true
243-
then qualifierType.hasMember(fp)
244-
else fp.getDeclaringType().isImplicitlyConvertibleTo(qualifierType)
245-
) and
246274
result = fp.getType() and
247275
isExact = false
248276
)
@@ -251,13 +279,6 @@ private module Internal {
251279
result = getASourceType(e, isExact)
252280
}
253281

254-
private Type getAPossibleTypeDynamicMemberAccessQualifier(
255-
DynamicMemberAccess dma, boolean isExact, FieldOrProperty fp
256-
) {
257-
result = getAPossibleType(dma.getQualifier(), isExact) and
258-
fp.getName() = dma.getLateBoundTargetName()
259-
}
260-
261282
/**
262283
* Provides the predicate `getASourceType()` for finding all relevant source
263284
* types for a given expression.
@@ -799,22 +820,14 @@ private module Internal {
799820
// conflicting types (for example, `Tuple<int, string>` is considered
800821
// compatible with `Tuple<T, T>`).
801822
override RuntimeCallable getADynamicTarget() {
802-
// Condition 1
803-
result = getADynamicTargetCandidate() and
804-
// Condition 2
805-
forall(int i | i in [0 .. getNumberOfArguments() - 1] |
806-
result = getADynamicTargetCandidateWithCompatibleArg(i)
807-
)
808-
}
809-
810-
private RuntimeCallable getADynamicTargetCandidateWithCompatibleArg(int i) {
811-
result = getADynamicTargetCandidateWithCompatibleArg1(i) or
812-
result = getADynamicTargetCandidateWithCompatibleArg2(i)
823+
result = this.getADynamicTarget(this.getNumberOfArguments() - 1)
813824
}
814825

815-
pragma[noinline]
816-
private RuntimeCallable getADynamicTargetCandidateWithCompatibleArg1(int i) {
817-
result = this.getADynamicTargetCandidate() and
826+
private RuntimeCallable getADynamicTarget(int i) {
827+
i = -1 and
828+
result = this.getADynamicTargetCandidate()
829+
or
830+
result = this.getADynamicTarget(i - 1) and
818831
exists(Type parameterType, Type argumentType |
819832
parameterType = this.getAParameterType(result, i) and
820833
argumentType = getAPossibleType(this.getArgument(i), _)
@@ -827,6 +840,12 @@ private module Internal {
827840
or
828841
reflectionOrDynamicArgEqualsParamModuloTypeParameters(argumentType, parameterType)
829842
)
843+
or
844+
result = this.getADynamicTarget(i - 1) and
845+
exists(Type parameterType, Type t | parameterType = this.getAParameterType(result, i) |
846+
this.argumentConvConstExpr(i, t) and
847+
t.isImplicitlyConvertibleTo(parameterType)
848+
)
830849
}
831850

832851
private Type getAParameterType(RuntimeCallable c, int i) {
@@ -840,15 +859,6 @@ private module Internal {
840859
)
841860
}
842861

843-
pragma[noinline]
844-
private RuntimeCallable getADynamicTargetCandidateWithCompatibleArg2(int i) {
845-
result = this.getADynamicTargetCandidate() and
846-
exists(Type parameterType, Type t | parameterType = this.getAParameterType(result, i) |
847-
this.argumentConvConstExpr(i, t) and
848-
t.isImplicitlyConvertibleTo(parameterType)
849-
)
850-
}
851-
852862
pragma[noinline]
853863
private predicate argumentConvConstExpr(int i, Type t) {
854864
convConstantExpr(this.getArgument(i), t)
@@ -954,7 +964,7 @@ private module Internal {
954964
*/
955965
private predicate isReflectionOrDynamicCallArgumentWithTypeParameters(Type argType, Type paramType) {
956966
exists(DispatchReflectionOrDynamicCall call, Parameter p, int i, int j |
957-
p = call.getAStaticTarget().getParameter(i) and
967+
p = call.getADynamicTargetCandidate().getParameter(i) and
958968
(
959969
if p.isParams()
960970
then (

csharp/ql/src/semmle/code/csharp/exprs/Expr.qll

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,14 @@ class QualifiableExpr extends Expr, @qualifiable_expr {
654654
predicate isConditional() { conditional_access(this) }
655655
}
656656

657+
private Expr getAnAssignOrForeachChild() {
658+
result = any(AssignExpr e).getLValue()
659+
or
660+
result = any(ForeachStmt fs).getVariableDeclTuple()
661+
or
662+
result = getAnAssignOrForeachChild().getAChildExpr()
663+
}
664+
657665
/**
658666
* An expression representing a tuple, for example
659667
* `(1, 2)` on line 2 or `(var x, var y)` on line 5 in
@@ -678,10 +686,7 @@ class TupleExpr extends Expr, @tuple_expr {
678686
Expr getAnArgument() { result = getArgument(_) }
679687

680688
/** Holds if this tuple is a read access. */
681-
predicate isReadAccess() {
682-
not exists(AssignExpr e | this = e.getLValue().getAChildExpr*()) and
683-
not exists(ForeachStmt fs | this = fs.getVariableDeclTuple().getAChildExpr*())
684-
}
689+
predicate isReadAccess() { not this = getAnAssignOrForeachChild() }
685690
}
686691

687692
/**

csharp/ql/test/library-tests/controlflow/splits/SplittingStressTest.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,4 +166,4 @@ void M(bool b1, bool b2, bool b3, bool b4, bool b5, bool b6, bool b7, bool b8, b
166166
;
167167
;
168168
}
169-
}
169+
}

csharp/ql/test/query-tests/Concurrency/UnsafeLazyInitialization/UnsafeLazyInitialization.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ void Fn()
4444
{
4545
if (obj2 == null)
4646
{
47-
obj2 = null;
47+
obj2 = null;
4848
}
4949
}
5050
}

csharp/ql/test/query-tests/Security Features/CWE-094/CodeInjection.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,6 @@ public bool IsReusable
5555
void OnButtonClicked()
5656
{
5757
// BAD: Use the Roslyn APIs to dynamically evaluate C#
58-
CSharpScript.EvaluateAsync(box1.Text);
58+
CSharpScript.EvaluateAsync(box1.Text);
5959
}
6060
}

csharp/ql/test/query-tests/Security Features/CWE-094/CodeInjection.expected

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ nodes
55
| CodeInjection.cs:25:23:25:45 | access to property QueryString |
66
| CodeInjection.cs:31:64:31:67 | access to local variable code |
77
| CodeInjection.cs:42:36:42:39 | access to local variable code |
8-
| CodeInjection.cs:58:33:58:41 | access to property Text |
8+
| CodeInjection.cs:58:36:58:44 | access to property Text |
99
#select
1010
| CodeInjection.cs:31:64:31:67 | access to local variable code | CodeInjection.cs:25:23:25:45 | access to property QueryString | CodeInjection.cs:31:64:31:67 | access to local variable code | $@ flows to here and is compiled as code. | CodeInjection.cs:25:23:25:45 | access to property QueryString | User-provided value |
1111
| CodeInjection.cs:42:36:42:39 | access to local variable code | CodeInjection.cs:25:23:25:45 | access to property QueryString | CodeInjection.cs:42:36:42:39 | access to local variable code | $@ flows to here and is compiled as code. | CodeInjection.cs:25:23:25:45 | access to property QueryString | User-provided value |
12-
| CodeInjection.cs:58:33:58:41 | access to property Text | CodeInjection.cs:58:33:58:41 | access to property Text | CodeInjection.cs:58:33:58:41 | access to property Text | $@ flows to here and is compiled as code. | CodeInjection.cs:58:33:58:41 | access to property Text | User-provided value |
12+
| CodeInjection.cs:58:36:58:44 | access to property Text | CodeInjection.cs:58:36:58:44 | access to property Text | CodeInjection.cs:58:36:58:44 | access to property Text | $@ flows to here and is compiled as code. | CodeInjection.cs:58:36:58:44 | access to property Text | User-provided value |

csharp/ql/test/query-tests/Security Features/CWE-134/UncontrolledFormatString.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,16 @@ public class TaintedPathHandler : IHttpHandler
99
public void ProcessRequest(HttpContext ctx)
1010
{
1111
String path = ctx.Request.QueryString["page"];
12-
12+
1313
// BAD: Uncontrolled format string.
1414
String.Format(path, "Do not do this");
15-
15+
1616
// BAD: Using an IFormatProvider.
1717
String.Format((IFormatProvider)null, path, "Do not do this");
1818

1919
// GOOD: Not the format string.
2020
String.Format("Do not do this", path);
21-
21+
2222
// GOOD: Not the format string.
2323
String.Format((IFormatProvider)null, "Do not do this", path);
2424
}
@@ -27,7 +27,7 @@ public void ProcessRequest(HttpContext ctx)
2727

2828
void OnButtonClicked()
2929
{
30-
// BAD: Uncontrolled format string.
31-
String.Format(box1.Text, "Do not do this");
30+
// BAD: Uncontrolled format string.
31+
String.Format(box1.Text, "Do not do this");
3232
}
3333
}

csharp/ql/test/query-tests/Security Features/CWE-134/UncontrolledFormatString.expected

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@ nodes
88
| UncontrolledFormatString.cs:17:46:17:49 | access to local variable path |
99
| UncontrolledFormatString.cs:20:23:20:38 | "Do not do this" |
1010
| UncontrolledFormatString.cs:23:46:23:61 | "Do not do this" |
11-
| UncontrolledFormatString.cs:31:20:31:28 | access to property Text |
11+
| UncontrolledFormatString.cs:31:23:31:31 | access to property Text |
1212
| UncontrolledFormatStringBad.cs:9:25:9:47 | access to property QueryString |
1313
| UncontrolledFormatStringBad.cs:12:39:12:44 | access to local variable format |
1414
#select
1515
| UncontrolledFormatString.cs:14:23:14:26 | access to local variable path | UncontrolledFormatString.cs:11:23:11:45 | access to property QueryString | UncontrolledFormatString.cs:14:23:14:26 | access to local variable path | $@ flows to here and is used as a format string. | UncontrolledFormatString.cs:11:23:11:45 | access to property QueryString | access to property QueryString |
1616
| UncontrolledFormatString.cs:17:46:17:49 | access to local variable path | UncontrolledFormatString.cs:11:23:11:45 | access to property QueryString | UncontrolledFormatString.cs:17:46:17:49 | access to local variable path | $@ flows to here and is used as a format string. | UncontrolledFormatString.cs:11:23:11:45 | access to property QueryString | access to property QueryString |
17-
| UncontrolledFormatString.cs:31:20:31:28 | access to property Text | UncontrolledFormatString.cs:31:20:31:28 | access to property Text | UncontrolledFormatString.cs:31:20:31:28 | access to property Text | $@ flows to here and is used as a format string. | UncontrolledFormatString.cs:31:20:31:28 | access to property Text | access to property Text |
17+
| UncontrolledFormatString.cs:31:23:31:31 | access to property Text | UncontrolledFormatString.cs:31:23:31:31 | access to property Text | UncontrolledFormatString.cs:31:23:31:31 | access to property Text | $@ flows to here and is used as a format string. | UncontrolledFormatString.cs:31:23:31:31 | access to property Text | access to property Text |
1818
| UncontrolledFormatStringBad.cs:12:39:12:44 | access to local variable format | UncontrolledFormatStringBad.cs:9:25:9:47 | access to property QueryString | UncontrolledFormatStringBad.cs:12:39:12:44 | access to local variable format | $@ flows to here and is used as a format string. | UncontrolledFormatStringBad.cs:9:25:9:47 | access to property QueryString | access to property QueryString |

0 commit comments

Comments
 (0)