Skip to content

Commit a7f5dec

Browse files
authored
Merge branch 'main' into kaspersv/go-enable-warn-on-implicit-this
2 parents 46727af + 0b2f560 commit a7f5dec

File tree

83 files changed

+1511
-562
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

83 files changed

+1511
-562
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: feature
3+
---
4+
* A new predicate `BarrierGuard::getAnIndirectBarrierNode` has been added to the new dataflow library (`semmle.code.cpp.dataflow.new.DataFlow`) to mark indirect expressions as barrier nodes using the `BarrierGuard` API.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: majorAnalysis
3+
---
4+
* In the intermediate representation, handling of control flow after non-returning calls has been improved. This should remove false positives in queries that use the intermedite representation or libraries based on it, including the new data flow library.

cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll

Lines changed: 110 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1903,7 +1903,38 @@ signature predicate guardChecksSig(IRGuardCondition g, Expr e, boolean branch);
19031903
* in data flow and taint tracking.
19041904
*/
19051905
module BarrierGuard<guardChecksSig/3 guardChecks> {
1906-
/** Gets a node that is safely guarded by the given guard check. */
1906+
/**
1907+
* Gets an expression node that is safely guarded by the given guard check.
1908+
*
1909+
* For example, given the following code:
1910+
* ```cpp
1911+
* int x = source();
1912+
* // ...
1913+
* if(is_safe_int(x)) {
1914+
* sink(x);
1915+
* }
1916+
* ```
1917+
* and the following barrier guard predicate:
1918+
* ```ql
1919+
* predicate myGuardChecks(IRGuardCondition g, Expr e, boolean branch) {
1920+
* exists(Call call |
1921+
* g.getUnconvertedResultExpression() = call and
1922+
* call.getTarget().hasName("is_safe_int") and
1923+
* e = call.getAnArgument() and
1924+
* branch = true
1925+
* )
1926+
* }
1927+
* ```
1928+
* implementing `isBarrier` as:
1929+
* ```ql
1930+
* predicate isBarrier(DataFlow::Node barrier) {
1931+
* barrier = DataFlow::BarrierGuard<myGuardChecks/3>::getABarrierNode()
1932+
* }
1933+
* ```
1934+
* will block flow from `x = source()` to `sink(x)`.
1935+
*
1936+
* NOTE: If an indirect expression is tracked, use `getAnIndirectBarrierNode` instead.
1937+
*/
19071938
ExprNode getABarrierNode() {
19081939
exists(IRGuardCondition g, Expr e, ValueNumber value, boolean edge |
19091940
e = value.getAnInstruction().getConvertedResultExpression() and
@@ -1912,6 +1943,84 @@ module BarrierGuard<guardChecksSig/3 guardChecks> {
19121943
g.controls(result.getBasicBlock(), edge)
19131944
)
19141945
}
1946+
1947+
/**
1948+
* Gets an indirect expression node that is safely guarded by the given guard check.
1949+
*
1950+
* For example, given the following code:
1951+
* ```cpp
1952+
* int* p;
1953+
* // ...
1954+
* *p = source();
1955+
* if(is_safe_pointer(p)) {
1956+
* sink(*p);
1957+
* }
1958+
* ```
1959+
* and the following barrier guard check:
1960+
* ```ql
1961+
* predicate myGuardChecks(IRGuardCondition g, Expr e, boolean branch) {
1962+
* exists(Call call |
1963+
* g.getUnconvertedResultExpression() = call and
1964+
* call.getTarget().hasName("is_safe_pointer") and
1965+
* e = call.getAnArgument() and
1966+
* branch = true
1967+
* )
1968+
* }
1969+
* ```
1970+
* implementing `isBarrier` as:
1971+
* ```ql
1972+
* predicate isBarrier(DataFlow::Node barrier) {
1973+
* barrier = DataFlow::BarrierGuard<myGuardChecks/3>::getAnIndirectBarrierNode()
1974+
* }
1975+
* ```
1976+
* will block flow from `x = source()` to `sink(x)`.
1977+
*
1978+
* NOTE: If a non-indirect expression is tracked, use `getABarrierNode` instead.
1979+
*/
1980+
IndirectExprNode getAnIndirectBarrierNode() { result = getAnIndirectBarrierNode(_) }
1981+
1982+
/**
1983+
* Gets an indirect expression node with indirection index `indirectionIndex` that is
1984+
* safely guarded by the given guard check.
1985+
*
1986+
* For example, given the following code:
1987+
* ```cpp
1988+
* int* p;
1989+
* // ...
1990+
* *p = source();
1991+
* if(is_safe_pointer(p)) {
1992+
* sink(*p);
1993+
* }
1994+
* ```
1995+
* and the following barrier guard check:
1996+
* ```ql
1997+
* predicate myGuardChecks(IRGuardCondition g, Expr e, boolean branch) {
1998+
* exists(Call call |
1999+
* g.getUnconvertedResultExpression() = call and
2000+
* call.getTarget().hasName("is_safe_pointer") and
2001+
* e = call.getAnArgument() and
2002+
* branch = true
2003+
* )
2004+
* }
2005+
* ```
2006+
* implementing `isBarrier` as:
2007+
* ```ql
2008+
* predicate isBarrier(DataFlow::Node barrier) {
2009+
* barrier = DataFlow::BarrierGuard<myGuardChecks/3>::getAnIndirectBarrierNode(1)
2010+
* }
2011+
* ```
2012+
* will block flow from `x = source()` to `sink(x)`.
2013+
*
2014+
* NOTE: If a non-indirect expression is tracked, use `getABarrierNode` instead.
2015+
*/
2016+
IndirectExprNode getAnIndirectBarrierNode(int indirectionIndex) {
2017+
exists(IRGuardCondition g, Expr e, ValueNumber value, boolean edge |
2018+
e = value.getAnInstruction().getConvertedResultExpression() and
2019+
result.getConvertedExpr(indirectionIndex) = e and
2020+
guardChecks(g, value.getAnInstruction().getConvertedResultExpression(), edge) and
2021+
g.controls(result.getBasicBlock(), edge)
2022+
)
2023+
}
19152024
}
19162025

19172026
/**

cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,13 @@ private module Cached {
3434

3535
cached
3636
predicate hasUnreachedInstructionCached(IRFunction irFunc) {
37-
exists(OldInstruction oldInstruction |
37+
exists(OldIR::Instruction oldInstruction |
3838
irFunc = oldInstruction.getEnclosingIRFunction() and
39-
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
39+
(
40+
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
41+
or
42+
oldInstruction.getOpcode() instanceof Opcode::Unreached
43+
)
4044
)
4145
}
4246

@@ -366,21 +370,19 @@ private module Cached {
366370
then
367371
result = getChi(getOldInstruction(instruction)) and
368372
kind instanceof GotoEdge
369-
else (
373+
else
370374
exists(OldInstruction oldInstruction |
371-
oldInstruction = getOldInstruction(instruction) and
375+
(
376+
oldInstruction = getOldInstruction(instruction)
377+
or
378+
instruction = getChi(oldInstruction)
379+
) and
372380
(
373381
if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind)
374382
then result = unreachedInstruction(instruction.getEnclosingIRFunction())
375383
else result = getNewInstruction(oldInstruction.getSuccessor(kind))
376384
)
377385
)
378-
or
379-
exists(OldInstruction oldInstruction |
380-
instruction = getChi(oldInstruction) and
381-
result = getNewInstruction(oldInstruction.getSuccessor(kind))
382-
)
383-
)
384386
}
385387

386388
cached

cpp/ql/lib/semmle/code/cpp/ir/implementation/internal/TInstruction.qll

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,9 @@ newtype TInstruction =
1919
) {
2020
IRConstruction::Raw::hasInstruction(tag1, tag2)
2121
} or
22+
TRawUnreachedInstruction(IRFunctionBase irFunc) {
23+
IRConstruction::hasUnreachedInstruction(irFunc)
24+
} or
2225
TUnaliasedSsaPhiInstruction(
2326
TRawInstruction blockStartInstr, UnaliasedSsa::Ssa::MemoryLocation memoryLocation
2427
) {

cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/IRConstruction.qll

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,9 +178,9 @@ module Raw {
178178
}
179179
}
180180

181-
class TStageInstruction = TRawInstruction;
181+
class TStageInstruction = TRawInstruction or TRawUnreachedInstruction;
182182

183-
predicate hasInstruction(TRawInstruction instr) { any() }
183+
predicate hasInstruction(TStageInstruction instr) { any() }
184184

185185
predicate hasModeledMemoryResult(Instruction instruction) { none() }
186186

@@ -368,6 +368,11 @@ private predicate isStrictlyForwardGoto(GotoStmt goto) {
368368

369369
Locatable getInstructionAst(TStageInstruction instr) {
370370
result = getInstructionTranslatedElement(instr).getAst()
371+
or
372+
exists(IRFunction irFunc |
373+
instr = TRawUnreachedInstruction(irFunc) and
374+
result = irFunc.getFunction()
375+
)
371376
}
372377

373378
/** DEPRECATED: Alias for getInstructionAst */
@@ -377,14 +382,22 @@ deprecated Locatable getInstructionAST(TStageInstruction instr) {
377382

378383
CppType getInstructionResultType(TStageInstruction instr) {
379384
getInstructionTranslatedElement(instr).hasInstruction(_, getInstructionTag(instr), result)
385+
or
386+
instr instanceof TRawUnreachedInstruction and
387+
result = getVoidType()
380388
}
381389

382390
predicate getInstructionOpcode(Opcode opcode, TStageInstruction instr) {
383391
getInstructionTranslatedElement(instr).hasInstruction(opcode, getInstructionTag(instr), _)
392+
or
393+
instr instanceof TRawUnreachedInstruction and
394+
opcode instanceof Opcode::Unreached
384395
}
385396

386397
IRFunctionBase getInstructionEnclosingIRFunction(TStageInstruction instr) {
387398
result.getFunction() = getInstructionTranslatedElement(instr).getFunction()
399+
or
400+
instr = TRawUnreachedInstruction(result)
388401
}
389402

390403
Instruction getPrimaryInstructionForSideEffect(SideEffectInstruction instruction) {
@@ -393,6 +406,16 @@ Instruction getPrimaryInstructionForSideEffect(SideEffectInstruction instruction
393406
.getPrimaryInstructionForSideEffect(getInstructionTag(instruction))
394407
}
395408

409+
predicate hasUnreachedInstruction(IRFunction func) {
410+
exists(Call c |
411+
c.getEnclosingFunction() = func.getFunction() and
412+
any(Options opt).exits(c.getTarget())
413+
) and
414+
not exists(TranslatedUnreachableReturnStmt return |
415+
return.getEnclosingFunction().getFunction() = func.getFunction()
416+
)
417+
}
418+
396419
import CachedForDebugging
397420

398421
cached

cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/InstructionTag.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ newtype TInstructionTag =
3434
CallTargetTag() or
3535
CallTag() or
3636
CallSideEffectTag() or
37+
CallNoReturnTag() or
3738
AllocationSizeTag() or
3839
AllocationElementSizeTag() or
3940
AllocationExtentConvertTag() or

cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/TranslatedCall.qll

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ private import SideEffects
88
private import TranslatedElement
99
private import TranslatedExpr
1010
private import TranslatedFunction
11+
private import DefaultOptions as DefaultOptions
1112

1213
/**
1314
* Gets the `CallInstruction` from the `TranslatedCallExpr` for the specified expression.
@@ -66,7 +67,13 @@ abstract class TranslatedCall extends TranslatedExpr {
6667
)
6768
or
6869
child = getSideEffects() and
69-
result = getParent().getChildSuccessor(this)
70+
if this.isNoReturn()
71+
then
72+
result =
73+
any(UnreachedInstruction instr |
74+
this.getEnclosingFunction().getFunction() = instr.getEnclosingFunction()
75+
)
76+
else result = this.getParent().getChildSuccessor(this)
7077
}
7178

7279
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
@@ -161,6 +168,8 @@ abstract class TranslatedCall extends TranslatedExpr {
161168
*/
162169
abstract predicate hasArguments();
163170

171+
predicate isNoReturn() { none() }
172+
164173
final TranslatedSideEffects getSideEffects() { result.getExpr() = expr }
165174
}
166175

@@ -266,6 +275,8 @@ abstract class TranslatedCallExpr extends TranslatedNonConstantExpr, TranslatedC
266275
}
267276

268277
final override int getNumberOfArguments() { result = expr.getNumberOfArguments() }
278+
279+
final override predicate isNoReturn() { any(Options opt).exits(expr.getTarget()) }
269280
}
270281

271282
/**

cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/internal/reachability/ReachableBlock.qll

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ predicate isInfeasibleInstructionSuccessor(Instruction instr, EdgeKind kind) {
77
conditionValue = getConstantValue(instr.(ConditionalBranchInstruction).getCondition()) and
88
if conditionValue = 0 then kind instanceof TrueEdge else kind instanceof FalseEdge
99
)
10+
or
11+
instr.getSuccessor(kind) instanceof UnreachedInstruction and
12+
kind instanceof GotoEdge
1013
}
1114

1215
pragma[noinline]
@@ -41,7 +44,9 @@ class ReachableBlock extends IRBlockBase {
4144
* An instruction that is contained in a reachable block.
4245
*/
4346
class ReachableInstruction extends Instruction {
44-
ReachableInstruction() { this.getBlock() instanceof ReachableBlock }
47+
ReachableInstruction() {
48+
this.getBlock() instanceof ReachableBlock and not this instanceof UnreachedInstruction
49+
}
4550
}
4651

4752
module Graph {

cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,13 @@ private module Cached {
3434

3535
cached
3636
predicate hasUnreachedInstructionCached(IRFunction irFunc) {
37-
exists(OldInstruction oldInstruction |
37+
exists(OldIR::Instruction oldInstruction |
3838
irFunc = oldInstruction.getEnclosingIRFunction() and
39-
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
39+
(
40+
Reachability::isInfeasibleInstructionSuccessor(oldInstruction, _)
41+
or
42+
oldInstruction.getOpcode() instanceof Opcode::Unreached
43+
)
4044
)
4145
}
4246

@@ -366,21 +370,19 @@ private module Cached {
366370
then
367371
result = getChi(getOldInstruction(instruction)) and
368372
kind instanceof GotoEdge
369-
else (
373+
else
370374
exists(OldInstruction oldInstruction |
371-
oldInstruction = getOldInstruction(instruction) and
375+
(
376+
oldInstruction = getOldInstruction(instruction)
377+
or
378+
instruction = getChi(oldInstruction)
379+
) and
372380
(
373381
if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind)
374382
then result = unreachedInstruction(instruction.getEnclosingIRFunction())
375383
else result = getNewInstruction(oldInstruction.getSuccessor(kind))
376384
)
377385
)
378-
or
379-
exists(OldInstruction oldInstruction |
380-
instruction = getChi(oldInstruction) and
381-
result = getNewInstruction(oldInstruction.getSuccessor(kind))
382-
)
383-
)
384386
}
385387

386388
cached

0 commit comments

Comments
 (0)