mirror of
https://github.com/github/codeql.git
synced 2026-06-23 13:47:03 +02:00
Compare commits
1 Commits
main
...
copilot/up
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5310accfba |
File diff suppressed because it is too large
Load Diff
@@ -25,7 +25,7 @@ namespace Semmle.Extraction.CSharp.Entities.Statements
|
||||
{
|
||||
var type = Type.Create(Context, Context.GetType(Stmt.Declaration!.Type));
|
||||
trapFile.catch_type(this, type.TypeRef, true);
|
||||
TypeMention.Create(Context, Stmt.Declaration!.Type, this, type);
|
||||
Expression.Create(Context, Stmt.Declaration!.Type, this, 0);
|
||||
}
|
||||
else // A catch clause of the form 'catch { ... }'
|
||||
{
|
||||
|
||||
@@ -995,6 +995,23 @@ class SpecificCatchClause extends CatchClause {
|
||||
/** Gets the local variable declaration of this catch clause, if any. */
|
||||
LocalVariableDeclExpr getVariableDeclExpr() { result.getParent() = this }
|
||||
|
||||
/**
|
||||
* Gets the type access of this catch clause, if it has no variable declaration.
|
||||
*
|
||||
* For example, the type access in
|
||||
*
|
||||
* ```csharp
|
||||
* try { ... }
|
||||
* catch (IOException) { ... }
|
||||
* ```
|
||||
*
|
||||
* is `IOException`.
|
||||
*/
|
||||
TypeAccess getTypeAccess() {
|
||||
not exists(this.getVariableDeclExpr()) and
|
||||
result = this.getChild(0)
|
||||
}
|
||||
|
||||
override string toString() { result = "catch (...) {...}" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "SpecificCatchClause" }
|
||||
|
||||
@@ -90,6 +90,7 @@ module Ast implements AstSig<Location> {
|
||||
private AstNode getStmtChild0(Stmt s, int i) {
|
||||
not s instanceof FixedStmt and
|
||||
not s instanceof UsingBlockStmt and
|
||||
not skipControlFlow(result) and
|
||||
result = s.getChild(i)
|
||||
or
|
||||
s =
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The C# extractor now extracts the exception type in a `catch(ExceptionType)` clause (without a variable) as a `TypeAccess` expression instead of a `TypeMention`. The new `SpecificCatchClause.getTypeAccess()` predicate provides access to this expression.
|
||||
@@ -101,7 +101,8 @@ csharp6.cs:
|
||||
# 32| 0: [IntLiteral] 2
|
||||
# 32| 0: [IntLiteral] 1
|
||||
# 34| 1: [SpecificCatchClause] catch (...) {...}
|
||||
# 34| 0: [TypeMention] IndexOutOfRangeException
|
||||
# 34| 0: [TypeAccess] access to type IndexOutOfRangeException
|
||||
# 34| 0: [TypeMention] IndexOutOfRangeException
|
||||
# 35| 1: [BlockStmt] {...}
|
||||
# 34| 2: [EQExpr] ... == ...
|
||||
# 34| 0: [PropertyCall] access to property Value
|
||||
|
||||
@@ -1 +1 @@
|
||||
| statements.cs:234:13:237:13 | checked {...} | statements.cs:235:13:237:13 | {...} |
|
||||
| statements.cs:250:13:253:13 | checked {...} | statements.cs:251:13:253:13 | {...} |
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
| fixed.cs:3:7:3:11 | {...} | fixed.cs:3:7:3:11 | Fixed |
|
||||
| statements.cs:8:11:8:15 | {...} | statements.cs:8:11:8:15 | Class |
|
||||
| statements.cs:244:15:244:25 | {...} | statements.cs:244:15:244:25 | AccountLock |
|
||||
| statements.cs:260:15:260:25 | {...} | statements.cs:260:15:260:25 | AccountLock |
|
||||
|
||||
@@ -1 +1 @@
|
||||
| statements.cs:273:21:273:31 | MainLabeled | statements.cs:276:9:276:13 | Label: |
|
||||
| statements.cs:289:21:289:31 | MainLabeled | statements.cs:292:9:292:13 | Label: |
|
||||
|
||||
@@ -1 +1 @@
|
||||
| statements.cs:249:17:256:17 | lock (...) {...} | statements.cs:249:23:249:26 | this access | statements.cs:250:17:256:17 | {...} |
|
||||
| statements.cs:265:17:272:17 | lock (...) {...} | statements.cs:265:23:265:26 | this access | statements.cs:266:17:272:17 | {...} |
|
||||
|
||||
@@ -1 +1 @@
|
||||
| statements.cs:285:13:288:13 | lock (...) {...} | statements.cs:285:19:285:28 | access to field lockObject | Lock | statements.cs:286:13:288:13 | {...} |
|
||||
| statements.cs:301:13:304:13 | lock (...) {...} | statements.cs:301:19:301:28 | access to field lockObject | Lock | statements.cs:302:13:304:13 | {...} |
|
||||
|
||||
@@ -603,115 +603,147 @@ statements.cs:
|
||||
# 223| -1: [TypeAccess] access to type Console
|
||||
# 223| 0: [TypeMention] Console
|
||||
# 223| 0: [StringLiteralUtf16] "Exception"
|
||||
# 231| 27: [Method] MainCheckedUnchecked
|
||||
# 231| 27: [Method] MainTryCatchNoVar
|
||||
# 231| -1: [TypeMention] Void
|
||||
#-----| 2: (Parameters)
|
||||
# 231| 0: [Parameter] args
|
||||
# 231| -1: [TypeMention] String[]
|
||||
# 231| 1: [TypeMention] string
|
||||
# 232| 4: [BlockStmt] {...}
|
||||
# 233| 0: [LocalVariableDeclStmt] ... ...;
|
||||
# 233| 0: [LocalVariableDeclAndInitExpr] Int32 i = ...
|
||||
# 233| -1: [TypeMention] int
|
||||
# 233| 0: [LocalVariableAccess] access to local variable i
|
||||
# 233| 1: [MemberConstantAccess] access to constant MaxValue
|
||||
# 233| -1: [TypeAccess] access to type Int32
|
||||
# 233| 0: [TypeMention] int
|
||||
# 234| 1: [CheckedStmt] checked {...}
|
||||
# 235| 0: [BlockStmt] {...}
|
||||
# 236| 0: [ExprStmt] ...;
|
||||
# 236| 0: [MethodCall] call to method WriteLine
|
||||
# 236| -1: [TypeAccess] access to type Console
|
||||
# 236| 0: [TypeMention] Console
|
||||
# 236| 0: [AddExpr] ... + ...
|
||||
# 236| 0: [LocalVariableAccess] access to local variable i
|
||||
# 236| 1: [IntLiteral] 1
|
||||
# 238| 2: [UncheckedStmt] unchecked {...}
|
||||
# 239| 0: [BlockStmt] {...}
|
||||
# 240| 0: [ExprStmt] ...;
|
||||
# 240| 0: [MethodCall] call to method WriteLine
|
||||
# 240| -1: [TypeAccess] access to type Console
|
||||
# 240| 0: [TypeMention] Console
|
||||
# 240| 0: [AddExpr] ... + ...
|
||||
# 240| 0: [LocalVariableAccess] access to local variable i
|
||||
# 240| 1: [IntLiteral] 1
|
||||
# 244| 28: [Class] AccountLock
|
||||
# 246| 6: [Field] balance
|
||||
# 246| -1: [TypeMention] decimal
|
||||
# 247| 7: [Method] Withdraw
|
||||
# 247| -1: [TypeMention] Void
|
||||
# 233| 0: [TryStmt] try {...} ...
|
||||
# 234| 0: [BlockStmt] {...}
|
||||
# 235| 0: [ExprStmt] ...;
|
||||
# 235| 0: [MethodCall] call to method WriteLine
|
||||
# 235| -1: [TypeAccess] access to type Console
|
||||
# 235| 0: [TypeMention] Console
|
||||
# 235| 0: [StringLiteralUtf16] "try"
|
||||
# 237| 1: [SpecificCatchClause] catch (...) {...}
|
||||
# 237| 0: [TypeAccess] access to type IOException
|
||||
# 237| 0: [TypeMention] IOException
|
||||
# 238| 1: [BlockStmt] {...}
|
||||
# 239| 0: [ExprStmt] ...;
|
||||
# 239| 0: [MethodCall] call to method WriteLine
|
||||
# 239| -1: [TypeAccess] access to type Console
|
||||
# 239| 0: [TypeMention] Console
|
||||
# 239| 0: [StringLiteralUtf16] "catch (IOException) without variable"
|
||||
# 241| 2: [SpecificCatchClause] catch (...) {...}
|
||||
# 241| 0: [TypeAccess] access to type Exception
|
||||
# 241| 0: [TypeMention] Exception
|
||||
# 242| 1: [BlockStmt] {...}
|
||||
# 243| 0: [ExprStmt] ...;
|
||||
# 243| 0: [MethodCall] call to method WriteLine
|
||||
# 243| -1: [TypeAccess] access to type Console
|
||||
# 243| 0: [TypeMention] Console
|
||||
# 243| 0: [StringLiteralUtf16] "catch (Exception) without variable"
|
||||
# 247| 28: [Method] MainCheckedUnchecked
|
||||
# 247| -1: [TypeMention] Void
|
||||
# 248| 4: [BlockStmt] {...}
|
||||
# 249| 0: [LocalVariableDeclStmt] ... ...;
|
||||
# 249| 0: [LocalVariableDeclAndInitExpr] Int32 i = ...
|
||||
# 249| -1: [TypeMention] int
|
||||
# 249| 0: [LocalVariableAccess] access to local variable i
|
||||
# 249| 1: [MemberConstantAccess] access to constant MaxValue
|
||||
# 249| -1: [TypeAccess] access to type Int32
|
||||
# 249| 0: [TypeMention] int
|
||||
# 250| 1: [CheckedStmt] checked {...}
|
||||
# 251| 0: [BlockStmt] {...}
|
||||
# 252| 0: [ExprStmt] ...;
|
||||
# 252| 0: [MethodCall] call to method WriteLine
|
||||
# 252| -1: [TypeAccess] access to type Console
|
||||
# 252| 0: [TypeMention] Console
|
||||
# 252| 0: [AddExpr] ... + ...
|
||||
# 252| 0: [LocalVariableAccess] access to local variable i
|
||||
# 252| 1: [IntLiteral] 1
|
||||
# 254| 2: [UncheckedStmt] unchecked {...}
|
||||
# 255| 0: [BlockStmt] {...}
|
||||
# 256| 0: [ExprStmt] ...;
|
||||
# 256| 0: [MethodCall] call to method WriteLine
|
||||
# 256| -1: [TypeAccess] access to type Console
|
||||
# 256| 0: [TypeMention] Console
|
||||
# 256| 0: [AddExpr] ... + ...
|
||||
# 256| 0: [LocalVariableAccess] access to local variable i
|
||||
# 256| 1: [IntLiteral] 1
|
||||
# 260| 29: [Class] AccountLock
|
||||
# 262| 6: [Field] balance
|
||||
# 262| -1: [TypeMention] decimal
|
||||
# 263| 7: [Method] Withdraw
|
||||
# 263| -1: [TypeMention] Void
|
||||
#-----| 2: (Parameters)
|
||||
# 247| 0: [Parameter] amount
|
||||
# 247| -1: [TypeMention] decimal
|
||||
# 248| 4: [BlockStmt] {...}
|
||||
# 249| 0: [LockStmt] lock (...) {...}
|
||||
# 249| 0: [ThisAccess] this access
|
||||
# 250| 1: [BlockStmt] {...}
|
||||
# 251| 0: [IfStmt] if (...) ...
|
||||
# 251| 0: [GTExpr] ... > ...
|
||||
# 251| 0: [ParameterAccess] access to parameter amount
|
||||
# 251| 1: [FieldAccess] access to field balance
|
||||
# 252| 1: [BlockStmt] {...}
|
||||
# 253| 0: [ThrowStmt] throw ...;
|
||||
# 253| 0: [ObjectCreation] object creation of type Exception
|
||||
# 253| -1: [TypeMention] Exception
|
||||
# 253| 0: [StringLiteralUtf16] "Insufficient funds"
|
||||
# 255| 1: [ExprStmt] ...;
|
||||
# 255| 0: [AssignSubExpr] ... -= ...
|
||||
# 255| 0: [FieldAccess] access to field balance
|
||||
# 255| 1: [ParameterAccess] access to parameter amount
|
||||
# 260| 29: [Method] MainUsing
|
||||
# 260| -1: [TypeMention] Void
|
||||
# 261| 4: [BlockStmt] {...}
|
||||
# 262| 0: [UsingBlockStmt] using (...) {...}
|
||||
# 262| -1: [LocalVariableDeclAndInitExpr] TextWriter w = ...
|
||||
# 262| -1: [TypeMention] TextWriter
|
||||
# 262| 0: [LocalVariableAccess] access to local variable w
|
||||
# 262| 1: [MethodCall] call to method CreateText
|
||||
# 262| -1: [TypeAccess] access to type File
|
||||
# 262| 0: [TypeMention] File
|
||||
# 262| 0: [StringLiteralUtf16] "test.txt"
|
||||
# 263| 1: [BlockStmt] {...}
|
||||
# 264| 0: [ExprStmt] ...;
|
||||
# 264| 0: [MethodCall] call to method WriteLine
|
||||
# 264| -1: [LocalVariableAccess] access to local variable w
|
||||
# 264| 0: [StringLiteralUtf16] "Line one"
|
||||
# 265| 1: [ExprStmt] ...;
|
||||
# 265| 0: [MethodCall] call to method WriteLine
|
||||
# 265| -1: [LocalVariableAccess] access to local variable w
|
||||
# 265| 0: [StringLiteralUtf16] "Line two"
|
||||
# 266| 2: [ExprStmt] ...;
|
||||
# 266| 0: [MethodCall] call to method WriteLine
|
||||
# 266| -1: [LocalVariableAccess] access to local variable w
|
||||
# 266| 0: [StringLiteralUtf16] "Line three"
|
||||
# 268| 1: [UsingBlockStmt] using (...) {...}
|
||||
# 268| 0: [MethodCall] call to method CreateText
|
||||
# 268| -1: [TypeAccess] access to type File
|
||||
# 268| 0: [TypeMention] File
|
||||
# 268| 0: [StringLiteralUtf16] "test.txt"
|
||||
# 269| 1: [BlockStmt] {...}
|
||||
# 273| 30: [Method] MainLabeled
|
||||
# 273| -1: [TypeMention] Void
|
||||
# 274| 4: [BlockStmt] {...}
|
||||
# 275| 0: [GotoLabelStmt] goto ...;
|
||||
# 276| 1: [LabelStmt] Label:
|
||||
# 277| 2: [LocalVariableDeclStmt] ... ...;
|
||||
# 277| 0: [LocalVariableDeclAndInitExpr] Int32 x = ...
|
||||
# 277| -1: [TypeMention] int
|
||||
# 277| 0: [LocalVariableAccess] access to local variable x
|
||||
# 277| 1: [IntLiteral] 23
|
||||
# 278| 3: [ExprStmt] ...;
|
||||
# 278| 0: [AssignExpr] ... = ...
|
||||
# 278| 0: [LocalVariableAccess] access to local variable x
|
||||
# 278| 1: [IntLiteral] 9
|
||||
# 281| 31: [Field] lockObject
|
||||
# 281| -1: [TypeMention] Lock
|
||||
# 281| 1: [ObjectCreation] object creation of type Lock
|
||||
# 281| 0: [TypeMention] Lock
|
||||
# 283| 32: [Method] LockMethod
|
||||
# 283| -1: [TypeMention] Void
|
||||
# 284| 4: [BlockStmt] {...}
|
||||
# 285| 0: [LockStmt] lock (...) {...}
|
||||
# 285| 0: [FieldAccess] access to field lockObject
|
||||
# 286| 1: [BlockStmt] {...}
|
||||
# 287| 0: [ExprStmt] ...;
|
||||
# 287| 0: [MethodCall] call to method WriteLine
|
||||
# 287| -1: [TypeAccess] access to type Console
|
||||
# 287| 0: [TypeMention] Console
|
||||
# 287| 0: [StringLiteralUtf16] "Locked"
|
||||
# 263| 0: [Parameter] amount
|
||||
# 263| -1: [TypeMention] decimal
|
||||
# 264| 4: [BlockStmt] {...}
|
||||
# 265| 0: [LockStmt] lock (...) {...}
|
||||
# 265| 0: [ThisAccess] this access
|
||||
# 266| 1: [BlockStmt] {...}
|
||||
# 267| 0: [IfStmt] if (...) ...
|
||||
# 267| 0: [GTExpr] ... > ...
|
||||
# 267| 0: [ParameterAccess] access to parameter amount
|
||||
# 267| 1: [FieldAccess] access to field balance
|
||||
# 268| 1: [BlockStmt] {...}
|
||||
# 269| 0: [ThrowStmt] throw ...;
|
||||
# 269| 0: [ObjectCreation] object creation of type Exception
|
||||
# 269| -1: [TypeMention] Exception
|
||||
# 269| 0: [StringLiteralUtf16] "Insufficient funds"
|
||||
# 271| 1: [ExprStmt] ...;
|
||||
# 271| 0: [AssignSubExpr] ... -= ...
|
||||
# 271| 0: [FieldAccess] access to field balance
|
||||
# 271| 1: [ParameterAccess] access to parameter amount
|
||||
# 276| 30: [Method] MainUsing
|
||||
# 276| -1: [TypeMention] Void
|
||||
# 277| 4: [BlockStmt] {...}
|
||||
# 278| 0: [UsingBlockStmt] using (...) {...}
|
||||
# 278| -1: [LocalVariableDeclAndInitExpr] TextWriter w = ...
|
||||
# 278| -1: [TypeMention] TextWriter
|
||||
# 278| 0: [LocalVariableAccess] access to local variable w
|
||||
# 278| 1: [MethodCall] call to method CreateText
|
||||
# 278| -1: [TypeAccess] access to type File
|
||||
# 278| 0: [TypeMention] File
|
||||
# 278| 0: [StringLiteralUtf16] "test.txt"
|
||||
# 279| 1: [BlockStmt] {...}
|
||||
# 280| 0: [ExprStmt] ...;
|
||||
# 280| 0: [MethodCall] call to method WriteLine
|
||||
# 280| -1: [LocalVariableAccess] access to local variable w
|
||||
# 280| 0: [StringLiteralUtf16] "Line one"
|
||||
# 281| 1: [ExprStmt] ...;
|
||||
# 281| 0: [MethodCall] call to method WriteLine
|
||||
# 281| -1: [LocalVariableAccess] access to local variable w
|
||||
# 281| 0: [StringLiteralUtf16] "Line two"
|
||||
# 282| 2: [ExprStmt] ...;
|
||||
# 282| 0: [MethodCall] call to method WriteLine
|
||||
# 282| -1: [LocalVariableAccess] access to local variable w
|
||||
# 282| 0: [StringLiteralUtf16] "Line three"
|
||||
# 284| 1: [UsingBlockStmt] using (...) {...}
|
||||
# 284| 0: [MethodCall] call to method CreateText
|
||||
# 284| -1: [TypeAccess] access to type File
|
||||
# 284| 0: [TypeMention] File
|
||||
# 284| 0: [StringLiteralUtf16] "test.txt"
|
||||
# 285| 1: [BlockStmt] {...}
|
||||
# 289| 31: [Method] MainLabeled
|
||||
# 289| -1: [TypeMention] Void
|
||||
# 290| 4: [BlockStmt] {...}
|
||||
# 291| 0: [GotoLabelStmt] goto ...;
|
||||
# 292| 1: [LabelStmt] Label:
|
||||
# 293| 2: [LocalVariableDeclStmt] ... ...;
|
||||
# 293| 0: [LocalVariableDeclAndInitExpr] Int32 x = ...
|
||||
# 293| -1: [TypeMention] int
|
||||
# 293| 0: [LocalVariableAccess] access to local variable x
|
||||
# 293| 1: [IntLiteral] 23
|
||||
# 294| 3: [ExprStmt] ...;
|
||||
# 294| 0: [AssignExpr] ... = ...
|
||||
# 294| 0: [LocalVariableAccess] access to local variable x
|
||||
# 294| 1: [IntLiteral] 9
|
||||
# 297| 32: [Field] lockObject
|
||||
# 297| -1: [TypeMention] Lock
|
||||
# 297| 1: [ObjectCreation] object creation of type Lock
|
||||
# 297| 0: [TypeMention] Lock
|
||||
# 299| 33: [Method] LockMethod
|
||||
# 299| -1: [TypeMention] Void
|
||||
# 300| 4: [BlockStmt] {...}
|
||||
# 301| 0: [LockStmt] lock (...) {...}
|
||||
# 301| 0: [FieldAccess] access to field lockObject
|
||||
# 302| 1: [BlockStmt] {...}
|
||||
# 303| 0: [ExprStmt] ...;
|
||||
# 303| 0: [MethodCall] call to method WriteLine
|
||||
# 303| -1: [TypeAccess] access to type Console
|
||||
# 303| 0: [TypeMention] Console
|
||||
# 303| 0: [StringLiteralUtf16] "Locked"
|
||||
|
||||
@@ -17,9 +17,13 @@
|
||||
| statements.cs:218:13:220:13 | {...} | statements.cs:219:17:219:45 | ...; |
|
||||
| statements.cs:222:13:224:13 | {...} | statements.cs:223:17:223:47 | ...; |
|
||||
| statements.cs:226:13:228:13 | {...} | statements.cs:227:17:227:47 | ...; |
|
||||
| statements.cs:235:13:237:13 | {...} | statements.cs:236:17:236:41 | ...; |
|
||||
| statements.cs:239:13:241:13 | {...} | statements.cs:240:17:240:41 | ...; |
|
||||
| statements.cs:248:13:257:13 | {...} | statements.cs:249:17:256:17 | lock (...) {...} |
|
||||
| statements.cs:252:21:254:21 | {...} | statements.cs:253:25:253:66 | throw ...; |
|
||||
| statements.cs:284:9:289:9 | {...} | statements.cs:285:13:288:13 | lock (...) {...} |
|
||||
| statements.cs:286:13:288:13 | {...} | statements.cs:287:17:287:44 | ...; |
|
||||
| statements.cs:232:9:245:9 | {...} | statements.cs:233:13:244:13 | try {...} ... |
|
||||
| statements.cs:234:13:236:13 | {...} | statements.cs:235:17:235:41 | ...; |
|
||||
| statements.cs:238:13:240:13 | {...} | statements.cs:239:17:239:74 | ...; |
|
||||
| statements.cs:242:13:244:13 | {...} | statements.cs:243:17:243:72 | ...; |
|
||||
| statements.cs:251:13:253:13 | {...} | statements.cs:252:17:252:41 | ...; |
|
||||
| statements.cs:255:13:257:13 | {...} | statements.cs:256:17:256:41 | ...; |
|
||||
| statements.cs:264:13:273:13 | {...} | statements.cs:265:17:272:17 | lock (...) {...} |
|
||||
| statements.cs:268:21:270:21 | {...} | statements.cs:269:25:269:66 | throw ...; |
|
||||
| statements.cs:300:9:305:9 | {...} | statements.cs:301:13:304:13 | lock (...) {...} |
|
||||
| statements.cs:302:13:304:13 | {...} | statements.cs:303:17:303:44 | ...; |
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
| statements.cs:246:21:246:27 | balance |
|
||||
| statements.cs:281:31:281:40 | lockObject |
|
||||
| statements.cs:262:21:262:27 | balance |
|
||||
| statements.cs:297:31:297:40 | lockObject |
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
| statements.cs:237:13:240:13 | catch (...) {...} | statements.cs:237:20:237:30 | access to type IOException | file:///home/runner/work/codeql/codeql/csharp/extractor-pack/tools/linux64/System.Private.CoreLib.dll:0:0:0:0 | IOException |
|
||||
| statements.cs:241:13:244:13 | catch (...) {...} | statements.cs:241:20:241:28 | access to type Exception | file:///home/runner/work/codeql/codeql/csharp/extractor-pack/tools/linux64/System.Private.CoreLib.dll:0:0:0:0 | Exception |
|
||||
13
csharp/ql/test/library-tests/statements/TryCatch9.ql
Normal file
13
csharp/ql/test/library-tests/statements/TryCatch9.ql
Normal file
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* @name Test for try catches without variable
|
||||
*/
|
||||
|
||||
import csharp
|
||||
|
||||
from Method m, TryStmt s, SpecificCatchClause c, TypeAccess ta
|
||||
where
|
||||
s.getEnclosingCallable() = m and
|
||||
m.getName() = "MainTryCatchNoVar" and
|
||||
s.getACatchClause() = c and
|
||||
c.getTypeAccess() = ta
|
||||
select c, ta, ta.getTarget()
|
||||
@@ -1 +1 @@
|
||||
| statements.cs:238:13:241:13 | unchecked {...} | statements.cs:239:13:241:13 | {...} |
|
||||
| statements.cs:254:13:257:13 | unchecked {...} | statements.cs:255:13:257:13 | {...} |
|
||||
|
||||
@@ -1 +1 @@
|
||||
| statements.cs:260:21:260:29 | MainUsing |
|
||||
| statements.cs:276:21:276:29 | MainUsing |
|
||||
|
||||
@@ -1 +1 @@
|
||||
| statements.cs:260:21:260:29 | MainUsing | statements.cs:262:31:262:31 | w |
|
||||
| statements.cs:276:21:276:29 | MainUsing | statements.cs:278:31:278:31 | w |
|
||||
|
||||
@@ -228,6 +228,22 @@ namespace Statements
|
||||
}
|
||||
}
|
||||
|
||||
static void MainTryCatchNoVar(string[] args)
|
||||
{
|
||||
try
|
||||
{
|
||||
Console.WriteLine("try");
|
||||
}
|
||||
catch (IOException)
|
||||
{
|
||||
Console.WriteLine("catch (IOException) without variable");
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Console.WriteLine("catch (Exception) without variable");
|
||||
}
|
||||
}
|
||||
|
||||
static void MainCheckedUnchecked()
|
||||
{
|
||||
int i = int.MaxValue;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
overlay[local]
|
||||
module;
|
||||
|
||||
import python as Py
|
||||
import python
|
||||
private import semmle.python.internal.CachedStages
|
||||
private import codeql.controlflow.BasicBlock as BB
|
||||
|
||||
@@ -17,7 +17,7 @@ private import codeql.controlflow.BasicBlock as BB
|
||||
*/
|
||||
|
||||
private predicate augstore(ControlFlowNode load, ControlFlowNode store) {
|
||||
exists(Py::Expr load_store | exists(Py::AugAssign aa | aa.getTarget() = load_store) |
|
||||
exists(Expr load_store | exists(AugAssign aa | aa.getTarget() = load_store) |
|
||||
toAst(load) = load_store and
|
||||
toAst(store) = load_store and
|
||||
load.strictlyDominates(store)
|
||||
@@ -25,7 +25,7 @@ private predicate augstore(ControlFlowNode load, ControlFlowNode store) {
|
||||
}
|
||||
|
||||
/** A non-dispatched getNode() to avoid negative recursion issues */
|
||||
private Py::AstNode toAst(ControlFlowNode n) { py_flow_bb_node(n, result, _, _) }
|
||||
private AstNode toAst(ControlFlowNode n) { py_flow_bb_node(n, result, _, _) }
|
||||
|
||||
/**
|
||||
* A control flow node. Control flow nodes have a many-to-one relation with syntactic nodes,
|
||||
@@ -35,19 +35,19 @@ private Py::AstNode toAst(ControlFlowNode n) { py_flow_bb_node(n, result, _, _)
|
||||
class ControlFlowNode extends @py_flow_node {
|
||||
/** Whether this control flow node is a load (including those in augmented assignments) */
|
||||
predicate isLoad() {
|
||||
exists(Py::Expr e | e = toAst(this) | py_expr_contexts(_, 3, e) and not augstore(_, this))
|
||||
exists(Expr e | e = toAst(this) | py_expr_contexts(_, 3, e) and not augstore(_, this))
|
||||
}
|
||||
|
||||
/** Whether this control flow node is a store (including those in augmented assignments) */
|
||||
predicate isStore() {
|
||||
exists(Py::Expr e | e = toAst(this) | py_expr_contexts(_, 5, e) or augstore(_, this))
|
||||
exists(Expr e | e = toAst(this) | py_expr_contexts(_, 5, e) or augstore(_, this))
|
||||
}
|
||||
|
||||
/** Whether this control flow node is a delete */
|
||||
predicate isDelete() { exists(Py::Expr e | e = toAst(this) | py_expr_contexts(_, 2, e)) }
|
||||
predicate isDelete() { exists(Expr e | e = toAst(this) | py_expr_contexts(_, 2, e)) }
|
||||
|
||||
/** Whether this control flow node is a parameter */
|
||||
predicate isParameter() { exists(Py::Expr e | e = toAst(this) | py_expr_contexts(_, 4, e)) }
|
||||
predicate isParameter() { exists(Expr e | e = toAst(this) | py_expr_contexts(_, 4, e)) }
|
||||
|
||||
/** Whether this control flow node is a store in an augmented assignment */
|
||||
predicate isAugStore() { augstore(_, this) }
|
||||
@@ -57,61 +57,61 @@ class ControlFlowNode extends @py_flow_node {
|
||||
|
||||
/** Whether this flow node corresponds to a literal */
|
||||
predicate isLiteral() {
|
||||
toAst(this) instanceof Py::Bytes
|
||||
toAst(this) instanceof Bytes
|
||||
or
|
||||
toAst(this) instanceof Py::Dict
|
||||
toAst(this) instanceof Dict
|
||||
or
|
||||
toAst(this) instanceof Py::DictComp
|
||||
toAst(this) instanceof DictComp
|
||||
or
|
||||
toAst(this) instanceof Py::Set
|
||||
toAst(this) instanceof Set
|
||||
or
|
||||
toAst(this) instanceof Py::SetComp
|
||||
toAst(this) instanceof SetComp
|
||||
or
|
||||
toAst(this) instanceof Py::Ellipsis
|
||||
toAst(this) instanceof Ellipsis
|
||||
or
|
||||
toAst(this) instanceof Py::GeneratorExp
|
||||
toAst(this) instanceof GeneratorExp
|
||||
or
|
||||
toAst(this) instanceof Py::Lambda
|
||||
toAst(this) instanceof Lambda
|
||||
or
|
||||
toAst(this) instanceof Py::ListComp
|
||||
toAst(this) instanceof ListComp
|
||||
or
|
||||
toAst(this) instanceof Py::List
|
||||
toAst(this) instanceof List
|
||||
or
|
||||
toAst(this) instanceof Py::Num
|
||||
toAst(this) instanceof Num
|
||||
or
|
||||
toAst(this) instanceof Py::Tuple
|
||||
toAst(this) instanceof Tuple
|
||||
or
|
||||
toAst(this) instanceof Py::Unicode
|
||||
toAst(this) instanceof Unicode
|
||||
or
|
||||
toAst(this) instanceof Py::NameConstant
|
||||
toAst(this) instanceof NameConstant
|
||||
}
|
||||
|
||||
/** Whether this flow node corresponds to an attribute expression */
|
||||
predicate isAttribute() { toAst(this) instanceof Py::Attribute }
|
||||
predicate isAttribute() { toAst(this) instanceof Attribute }
|
||||
|
||||
/** Whether this flow node corresponds to an subscript expression */
|
||||
predicate isSubscript() { toAst(this) instanceof Py::Subscript }
|
||||
predicate isSubscript() { toAst(this) instanceof Subscript }
|
||||
|
||||
/** Whether this flow node corresponds to an import member */
|
||||
predicate isImportMember() { toAst(this) instanceof Py::ImportMember }
|
||||
predicate isImportMember() { toAst(this) instanceof ImportMember }
|
||||
|
||||
/** Whether this flow node corresponds to a call */
|
||||
predicate isCall() { toAst(this) instanceof Py::Call }
|
||||
predicate isCall() { toAst(this) instanceof Call }
|
||||
|
||||
/** Whether this flow node is the first in a module */
|
||||
predicate isModuleEntry() { this.isEntryNode() and toAst(this) instanceof Py::Module }
|
||||
predicate isModuleEntry() { this.isEntryNode() and toAst(this) instanceof Module }
|
||||
|
||||
/** Whether this flow node corresponds to an import */
|
||||
predicate isImport() { toAst(this) instanceof Py::ImportExpr }
|
||||
predicate isImport() { toAst(this) instanceof ImportExpr }
|
||||
|
||||
/** Whether this flow node corresponds to a conditional expression */
|
||||
predicate isIfExp() { toAst(this) instanceof Py::IfExp }
|
||||
predicate isIfExp() { toAst(this) instanceof IfExp }
|
||||
|
||||
/** Whether this flow node corresponds to a function definition expression */
|
||||
predicate isFunction() { toAst(this) instanceof Py::FunctionExpr }
|
||||
predicate isFunction() { toAst(this) instanceof FunctionExpr }
|
||||
|
||||
/** Whether this flow node corresponds to a class definition expression */
|
||||
predicate isClass() { toAst(this) instanceof Py::ClassExpr }
|
||||
predicate isClass() { toAst(this) instanceof ClassExpr }
|
||||
|
||||
/** Gets a predecessor of this flow node */
|
||||
ControlFlowNode getAPredecessor() { this = result.getASuccessor() }
|
||||
@@ -123,25 +123,25 @@ class ControlFlowNode extends @py_flow_node {
|
||||
ControlFlowNode getImmediateDominator() { py_idoms(this, result) }
|
||||
|
||||
/** Gets the syntactic element corresponding to this flow node */
|
||||
Py::AstNode getNode() { py_flow_bb_node(this, result, _, _) }
|
||||
AstNode getNode() { py_flow_bb_node(this, result, _, _) }
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
cached
|
||||
string toString() {
|
||||
Stages::AST::ref() and
|
||||
// Since modules can have ambigous names, entry nodes can too, if we do not collate them.
|
||||
exists(Py::Scope s | s.getEntryNode() = this |
|
||||
exists(Scope s | s.getEntryNode() = this |
|
||||
result = "Entry node for " + concat( | | s.toString(), ",")
|
||||
)
|
||||
or
|
||||
exists(Py::Scope s | s.getANormalExit() = this | result = "Exit node for " + s.toString())
|
||||
exists(Scope s | s.getANormalExit() = this | result = "Exit node for " + s.toString())
|
||||
or
|
||||
not exists(Py::Scope s | s.getEntryNode() = this or s.getANormalExit() = this) and
|
||||
not exists(Scope s | s.getEntryNode() = this or s.getANormalExit() = this) and
|
||||
result = "ControlFlowNode for " + this.getNode().toString()
|
||||
}
|
||||
|
||||
/** Gets the location of this ControlFlowNode */
|
||||
Py::Location getLocation() { result = this.getNode().getLocation() }
|
||||
Location getLocation() { result = this.getNode().getLocation() }
|
||||
|
||||
/** Whether this flow node is the first in its scope */
|
||||
predicate isEntryNode() { py_scope_flow(this, _, -1) }
|
||||
@@ -151,9 +151,9 @@ class ControlFlowNode extends @py_flow_node {
|
||||
|
||||
/** Gets the scope containing this flow node */
|
||||
cached
|
||||
Py::Scope getScope() {
|
||||
Scope getScope() {
|
||||
Stages::AST::ref() and
|
||||
if this.getNode() instanceof Py::Scope
|
||||
if this.getNode() instanceof Scope
|
||||
then
|
||||
/* Entry or exit node */
|
||||
result = this.getNode()
|
||||
@@ -161,7 +161,7 @@ class ControlFlowNode extends @py_flow_node {
|
||||
}
|
||||
|
||||
/** Gets the enclosing module */
|
||||
Py::Module getEnclosingModule() { result = this.getScope().getEnclosingModule() }
|
||||
Module getEnclosingModule() { result = this.getScope().getEnclosingModule() }
|
||||
|
||||
/** Gets a successor for this node if the relevant condition is True. */
|
||||
ControlFlowNode getATrueSuccessor() {
|
||||
@@ -188,7 +188,7 @@ class ControlFlowNode extends @py_flow_node {
|
||||
}
|
||||
|
||||
/** Whether the scope may be exited as a result of this node raising an exception */
|
||||
predicate isExceptionalExit(Py::Scope s) { py_scope_flow(this, s, 1) }
|
||||
predicate isExceptionalExit(Scope s) { py_scope_flow(this, s, 1) }
|
||||
|
||||
/** Whether this node is a normal (non-exceptional) exit */
|
||||
predicate isNormalExit() { py_scope_flow(this, _, 0) or py_scope_flow(this, _, 2) }
|
||||
@@ -236,7 +236,7 @@ class ControlFlowNode extends @py_flow_node {
|
||||
/* join-ordering helper for `getAChild() */
|
||||
pragma[noinline]
|
||||
private ControlFlowNode getExprChild(BasicBlock dom) {
|
||||
this.getNode().(Py::Expr).getAChildNode() = result.getNode() and
|
||||
this.getNode().(Expr).getAChildNode() = result.getNode() and
|
||||
result.getBasicBlock().dominates(dom) and
|
||||
not this instanceof UnaryExprNode
|
||||
}
|
||||
@@ -249,16 +249,16 @@ class ControlFlowNode extends @py_flow_node {
|
||||
*/
|
||||
|
||||
private class AnyNode extends ControlFlowNode {
|
||||
override Py::AstNode getNode() { result = super.getNode() }
|
||||
override AstNode getNode() { result = super.getNode() }
|
||||
}
|
||||
|
||||
/** A control flow node corresponding to a call expression, such as `func(...)` */
|
||||
class CallNode extends ControlFlowNode {
|
||||
CallNode() { toAst(this) instanceof Py::Call }
|
||||
CallNode() { toAst(this) instanceof Call }
|
||||
|
||||
/** Gets the flow node corresponding to the function expression for the call corresponding to this flow node */
|
||||
ControlFlowNode getFunction() {
|
||||
exists(Py::Call c |
|
||||
exists(Call c |
|
||||
this.getNode() = c and
|
||||
c.getFunc() = result.getNode() and
|
||||
result.getBasicBlock().dominates(this.getBasicBlock())
|
||||
@@ -267,7 +267,7 @@ class CallNode extends ControlFlowNode {
|
||||
|
||||
/** Gets the flow node corresponding to the n'th positional argument of the call corresponding to this flow node */
|
||||
ControlFlowNode getArg(int n) {
|
||||
exists(Py::Call c |
|
||||
exists(Call c |
|
||||
this.getNode() = c and
|
||||
c.getArg(n) = result.getNode() and
|
||||
result.getBasicBlock().dominates(this.getBasicBlock())
|
||||
@@ -276,7 +276,7 @@ class CallNode extends ControlFlowNode {
|
||||
|
||||
/** Gets the flow node corresponding to the named argument of the call corresponding to this flow node */
|
||||
ControlFlowNode getArgByName(string name) {
|
||||
exists(Py::Call c, Py::Keyword k |
|
||||
exists(Call c, Keyword k |
|
||||
this.getNode() = c and
|
||||
k = c.getANamedArg() and
|
||||
k.getValue() = result.getNode() and
|
||||
@@ -292,7 +292,7 @@ class CallNode extends ControlFlowNode {
|
||||
result = this.getArgByName(_)
|
||||
}
|
||||
|
||||
override Py::Call getNode() { result = super.getNode() }
|
||||
override Call getNode() { result = super.getNode() }
|
||||
|
||||
predicate isDecoratorCall() {
|
||||
this.isClassDecoratorCall()
|
||||
@@ -301,11 +301,11 @@ class CallNode extends ControlFlowNode {
|
||||
}
|
||||
|
||||
predicate isClassDecoratorCall() {
|
||||
exists(Py::ClassExpr cls | this.getNode() = cls.getADecoratorCall())
|
||||
exists(ClassExpr cls | this.getNode() = cls.getADecoratorCall())
|
||||
}
|
||||
|
||||
predicate isFunctionDecoratorCall() {
|
||||
exists(Py::FunctionExpr func | this.getNode() = func.getADecoratorCall())
|
||||
exists(FunctionExpr func | this.getNode() = func.getADecoratorCall())
|
||||
}
|
||||
|
||||
/** Gets the first tuple (*) argument of this call, if any. */
|
||||
@@ -323,11 +323,11 @@ class CallNode extends ControlFlowNode {
|
||||
|
||||
/** A control flow corresponding to an attribute expression, such as `value.attr` */
|
||||
class AttrNode extends ControlFlowNode {
|
||||
AttrNode() { toAst(this) instanceof Py::Attribute }
|
||||
AttrNode() { toAst(this) instanceof Attribute }
|
||||
|
||||
/** Gets the flow node corresponding to the object of the attribute expression corresponding to this flow node */
|
||||
ControlFlowNode getObject() {
|
||||
exists(Py::Attribute a |
|
||||
exists(Attribute a |
|
||||
this.getNode() = a and
|
||||
a.getObject() = result.getNode() and
|
||||
result.getBasicBlock().dominates(this.getBasicBlock())
|
||||
@@ -339,7 +339,7 @@ class AttrNode extends ControlFlowNode {
|
||||
* with the matching name
|
||||
*/
|
||||
ControlFlowNode getObject(string name) {
|
||||
exists(Py::Attribute a |
|
||||
exists(Attribute a |
|
||||
this.getNode() = a and
|
||||
a.getObject() = result.getNode() and
|
||||
a.getName() = name and
|
||||
@@ -348,57 +348,57 @@ class AttrNode extends ControlFlowNode {
|
||||
}
|
||||
|
||||
/** Gets the attribute name of the attribute expression corresponding to this flow node */
|
||||
string getName() { exists(Py::Attribute a | this.getNode() = a and a.getName() = result) }
|
||||
string getName() { exists(Attribute a | this.getNode() = a and a.getName() = result) }
|
||||
|
||||
override Py::Attribute getNode() { result = super.getNode() }
|
||||
override Attribute getNode() { result = super.getNode() }
|
||||
}
|
||||
|
||||
/** A control flow node corresponding to a `from ... import ...` expression */
|
||||
class ImportMemberNode extends ControlFlowNode {
|
||||
ImportMemberNode() { toAst(this) instanceof Py::ImportMember }
|
||||
ImportMemberNode() { toAst(this) instanceof ImportMember }
|
||||
|
||||
/**
|
||||
* Gets the flow node corresponding to the module in the import-member expression corresponding to this flow node,
|
||||
* with the matching name
|
||||
*/
|
||||
ControlFlowNode getModule(string name) {
|
||||
exists(Py::ImportMember i | this.getNode() = i and i.getModule() = result.getNode() |
|
||||
exists(ImportMember i | this.getNode() = i and i.getModule() = result.getNode() |
|
||||
i.getName() = name and
|
||||
result.getBasicBlock().dominates(this.getBasicBlock())
|
||||
)
|
||||
}
|
||||
|
||||
override Py::ImportMember getNode() { result = super.getNode() }
|
||||
override ImportMember getNode() { result = super.getNode() }
|
||||
}
|
||||
|
||||
/** A control flow node corresponding to an artificial expression representing an import */
|
||||
class ImportExprNode extends ControlFlowNode {
|
||||
ImportExprNode() { toAst(this) instanceof Py::ImportExpr }
|
||||
ImportExprNode() { toAst(this) instanceof ImportExpr }
|
||||
|
||||
override Py::ImportExpr getNode() { result = super.getNode() }
|
||||
override ImportExpr getNode() { result = super.getNode() }
|
||||
}
|
||||
|
||||
/** A control flow node corresponding to a `from ... import *` statement */
|
||||
class ImportStarNode extends ControlFlowNode {
|
||||
ImportStarNode() { toAst(this) instanceof Py::ImportStar }
|
||||
ImportStarNode() { toAst(this) instanceof ImportStar }
|
||||
|
||||
/** Gets the flow node corresponding to the module in the import-star corresponding to this flow node */
|
||||
ControlFlowNode getModule() {
|
||||
exists(Py::ImportStar i | this.getNode() = i and i.getModuleExpr() = result.getNode() |
|
||||
exists(ImportStar i | this.getNode() = i and i.getModuleExpr() = result.getNode() |
|
||||
result.getBasicBlock().dominates(this.getBasicBlock())
|
||||
)
|
||||
}
|
||||
|
||||
override Py::ImportStar getNode() { result = super.getNode() }
|
||||
override ImportStar getNode() { result = super.getNode() }
|
||||
}
|
||||
|
||||
/** A control flow node corresponding to a subscript expression, such as `value[slice]` */
|
||||
class SubscriptNode extends ControlFlowNode {
|
||||
SubscriptNode() { toAst(this) instanceof Py::Subscript }
|
||||
SubscriptNode() { toAst(this) instanceof Subscript }
|
||||
|
||||
/** flow node corresponding to the value of the sequence in a subscript operation */
|
||||
ControlFlowNode getObject() {
|
||||
exists(Py::Subscript s |
|
||||
exists(Subscript s |
|
||||
this.getNode() = s and
|
||||
s.getObject() = result.getNode() and
|
||||
result.getBasicBlock().dominates(this.getBasicBlock())
|
||||
@@ -407,23 +407,23 @@ class SubscriptNode extends ControlFlowNode {
|
||||
|
||||
/** flow node corresponding to the index in a subscript operation */
|
||||
ControlFlowNode getIndex() {
|
||||
exists(Py::Subscript s |
|
||||
exists(Subscript s |
|
||||
this.getNode() = s and
|
||||
s.getIndex() = result.getNode() and
|
||||
result.getBasicBlock().dominates(this.getBasicBlock())
|
||||
)
|
||||
}
|
||||
|
||||
override Py::Subscript getNode() { result = super.getNode() }
|
||||
override Subscript getNode() { result = super.getNode() }
|
||||
}
|
||||
|
||||
/** A control flow node corresponding to a comparison operation, such as `x<y` */
|
||||
class CompareNode extends ControlFlowNode {
|
||||
CompareNode() { toAst(this) instanceof Py::Compare }
|
||||
CompareNode() { toAst(this) instanceof Compare }
|
||||
|
||||
/** Whether left and right are a pair of operands for this comparison */
|
||||
predicate operands(ControlFlowNode left, Py::Cmpop op, ControlFlowNode right) {
|
||||
exists(Py::Compare c, Py::Expr eleft, Py::Expr eright |
|
||||
predicate operands(ControlFlowNode left, Cmpop op, ControlFlowNode right) {
|
||||
exists(Compare c, Expr eleft, Expr eright |
|
||||
this.getNode() = c and left.getNode() = eleft and right.getNode() = eright
|
||||
|
|
||||
eleft = c.getLeft() and eright = c.getComparator(0) and op = c.getOp(0)
|
||||
@@ -436,26 +436,26 @@ class CompareNode extends ControlFlowNode {
|
||||
right.getBasicBlock().dominates(this.getBasicBlock())
|
||||
}
|
||||
|
||||
override Py::Compare getNode() { result = super.getNode() }
|
||||
override Compare getNode() { result = super.getNode() }
|
||||
}
|
||||
|
||||
/** A control flow node corresponding to a conditional expression such as, `body if test else orelse` */
|
||||
class IfExprNode extends ControlFlowNode {
|
||||
IfExprNode() { toAst(this) instanceof Py::IfExp }
|
||||
IfExprNode() { toAst(this) instanceof IfExp }
|
||||
|
||||
/** flow node corresponding to one of the operands of an if-expression */
|
||||
ControlFlowNode getAnOperand() { result = this.getAPredecessor() }
|
||||
|
||||
override Py::IfExp getNode() { result = super.getNode() }
|
||||
override IfExp getNode() { result = super.getNode() }
|
||||
}
|
||||
|
||||
/** A control flow node corresponding to an assignment expression such as `lhs := rhs`. */
|
||||
class AssignmentExprNode extends ControlFlowNode {
|
||||
AssignmentExprNode() { toAst(this) instanceof Py::AssignExpr }
|
||||
AssignmentExprNode() { toAst(this) instanceof AssignExpr }
|
||||
|
||||
/** Gets the flow node corresponding to the left-hand side of the assignment expression */
|
||||
ControlFlowNode getTarget() {
|
||||
exists(Py::AssignExpr a |
|
||||
exists(AssignExpr a |
|
||||
this.getNode() = a and
|
||||
a.getTarget() = result.getNode() and
|
||||
result.getBasicBlock().dominates(this.getBasicBlock())
|
||||
@@ -464,27 +464,27 @@ class AssignmentExprNode extends ControlFlowNode {
|
||||
|
||||
/** Gets the flow node corresponding to the right-hand side of the assignment expression */
|
||||
ControlFlowNode getValue() {
|
||||
exists(Py::AssignExpr a |
|
||||
exists(AssignExpr a |
|
||||
this.getNode() = a and
|
||||
a.getValue() = result.getNode() and
|
||||
result.getBasicBlock().dominates(this.getBasicBlock())
|
||||
)
|
||||
}
|
||||
|
||||
override Py::AssignExpr getNode() { result = super.getNode() }
|
||||
override AssignExpr getNode() { result = super.getNode() }
|
||||
}
|
||||
|
||||
/** A control flow node corresponding to a binary expression, such as `x + y` */
|
||||
class BinaryExprNode extends ControlFlowNode {
|
||||
BinaryExprNode() { toAst(this) instanceof Py::BinaryExpr }
|
||||
BinaryExprNode() { toAst(this) instanceof BinaryExpr }
|
||||
|
||||
/** flow node corresponding to one of the operands of a binary expression */
|
||||
ControlFlowNode getAnOperand() { result = this.getLeft() or result = this.getRight() }
|
||||
|
||||
override Py::BinaryExpr getNode() { result = super.getNode() }
|
||||
override BinaryExpr getNode() { result = super.getNode() }
|
||||
|
||||
ControlFlowNode getLeft() {
|
||||
exists(Py::BinaryExpr b |
|
||||
exists(BinaryExpr b |
|
||||
this.getNode() = b and
|
||||
result.getNode() = b.getLeft() and
|
||||
result.getBasicBlock().dominates(this.getBasicBlock())
|
||||
@@ -492,7 +492,7 @@ class BinaryExprNode extends ControlFlowNode {
|
||||
}
|
||||
|
||||
ControlFlowNode getRight() {
|
||||
exists(Py::BinaryExpr b |
|
||||
exists(BinaryExpr b |
|
||||
this.getNode() = b and
|
||||
result.getNode() = b.getRight() and
|
||||
result.getBasicBlock().dominates(this.getBasicBlock())
|
||||
@@ -500,11 +500,11 @@ class BinaryExprNode extends ControlFlowNode {
|
||||
}
|
||||
|
||||
/** Gets the operator of this binary expression node. */
|
||||
Py::Operator getOp() { result = this.getNode().getOp() }
|
||||
Operator getOp() { result = this.getNode().getOp() }
|
||||
|
||||
/** Whether left and right are a pair of operands for this binary expression */
|
||||
predicate operands(ControlFlowNode left, Py::Operator op, ControlFlowNode right) {
|
||||
exists(Py::BinaryExpr b, Py::Expr eleft, Py::Expr eright |
|
||||
predicate operands(ControlFlowNode left, Operator op, ControlFlowNode right) {
|
||||
exists(BinaryExpr b, Expr eleft, Expr eright |
|
||||
this.getNode() = b and left.getNode() = eleft and right.getNode() = eright
|
||||
|
|
||||
eleft = b.getLeft() and eright = b.getRight() and op = b.getOp()
|
||||
@@ -516,20 +516,20 @@ class BinaryExprNode extends ControlFlowNode {
|
||||
|
||||
/** A control flow node corresponding to a boolean shortcut (and/or) operation */
|
||||
class BoolExprNode extends ControlFlowNode {
|
||||
BoolExprNode() { toAst(this) instanceof Py::BoolExpr }
|
||||
BoolExprNode() { toAst(this) instanceof BoolExpr }
|
||||
|
||||
/** flow node corresponding to one of the operands of a boolean expression */
|
||||
ControlFlowNode getAnOperand() {
|
||||
exists(Py::BoolExpr b | this.getNode() = b and result.getNode() = b.getAValue()) and
|
||||
exists(BoolExpr b | this.getNode() = b and result.getNode() = b.getAValue()) and
|
||||
this.getBasicBlock().dominates(result.getBasicBlock())
|
||||
}
|
||||
|
||||
override Py::BoolExpr getNode() { result = super.getNode() }
|
||||
override BoolExpr getNode() { result = super.getNode() }
|
||||
}
|
||||
|
||||
/** A control flow node corresponding to a unary expression: (`+x`), (`-x`) or (`~x`) */
|
||||
class UnaryExprNode extends ControlFlowNode {
|
||||
UnaryExprNode() { toAst(this) instanceof Py::UnaryExpr }
|
||||
UnaryExprNode() { toAst(this) instanceof UnaryExpr }
|
||||
|
||||
/**
|
||||
* Gets flow node corresponding to the operand of a unary expression.
|
||||
@@ -540,7 +540,7 @@ class UnaryExprNode extends ControlFlowNode {
|
||||
*/
|
||||
ControlFlowNode getOperand() { result = this.getAPredecessor() }
|
||||
|
||||
override Py::UnaryExpr getNode() { result = super.getNode() }
|
||||
override UnaryExpr getNode() { result = super.getNode() }
|
||||
|
||||
override ControlFlowNode getAChild() { result = this.getAPredecessor() }
|
||||
}
|
||||
@@ -555,22 +555,22 @@ class DefinitionNode extends ControlFlowNode {
|
||||
cached
|
||||
DefinitionNode() {
|
||||
Stages::AST::ref() and
|
||||
exists(Py::Assign a | this.getNode() = a.getATarget())
|
||||
exists(Assign a | this.getNode() = a.getATarget())
|
||||
or
|
||||
exists(Py::AssignExpr a | this.getNode() = a.getTarget())
|
||||
exists(AssignExpr a | this.getNode() = a.getTarget())
|
||||
or
|
||||
exists(Py::AnnAssign a | this.getNode() = a.getTarget() and exists(a.getValue()))
|
||||
exists(AnnAssign a | this.getNode() = a.getTarget() and exists(a.getValue()))
|
||||
or
|
||||
exists(Py::Alias a | this.getNode() = a.getAsname())
|
||||
exists(Alias a | this.getNode() = a.getAsname())
|
||||
or
|
||||
augstore(_, this)
|
||||
or
|
||||
// `x, y = 1, 2` where LHS is a combination of list or tuples
|
||||
exists(Py::Assign a | this.getNode() = list_or_tuple_nested_element(a.getATarget()))
|
||||
exists(Assign a | this.getNode() = list_or_tuple_nested_element(a.getATarget()))
|
||||
or
|
||||
exists(Py::For for | this.getNode() = for.getTarget())
|
||||
exists(For for | this.getNode() = for.getTarget())
|
||||
or
|
||||
exists(Py::Parameter param | this.getNode() = param.asName() and exists(param.getDefault()))
|
||||
exists(Parameter param | this.getNode() = param.asName() and exists(param.getDefault()))
|
||||
}
|
||||
|
||||
/** flow node corresponding to the value assigned for the definition corresponding to this flow node */
|
||||
@@ -584,16 +584,16 @@ class DefinitionNode extends ControlFlowNode {
|
||||
// since the default value for a parameter is evaluated in the same basic block as
|
||||
// the function definition, but the parameter belongs to the basic block of the function,
|
||||
// there is no dominance relationship between the two.
|
||||
exists(Py::Parameter param | this.getNode() = param.asName())
|
||||
exists(Parameter param | this.getNode() = param.asName())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private Py::Expr list_or_tuple_nested_element(Py::Expr list_or_tuple) {
|
||||
exists(Py::Expr elt |
|
||||
elt = list_or_tuple.(Py::Tuple).getAnElt()
|
||||
private Expr list_or_tuple_nested_element(Expr list_or_tuple) {
|
||||
exists(Expr elt |
|
||||
elt = list_or_tuple.(Tuple).getAnElt()
|
||||
or
|
||||
elt = list_or_tuple.(Py::List).getAnElt()
|
||||
elt = list_or_tuple.(List).getAnElt()
|
||||
|
|
||||
result = elt
|
||||
or
|
||||
@@ -603,12 +603,12 @@ private Py::Expr list_or_tuple_nested_element(Py::Expr list_or_tuple) {
|
||||
|
||||
/**
|
||||
* A control flow node corresponding to a deletion statement, such as `del x`.
|
||||
* There can be multiple `DeletionNode`s for each `Py::Delete` such that each
|
||||
* There can be multiple `DeletionNode`s for each `Delete` such that each
|
||||
* target has own `DeletionNode`. The CFG for `del a, x.y` looks like:
|
||||
* `NameNode('a') -> DeletionNode -> NameNode('b') -> AttrNode('y') -> DeletionNode`.
|
||||
*/
|
||||
class DeletionNode extends ControlFlowNode {
|
||||
DeletionNode() { toAst(this) instanceof Py::Delete }
|
||||
DeletionNode() { toAst(this) instanceof Delete }
|
||||
|
||||
/** Gets the unique target of this deletion node. */
|
||||
ControlFlowNode getTarget() { result.getASuccessor() = this }
|
||||
@@ -617,9 +617,9 @@ class DeletionNode extends ControlFlowNode {
|
||||
/** A control flow node corresponding to a sequence (tuple or list) literal */
|
||||
abstract class SequenceNode extends ControlFlowNode {
|
||||
SequenceNode() {
|
||||
toAst(this) instanceof Py::Tuple
|
||||
toAst(this) instanceof Tuple
|
||||
or
|
||||
toAst(this) instanceof Py::List
|
||||
toAst(this) instanceof List
|
||||
}
|
||||
|
||||
/** Gets the control flow node for an element of this sequence */
|
||||
@@ -632,11 +632,11 @@ abstract class SequenceNode extends ControlFlowNode {
|
||||
|
||||
/** A control flow node corresponding to a tuple expression such as `( 1, 3, 5, 7, 9 )` */
|
||||
class TupleNode extends SequenceNode {
|
||||
TupleNode() { toAst(this) instanceof Py::Tuple }
|
||||
TupleNode() { toAst(this) instanceof Tuple }
|
||||
|
||||
override ControlFlowNode getElement(int n) {
|
||||
Stages::AST::ref() and
|
||||
exists(Py::Tuple t | this.getNode() = t and result.getNode() = t.getElt(n)) and
|
||||
exists(Tuple t | this.getNode() = t and result.getNode() = t.getElt(n)) and
|
||||
(
|
||||
result.getBasicBlock().dominates(this.getBasicBlock())
|
||||
or
|
||||
@@ -647,10 +647,10 @@ class TupleNode extends SequenceNode {
|
||||
|
||||
/** A control flow node corresponding to a list expression, such as `[ 1, 3, 5, 7, 9 ]` */
|
||||
class ListNode extends SequenceNode {
|
||||
ListNode() { toAst(this) instanceof Py::List }
|
||||
ListNode() { toAst(this) instanceof List }
|
||||
|
||||
override ControlFlowNode getElement(int n) {
|
||||
exists(Py::List l | this.getNode() = l and result.getNode() = l.getElt(n)) and
|
||||
exists(List l | this.getNode() = l and result.getNode() = l.getElt(n)) and
|
||||
(
|
||||
result.getBasicBlock().dominates(this.getBasicBlock())
|
||||
or
|
||||
@@ -661,10 +661,10 @@ class ListNode extends SequenceNode {
|
||||
|
||||
/** A control flow node corresponding to a set expression, such as `{ 1, 3, 5, 7, 9 }` */
|
||||
class SetNode extends ControlFlowNode {
|
||||
SetNode() { toAst(this) instanceof Py::Set }
|
||||
SetNode() { toAst(this) instanceof Set }
|
||||
|
||||
ControlFlowNode getAnElement() {
|
||||
exists(Py::Set s | this.getNode() = s and result.getNode() = s.getElt(_)) and
|
||||
exists(Set s | this.getNode() = s and result.getNode() = s.getElt(_)) and
|
||||
(
|
||||
result.getBasicBlock().dominates(this.getBasicBlock())
|
||||
or
|
||||
@@ -675,20 +675,20 @@ class SetNode extends ControlFlowNode {
|
||||
|
||||
/** A control flow node corresponding to a dictionary literal, such as `{ 'a': 1, 'b': 2 }` */
|
||||
class DictNode extends ControlFlowNode {
|
||||
DictNode() { toAst(this) instanceof Py::Dict }
|
||||
DictNode() { toAst(this) instanceof Dict }
|
||||
|
||||
/**
|
||||
* Gets a key of this dictionary literal node, for those items that have keys
|
||||
* E.g, in {'a':1, **b} this returns only 'a'
|
||||
*/
|
||||
ControlFlowNode getAKey() {
|
||||
exists(Py::Dict d | this.getNode() = d and result.getNode() = d.getAKey()) and
|
||||
exists(Dict d | this.getNode() = d and result.getNode() = d.getAKey()) and
|
||||
result.getBasicBlock().dominates(this.getBasicBlock())
|
||||
}
|
||||
|
||||
/** Gets a value of this dictionary literal node */
|
||||
ControlFlowNode getAValue() {
|
||||
exists(Py::Dict d | this.getNode() = d and result.getNode() = d.getAValue()) and
|
||||
exists(Dict d | this.getNode() = d and result.getNode() = d.getAValue()) and
|
||||
result.getBasicBlock().dominates(this.getBasicBlock())
|
||||
}
|
||||
}
|
||||
@@ -712,23 +712,21 @@ class IterableNode extends ControlFlowNode {
|
||||
}
|
||||
}
|
||||
|
||||
private Py::AstNode assigned_value(Py::Expr lhs) {
|
||||
private AstNode assigned_value(Expr lhs) {
|
||||
/* lhs = result */
|
||||
exists(Py::Assign a | a.getATarget() = lhs and result = a.getValue())
|
||||
exists(Assign a | a.getATarget() = lhs and result = a.getValue())
|
||||
or
|
||||
/* lhs := result */
|
||||
exists(Py::AssignExpr a | a.getTarget() = lhs and result = a.getValue())
|
||||
exists(AssignExpr a | a.getTarget() = lhs and result = a.getValue())
|
||||
or
|
||||
/* lhs : annotation = result */
|
||||
exists(Py::AnnAssign a | a.getTarget() = lhs and result = a.getValue())
|
||||
exists(AnnAssign a | a.getTarget() = lhs and result = a.getValue())
|
||||
or
|
||||
/* import result as lhs */
|
||||
exists(Py::Alias a | a.getAsname() = lhs and result = a.getValue())
|
||||
exists(Alias a | a.getAsname() = lhs and result = a.getValue())
|
||||
or
|
||||
/* lhs += x => result = (lhs + x) */
|
||||
exists(Py::AugAssign a, Py::BinaryExpr b |
|
||||
b = a.getOperation() and result = b and lhs = b.getLeft()
|
||||
)
|
||||
exists(AugAssign a, BinaryExpr b | b = a.getOperation() and result = b and lhs = b.getLeft())
|
||||
or
|
||||
/*
|
||||
* ..., lhs, ... = ..., result, ...
|
||||
@@ -736,31 +734,31 @@ private Py::AstNode assigned_value(Py::Expr lhs) {
|
||||
* ..., (..., lhs, ...), ... = ..., (..., result, ...), ...
|
||||
*/
|
||||
|
||||
exists(Py::Assign a | nested_sequence_assign(a.getATarget(), a.getValue(), lhs, result))
|
||||
exists(Assign a | nested_sequence_assign(a.getATarget(), a.getValue(), lhs, result))
|
||||
or
|
||||
/* for lhs in seq: => `result` is the `for` node, representing the `iter(next(seq))` operation. */
|
||||
result.(Py::For).getTarget() = lhs
|
||||
result.(For).getTarget() = lhs
|
||||
or
|
||||
exists(Py::Parameter param | lhs = param.asName() and result = param.getDefault())
|
||||
exists(Parameter param | lhs = param.asName() and result = param.getDefault())
|
||||
}
|
||||
|
||||
predicate nested_sequence_assign(
|
||||
Py::Expr left_parent, Py::Expr right_parent, Py::Expr left_result, Py::Expr right_result
|
||||
Expr left_parent, Expr right_parent, Expr left_result, Expr right_result
|
||||
) {
|
||||
exists(Py::Assign a |
|
||||
exists(Assign a |
|
||||
a.getATarget().getASubExpression*() = left_parent and
|
||||
a.getValue().getASubExpression*() = right_parent
|
||||
) and
|
||||
exists(int i, Py::Expr left_elem, Py::Expr right_elem |
|
||||
exists(int i, Expr left_elem, Expr right_elem |
|
||||
(
|
||||
left_elem = left_parent.(Py::Tuple).getElt(i)
|
||||
left_elem = left_parent.(Tuple).getElt(i)
|
||||
or
|
||||
left_elem = left_parent.(Py::List).getElt(i)
|
||||
left_elem = left_parent.(List).getElt(i)
|
||||
) and
|
||||
(
|
||||
right_elem = right_parent.(Py::Tuple).getElt(i)
|
||||
right_elem = right_parent.(Tuple).getElt(i)
|
||||
or
|
||||
right_elem = right_parent.(Py::List).getElt(i)
|
||||
right_elem = right_parent.(List).getElt(i)
|
||||
)
|
||||
|
|
||||
left_result = left_elem and right_result = right_elem
|
||||
@@ -771,9 +769,9 @@ predicate nested_sequence_assign(
|
||||
|
||||
/** A flow node for a `for` statement. */
|
||||
class ForNode extends ControlFlowNode {
|
||||
ForNode() { toAst(this) instanceof Py::For }
|
||||
ForNode() { toAst(this) instanceof For }
|
||||
|
||||
override Py::For getNode() { result = super.getNode() }
|
||||
override For getNode() { result = super.getNode() }
|
||||
|
||||
/** Holds if this `for` statement causes iteration over `sequence` storing each step of the iteration in `target` */
|
||||
predicate iterates(ControlFlowNode target, ControlFlowNode sequence) {
|
||||
@@ -784,7 +782,7 @@ class ForNode extends ControlFlowNode {
|
||||
|
||||
/** Gets the sequence node for this `for` statement. */
|
||||
ControlFlowNode getSequence() {
|
||||
exists(Py::For for |
|
||||
exists(For for |
|
||||
toAst(this) = for and
|
||||
for.getIter() = result.getNode()
|
||||
|
|
||||
@@ -794,7 +792,7 @@ class ForNode extends ControlFlowNode {
|
||||
|
||||
/** A possible `target` for this `for` statement, not accounting for loop unrolling */
|
||||
private ControlFlowNode possibleTarget() {
|
||||
exists(Py::For for |
|
||||
exists(For for |
|
||||
toAst(this) = for and
|
||||
for.getTarget() = result.getNode() and
|
||||
this.getBasicBlock().dominates(result.getBasicBlock())
|
||||
@@ -811,11 +809,11 @@ class ForNode extends ControlFlowNode {
|
||||
|
||||
/** A flow node for a `raise` statement */
|
||||
class RaiseStmtNode extends ControlFlowNode {
|
||||
RaiseStmtNode() { toAst(this) instanceof Py::Raise }
|
||||
RaiseStmtNode() { toAst(this) instanceof Raise }
|
||||
|
||||
/** Gets the control flow node for the exception raised by this raise statement */
|
||||
ControlFlowNode getException() {
|
||||
exists(Py::Raise r |
|
||||
exists(Raise r |
|
||||
r = toAst(this) and
|
||||
r.getException() = toAst(result) and
|
||||
result.getBasicBlock().dominates(this.getBasicBlock())
|
||||
@@ -829,36 +827,36 @@ class RaiseStmtNode extends ControlFlowNode {
|
||||
*/
|
||||
class NameNode extends ControlFlowNode {
|
||||
NameNode() {
|
||||
exists(Py::Name n | py_flow_bb_node(this, n, _, _))
|
||||
exists(Name n | py_flow_bb_node(this, n, _, _))
|
||||
or
|
||||
exists(Py::PlaceHolder p | py_flow_bb_node(this, p, _, _))
|
||||
exists(PlaceHolder p | py_flow_bb_node(this, p, _, _))
|
||||
}
|
||||
|
||||
/** Whether this flow node defines the variable `v`. */
|
||||
predicate defines(Py::Variable v) {
|
||||
exists(Py::Name d | this.getNode() = d and d.defines(v)) and
|
||||
predicate defines(Variable v) {
|
||||
exists(Name d | this.getNode() = d and d.defines(v)) and
|
||||
not this.isLoad()
|
||||
}
|
||||
|
||||
/** Whether this flow node deletes the variable `v`. */
|
||||
predicate deletes(Py::Variable v) { exists(Py::Name d | this.getNode() = d and d.deletes(v)) }
|
||||
predicate deletes(Variable v) { exists(Name d | this.getNode() = d and d.deletes(v)) }
|
||||
|
||||
/** Whether this flow node uses the variable `v`. */
|
||||
predicate uses(Py::Variable v) {
|
||||
predicate uses(Variable v) {
|
||||
this.isLoad() and
|
||||
exists(Py::Name u | this.getNode() = u and u.uses(v))
|
||||
exists(Name u | this.getNode() = u and u.uses(v))
|
||||
or
|
||||
exists(Py::PlaceHolder u |
|
||||
this.getNode() = u and u.getVariable() = v and u.getCtx() instanceof Py::Load
|
||||
exists(PlaceHolder u |
|
||||
this.getNode() = u and u.getVariable() = v and u.getCtx() instanceof Load
|
||||
)
|
||||
or
|
||||
Scopes::use_of_global_variable(this, v.getScope(), v.getId())
|
||||
}
|
||||
|
||||
string getId() {
|
||||
result = this.getNode().(Py::Name).getId()
|
||||
result = this.getNode().(Name).getId()
|
||||
or
|
||||
result = this.getNode().(Py::PlaceHolder).getId()
|
||||
result = this.getNode().(PlaceHolder).getId()
|
||||
}
|
||||
|
||||
/** Whether this is a use of a local variable. */
|
||||
@@ -870,39 +868,37 @@ class NameNode extends ControlFlowNode {
|
||||
/** Whether this is a use of a global (including builtin) variable. */
|
||||
predicate isGlobal() { Scopes::use_of_global_variable(this, _, _) }
|
||||
|
||||
predicate isSelf() {
|
||||
exists(Py::SsaVariable selfvar | selfvar.isSelf() and selfvar.getAUse() = this)
|
||||
}
|
||||
predicate isSelf() { exists(SsaVariable selfvar | selfvar.isSelf() and selfvar.getAUse() = this) }
|
||||
}
|
||||
|
||||
/** A control flow node corresponding to a named constant, one of `None`, `True` or `False`. */
|
||||
class NameConstantNode extends NameNode {
|
||||
NameConstantNode() { exists(Py::NameConstant n | py_flow_bb_node(this, n, _, _)) }
|
||||
NameConstantNode() { exists(NameConstant n | py_flow_bb_node(this, n, _, _)) }
|
||||
/*
|
||||
* We ought to override uses as well, but that has
|
||||
* a serious performance impact.
|
||||
* deprecated predicate uses(Py::Variable v) { none() }
|
||||
* deprecated predicate uses(Variable v) { none() }
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
/** A control flow node corresponding to a starred expression, `*a`. */
|
||||
class StarredNode extends ControlFlowNode {
|
||||
StarredNode() { toAst(this) instanceof Py::Starred }
|
||||
StarredNode() { toAst(this) instanceof Starred }
|
||||
|
||||
ControlFlowNode getValue() { toAst(result) = toAst(this).(Py::Starred).getValue() }
|
||||
ControlFlowNode getValue() { toAst(result) = toAst(this).(Starred).getValue() }
|
||||
}
|
||||
|
||||
/** The ControlFlowNode for an 'except' statement. */
|
||||
class ExceptFlowNode extends ControlFlowNode {
|
||||
ExceptFlowNode() { this.getNode() instanceof Py::ExceptStmt }
|
||||
ExceptFlowNode() { this.getNode() instanceof ExceptStmt }
|
||||
|
||||
/**
|
||||
* Gets the type handled by this exception handler.
|
||||
* `Py::ExceptionType` in `except Py::ExceptionType as e:`
|
||||
* `ExceptionType` in `except ExceptionType as e:`
|
||||
*/
|
||||
ControlFlowNode getType() {
|
||||
exists(Py::ExceptStmt ex |
|
||||
exists(ExceptStmt ex |
|
||||
this.getBasicBlock().dominates(result.getBasicBlock()) and
|
||||
ex = this.getNode() and
|
||||
result.getNode() = ex.getType()
|
||||
@@ -911,10 +907,10 @@ class ExceptFlowNode extends ControlFlowNode {
|
||||
|
||||
/**
|
||||
* Gets the name assigned to the handled exception, if any.
|
||||
* `e` in `except Py::ExceptionType as e:`
|
||||
* `e` in `except ExceptionType as e:`
|
||||
*/
|
||||
ControlFlowNode getName() {
|
||||
exists(Py::ExceptStmt ex |
|
||||
exists(ExceptStmt ex |
|
||||
this.getBasicBlock().dominates(result.getBasicBlock()) and
|
||||
ex = this.getNode() and
|
||||
result.getNode() = ex.getName()
|
||||
@@ -924,30 +920,30 @@ class ExceptFlowNode extends ControlFlowNode {
|
||||
|
||||
/** The ControlFlowNode for an 'except*' statement. */
|
||||
class ExceptGroupFlowNode extends ControlFlowNode {
|
||||
ExceptGroupFlowNode() { this.getNode() instanceof Py::ExceptGroupStmt }
|
||||
ExceptGroupFlowNode() { this.getNode() instanceof ExceptGroupStmt }
|
||||
|
||||
/**
|
||||
* Gets the type handled by this exception handler.
|
||||
* `Py::ExceptionType` in `except* Py::ExceptionType as e:`
|
||||
* `ExceptionType` in `except* ExceptionType as e:`
|
||||
*/
|
||||
ControlFlowNode getType() {
|
||||
this.getBasicBlock().dominates(result.getBasicBlock()) and
|
||||
result.getNode() = this.getNode().(Py::ExceptGroupStmt).getType()
|
||||
result.getNode() = this.getNode().(ExceptGroupStmt).getType()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the name assigned to the handled exception, if any.
|
||||
* `e` in `except* Py::ExceptionType as e:`
|
||||
* `e` in `except* ExceptionType as e:`
|
||||
*/
|
||||
ControlFlowNode getName() {
|
||||
this.getBasicBlock().dominates(result.getBasicBlock()) and
|
||||
result.getNode() = this.getNode().(Py::ExceptGroupStmt).getName()
|
||||
result.getNode() = this.getNode().(ExceptGroupStmt).getName()
|
||||
}
|
||||
}
|
||||
|
||||
private module Scopes {
|
||||
private predicate fast_local(NameNode n) {
|
||||
exists(Py::FastLocalVariable v |
|
||||
exists(FastLocalVariable v |
|
||||
n.uses(v) and
|
||||
v.getScope() = n.getScope()
|
||||
)
|
||||
@@ -956,15 +952,15 @@ private module Scopes {
|
||||
predicate local(NameNode n) {
|
||||
fast_local(n)
|
||||
or
|
||||
exists(Py::SsaVariable var |
|
||||
exists(SsaVariable var |
|
||||
var.getAUse() = n and
|
||||
n.getScope() instanceof Py::Class and
|
||||
n.getScope() instanceof Class and
|
||||
exists(var.getDefinition())
|
||||
)
|
||||
}
|
||||
|
||||
predicate non_local(NameNode n) {
|
||||
exists(Py::FastLocalVariable flv |
|
||||
exists(FastLocalVariable flv |
|
||||
flv.getALoad() = n.getNode() and
|
||||
not flv.getScope() = n.getScope()
|
||||
)
|
||||
@@ -972,20 +968,20 @@ private module Scopes {
|
||||
|
||||
// magic is fine, but we get questionable join-ordering of it
|
||||
pragma[nomagic]
|
||||
predicate use_of_global_variable(NameNode n, Py::Module scope, string name) {
|
||||
predicate use_of_global_variable(NameNode n, Module scope, string name) {
|
||||
n.isLoad() and
|
||||
not non_local(n) and
|
||||
not exists(Py::SsaVariable var | var.getAUse() = n |
|
||||
var.getVariable() instanceof Py::FastLocalVariable
|
||||
not exists(SsaVariable var | var.getAUse() = n |
|
||||
var.getVariable() instanceof FastLocalVariable
|
||||
or
|
||||
n.getScope() instanceof Py::Class and
|
||||
n.getScope() instanceof Class and
|
||||
not maybe_undefined(var)
|
||||
) and
|
||||
name = n.getId() and
|
||||
scope = n.getEnclosingModule()
|
||||
}
|
||||
|
||||
private predicate maybe_undefined(Py::SsaVariable var) {
|
||||
private predicate maybe_undefined(SsaVariable var) {
|
||||
not exists(var.getDefinition()) and not py_ssa_phi(var, _)
|
||||
or
|
||||
var.getDefinition().isDelete()
|
||||
@@ -1062,13 +1058,13 @@ class BasicBlock extends @py_flow_node {
|
||||
private predicate oneNodeBlock() { this.firstNode() = this.getLastNode() }
|
||||
|
||||
private predicate startLocationInfo(string file, int line, int col) {
|
||||
if this.firstNode().getNode() instanceof Py::Scope
|
||||
if this.firstNode().getNode() instanceof Scope
|
||||
then this.firstNode().getASuccessor().getLocation().hasLocationInfo(file, line, col, _, _)
|
||||
else this.firstNode().getLocation().hasLocationInfo(file, line, col, _, _)
|
||||
}
|
||||
|
||||
private predicate endLocationInfo(int endl, int endc) {
|
||||
if this.getLastNode().getNode() instanceof Py::Scope and not this.oneNodeBlock()
|
||||
if this.getLastNode().getNode() instanceof Scope and not this.oneNodeBlock()
|
||||
then this.getLastNode().getAPredecessor().getLocation().hasLocationInfo(_, _, _, endl, endc)
|
||||
else this.getLastNode().getLocation().hasLocationInfo(_, _, _, endl, endc)
|
||||
}
|
||||
@@ -1085,7 +1081,7 @@ class BasicBlock extends @py_flow_node {
|
||||
|
||||
/** Whether flow from this basic block reaches a normal exit from its scope */
|
||||
predicate reachesExit() {
|
||||
exists(Py::Scope s | s.getANormalExit().getBasicBlock() = this)
|
||||
exists(Scope s | s.getANormalExit().getBasicBlock() = this)
|
||||
or
|
||||
this.getASuccessor().reachesExit()
|
||||
}
|
||||
@@ -1126,7 +1122,7 @@ class BasicBlock extends @py_flow_node {
|
||||
|
||||
/** Gets the scope of this block */
|
||||
pragma[nomagic]
|
||||
Py::Scope getScope() {
|
||||
Scope getScope() {
|
||||
exists(ControlFlowNode n | n.getBasicBlock() = this |
|
||||
/* Take care not to use an entry or exit node as that node's scope will be the outer scope */
|
||||
not py_scope_flow(n, _, -1) and
|
||||
@@ -1149,17 +1145,17 @@ class BasicBlock extends @py_flow_node {
|
||||
predicate reaches(BasicBlock other) { this = other or this.strictlyReaches(other) }
|
||||
|
||||
/**
|
||||
* Gets the `Py::ConditionBlock`, if any, that controls this block and
|
||||
* does not control any other `Py::ConditionBlock`s that control this block.
|
||||
* That is the `Py::ConditionBlock` that is closest dominator.
|
||||
* Gets the `ConditionBlock`, if any, that controls this block and
|
||||
* does not control any other `ConditionBlock`s that control this block.
|
||||
* That is the `ConditionBlock` that is closest dominator.
|
||||
*/
|
||||
Py::ConditionBlock getImmediatelyControllingBlock() {
|
||||
ConditionBlock getImmediatelyControllingBlock() {
|
||||
result = this.nonControllingImmediateDominator*().getImmediateDominator()
|
||||
}
|
||||
|
||||
private BasicBlock nonControllingImmediateDominator() {
|
||||
result = this.getImmediateDominator() and
|
||||
not result.(Py::ConditionBlock).controls(this, _)
|
||||
not result.(ConditionBlock).controls(this, _)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1179,7 +1175,7 @@ private class ControlFlowNodeAlias = ControlFlowNode;
|
||||
|
||||
final private class FinalBasicBlock = BasicBlock;
|
||||
|
||||
module Cfg implements BB::CfgSig<Py::Location> {
|
||||
module Cfg implements BB::CfgSig<Location> {
|
||||
private import codeql.controlflow.SuccessorType
|
||||
|
||||
class ControlFlowNode = ControlFlowNodeAlias;
|
||||
@@ -1190,7 +1186,7 @@ module Cfg implements BB::CfgSig<Py::Location> {
|
||||
// Using the location of the first node is simple
|
||||
// and we just need a way to identify the basic block
|
||||
// during debugging, so this will be serviceable.
|
||||
Py::Location getLocation() { result = super.getNode(0).getLocation() }
|
||||
Location getLocation() { result = super.getNode(0).getLocation() }
|
||||
|
||||
int length() { result = count(int i | exists(this.getNode(i))) }
|
||||
|
||||
|
||||
@@ -1,12 +0,0 @@
|
||||
| test.rs:19:9:19:34 | ...::compute(...) | HashingAlgorithm MD5 WEAK inputs:1 |
|
||||
| test.rs:20:9:20:40 | ...::compute(...) | HashingAlgorithm MD5 WEAK inputs:1 |
|
||||
| test.rs:21:9:21:34 | ...::compute(...) | HashingAlgorithm MD5 WEAK inputs:1 |
|
||||
| test.rs:22:9:22:44 | ...::compute(...) | HashingAlgorithm MD5 WEAK inputs:1 |
|
||||
| test.rs:67:26:67:40 | ...::new(...) | HashingAlgorithm MD5 WEAK |
|
||||
| test.rs:73:9:73:23 | ...::new(...) | HashingAlgorithm MD5 WEAK |
|
||||
| test.rs:74:9:74:23 | ...::new(...) | HashingAlgorithm MD5 WEAK |
|
||||
| test.rs:133:26:133:40 | ...::new(...) | HashingAlgorithm MD5 WEAK |
|
||||
| test.rs:156:26:156:40 | ...::new(...) | HashingAlgorithm MD5 WEAK |
|
||||
| test.rs:176:13:176:24 | ...::new(...) | EncryptionAlgorithm SEED |
|
||||
| test.rs:199:22:199:32 | ...::new(...) | HashingAlgorithm SHA1 WEAK |
|
||||
| test.rs:211:13:211:35 | ...::compute(...) | HashingAlgorithm MD5 WEAK inputs:1 |
|
||||
@@ -1,3 +0,0 @@
|
||||
query: queries/summary/CryptographicOperations.ql
|
||||
postprocess:
|
||||
- utils/test/InlineExpectationsTestQuery.ql
|
||||
@@ -1,13 +1,9 @@
|
||||
#select
|
||||
| test.rs:20:9:20:24 | ...::compute | test.rs:20:26:20:39 | credit_card_no | test.rs:20:9:20:24 | ...::compute | $@ is used in a hashing algorithm (MD5) that is insecure. | test.rs:20:26:20:39 | credit_card_no | Sensitive data (private) |
|
||||
| test.rs:21:9:21:24 | ...::compute | test.rs:21:26:21:33 | password | test.rs:21:9:21:24 | ...::compute | $@ is used in a hashing algorithm (MD5) that is insecure for password hashing, since it is not a computationally expensive hash function. | test.rs:21:26:21:33 | password | Sensitive data (password) |
|
||||
| test.rs:211:13:211:28 | ...::compute | test.rs:226:29:226:36 | password | test.rs:211:13:211:28 | ...::compute | $@ is used in a hashing algorithm (MD5) that is insecure for password hashing, since it is not a computationally expensive hash function. | test.rs:226:29:226:36 | password | Sensitive data (password) |
|
||||
edges
|
||||
| test.rs:20:26:20:39 | credit_card_no | test.rs:20:9:20:24 | ...::compute | provenance | MaD:1 Sink:MaD:1 |
|
||||
| test.rs:21:26:21:33 | password | test.rs:21:9:21:24 | ...::compute | provenance | MaD:1 Sink:MaD:1 |
|
||||
| test.rs:210:20:210:30 | ...: ... | test.rs:211:30:211:34 | value | provenance | |
|
||||
| test.rs:211:30:211:34 | value | test.rs:211:13:211:28 | ...::compute | provenance | MaD:1 Sink:MaD:1 |
|
||||
| test.rs:226:29:226:36 | password | test.rs:210:20:210:30 | ...: ... | provenance | |
|
||||
models
|
||||
| 1 | Sink: md5::compute; Argument[0]; hasher-input |
|
||||
nodes
|
||||
@@ -15,8 +11,4 @@ nodes
|
||||
| test.rs:20:26:20:39 | credit_card_no | semmle.label | credit_card_no |
|
||||
| test.rs:21:9:21:24 | ...::compute | semmle.label | ...::compute |
|
||||
| test.rs:21:26:21:33 | password | semmle.label | password |
|
||||
| test.rs:210:20:210:30 | ...: ... | semmle.label | ...: ... |
|
||||
| test.rs:211:13:211:28 | ...::compute | semmle.label | ...::compute |
|
||||
| test.rs:211:30:211:34 | value | semmle.label | value |
|
||||
| test.rs:226:29:226:36 | password | semmle.label | password |
|
||||
subpaths
|
||||
|
||||
@@ -16,10 +16,10 @@ fn test_hash_algorithms(
|
||||
_ = md5::Md5::digest(encrypted_password);
|
||||
|
||||
// MD5 (alternative / older library)
|
||||
_ = md5_alt::compute(harmless); // $ Alert[rust/summary/cryptographic-operations]
|
||||
_ = md5_alt::compute(credit_card_no); // $ Alert[rust/summary/cryptographic-operations] Alert[rust/weak-sensitive-data-hashing]
|
||||
_ = md5_alt::compute(password); // $ Alert[rust/summary/cryptographic-operations] Alert[rust/weak-sensitive-data-hashing]
|
||||
_ = md5_alt::compute(encrypted_password); // $ Alert[rust/summary/cryptographic-operations]
|
||||
_ = md5_alt::compute(harmless);
|
||||
_ = md5_alt::compute(credit_card_no); // $ Alert[rust/weak-sensitive-data-hashing]
|
||||
_ = md5_alt::compute(password); // $ Alert[rust/weak-sensitive-data-hashing]
|
||||
_ = md5_alt::compute(encrypted_password);
|
||||
|
||||
// SHA-1
|
||||
_ = sha1::Sha1::digest(harmless);
|
||||
@@ -64,14 +64,14 @@ fn test_hash_code_patterns(
|
||||
_ = md5::Md5::digest(password_vec); // $ MISSING: Alert[rust/weak-sensitive-data-hashing]
|
||||
|
||||
// hash through a hasher object
|
||||
let mut md5_hasher = md5::Md5::new(); // $ Alert[rust/summary/cryptographic-operations]
|
||||
let mut md5_hasher = md5::Md5::new();
|
||||
md5_hasher.update(b"abc");
|
||||
md5_hasher.update(harmless);
|
||||
md5_hasher.update(password); // $ MISSING: Alert[rust/weak-sensitive-data-hashing]
|
||||
_ = md5_hasher.finalize();
|
||||
|
||||
_ = md5::Md5::new().chain_update(harmless).chain_update(harmless).chain_update(harmless).finalize(); // $ Alert[rust/summary/cryptographic-operations]
|
||||
_ = md5::Md5::new().chain_update(harmless).chain_update(password).chain_update(harmless).finalize(); // $ Alert[rust/summary/cryptographic-operations] MISSING: Alert[rust/weak-sensitive-data-hashing]
|
||||
_ = md5::Md5::new().chain_update(harmless).chain_update(harmless).chain_update(harmless).finalize();
|
||||
_ = md5::Md5::new().chain_update(harmless).chain_update(password).chain_update(harmless).finalize(); // $ MISSING: Alert[rust/weak-sensitive-data-hashing]
|
||||
|
||||
_ = md5::Md5::new_with_prefix(harmless).finalize();
|
||||
_ = md5::Md5::new_with_prefix(password).finalize(); // $ MISSING: Alert[rust/weak-sensitive-data-hashing]
|
||||
@@ -130,7 +130,7 @@ fn test_hash_structs() {
|
||||
let str3c = serde_urlencoded::to_string(&s3).unwrap();
|
||||
|
||||
// hash with MD5
|
||||
let mut md5_hasher = md5::Md5::new(); // $ Alert[rust/summary/cryptographic-operations]
|
||||
let mut md5_hasher = md5::Md5::new();
|
||||
md5_hasher.update(s1.data);
|
||||
md5_hasher.update(s2.credit_card_no); // $ MISSING: Alert[rust/weak-sensitive-data-hashing]
|
||||
md5_hasher.update(s3.password); // $ MISSING: Alert[rust/weak-sensitive-data-hashing]
|
||||
@@ -153,75 +153,8 @@ fn test_hash_file(
|
||||
let mut harmless_file = std::fs::File::open(harmless_filename).unwrap();
|
||||
let mut password_file = std::fs::File::open(password_filename).unwrap();
|
||||
|
||||
let mut md5_hasher = md5::Md5::new(); // $ Alert[rust/summary/cryptographic-operations]
|
||||
let mut md5_hasher = md5::Md5::new();
|
||||
_ = std::io::copy(&mut harmless_file, &mut md5_hasher);
|
||||
_ = std::io::copy(&mut password_file, &mut md5_hasher); // $ MISSING: Alert[rust/weak-sensitive-data-hashing]
|
||||
_ = md5_hasher.finalize();
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
struct Seed {
|
||||
}
|
||||
|
||||
impl Seed {
|
||||
fn new(_seed_value: u64) -> Self {
|
||||
Seed { }
|
||||
}
|
||||
}
|
||||
|
||||
fn test_seed() {
|
||||
// this will be misrecognized as a use of the SEED algorithm, but SEED is strong and the input
|
||||
// is not sensitive data, so `rust/weak-sensitive-data-hashing` should not report a result here.
|
||||
let _ = Seed::new(0); // $ Alert[rust/summary/cryptographic-operations]
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
struct Sha1 {
|
||||
}
|
||||
|
||||
impl Sha1 {
|
||||
const fn new() -> Self {
|
||||
Sha1 { }
|
||||
}
|
||||
|
||||
const fn update(&mut self, _data: &[u8]) {
|
||||
// ...
|
||||
}
|
||||
|
||||
const fn finalize(self) -> [u8; 20] {
|
||||
[0; 20]
|
||||
}
|
||||
}
|
||||
|
||||
fn sha1_test(password: &[u8]) {
|
||||
let mut hasher = Sha1::new(); // $ Alert[rust/summary/cryptographic-operations]
|
||||
hasher.update(password); // $ MISSING: Alert[rust/weak-sensitive-data-hashing]
|
||||
_ = hasher.finalize();
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
struct HashCollection {
|
||||
}
|
||||
|
||||
impl HashCollection {
|
||||
pub fn add_sig(value: &str) -> Self {
|
||||
_ = md5_alt::compute(value); // $ Alert[rust/summary/cryptographic-operations] Alert[rust/weak-sensitive-data-hashing]
|
||||
|
||||
// ...
|
||||
|
||||
HashCollection { }
|
||||
}
|
||||
}
|
||||
|
||||
fn test_hash_collection() {
|
||||
// this indirectly performs MD5 hashing, but the data is not sensitive
|
||||
let id: &str = "my_id_1234567890";
|
||||
HashCollection::add_sig(id);
|
||||
|
||||
// this indirectly performs MD5 hashing, and the data is sensitive; the result is reported here
|
||||
let password: &str = "password123";
|
||||
HashCollection::add_sig(password); // $ Source
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user