Skip to content

Commit f4a5e1e

Browse files
authored
Merge branch 'main' into java/mocking-all-non-private-methods-means-unit-test-is-too-big
2 parents cdb0d25 + 9905cd6 commit f4a5e1e

File tree

70 files changed

+4248
-386
lines changed

Some content is hidden

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

70 files changed

+4248
-386
lines changed
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* The global value numbering library (`semmle.code.cpp.valuenumbering.GlobalValueNumbering` and `semmle.code.cpp.ir.ValueNumbering`) has been improved so more expressions are assigned the same value number.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* Improved dataflow through global variables in the new dataflow library (`semmle.code.cpp.dataflow.new.DataFlow` and `semmle.code.cpp.dataflow.new.TaintTracking`). Queries based on these libraries will produce more results on codebases with many global variables.

cpp/ql/lib/semmle/code/cpp/commons/Buffer.qll

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,19 +57,27 @@ private Class getRootType(FieldAccess fa) {
5757
)
5858
}
5959

60+
/**
61+
* Gets the size of `v`. This predicate does not have a result when the
62+
* unspecified type of `v` is a `ReferenceType`.
63+
*/
64+
private int getVariableSize(Variable v) {
65+
exists(Type t |
66+
t = v.getUnspecifiedType() and
67+
not t instanceof ReferenceType and
68+
result = t.getSize()
69+
)
70+
}
71+
6072
/**
6173
* Gets the size of the buffer access at `va`.
6274
*/
6375
private int getSize(VariableAccess va) {
6476
exists(Variable v | va.getTarget() = v |
6577
// If `v` is not a field then the size of the buffer is just
6678
// the size of the type of `v`.
67-
exists(Type t |
68-
t = v.getUnspecifiedType() and
69-
not v instanceof Field and
70-
not t instanceof ReferenceType and
71-
result = t.getSize()
72-
)
79+
not v instanceof Field and
80+
result = getVariableSize(v)
7381
or
7482
exists(Class c, int trueSize |
7583
// Otherwise, we find the "outermost" object and compute the size
@@ -92,7 +100,7 @@ private int getSize(VariableAccess va) {
92100
// buffer is `12 - 4 = 8`.
93101
c = getRootType(va) and
94102
// we calculate the size based on the last field, to avoid including any padding after it
95-
trueSize = max(Field f | | f.getOffsetInClass(c) + f.getUnspecifiedType().getSize()) and
103+
trueSize = max(Field f | | f.getOffsetInClass(c) + getVariableSize(f)) and
96104
result = trueSize - v.(Field).getOffsetInClass(c)
97105
)
98106
)

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,13 @@ private module IndirectInstructions {
332332

333333
import IndirectInstructions
334334

335+
predicate isPostUpdateNodeImpl(Operand operand, int indirectionIndex) {
336+
operand = any(FieldAddress fa).getObjectAddressOperand() and
337+
indirectionIndex = [0 .. Ssa::countIndirectionsForCppType(Ssa::getLanguageType(operand))]
338+
or
339+
Ssa::isModifiableByCall(operand, indirectionIndex)
340+
}
341+
335342
/** Gets the callable in which this node occurs. */
336343
DataFlowCallable nodeGetEnclosingCallable(Node n) { result = n.getEnclosingCallable() }
337344

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

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,7 @@ private newtype TIRDataFlowNode =
4242
[getMinIndirectionsForType(var.getUnspecifiedType()) .. SsaImpl::getMaxIndirectionsForType(var.getUnspecifiedType())]
4343
} or
4444
TPostUpdateNodeImpl(Operand operand, int indirectionIndex) {
45-
operand = any(FieldAddress fa).getObjectAddressOperand() and
46-
indirectionIndex =
47-
[0 .. SsaImpl::countIndirectionsForCppType(SsaImpl::getLanguageType(operand))]
48-
or
49-
SsaImpl::isModifiableByCall(operand, indirectionIndex)
45+
isPostUpdateNodeImpl(operand, indirectionIndex)
5046
} or
5147
TSsaSynthNode(SsaImpl::SynthNode n) or
5248
TSsaIteratorNode(IteratorFlow::IteratorFlowNode n) or

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,14 @@ private predicate isGlobalUse(
143143
min(int cand, VariableAddressInstruction vai |
144144
vai.getEnclosingIRFunction() = f and
145145
vai.getAstVariable() = v and
146-
isDef(_, _, _, vai, cand, indirectionIndex)
146+
(
147+
isDef(_, _, _, vai, cand, indirectionIndex)
148+
or
149+
exists(Operand operand |
150+
isUse(_, operand, vai, cand, indirectionIndex) and
151+
isPostUpdateNodeImpl(operand, indirectionIndex)
152+
)
153+
)
147154
|
148155
cand
149156
)

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,23 @@ newtype TValueNumber =
4343
} or
4444
TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) }
4545

46+
/**
47+
* A `ConvertInstruction` which converts data of type `T` to data of type `U`
48+
* where `T` and `U` only differ in specifiers. For example, if `T` is `int`
49+
* and `U` is `const T` this is a conversion from a non-const integer to a
50+
* const integer.
51+
*
52+
* Generally, the value number of a converted value is different from the value
53+
* number of an unconverted value, but conversions which only modify specifiers
54+
* leave the resulting value bitwise identical to the old value.
55+
*/
56+
class TypePreservingConvertInstruction extends ConvertInstruction {
57+
TypePreservingConvertInstruction() {
58+
pragma[only_bind_out](this.getResultType().getUnspecifiedType()) =
59+
pragma[only_bind_out](this.getUnary().getResultType().getUnspecifiedType())
60+
}
61+
}
62+
4663
/**
4764
* A `CopyInstruction` whose source operand's value is congruent to the definition of that source
4865
* operand.
@@ -216,6 +233,7 @@ private predicate unaryValueNumber(
216233
not instr instanceof InheritanceConversionInstruction and
217234
not instr instanceof CopyInstruction and
218235
not instr instanceof FieldAddressInstruction and
236+
not instr instanceof TypePreservingConvertInstruction and
219237
instr.getOpcode() = opcode and
220238
tvalueNumber(instr.getUnary()) = operand
221239
}
@@ -351,6 +369,10 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
351369
or
352370
// The value number of a copy is just the value number of its source value.
353371
result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue())
372+
or
373+
// The value number of a type-preserving conversion is just the value
374+
// number of the unconverted value.
375+
result = tvalueNumber(instr.(TypePreservingConvertInstruction).getUnary())
354376
)
355377
)
356378
}

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,23 @@ newtype TValueNumber =
4343
} or
4444
TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) }
4545

46+
/**
47+
* A `ConvertInstruction` which converts data of type `T` to data of type `U`
48+
* where `T` and `U` only differ in specifiers. For example, if `T` is `int`
49+
* and `U` is `const T` this is a conversion from a non-const integer to a
50+
* const integer.
51+
*
52+
* Generally, the value number of a converted value is different from the value
53+
* number of an unconverted value, but conversions which only modify specifiers
54+
* leave the resulting value bitwise identical to the old value.
55+
*/
56+
class TypePreservingConvertInstruction extends ConvertInstruction {
57+
TypePreservingConvertInstruction() {
58+
pragma[only_bind_out](this.getResultType().getUnspecifiedType()) =
59+
pragma[only_bind_out](this.getUnary().getResultType().getUnspecifiedType())
60+
}
61+
}
62+
4663
/**
4764
* A `CopyInstruction` whose source operand's value is congruent to the definition of that source
4865
* operand.
@@ -216,6 +233,7 @@ private predicate unaryValueNumber(
216233
not instr instanceof InheritanceConversionInstruction and
217234
not instr instanceof CopyInstruction and
218235
not instr instanceof FieldAddressInstruction and
236+
not instr instanceof TypePreservingConvertInstruction and
219237
instr.getOpcode() = opcode and
220238
tvalueNumber(instr.getUnary()) = operand
221239
}
@@ -351,6 +369,10 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
351369
or
352370
// The value number of a copy is just the value number of its source value.
353371
result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue())
372+
or
373+
// The value number of a type-preserving conversion is just the value
374+
// number of the unconverted value.
375+
result = tvalueNumber(instr.(TypePreservingConvertInstruction).getUnary())
354376
)
355377
)
356378
}

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

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,8 @@ newtype TInstructionTag =
9696
exists(Expr e | exists(e.getImplicitDestructorCall(index))) or
9797
exists(Stmt s | exists(s.getImplicitDestructorCall(index)))
9898
} or
99-
CoAwaitBranchTag()
99+
CoAwaitBranchTag() or
100+
BoolToIntConversionTag()
100101

101102
class InstructionTag extends TInstructionTag {
102103
final string toString() { result = getInstructionTagId(this) }
@@ -286,4 +287,6 @@ string getInstructionTagId(TInstructionTag tag) {
286287
)
287288
or
288289
tag = CoAwaitBranchTag() and result = "CoAwaitBranch"
290+
or
291+
tag = BoolToIntConversionTag() and result = "BoolToIntConversion"
289292
}

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

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,41 @@ predicate hasTranslatedSyntheticTemporaryObject(Expr expr) {
509509
not expr.hasLValueToRValueConversion()
510510
}
511511

512+
Opcode comparisonOpcode(ComparisonOperation expr) {
513+
expr instanceof EQExpr and result instanceof Opcode::CompareEQ
514+
or
515+
expr instanceof NEExpr and result instanceof Opcode::CompareNE
516+
or
517+
expr instanceof LTExpr and result instanceof Opcode::CompareLT
518+
or
519+
expr instanceof GTExpr and result instanceof Opcode::CompareGT
520+
or
521+
expr instanceof LEExpr and result instanceof Opcode::CompareLE
522+
or
523+
expr instanceof GEExpr and result instanceof Opcode::CompareGE
524+
}
525+
526+
private predicate parentExpectsBool(Expr child) {
527+
any(NotExpr notExpr).getOperand() = child
528+
or
529+
usedAsCondition(child)
530+
}
531+
532+
/**
533+
* Holds if `expr` should have a `TranslatedSyntheticBoolToIntConversion` on it.
534+
*/
535+
predicate hasTranslatedSyntheticBoolToIntConversion(Expr expr) {
536+
not ignoreExpr(expr) and
537+
not isIRConstant(expr) and
538+
not parentExpectsBool(expr) and
539+
expr.getUnspecifiedType() instanceof IntType and
540+
(
541+
expr instanceof NotExpr
542+
or
543+
exists(comparisonOpcode(expr))
544+
)
545+
}
546+
512547
class StaticInitializedStaticLocalVariable extends StaticLocalVariable {
513548
StaticInitializedStaticLocalVariable() {
514549
this.hasInitializer() and
@@ -647,6 +682,9 @@ newtype TTranslatedElement =
647682
// A temporary object that we had to synthesize ourselves, so that we could do a field access or
648683
// method call on a prvalue.
649684
TTranslatedSyntheticTemporaryObject(Expr expr) { hasTranslatedSyntheticTemporaryObject(expr) } or
685+
TTranslatedSyntheticBoolToIntConversion(Expr expr) {
686+
hasTranslatedSyntheticBoolToIntConversion(expr)
687+
} or
650688
// For expressions that would not otherwise generate an instruction.
651689
TTranslatedResultCopy(Expr expr) {
652690
not ignoreExpr(expr) and

0 commit comments

Comments
 (0)