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

Skip to content

Commit 39cd86a

Browse files
committed
C#: Move handling of callables into shared control flow library
1 parent bca51a9 commit 39cd86a

2 files changed

Lines changed: 121 additions & 119 deletions

File tree

csharp/ql/lib/semmle/code/csharp/controlflow/ControlFlowGraph.qll

Lines changed: 43 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ private module Ast implements AstSig<Location> {
2525

2626
class AstNode = ControlFlowElementOrCallable;
2727

28-
private predicate skipControlFlow(AstNode e) {
28+
additional predicate skipControlFlow(AstNode e) {
2929
e instanceof TypeAccess and
3030
not e instanceof TypeAccessPatternExpr
3131
or
@@ -82,13 +82,8 @@ private module Ast implements AstSig<Location> {
8282

8383
AstNode callableGetBody(Callable c) {
8484
not skipControlFlow(result) and
85-
(
86-
result = c.getBody() or
87-
result = c.(Constructor).getObjectInitializerCall() or
88-
result = c.(Constructor).getInitializer() or
89-
c.(ObjectInitMethod).initializes(result) or
90-
Initializers::staticMemberInitializer(c, result)
91-
)
85+
result = c.getBody() and
86+
not c instanceof Constructor // handled in `callableGetBodyPart`
9287
}
9388

9489
class Stmt = CS::Stmt;
@@ -222,10 +217,21 @@ private module Ast implements AstSig<Location> {
222217
* Unlike the standard `Compilation` class, this class also supports buildless
223218
* extraction.
224219
*/
225-
private newtype CompilationExt =
220+
private newtype TCompilationExt =
226221
TCompilation(Compilation c) { not extractionIsStandalone() } or
227222
TBuildless() { extractionIsStandalone() }
228223

224+
private class CompilationExt extends TCompilationExt {
225+
string toString() {
226+
exists(Compilation c |
227+
this = TCompilation(c) and
228+
result = c.toString()
229+
)
230+
or
231+
this = TBuildless() and result = "buildless compilation"
232+
}
233+
}
234+
229235
/** Gets the compilation that source file `f` belongs to. */
230236
private CompilationExt getCompilation(File f) {
231237
exists(Compilation c |
@@ -286,32 +292,18 @@ private module Initializers {
286292
}
287293

288294
/**
289-
* Gets the `i`th member initializer expression for object initializer method `obinit`
290-
* in compilation `comp`.
295+
* Gets the `i`th member initializer expression for object initializer method `obinit`.
291296
*/
292-
AssignExpr initializedInstanceMemberOrder(ObjectInitMethod obinit, CompilationExt comp, int i) {
293-
obinit.initializes(result) and
297+
AssignExpr initializedInstanceMemberOrder(ObjectInitMethod obinit, int i) {
294298
result =
295299
rank[i + 1](AssignExpr ae0, Location l, string filepath, int startline, int startcolumn |
296300
obinit.initializes(ae0) and
297301
l = ae0.getLocation() and
298-
l.hasLocationInfo(filepath, startline, startcolumn, _, _) and
299-
getCompilation(l.getFile()) = comp
302+
l.hasLocationInfo(filepath, startline, startcolumn, _, _)
300303
|
301304
ae0 order by startline, startcolumn, filepath
302305
)
303306
}
304-
305-
/**
306-
* Gets the last member initializer expression for object initializer method `obinit`
307-
* in compilation `comp`.
308-
*/
309-
AssignExpr lastInitializer(ObjectInitMethod obinit, CompilationExt comp) {
310-
exists(int i |
311-
result = initializedInstanceMemberOrder(obinit, comp, i) and
312-
not exists(initializedInstanceMemberOrder(obinit, comp, i + 1))
313-
)
314-
}
315307
}
316308

317309
private module Exceptions {
@@ -424,6 +416,31 @@ private module Input implements InputSig1, InputSig2 {
424416
l = TLblGoto(n.(LabelStmt).getLabel())
425417
}
426418

419+
class CallableBodyPartContext = CompilationExt;
420+
421+
pragma[nomagic]
422+
Ast::AstNode callableGetBodyPart(Callable c, CallableBodyPartContext ctx, int index) {
423+
not Ast::skipControlFlow(result) and
424+
ctx = getCompilation(result.getFile()) and
425+
(
426+
result = Initializers::initializedInstanceMemberOrder(c, index)
427+
or
428+
result = Initializers::initializedStaticMemberOrder(c, index)
429+
or
430+
exists(Constructor ctor, int i, int staticMembers |
431+
c = ctor and
432+
staticMembers = count(Expr init | Initializers::staticMemberInitializer(ctor, init)) and
433+
index = staticMembers + i + 1
434+
|
435+
i = 0 and result = ctor.getObjectInitializerCall()
436+
or
437+
i = 1 and result = ctor.getInitializer()
438+
or
439+
i = 2 and result = ctor.getBody()
440+
)
441+
)
442+
}
443+
427444
private Expr getQualifier(QualifiableExpr qe) {
428445
result = qe.getQualifier() or
429446
result = qe.(ExtensionMethodCall).getArgument(0)
@@ -474,80 +491,7 @@ private module Input implements InputSig1, InputSig2 {
474491
)
475492
}
476493

477-
pragma[noinline]
478-
private MethodCall getObjectInitializerCall(Constructor ctor, CompilationExt comp) {
479-
result = ctor.getObjectInitializerCall() and
480-
comp = getCompilation(result.getFile())
481-
}
482-
483-
pragma[noinline]
484-
private ConstructorInitializer getInitializer(Constructor ctor, CompilationExt comp) {
485-
result = ctor.getInitializer() and
486-
comp = getCompilation(result.getFile())
487-
}
488-
489-
pragma[noinline]
490-
private Ast::AstNode getBody(Constructor ctor, CompilationExt comp) {
491-
result = ctor.getBody() and
492-
comp = getCompilation(result.getFile())
493-
}
494-
495494
predicate step(PreControlFlowNode n1, PreControlFlowNode n2) {
496-
exists(Constructor ctor |
497-
n1.(EntryNodeImpl).getEnclosingCallable() = ctor and
498-
if Initializers::staticMemberInitializer(ctor, _)
499-
then n2.isBefore(Initializers::initializedStaticMemberOrder(ctor, 0))
500-
else
501-
if exists(ctor.getObjectInitializerCall())
502-
then n2.isBefore(ctor.getObjectInitializerCall())
503-
else
504-
if exists(ctor.getInitializer())
505-
then n2.isBefore(ctor.getInitializer())
506-
else n2.isBefore(ctor.getBody())
507-
or
508-
exists(int i | n1.isAfter(Initializers::initializedStaticMemberOrder(ctor, i)) |
509-
n2.isBefore(Initializers::initializedStaticMemberOrder(ctor, i + 1))
510-
or
511-
not exists(Initializers::initializedStaticMemberOrder(ctor, i + 1)) and
512-
n2.isBefore(ctor.getBody())
513-
)
514-
or
515-
exists(CompilationExt comp |
516-
n1.isAfter(getObjectInitializerCall(ctor, comp)) and
517-
if exists(getInitializer(ctor, comp))
518-
then n2.isBefore(getInitializer(ctor, comp))
519-
else
520-
// This is only relevant in the context of compilation errors, since
521-
// normally the existence of an object initializer call implies the
522-
// existence of an initializer.
523-
if exists(getBody(ctor, comp))
524-
then n2.isBefore(getBody(ctor, comp))
525-
else n2.(NormalExitNodeImpl).getEnclosingCallable() = ctor
526-
or
527-
n1.isAfter(getInitializer(ctor, comp)) and
528-
if exists(getBody(ctor, comp))
529-
then n2.isBefore(getBody(ctor, comp))
530-
else n2.(NormalExitNodeImpl).getEnclosingCallable() = ctor
531-
)
532-
or
533-
n1.isAfter(ctor.getBody()) and
534-
n2.(NormalExitNodeImpl).getEnclosingCallable() = ctor
535-
)
536-
or
537-
exists(ObjectInitMethod obinit |
538-
n1.(EntryNodeImpl).getEnclosingCallable() = obinit and
539-
n2.isBefore(Initializers::initializedInstanceMemberOrder(obinit, _, 0))
540-
or
541-
exists(CompilationExt comp, int i |
542-
// Flow from one member initializer to the next
543-
n1.isAfter(Initializers::initializedInstanceMemberOrder(obinit, comp, i)) and
544-
n2.isBefore(Initializers::initializedInstanceMemberOrder(obinit, comp, i + 1))
545-
)
546-
or
547-
n1.isAfter(Initializers::lastInitializer(obinit, _)) and
548-
n2.(NormalExitNodeImpl).getEnclosingCallable() = obinit
549-
)
550-
or
551495
exists(QualifiableExpr qe | qe.isConditional() |
552496
n1.isBefore(qe) and n2.isBefore(getQualifier(qe))
553497
or

shared/controlflow/codeql/controlflow/ControlFlowGraph.qll

Lines changed: 78 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -38,16 +38,16 @@ signature module AstSig<LocationSig Location> {
3838
Location getLocation();
3939
}
4040

41-
/** Gets the child of this AST node at the specified index. */
41+
/** Gets the child of AST node `n` at the specified index. */
4242
AstNode getChild(AstNode n, int index);
4343

44-
/** Gets the immediately enclosing callable that contains this node. */
44+
/** Gets the immediately enclosing callable that contains `node`. */
4545
Callable getEnclosingCallable(AstNode node);
4646

4747
/** A callable, for example a function, method, constructor, or top-level script. */
4848
class Callable extends AstNode;
4949

50-
/** Gets the body of this callable, if any. */
50+
/** Gets the body of callable `c`, if any. */
5151
AstNode callableGetBody(Callable c);
5252

5353
/** A statement. */
@@ -454,6 +454,27 @@ module Make0<LocationSig Location, AstSig<Location> Ast> {
454454
default predicate successorValueImplies(ConditionalSuccessor t1, ConditionalSuccessor t2) {
455455
none()
456456
}
457+
458+
/**
459+
* An additional context needed to identify the body parts of a callable.
460+
*
461+
* When not used, instantiate with the `Void` type.
462+
*/
463+
class CallableBodyPartContext {
464+
/** Gets a textual representation of this context. */
465+
string toString();
466+
}
467+
468+
/**
469+
* Gets the `index`th part of the body of `c` in context `ctx`. The indices do not
470+
* need to be consecutive nor start from a specific index.
471+
*
472+
* `callableGetBodyPart(c, _, _)` and `callableGetBody(c)` must never both hold
473+
* for a given callable `c`.
474+
*/
475+
default AstNode callableGetBodyPart(Callable c, CallableBodyPartContext ctx, int index) {
476+
none()
477+
}
457478
}
458479

459480
/**
@@ -661,6 +682,34 @@ module Make0<LocationSig Location, AstSig<Location> Ast> {
661682
* not step to it, since "after" represents normal termination).
662683
*/
663684

685+
private predicate isCallableBodyPart(Callable c, AstNode n) {
686+
n = callableGetBody(c) or n = Input1::callableGetBodyPart(c, _, _)
687+
}
688+
689+
private AstNode getRankedBodyPart(Callable c, Input1::CallableBodyPartContext ctx, int rnk) {
690+
result =
691+
rank[rnk](AstNode child, int ix |
692+
child = Input1::callableGetBodyPart(c, ctx, ix)
693+
|
694+
child order by ix
695+
)
696+
}
697+
698+
private AstNode getBodyEntry(Callable c) {
699+
result = callableGetBody(c)
700+
or
701+
result = getRankedBodyPart(c, _, 1)
702+
}
703+
704+
private AstNode getBodyExit(Callable c) {
705+
result = callableGetBody(c)
706+
or
707+
exists(Input1::CallableBodyPartContext ctx, int last |
708+
result = getRankedBodyPart(c, ctx, last) and
709+
not exists(getRankedBodyPart(c, ctx, last + 1))
710+
)
711+
}
712+
664713
cached
665714
private newtype TNode =
666715
TBeforeNode(AstNode n) { Input1::cfgCachedStageRef() and exists(getEnclosingCallable(n)) } or
@@ -677,9 +726,9 @@ module Make0<LocationSig Location, AstSig<Location> Ast> {
677726
TAdditionalNode(AstNode n, string tag) {
678727
additionalNode(n, tag, _) and exists(getEnclosingCallable(n))
679728
} or
680-
TEntryNode(Callable c) { exists(callableGetBody(c)) } or
681-
TAnnotatedExitNode(Callable c, Boolean normal) { exists(callableGetBody(c)) } or
682-
TExitNode(Callable c) { exists(callableGetBody(c)) }
729+
TEntryNode(Callable c) { isCallableBodyPart(c, _) } or
730+
TAnnotatedExitNode(Callable c, Boolean normal) { isCallableBodyPart(c, _) } or
731+
TExitNode(Callable c) { isCallableBodyPart(c, _) }
683732

684733
private class NodeImpl extends TNode {
685734
/**
@@ -895,7 +944,7 @@ module Make0<LocationSig Location, AstSig<Location> Ast> {
895944
}
896945

897946
/** The `PreControlFlowNode` at the entry point of a callable. */
898-
final class EntryNodeImpl extends NodeImpl, TEntryNode {
947+
final private class EntryNodeImpl extends NodeImpl, TEntryNode {
899948
private Callable c;
900949

901950
EntryNodeImpl() { this = TEntryNode(c) }
@@ -1097,7 +1146,7 @@ module Make0<LocationSig Location, AstSig<Location> Ast> {
10971146
private predicate endAbruptCompletion(AstNode ast, PreControlFlowNode n, AbruptCompletion c) {
10981147
Input2::endAbruptCompletion(ast, n, c)
10991148
or
1100-
exists(Callable callable | ast = callableGetBody(callable) |
1149+
exists(Callable callable | isCallableBodyPart(callable, ast) |
11011150
c.getSuccessorType() instanceof ReturnSuccessor and
11021151
n.(NormalExitNodeImpl).getEnclosingCallable() = callable
11031152
or
@@ -1255,22 +1304,15 @@ module Make0<LocationSig Location, AstSig<Location> Ast> {
12551304
)
12561305
}
12571306

1258-
private predicate hasSpecificCallableSteps(Callable c) {
1259-
exists(EntryNodeImpl entry | entry.getEnclosingCallable() = c and Input2::step(entry, _))
1260-
}
1261-
12621307
/** Holds if there is a local non-abrupt step from `n1` to `n2`. */
12631308
private predicate explicitStep(PreControlFlowNode n1, PreControlFlowNode n2) {
12641309
Input2::step(n1, n2)
12651310
or
12661311
exists(Callable c |
1267-
// Allow language-specific overrides for the default entry and exit edges.
1268-
not hasSpecificCallableSteps(c) and
12691312
n1.(EntryNodeImpl).getEnclosingCallable() = c and
1270-
n2.isBefore(callableGetBody(c))
1313+
n2.isBefore(getBodyEntry(c))
12711314
or
1272-
not hasSpecificCallableSteps(c) and
1273-
n1.isAfter(callableGetBody(c)) and
1315+
n1.isAfter(getBodyExit(c)) and
12741316
n2.(NormalExitNodeImpl).getEnclosingCallable() = c
12751317
or
12761318
n1.(AnnotatedExitNodeImpl).getEnclosingCallable() = c and
@@ -1650,9 +1692,17 @@ module Make0<LocationSig Location, AstSig<Location> Ast> {
16501692
n1.isBefore(ast) and
16511693
n2.isBefore(getRankedChild(ast, 1))
16521694
or
1653-
exists(int i |
1654-
n1.isAfter(getRankedChild(ast, i)) and
1655-
n2.isBefore(getRankedChild(ast, i + 1))
1695+
exists(int i, AstNode prev, AstNode next |
1696+
n1.isAfter(prev) and
1697+
n2.isBefore(next)
1698+
|
1699+
prev = getRankedChild(ast, i) and
1700+
next = getRankedChild(ast, i + 1)
1701+
or
1702+
exists(Input1::CallableBodyPartContext ctx |
1703+
prev = getRankedBodyPart(ast, ctx, i) and
1704+
next = getRankedBodyPart(ast, ctx, i + 1)
1705+
)
16561706
)
16571707
or
16581708
(
@@ -2128,6 +2178,14 @@ module Make0<LocationSig Location, AstSig<Location> Ast> {
21282178
query predicate selfLoop(ControlFlowNode node, SuccessorType t) {
21292179
node.getASuccessor(t) = node
21302180
}
2181+
2182+
/**
2183+
* Holds if `c` is included in both `callableGetBody` and `callableGetBodyPart`.
2184+
*/
2185+
query predicate bodyPartOverlap(Callable c) {
2186+
exists(callableGetBody(c)) and
2187+
exists(Input1::callableGetBodyPart(c, _, _))
2188+
}
21312189
}
21322190
}
21332191
}

0 commit comments

Comments
 (0)