mirror of
https://github.com/github/codeql.git
synced 2025-12-16 16:53:25 +01:00
Merge pull request #20156 from MathiasVP/value-numbering-for-noop-casts
C++: Value numbering for casts that only modify specifiers
This commit is contained in:
4
cpp/ql/lib/change-notes/2025-08-02-gvn.md
Normal file
4
cpp/ql/lib/change-notes/2025-08-02-gvn.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* 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.
|
||||
@@ -43,6 +43,23 @@ newtype TValueNumber =
|
||||
} or
|
||||
TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) }
|
||||
|
||||
/**
|
||||
* A `ConvertInstruction` which converts data of type `T` to data of type `U`
|
||||
* where `T` and `U` only differ in specifiers. For example, if `T` is `int`
|
||||
* and `U` is `const T` this is a conversion from a non-const integer to a
|
||||
* const integer.
|
||||
*
|
||||
* Generally, the value number of a converted value is different from the value
|
||||
* number of an unconverted value, but conversions which only modify specifiers
|
||||
* leave the resulting value bitwise identical to the old value.
|
||||
*/
|
||||
class TypePreservingConvertInstruction extends ConvertInstruction {
|
||||
TypePreservingConvertInstruction() {
|
||||
pragma[only_bind_out](this.getResultType().getUnspecifiedType()) =
|
||||
pragma[only_bind_out](this.getUnary().getResultType().getUnspecifiedType())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A `CopyInstruction` whose source operand's value is congruent to the definition of that source
|
||||
* operand.
|
||||
@@ -216,6 +233,7 @@ private predicate unaryValueNumber(
|
||||
not instr instanceof InheritanceConversionInstruction and
|
||||
not instr instanceof CopyInstruction and
|
||||
not instr instanceof FieldAddressInstruction and
|
||||
not instr instanceof TypePreservingConvertInstruction and
|
||||
instr.getOpcode() = opcode and
|
||||
tvalueNumber(instr.getUnary()) = operand
|
||||
}
|
||||
@@ -351,6 +369,10 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
or
|
||||
// The value number of a copy is just the value number of its source value.
|
||||
result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue())
|
||||
or
|
||||
// The value number of a type-preserving conversion is just the value
|
||||
// number of the unconverted value.
|
||||
result = tvalueNumber(instr.(TypePreservingConvertInstruction).getUnary())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -43,6 +43,23 @@ newtype TValueNumber =
|
||||
} or
|
||||
TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) }
|
||||
|
||||
/**
|
||||
* A `ConvertInstruction` which converts data of type `T` to data of type `U`
|
||||
* where `T` and `U` only differ in specifiers. For example, if `T` is `int`
|
||||
* and `U` is `const T` this is a conversion from a non-const integer to a
|
||||
* const integer.
|
||||
*
|
||||
* Generally, the value number of a converted value is different from the value
|
||||
* number of an unconverted value, but conversions which only modify specifiers
|
||||
* leave the resulting value bitwise identical to the old value.
|
||||
*/
|
||||
class TypePreservingConvertInstruction extends ConvertInstruction {
|
||||
TypePreservingConvertInstruction() {
|
||||
pragma[only_bind_out](this.getResultType().getUnspecifiedType()) =
|
||||
pragma[only_bind_out](this.getUnary().getResultType().getUnspecifiedType())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A `CopyInstruction` whose source operand's value is congruent to the definition of that source
|
||||
* operand.
|
||||
@@ -216,6 +233,7 @@ private predicate unaryValueNumber(
|
||||
not instr instanceof InheritanceConversionInstruction and
|
||||
not instr instanceof CopyInstruction and
|
||||
not instr instanceof FieldAddressInstruction and
|
||||
not instr instanceof TypePreservingConvertInstruction and
|
||||
instr.getOpcode() = opcode and
|
||||
tvalueNumber(instr.getUnary()) = operand
|
||||
}
|
||||
@@ -351,6 +369,10 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
or
|
||||
// The value number of a copy is just the value number of its source value.
|
||||
result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue())
|
||||
or
|
||||
// The value number of a type-preserving conversion is just the value
|
||||
// number of the unconverted value.
|
||||
result = tvalueNumber(instr.(TypePreservingConvertInstruction).getUnary())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -43,6 +43,23 @@ newtype TValueNumber =
|
||||
} or
|
||||
TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) }
|
||||
|
||||
/**
|
||||
* A `ConvertInstruction` which converts data of type `T` to data of type `U`
|
||||
* where `T` and `U` only differ in specifiers. For example, if `T` is `int`
|
||||
* and `U` is `const T` this is a conversion from a non-const integer to a
|
||||
* const integer.
|
||||
*
|
||||
* Generally, the value number of a converted value is different from the value
|
||||
* number of an unconverted value, but conversions which only modify specifiers
|
||||
* leave the resulting value bitwise identical to the old value.
|
||||
*/
|
||||
class TypePreservingConvertInstruction extends ConvertInstruction {
|
||||
TypePreservingConvertInstruction() {
|
||||
pragma[only_bind_out](this.getResultType().getUnspecifiedType()) =
|
||||
pragma[only_bind_out](this.getUnary().getResultType().getUnspecifiedType())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A `CopyInstruction` whose source operand's value is congruent to the definition of that source
|
||||
* operand.
|
||||
@@ -216,6 +233,7 @@ private predicate unaryValueNumber(
|
||||
not instr instanceof InheritanceConversionInstruction and
|
||||
not instr instanceof CopyInstruction and
|
||||
not instr instanceof FieldAddressInstruction and
|
||||
not instr instanceof TypePreservingConvertInstruction and
|
||||
instr.getOpcode() = opcode and
|
||||
tvalueNumber(instr.getUnary()) = operand
|
||||
}
|
||||
@@ -351,6 +369,10 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
|
||||
or
|
||||
// The value number of a copy is just the value number of its source value.
|
||||
result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue())
|
||||
or
|
||||
// The value number of a type-preserving conversion is just the value
|
||||
// number of the unconverted value.
|
||||
result = tvalueNumber(instr.(TypePreservingConvertInstruction).getUnary())
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1145,3 +1145,43 @@ test.cpp:
|
||||
# 152| v152_7(void) = ReturnVoid :
|
||||
# 152| v152_8(void) = AliasedUse : ~m156_7
|
||||
# 152| v152_9(void) = ExitFunction :
|
||||
|
||||
# 166| void test_constMemberFunction()
|
||||
# 166| Block 0
|
||||
# 166| v166_1(void) = EnterFunction :
|
||||
# 166| m166_2(unknown) = AliasedDefinition :
|
||||
# 166| valnum = unique
|
||||
# 166| m166_3(unknown) = InitializeNonLocal :
|
||||
# 166| valnum = unique
|
||||
# 166| m166_4(unknown) = Chi : total:m166_2, partial:m166_3
|
||||
# 166| valnum = unique
|
||||
# 167| r167_1(glval<StructWithConstMemberFunction>) = VariableAddress[s] :
|
||||
# 167| valnum = r167_1, r168_2, r169_1, r169_2
|
||||
# 167| m167_2(StructWithConstMemberFunction) = Uninitialized[s] : &:r167_1
|
||||
# 167| valnum = m167_2, m168_4, r168_3
|
||||
# 167| m167_3(unknown) = Chi : total:m166_4, partial:m167_2
|
||||
# 167| valnum = unique
|
||||
# 168| r168_1(glval<StructWithConstMemberFunction>) = VariableAddress[s2] :
|
||||
# 168| valnum = unique
|
||||
# 168| r168_2(glval<StructWithConstMemberFunction>) = VariableAddress[s] :
|
||||
# 168| valnum = r167_1, r168_2, r169_1, r169_2
|
||||
# 168| r168_3(StructWithConstMemberFunction) = Load[s] : &:r168_2, m167_2
|
||||
# 168| valnum = m167_2, m168_4, r168_3
|
||||
# 168| m168_4(StructWithConstMemberFunction) = Store[s2] : &:r168_1, r168_3
|
||||
# 168| valnum = m167_2, m168_4, r168_3
|
||||
# 169| r169_1(glval<StructWithConstMemberFunction>) = VariableAddress[s] :
|
||||
# 169| valnum = r167_1, r168_2, r169_1, r169_2
|
||||
# 169| r169_2(glval<StructWithConstMemberFunction>) = Convert : r169_1
|
||||
# 169| valnum = r167_1, r168_2, r169_1, r169_2
|
||||
# 169| r169_3(glval<unknown>) = FunctionAddress[constMemberFunction] :
|
||||
# 169| valnum = unique
|
||||
# 169| v169_4(void) = Call[constMemberFunction] : func:r169_3, this:r169_2
|
||||
# 169| m169_5(unknown) = ^CallSideEffect : ~m167_3
|
||||
# 169| valnum = unique
|
||||
# 169| m169_6(unknown) = Chi : total:m167_3, partial:m169_5
|
||||
# 169| valnum = unique
|
||||
# 169| v169_7(void) = ^IndirectReadSideEffect[-1] : &:r169_2, ~m169_6
|
||||
# 170| v170_1(void) = NoOp :
|
||||
# 166| v166_5(void) = ReturnVoid :
|
||||
# 166| v166_6(void) = AliasedUse : ~m169_6
|
||||
# 166| v166_7(void) = ExitFunction :
|
||||
|
||||
@@ -157,3 +157,14 @@ void test_read_global_different(int n) {
|
||||
|
||||
int d = global_a->x;
|
||||
}
|
||||
|
||||
struct StructWithConstMemberFunction {
|
||||
int x;
|
||||
void constMemberFunction() const;
|
||||
};
|
||||
|
||||
void test_constMemberFunction() {
|
||||
StructWithConstMemberFunction s;
|
||||
StructWithConstMemberFunction s2 = s;
|
||||
s.constMemberFunction();
|
||||
}
|
||||
@@ -13,7 +13,6 @@
|
||||
| test.cpp:49:2:49:9 | call to strcpy_s | Potentially unsafe call to strcpy_s; second argument should be size of destination. |
|
||||
| test.cpp:62:3:62:9 | call to strncpy | Potentially unsafe call to strncpy; third argument should be size of destination. |
|
||||
| test.cpp:65:3:65:9 | call to strncpy | Potentially unsafe call to strncpy; third argument should be size of destination. |
|
||||
| test.cpp:70:2:70:8 | call to strncpy | Potentially unsafe call to strncpy; third argument should be size of destination. |
|
||||
| test.cpp:81:3:81:9 | call to strncpy | Potentially unsafe call to strncpy; third argument should be size of destination. |
|
||||
| test.cpp:84:3:84:9 | call to strncpy | Potentially unsafe call to strncpy; third argument should be size of destination. |
|
||||
| test.cpp:105:2:105:10 | call to wcsxfrm_l | Potentially unsafe call to wcsxfrm_l; third argument should be size of destination. |
|
||||
|
||||
Reference in New Issue
Block a user