C++: Define an extractor version table and use in IR generation

This commit is contained in:
Jeroen Ketema
2023-10-24 17:34:16 +02:00
parent 29d57d82b7
commit 903f376620
11 changed files with 9781 additions and 741 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,3 @@
description: Introduce extractor version numbers
compatibility: breaking
extractor_version.rel: delete

View File

@@ -0,0 +1,10 @@
/**
* INTERNAL: Do not use. Provides predicates for getting the CodeQL and frontend
* version used during database extraction.
*/
/** Get the extractor CodeQL version */
string getExtractorCodeQLVersion() { extractor_version(result, _) }
/** Get the extractor frontend version */
string getExtractorFrontendVersion() { extractor_version(_, result) }

View File

@@ -1,5 +1,6 @@
private import cpp private import cpp
import semmle.code.cpp.ir.implementation.raw.IR import semmle.code.cpp.ir.implementation.raw.IR
private import semmle.code.cpp.internal.ExtractorVersion
private import semmle.code.cpp.ir.IRConfiguration private import semmle.code.cpp.ir.IRConfiguration
private import semmle.code.cpp.ir.implementation.Opcode private import semmle.code.cpp.ir.implementation.Opcode
private import semmle.code.cpp.ir.implementation.internal.OperandTag private import semmle.code.cpp.ir.implementation.internal.OperandTag
@@ -362,10 +363,10 @@ predicate ignoreLoad(Expr expr) {
expr instanceof FunctionAccess expr instanceof FunctionAccess
or or
// The load is duplicated from the operand. // The load is duplicated from the operand.
expr instanceof ParenthesisExpr exists(getExtractorFrontendVersion()) and expr instanceof ParenthesisExpr
or or
// The load is duplicated from the right operand. // The load is duplicated from the right operand.
expr instanceof CommaExpr exists(getExtractorFrontendVersion()) and expr instanceof CommaExpr
or or
expr.(PointerDereferenceExpr).getOperand().getFullyConverted().getType().getUnspecifiedType() expr.(PointerDereferenceExpr).getOperand().getFullyConverted().getType().getUnspecifiedType()
instanceof FunctionPointerType instanceof FunctionPointerType

View File

@@ -1,4 +1,5 @@
private import cpp private import cpp
private import semmle.code.cpp.internal.ExtractorVersion
private import semmle.code.cpp.ir.implementation.IRType private import semmle.code.cpp.ir.implementation.IRType
private import semmle.code.cpp.ir.implementation.Opcode private import semmle.code.cpp.ir.implementation.Opcode
private import semmle.code.cpp.ir.implementation.internal.OperandTag private import semmle.code.cpp.ir.implementation.internal.OperandTag
@@ -648,7 +649,21 @@ abstract class TranslatedCrementOperation extends TranslatedNonConstantExpr {
class TranslatedPrefixCrementOperation extends TranslatedCrementOperation { class TranslatedPrefixCrementOperation extends TranslatedCrementOperation {
override PrefixCrementOperation expr; override PrefixCrementOperation expr;
override Instruction getResult() { result = this.getUnloadedOperand().getResult() } override Instruction getResult() {
// The following distinction is needed to work around extractor limitations
// in old versions of the extractor.
if expr.isPRValueCategory() and not exists(getExtractorFrontendVersion())
then
// If this is C, then the result of a prefix crement is a prvalue for the
// new value assigned to the operand. If this is C++, then the result is
// an lvalue, but that lvalue is being loaded as part of this expression.
// EDG doesn't mark this as a load.
result = this.getInstruction(CrementOpTag())
else
// This is C++, where the result is an lvalue for the operand, and that
// lvalue is not being loaded as part of this expression.
result = this.getUnloadedOperand().getResult()
}
} }
class TranslatedPostfixCrementOperation extends TranslatedCrementOperation { class TranslatedPostfixCrementOperation extends TranslatedCrementOperation {
@@ -1491,7 +1506,21 @@ class TranslatedAssignExpr extends TranslatedNonConstantExpr {
result = this.getRightOperand().getFirstInstruction() result = this.getRightOperand().getFirstInstruction()
} }
final override Instruction getResult() { result = this.getLeftOperand().getResult() } final override Instruction getResult() {
// The following distinction is needed to work around extractor limitations
// in old versions of the extractor.
if expr.isPRValueCategory() and not exists(getExtractorFrontendVersion())
then
// If this is C, then the result of an assignment is a prvalue for the new
// value assigned to the left operand. If this is C++, then the result is
// an lvalue, but that lvalue is being loaded as part of this expression.
// EDG doesn't mark this as a load.
result = this.getRightOperand().getResult()
else
// This is C++, where the result is an lvalue for the left operand,
// and that lvalue is not being loaded as part of this expression.
result = this.getLeftOperand().getResult()
}
final TranslatedExpr getLeftOperand() { final TranslatedExpr getLeftOperand() {
result = getTranslatedExpr(expr.getLValue().getFullyConverted()) result = getTranslatedExpr(expr.getLValue().getFullyConverted())
@@ -1617,7 +1646,21 @@ class TranslatedAssignOperation extends TranslatedNonConstantExpr {
result = this.getRightOperand().getFirstInstruction() result = this.getRightOperand().getFirstInstruction()
} }
final override Instruction getResult() { result = this.getUnloadedLeftOperand().getResult() } final override Instruction getResult() {
// The following distinction is needed to work around extractor limitations
// in old versions of the extractor.
if expr.isPRValueCategory() and not exists(getExtractorFrontendVersion())
then
// If this is C, then the result of an assignment is a prvalue for the new
// value assigned to the left operand. If this is C++, then the result is
// an lvalue, but that lvalue is being loaded as part of this expression.
// EDG doesn't mark this as a load.
result = this.getStoredValue()
else
// This is C++, where the result is an lvalue for the left operand,
// and that lvalue is not being loaded as part of this expression.
result = this.getUnloadedLeftOperand().getResult()
}
final TranslatedExpr getUnloadedLeftOperand() { final TranslatedExpr getUnloadedLeftOperand() {
result = this.getLoadedLeftOperand().getOperand() result = this.getLoadedLeftOperand().getOperand()
@@ -2155,15 +2198,16 @@ abstract class TranslatedConditionalExpr extends TranslatedNonConstantExpr {
not this.elseIsVoid() and tag = ConditionValueFalseStoreTag() not this.elseIsVoid() and tag = ConditionValueFalseStoreTag()
) and ) and
opcode instanceof Opcode::Store and opcode instanceof Opcode::Store and
( if exists(getExtractorFrontendVersion())
then
not expr.hasLValueToRValueConversion() and not expr.hasLValueToRValueConversion() and
resultType = this.getResultType() resultType = this.getResultType()
or or
expr.hasLValueToRValueConversion() and expr.hasLValueToRValueConversion() and
resultType = getTypeForPRValue(expr.getType()) resultType = getTypeForPRValue(expr.getType())
) else resultType = this.getResultType()
or or
not expr.hasLValueToRValueConversion() and (not expr.hasLValueToRValueConversion() or not exists(getExtractorFrontendVersion())) and
tag = ConditionValueResultLoadTag() and tag = ConditionValueResultLoadTag() and
opcode instanceof Opcode::Load and opcode instanceof Opcode::Load and
resultType = this.getResultType() resultType = this.getResultType()
@@ -2193,15 +2237,16 @@ abstract class TranslatedConditionalExpr extends TranslatedNonConstantExpr {
) )
or or
tag = ConditionValueResultTempAddressTag() and tag = ConditionValueResultTempAddressTag() and
( if exists(getExtractorFrontendVersion())
then
not expr.hasLValueToRValueConversion() and not expr.hasLValueToRValueConversion() and
result = this.getInstruction(ConditionValueResultLoadTag()) result = this.getInstruction(ConditionValueResultLoadTag())
or or
expr.hasLValueToRValueConversion() and expr.hasLValueToRValueConversion() and
result = this.getParent().getChildSuccessor(this) result = this.getParent().getChildSuccessor(this)
) else result = this.getInstruction(ConditionValueResultLoadTag())
or or
not expr.hasLValueToRValueConversion() and (not expr.hasLValueToRValueConversion() or not exists(getExtractorFrontendVersion())) and
tag = ConditionValueResultLoadTag() and tag = ConditionValueResultLoadTag() and
result = this.getParent().getChildSuccessor(this) result = this.getParent().getChildSuccessor(this)
) )
@@ -2230,7 +2275,7 @@ abstract class TranslatedConditionalExpr extends TranslatedNonConstantExpr {
result = this.getElse().getResult() result = this.getElse().getResult()
) )
or or
not expr.hasLValueToRValueConversion() and (not expr.hasLValueToRValueConversion() or not exists(getExtractorFrontendVersion())) and
tag = ConditionValueResultLoadTag() and tag = ConditionValueResultLoadTag() and
operandTag instanceof AddressOperandTag and operandTag instanceof AddressOperandTag and
result = this.getInstruction(ConditionValueResultTempAddressTag()) result = this.getInstruction(ConditionValueResultTempAddressTag())
@@ -2240,13 +2285,14 @@ abstract class TranslatedConditionalExpr extends TranslatedNonConstantExpr {
final override predicate hasTempVariable(TempVariableTag tag, CppType type) { final override predicate hasTempVariable(TempVariableTag tag, CppType type) {
not this.resultIsVoid() and not this.resultIsVoid() and
tag = ConditionValueTempVar() and tag = ConditionValueTempVar() and
( if exists(getExtractorFrontendVersion())
then
not expr.hasLValueToRValueConversion() and not expr.hasLValueToRValueConversion() and
type = this.getResultType() type = this.getResultType()
or or
expr.hasLValueToRValueConversion() and expr.hasLValueToRValueConversion() and
type = getTypeForPRValue(expr.getType()) type = getTypeForPRValue(expr.getType())
) else type = this.getResultType()
} }
final override IRVariable getInstructionVariable(InstructionTag tag) { final override IRVariable getInstructionVariable(InstructionTag tag) {
@@ -2261,13 +2307,14 @@ abstract class TranslatedConditionalExpr extends TranslatedNonConstantExpr {
final override Instruction getResult() { final override Instruction getResult() {
not this.resultIsVoid() and not this.resultIsVoid() and
( if exists(getExtractorFrontendVersion())
then
expr.hasLValueToRValueConversion() and expr.hasLValueToRValueConversion() and
result = this.getInstruction(ConditionValueResultTempAddressTag()) result = this.getInstruction(ConditionValueResultTempAddressTag())
or or
not expr.hasLValueToRValueConversion() and not expr.hasLValueToRValueConversion() and
result = this.getInstruction(ConditionValueResultLoadTag()) result = this.getInstruction(ConditionValueResultLoadTag())
) else result = this.getInstruction(ConditionValueResultLoadTag())
} }
override Instruction getChildSuccessor(TranslatedElement child) { override Instruction getChildSuccessor(TranslatedElement child) {
@@ -3226,9 +3273,19 @@ predicate exprNeedsCopyIfNotLoaded(Expr expr) {
( (
expr instanceof AssignExpr expr instanceof AssignExpr
or or
expr instanceof AssignOperation expr instanceof AssignOperation and
(
not expr.isPRValueCategory() // is C++
or
exists(getExtractorFrontendVersion())
)
or or
expr instanceof PrefixCrementOperation expr instanceof PrefixCrementOperation and
(
not expr.isPRValueCategory() // is C++
or
exists(getExtractorFrontendVersion())
)
or or
// Because the load is on the `e` in `e++`. // Because the load is on the `e` in `e++`.
expr instanceof PostfixCrementOperation expr instanceof PostfixCrementOperation

View File

@@ -197,6 +197,11 @@ svnchurn(
* C++ dbscheme * C++ dbscheme
*/ */
extractor_version(
string codeql_version: string ref,
string frontend_version: string ref
)
@location = @location_stmt | @location_expr | @location_default ; @location = @location_stmt | @location_expr | @location_default ;
/** /**

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
description: Introduce extractor version numbers
compatibility: full