From 1777c9475ee6530c485518575644b1b88ea72a9f Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Mon, 28 Oct 2019 14:26:35 -0700 Subject: [PATCH 1/3] C++/C#: Remove `Instruction::getResultType()` and friends Now that the language-neutral IR type system is in place, this PR gets rid of the language-specific IR type APIs that caused the original problem. I've fixed up a fair bit of code to avoid these, including range analysis and sign analysis. These last two are almost shareable between C# and C++ now that they depend on `IRType`, but I haven't done the actual work to officially share them. --- .../cpp/ir/dataflow/internal/DataFlowUtil.qll | 12 ++++- .../code/cpp/ir/implementation/IRType.qll | 16 ++++-- .../aliased_ssa/Instruction.qll | 49 ++--------------- .../ir/implementation/aliased_ssa/Operand.qll | 18 ------- .../aliased_ssa/internal/AliasAnalysis.qll | 13 ++--- .../cpp/ir/implementation/raw/Instruction.qll | 49 ++--------------- .../cpp/ir/implementation/raw/Operand.qll | 18 ------- .../unaliased_ssa/Instruction.qll | 49 ++--------------- .../implementation/unaliased_ssa/Operand.qll | 18 ------- .../unaliased_ssa/internal/AliasAnalysis.qll | 13 ++--- .../semmle/code/cpp/rangeanalysis/Bound.qll | 4 +- .../code/cpp/rangeanalysis/RangeAnalysis.qll | 41 +++++++------- .../code/cpp/rangeanalysis/SignAnalysis.qll | 11 ++-- .../code/csharp/ir/implementation/IRType.qll | 16 ++++-- .../ir/implementation/raw/Instruction.qll | 49 ++--------------- .../csharp/ir/implementation/raw/Operand.qll | 18 ------- .../raw/internal/TranslatedDeclaration.qll | 3 +- .../raw/internal/TranslatedExpr.qll | 10 ++-- .../raw/internal/TranslatedInitialization.qll | 14 ++--- .../raw/internal/TranslatedStmt.qll | 6 +-- .../unaliased_ssa/Instruction.qll | 49 ++--------------- .../implementation/unaliased_ssa/Operand.qll | 18 ------- .../unaliased_ssa/internal/AliasAnalysis.qll | 11 +--- .../code/csharp/ir/rangeanalysis/Bound.qll | 4 +- .../csharp/ir/rangeanalysis/RangeAnalysis.qll | 53 +++++++------------ .../csharp/ir/rangeanalysis/SignAnalysis.qll | 11 ++-- 26 files changed, 137 insertions(+), 436 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll index 0476ea3c30ab..86699476fd18 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll @@ -5,6 +5,7 @@ private import cpp private import semmle.code.cpp.ir.IR private import semmle.code.cpp.controlflow.IRGuards +private import semmle.code.cpp.ir.internal.IRCppLanguage as Language /** * A newtype wrapper to prevent accidental casts between `Node` and @@ -33,7 +34,16 @@ class Node extends TIRDataFlowNode { Function getFunction() { result = instr.getEnclosingFunction() } /** Gets the type of this node. */ - Type getType() { result = instr.getResultType() } + Type getType() { + exists(Language::LanguageType resultType | + resultType = instr.getResultLanguageType() and + ( + resultType.hasUnspecifiedType(result, _) + or + not resultType.hasUnspecifiedType(_, _) and result instanceof Language::UnknownType + ) + ) + } Instruction asInstruction() { this = MkIRDataFlowNode(result) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll index 0abfa14023d8..77a255868963 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll @@ -120,7 +120,7 @@ class IRBooleanType extends IRSizedType, TIRBooleanType { } /** - * A numberic type. This includes `IRSignedIntegerType`, `IRUnsignedIntegerType`, and + * A numeric type. This includes `IRSignedIntegerType`, `IRUnsignedIntegerType`, and * `IRFloatingPointType`. */ class IRNumericType extends IRSizedType { @@ -131,11 +131,21 @@ class IRNumericType extends IRSizedType { } } +/** + * An integer type. This includes `IRSignedIntegerType` and `IRUnsignedIntegerType`. + */ +class IRIntegerType extends IRNumericType { + IRIntegerType() { + this = TIRSignedIntegerType(byteSize) or + this = TIRUnsignedIntegerType(byteSize) + } +} + /** * A signed two's-complement integer. Also used to represent enums whose underlying type is a signed * integer, as well as character types whose representation is signed. */ -class IRSignedIntegerType extends IRNumericType, TIRSignedIntegerType { +class IRSignedIntegerType extends IRIntegerType, TIRSignedIntegerType { final override string toString() { result = "int" + byteSize.toString() } final override Language::LanguageType getCanonicalLanguageType() { @@ -147,7 +157,7 @@ class IRSignedIntegerType extends IRNumericType, TIRSignedIntegerType { * An unsigned two's-complement integer. Also used to represent enums whose underlying type is an * unsigned integer, as well as character types whose representation is unsigned. */ -class IRUnsignedIntegerType extends IRNumericType, TIRUnsignedIntegerType { +class IRUnsignedIntegerType extends IRIntegerType, TIRUnsignedIntegerType { final override string toString() { result = "uint" + byteSize.toString() } final override Language::LanguageType getCanonicalLanguageType() { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index 79e39fab3814..b83a3bca9cd7 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -115,7 +115,7 @@ module InstructionSanity { query predicate missingOperandType(Operand operand, string message) { exists(Language::Function func, Instruction use | - not exists(operand.getType()) and + not exists(operand.getLanguageType()) and use = operand.getUse() and func = use.getEnclosingFunction() and message = "Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() @@ -455,52 +455,11 @@ class Instruction extends Construction::TInstruction { */ final IRType getResultIRType() { result = getResultLanguageType().getIRType() } - /** - * Gets the type of the result produced by this instruction. If the - * instruction does not produce a result, its result type will be `VoidType`. - * - * If `isGLValue()` holds, then the result type of this instruction should be - * thought of as "pointer to `getResultType()`". - */ - final Language::Type getResultType() { - exists(Language::LanguageType resultType | - resultType = getResultLanguageType() and - ( - resultType.hasUnspecifiedType(result, _) - or - not resultType.hasUnspecifiedType(_, _) and result instanceof Language::UnknownType - ) - ) - } - - /** - * Holds if the result produced by this instruction is a glvalue. If this - * holds, the result of the instruction represents the address of a location, - * and the type of the location is given by `getResultType()`. If this does - * not hold, the result of the instruction represents a value whose type is - * given by `getResultType()`. - * - * For example, the statement `y = x;` generates the following IR: - * r1_0(glval: int) = VariableAddress[x] - * r1_1(int) = Load r1_0, mu0_1 - * r1_2(glval: int) = VariableAddress[y] - * mu1_3(int) = Store r1_2, r1_1 - * - * The result of each `VariableAddress` instruction is a glvalue of type - * `int`, representing the address of the corresponding integer variable. The - * result of the `Load` instruction is a prvalue of type `int`, representing - * the integer value loaded from variable `x`. - */ - final predicate isGLValue() { Construction::getInstructionResultType(this).hasType(_, true) } - /** * Gets the size of the result produced by this instruction, in bytes. If the * result does not have a known constant size, this predicate does not hold. - * - * If `this.isGLValue()` holds for this instruction, the value of - * `getResultSize()` will always be the size of a pointer. */ - final int getResultSize() { result = Construction::getInstructionResultType(this).getByteSize() } + final int getResultSize() { result = getResultLanguageType().getByteSize() } /** * Gets the opcode that specifies the operation performed by this instruction. @@ -799,11 +758,11 @@ class ConstantInstruction extends ConstantValueInstruction { } class IntegerConstantInstruction extends ConstantInstruction { - IntegerConstantInstruction() { getResultType() instanceof Language::IntegralType } + IntegerConstantInstruction() { getResultIRType() instanceof IRIntegerType or getResultIRType() instanceof IRBooleanType } } class FloatConstantInstruction extends ConstantInstruction { - FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType } + FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType } } class StringConstantInstruction extends Instruction { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll index 1b27583f4690..a5cc894355ea 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll @@ -155,24 +155,6 @@ class Operand extends TOperand { */ final IRType getIRType() { result = getLanguageType().getIRType() } - /** - * Gets the type of the value consumed by this operand. This is usually the same as the - * result type of the definition instruction consumed by this operand. For register operands, - * this is always the case. For some memory operands, the operand type may be different from - * the definition type, such as in the case of a partial read or a read from a pointer that - * has been cast to a different type. - */ - final Language::Type getType() { getLanguageType().hasType(result, _) } - - /** - * Holds if the value consumed by this operand is a glvalue. If this - * holds, the value of the operand represents the address of a location, - * and the type of the location is given by `getType()`. If this does - * not hold, the value of the operand represents a value whose type is - * given by `getType()`. - */ - final predicate isGLValue() { getLanguageType().hasType(_, true) } - /** * Gets the size of the value consumed by this operand, in bytes. If the operand does not have * a known constant size, this predicate does not hold. diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll index b9aa07c1b367..2f7aedea8f62 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/AliasAnalysis.qll @@ -55,7 +55,7 @@ private predicate operandIsConsumedWithoutEscaping(Operand operand) { instr instanceof PointerDiffInstruction or // Converting an address to a `bool` does not escape the address. - instr.(ConvertInstruction).getResultType() instanceof BoolType + instr.(ConvertInstruction).getResultIRType() instanceof IRBooleanType ) ) or @@ -125,15 +125,8 @@ private predicate operandIsPropagated(Operand operand, IntValue bitOffset) { bitOffset = Ints::unknown() or // Conversion to another pointer type propagates the source address. - exists(ConvertInstruction convert, Type resultType | - convert = instr and - resultType = convert.getResultType() and - ( - resultType instanceof PointerType or - resultType instanceof Class //REVIEW: Remove when all glvalues are pointers - ) and - bitOffset = 0 - ) + instr.(ConvertInstruction).getResultIRType() instanceof IRAddressType and + bitOffset = 0 or // Adding an integer to or subtracting an integer from a pointer propagates // the address with an offset. diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll index 79e39fab3814..b83a3bca9cd7 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -115,7 +115,7 @@ module InstructionSanity { query predicate missingOperandType(Operand operand, string message) { exists(Language::Function func, Instruction use | - not exists(operand.getType()) and + not exists(operand.getLanguageType()) and use = operand.getUse() and func = use.getEnclosingFunction() and message = "Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() @@ -455,52 +455,11 @@ class Instruction extends Construction::TInstruction { */ final IRType getResultIRType() { result = getResultLanguageType().getIRType() } - /** - * Gets the type of the result produced by this instruction. If the - * instruction does not produce a result, its result type will be `VoidType`. - * - * If `isGLValue()` holds, then the result type of this instruction should be - * thought of as "pointer to `getResultType()`". - */ - final Language::Type getResultType() { - exists(Language::LanguageType resultType | - resultType = getResultLanguageType() and - ( - resultType.hasUnspecifiedType(result, _) - or - not resultType.hasUnspecifiedType(_, _) and result instanceof Language::UnknownType - ) - ) - } - - /** - * Holds if the result produced by this instruction is a glvalue. If this - * holds, the result of the instruction represents the address of a location, - * and the type of the location is given by `getResultType()`. If this does - * not hold, the result of the instruction represents a value whose type is - * given by `getResultType()`. - * - * For example, the statement `y = x;` generates the following IR: - * r1_0(glval: int) = VariableAddress[x] - * r1_1(int) = Load r1_0, mu0_1 - * r1_2(glval: int) = VariableAddress[y] - * mu1_3(int) = Store r1_2, r1_1 - * - * The result of each `VariableAddress` instruction is a glvalue of type - * `int`, representing the address of the corresponding integer variable. The - * result of the `Load` instruction is a prvalue of type `int`, representing - * the integer value loaded from variable `x`. - */ - final predicate isGLValue() { Construction::getInstructionResultType(this).hasType(_, true) } - /** * Gets the size of the result produced by this instruction, in bytes. If the * result does not have a known constant size, this predicate does not hold. - * - * If `this.isGLValue()` holds for this instruction, the value of - * `getResultSize()` will always be the size of a pointer. */ - final int getResultSize() { result = Construction::getInstructionResultType(this).getByteSize() } + final int getResultSize() { result = getResultLanguageType().getByteSize() } /** * Gets the opcode that specifies the operation performed by this instruction. @@ -799,11 +758,11 @@ class ConstantInstruction extends ConstantValueInstruction { } class IntegerConstantInstruction extends ConstantInstruction { - IntegerConstantInstruction() { getResultType() instanceof Language::IntegralType } + IntegerConstantInstruction() { getResultIRType() instanceof IRIntegerType or getResultIRType() instanceof IRBooleanType } } class FloatConstantInstruction extends ConstantInstruction { - FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType } + FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType } } class StringConstantInstruction extends Instruction { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll index 1b27583f4690..a5cc894355ea 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll @@ -155,24 +155,6 @@ class Operand extends TOperand { */ final IRType getIRType() { result = getLanguageType().getIRType() } - /** - * Gets the type of the value consumed by this operand. This is usually the same as the - * result type of the definition instruction consumed by this operand. For register operands, - * this is always the case. For some memory operands, the operand type may be different from - * the definition type, such as in the case of a partial read or a read from a pointer that - * has been cast to a different type. - */ - final Language::Type getType() { getLanguageType().hasType(result, _) } - - /** - * Holds if the value consumed by this operand is a glvalue. If this - * holds, the value of the operand represents the address of a location, - * and the type of the location is given by `getType()`. If this does - * not hold, the value of the operand represents a value whose type is - * given by `getType()`. - */ - final predicate isGLValue() { getLanguageType().hasType(_, true) } - /** * Gets the size of the value consumed by this operand, in bytes. If the operand does not have * a known constant size, this predicate does not hold. diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index 79e39fab3814..b83a3bca9cd7 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -115,7 +115,7 @@ module InstructionSanity { query predicate missingOperandType(Operand operand, string message) { exists(Language::Function func, Instruction use | - not exists(operand.getType()) and + not exists(operand.getLanguageType()) and use = operand.getUse() and func = use.getEnclosingFunction() and message = "Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() @@ -455,52 +455,11 @@ class Instruction extends Construction::TInstruction { */ final IRType getResultIRType() { result = getResultLanguageType().getIRType() } - /** - * Gets the type of the result produced by this instruction. If the - * instruction does not produce a result, its result type will be `VoidType`. - * - * If `isGLValue()` holds, then the result type of this instruction should be - * thought of as "pointer to `getResultType()`". - */ - final Language::Type getResultType() { - exists(Language::LanguageType resultType | - resultType = getResultLanguageType() and - ( - resultType.hasUnspecifiedType(result, _) - or - not resultType.hasUnspecifiedType(_, _) and result instanceof Language::UnknownType - ) - ) - } - - /** - * Holds if the result produced by this instruction is a glvalue. If this - * holds, the result of the instruction represents the address of a location, - * and the type of the location is given by `getResultType()`. If this does - * not hold, the result of the instruction represents a value whose type is - * given by `getResultType()`. - * - * For example, the statement `y = x;` generates the following IR: - * r1_0(glval: int) = VariableAddress[x] - * r1_1(int) = Load r1_0, mu0_1 - * r1_2(glval: int) = VariableAddress[y] - * mu1_3(int) = Store r1_2, r1_1 - * - * The result of each `VariableAddress` instruction is a glvalue of type - * `int`, representing the address of the corresponding integer variable. The - * result of the `Load` instruction is a prvalue of type `int`, representing - * the integer value loaded from variable `x`. - */ - final predicate isGLValue() { Construction::getInstructionResultType(this).hasType(_, true) } - /** * Gets the size of the result produced by this instruction, in bytes. If the * result does not have a known constant size, this predicate does not hold. - * - * If `this.isGLValue()` holds for this instruction, the value of - * `getResultSize()` will always be the size of a pointer. */ - final int getResultSize() { result = Construction::getInstructionResultType(this).getByteSize() } + final int getResultSize() { result = getResultLanguageType().getByteSize() } /** * Gets the opcode that specifies the operation performed by this instruction. @@ -799,11 +758,11 @@ class ConstantInstruction extends ConstantValueInstruction { } class IntegerConstantInstruction extends ConstantInstruction { - IntegerConstantInstruction() { getResultType() instanceof Language::IntegralType } + IntegerConstantInstruction() { getResultIRType() instanceof IRIntegerType or getResultIRType() instanceof IRBooleanType } } class FloatConstantInstruction extends ConstantInstruction { - FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType } + FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType } } class StringConstantInstruction extends Instruction { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll index 1b27583f4690..a5cc894355ea 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Operand.qll @@ -155,24 +155,6 @@ class Operand extends TOperand { */ final IRType getIRType() { result = getLanguageType().getIRType() } - /** - * Gets the type of the value consumed by this operand. This is usually the same as the - * result type of the definition instruction consumed by this operand. For register operands, - * this is always the case. For some memory operands, the operand type may be different from - * the definition type, such as in the case of a partial read or a read from a pointer that - * has been cast to a different type. - */ - final Language::Type getType() { getLanguageType().hasType(result, _) } - - /** - * Holds if the value consumed by this operand is a glvalue. If this - * holds, the value of the operand represents the address of a location, - * and the type of the location is given by `getType()`. If this does - * not hold, the value of the operand represents a value whose type is - * given by `getType()`. - */ - final predicate isGLValue() { getLanguageType().hasType(_, true) } - /** * Gets the size of the value consumed by this operand, in bytes. If the operand does not have * a known constant size, this predicate does not hold. diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll index b9aa07c1b367..2f7aedea8f62 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll @@ -55,7 +55,7 @@ private predicate operandIsConsumedWithoutEscaping(Operand operand) { instr instanceof PointerDiffInstruction or // Converting an address to a `bool` does not escape the address. - instr.(ConvertInstruction).getResultType() instanceof BoolType + instr.(ConvertInstruction).getResultIRType() instanceof IRBooleanType ) ) or @@ -125,15 +125,8 @@ private predicate operandIsPropagated(Operand operand, IntValue bitOffset) { bitOffset = Ints::unknown() or // Conversion to another pointer type propagates the source address. - exists(ConvertInstruction convert, Type resultType | - convert = instr and - resultType = convert.getResultType() and - ( - resultType instanceof PointerType or - resultType instanceof Class //REVIEW: Remove when all glvalues are pointers - ) and - bitOffset = 0 - ) + instr.(ConvertInstruction).getResultIRType() instanceof IRAddressType and + bitOffset = 0 or // Adding an integer to or subtracting an integer from a pointer propagates // the address with an offset. diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/Bound.qll b/cpp/ql/src/semmle/code/cpp/rangeanalysis/Bound.qll index fe0e211087c3..b2f6df79d947 100644 --- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/Bound.qll +++ b/cpp/ql/src/semmle/code/cpp/rangeanalysis/Bound.qll @@ -8,8 +8,8 @@ private newtype TBound = exists(Instruction i | vn.getAnInstruction() = i and ( - i.getResultType() instanceof IntegralType or - i.getResultType() instanceof PointerType + i.getResultIRType() instanceof IRIntegerType or + i.getResultIRType() instanceof IRAddressType ) and not vn.getAnInstruction() instanceof ConstantInstruction | diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeAnalysis.qll b/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeAnalysis.qll index 50fe6ab9a550..d431bbee29e4 100644 --- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/rangeanalysis/RangeAnalysis.qll @@ -67,7 +67,6 @@ * back-edge as a precise bound might require traversing a loop once). */ -import cpp private import semmle.code.cpp.ir.IR private import semmle.code.cpp.controlflow.IRGuards private import semmle.code.cpp.ir.ValueNumbering @@ -202,44 +201,44 @@ class CondReason extends Reason, TCondReason { * range analysis. */ pragma[inline] -private predicate safeCast(IntegralType fromtyp, IntegralType totyp) { - fromtyp.getSize() < totyp.getSize() and +private predicate safeCast(IRIntegerType fromtyp, IRIntegerType totyp) { + fromtyp.getByteSize() < totyp.getByteSize() and ( - fromtyp.isUnsigned() + fromtyp instanceof IRUnsignedIntegerType or - totyp.isSigned() + totyp instanceof IRSignedIntegerType ) or - fromtyp.getSize() <= totyp.getSize() and + fromtyp.getByteSize() <= totyp.getByteSize() and ( - fromtyp.isSigned() and - totyp.isSigned() + fromtyp instanceof IRSignedIntegerType and + totyp instanceof IRSignedIntegerType or - fromtyp.isUnsigned() and - totyp.isUnsigned() + fromtyp instanceof IRUnsignedIntegerType and + totyp instanceof IRUnsignedIntegerType ) } private class SafeCastInstruction extends ConvertInstruction { SafeCastInstruction() { - safeCast(getResultType(), getUnary().getResultType()) + safeCast(getResultIRType(), getUnary().getResultIRType()) or - getResultType() instanceof PointerType and - getUnary().getResultType() instanceof PointerType + getResultIRType() instanceof IRAddressType and + getUnary().getResultIRType() instanceof IRAddressType } } /** * Holds if `typ` is a small integral type with the given lower and upper bounds. */ -private predicate typeBound(IntegralType typ, int lowerbound, int upperbound) { - typ.isSigned() and typ.getSize() = 1 and lowerbound = -128 and upperbound = 127 +private predicate typeBound(IRIntegerType typ, int lowerbound, int upperbound) { + typ instanceof IRSignedIntegerType and typ.getByteSize() = 1 and lowerbound = -128 and upperbound = 127 or - typ.isUnsigned() and typ.getSize() = 1 and lowerbound = 0 and upperbound = 255 + typ instanceof IRUnsignedIntegerType and typ.getByteSize() = 1 and lowerbound = 0 and upperbound = 255 or - typ.isSigned() and typ.getSize() = 2 and lowerbound = -32768 and upperbound = 32767 + typ instanceof IRSignedIntegerType and typ.getByteSize() = 2 and lowerbound = -32768 and upperbound = 32767 or - typ.isUnsigned() and typ.getSize() = 2 and lowerbound = 0 and upperbound = 65535 + typ instanceof IRUnsignedIntegerType and typ.getByteSize() = 2 and lowerbound = 0 and upperbound = 65535 } /** @@ -248,14 +247,14 @@ private predicate typeBound(IntegralType typ, int lowerbound, int upperbound) { private class NarrowingCastInstruction extends ConvertInstruction { NarrowingCastInstruction() { not this instanceof SafeCastInstruction and - typeBound(getResultType(), _, _) + typeBound(getResultIRType(), _, _) } /** Gets the lower bound of the resulting type. */ - int getLowerBound() { typeBound(getResultType(), result, _) } + int getLowerBound() { typeBound(getResultIRType(), result, _) } /** Gets the upper bound of the resulting type. */ - int getUpperBound() { typeBound(getResultType(), _, result) } + int getUpperBound() { typeBound(getResultIRType(), _, result) } } /** diff --git a/cpp/ql/src/semmle/code/cpp/rangeanalysis/SignAnalysis.qll b/cpp/ql/src/semmle/code/cpp/rangeanalysis/SignAnalysis.qll index ca641f826ef3..380c869231b2 100644 --- a/cpp/ql/src/semmle/code/cpp/rangeanalysis/SignAnalysis.qll +++ b/cpp/ql/src/semmle/code/cpp/rangeanalysis/SignAnalysis.qll @@ -6,7 +6,6 @@ * three-valued domain `{negative, zero, positive}`. */ -import cpp private import semmle.code.cpp.ir.IR private import semmle.code.cpp.controlflow.IRGuards private import semmle.code.cpp.ir.ValueNumbering @@ -471,7 +470,7 @@ module SignAnalysisCached { not exists(certainInstructionSign(i)) and not ( result = TNeg() and - i.getResultType().(IntegralType).isUnsigned() + i.getResultIRType() instanceof IRUnsignedIntegerType ) and ( unknownSign(i) @@ -479,9 +478,9 @@ module SignAnalysisCached { exists(ConvertInstruction ci, Instruction prior, boolean fromSigned, boolean toSigned | i = ci and prior = ci.getUnary() and - (if ci.getResultType().(IntegralType).isSigned() then toSigned = true else toSigned = false) and + (if ci.getResultIRType() instanceof IRSignedIntegerType then toSigned = true else toSigned = false) and ( - if prior.getResultType().(IntegralType).isSigned() + if prior.getResultIRType() instanceof IRSignedIntegerType then fromSigned = true else fromSigned = false ) and @@ -514,11 +513,11 @@ module SignAnalysisCached { i instanceof ShiftLeftInstruction and result = s1.lshift(s2) or i instanceof ShiftRightInstruction and - i.getResultType().(IntegralType).isSigned() and + i.getResultIRType() instanceof IRSignedIntegerType and result = s1.rshift(s2) or i instanceof ShiftRightInstruction and - not i.getResultType().(IntegralType).isSigned() and + not i.getResultIRType() instanceof IRSignedIntegerType and result = s1.urshift(s2) ) or diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll index 0abfa14023d8..77a255868963 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/IRType.qll @@ -120,7 +120,7 @@ class IRBooleanType extends IRSizedType, TIRBooleanType { } /** - * A numberic type. This includes `IRSignedIntegerType`, `IRUnsignedIntegerType`, and + * A numeric type. This includes `IRSignedIntegerType`, `IRUnsignedIntegerType`, and * `IRFloatingPointType`. */ class IRNumericType extends IRSizedType { @@ -131,11 +131,21 @@ class IRNumericType extends IRSizedType { } } +/** + * An integer type. This includes `IRSignedIntegerType` and `IRUnsignedIntegerType`. + */ +class IRIntegerType extends IRNumericType { + IRIntegerType() { + this = TIRSignedIntegerType(byteSize) or + this = TIRUnsignedIntegerType(byteSize) + } +} + /** * A signed two's-complement integer. Also used to represent enums whose underlying type is a signed * integer, as well as character types whose representation is signed. */ -class IRSignedIntegerType extends IRNumericType, TIRSignedIntegerType { +class IRSignedIntegerType extends IRIntegerType, TIRSignedIntegerType { final override string toString() { result = "int" + byteSize.toString() } final override Language::LanguageType getCanonicalLanguageType() { @@ -147,7 +157,7 @@ class IRSignedIntegerType extends IRNumericType, TIRSignedIntegerType { * An unsigned two's-complement integer. Also used to represent enums whose underlying type is an * unsigned integer, as well as character types whose representation is unsigned. */ -class IRUnsignedIntegerType extends IRNumericType, TIRUnsignedIntegerType { +class IRUnsignedIntegerType extends IRIntegerType, TIRUnsignedIntegerType { final override string toString() { result = "uint" + byteSize.toString() } final override Language::LanguageType getCanonicalLanguageType() { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll index 79e39fab3814..b83a3bca9cd7 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll @@ -115,7 +115,7 @@ module InstructionSanity { query predicate missingOperandType(Operand operand, string message) { exists(Language::Function func, Instruction use | - not exists(operand.getType()) and + not exists(operand.getLanguageType()) and use = operand.getUse() and func = use.getEnclosingFunction() and message = "Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() @@ -455,52 +455,11 @@ class Instruction extends Construction::TInstruction { */ final IRType getResultIRType() { result = getResultLanguageType().getIRType() } - /** - * Gets the type of the result produced by this instruction. If the - * instruction does not produce a result, its result type will be `VoidType`. - * - * If `isGLValue()` holds, then the result type of this instruction should be - * thought of as "pointer to `getResultType()`". - */ - final Language::Type getResultType() { - exists(Language::LanguageType resultType | - resultType = getResultLanguageType() and - ( - resultType.hasUnspecifiedType(result, _) - or - not resultType.hasUnspecifiedType(_, _) and result instanceof Language::UnknownType - ) - ) - } - - /** - * Holds if the result produced by this instruction is a glvalue. If this - * holds, the result of the instruction represents the address of a location, - * and the type of the location is given by `getResultType()`. If this does - * not hold, the result of the instruction represents a value whose type is - * given by `getResultType()`. - * - * For example, the statement `y = x;` generates the following IR: - * r1_0(glval: int) = VariableAddress[x] - * r1_1(int) = Load r1_0, mu0_1 - * r1_2(glval: int) = VariableAddress[y] - * mu1_3(int) = Store r1_2, r1_1 - * - * The result of each `VariableAddress` instruction is a glvalue of type - * `int`, representing the address of the corresponding integer variable. The - * result of the `Load` instruction is a prvalue of type `int`, representing - * the integer value loaded from variable `x`. - */ - final predicate isGLValue() { Construction::getInstructionResultType(this).hasType(_, true) } - /** * Gets the size of the result produced by this instruction, in bytes. If the * result does not have a known constant size, this predicate does not hold. - * - * If `this.isGLValue()` holds for this instruction, the value of - * `getResultSize()` will always be the size of a pointer. */ - final int getResultSize() { result = Construction::getInstructionResultType(this).getByteSize() } + final int getResultSize() { result = getResultLanguageType().getByteSize() } /** * Gets the opcode that specifies the operation performed by this instruction. @@ -799,11 +758,11 @@ class ConstantInstruction extends ConstantValueInstruction { } class IntegerConstantInstruction extends ConstantInstruction { - IntegerConstantInstruction() { getResultType() instanceof Language::IntegralType } + IntegerConstantInstruction() { getResultIRType() instanceof IRIntegerType or getResultIRType() instanceof IRBooleanType } } class FloatConstantInstruction extends ConstantInstruction { - FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType } + FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType } } class StringConstantInstruction extends Instruction { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll index 1b27583f4690..a5cc894355ea 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Operand.qll @@ -155,24 +155,6 @@ class Operand extends TOperand { */ final IRType getIRType() { result = getLanguageType().getIRType() } - /** - * Gets the type of the value consumed by this operand. This is usually the same as the - * result type of the definition instruction consumed by this operand. For register operands, - * this is always the case. For some memory operands, the operand type may be different from - * the definition type, such as in the case of a partial read or a read from a pointer that - * has been cast to a different type. - */ - final Language::Type getType() { getLanguageType().hasType(result, _) } - - /** - * Holds if the value consumed by this operand is a glvalue. If this - * holds, the value of the operand represents the address of a location, - * and the type of the location is given by `getType()`. If this does - * not hold, the value of the operand represents a value whose type is - * given by `getType()`. - */ - final predicate isGLValue() { getLanguageType().hasType(_, true) } - /** * Gets the size of the value consumed by this operand, in bytes. If the operand does not have * a known constant size, this predicate does not hold. diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedDeclaration.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedDeclaration.qll index 9cd0a0a34fce..a17de3f3d141 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedDeclaration.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedDeclaration.qll @@ -6,6 +6,7 @@ private import InstructionTag private import TranslatedElement private import TranslatedExpr private import TranslatedInitialization +private import semmle.code.csharp.ir.internal.CSharpType private import semmle.code.csharp.ir.internal.IRCSharpLanguage as Language private import common.TranslatedDeclarationBase @@ -50,7 +51,7 @@ class TranslatedLocalVariableDeclaration extends TranslatedLocalDeclaration, override Type getVarType() { result = getVariableType(getDeclVar()) } - override Type getTargetType() { result = getVariableType(var) } + override CSharpType getTargetType() { result = getTypeForPRValue(getVariableType(var)) } override IRVariable getInstructionVariable(InstructionTag tag) { ( diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll index 2ccac5af4e01..efff3bc31c5f 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedExpr.qll @@ -486,8 +486,8 @@ class TranslatedObjectInitializerExpr extends TranslatedNonConstantExpr, Initial result = this.getParent().getInstruction(NewObjTag()) } - override Type getTargetType() { - result = this.getParent().getInstruction(NewObjTag()).getResultType() + override CSharpType getTargetType() { + result = this.getParent().getInstruction(NewObjTag()).getResultLanguageType() } } @@ -526,8 +526,8 @@ class TranslatedCollectionInitializer extends TranslatedNonConstantExpr, Initial result = this.getParent().getInstruction(NewObjTag()) } - override Type getTargetType() { - result = this.getParent().getInstruction(NewObjTag()).getResultType() + override CSharpType getTargetType() { + result = this.getParent().getInstruction(NewObjTag()).getResultLanguageType() } } @@ -1928,7 +1928,7 @@ class TranslatedLambdaExpr extends TranslatedNonConstantExpr, InitializationCont result = this.getInstruction(InitializerVariableAddressTag()) } - final override Type getTargetType() { result = this.getResultType() } + final override CSharpType getTargetType() { result = getTypeForPRValue(this.getResultType()) } private predicate hasInitializer() { exists(this.getInitialization()) } diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedInitialization.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedInitialization.qll index 0f6094f7a93c..1c9cb9553c03 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedInitialization.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedInitialization.qll @@ -35,7 +35,7 @@ abstract class InitializationContext extends TranslatedElement { /** * Gets the type of the location to be initialized. */ - abstract Type getTargetType(); + abstract CSharpType getTargetType(); } /** @@ -96,7 +96,7 @@ abstract class TranslatedListInitialization extends TranslatedInitialization, In override Instruction getTargetAddress() { result = this.getContext().getTargetAddress() } - override Type getTargetType() { result = this.getContext().getTargetType() } + override CSharpType getTargetType() { result = this.getContext().getTargetType() } } /** @@ -136,7 +136,7 @@ class TranslatedDirectInitialization extends TranslatedInitialization { override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) { tag = InitializerStoreTag() and opcode instanceof Opcode::Store and - resultType = getTypeForPRValue(this.getContext().getTargetType()) + resultType = this.getContext().getTargetType() or needsConversion() and tag = AssignmentConvertRightTag() and @@ -144,7 +144,7 @@ class TranslatedDirectInitialization extends TranslatedInitialization { // crudely represent conversions. Could // be useful to represent the whole chain of conversions opcode instanceof Opcode::Convert and - resultType = getTypeForPRValue(this.getContext().getTargetType()) + resultType = this.getContext().getTargetType() } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { @@ -191,7 +191,9 @@ class TranslatedDirectInitialization extends TranslatedInitialization { TranslatedExpr getInitializer() { result = getTranslatedExpr(expr) } - private predicate needsConversion() { expr.getType() != this.getContext().getTargetType() } + private predicate needsConversion() { + getTypeForPRValue(expr.getType()) != this.getContext().getTargetType() + } } /** @@ -279,7 +281,7 @@ class TranslatedExplicitElementInitialization extends TranslatedElementInitializ override Instruction getTargetAddress() { result = this.getInstruction(getElementAddressTag()) } - override Type getTargetType() { result = getElementType() } + override CSharpType getTargetType() { result = getTypeForPRValue(getElementType()) } override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { result = TranslatedElementInitialization.super.getInstructionSuccessor(tag, kind) diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedStmt.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedStmt.qll index ff6a7597ad26..abeff761ce63 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedStmt.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/internal/TranslatedStmt.qll @@ -181,8 +181,8 @@ class TranslatedReturnValueStmt extends TranslatedReturnStmt, InitializationCont result = this.getInstruction(InitializerVariableAddressTag()) } - override Type getTargetType() { - result = this.getEnclosingFunction().getReturnVariable().getType() + override CSharpType getTargetType() { + result = getTypeForPRValue(this.getEnclosingFunction().getReturnVariable().getType()) } TranslatedInitialization getInitialization() { @@ -473,7 +473,7 @@ class TranslatedThrowExceptionStmt extends TranslatedStmt, InitializationContext result = this.getInstruction(InitializerVariableAddressTag()) } - override Type getTargetType() { result = this.getExceptionType() } + override CSharpType getTargetType() { result = getTypeForPRValue(this.getExceptionType()) } TranslatedInitialization getInitialization() { result = getTranslatedInitialization(stmt.getExpr()) diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll index 79e39fab3814..b83a3bca9cd7 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll @@ -115,7 +115,7 @@ module InstructionSanity { query predicate missingOperandType(Operand operand, string message) { exists(Language::Function func, Instruction use | - not exists(operand.getType()) and + not exists(operand.getLanguageType()) and use = operand.getUse() and func = use.getEnclosingFunction() and message = "Operand '" + operand.toString() + "' of instruction '" + use.getOpcode().toString() @@ -455,52 +455,11 @@ class Instruction extends Construction::TInstruction { */ final IRType getResultIRType() { result = getResultLanguageType().getIRType() } - /** - * Gets the type of the result produced by this instruction. If the - * instruction does not produce a result, its result type will be `VoidType`. - * - * If `isGLValue()` holds, then the result type of this instruction should be - * thought of as "pointer to `getResultType()`". - */ - final Language::Type getResultType() { - exists(Language::LanguageType resultType | - resultType = getResultLanguageType() and - ( - resultType.hasUnspecifiedType(result, _) - or - not resultType.hasUnspecifiedType(_, _) and result instanceof Language::UnknownType - ) - ) - } - - /** - * Holds if the result produced by this instruction is a glvalue. If this - * holds, the result of the instruction represents the address of a location, - * and the type of the location is given by `getResultType()`. If this does - * not hold, the result of the instruction represents a value whose type is - * given by `getResultType()`. - * - * For example, the statement `y = x;` generates the following IR: - * r1_0(glval: int) = VariableAddress[x] - * r1_1(int) = Load r1_0, mu0_1 - * r1_2(glval: int) = VariableAddress[y] - * mu1_3(int) = Store r1_2, r1_1 - * - * The result of each `VariableAddress` instruction is a glvalue of type - * `int`, representing the address of the corresponding integer variable. The - * result of the `Load` instruction is a prvalue of type `int`, representing - * the integer value loaded from variable `x`. - */ - final predicate isGLValue() { Construction::getInstructionResultType(this).hasType(_, true) } - /** * Gets the size of the result produced by this instruction, in bytes. If the * result does not have a known constant size, this predicate does not hold. - * - * If `this.isGLValue()` holds for this instruction, the value of - * `getResultSize()` will always be the size of a pointer. */ - final int getResultSize() { result = Construction::getInstructionResultType(this).getByteSize() } + final int getResultSize() { result = getResultLanguageType().getByteSize() } /** * Gets the opcode that specifies the operation performed by this instruction. @@ -799,11 +758,11 @@ class ConstantInstruction extends ConstantValueInstruction { } class IntegerConstantInstruction extends ConstantInstruction { - IntegerConstantInstruction() { getResultType() instanceof Language::IntegralType } + IntegerConstantInstruction() { getResultIRType() instanceof IRIntegerType or getResultIRType() instanceof IRBooleanType } } class FloatConstantInstruction extends ConstantInstruction { - FloatConstantInstruction() { getResultType() instanceof Language::FloatingPointType } + FloatConstantInstruction() { getResultIRType() instanceof IRFloatingPointType } } class StringConstantInstruction extends Instruction { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll index 1b27583f4690..a5cc894355ea 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Operand.qll @@ -155,24 +155,6 @@ class Operand extends TOperand { */ final IRType getIRType() { result = getLanguageType().getIRType() } - /** - * Gets the type of the value consumed by this operand. This is usually the same as the - * result type of the definition instruction consumed by this operand. For register operands, - * this is always the case. For some memory operands, the operand type may be different from - * the definition type, such as in the case of a partial read or a read from a pointer that - * has been cast to a different type. - */ - final Language::Type getType() { getLanguageType().hasType(result, _) } - - /** - * Holds if the value consumed by this operand is a glvalue. If this - * holds, the value of the operand represents the address of a location, - * and the type of the location is given by `getType()`. If this does - * not hold, the value of the operand represents a value whose type is - * given by `getType()`. - */ - final predicate isGLValue() { getLanguageType().hasType(_, true) } - /** * Gets the size of the value consumed by this operand, in bytes. If the operand does not have * a known constant size, this predicate does not hold. diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll index 1f5064f6766f..b0aabc21c690 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/internal/AliasAnalysis.qll @@ -126,15 +126,8 @@ private predicate operandIsPropagated(Operand operand, IntValue bitOffset) { // virtual memory model for the IR I don't think such conversions provide any meaningful // information; // Conversion to another pointer type propagates the source address. - exists(ConvertInstruction convert, Type resultType | - convert = instr and - resultType = convert.getResultType() and - ( - resultType instanceof PointerType or - resultType instanceof RefType - ) and - bitOffset = 0 - ) + instr.(ConvertInstruction).getResultIRType() instanceof IRAddressType and + bitOffset = 0 or // Adding an integer to or subtracting an integer from a pointer propagates // the address with an offset. diff --git a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/Bound.qll b/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/Bound.qll index 8cde0baddfc5..19803bc4e73f 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/Bound.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/Bound.qll @@ -8,8 +8,8 @@ private newtype TBound = exists(Instruction i | vn.getAnInstruction() = i and ( - i.getResultType() instanceof IntegralType or - i.getResultType() instanceof PointerType + i.getResultIRType() instanceof IRIntegerType or + i.getResultIRType() instanceof IRAddressType ) and not vn.getAnInstruction() instanceof ConstantInstruction | diff --git a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeAnalysis.qll b/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeAnalysis.qll index e3403728633d..474274648403 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeAnalysis.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/RangeAnalysis.qll @@ -67,7 +67,6 @@ * back-edge as a precise bound might require traversing a loop once). */ -import csharp private import semmle.code.csharp.ir.IR private import semmle.code.csharp.ir.internal.IRGuards private import semmle.code.csharp.ir.ValueNumbering @@ -202,56 +201,44 @@ class CondReason extends Reason, TCondReason { * range analysis. */ pragma[inline] -private predicate safeCast(IntegralType fromtyp, IntegralType totyp) { - fromtyp.getSize() < totyp.getSize() and +private predicate safeCast(IRIntegerType fromtyp, IRIntegerType totyp) { + fromtyp.getByteSize() < totyp.getByteSize() and ( - fromtyp instanceof UnsignedIntegralType + fromtyp instanceof IRUnsignedIntegerType or - totyp instanceof SignedIntegralType + totyp instanceof IRSignedIntegerType ) or - fromtyp.getSize() <= totyp.getSize() and + fromtyp.getByteSize() <= totyp.getByteSize() and ( - fromtyp instanceof SignedIntegralType and - totyp instanceof SignedIntegralType + fromtyp instanceof IRSignedIntegerType and + totyp instanceof IRSignedIntegerType or - fromtyp instanceof UnsignedIntegralType and - totyp instanceof UnsignedIntegralType + fromtyp instanceof IRUnsignedIntegerType and + totyp instanceof IRUnsignedIntegerType ) } private class SafeCastInstruction extends ConvertInstruction { SafeCastInstruction() { - safeCast(getResultType(), getUnary().getResultType()) + safeCast(getResultIRType(), getUnary().getResultIRType()) or - getResultType() instanceof PointerType and - getUnary().getResultType() instanceof PointerType + getResultIRType() instanceof IRAddressType and + getUnary().getResultIRType() instanceof IRAddressType } } /** * Holds if `typ` is a small integral type with the given lower and upper bounds. */ -private predicate typeBound(IntegralType typ, int lowerbound, int upperbound) { - typ instanceof SignedIntegralType and - typ.getSize() = 1 and - lowerbound = typ.minValue() and - upperbound = typ.maxValue() +private predicate typeBound(IRIntegerType typ, int lowerbound, int upperbound) { + typ instanceof IRSignedIntegerType and typ.getByteSize() = 1 and lowerbound = -128 and upperbound = 127 or - typ instanceof UnsignedIntegralType and - typ.getSize() = 1 and - lowerbound = typ.minValue() and - upperbound = typ.maxValue() + typ instanceof IRUnsignedIntegerType and typ.getByteSize() = 1 and lowerbound = 0 and upperbound = 255 or - typ instanceof SignedIntegralType and - typ.getSize() = 2 and - lowerbound = typ.minValue() and - upperbound = typ.maxValue() + typ instanceof IRSignedIntegerType and typ.getByteSize() = 2 and lowerbound = -32768 and upperbound = 32767 or - typ instanceof UnsignedIntegralType and - typ.getSize() = 2 and - lowerbound = typ.minValue() and - upperbound = typ.maxValue() + typ instanceof IRUnsignedIntegerType and typ.getByteSize() = 2 and lowerbound = 0 and upperbound = 65535 } /** @@ -260,14 +247,14 @@ private predicate typeBound(IntegralType typ, int lowerbound, int upperbound) { private class NarrowingCastInstruction extends ConvertInstruction { NarrowingCastInstruction() { not this instanceof SafeCastInstruction and - typeBound(getResultType(), _, _) + typeBound(getResultIRType(), _, _) } /** Gets the lower bound of the resulting type. */ - int getLowerBound() { typeBound(getResultType(), result, _) } + int getLowerBound() { typeBound(getResultIRType(), result, _) } /** Gets the upper bound of the resulting type. */ - int getUpperBound() { typeBound(getResultType(), _, result) } + int getUpperBound() { typeBound(getResultIRType(), _, result) } } /** diff --git a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/SignAnalysis.qll b/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/SignAnalysis.qll index 1cba4d7e732e..23bfd5da7081 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/SignAnalysis.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/rangeanalysis/SignAnalysis.qll @@ -6,7 +6,6 @@ * three-valued domain `{negative, zero, positive}`. */ -import csharp private import semmle.code.csharp.ir.IR private import semmle.code.csharp.ir.internal.IRGuards private import semmle.code.csharp.ir.ValueNumbering @@ -471,7 +470,7 @@ module SignAnalysisCached { not exists(certainInstructionSign(i)) and not ( result = TNeg() and - i.getResultType() instanceof UnsignedIntegralType + i.getResultIRType() instanceof IRUnsignedIntegerType ) and ( unknownSign(i) @@ -480,12 +479,12 @@ module SignAnalysisCached { i = ci and prior = ci.getUnary() and ( - if ci.getResultType() instanceof SignedIntegralType + if ci.getResultIRType() instanceof IRSignedIntegerType then toSigned = true else toSigned = false ) and ( - if prior.getResultType() instanceof SignedIntegralType + if prior.getResultIRType() instanceof IRSignedIntegerType then fromSigned = true else fromSigned = false ) and @@ -518,11 +517,11 @@ module SignAnalysisCached { i instanceof ShiftLeftInstruction and result = s1.lshift(s2) or i instanceof ShiftRightInstruction and - i.getResultType().(IntegralType) instanceof SignedIntegralType and + i.getResultIRType() instanceof IRSignedIntegerType and result = s1.rshift(s2) or i instanceof ShiftRightInstruction and - not i.getResultType().(IntegralType) instanceof SignedIntegralType and + not i.getResultIRType() instanceof IRSignedIntegerType and result = s1.urshift(s2) ) or From cfd2507dcbf1bd5af9acb50d5005a7d99fbebf59 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Mon, 28 Oct 2019 16:46:26 -0700 Subject: [PATCH 2/3] C++/C#: Fix formatting --- .../code/cpp/ir/implementation/aliased_ssa/Instruction.qll | 4 +++- .../src/semmle/code/cpp/ir/implementation/raw/Instruction.qll | 4 +++- .../code/cpp/ir/implementation/unaliased_ssa/Instruction.qll | 4 +++- .../semmle/code/csharp/ir/implementation/raw/Instruction.qll | 4 +++- .../csharp/ir/implementation/unaliased_ssa/Instruction.qll | 4 +++- 5 files changed, 15 insertions(+), 5 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll index b83a3bca9cd7..4ce3e54b9e39 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll @@ -758,7 +758,9 @@ class ConstantInstruction extends ConstantValueInstruction { } class IntegerConstantInstruction extends ConstantInstruction { - IntegerConstantInstruction() { getResultIRType() instanceof IRIntegerType or getResultIRType() instanceof IRBooleanType } + IntegerConstantInstruction() { + getResultIRType() instanceof IRIntegerType or getResultIRType() instanceof IRBooleanType + } } class FloatConstantInstruction extends ConstantInstruction { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll index b83a3bca9cd7..4ce3e54b9e39 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll @@ -758,7 +758,9 @@ class ConstantInstruction extends ConstantValueInstruction { } class IntegerConstantInstruction extends ConstantInstruction { - IntegerConstantInstruction() { getResultIRType() instanceof IRIntegerType or getResultIRType() instanceof IRBooleanType } + IntegerConstantInstruction() { + getResultIRType() instanceof IRIntegerType or getResultIRType() instanceof IRBooleanType + } } class FloatConstantInstruction extends ConstantInstruction { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll index b83a3bca9cd7..4ce3e54b9e39 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll @@ -758,7 +758,9 @@ class ConstantInstruction extends ConstantValueInstruction { } class IntegerConstantInstruction extends ConstantInstruction { - IntegerConstantInstruction() { getResultIRType() instanceof IRIntegerType or getResultIRType() instanceof IRBooleanType } + IntegerConstantInstruction() { + getResultIRType() instanceof IRIntegerType or getResultIRType() instanceof IRBooleanType + } } class FloatConstantInstruction extends ConstantInstruction { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll index b83a3bca9cd7..4ce3e54b9e39 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/raw/Instruction.qll @@ -758,7 +758,9 @@ class ConstantInstruction extends ConstantValueInstruction { } class IntegerConstantInstruction extends ConstantInstruction { - IntegerConstantInstruction() { getResultIRType() instanceof IRIntegerType or getResultIRType() instanceof IRBooleanType } + IntegerConstantInstruction() { + getResultIRType() instanceof IRIntegerType or getResultIRType() instanceof IRBooleanType + } } class FloatConstantInstruction extends ConstantInstruction { diff --git a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll index b83a3bca9cd7..4ce3e54b9e39 100644 --- a/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll +++ b/csharp/ql/src/semmle/code/csharp/ir/implementation/unaliased_ssa/Instruction.qll @@ -758,7 +758,9 @@ class ConstantInstruction extends ConstantValueInstruction { } class IntegerConstantInstruction extends ConstantInstruction { - IntegerConstantInstruction() { getResultIRType() instanceof IRIntegerType or getResultIRType() instanceof IRBooleanType } + IntegerConstantInstruction() { + getResultIRType() instanceof IRIntegerType or getResultIRType() instanceof IRBooleanType + } } class FloatConstantInstruction extends ConstantInstruction { From f7d37c12581fbff65d1cf10263e1914193869690 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Mon, 28 Oct 2019 16:52:40 -0700 Subject: [PATCH 3/3] C++: Fix `RedundantNullTestSimple.ql` after IRType change --- cpp/ql/src/Likely Bugs/RedundantNullCheckSimple.ql | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/cpp/ql/src/Likely Bugs/RedundantNullCheckSimple.ql b/cpp/ql/src/Likely Bugs/RedundantNullCheckSimple.ql index cce74e064a2e..34be477da542 100644 --- a/cpp/ql/src/Likely Bugs/RedundantNullCheckSimple.ql +++ b/cpp/ql/src/Likely Bugs/RedundantNullCheckSimple.ql @@ -23,7 +23,7 @@ import semmle.code.cpp.ir.ValueNumbering class NullInstruction extends ConstantValueInstruction { NullInstruction() { this.getValue() = "0" and - this.getResultType().getUnspecifiedType() instanceof PointerType + this.getResultIRType() instanceof IRAddressType } } @@ -42,8 +42,8 @@ predicate explicitNullTestOfInstruction(Instruction checked, Instruction bool) { or bool = any(ConvertInstruction convert | checked = convert.getUnary() and - convert.getResultType() instanceof BoolType and - checked.getResultType() instanceof PointerType + convert.getResultIRType() instanceof IRBooleanType and + checked.getResultIRType() instanceof IRAddressType ) }