From f48948c604bfde1fcc87e7e255f9963439d9dfd3 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Fri, 26 Jun 2020 09:04:37 -0400 Subject: [PATCH 01/20] C++: Opcode cleanup - Remove unused `MemoryAccessOpcode` - Make `OpcodeWithCondition` private - Add QLDoc for `Opcode` module --- cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll | 7 ++++--- csharp/ql/src/experimental/ir/implementation/Opcode.qll | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll index c0b8adbe56b..fe1b9e260aa 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll @@ -174,15 +174,13 @@ abstract class CopyOpcode extends Opcode { } abstract class ConvertToBaseOpcode extends UnaryOpcode { } -abstract class MemoryAccessOpcode extends Opcode { } - abstract class ReturnOpcode extends Opcode { } abstract class ThrowOpcode extends Opcode { } abstract class CatchOpcode extends Opcode { } -abstract class OpcodeWithCondition extends Opcode { +abstract private class OpcodeWithCondition extends Opcode { final override predicate hasOperandInternal(OperandTag tag) { tag instanceof ConditionOperandTag } } @@ -336,6 +334,9 @@ abstract class ReadSideEffectOpcode extends SideEffectOpcode { */ abstract class WriteSideEffectOpcode extends SideEffectOpcode { } +/** + * Provides `Opcode`s that specify the operation performed by an `Instruction`. + */ module Opcode { class NoOp extends Opcode, TNoOp { final override string toString() { result = "NoOp" } diff --git a/csharp/ql/src/experimental/ir/implementation/Opcode.qll b/csharp/ql/src/experimental/ir/implementation/Opcode.qll index c0b8adbe56b..fe1b9e260aa 100644 --- a/csharp/ql/src/experimental/ir/implementation/Opcode.qll +++ b/csharp/ql/src/experimental/ir/implementation/Opcode.qll @@ -174,15 +174,13 @@ abstract class CopyOpcode extends Opcode { } abstract class ConvertToBaseOpcode extends UnaryOpcode { } -abstract class MemoryAccessOpcode extends Opcode { } - abstract class ReturnOpcode extends Opcode { } abstract class ThrowOpcode extends Opcode { } abstract class CatchOpcode extends Opcode { } -abstract class OpcodeWithCondition extends Opcode { +abstract private class OpcodeWithCondition extends Opcode { final override predicate hasOperandInternal(OperandTag tag) { tag instanceof ConditionOperandTag } } @@ -336,6 +334,9 @@ abstract class ReadSideEffectOpcode extends SideEffectOpcode { */ abstract class WriteSideEffectOpcode extends SideEffectOpcode { } +/** + * Provides `Opcode`s that specify the operation performed by an `Instruction`. + */ module Opcode { class NoOp extends Opcode, TNoOp { final override string toString() { result = "NoOp" } From 023e1dc0a29d8028dddd468631dd3725b841158c Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Fri, 26 Jun 2020 11:39:10 -0400 Subject: [PATCH 02/20] Instruction and opcode cleanup - Renamed `DynamicCastToVoid` to the more descriptive `CompleteObjectAddress` - Split verbose description from summary in a few Instruction QLDoc comments. - Added `Instruction` classes for the few remaining `Opcode`s that didn't have one. - Removed a use of "e.g." --- .../code/cpp/ir/implementation/Opcode.qll | 6 +- .../aliased_ssa/Instruction.qll | 137 ++++++++++++++++-- .../cpp/ir/implementation/raw/Instruction.qll | 137 ++++++++++++++++-- .../raw/internal/TranslatedExpr.qll | 2 +- .../unaliased_ssa/Instruction.qll | 137 ++++++++++++++++-- .../experimental/ir/implementation/Opcode.qll | 6 +- .../ir/implementation/raw/Instruction.qll | 137 ++++++++++++++++-- .../unaliased_ssa/Instruction.qll | 137 ++++++++++++++++-- 8 files changed, 642 insertions(+), 57 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll index fe1b9e260aa..8b296346662 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll @@ -45,7 +45,7 @@ private newtype TOpcode = TConvertToDerived() or TCheckedConvertOrNull() or TCheckedConvertOrThrow() or - TDynamicCastToVoid() or + TCompleteObjectAddress() or TVariableAddress() or TFieldAddress() or TFunctionAddress() or @@ -514,8 +514,8 @@ module Opcode { final override string toString() { result = "CheckedConvertOrThrow" } } - class DynamicCastToVoid extends UnaryOpcode, TDynamicCastToVoid { - final override string toString() { result = "DynamicCastToVoid" } + class CompleteObjectAddress extends UnaryOpcode, TCompleteObjectAddress { + final override string toString() { result = "CompleteObjectAddress" } } class VariableAddress extends Opcode, TVariableAddress { 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 79516f6780d..e331a319cf8 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 @@ -537,6 +537,18 @@ class VariableAddressInstruction extends VariableInstruction { VariableAddressInstruction() { getOpcode() instanceof Opcode::VariableAddress } } +/** + * An instruction that returns the address of a function. + * + * This instruction returns the address of a function, including non-member functions, static member + * functions, and non-static member functions. + * + * The result has an `IRFunctionAddress` type. + */ +class FunctionAddressInstruction extends FunctionInstruction { + FunctionAddressInstruction() { getOpcode() instanceof Opcode::FunctionAddress } +} + /** * An instruction that initializes a parameter of the enclosing function with the value of the * corresponding argument passed by the caller. @@ -553,6 +565,16 @@ class InitializeParameterInstruction extends VariableInstruction { final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that initializes all memory that existed before this function was called. + * + * This instruction provides a definition for memory that, because it was actually allocated and + * initialized elsewhere, would not otherwise have a definition in this function. + */ +class InitializeNonLocalInstruction extends Instruction { + InitializeNonLocalInstruction() { getOpcode() instanceof Opcode::InitializeNonLocal } +} + /** * An instruction that initializes the memory pointed to by a parameter of the enclosing function * with the value of that memory on entry to the function. @@ -590,6 +612,25 @@ class FieldAddressInstruction extends FieldInstruction { final Instruction getObjectAddress() { result = getObjectAddressOperand().getDef() } } +/** + * An instruction that computes the address of the first element of a managed array. + * + * This instruction is used for element access to C# arrays. + */ +class ElementsAddressInstruction extends UnaryInstruction { + ElementsAddressInstruction() { getOpcode() instanceof Opcode::ElementsAddress } + + /** + * Gets the operand that provides the address of the array object. + */ + final UnaryOperand getArrayObjectAddressOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the address of the array object. + */ + final Instruction getArrayObjectAddress() { result = getArrayObjectAddressOperand().getDef() } +} + /** * An instruction that produces a well-defined but unknown result and has * unknown side effects, including side effects that are not conservatively @@ -1177,6 +1218,19 @@ class CheckedConvertOrThrowInstruction extends UnaryInstruction { CheckedConvertOrThrowInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrThrow } } +/** + * An instruction that returns the address of the complete object that contains the subobject + * pointed to by its operand. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent `dyanmic_cast` in C++, which returns the pointer to + * the most-derived object. + */ +class CompleteObjectAddressInstruction extends UnaryInstruction { + CompleteObjectAddressInstruction() { getOpcode() instanceof Opcode::CompleteObjectAddress } +} + /** * An instruction that converts the address of an object to the address of a different subobject of * the same object, without any type checking at runtime. @@ -1453,7 +1507,7 @@ class CallInstruction extends Instruction { * Gets the `Function` that the call targets, if this is statically known. */ final Language::Function getStaticCallTarget() { - result = getCallTarget().(FunctionInstruction).getFunctionSymbol() + result = getCallTarget().(FunctionAddressInstruction).getFunctionSymbol() } /** @@ -1516,9 +1570,10 @@ class CallSideEffectInstruction extends SideEffectInstruction { /** * An instruction representing the side effect of a function call on any memory - * that might be read by that call. This instruction is emitted instead of - * `CallSideEffectInstruction` when it's certain that the call target cannot - * write to escaped memory. + * that might be read by that call. + * + * This instruction is emitted instead of `CallSideEffectInstruction` when it is certain that the + * call target cannot write to escaped memory. */ class CallReadSideEffectInstruction extends SideEffectInstruction { CallReadSideEffectInstruction() { getOpcode() instanceof Opcode::CallReadSideEffect } @@ -1612,6 +1667,7 @@ class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstructi /** * An instruction representing the potential write of an indirect parameter within a function call. + * * Unlike `IndirectWriteSideEffectInstruction`, the location might not be completely overwritten. * written. */ @@ -1623,6 +1679,7 @@ class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction { /** * An instruction representing the write of an indirect buffer parameter within a function call. + * * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { @@ -1631,6 +1688,7 @@ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { /** * An instruction representing the write of an indirect buffer parameter within a function call. + * * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { @@ -1642,7 +1700,7 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio } /** - * An instruction representing the initial value of newly allocated memory, e.g. the result of a + * An instruction representing the initial value of newly allocated memory, such as the result of a * call to `malloc`. */ class InitializeDynamicAllocationInstruction extends SideEffectInstruction { @@ -1860,17 +1918,20 @@ class ChiInstruction extends Instruction { } /** - * An instruction representing unreachable code. Inserted in place of the original target - * instruction of a `ConditionalBranch` or `Switch` instruction where that particular edge is - * infeasible. + * An instruction representing unreachable code. + * + * This instruction is inserted in place of the original target instruction of a `ConditionalBranch` + * or `Switch` instruction where that particular edge is infeasible. */ class UnreachedInstruction extends Instruction { UnreachedInstruction() { getOpcode() instanceof Opcode::Unreached } } /** - * An instruction representing a built-in operation. This is used to represent - * operations such as access to variable argument lists. + * An instruction representing a built-in operation. + * + * This is used to represent a variety of intrinsic operations provided by the compiler + * implementation, such as vector arithmetic. */ class BuiltInOperationInstruction extends Instruction { Language::BuiltInOperation operation; @@ -1892,3 +1953,59 @@ class BuiltInInstruction extends BuiltInOperationInstruction { final override string getImmediateString() { result = getBuiltInOperation().toString() } } + +/** + * An instruction that returns a `va_list` to access the arguments passed to the `...` parameter. + * + * The operand specifies the address of the `IREllipsisVariable` used to represent the `...` + * parameter. The result is a `va_list` that initially refers to the first argument that was passed + * to the `...` parameter. + */ +class VarArgsStartInstruction extends UnaryInstruction { + VarArgsStartInstruction() { getOpcode() instanceof Opcode::VarArgsStart } +} + +/** + * An instruction that cleans up a `va_list` after it is no longer in use. + * + * The operand specifies the address of the `va_list` to clean up. This instruction does not return + * a result. + */ +class VarArgsEndInstruction extends UnaryInstruction { + VarArgsEndInstruction() { getOpcode() instanceof Opcode::VarArgsEnd } +} + +/** + * An instruction that returns the address of the argument currently pointed to by a `va_list`. + * + * The operand is the `va_list` that points to the argument. The result is the address of the + * argument. + */ +class VarArgInstruction extends UnaryInstruction { + VarArgInstruction() { getOpcode() instanceof Opcode::VarArg } +} + +/** + * An instruction that modifies a `va_list` to point to the next argument that was passed to the + * `...` parameter. + * + * The operand is the current `va_list`. The result is an updated `va_list` that points to the next + * argument of the `...` parameter. + */ +class NextVarArgInstruction extends UnaryInstruction { + NextVarArgInstruction() { getOpcode() instanceof Opcode::NextVarArg } +} + +/** + * An instruction that allocates a new object on the managed heap. + * + * This instruction is used to represent the allocation of a new object in C# using the `new` + * expression. This instruction does not invoke a constructor for the object. Instead, there will be + * a subsequent `Call` instruction to invoke the appropriate constructor directory, passing the + * result of the `NewObj` as the `this` argument. + * + * The result is the address of the newly allocated object. + */ +class NewObjInstruction extends Instruction { + NewObjInstruction() { getOpcode() instanceof Opcode::NewObj } +} 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 79516f6780d..e331a319cf8 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 @@ -537,6 +537,18 @@ class VariableAddressInstruction extends VariableInstruction { VariableAddressInstruction() { getOpcode() instanceof Opcode::VariableAddress } } +/** + * An instruction that returns the address of a function. + * + * This instruction returns the address of a function, including non-member functions, static member + * functions, and non-static member functions. + * + * The result has an `IRFunctionAddress` type. + */ +class FunctionAddressInstruction extends FunctionInstruction { + FunctionAddressInstruction() { getOpcode() instanceof Opcode::FunctionAddress } +} + /** * An instruction that initializes a parameter of the enclosing function with the value of the * corresponding argument passed by the caller. @@ -553,6 +565,16 @@ class InitializeParameterInstruction extends VariableInstruction { final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that initializes all memory that existed before this function was called. + * + * This instruction provides a definition for memory that, because it was actually allocated and + * initialized elsewhere, would not otherwise have a definition in this function. + */ +class InitializeNonLocalInstruction extends Instruction { + InitializeNonLocalInstruction() { getOpcode() instanceof Opcode::InitializeNonLocal } +} + /** * An instruction that initializes the memory pointed to by a parameter of the enclosing function * with the value of that memory on entry to the function. @@ -590,6 +612,25 @@ class FieldAddressInstruction extends FieldInstruction { final Instruction getObjectAddress() { result = getObjectAddressOperand().getDef() } } +/** + * An instruction that computes the address of the first element of a managed array. + * + * This instruction is used for element access to C# arrays. + */ +class ElementsAddressInstruction extends UnaryInstruction { + ElementsAddressInstruction() { getOpcode() instanceof Opcode::ElementsAddress } + + /** + * Gets the operand that provides the address of the array object. + */ + final UnaryOperand getArrayObjectAddressOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the address of the array object. + */ + final Instruction getArrayObjectAddress() { result = getArrayObjectAddressOperand().getDef() } +} + /** * An instruction that produces a well-defined but unknown result and has * unknown side effects, including side effects that are not conservatively @@ -1177,6 +1218,19 @@ class CheckedConvertOrThrowInstruction extends UnaryInstruction { CheckedConvertOrThrowInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrThrow } } +/** + * An instruction that returns the address of the complete object that contains the subobject + * pointed to by its operand. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent `dyanmic_cast` in C++, which returns the pointer to + * the most-derived object. + */ +class CompleteObjectAddressInstruction extends UnaryInstruction { + CompleteObjectAddressInstruction() { getOpcode() instanceof Opcode::CompleteObjectAddress } +} + /** * An instruction that converts the address of an object to the address of a different subobject of * the same object, without any type checking at runtime. @@ -1453,7 +1507,7 @@ class CallInstruction extends Instruction { * Gets the `Function` that the call targets, if this is statically known. */ final Language::Function getStaticCallTarget() { - result = getCallTarget().(FunctionInstruction).getFunctionSymbol() + result = getCallTarget().(FunctionAddressInstruction).getFunctionSymbol() } /** @@ -1516,9 +1570,10 @@ class CallSideEffectInstruction extends SideEffectInstruction { /** * An instruction representing the side effect of a function call on any memory - * that might be read by that call. This instruction is emitted instead of - * `CallSideEffectInstruction` when it's certain that the call target cannot - * write to escaped memory. + * that might be read by that call. + * + * This instruction is emitted instead of `CallSideEffectInstruction` when it is certain that the + * call target cannot write to escaped memory. */ class CallReadSideEffectInstruction extends SideEffectInstruction { CallReadSideEffectInstruction() { getOpcode() instanceof Opcode::CallReadSideEffect } @@ -1612,6 +1667,7 @@ class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstructi /** * An instruction representing the potential write of an indirect parameter within a function call. + * * Unlike `IndirectWriteSideEffectInstruction`, the location might not be completely overwritten. * written. */ @@ -1623,6 +1679,7 @@ class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction { /** * An instruction representing the write of an indirect buffer parameter within a function call. + * * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { @@ -1631,6 +1688,7 @@ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { /** * An instruction representing the write of an indirect buffer parameter within a function call. + * * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { @@ -1642,7 +1700,7 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio } /** - * An instruction representing the initial value of newly allocated memory, e.g. the result of a + * An instruction representing the initial value of newly allocated memory, such as the result of a * call to `malloc`. */ class InitializeDynamicAllocationInstruction extends SideEffectInstruction { @@ -1860,17 +1918,20 @@ class ChiInstruction extends Instruction { } /** - * An instruction representing unreachable code. Inserted in place of the original target - * instruction of a `ConditionalBranch` or `Switch` instruction where that particular edge is - * infeasible. + * An instruction representing unreachable code. + * + * This instruction is inserted in place of the original target instruction of a `ConditionalBranch` + * or `Switch` instruction where that particular edge is infeasible. */ class UnreachedInstruction extends Instruction { UnreachedInstruction() { getOpcode() instanceof Opcode::Unreached } } /** - * An instruction representing a built-in operation. This is used to represent - * operations such as access to variable argument lists. + * An instruction representing a built-in operation. + * + * This is used to represent a variety of intrinsic operations provided by the compiler + * implementation, such as vector arithmetic. */ class BuiltInOperationInstruction extends Instruction { Language::BuiltInOperation operation; @@ -1892,3 +1953,59 @@ class BuiltInInstruction extends BuiltInOperationInstruction { final override string getImmediateString() { result = getBuiltInOperation().toString() } } + +/** + * An instruction that returns a `va_list` to access the arguments passed to the `...` parameter. + * + * The operand specifies the address of the `IREllipsisVariable` used to represent the `...` + * parameter. The result is a `va_list` that initially refers to the first argument that was passed + * to the `...` parameter. + */ +class VarArgsStartInstruction extends UnaryInstruction { + VarArgsStartInstruction() { getOpcode() instanceof Opcode::VarArgsStart } +} + +/** + * An instruction that cleans up a `va_list` after it is no longer in use. + * + * The operand specifies the address of the `va_list` to clean up. This instruction does not return + * a result. + */ +class VarArgsEndInstruction extends UnaryInstruction { + VarArgsEndInstruction() { getOpcode() instanceof Opcode::VarArgsEnd } +} + +/** + * An instruction that returns the address of the argument currently pointed to by a `va_list`. + * + * The operand is the `va_list` that points to the argument. The result is the address of the + * argument. + */ +class VarArgInstruction extends UnaryInstruction { + VarArgInstruction() { getOpcode() instanceof Opcode::VarArg } +} + +/** + * An instruction that modifies a `va_list` to point to the next argument that was passed to the + * `...` parameter. + * + * The operand is the current `va_list`. The result is an updated `va_list` that points to the next + * argument of the `...` parameter. + */ +class NextVarArgInstruction extends UnaryInstruction { + NextVarArgInstruction() { getOpcode() instanceof Opcode::NextVarArg } +} + +/** + * An instruction that allocates a new object on the managed heap. + * + * This instruction is used to represent the allocation of a new object in C# using the `new` + * expression. This instruction does not invoke a constructor for the object. Instead, there will be + * a subsequent `Call` instruction to invoke the appropriate constructor directory, passing the + * result of the `NewObj` as the `this` argument. + * + * The result is the address of the newly allocated object. + */ +class NewObjInstruction extends Instruction { + NewObjInstruction() { getOpcode() instanceof Opcode::NewObj } +} diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll index 75e70d1986f..98bcd1da8b2 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedExpr.qll @@ -1011,7 +1011,7 @@ class TranslatedDynamicCast extends TranslatedSingleInstructionConversion { if resultType instanceof PointerType then if resultType.(PointerType).getBaseType() instanceof VoidType - then result instanceof Opcode::DynamicCastToVoid + then result instanceof Opcode::CompleteObjectAddress else result instanceof Opcode::CheckedConvertOrNull else result instanceof Opcode::CheckedConvertOrThrow ) 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 79516f6780d..e331a319cf8 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 @@ -537,6 +537,18 @@ class VariableAddressInstruction extends VariableInstruction { VariableAddressInstruction() { getOpcode() instanceof Opcode::VariableAddress } } +/** + * An instruction that returns the address of a function. + * + * This instruction returns the address of a function, including non-member functions, static member + * functions, and non-static member functions. + * + * The result has an `IRFunctionAddress` type. + */ +class FunctionAddressInstruction extends FunctionInstruction { + FunctionAddressInstruction() { getOpcode() instanceof Opcode::FunctionAddress } +} + /** * An instruction that initializes a parameter of the enclosing function with the value of the * corresponding argument passed by the caller. @@ -553,6 +565,16 @@ class InitializeParameterInstruction extends VariableInstruction { final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that initializes all memory that existed before this function was called. + * + * This instruction provides a definition for memory that, because it was actually allocated and + * initialized elsewhere, would not otherwise have a definition in this function. + */ +class InitializeNonLocalInstruction extends Instruction { + InitializeNonLocalInstruction() { getOpcode() instanceof Opcode::InitializeNonLocal } +} + /** * An instruction that initializes the memory pointed to by a parameter of the enclosing function * with the value of that memory on entry to the function. @@ -590,6 +612,25 @@ class FieldAddressInstruction extends FieldInstruction { final Instruction getObjectAddress() { result = getObjectAddressOperand().getDef() } } +/** + * An instruction that computes the address of the first element of a managed array. + * + * This instruction is used for element access to C# arrays. + */ +class ElementsAddressInstruction extends UnaryInstruction { + ElementsAddressInstruction() { getOpcode() instanceof Opcode::ElementsAddress } + + /** + * Gets the operand that provides the address of the array object. + */ + final UnaryOperand getArrayObjectAddressOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the address of the array object. + */ + final Instruction getArrayObjectAddress() { result = getArrayObjectAddressOperand().getDef() } +} + /** * An instruction that produces a well-defined but unknown result and has * unknown side effects, including side effects that are not conservatively @@ -1177,6 +1218,19 @@ class CheckedConvertOrThrowInstruction extends UnaryInstruction { CheckedConvertOrThrowInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrThrow } } +/** + * An instruction that returns the address of the complete object that contains the subobject + * pointed to by its operand. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent `dyanmic_cast` in C++, which returns the pointer to + * the most-derived object. + */ +class CompleteObjectAddressInstruction extends UnaryInstruction { + CompleteObjectAddressInstruction() { getOpcode() instanceof Opcode::CompleteObjectAddress } +} + /** * An instruction that converts the address of an object to the address of a different subobject of * the same object, without any type checking at runtime. @@ -1453,7 +1507,7 @@ class CallInstruction extends Instruction { * Gets the `Function` that the call targets, if this is statically known. */ final Language::Function getStaticCallTarget() { - result = getCallTarget().(FunctionInstruction).getFunctionSymbol() + result = getCallTarget().(FunctionAddressInstruction).getFunctionSymbol() } /** @@ -1516,9 +1570,10 @@ class CallSideEffectInstruction extends SideEffectInstruction { /** * An instruction representing the side effect of a function call on any memory - * that might be read by that call. This instruction is emitted instead of - * `CallSideEffectInstruction` when it's certain that the call target cannot - * write to escaped memory. + * that might be read by that call. + * + * This instruction is emitted instead of `CallSideEffectInstruction` when it is certain that the + * call target cannot write to escaped memory. */ class CallReadSideEffectInstruction extends SideEffectInstruction { CallReadSideEffectInstruction() { getOpcode() instanceof Opcode::CallReadSideEffect } @@ -1612,6 +1667,7 @@ class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstructi /** * An instruction representing the potential write of an indirect parameter within a function call. + * * Unlike `IndirectWriteSideEffectInstruction`, the location might not be completely overwritten. * written. */ @@ -1623,6 +1679,7 @@ class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction { /** * An instruction representing the write of an indirect buffer parameter within a function call. + * * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { @@ -1631,6 +1688,7 @@ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { /** * An instruction representing the write of an indirect buffer parameter within a function call. + * * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { @@ -1642,7 +1700,7 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio } /** - * An instruction representing the initial value of newly allocated memory, e.g. the result of a + * An instruction representing the initial value of newly allocated memory, such as the result of a * call to `malloc`. */ class InitializeDynamicAllocationInstruction extends SideEffectInstruction { @@ -1860,17 +1918,20 @@ class ChiInstruction extends Instruction { } /** - * An instruction representing unreachable code. Inserted in place of the original target - * instruction of a `ConditionalBranch` or `Switch` instruction where that particular edge is - * infeasible. + * An instruction representing unreachable code. + * + * This instruction is inserted in place of the original target instruction of a `ConditionalBranch` + * or `Switch` instruction where that particular edge is infeasible. */ class UnreachedInstruction extends Instruction { UnreachedInstruction() { getOpcode() instanceof Opcode::Unreached } } /** - * An instruction representing a built-in operation. This is used to represent - * operations such as access to variable argument lists. + * An instruction representing a built-in operation. + * + * This is used to represent a variety of intrinsic operations provided by the compiler + * implementation, such as vector arithmetic. */ class BuiltInOperationInstruction extends Instruction { Language::BuiltInOperation operation; @@ -1892,3 +1953,59 @@ class BuiltInInstruction extends BuiltInOperationInstruction { final override string getImmediateString() { result = getBuiltInOperation().toString() } } + +/** + * An instruction that returns a `va_list` to access the arguments passed to the `...` parameter. + * + * The operand specifies the address of the `IREllipsisVariable` used to represent the `...` + * parameter. The result is a `va_list` that initially refers to the first argument that was passed + * to the `...` parameter. + */ +class VarArgsStartInstruction extends UnaryInstruction { + VarArgsStartInstruction() { getOpcode() instanceof Opcode::VarArgsStart } +} + +/** + * An instruction that cleans up a `va_list` after it is no longer in use. + * + * The operand specifies the address of the `va_list` to clean up. This instruction does not return + * a result. + */ +class VarArgsEndInstruction extends UnaryInstruction { + VarArgsEndInstruction() { getOpcode() instanceof Opcode::VarArgsEnd } +} + +/** + * An instruction that returns the address of the argument currently pointed to by a `va_list`. + * + * The operand is the `va_list` that points to the argument. The result is the address of the + * argument. + */ +class VarArgInstruction extends UnaryInstruction { + VarArgInstruction() { getOpcode() instanceof Opcode::VarArg } +} + +/** + * An instruction that modifies a `va_list` to point to the next argument that was passed to the + * `...` parameter. + * + * The operand is the current `va_list`. The result is an updated `va_list` that points to the next + * argument of the `...` parameter. + */ +class NextVarArgInstruction extends UnaryInstruction { + NextVarArgInstruction() { getOpcode() instanceof Opcode::NextVarArg } +} + +/** + * An instruction that allocates a new object on the managed heap. + * + * This instruction is used to represent the allocation of a new object in C# using the `new` + * expression. This instruction does not invoke a constructor for the object. Instead, there will be + * a subsequent `Call` instruction to invoke the appropriate constructor directory, passing the + * result of the `NewObj` as the `this` argument. + * + * The result is the address of the newly allocated object. + */ +class NewObjInstruction extends Instruction { + NewObjInstruction() { getOpcode() instanceof Opcode::NewObj } +} diff --git a/csharp/ql/src/experimental/ir/implementation/Opcode.qll b/csharp/ql/src/experimental/ir/implementation/Opcode.qll index fe1b9e260aa..8b296346662 100644 --- a/csharp/ql/src/experimental/ir/implementation/Opcode.qll +++ b/csharp/ql/src/experimental/ir/implementation/Opcode.qll @@ -45,7 +45,7 @@ private newtype TOpcode = TConvertToDerived() or TCheckedConvertOrNull() or TCheckedConvertOrThrow() or - TDynamicCastToVoid() or + TCompleteObjectAddress() or TVariableAddress() or TFieldAddress() or TFunctionAddress() or @@ -514,8 +514,8 @@ module Opcode { final override string toString() { result = "CheckedConvertOrThrow" } } - class DynamicCastToVoid extends UnaryOpcode, TDynamicCastToVoid { - final override string toString() { result = "DynamicCastToVoid" } + class CompleteObjectAddress extends UnaryOpcode, TCompleteObjectAddress { + final override string toString() { result = "CompleteObjectAddress" } } class VariableAddress extends Opcode, TVariableAddress { diff --git a/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll b/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll index 79516f6780d..e331a319cf8 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll @@ -537,6 +537,18 @@ class VariableAddressInstruction extends VariableInstruction { VariableAddressInstruction() { getOpcode() instanceof Opcode::VariableAddress } } +/** + * An instruction that returns the address of a function. + * + * This instruction returns the address of a function, including non-member functions, static member + * functions, and non-static member functions. + * + * The result has an `IRFunctionAddress` type. + */ +class FunctionAddressInstruction extends FunctionInstruction { + FunctionAddressInstruction() { getOpcode() instanceof Opcode::FunctionAddress } +} + /** * An instruction that initializes a parameter of the enclosing function with the value of the * corresponding argument passed by the caller. @@ -553,6 +565,16 @@ class InitializeParameterInstruction extends VariableInstruction { final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that initializes all memory that existed before this function was called. + * + * This instruction provides a definition for memory that, because it was actually allocated and + * initialized elsewhere, would not otherwise have a definition in this function. + */ +class InitializeNonLocalInstruction extends Instruction { + InitializeNonLocalInstruction() { getOpcode() instanceof Opcode::InitializeNonLocal } +} + /** * An instruction that initializes the memory pointed to by a parameter of the enclosing function * with the value of that memory on entry to the function. @@ -590,6 +612,25 @@ class FieldAddressInstruction extends FieldInstruction { final Instruction getObjectAddress() { result = getObjectAddressOperand().getDef() } } +/** + * An instruction that computes the address of the first element of a managed array. + * + * This instruction is used for element access to C# arrays. + */ +class ElementsAddressInstruction extends UnaryInstruction { + ElementsAddressInstruction() { getOpcode() instanceof Opcode::ElementsAddress } + + /** + * Gets the operand that provides the address of the array object. + */ + final UnaryOperand getArrayObjectAddressOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the address of the array object. + */ + final Instruction getArrayObjectAddress() { result = getArrayObjectAddressOperand().getDef() } +} + /** * An instruction that produces a well-defined but unknown result and has * unknown side effects, including side effects that are not conservatively @@ -1177,6 +1218,19 @@ class CheckedConvertOrThrowInstruction extends UnaryInstruction { CheckedConvertOrThrowInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrThrow } } +/** + * An instruction that returns the address of the complete object that contains the subobject + * pointed to by its operand. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent `dyanmic_cast` in C++, which returns the pointer to + * the most-derived object. + */ +class CompleteObjectAddressInstruction extends UnaryInstruction { + CompleteObjectAddressInstruction() { getOpcode() instanceof Opcode::CompleteObjectAddress } +} + /** * An instruction that converts the address of an object to the address of a different subobject of * the same object, without any type checking at runtime. @@ -1453,7 +1507,7 @@ class CallInstruction extends Instruction { * Gets the `Function` that the call targets, if this is statically known. */ final Language::Function getStaticCallTarget() { - result = getCallTarget().(FunctionInstruction).getFunctionSymbol() + result = getCallTarget().(FunctionAddressInstruction).getFunctionSymbol() } /** @@ -1516,9 +1570,10 @@ class CallSideEffectInstruction extends SideEffectInstruction { /** * An instruction representing the side effect of a function call on any memory - * that might be read by that call. This instruction is emitted instead of - * `CallSideEffectInstruction` when it's certain that the call target cannot - * write to escaped memory. + * that might be read by that call. + * + * This instruction is emitted instead of `CallSideEffectInstruction` when it is certain that the + * call target cannot write to escaped memory. */ class CallReadSideEffectInstruction extends SideEffectInstruction { CallReadSideEffectInstruction() { getOpcode() instanceof Opcode::CallReadSideEffect } @@ -1612,6 +1667,7 @@ class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstructi /** * An instruction representing the potential write of an indirect parameter within a function call. + * * Unlike `IndirectWriteSideEffectInstruction`, the location might not be completely overwritten. * written. */ @@ -1623,6 +1679,7 @@ class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction { /** * An instruction representing the write of an indirect buffer parameter within a function call. + * * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { @@ -1631,6 +1688,7 @@ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { /** * An instruction representing the write of an indirect buffer parameter within a function call. + * * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { @@ -1642,7 +1700,7 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio } /** - * An instruction representing the initial value of newly allocated memory, e.g. the result of a + * An instruction representing the initial value of newly allocated memory, such as the result of a * call to `malloc`. */ class InitializeDynamicAllocationInstruction extends SideEffectInstruction { @@ -1860,17 +1918,20 @@ class ChiInstruction extends Instruction { } /** - * An instruction representing unreachable code. Inserted in place of the original target - * instruction of a `ConditionalBranch` or `Switch` instruction where that particular edge is - * infeasible. + * An instruction representing unreachable code. + * + * This instruction is inserted in place of the original target instruction of a `ConditionalBranch` + * or `Switch` instruction where that particular edge is infeasible. */ class UnreachedInstruction extends Instruction { UnreachedInstruction() { getOpcode() instanceof Opcode::Unreached } } /** - * An instruction representing a built-in operation. This is used to represent - * operations such as access to variable argument lists. + * An instruction representing a built-in operation. + * + * This is used to represent a variety of intrinsic operations provided by the compiler + * implementation, such as vector arithmetic. */ class BuiltInOperationInstruction extends Instruction { Language::BuiltInOperation operation; @@ -1892,3 +1953,59 @@ class BuiltInInstruction extends BuiltInOperationInstruction { final override string getImmediateString() { result = getBuiltInOperation().toString() } } + +/** + * An instruction that returns a `va_list` to access the arguments passed to the `...` parameter. + * + * The operand specifies the address of the `IREllipsisVariable` used to represent the `...` + * parameter. The result is a `va_list` that initially refers to the first argument that was passed + * to the `...` parameter. + */ +class VarArgsStartInstruction extends UnaryInstruction { + VarArgsStartInstruction() { getOpcode() instanceof Opcode::VarArgsStart } +} + +/** + * An instruction that cleans up a `va_list` after it is no longer in use. + * + * The operand specifies the address of the `va_list` to clean up. This instruction does not return + * a result. + */ +class VarArgsEndInstruction extends UnaryInstruction { + VarArgsEndInstruction() { getOpcode() instanceof Opcode::VarArgsEnd } +} + +/** + * An instruction that returns the address of the argument currently pointed to by a `va_list`. + * + * The operand is the `va_list` that points to the argument. The result is the address of the + * argument. + */ +class VarArgInstruction extends UnaryInstruction { + VarArgInstruction() { getOpcode() instanceof Opcode::VarArg } +} + +/** + * An instruction that modifies a `va_list` to point to the next argument that was passed to the + * `...` parameter. + * + * The operand is the current `va_list`. The result is an updated `va_list` that points to the next + * argument of the `...` parameter. + */ +class NextVarArgInstruction extends UnaryInstruction { + NextVarArgInstruction() { getOpcode() instanceof Opcode::NextVarArg } +} + +/** + * An instruction that allocates a new object on the managed heap. + * + * This instruction is used to represent the allocation of a new object in C# using the `new` + * expression. This instruction does not invoke a constructor for the object. Instead, there will be + * a subsequent `Call` instruction to invoke the appropriate constructor directory, passing the + * result of the `NewObj` as the `this` argument. + * + * The result is the address of the newly allocated object. + */ +class NewObjInstruction extends Instruction { + NewObjInstruction() { getOpcode() instanceof Opcode::NewObj } +} diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll index 79516f6780d..e331a319cf8 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll @@ -537,6 +537,18 @@ class VariableAddressInstruction extends VariableInstruction { VariableAddressInstruction() { getOpcode() instanceof Opcode::VariableAddress } } +/** + * An instruction that returns the address of a function. + * + * This instruction returns the address of a function, including non-member functions, static member + * functions, and non-static member functions. + * + * The result has an `IRFunctionAddress` type. + */ +class FunctionAddressInstruction extends FunctionInstruction { + FunctionAddressInstruction() { getOpcode() instanceof Opcode::FunctionAddress } +} + /** * An instruction that initializes a parameter of the enclosing function with the value of the * corresponding argument passed by the caller. @@ -553,6 +565,16 @@ class InitializeParameterInstruction extends VariableInstruction { final Language::Parameter getParameter() { result = var.(IRUserVariable).getVariable() } } +/** + * An instruction that initializes all memory that existed before this function was called. + * + * This instruction provides a definition for memory that, because it was actually allocated and + * initialized elsewhere, would not otherwise have a definition in this function. + */ +class InitializeNonLocalInstruction extends Instruction { + InitializeNonLocalInstruction() { getOpcode() instanceof Opcode::InitializeNonLocal } +} + /** * An instruction that initializes the memory pointed to by a parameter of the enclosing function * with the value of that memory on entry to the function. @@ -590,6 +612,25 @@ class FieldAddressInstruction extends FieldInstruction { final Instruction getObjectAddress() { result = getObjectAddressOperand().getDef() } } +/** + * An instruction that computes the address of the first element of a managed array. + * + * This instruction is used for element access to C# arrays. + */ +class ElementsAddressInstruction extends UnaryInstruction { + ElementsAddressInstruction() { getOpcode() instanceof Opcode::ElementsAddress } + + /** + * Gets the operand that provides the address of the array object. + */ + final UnaryOperand getArrayObjectAddressOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the address of the array object. + */ + final Instruction getArrayObjectAddress() { result = getArrayObjectAddressOperand().getDef() } +} + /** * An instruction that produces a well-defined but unknown result and has * unknown side effects, including side effects that are not conservatively @@ -1177,6 +1218,19 @@ class CheckedConvertOrThrowInstruction extends UnaryInstruction { CheckedConvertOrThrowInstruction() { getOpcode() instanceof Opcode::CheckedConvertOrThrow } } +/** + * An instruction that returns the address of the complete object that contains the subobject + * pointed to by its operand. + * + * If the operand holds a null address, the result is a null address. + * + * This instruction is used to represent `dyanmic_cast` in C++, which returns the pointer to + * the most-derived object. + */ +class CompleteObjectAddressInstruction extends UnaryInstruction { + CompleteObjectAddressInstruction() { getOpcode() instanceof Opcode::CompleteObjectAddress } +} + /** * An instruction that converts the address of an object to the address of a different subobject of * the same object, without any type checking at runtime. @@ -1453,7 +1507,7 @@ class CallInstruction extends Instruction { * Gets the `Function` that the call targets, if this is statically known. */ final Language::Function getStaticCallTarget() { - result = getCallTarget().(FunctionInstruction).getFunctionSymbol() + result = getCallTarget().(FunctionAddressInstruction).getFunctionSymbol() } /** @@ -1516,9 +1570,10 @@ class CallSideEffectInstruction extends SideEffectInstruction { /** * An instruction representing the side effect of a function call on any memory - * that might be read by that call. This instruction is emitted instead of - * `CallSideEffectInstruction` when it's certain that the call target cannot - * write to escaped memory. + * that might be read by that call. + * + * This instruction is emitted instead of `CallSideEffectInstruction` when it is certain that the + * call target cannot write to escaped memory. */ class CallReadSideEffectInstruction extends SideEffectInstruction { CallReadSideEffectInstruction() { getOpcode() instanceof Opcode::CallReadSideEffect } @@ -1612,6 +1667,7 @@ class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstructi /** * An instruction representing the potential write of an indirect parameter within a function call. + * * Unlike `IndirectWriteSideEffectInstruction`, the location might not be completely overwritten. * written. */ @@ -1623,6 +1679,7 @@ class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction { /** * An instruction representing the write of an indirect buffer parameter within a function call. + * * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { @@ -1631,6 +1688,7 @@ class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { /** * An instruction representing the write of an indirect buffer parameter within a function call. + * * Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten. */ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction { @@ -1642,7 +1700,7 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio } /** - * An instruction representing the initial value of newly allocated memory, e.g. the result of a + * An instruction representing the initial value of newly allocated memory, such as the result of a * call to `malloc`. */ class InitializeDynamicAllocationInstruction extends SideEffectInstruction { @@ -1860,17 +1918,20 @@ class ChiInstruction extends Instruction { } /** - * An instruction representing unreachable code. Inserted in place of the original target - * instruction of a `ConditionalBranch` or `Switch` instruction where that particular edge is - * infeasible. + * An instruction representing unreachable code. + * + * This instruction is inserted in place of the original target instruction of a `ConditionalBranch` + * or `Switch` instruction where that particular edge is infeasible. */ class UnreachedInstruction extends Instruction { UnreachedInstruction() { getOpcode() instanceof Opcode::Unreached } } /** - * An instruction representing a built-in operation. This is used to represent - * operations such as access to variable argument lists. + * An instruction representing a built-in operation. + * + * This is used to represent a variety of intrinsic operations provided by the compiler + * implementation, such as vector arithmetic. */ class BuiltInOperationInstruction extends Instruction { Language::BuiltInOperation operation; @@ -1892,3 +1953,59 @@ class BuiltInInstruction extends BuiltInOperationInstruction { final override string getImmediateString() { result = getBuiltInOperation().toString() } } + +/** + * An instruction that returns a `va_list` to access the arguments passed to the `...` parameter. + * + * The operand specifies the address of the `IREllipsisVariable` used to represent the `...` + * parameter. The result is a `va_list` that initially refers to the first argument that was passed + * to the `...` parameter. + */ +class VarArgsStartInstruction extends UnaryInstruction { + VarArgsStartInstruction() { getOpcode() instanceof Opcode::VarArgsStart } +} + +/** + * An instruction that cleans up a `va_list` after it is no longer in use. + * + * The operand specifies the address of the `va_list` to clean up. This instruction does not return + * a result. + */ +class VarArgsEndInstruction extends UnaryInstruction { + VarArgsEndInstruction() { getOpcode() instanceof Opcode::VarArgsEnd } +} + +/** + * An instruction that returns the address of the argument currently pointed to by a `va_list`. + * + * The operand is the `va_list` that points to the argument. The result is the address of the + * argument. + */ +class VarArgInstruction extends UnaryInstruction { + VarArgInstruction() { getOpcode() instanceof Opcode::VarArg } +} + +/** + * An instruction that modifies a `va_list` to point to the next argument that was passed to the + * `...` parameter. + * + * The operand is the current `va_list`. The result is an updated `va_list` that points to the next + * argument of the `...` parameter. + */ +class NextVarArgInstruction extends UnaryInstruction { + NextVarArgInstruction() { getOpcode() instanceof Opcode::NextVarArg } +} + +/** + * An instruction that allocates a new object on the managed heap. + * + * This instruction is used to represent the allocation of a new object in C# using the `new` + * expression. This instruction does not invoke a constructor for the object. Instead, there will be + * a subsequent `Call` instruction to invoke the appropriate constructor directory, passing the + * result of the `NewObj` as the `this` argument. + * + * The result is the address of the newly allocated object. + */ +class NewObjInstruction extends Instruction { + NewObjInstruction() { getOpcode() instanceof Opcode::NewObj } +} From 281985b845a063e1a59b1a6051f9ed934ac45f70 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Fri, 26 Jun 2020 11:42:32 -0400 Subject: [PATCH 03/20] C++: Sync `Opcode.qll` QLDoc with `Instruction.qll` QLDoc For every concrete `Opcode`, there is a corresponding `Instruction` class. Rather than duplicate all of the QLDoc by hand, I wrote a quick Python script to copy the QLDoc from `Instruction.qll` to `Opcode.qll`. I don't expect that we will need to do this often, so I'm not hooking it up to a PR check or anything like that, but I did commit the script itself in case we need it again. --- config/opcode-qldoc.py | 83 ++++++ .../code/cpp/ir/implementation/Opcode.qll | 273 ++++++++++++++++++ .../experimental/ir/implementation/Opcode.qll | 273 ++++++++++++++++++ 3 files changed, 629 insertions(+) create mode 100644 config/opcode-qldoc.py diff --git a/config/opcode-qldoc.py b/config/opcode-qldoc.py new file mode 100644 index 00000000000..c53563f11c5 --- /dev/null +++ b/config/opcode-qldoc.py @@ -0,0 +1,83 @@ +#!/usr/bin/env python3 + +import os +import re +path = os.path + +start_qldoc_re = re.compile(r'^\s*/\*\*') # Start of a QLDoc comment +end_qldoc_re = re.compile(r'\*/\s*$') # End of a QLDoc comment +blank_qldoc_line_re = re.compile(r'^\s*\*\s*$') # A line in a QLDoc comment with only the '*' +instruction_class_re = re.compile(r'^class (?P[A-aa-z0-9]+)Instruction\s') # Declaration of an `Instruction` class +opcode_class_re = re.compile(r'^\s*class (?P[A-aa-z0-9]+)\s') # Declaration of an `Opcode` class + +script_dir = path.realpath(path.dirname(__file__)) +instruction_path = path.realpath(path.join(script_dir, '../cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll')) +opcode_path = path.realpath(path.join(script_dir, '../cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll')) + +# Scan `Instruction.qll`, keeping track of the QLDoc comment attached to each declaration of a class +# whose name ends with `Instruction`. +instruction_comments = {} +in_qldoc = False +saw_blank_line_in_qldoc = False +qldoc_lines = [] +with open(instruction_path, 'r', encoding='utf-8') as instr: + for line in instr: + if in_qldoc: + if end_qldoc_re.search(line): + qldoc_lines.append(line) + in_qldoc = False + elif blank_qldoc_line_re.search(line): + # We're going to skip any lines after the first blank line, to avoid duplicating all + # of the verbose description. + saw_blank_line_in_qldoc = True + elif not saw_blank_line_in_qldoc: + qldoc_lines.append(line) + else: + if start_qldoc_re.search(line): + # Starting a new QLDoc comment. + saw_blank_line_in_qldoc = False + qldoc_lines.append(line) + if not end_qldoc_re.search(line): + in_qldoc = True + else: + instruction_match = instruction_class_re.search(line) + if instruction_match: + # Found the declaration of an `Instruction` class. Record the QLDoc comments. + instruction_comments[instruction_match.group('name')] = qldoc_lines + qldoc_lines = [] + +# Scan `Opcode.qll`. Whenever we see the declaration of an `Opcode` class for which we have a +# corresponding `Instruction` class, we'll attach a copy of the `Instruction`'s QLDoc comment. +in_qldoc = False +qldoc_lines = [] +output_lines = [] +with open(opcode_path, 'r', encoding='utf-8') as opcode: + for line in opcode: + if in_qldoc: + qldoc_lines.append(line) + if end_qldoc_re.search(line): + in_qldoc = False + else: + if start_qldoc_re.search(line): + qldoc_lines.append(line) + if not end_qldoc_re.search(line): + in_qldoc = True + else: + opcode_match = opcode_class_re.search(line) + if opcode_match: + # Found an `Opcode` that matches a known `Instruction`. Replace the QLDoc with + # a copy of the one from the `Instruction`. + name = opcode_match.group('name') + if instruction_comments.get(name): + # Indent by two additional spaces, since opcodes are declared in the + # `Opcode` module. + # Rename `instruction` to `operation`. + qldoc_lines = [(' ' + qldoc_line.replace(' An instruction ', ' An operation ')) + for qldoc_line in instruction_comments[name]] + output_lines.extend(qldoc_lines) + qldoc_lines = [] + output_lines.append(line) + +# Write out the updated `Opcode.qll` +with open(opcode_path, 'w', encoding='utf-8') as opcode: + opcode.writelines(output_lines) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll index 8b296346662..b903725e1e0 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll @@ -338,46 +338,84 @@ abstract class WriteSideEffectOpcode extends SideEffectOpcode { } * Provides `Opcode`s that specify the operation performed by an `Instruction`. */ module Opcode { + /** + * An operation that has no effect. + */ class NoOp extends Opcode, TNoOp { final override string toString() { result = "NoOp" } } + /** + * An operation that returns an uninitialized value. + */ class Uninitialized extends IndirectWriteOpcode, TUninitialized { final override string toString() { result = "Uninitialized" } } + /** + * An operation that produces a well-defined but unknown result and has + * unknown side effects, including side effects that are not conservatively + * modeled in the SSA graph. + */ class Error extends Opcode, TError { final override string toString() { result = "Error" } } + /** + * An operation that initializes a parameter of the enclosing function with the value of the + * corresponding argument passed by the caller. + */ class InitializeParameter extends IndirectWriteOpcode, TInitializeParameter { final override string toString() { result = "InitializeParameter" } } + /** + * An operation that initializes the memory pointed to by a parameter of the enclosing function + * with the value of that memory on entry to the function. + */ class InitializeIndirection extends EntireAllocationWriteOpcode, TInitializeIndirection { final override string toString() { result = "InitializeIndirection" } } + /** + * An operation that initializes the `this` pointer parameter of the enclosing function. + */ class InitializeThis extends Opcode, TInitializeThis { final override string toString() { result = "InitializeThis" } } + /** + * An operation representing the entry point to a function. + */ class EnterFunction extends Opcode, TEnterFunction { final override string toString() { result = "EnterFunction" } } + /** + * An operation representing the exit point of a function. + */ class ExitFunction extends Opcode, TExitFunction { final override string toString() { result = "ExitFunction" } } + /** + * An operation that returns control to the caller of the function, including a return value. + */ class ReturnValue extends ReturnOpcode, OpcodeWithLoad, TReturnValue { final override string toString() { result = "ReturnValue" } } + /** + * An operation that returns control to the caller of the function, without returning a value. + */ class ReturnVoid extends ReturnOpcode, TReturnVoid { final override string toString() { result = "ReturnVoid" } } + /** + * An operation that represents the use of the value pointed to by a parameter of the function + * after the function returns control to its caller. + */ class ReturnIndirection extends EntireAllocationReadOpcode, TReturnIndirection { final override string toString() { result = "ReturnIndirection" } @@ -386,14 +424,23 @@ module Opcode { } } + /** + * An operation that returns a register result containing a copy of its register operand. + */ class CopyValue extends UnaryOpcode, CopyOpcode, TCopyValue { final override string toString() { result = "CopyValue" } } + /** + * An operation that returns a register result containing a copy of its memory operand. + */ class Load extends CopyOpcode, OpcodeWithLoad, TLoad { final override string toString() { result = "Load" } } + /** + * An operation that returns a memory result containing a copy of its register operand. + */ class Store extends CopyOpcode, IndirectWriteOpcode, TStore { final override string toString() { result = "Store" } @@ -402,154 +449,282 @@ module Opcode { } } + /** + * An operation that computes the sum of two numeric operands. + */ class Add extends BinaryArithmeticOpcode, TAdd { final override string toString() { result = "Add" } } + /** + * An operation that computes the difference of two numeric operands. + */ class Sub extends BinaryArithmeticOpcode, TSub { final override string toString() { result = "Sub" } } + /** + * An operation that computes the product of two numeric operands. + */ class Mul extends BinaryArithmeticOpcode, TMul { final override string toString() { result = "Mul" } } + /** + * An operation that computes the quotient of two numeric operands. + */ class Div extends BinaryArithmeticOpcode, TDiv { final override string toString() { result = "Div" } } + /** + * An operation that computes the remainder of two integer operands. + */ class Rem extends BinaryArithmeticOpcode, TRem { final override string toString() { result = "Rem" } } + /** + * An operation that negates a single numeric operand. + */ class Negate extends UnaryArithmeticOpcode, TNegate { final override string toString() { result = "Negate" } } + /** + * An operation that shifts its left operand to the left by the number of bits specified by its + * right operand. + */ class ShiftLeft extends BinaryBitwiseOpcode, TShiftLeft { final override string toString() { result = "ShiftLeft" } } + /** + * An operation that shifts its left operand to the right by the number of bits specified by its + * right operand. + */ class ShiftRight extends BinaryBitwiseOpcode, TShiftRight { final override string toString() { result = "ShiftRight" } } + /** + * An operation that computes the bitwise "and" of two integer operands. + */ class BitAnd extends BinaryBitwiseOpcode, TBitAnd { final override string toString() { result = "BitAnd" } } + /** + * An operation that computes the bitwise "or" of two integer operands. + */ class BitOr extends BinaryBitwiseOpcode, TBitOr { final override string toString() { result = "BitOr" } } + /** + * An operation that computes the bitwise "xor" of two integer operands. + */ class BitXor extends BinaryBitwiseOpcode, TBitXor { final override string toString() { result = "BitXor" } } + /** + * An operation that computes the bitwise complement of its operand. + */ class BitComplement extends UnaryBitwiseOpcode, TBitComplement { final override string toString() { result = "BitComplement" } } + /** + * An operation that computes the logical complement of its operand. + */ class LogicalNot extends UnaryOpcode, TLogicalNot { final override string toString() { result = "LogicalNot" } } + /** + * An operation that returns a `true` result if its operands are equal. + */ class CompareEQ extends CompareOpcode, TCompareEQ { final override string toString() { result = "CompareEQ" } } + /** + * An operation that returns a `true` result if its operands are not equal. + */ class CompareNE extends CompareOpcode, TCompareNE { final override string toString() { result = "CompareNE" } } + /** + * An operation that returns a `true` result if its left operand is less than its right operand. + */ class CompareLT extends RelationalOpcode, TCompareLT { final override string toString() { result = "CompareLT" } } + /** + * An operation that returns a `true` result if its left operand is greater than its right operand. + */ class CompareGT extends RelationalOpcode, TCompareGT { final override string toString() { result = "CompareGT" } } + /** + * An operation that returns a `true` result if its left operand is less than or equal to its + * right operand. + */ class CompareLE extends RelationalOpcode, TCompareLE { final override string toString() { result = "CompareLE" } } + /** + * An operation that returns a `true` result if its left operand is greater than or equal to its + * right operand. + */ class CompareGE extends RelationalOpcode, TCompareGE { final override string toString() { result = "CompareGE" } } + /** + * An operation that adds an integer offset to a pointer. + */ class PointerAdd extends PointerOffsetOpcode, TPointerAdd { final override string toString() { result = "PointerAdd" } } + /** + * An operation that subtracts an integer offset from a pointer. + */ class PointerSub extends PointerOffsetOpcode, TPointerSub { final override string toString() { result = "PointerSub" } } + /** + * An operation that computes the difference between two pointers. + */ class PointerDiff extends PointerArithmeticOpcode, TPointerDiff { final override string toString() { result = "PointerDiff" } } + /** + * An operation that converts the value of its operand to a value of a different type. + */ class Convert extends UnaryOpcode, TConvert { final override string toString() { result = "Convert" } } + /** + * An operation that converts from the address of a derived class to the address of a direct + * non-virtual base class. + */ class ConvertToNonVirtualBase extends ConvertToBaseOpcode, TConvertToNonVirtualBase { final override string toString() { result = "ConvertToNonVirtualBase" } } + /** + * An operation that converts from the address of a derived class to the address of a virtual base + * class. + */ class ConvertToVirtualBase extends ConvertToBaseOpcode, TConvertToVirtualBase { final override string toString() { result = "ConvertToVirtualBase" } } + /** + * An operation that converts from the address of a base class to the address of a direct + * non-virtual derived class. + */ class ConvertToDerived extends UnaryOpcode, TConvertToDerived { final override string toString() { result = "ConvertToDerived" } } + /** + * An operation that converts the address of a polymorphic object to the address of a different + * subobject of the same polymorphic object, returning a null address if the dynamic type of the + * object is not compatible with the result type. + */ class CheckedConvertOrNull extends UnaryOpcode, TCheckedConvertOrNull { final override string toString() { result = "CheckedConvertOrNull" } } + /** + * An operation that converts the address of a polymorphic object to the address of a different + * subobject of the same polymorphic object, throwing an exception if the dynamic type of the object + * is not compatible with the result type. + */ class CheckedConvertOrThrow extends UnaryOpcode, TCheckedConvertOrThrow { final override string toString() { result = "CheckedConvertOrThrow" } } + /** + * An operation that returns the address of the complete object that contains the subobject + * pointed to by its operand. + */ class CompleteObjectAddress extends UnaryOpcode, TCompleteObjectAddress { final override string toString() { result = "CompleteObjectAddress" } } + /** + * An operation that returns the address of a variable. + */ class VariableAddress extends Opcode, TVariableAddress { final override string toString() { result = "VariableAddress" } } + /** + * An operation that computes the address of a non-static field of an object. + */ class FieldAddress extends UnaryOpcode, TFieldAddress { final override string toString() { result = "FieldAddress" } } + /** + * An operation that computes the address of the first element of a managed array. + */ class ElementsAddress extends UnaryOpcode, TElementsAddress { final override string toString() { result = "ElementsAddress" } } + /** + * An operation that returns the address of a function. + */ class FunctionAddress extends Opcode, TFunctionAddress { final override string toString() { result = "FunctionAddress" } } + /** + * An operation whose result is a constant value. + */ class Constant extends Opcode, TConstant { final override string toString() { result = "Constant" } } + /** + * An operation whose result is the address of a string literal. + */ class StringConstant extends Opcode, TStringConstant { final override string toString() { result = "StringConstant" } } + /** + * An operation that branches to one of two successor instructions based on the value of a Boolean + * operand. + */ class ConditionalBranch extends OpcodeWithCondition, TConditionalBranch { final override string toString() { result = "ConditionalBranch" } } + /** + * An operation that branches to one of multiple successor instructions based on the value of an + * integer operand. + */ class Switch extends OpcodeWithCondition, TSwitch { final override string toString() { result = "Switch" } } + /** + * An operation that calls a function. + */ class Call extends Opcode, TCall { final override string toString() { result = "Call" } @@ -558,32 +733,53 @@ module Opcode { } } + /** + * An operation that catches an exception of a specific type. + */ class CatchByType extends CatchOpcode, TCatchByType { final override string toString() { result = "CatchByType" } } + /** + * An operation that catches any exception. + */ class CatchAny extends CatchOpcode, TCatchAny { final override string toString() { result = "CatchAny" } } + /** + * An operation that throws a new exception. + */ class ThrowValue extends ThrowOpcode, OpcodeWithLoad, TThrowValue { final override string toString() { result = "ThrowValue" } } + /** + * An operation that re-throws the current exception. + */ class ReThrow extends ThrowOpcode, TReThrow { final override string toString() { result = "ReThrow" } } + /** + * An operation that exits the current function by propagating an exception. + */ class Unwind extends Opcode, TUnwind { final override string toString() { result = "Unwind" } } + /** + * An operation that initializes all escaped memory. + */ class AliasedDefinition extends Opcode, TAliasedDefinition { final override string toString() { result = "AliasedDefinition" } final override MemoryAccessKind getWriteMemoryAccess() { result instanceof EscapedMemoryAccess } } + /** + * An operation that initializes all memory that existed before this function was called. + */ class InitializeNonLocal extends Opcode, TInitializeNonLocal { final override string toString() { result = "InitializeNonLocal" } @@ -592,6 +788,9 @@ module Opcode { } } + /** + * An operation that consumes all escaped memory on exit from the function. + */ class AliasedUse extends Opcode, TAliasedUse { final override string toString() { result = "AliasedUse" } @@ -602,92 +801,157 @@ module Opcode { } } + /** + * An operation representing the choice of one of multiple input values based on control flow. + */ class Phi extends Opcode, TPhi { final override string toString() { result = "Phi" } final override MemoryAccessKind getWriteMemoryAccess() { result instanceof PhiMemoryAccess } } + /** + * An operation representing a built-in operation that does not have a specific opcode. The + * actual operation is specified by the `getBuiltInOperation()` predicate. + */ class BuiltIn extends BuiltInOperationOpcode, TBuiltIn { final override string toString() { result = "BuiltIn" } } + /** + * An operation that returns a `va_list` to access the arguments passed to the `...` parameter. + */ class VarArgsStart extends UnaryOpcode, TVarArgsStart { final override string toString() { result = "VarArgsStart" } } + /** + * An operation that cleans up a `va_list` after it is no longer in use. + */ class VarArgsEnd extends UnaryOpcode, TVarArgsEnd { final override string toString() { result = "VarArgsEnd" } } + /** + * An operation that returns the address of the argument currently pointed to by a `va_list`. + */ class VarArg extends UnaryOpcode, TVarArg { final override string toString() { result = "VarArg" } } + /** + * An operation that modifies a `va_list` to point to the next argument that was passed to the + * `...` parameter. + */ class NextVarArg extends UnaryOpcode, TNextVarArg { final override string toString() { result = "NextVarArg" } } + /** + * An operation representing the side effect of a function call on any memory that might be + * accessed by that call. + */ class CallSideEffect extends WriteSideEffectOpcode, EscapedWriteOpcode, MayWriteOpcode, ReadSideEffectOpcode, EscapedReadOpcode, MayReadOpcode, TCallSideEffect { final override string toString() { result = "CallSideEffect" } } + /** + * An operation representing the side effect of a function call on any memory + * that might be read by that call. + */ class CallReadSideEffect extends ReadSideEffectOpcode, EscapedReadOpcode, MayReadOpcode, TCallReadSideEffect { final override string toString() { result = "CallReadSideEffect" } } + /** + * An operation representing the read of an indirect parameter within a function call. + */ class IndirectReadSideEffect extends ReadSideEffectOpcode, IndirectReadOpcode, TIndirectReadSideEffect { final override string toString() { result = "IndirectReadSideEffect" } } + /** + * An operation representing the write of an indirect parameter within a function call. + */ class IndirectMustWriteSideEffect extends WriteSideEffectOpcode, IndirectWriteOpcode, TIndirectMustWriteSideEffect { final override string toString() { result = "IndirectMustWriteSideEffect" } } + /** + * An operation representing the potential write of an indirect parameter within a function call. + */ class IndirectMayWriteSideEffect extends WriteSideEffectOpcode, IndirectWriteOpcode, MayWriteOpcode, TIndirectMayWriteSideEffect { final override string toString() { result = "IndirectMayWriteSideEffect" } } + /** + * An operation representing the read of an indirect buffer parameter within a function call. + */ class BufferReadSideEffect extends ReadSideEffectOpcode, UnsizedBufferReadOpcode, TBufferReadSideEffect { final override string toString() { result = "BufferReadSideEffect" } } + /** + * An operation representing the write of an indirect buffer parameter within a function call. The + * entire buffer is overwritten. + */ class BufferMustWriteSideEffect extends WriteSideEffectOpcode, UnsizedBufferWriteOpcode, TBufferMustWriteSideEffect { final override string toString() { result = "BufferMustWriteSideEffect" } } + /** + * An operation representing the write of an indirect buffer parameter within a function call. + */ class BufferMayWriteSideEffect extends WriteSideEffectOpcode, UnsizedBufferWriteOpcode, MayWriteOpcode, TBufferMayWriteSideEffect { final override string toString() { result = "BufferMayWriteSideEffect" } } + /** + * An operation representing the read of an indirect buffer parameter within a function call. + */ class SizedBufferReadSideEffect extends ReadSideEffectOpcode, SizedBufferReadOpcode, TSizedBufferReadSideEffect { final override string toString() { result = "SizedBufferReadSideEffect" } } + /** + * An operation representing the write of an indirect buffer parameter within a function call. The + * entire buffer is overwritten. + */ class SizedBufferMustWriteSideEffect extends WriteSideEffectOpcode, SizedBufferWriteOpcode, TSizedBufferMustWriteSideEffect { final override string toString() { result = "SizedBufferMustWriteSideEffect" } } + /** + * An operation representing the write of an indirect buffer parameter within a function call. + */ class SizedBufferMayWriteSideEffect extends WriteSideEffectOpcode, SizedBufferWriteOpcode, MayWriteOpcode, TSizedBufferMayWriteSideEffect { final override string toString() { result = "SizedBufferMayWriteSideEffect" } } + /** + * An operation representing the initial value of newly allocated memory, such as the result of a + * call to `malloc`. + */ class InitializeDynamicAllocation extends SideEffectOpcode, EntireAllocationWriteOpcode, TInitializeDynamicAllocation { final override string toString() { result = "InitializeDynamicAllocation" } } + /** + * An operation representing the effect that a write to a memory may have on potential aliases of + * that memory. + */ class Chi extends Opcode, TChi { final override string toString() { result = "Chi" } @@ -702,6 +966,9 @@ module Opcode { } } + /** + * An operation representing a GNU or MSVC inline assembly statement. + */ class InlineAsm extends Opcode, EscapedWriteOpcode, MayWriteOpcode, EscapedReadOpcode, MayReadOpcode, TInlineAsm { final override string toString() { result = "InlineAsm" } @@ -711,10 +978,16 @@ module Opcode { } } + /** + * An operation representing unreachable code. + */ class Unreached extends Opcode, TUnreached { final override string toString() { result = "Unreached" } } + /** + * An operation that allocates a new object on the managed heap. + */ class NewObj extends Opcode, TNewObj { final override string toString() { result = "NewObj" } } diff --git a/csharp/ql/src/experimental/ir/implementation/Opcode.qll b/csharp/ql/src/experimental/ir/implementation/Opcode.qll index 8b296346662..b903725e1e0 100644 --- a/csharp/ql/src/experimental/ir/implementation/Opcode.qll +++ b/csharp/ql/src/experimental/ir/implementation/Opcode.qll @@ -338,46 +338,84 @@ abstract class WriteSideEffectOpcode extends SideEffectOpcode { } * Provides `Opcode`s that specify the operation performed by an `Instruction`. */ module Opcode { + /** + * An operation that has no effect. + */ class NoOp extends Opcode, TNoOp { final override string toString() { result = "NoOp" } } + /** + * An operation that returns an uninitialized value. + */ class Uninitialized extends IndirectWriteOpcode, TUninitialized { final override string toString() { result = "Uninitialized" } } + /** + * An operation that produces a well-defined but unknown result and has + * unknown side effects, including side effects that are not conservatively + * modeled in the SSA graph. + */ class Error extends Opcode, TError { final override string toString() { result = "Error" } } + /** + * An operation that initializes a parameter of the enclosing function with the value of the + * corresponding argument passed by the caller. + */ class InitializeParameter extends IndirectWriteOpcode, TInitializeParameter { final override string toString() { result = "InitializeParameter" } } + /** + * An operation that initializes the memory pointed to by a parameter of the enclosing function + * with the value of that memory on entry to the function. + */ class InitializeIndirection extends EntireAllocationWriteOpcode, TInitializeIndirection { final override string toString() { result = "InitializeIndirection" } } + /** + * An operation that initializes the `this` pointer parameter of the enclosing function. + */ class InitializeThis extends Opcode, TInitializeThis { final override string toString() { result = "InitializeThis" } } + /** + * An operation representing the entry point to a function. + */ class EnterFunction extends Opcode, TEnterFunction { final override string toString() { result = "EnterFunction" } } + /** + * An operation representing the exit point of a function. + */ class ExitFunction extends Opcode, TExitFunction { final override string toString() { result = "ExitFunction" } } + /** + * An operation that returns control to the caller of the function, including a return value. + */ class ReturnValue extends ReturnOpcode, OpcodeWithLoad, TReturnValue { final override string toString() { result = "ReturnValue" } } + /** + * An operation that returns control to the caller of the function, without returning a value. + */ class ReturnVoid extends ReturnOpcode, TReturnVoid { final override string toString() { result = "ReturnVoid" } } + /** + * An operation that represents the use of the value pointed to by a parameter of the function + * after the function returns control to its caller. + */ class ReturnIndirection extends EntireAllocationReadOpcode, TReturnIndirection { final override string toString() { result = "ReturnIndirection" } @@ -386,14 +424,23 @@ module Opcode { } } + /** + * An operation that returns a register result containing a copy of its register operand. + */ class CopyValue extends UnaryOpcode, CopyOpcode, TCopyValue { final override string toString() { result = "CopyValue" } } + /** + * An operation that returns a register result containing a copy of its memory operand. + */ class Load extends CopyOpcode, OpcodeWithLoad, TLoad { final override string toString() { result = "Load" } } + /** + * An operation that returns a memory result containing a copy of its register operand. + */ class Store extends CopyOpcode, IndirectWriteOpcode, TStore { final override string toString() { result = "Store" } @@ -402,154 +449,282 @@ module Opcode { } } + /** + * An operation that computes the sum of two numeric operands. + */ class Add extends BinaryArithmeticOpcode, TAdd { final override string toString() { result = "Add" } } + /** + * An operation that computes the difference of two numeric operands. + */ class Sub extends BinaryArithmeticOpcode, TSub { final override string toString() { result = "Sub" } } + /** + * An operation that computes the product of two numeric operands. + */ class Mul extends BinaryArithmeticOpcode, TMul { final override string toString() { result = "Mul" } } + /** + * An operation that computes the quotient of two numeric operands. + */ class Div extends BinaryArithmeticOpcode, TDiv { final override string toString() { result = "Div" } } + /** + * An operation that computes the remainder of two integer operands. + */ class Rem extends BinaryArithmeticOpcode, TRem { final override string toString() { result = "Rem" } } + /** + * An operation that negates a single numeric operand. + */ class Negate extends UnaryArithmeticOpcode, TNegate { final override string toString() { result = "Negate" } } + /** + * An operation that shifts its left operand to the left by the number of bits specified by its + * right operand. + */ class ShiftLeft extends BinaryBitwiseOpcode, TShiftLeft { final override string toString() { result = "ShiftLeft" } } + /** + * An operation that shifts its left operand to the right by the number of bits specified by its + * right operand. + */ class ShiftRight extends BinaryBitwiseOpcode, TShiftRight { final override string toString() { result = "ShiftRight" } } + /** + * An operation that computes the bitwise "and" of two integer operands. + */ class BitAnd extends BinaryBitwiseOpcode, TBitAnd { final override string toString() { result = "BitAnd" } } + /** + * An operation that computes the bitwise "or" of two integer operands. + */ class BitOr extends BinaryBitwiseOpcode, TBitOr { final override string toString() { result = "BitOr" } } + /** + * An operation that computes the bitwise "xor" of two integer operands. + */ class BitXor extends BinaryBitwiseOpcode, TBitXor { final override string toString() { result = "BitXor" } } + /** + * An operation that computes the bitwise complement of its operand. + */ class BitComplement extends UnaryBitwiseOpcode, TBitComplement { final override string toString() { result = "BitComplement" } } + /** + * An operation that computes the logical complement of its operand. + */ class LogicalNot extends UnaryOpcode, TLogicalNot { final override string toString() { result = "LogicalNot" } } + /** + * An operation that returns a `true` result if its operands are equal. + */ class CompareEQ extends CompareOpcode, TCompareEQ { final override string toString() { result = "CompareEQ" } } + /** + * An operation that returns a `true` result if its operands are not equal. + */ class CompareNE extends CompareOpcode, TCompareNE { final override string toString() { result = "CompareNE" } } + /** + * An operation that returns a `true` result if its left operand is less than its right operand. + */ class CompareLT extends RelationalOpcode, TCompareLT { final override string toString() { result = "CompareLT" } } + /** + * An operation that returns a `true` result if its left operand is greater than its right operand. + */ class CompareGT extends RelationalOpcode, TCompareGT { final override string toString() { result = "CompareGT" } } + /** + * An operation that returns a `true` result if its left operand is less than or equal to its + * right operand. + */ class CompareLE extends RelationalOpcode, TCompareLE { final override string toString() { result = "CompareLE" } } + /** + * An operation that returns a `true` result if its left operand is greater than or equal to its + * right operand. + */ class CompareGE extends RelationalOpcode, TCompareGE { final override string toString() { result = "CompareGE" } } + /** + * An operation that adds an integer offset to a pointer. + */ class PointerAdd extends PointerOffsetOpcode, TPointerAdd { final override string toString() { result = "PointerAdd" } } + /** + * An operation that subtracts an integer offset from a pointer. + */ class PointerSub extends PointerOffsetOpcode, TPointerSub { final override string toString() { result = "PointerSub" } } + /** + * An operation that computes the difference between two pointers. + */ class PointerDiff extends PointerArithmeticOpcode, TPointerDiff { final override string toString() { result = "PointerDiff" } } + /** + * An operation that converts the value of its operand to a value of a different type. + */ class Convert extends UnaryOpcode, TConvert { final override string toString() { result = "Convert" } } + /** + * An operation that converts from the address of a derived class to the address of a direct + * non-virtual base class. + */ class ConvertToNonVirtualBase extends ConvertToBaseOpcode, TConvertToNonVirtualBase { final override string toString() { result = "ConvertToNonVirtualBase" } } + /** + * An operation that converts from the address of a derived class to the address of a virtual base + * class. + */ class ConvertToVirtualBase extends ConvertToBaseOpcode, TConvertToVirtualBase { final override string toString() { result = "ConvertToVirtualBase" } } + /** + * An operation that converts from the address of a base class to the address of a direct + * non-virtual derived class. + */ class ConvertToDerived extends UnaryOpcode, TConvertToDerived { final override string toString() { result = "ConvertToDerived" } } + /** + * An operation that converts the address of a polymorphic object to the address of a different + * subobject of the same polymorphic object, returning a null address if the dynamic type of the + * object is not compatible with the result type. + */ class CheckedConvertOrNull extends UnaryOpcode, TCheckedConvertOrNull { final override string toString() { result = "CheckedConvertOrNull" } } + /** + * An operation that converts the address of a polymorphic object to the address of a different + * subobject of the same polymorphic object, throwing an exception if the dynamic type of the object + * is not compatible with the result type. + */ class CheckedConvertOrThrow extends UnaryOpcode, TCheckedConvertOrThrow { final override string toString() { result = "CheckedConvertOrThrow" } } + /** + * An operation that returns the address of the complete object that contains the subobject + * pointed to by its operand. + */ class CompleteObjectAddress extends UnaryOpcode, TCompleteObjectAddress { final override string toString() { result = "CompleteObjectAddress" } } + /** + * An operation that returns the address of a variable. + */ class VariableAddress extends Opcode, TVariableAddress { final override string toString() { result = "VariableAddress" } } + /** + * An operation that computes the address of a non-static field of an object. + */ class FieldAddress extends UnaryOpcode, TFieldAddress { final override string toString() { result = "FieldAddress" } } + /** + * An operation that computes the address of the first element of a managed array. + */ class ElementsAddress extends UnaryOpcode, TElementsAddress { final override string toString() { result = "ElementsAddress" } } + /** + * An operation that returns the address of a function. + */ class FunctionAddress extends Opcode, TFunctionAddress { final override string toString() { result = "FunctionAddress" } } + /** + * An operation whose result is a constant value. + */ class Constant extends Opcode, TConstant { final override string toString() { result = "Constant" } } + /** + * An operation whose result is the address of a string literal. + */ class StringConstant extends Opcode, TStringConstant { final override string toString() { result = "StringConstant" } } + /** + * An operation that branches to one of two successor instructions based on the value of a Boolean + * operand. + */ class ConditionalBranch extends OpcodeWithCondition, TConditionalBranch { final override string toString() { result = "ConditionalBranch" } } + /** + * An operation that branches to one of multiple successor instructions based on the value of an + * integer operand. + */ class Switch extends OpcodeWithCondition, TSwitch { final override string toString() { result = "Switch" } } + /** + * An operation that calls a function. + */ class Call extends Opcode, TCall { final override string toString() { result = "Call" } @@ -558,32 +733,53 @@ module Opcode { } } + /** + * An operation that catches an exception of a specific type. + */ class CatchByType extends CatchOpcode, TCatchByType { final override string toString() { result = "CatchByType" } } + /** + * An operation that catches any exception. + */ class CatchAny extends CatchOpcode, TCatchAny { final override string toString() { result = "CatchAny" } } + /** + * An operation that throws a new exception. + */ class ThrowValue extends ThrowOpcode, OpcodeWithLoad, TThrowValue { final override string toString() { result = "ThrowValue" } } + /** + * An operation that re-throws the current exception. + */ class ReThrow extends ThrowOpcode, TReThrow { final override string toString() { result = "ReThrow" } } + /** + * An operation that exits the current function by propagating an exception. + */ class Unwind extends Opcode, TUnwind { final override string toString() { result = "Unwind" } } + /** + * An operation that initializes all escaped memory. + */ class AliasedDefinition extends Opcode, TAliasedDefinition { final override string toString() { result = "AliasedDefinition" } final override MemoryAccessKind getWriteMemoryAccess() { result instanceof EscapedMemoryAccess } } + /** + * An operation that initializes all memory that existed before this function was called. + */ class InitializeNonLocal extends Opcode, TInitializeNonLocal { final override string toString() { result = "InitializeNonLocal" } @@ -592,6 +788,9 @@ module Opcode { } } + /** + * An operation that consumes all escaped memory on exit from the function. + */ class AliasedUse extends Opcode, TAliasedUse { final override string toString() { result = "AliasedUse" } @@ -602,92 +801,157 @@ module Opcode { } } + /** + * An operation representing the choice of one of multiple input values based on control flow. + */ class Phi extends Opcode, TPhi { final override string toString() { result = "Phi" } final override MemoryAccessKind getWriteMemoryAccess() { result instanceof PhiMemoryAccess } } + /** + * An operation representing a built-in operation that does not have a specific opcode. The + * actual operation is specified by the `getBuiltInOperation()` predicate. + */ class BuiltIn extends BuiltInOperationOpcode, TBuiltIn { final override string toString() { result = "BuiltIn" } } + /** + * An operation that returns a `va_list` to access the arguments passed to the `...` parameter. + */ class VarArgsStart extends UnaryOpcode, TVarArgsStart { final override string toString() { result = "VarArgsStart" } } + /** + * An operation that cleans up a `va_list` after it is no longer in use. + */ class VarArgsEnd extends UnaryOpcode, TVarArgsEnd { final override string toString() { result = "VarArgsEnd" } } + /** + * An operation that returns the address of the argument currently pointed to by a `va_list`. + */ class VarArg extends UnaryOpcode, TVarArg { final override string toString() { result = "VarArg" } } + /** + * An operation that modifies a `va_list` to point to the next argument that was passed to the + * `...` parameter. + */ class NextVarArg extends UnaryOpcode, TNextVarArg { final override string toString() { result = "NextVarArg" } } + /** + * An operation representing the side effect of a function call on any memory that might be + * accessed by that call. + */ class CallSideEffect extends WriteSideEffectOpcode, EscapedWriteOpcode, MayWriteOpcode, ReadSideEffectOpcode, EscapedReadOpcode, MayReadOpcode, TCallSideEffect { final override string toString() { result = "CallSideEffect" } } + /** + * An operation representing the side effect of a function call on any memory + * that might be read by that call. + */ class CallReadSideEffect extends ReadSideEffectOpcode, EscapedReadOpcode, MayReadOpcode, TCallReadSideEffect { final override string toString() { result = "CallReadSideEffect" } } + /** + * An operation representing the read of an indirect parameter within a function call. + */ class IndirectReadSideEffect extends ReadSideEffectOpcode, IndirectReadOpcode, TIndirectReadSideEffect { final override string toString() { result = "IndirectReadSideEffect" } } + /** + * An operation representing the write of an indirect parameter within a function call. + */ class IndirectMustWriteSideEffect extends WriteSideEffectOpcode, IndirectWriteOpcode, TIndirectMustWriteSideEffect { final override string toString() { result = "IndirectMustWriteSideEffect" } } + /** + * An operation representing the potential write of an indirect parameter within a function call. + */ class IndirectMayWriteSideEffect extends WriteSideEffectOpcode, IndirectWriteOpcode, MayWriteOpcode, TIndirectMayWriteSideEffect { final override string toString() { result = "IndirectMayWriteSideEffect" } } + /** + * An operation representing the read of an indirect buffer parameter within a function call. + */ class BufferReadSideEffect extends ReadSideEffectOpcode, UnsizedBufferReadOpcode, TBufferReadSideEffect { final override string toString() { result = "BufferReadSideEffect" } } + /** + * An operation representing the write of an indirect buffer parameter within a function call. The + * entire buffer is overwritten. + */ class BufferMustWriteSideEffect extends WriteSideEffectOpcode, UnsizedBufferWriteOpcode, TBufferMustWriteSideEffect { final override string toString() { result = "BufferMustWriteSideEffect" } } + /** + * An operation representing the write of an indirect buffer parameter within a function call. + */ class BufferMayWriteSideEffect extends WriteSideEffectOpcode, UnsizedBufferWriteOpcode, MayWriteOpcode, TBufferMayWriteSideEffect { final override string toString() { result = "BufferMayWriteSideEffect" } } + /** + * An operation representing the read of an indirect buffer parameter within a function call. + */ class SizedBufferReadSideEffect extends ReadSideEffectOpcode, SizedBufferReadOpcode, TSizedBufferReadSideEffect { final override string toString() { result = "SizedBufferReadSideEffect" } } + /** + * An operation representing the write of an indirect buffer parameter within a function call. The + * entire buffer is overwritten. + */ class SizedBufferMustWriteSideEffect extends WriteSideEffectOpcode, SizedBufferWriteOpcode, TSizedBufferMustWriteSideEffect { final override string toString() { result = "SizedBufferMustWriteSideEffect" } } + /** + * An operation representing the write of an indirect buffer parameter within a function call. + */ class SizedBufferMayWriteSideEffect extends WriteSideEffectOpcode, SizedBufferWriteOpcode, MayWriteOpcode, TSizedBufferMayWriteSideEffect { final override string toString() { result = "SizedBufferMayWriteSideEffect" } } + /** + * An operation representing the initial value of newly allocated memory, such as the result of a + * call to `malloc`. + */ class InitializeDynamicAllocation extends SideEffectOpcode, EntireAllocationWriteOpcode, TInitializeDynamicAllocation { final override string toString() { result = "InitializeDynamicAllocation" } } + /** + * An operation representing the effect that a write to a memory may have on potential aliases of + * that memory. + */ class Chi extends Opcode, TChi { final override string toString() { result = "Chi" } @@ -702,6 +966,9 @@ module Opcode { } } + /** + * An operation representing a GNU or MSVC inline assembly statement. + */ class InlineAsm extends Opcode, EscapedWriteOpcode, MayWriteOpcode, EscapedReadOpcode, MayReadOpcode, TInlineAsm { final override string toString() { result = "InlineAsm" } @@ -711,10 +978,16 @@ module Opcode { } } + /** + * An operation representing unreachable code. + */ class Unreached extends Opcode, TUnreached { final override string toString() { result = "Unreached" } } + /** + * An operation that allocates a new object on the managed heap. + */ class NewObj extends Opcode, TNewObj { final override string toString() { result = "NewObj" } } From 5f290520ab2e0c347e5a603b386f8da2c7b2e71b Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Fri, 26 Jun 2020 13:45:41 -0400 Subject: [PATCH 04/20] C++: Accept test diffs due to opcode rename --- cpp/ql/test/library-tests/ir/ir/raw_ir.expected | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected index 999df2c5202..a2be838ae48 100644 --- a/cpp/ql/test/library-tests/ir/ir/raw_ir.expected +++ b/cpp/ql/test/library-tests/ir/ir/raw_ir.expected @@ -4867,12 +4867,12 @@ ir.cpp: # 863| r863_1(glval) = VariableAddress[pv] : # 863| r863_2(glval) = VariableAddress[pb] : # 863| r863_3(PolymorphicBase *) = Load : &:r863_2, ~m? -# 863| r863_4(void *) = DynamicCastToVoid : r863_3 +# 863| r863_4(void *) = CompleteObjectAddress : r863_3 # 863| mu863_5(void *) = Store : &:r863_1, r863_4 # 864| r864_1(glval) = VariableAddress[pcv] : # 864| r864_2(glval) = VariableAddress[pd] : # 864| r864_3(PolymorphicDerived *) = Load : &:r864_2, ~m? -# 864| r864_4(void *) = DynamicCastToVoid : r864_3 +# 864| r864_4(void *) = CompleteObjectAddress : r864_3 # 864| mu864_5(void *) = Store : &:r864_1, r864_4 # 865| v865_1(void) = NoOp : # 849| v849_4(void) = ReturnVoid : From bdf121f3b846d2c8157e6a9ac861aa8a6c766fa5 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Fri, 26 Jun 2020 16:04:33 -0400 Subject: [PATCH 05/20] C++: Update opcode QLDoc script to handle abstract base classes This auto-generates even more QLDoc for `Opcode.qll` --- config/opcode-qldoc.py | 31 ++++++--- .../code/cpp/ir/implementation/Opcode.qll | 65 ++++++++++++++++++- .../experimental/ir/implementation/Opcode.qll | 65 ++++++++++++++++++- 3 files changed, 148 insertions(+), 13 deletions(-) diff --git a/config/opcode-qldoc.py b/config/opcode-qldoc.py index c53563f11c5..f44632bc4ee 100644 --- a/config/opcode-qldoc.py +++ b/config/opcode-qldoc.py @@ -8,7 +8,8 @@ start_qldoc_re = re.compile(r'^\s*/\*\*') # Start of a QLDoc comment end_qldoc_re = re.compile(r'\*/\s*$') # End of a QLDoc comment blank_qldoc_line_re = re.compile(r'^\s*\*\s*$') # A line in a QLDoc comment with only the '*' instruction_class_re = re.compile(r'^class (?P[A-aa-z0-9]+)Instruction\s') # Declaration of an `Instruction` class -opcode_class_re = re.compile(r'^\s*class (?P[A-aa-z0-9]+)\s') # Declaration of an `Opcode` class +opcode_base_class_re = re.compile(r'^abstract class (?P[A-aa-z0-9]+)Opcode\s') # Declaration of an `Opcode` base class +opcode_class_re = re.compile(r'^ class (?P[A-aa-z0-9]+)\s') # Declaration of an `Opcode` class script_dir = path.realpath(path.dirname(__file__)) instruction_path = path.realpath(path.join(script_dir, '../cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Instruction.qll')) @@ -63,17 +64,29 @@ with open(opcode_path, 'r', encoding='utf-8') as opcode: if not end_qldoc_re.search(line): in_qldoc = True else: - opcode_match = opcode_class_re.search(line) - if opcode_match: - # Found an `Opcode` that matches a known `Instruction`. Replace the QLDoc with - # a copy of the one from the `Instruction`. - name = opcode_match.group('name') - if instruction_comments.get(name): + name_without_suffix = None + name = None + indent = '' + opcode_base_match = opcode_base_class_re.search(line) + if opcode_base_match: + name_without_suffix = opcode_base_match.group('name') + name = name_without_suffix + 'Opcode' + else: + opcode_match = opcode_class_re.search(line) + if opcode_match: + name_without_suffix = opcode_match.group('name') + name = name_without_suffix # Indent by two additional spaces, since opcodes are declared in the # `Opcode` module. + indent = ' ' + + if name_without_suffix: + # Found an `Opcode` that matches a known `Instruction`. Replace the QLDoc with + # a copy of the one from the `Instruction`. + if instruction_comments.get(name_without_suffix): # Rename `instruction` to `operation`. - qldoc_lines = [(' ' + qldoc_line.replace(' An instruction ', ' An operation ')) - for qldoc_line in instruction_comments[name]] + qldoc_lines = [(indent + qldoc_line.replace(' An instruction ', ' An operation ')) + for qldoc_line in instruction_comments[name_without_suffix]] output_lines.extend(qldoc_lines) qldoc_lines = [] output_lines.append(line) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll index b903725e1e0..98e48ffb67e 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll @@ -139,10 +139,16 @@ class Opcode extends TOpcode { predicate hasOperandInternal(OperandTag tag) { none() } } +/** + * An operation whose result is computed from a single operand. + */ abstract class UnaryOpcode extends Opcode { final override predicate hasOperandInternal(OperandTag tag) { tag instanceof UnaryOperandTag } } +/** + * An operation whose result is computed from two operands. + */ abstract class BinaryOpcode extends Opcode { final override predicate hasOperandInternal(OperandTag tag) { tag instanceof LeftOperandTag or @@ -150,42 +156,95 @@ abstract class BinaryOpcode extends Opcode { } } +/** + * An operation that performs a binary arithmetic operation involving at least one pointer + * operand. + */ abstract class PointerArithmeticOpcode extends BinaryOpcode { } +/** + * An operation that adds or subtracts an integer offset from a pointer. + */ abstract class PointerOffsetOpcode extends PointerArithmeticOpcode { } +/** + * An operation that computes the result of an arithmetic operation. + */ abstract class ArithmeticOpcode extends Opcode { } +/** + * An operation that performs an arithmetic operation on two numeric operands. + */ abstract class BinaryArithmeticOpcode extends BinaryOpcode, ArithmeticOpcode { } +/** + * An operation whose result is computed by performing an arithmetic operation on a single + * numeric operand. + */ abstract class UnaryArithmeticOpcode extends UnaryOpcode, ArithmeticOpcode { } +/** + * An operation that computes the result of a bitwise operation. + */ abstract class BitwiseOpcode extends Opcode { } +/** + * An operation that performs a bitwise operation on two integer operands. + */ abstract class BinaryBitwiseOpcode extends BinaryOpcode, BitwiseOpcode { } +/** + * An operation that performs a bitwise operation on a single integer operand. + */ abstract class UnaryBitwiseOpcode extends UnaryOpcode, BitwiseOpcode { } +/** + * An operation that compares two numeric operands. + */ abstract class CompareOpcode extends BinaryOpcode { } +/** + * An operation that does a relative comparison of two values, such as `<` or `>=`. + */ abstract class RelationalOpcode extends CompareOpcode { } +/** + * An operation that returns a copy of its operand. + */ abstract class CopyOpcode extends Opcode { } +/** + * An operation that converts from the address of a derived class to the address of a base class. + */ abstract class ConvertToBaseOpcode extends UnaryOpcode { } +/** + * An operation that returns control to the caller of the function. + */ abstract class ReturnOpcode extends Opcode { } +/** + * An operation that throws an exception. + */ abstract class ThrowOpcode extends Opcode { } +/** + * An operation that starts a `catch` handler. + */ abstract class CatchOpcode extends Opcode { } abstract private class OpcodeWithCondition extends Opcode { final override predicate hasOperandInternal(OperandTag tag) { tag instanceof ConditionOperandTag } } +/** + * An operation representing a built-in operation. + */ abstract class BuiltInOperationOpcode extends Opcode { } +/** + * An operation representing a side effect of a function call. + */ abstract class SideEffectOpcode extends Opcode { } /** @@ -321,7 +380,8 @@ abstract class OpcodeWithLoad extends IndirectReadOpcode { } /** - * An opcode that reads from a set of memory locations as a side effect. + * An operation representing a read side effect of a function call on a + * specific parameter. */ abstract class ReadSideEffectOpcode extends SideEffectOpcode { final override predicate hasOperandInternal(OperandTag tag) { @@ -330,7 +390,8 @@ abstract class ReadSideEffectOpcode extends SideEffectOpcode { } /** - * An opcode that writes to a set of memory locations as a side effect. + * An operation representing a write side effect of a function call on a + * specific parameter. */ abstract class WriteSideEffectOpcode extends SideEffectOpcode { } diff --git a/csharp/ql/src/experimental/ir/implementation/Opcode.qll b/csharp/ql/src/experimental/ir/implementation/Opcode.qll index b903725e1e0..98e48ffb67e 100644 --- a/csharp/ql/src/experimental/ir/implementation/Opcode.qll +++ b/csharp/ql/src/experimental/ir/implementation/Opcode.qll @@ -139,10 +139,16 @@ class Opcode extends TOpcode { predicate hasOperandInternal(OperandTag tag) { none() } } +/** + * An operation whose result is computed from a single operand. + */ abstract class UnaryOpcode extends Opcode { final override predicate hasOperandInternal(OperandTag tag) { tag instanceof UnaryOperandTag } } +/** + * An operation whose result is computed from two operands. + */ abstract class BinaryOpcode extends Opcode { final override predicate hasOperandInternal(OperandTag tag) { tag instanceof LeftOperandTag or @@ -150,42 +156,95 @@ abstract class BinaryOpcode extends Opcode { } } +/** + * An operation that performs a binary arithmetic operation involving at least one pointer + * operand. + */ abstract class PointerArithmeticOpcode extends BinaryOpcode { } +/** + * An operation that adds or subtracts an integer offset from a pointer. + */ abstract class PointerOffsetOpcode extends PointerArithmeticOpcode { } +/** + * An operation that computes the result of an arithmetic operation. + */ abstract class ArithmeticOpcode extends Opcode { } +/** + * An operation that performs an arithmetic operation on two numeric operands. + */ abstract class BinaryArithmeticOpcode extends BinaryOpcode, ArithmeticOpcode { } +/** + * An operation whose result is computed by performing an arithmetic operation on a single + * numeric operand. + */ abstract class UnaryArithmeticOpcode extends UnaryOpcode, ArithmeticOpcode { } +/** + * An operation that computes the result of a bitwise operation. + */ abstract class BitwiseOpcode extends Opcode { } +/** + * An operation that performs a bitwise operation on two integer operands. + */ abstract class BinaryBitwiseOpcode extends BinaryOpcode, BitwiseOpcode { } +/** + * An operation that performs a bitwise operation on a single integer operand. + */ abstract class UnaryBitwiseOpcode extends UnaryOpcode, BitwiseOpcode { } +/** + * An operation that compares two numeric operands. + */ abstract class CompareOpcode extends BinaryOpcode { } +/** + * An operation that does a relative comparison of two values, such as `<` or `>=`. + */ abstract class RelationalOpcode extends CompareOpcode { } +/** + * An operation that returns a copy of its operand. + */ abstract class CopyOpcode extends Opcode { } +/** + * An operation that converts from the address of a derived class to the address of a base class. + */ abstract class ConvertToBaseOpcode extends UnaryOpcode { } +/** + * An operation that returns control to the caller of the function. + */ abstract class ReturnOpcode extends Opcode { } +/** + * An operation that throws an exception. + */ abstract class ThrowOpcode extends Opcode { } +/** + * An operation that starts a `catch` handler. + */ abstract class CatchOpcode extends Opcode { } abstract private class OpcodeWithCondition extends Opcode { final override predicate hasOperandInternal(OperandTag tag) { tag instanceof ConditionOperandTag } } +/** + * An operation representing a built-in operation. + */ abstract class BuiltInOperationOpcode extends Opcode { } +/** + * An operation representing a side effect of a function call. + */ abstract class SideEffectOpcode extends Opcode { } /** @@ -321,7 +380,8 @@ abstract class OpcodeWithLoad extends IndirectReadOpcode { } /** - * An opcode that reads from a set of memory locations as a side effect. + * An operation representing a read side effect of a function call on a + * specific parameter. */ abstract class ReadSideEffectOpcode extends SideEffectOpcode { final override predicate hasOperandInternal(OperandTag tag) { @@ -330,7 +390,8 @@ abstract class ReadSideEffectOpcode extends SideEffectOpcode { } /** - * An opcode that writes to a set of memory locations as a side effect. + * An operation representing a write side effect of a function call on a + * specific parameter. */ abstract class WriteSideEffectOpcode extends SideEffectOpcode { } From 4dcdd8a0ee6dc8dd82b5f1906b59ee3b3d49dd5b Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Fri, 26 Jun 2020 17:25:30 -0400 Subject: [PATCH 06/20] C++: Add last remaining QLDoc to `Opcode.qll` --- cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll | 6 ++++++ csharp/ql/src/experimental/ir/implementation/Opcode.qll | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll index 98e48ffb67e..b9655125423 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll @@ -1,3 +1,8 @@ +/** + * Provides `Opcode`s that specify the operation performed by an `Instruction`, as well as metadata + * about those opcodes, such as operand kinds and memory accesses. + */ + private import internal.OpcodeImports as Imports private import internal.OperandTag import Imports::MemoryAccessKind @@ -87,6 +92,7 @@ private newtype TOpcode = TNewObj() class Opcode extends TOpcode { + /** Gets a textual representation of this element. */ string toString() { result = "UnknownOpcode" } /** diff --git a/csharp/ql/src/experimental/ir/implementation/Opcode.qll b/csharp/ql/src/experimental/ir/implementation/Opcode.qll index 98e48ffb67e..b9655125423 100644 --- a/csharp/ql/src/experimental/ir/implementation/Opcode.qll +++ b/csharp/ql/src/experimental/ir/implementation/Opcode.qll @@ -1,3 +1,8 @@ +/** + * Provides `Opcode`s that specify the operation performed by an `Instruction`, as well as metadata + * about those opcodes, such as operand kinds and memory accesses. + */ + private import internal.OpcodeImports as Imports private import internal.OperandTag import Imports::MemoryAccessKind @@ -87,6 +92,7 @@ private newtype TOpcode = TNewObj() class Opcode extends TOpcode { + /** Gets a textual representation of this element. */ string toString() { result = "UnknownOpcode" } /** From 6de3d5bc3dcbe4b7d17f06c95f1ae5e375ef4975 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Mon, 29 Jun 2020 12:41:36 -0400 Subject: [PATCH 07/20] C++: Change opcode QLDocs to refer to instruction QLDocs As discussed in today's C++ analysis team meeting. `Opcode` is rarely used directly, so we'll just refer to the documentation for the corresponding `Instruction` class. I've preserved the script in case we want to do a bulk change of all of the `Opcode` comments, but I don't expect it will be needed if we just add a new `Opcode` or two. --- config/opcode-qldoc.py | 12 +- .../code/cpp/ir/implementation/Opcode.qll | 443 ++++++++++++------ .../experimental/ir/implementation/Opcode.qll | 443 ++++++++++++------ 3 files changed, 627 insertions(+), 271 deletions(-) diff --git a/config/opcode-qldoc.py b/config/opcode-qldoc.py index f44632bc4ee..e379e6a3ea9 100644 --- a/config/opcode-qldoc.py +++ b/config/opcode-qldoc.py @@ -4,6 +4,7 @@ import os import re path = os.path +needs_an_re = re.compile(r'^(?!Unary)[AEIOU]') # Name requiring "an" instead of "a". start_qldoc_re = re.compile(r'^\s*/\*\*') # Start of a QLDoc comment end_qldoc_re = re.compile(r'\*/\s*$') # End of a QLDoc comment blank_qldoc_line_re = re.compile(r'^\s*\*\s*$') # A line in a QLDoc comment with only the '*' @@ -84,9 +85,14 @@ with open(opcode_path, 'r', encoding='utf-8') as opcode: # Found an `Opcode` that matches a known `Instruction`. Replace the QLDoc with # a copy of the one from the `Instruction`. if instruction_comments.get(name_without_suffix): - # Rename `instruction` to `operation`. - qldoc_lines = [(indent + qldoc_line.replace(' An instruction ', ' An operation ')) - for qldoc_line in instruction_comments[name_without_suffix]] + article = 'an' if needs_an_re.search(name_without_suffix) else 'a' + qldoc_lines = [ + indent + '/**\n', + indent + ' * The `Opcode` for ' + article + ' `' + name_without_suffix + 'Instruction`.\n', + indent + ' *\n', + indent + ' * See the `' + name_without_suffix + 'Instruction` documentation for more details.\n', + indent + ' */\n' + ] output_lines.extend(qldoc_lines) qldoc_lines = [] output_lines.append(line) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll index b9655125423..aca058ab47c 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll @@ -146,14 +146,18 @@ class Opcode extends TOpcode { } /** - * An operation whose result is computed from a single operand. + * The `Opcode` for a `UnaryInstruction`. + * + * See the `UnaryInstruction` documentation for more details. */ abstract class UnaryOpcode extends Opcode { final override predicate hasOperandInternal(OperandTag tag) { tag instanceof UnaryOperandTag } } /** - * An operation whose result is computed from two operands. + * The `Opcode` for a `BinaryInstruction`. + * + * See the `BinaryInstruction` documentation for more details. */ abstract class BinaryOpcode extends Opcode { final override predicate hasOperandInternal(OperandTag tag) { @@ -163,79 +167,107 @@ abstract class BinaryOpcode extends Opcode { } /** - * An operation that performs a binary arithmetic operation involving at least one pointer - * operand. + * The `Opcode` for a `PointerArithmeticInstruction`. + * + * See the `PointerArithmeticInstruction` documentation for more details. */ abstract class PointerArithmeticOpcode extends BinaryOpcode { } /** - * An operation that adds or subtracts an integer offset from a pointer. + * The `Opcode` for a `PointerOffsetInstruction`. + * + * See the `PointerOffsetInstruction` documentation for more details. */ abstract class PointerOffsetOpcode extends PointerArithmeticOpcode { } /** - * An operation that computes the result of an arithmetic operation. + * The `Opcode` for an `ArithmeticInstruction`. + * + * See the `ArithmeticInstruction` documentation for more details. */ abstract class ArithmeticOpcode extends Opcode { } /** - * An operation that performs an arithmetic operation on two numeric operands. + * The `Opcode` for a `BinaryArithmeticInstruction`. + * + * See the `BinaryArithmeticInstruction` documentation for more details. */ abstract class BinaryArithmeticOpcode extends BinaryOpcode, ArithmeticOpcode { } /** - * An operation whose result is computed by performing an arithmetic operation on a single - * numeric operand. + * The `Opcode` for a `UnaryArithmeticInstruction`. + * + * See the `UnaryArithmeticInstruction` documentation for more details. */ abstract class UnaryArithmeticOpcode extends UnaryOpcode, ArithmeticOpcode { } /** - * An operation that computes the result of a bitwise operation. + * The `Opcode` for a `BitwiseInstruction`. + * + * See the `BitwiseInstruction` documentation for more details. */ abstract class BitwiseOpcode extends Opcode { } /** - * An operation that performs a bitwise operation on two integer operands. + * The `Opcode` for a `BinaryBitwiseInstruction`. + * + * See the `BinaryBitwiseInstruction` documentation for more details. */ abstract class BinaryBitwiseOpcode extends BinaryOpcode, BitwiseOpcode { } /** - * An operation that performs a bitwise operation on a single integer operand. + * The `Opcode` for a `UnaryBitwiseInstruction`. + * + * See the `UnaryBitwiseInstruction` documentation for more details. */ abstract class UnaryBitwiseOpcode extends UnaryOpcode, BitwiseOpcode { } /** - * An operation that compares two numeric operands. + * The `Opcode` for a `CompareInstruction`. + * + * See the `CompareInstruction` documentation for more details. */ abstract class CompareOpcode extends BinaryOpcode { } /** - * An operation that does a relative comparison of two values, such as `<` or `>=`. + * The `Opcode` for a `RelationalInstruction`. + * + * See the `RelationalInstruction` documentation for more details. */ abstract class RelationalOpcode extends CompareOpcode { } /** - * An operation that returns a copy of its operand. + * The `Opcode` for a `CopyInstruction`. + * + * See the `CopyInstruction` documentation for more details. */ abstract class CopyOpcode extends Opcode { } /** - * An operation that converts from the address of a derived class to the address of a base class. + * The `Opcode` for a `ConvertToBaseInstruction`. + * + * See the `ConvertToBaseInstruction` documentation for more details. */ abstract class ConvertToBaseOpcode extends UnaryOpcode { } /** - * An operation that returns control to the caller of the function. + * The `Opcode` for a `ReturnInstruction`. + * + * See the `ReturnInstruction` documentation for more details. */ abstract class ReturnOpcode extends Opcode { } /** - * An operation that throws an exception. + * The `Opcode` for a `ThrowInstruction`. + * + * See the `ThrowInstruction` documentation for more details. */ abstract class ThrowOpcode extends Opcode { } /** - * An operation that starts a `catch` handler. + * The `Opcode` for a `CatchInstruction`. + * + * See the `CatchInstruction` documentation for more details. */ abstract class CatchOpcode extends Opcode { } @@ -244,12 +276,16 @@ abstract private class OpcodeWithCondition extends Opcode { } /** - * An operation representing a built-in operation. + * The `Opcode` for a `BuiltInOperationInstruction`. + * + * See the `BuiltInOperationInstruction` documentation for more details. */ abstract class BuiltInOperationOpcode extends Opcode { } /** - * An operation representing a side effect of a function call. + * The `Opcode` for a `SideEffectInstruction`. + * + * See the `SideEffectInstruction` documentation for more details. */ abstract class SideEffectOpcode extends Opcode { } @@ -386,8 +422,9 @@ abstract class OpcodeWithLoad extends IndirectReadOpcode { } /** - * An operation representing a read side effect of a function call on a - * specific parameter. + * The `Opcode` for a `ReadSideEffectInstruction`. + * + * See the `ReadSideEffectInstruction` documentation for more details. */ abstract class ReadSideEffectOpcode extends SideEffectOpcode { final override predicate hasOperandInternal(OperandTag tag) { @@ -396,8 +433,9 @@ abstract class ReadSideEffectOpcode extends SideEffectOpcode { } /** - * An operation representing a write side effect of a function call on a - * specific parameter. + * The `Opcode` for a `WriteSideEffectInstruction`. + * + * See the `WriteSideEffectInstruction` documentation for more details. */ abstract class WriteSideEffectOpcode extends SideEffectOpcode { } @@ -406,82 +444,99 @@ abstract class WriteSideEffectOpcode extends SideEffectOpcode { } */ module Opcode { /** - * An operation that has no effect. + * The `Opcode` for a `NoOpInstruction`. + * + * See the `NoOpInstruction` documentation for more details. */ class NoOp extends Opcode, TNoOp { final override string toString() { result = "NoOp" } } /** - * An operation that returns an uninitialized value. + * The `Opcode` for an `UninitializedInstruction`. + * + * See the `UninitializedInstruction` documentation for more details. */ class Uninitialized extends IndirectWriteOpcode, TUninitialized { final override string toString() { result = "Uninitialized" } } /** - * An operation that produces a well-defined but unknown result and has - * unknown side effects, including side effects that are not conservatively - * modeled in the SSA graph. + * The `Opcode` for an `ErrorInstruction`. + * + * See the `ErrorInstruction` documentation for more details. */ class Error extends Opcode, TError { final override string toString() { result = "Error" } } /** - * An operation that initializes a parameter of the enclosing function with the value of the - * corresponding argument passed by the caller. + * The `Opcode` for an `InitializeParameterInstruction`. + * + * See the `InitializeParameterInstruction` documentation for more details. */ class InitializeParameter extends IndirectWriteOpcode, TInitializeParameter { final override string toString() { result = "InitializeParameter" } } /** - * An operation that initializes the memory pointed to by a parameter of the enclosing function - * with the value of that memory on entry to the function. + * The `Opcode` for an `InitializeIndirectionInstruction`. + * + * See the `InitializeIndirectionInstruction` documentation for more details. */ class InitializeIndirection extends EntireAllocationWriteOpcode, TInitializeIndirection { final override string toString() { result = "InitializeIndirection" } } /** - * An operation that initializes the `this` pointer parameter of the enclosing function. + * The `Opcode` for an `InitializeThisInstruction`. + * + * See the `InitializeThisInstruction` documentation for more details. */ class InitializeThis extends Opcode, TInitializeThis { final override string toString() { result = "InitializeThis" } } /** - * An operation representing the entry point to a function. + * The `Opcode` for an `EnterFunctionInstruction`. + * + * See the `EnterFunctionInstruction` documentation for more details. */ class EnterFunction extends Opcode, TEnterFunction { final override string toString() { result = "EnterFunction" } } /** - * An operation representing the exit point of a function. + * The `Opcode` for an `ExitFunctionInstruction`. + * + * See the `ExitFunctionInstruction` documentation for more details. */ class ExitFunction extends Opcode, TExitFunction { final override string toString() { result = "ExitFunction" } } /** - * An operation that returns control to the caller of the function, including a return value. + * The `Opcode` for a `ReturnValueInstruction`. + * + * See the `ReturnValueInstruction` documentation for more details. */ class ReturnValue extends ReturnOpcode, OpcodeWithLoad, TReturnValue { final override string toString() { result = "ReturnValue" } } /** - * An operation that returns control to the caller of the function, without returning a value. + * The `Opcode` for a `ReturnVoidInstruction`. + * + * See the `ReturnVoidInstruction` documentation for more details. */ class ReturnVoid extends ReturnOpcode, TReturnVoid { final override string toString() { result = "ReturnVoid" } } /** - * An operation that represents the use of the value pointed to by a parameter of the function - * after the function returns control to its caller. + * The `Opcode` for a `ReturnIndirectionInstruction`. + * + * See the `ReturnIndirectionInstruction` documentation for more details. */ class ReturnIndirection extends EntireAllocationReadOpcode, TReturnIndirection { final override string toString() { result = "ReturnIndirection" } @@ -492,21 +547,27 @@ module Opcode { } /** - * An operation that returns a register result containing a copy of its register operand. + * The `Opcode` for a `CopyValueInstruction`. + * + * See the `CopyValueInstruction` documentation for more details. */ class CopyValue extends UnaryOpcode, CopyOpcode, TCopyValue { final override string toString() { result = "CopyValue" } } /** - * An operation that returns a register result containing a copy of its memory operand. + * The `Opcode` for a `LoadInstruction`. + * + * See the `LoadInstruction` documentation for more details. */ class Load extends CopyOpcode, OpcodeWithLoad, TLoad { final override string toString() { result = "Load" } } /** - * An operation that returns a memory result containing a copy of its register operand. + * The `Opcode` for a `StoreInstruction`. + * + * See the `StoreInstruction` documentation for more details. */ class Store extends CopyOpcode, IndirectWriteOpcode, TStore { final override string toString() { result = "Store" } @@ -517,280 +578,342 @@ module Opcode { } /** - * An operation that computes the sum of two numeric operands. + * The `Opcode` for an `AddInstruction`. + * + * See the `AddInstruction` documentation for more details. */ class Add extends BinaryArithmeticOpcode, TAdd { final override string toString() { result = "Add" } } /** - * An operation that computes the difference of two numeric operands. + * The `Opcode` for a `SubInstruction`. + * + * See the `SubInstruction` documentation for more details. */ class Sub extends BinaryArithmeticOpcode, TSub { final override string toString() { result = "Sub" } } /** - * An operation that computes the product of two numeric operands. + * The `Opcode` for a `MulInstruction`. + * + * See the `MulInstruction` documentation for more details. */ class Mul extends BinaryArithmeticOpcode, TMul { final override string toString() { result = "Mul" } } /** - * An operation that computes the quotient of two numeric operands. + * The `Opcode` for a `DivInstruction`. + * + * See the `DivInstruction` documentation for more details. */ class Div extends BinaryArithmeticOpcode, TDiv { final override string toString() { result = "Div" } } /** - * An operation that computes the remainder of two integer operands. + * The `Opcode` for a `RemInstruction`. + * + * See the `RemInstruction` documentation for more details. */ class Rem extends BinaryArithmeticOpcode, TRem { final override string toString() { result = "Rem" } } /** - * An operation that negates a single numeric operand. + * The `Opcode` for a `NegateInstruction`. + * + * See the `NegateInstruction` documentation for more details. */ class Negate extends UnaryArithmeticOpcode, TNegate { final override string toString() { result = "Negate" } } /** - * An operation that shifts its left operand to the left by the number of bits specified by its - * right operand. + * The `Opcode` for a `ShiftLeftInstruction`. + * + * See the `ShiftLeftInstruction` documentation for more details. */ class ShiftLeft extends BinaryBitwiseOpcode, TShiftLeft { final override string toString() { result = "ShiftLeft" } } /** - * An operation that shifts its left operand to the right by the number of bits specified by its - * right operand. + * The `Opcode` for a `ShiftRightInstruction`. + * + * See the `ShiftRightInstruction` documentation for more details. */ class ShiftRight extends BinaryBitwiseOpcode, TShiftRight { final override string toString() { result = "ShiftRight" } } /** - * An operation that computes the bitwise "and" of two integer operands. + * The `Opcode` for a `BitAndInstruction`. + * + * See the `BitAndInstruction` documentation for more details. */ class BitAnd extends BinaryBitwiseOpcode, TBitAnd { final override string toString() { result = "BitAnd" } } /** - * An operation that computes the bitwise "or" of two integer operands. + * The `Opcode` for a `BitOrInstruction`. + * + * See the `BitOrInstruction` documentation for more details. */ class BitOr extends BinaryBitwiseOpcode, TBitOr { final override string toString() { result = "BitOr" } } /** - * An operation that computes the bitwise "xor" of two integer operands. + * The `Opcode` for a `BitXorInstruction`. + * + * See the `BitXorInstruction` documentation for more details. */ class BitXor extends BinaryBitwiseOpcode, TBitXor { final override string toString() { result = "BitXor" } } /** - * An operation that computes the bitwise complement of its operand. + * The `Opcode` for a `BitComplementInstruction`. + * + * See the `BitComplementInstruction` documentation for more details. */ class BitComplement extends UnaryBitwiseOpcode, TBitComplement { final override string toString() { result = "BitComplement" } } /** - * An operation that computes the logical complement of its operand. + * The `Opcode` for a `LogicalNotInstruction`. + * + * See the `LogicalNotInstruction` documentation for more details. */ class LogicalNot extends UnaryOpcode, TLogicalNot { final override string toString() { result = "LogicalNot" } } /** - * An operation that returns a `true` result if its operands are equal. + * The `Opcode` for a `CompareEQInstruction`. + * + * See the `CompareEQInstruction` documentation for more details. */ class CompareEQ extends CompareOpcode, TCompareEQ { final override string toString() { result = "CompareEQ" } } /** - * An operation that returns a `true` result if its operands are not equal. + * The `Opcode` for a `CompareNEInstruction`. + * + * See the `CompareNEInstruction` documentation for more details. */ class CompareNE extends CompareOpcode, TCompareNE { final override string toString() { result = "CompareNE" } } /** - * An operation that returns a `true` result if its left operand is less than its right operand. + * The `Opcode` for a `CompareLTInstruction`. + * + * See the `CompareLTInstruction` documentation for more details. */ class CompareLT extends RelationalOpcode, TCompareLT { final override string toString() { result = "CompareLT" } } /** - * An operation that returns a `true` result if its left operand is greater than its right operand. + * The `Opcode` for a `CompareGTInstruction`. + * + * See the `CompareGTInstruction` documentation for more details. */ class CompareGT extends RelationalOpcode, TCompareGT { final override string toString() { result = "CompareGT" } } /** - * An operation that returns a `true` result if its left operand is less than or equal to its - * right operand. + * The `Opcode` for a `CompareLEInstruction`. + * + * See the `CompareLEInstruction` documentation for more details. */ class CompareLE extends RelationalOpcode, TCompareLE { final override string toString() { result = "CompareLE" } } /** - * An operation that returns a `true` result if its left operand is greater than or equal to its - * right operand. + * The `Opcode` for a `CompareGEInstruction`. + * + * See the `CompareGEInstruction` documentation for more details. */ class CompareGE extends RelationalOpcode, TCompareGE { final override string toString() { result = "CompareGE" } } /** - * An operation that adds an integer offset to a pointer. + * The `Opcode` for a `PointerAddInstruction`. + * + * See the `PointerAddInstruction` documentation for more details. */ class PointerAdd extends PointerOffsetOpcode, TPointerAdd { final override string toString() { result = "PointerAdd" } } /** - * An operation that subtracts an integer offset from a pointer. + * The `Opcode` for a `PointerSubInstruction`. + * + * See the `PointerSubInstruction` documentation for more details. */ class PointerSub extends PointerOffsetOpcode, TPointerSub { final override string toString() { result = "PointerSub" } } /** - * An operation that computes the difference between two pointers. + * The `Opcode` for a `PointerDiffInstruction`. + * + * See the `PointerDiffInstruction` documentation for more details. */ class PointerDiff extends PointerArithmeticOpcode, TPointerDiff { final override string toString() { result = "PointerDiff" } } /** - * An operation that converts the value of its operand to a value of a different type. + * The `Opcode` for a `ConvertInstruction`. + * + * See the `ConvertInstruction` documentation for more details. */ class Convert extends UnaryOpcode, TConvert { final override string toString() { result = "Convert" } } /** - * An operation that converts from the address of a derived class to the address of a direct - * non-virtual base class. + * The `Opcode` for a `ConvertToNonVirtualBaseInstruction`. + * + * See the `ConvertToNonVirtualBaseInstruction` documentation for more details. */ class ConvertToNonVirtualBase extends ConvertToBaseOpcode, TConvertToNonVirtualBase { final override string toString() { result = "ConvertToNonVirtualBase" } } /** - * An operation that converts from the address of a derived class to the address of a virtual base - * class. + * The `Opcode` for a `ConvertToVirtualBaseInstruction`. + * + * See the `ConvertToVirtualBaseInstruction` documentation for more details. */ class ConvertToVirtualBase extends ConvertToBaseOpcode, TConvertToVirtualBase { final override string toString() { result = "ConvertToVirtualBase" } } /** - * An operation that converts from the address of a base class to the address of a direct - * non-virtual derived class. + * The `Opcode` for a `ConvertToDerivedInstruction`. + * + * See the `ConvertToDerivedInstruction` documentation for more details. */ class ConvertToDerived extends UnaryOpcode, TConvertToDerived { final override string toString() { result = "ConvertToDerived" } } /** - * An operation that converts the address of a polymorphic object to the address of a different - * subobject of the same polymorphic object, returning a null address if the dynamic type of the - * object is not compatible with the result type. + * The `Opcode` for a `CheckedConvertOrNullInstruction`. + * + * See the `CheckedConvertOrNullInstruction` documentation for more details. */ class CheckedConvertOrNull extends UnaryOpcode, TCheckedConvertOrNull { final override string toString() { result = "CheckedConvertOrNull" } } /** - * An operation that converts the address of a polymorphic object to the address of a different - * subobject of the same polymorphic object, throwing an exception if the dynamic type of the object - * is not compatible with the result type. + * The `Opcode` for a `CheckedConvertOrThrowInstruction`. + * + * See the `CheckedConvertOrThrowInstruction` documentation for more details. */ class CheckedConvertOrThrow extends UnaryOpcode, TCheckedConvertOrThrow { final override string toString() { result = "CheckedConvertOrThrow" } } /** - * An operation that returns the address of the complete object that contains the subobject - * pointed to by its operand. + * The `Opcode` for a `CompleteObjectAddressInstruction`. + * + * See the `CompleteObjectAddressInstruction` documentation for more details. */ class CompleteObjectAddress extends UnaryOpcode, TCompleteObjectAddress { final override string toString() { result = "CompleteObjectAddress" } } /** - * An operation that returns the address of a variable. + * The `Opcode` for a `VariableAddressInstruction`. + * + * See the `VariableAddressInstruction` documentation for more details. */ class VariableAddress extends Opcode, TVariableAddress { final override string toString() { result = "VariableAddress" } } /** - * An operation that computes the address of a non-static field of an object. + * The `Opcode` for a `FieldAddressInstruction`. + * + * See the `FieldAddressInstruction` documentation for more details. */ class FieldAddress extends UnaryOpcode, TFieldAddress { final override string toString() { result = "FieldAddress" } } /** - * An operation that computes the address of the first element of a managed array. + * The `Opcode` for an `ElementsAddressInstruction`. + * + * See the `ElementsAddressInstruction` documentation for more details. */ class ElementsAddress extends UnaryOpcode, TElementsAddress { final override string toString() { result = "ElementsAddress" } } /** - * An operation that returns the address of a function. + * The `Opcode` for a `FunctionAddressInstruction`. + * + * See the `FunctionAddressInstruction` documentation for more details. */ class FunctionAddress extends Opcode, TFunctionAddress { final override string toString() { result = "FunctionAddress" } } /** - * An operation whose result is a constant value. + * The `Opcode` for a `ConstantInstruction`. + * + * See the `ConstantInstruction` documentation for more details. */ class Constant extends Opcode, TConstant { final override string toString() { result = "Constant" } } /** - * An operation whose result is the address of a string literal. + * The `Opcode` for a `StringConstantInstruction`. + * + * See the `StringConstantInstruction` documentation for more details. */ class StringConstant extends Opcode, TStringConstant { final override string toString() { result = "StringConstant" } } /** - * An operation that branches to one of two successor instructions based on the value of a Boolean - * operand. + * The `Opcode` for a `ConditionalBranchInstruction`. + * + * See the `ConditionalBranchInstruction` documentation for more details. */ class ConditionalBranch extends OpcodeWithCondition, TConditionalBranch { final override string toString() { result = "ConditionalBranch" } } /** - * An operation that branches to one of multiple successor instructions based on the value of an - * integer operand. + * The `Opcode` for a `SwitchInstruction`. + * + * See the `SwitchInstruction` documentation for more details. */ class Switch extends OpcodeWithCondition, TSwitch { final override string toString() { result = "Switch" } } /** - * An operation that calls a function. + * The `Opcode` for a `CallInstruction`. + * + * See the `CallInstruction` documentation for more details. */ class Call extends Opcode, TCall { final override string toString() { result = "Call" } @@ -801,42 +924,54 @@ module Opcode { } /** - * An operation that catches an exception of a specific type. + * The `Opcode` for a `CatchByTypeInstruction`. + * + * See the `CatchByTypeInstruction` documentation for more details. */ class CatchByType extends CatchOpcode, TCatchByType { final override string toString() { result = "CatchByType" } } /** - * An operation that catches any exception. + * The `Opcode` for a `CatchAnyInstruction`. + * + * See the `CatchAnyInstruction` documentation for more details. */ class CatchAny extends CatchOpcode, TCatchAny { final override string toString() { result = "CatchAny" } } /** - * An operation that throws a new exception. + * The `Opcode` for a `ThrowValueInstruction`. + * + * See the `ThrowValueInstruction` documentation for more details. */ class ThrowValue extends ThrowOpcode, OpcodeWithLoad, TThrowValue { final override string toString() { result = "ThrowValue" } } /** - * An operation that re-throws the current exception. + * The `Opcode` for a `ReThrowInstruction`. + * + * See the `ReThrowInstruction` documentation for more details. */ class ReThrow extends ThrowOpcode, TReThrow { final override string toString() { result = "ReThrow" } } /** - * An operation that exits the current function by propagating an exception. + * The `Opcode` for an `UnwindInstruction`. + * + * See the `UnwindInstruction` documentation for more details. */ class Unwind extends Opcode, TUnwind { final override string toString() { result = "Unwind" } } /** - * An operation that initializes all escaped memory. + * The `Opcode` for an `AliasedDefinitionInstruction`. + * + * See the `AliasedDefinitionInstruction` documentation for more details. */ class AliasedDefinition extends Opcode, TAliasedDefinition { final override string toString() { result = "AliasedDefinition" } @@ -845,7 +980,9 @@ module Opcode { } /** - * An operation that initializes all memory that existed before this function was called. + * The `Opcode` for an `InitializeNonLocalInstruction`. + * + * See the `InitializeNonLocalInstruction` documentation for more details. */ class InitializeNonLocal extends Opcode, TInitializeNonLocal { final override string toString() { result = "InitializeNonLocal" } @@ -856,7 +993,9 @@ module Opcode { } /** - * An operation that consumes all escaped memory on exit from the function. + * The `Opcode` for an `AliasedUseInstruction`. + * + * See the `AliasedUseInstruction` documentation for more details. */ class AliasedUse extends Opcode, TAliasedUse { final override string toString() { result = "AliasedUse" } @@ -869,7 +1008,9 @@ module Opcode { } /** - * An operation representing the choice of one of multiple input values based on control flow. + * The `Opcode` for a `PhiInstruction`. + * + * See the `PhiInstruction` documentation for more details. */ class Phi extends Opcode, TPhi { final override string toString() { result = "Phi" } @@ -878,45 +1019,54 @@ module Opcode { } /** - * An operation representing a built-in operation that does not have a specific opcode. The - * actual operation is specified by the `getBuiltInOperation()` predicate. + * The `Opcode` for a `BuiltInInstruction`. + * + * See the `BuiltInInstruction` documentation for more details. */ class BuiltIn extends BuiltInOperationOpcode, TBuiltIn { final override string toString() { result = "BuiltIn" } } /** - * An operation that returns a `va_list` to access the arguments passed to the `...` parameter. + * The `Opcode` for a `VarArgsStartInstruction`. + * + * See the `VarArgsStartInstruction` documentation for more details. */ class VarArgsStart extends UnaryOpcode, TVarArgsStart { final override string toString() { result = "VarArgsStart" } } /** - * An operation that cleans up a `va_list` after it is no longer in use. + * The `Opcode` for a `VarArgsEndInstruction`. + * + * See the `VarArgsEndInstruction` documentation for more details. */ class VarArgsEnd extends UnaryOpcode, TVarArgsEnd { final override string toString() { result = "VarArgsEnd" } } /** - * An operation that returns the address of the argument currently pointed to by a `va_list`. + * The `Opcode` for a `VarArgInstruction`. + * + * See the `VarArgInstruction` documentation for more details. */ class VarArg extends UnaryOpcode, TVarArg { final override string toString() { result = "VarArg" } } /** - * An operation that modifies a `va_list` to point to the next argument that was passed to the - * `...` parameter. + * The `Opcode` for a `NextVarArgInstruction`. + * + * See the `NextVarArgInstruction` documentation for more details. */ class NextVarArg extends UnaryOpcode, TNextVarArg { final override string toString() { result = "NextVarArg" } } /** - * An operation representing the side effect of a function call on any memory that might be - * accessed by that call. + * The `Opcode` for a `CallSideEffectInstruction`. + * + * See the `CallSideEffectInstruction` documentation for more details. */ class CallSideEffect extends WriteSideEffectOpcode, EscapedWriteOpcode, MayWriteOpcode, ReadSideEffectOpcode, EscapedReadOpcode, MayReadOpcode, TCallSideEffect { @@ -924,8 +1074,9 @@ module Opcode { } /** - * An operation representing the side effect of a function call on any memory - * that might be read by that call. + * The `Opcode` for a `CallReadSideEffectInstruction`. + * + * See the `CallReadSideEffectInstruction` documentation for more details. */ class CallReadSideEffect extends ReadSideEffectOpcode, EscapedReadOpcode, MayReadOpcode, TCallReadSideEffect { @@ -933,7 +1084,9 @@ module Opcode { } /** - * An operation representing the read of an indirect parameter within a function call. + * The `Opcode` for an `IndirectReadSideEffectInstruction`. + * + * See the `IndirectReadSideEffectInstruction` documentation for more details. */ class IndirectReadSideEffect extends ReadSideEffectOpcode, IndirectReadOpcode, TIndirectReadSideEffect { @@ -941,7 +1094,9 @@ module Opcode { } /** - * An operation representing the write of an indirect parameter within a function call. + * The `Opcode` for an `IndirectMustWriteSideEffectInstruction`. + * + * See the `IndirectMustWriteSideEffectInstruction` documentation for more details. */ class IndirectMustWriteSideEffect extends WriteSideEffectOpcode, IndirectWriteOpcode, TIndirectMustWriteSideEffect { @@ -949,7 +1104,9 @@ module Opcode { } /** - * An operation representing the potential write of an indirect parameter within a function call. + * The `Opcode` for an `IndirectMayWriteSideEffectInstruction`. + * + * See the `IndirectMayWriteSideEffectInstruction` documentation for more details. */ class IndirectMayWriteSideEffect extends WriteSideEffectOpcode, IndirectWriteOpcode, MayWriteOpcode, TIndirectMayWriteSideEffect { @@ -957,7 +1114,9 @@ module Opcode { } /** - * An operation representing the read of an indirect buffer parameter within a function call. + * The `Opcode` for a `BufferReadSideEffectInstruction`. + * + * See the `BufferReadSideEffectInstruction` documentation for more details. */ class BufferReadSideEffect extends ReadSideEffectOpcode, UnsizedBufferReadOpcode, TBufferReadSideEffect { @@ -965,8 +1124,9 @@ module Opcode { } /** - * An operation representing the write of an indirect buffer parameter within a function call. The - * entire buffer is overwritten. + * The `Opcode` for a `BufferMustWriteSideEffectInstruction`. + * + * See the `BufferMustWriteSideEffectInstruction` documentation for more details. */ class BufferMustWriteSideEffect extends WriteSideEffectOpcode, UnsizedBufferWriteOpcode, TBufferMustWriteSideEffect { @@ -974,7 +1134,9 @@ module Opcode { } /** - * An operation representing the write of an indirect buffer parameter within a function call. + * The `Opcode` for a `BufferMayWriteSideEffectInstruction`. + * + * See the `BufferMayWriteSideEffectInstruction` documentation for more details. */ class BufferMayWriteSideEffect extends WriteSideEffectOpcode, UnsizedBufferWriteOpcode, MayWriteOpcode, TBufferMayWriteSideEffect { @@ -982,7 +1144,9 @@ module Opcode { } /** - * An operation representing the read of an indirect buffer parameter within a function call. + * The `Opcode` for a `SizedBufferReadSideEffectInstruction`. + * + * See the `SizedBufferReadSideEffectInstruction` documentation for more details. */ class SizedBufferReadSideEffect extends ReadSideEffectOpcode, SizedBufferReadOpcode, TSizedBufferReadSideEffect { @@ -990,8 +1154,9 @@ module Opcode { } /** - * An operation representing the write of an indirect buffer parameter within a function call. The - * entire buffer is overwritten. + * The `Opcode` for a `SizedBufferMustWriteSideEffectInstruction`. + * + * See the `SizedBufferMustWriteSideEffectInstruction` documentation for more details. */ class SizedBufferMustWriteSideEffect extends WriteSideEffectOpcode, SizedBufferWriteOpcode, TSizedBufferMustWriteSideEffect { @@ -999,7 +1164,9 @@ module Opcode { } /** - * An operation representing the write of an indirect buffer parameter within a function call. + * The `Opcode` for a `SizedBufferMayWriteSideEffectInstruction`. + * + * See the `SizedBufferMayWriteSideEffectInstruction` documentation for more details. */ class SizedBufferMayWriteSideEffect extends WriteSideEffectOpcode, SizedBufferWriteOpcode, MayWriteOpcode, TSizedBufferMayWriteSideEffect { @@ -1007,8 +1174,9 @@ module Opcode { } /** - * An operation representing the initial value of newly allocated memory, such as the result of a - * call to `malloc`. + * The `Opcode` for an `InitializeDynamicAllocationInstruction`. + * + * See the `InitializeDynamicAllocationInstruction` documentation for more details. */ class InitializeDynamicAllocation extends SideEffectOpcode, EntireAllocationWriteOpcode, TInitializeDynamicAllocation { @@ -1016,8 +1184,9 @@ module Opcode { } /** - * An operation representing the effect that a write to a memory may have on potential aliases of - * that memory. + * The `Opcode` for a `ChiInstruction`. + * + * See the `ChiInstruction` documentation for more details. */ class Chi extends Opcode, TChi { final override string toString() { result = "Chi" } @@ -1034,7 +1203,9 @@ module Opcode { } /** - * An operation representing a GNU or MSVC inline assembly statement. + * The `Opcode` for an `InlineAsmInstruction`. + * + * See the `InlineAsmInstruction` documentation for more details. */ class InlineAsm extends Opcode, EscapedWriteOpcode, MayWriteOpcode, EscapedReadOpcode, MayReadOpcode, TInlineAsm { @@ -1046,14 +1217,18 @@ module Opcode { } /** - * An operation representing unreachable code. + * The `Opcode` for an `UnreachedInstruction`. + * + * See the `UnreachedInstruction` documentation for more details. */ class Unreached extends Opcode, TUnreached { final override string toString() { result = "Unreached" } } /** - * An operation that allocates a new object on the managed heap. + * The `Opcode` for a `NewObjInstruction`. + * + * See the `NewObjInstruction` documentation for more details. */ class NewObj extends Opcode, TNewObj { final override string toString() { result = "NewObj" } diff --git a/csharp/ql/src/experimental/ir/implementation/Opcode.qll b/csharp/ql/src/experimental/ir/implementation/Opcode.qll index b9655125423..aca058ab47c 100644 --- a/csharp/ql/src/experimental/ir/implementation/Opcode.qll +++ b/csharp/ql/src/experimental/ir/implementation/Opcode.qll @@ -146,14 +146,18 @@ class Opcode extends TOpcode { } /** - * An operation whose result is computed from a single operand. + * The `Opcode` for a `UnaryInstruction`. + * + * See the `UnaryInstruction` documentation for more details. */ abstract class UnaryOpcode extends Opcode { final override predicate hasOperandInternal(OperandTag tag) { tag instanceof UnaryOperandTag } } /** - * An operation whose result is computed from two operands. + * The `Opcode` for a `BinaryInstruction`. + * + * See the `BinaryInstruction` documentation for more details. */ abstract class BinaryOpcode extends Opcode { final override predicate hasOperandInternal(OperandTag tag) { @@ -163,79 +167,107 @@ abstract class BinaryOpcode extends Opcode { } /** - * An operation that performs a binary arithmetic operation involving at least one pointer - * operand. + * The `Opcode` for a `PointerArithmeticInstruction`. + * + * See the `PointerArithmeticInstruction` documentation for more details. */ abstract class PointerArithmeticOpcode extends BinaryOpcode { } /** - * An operation that adds or subtracts an integer offset from a pointer. + * The `Opcode` for a `PointerOffsetInstruction`. + * + * See the `PointerOffsetInstruction` documentation for more details. */ abstract class PointerOffsetOpcode extends PointerArithmeticOpcode { } /** - * An operation that computes the result of an arithmetic operation. + * The `Opcode` for an `ArithmeticInstruction`. + * + * See the `ArithmeticInstruction` documentation for more details. */ abstract class ArithmeticOpcode extends Opcode { } /** - * An operation that performs an arithmetic operation on two numeric operands. + * The `Opcode` for a `BinaryArithmeticInstruction`. + * + * See the `BinaryArithmeticInstruction` documentation for more details. */ abstract class BinaryArithmeticOpcode extends BinaryOpcode, ArithmeticOpcode { } /** - * An operation whose result is computed by performing an arithmetic operation on a single - * numeric operand. + * The `Opcode` for a `UnaryArithmeticInstruction`. + * + * See the `UnaryArithmeticInstruction` documentation for more details. */ abstract class UnaryArithmeticOpcode extends UnaryOpcode, ArithmeticOpcode { } /** - * An operation that computes the result of a bitwise operation. + * The `Opcode` for a `BitwiseInstruction`. + * + * See the `BitwiseInstruction` documentation for more details. */ abstract class BitwiseOpcode extends Opcode { } /** - * An operation that performs a bitwise operation on two integer operands. + * The `Opcode` for a `BinaryBitwiseInstruction`. + * + * See the `BinaryBitwiseInstruction` documentation for more details. */ abstract class BinaryBitwiseOpcode extends BinaryOpcode, BitwiseOpcode { } /** - * An operation that performs a bitwise operation on a single integer operand. + * The `Opcode` for a `UnaryBitwiseInstruction`. + * + * See the `UnaryBitwiseInstruction` documentation for more details. */ abstract class UnaryBitwiseOpcode extends UnaryOpcode, BitwiseOpcode { } /** - * An operation that compares two numeric operands. + * The `Opcode` for a `CompareInstruction`. + * + * See the `CompareInstruction` documentation for more details. */ abstract class CompareOpcode extends BinaryOpcode { } /** - * An operation that does a relative comparison of two values, such as `<` or `>=`. + * The `Opcode` for a `RelationalInstruction`. + * + * See the `RelationalInstruction` documentation for more details. */ abstract class RelationalOpcode extends CompareOpcode { } /** - * An operation that returns a copy of its operand. + * The `Opcode` for a `CopyInstruction`. + * + * See the `CopyInstruction` documentation for more details. */ abstract class CopyOpcode extends Opcode { } /** - * An operation that converts from the address of a derived class to the address of a base class. + * The `Opcode` for a `ConvertToBaseInstruction`. + * + * See the `ConvertToBaseInstruction` documentation for more details. */ abstract class ConvertToBaseOpcode extends UnaryOpcode { } /** - * An operation that returns control to the caller of the function. + * The `Opcode` for a `ReturnInstruction`. + * + * See the `ReturnInstruction` documentation for more details. */ abstract class ReturnOpcode extends Opcode { } /** - * An operation that throws an exception. + * The `Opcode` for a `ThrowInstruction`. + * + * See the `ThrowInstruction` documentation for more details. */ abstract class ThrowOpcode extends Opcode { } /** - * An operation that starts a `catch` handler. + * The `Opcode` for a `CatchInstruction`. + * + * See the `CatchInstruction` documentation for more details. */ abstract class CatchOpcode extends Opcode { } @@ -244,12 +276,16 @@ abstract private class OpcodeWithCondition extends Opcode { } /** - * An operation representing a built-in operation. + * The `Opcode` for a `BuiltInOperationInstruction`. + * + * See the `BuiltInOperationInstruction` documentation for more details. */ abstract class BuiltInOperationOpcode extends Opcode { } /** - * An operation representing a side effect of a function call. + * The `Opcode` for a `SideEffectInstruction`. + * + * See the `SideEffectInstruction` documentation for more details. */ abstract class SideEffectOpcode extends Opcode { } @@ -386,8 +422,9 @@ abstract class OpcodeWithLoad extends IndirectReadOpcode { } /** - * An operation representing a read side effect of a function call on a - * specific parameter. + * The `Opcode` for a `ReadSideEffectInstruction`. + * + * See the `ReadSideEffectInstruction` documentation for more details. */ abstract class ReadSideEffectOpcode extends SideEffectOpcode { final override predicate hasOperandInternal(OperandTag tag) { @@ -396,8 +433,9 @@ abstract class ReadSideEffectOpcode extends SideEffectOpcode { } /** - * An operation representing a write side effect of a function call on a - * specific parameter. + * The `Opcode` for a `WriteSideEffectInstruction`. + * + * See the `WriteSideEffectInstruction` documentation for more details. */ abstract class WriteSideEffectOpcode extends SideEffectOpcode { } @@ -406,82 +444,99 @@ abstract class WriteSideEffectOpcode extends SideEffectOpcode { } */ module Opcode { /** - * An operation that has no effect. + * The `Opcode` for a `NoOpInstruction`. + * + * See the `NoOpInstruction` documentation for more details. */ class NoOp extends Opcode, TNoOp { final override string toString() { result = "NoOp" } } /** - * An operation that returns an uninitialized value. + * The `Opcode` for an `UninitializedInstruction`. + * + * See the `UninitializedInstruction` documentation for more details. */ class Uninitialized extends IndirectWriteOpcode, TUninitialized { final override string toString() { result = "Uninitialized" } } /** - * An operation that produces a well-defined but unknown result and has - * unknown side effects, including side effects that are not conservatively - * modeled in the SSA graph. + * The `Opcode` for an `ErrorInstruction`. + * + * See the `ErrorInstruction` documentation for more details. */ class Error extends Opcode, TError { final override string toString() { result = "Error" } } /** - * An operation that initializes a parameter of the enclosing function with the value of the - * corresponding argument passed by the caller. + * The `Opcode` for an `InitializeParameterInstruction`. + * + * See the `InitializeParameterInstruction` documentation for more details. */ class InitializeParameter extends IndirectWriteOpcode, TInitializeParameter { final override string toString() { result = "InitializeParameter" } } /** - * An operation that initializes the memory pointed to by a parameter of the enclosing function - * with the value of that memory on entry to the function. + * The `Opcode` for an `InitializeIndirectionInstruction`. + * + * See the `InitializeIndirectionInstruction` documentation for more details. */ class InitializeIndirection extends EntireAllocationWriteOpcode, TInitializeIndirection { final override string toString() { result = "InitializeIndirection" } } /** - * An operation that initializes the `this` pointer parameter of the enclosing function. + * The `Opcode` for an `InitializeThisInstruction`. + * + * See the `InitializeThisInstruction` documentation for more details. */ class InitializeThis extends Opcode, TInitializeThis { final override string toString() { result = "InitializeThis" } } /** - * An operation representing the entry point to a function. + * The `Opcode` for an `EnterFunctionInstruction`. + * + * See the `EnterFunctionInstruction` documentation for more details. */ class EnterFunction extends Opcode, TEnterFunction { final override string toString() { result = "EnterFunction" } } /** - * An operation representing the exit point of a function. + * The `Opcode` for an `ExitFunctionInstruction`. + * + * See the `ExitFunctionInstruction` documentation for more details. */ class ExitFunction extends Opcode, TExitFunction { final override string toString() { result = "ExitFunction" } } /** - * An operation that returns control to the caller of the function, including a return value. + * The `Opcode` for a `ReturnValueInstruction`. + * + * See the `ReturnValueInstruction` documentation for more details. */ class ReturnValue extends ReturnOpcode, OpcodeWithLoad, TReturnValue { final override string toString() { result = "ReturnValue" } } /** - * An operation that returns control to the caller of the function, without returning a value. + * The `Opcode` for a `ReturnVoidInstruction`. + * + * See the `ReturnVoidInstruction` documentation for more details. */ class ReturnVoid extends ReturnOpcode, TReturnVoid { final override string toString() { result = "ReturnVoid" } } /** - * An operation that represents the use of the value pointed to by a parameter of the function - * after the function returns control to its caller. + * The `Opcode` for a `ReturnIndirectionInstruction`. + * + * See the `ReturnIndirectionInstruction` documentation for more details. */ class ReturnIndirection extends EntireAllocationReadOpcode, TReturnIndirection { final override string toString() { result = "ReturnIndirection" } @@ -492,21 +547,27 @@ module Opcode { } /** - * An operation that returns a register result containing a copy of its register operand. + * The `Opcode` for a `CopyValueInstruction`. + * + * See the `CopyValueInstruction` documentation for more details. */ class CopyValue extends UnaryOpcode, CopyOpcode, TCopyValue { final override string toString() { result = "CopyValue" } } /** - * An operation that returns a register result containing a copy of its memory operand. + * The `Opcode` for a `LoadInstruction`. + * + * See the `LoadInstruction` documentation for more details. */ class Load extends CopyOpcode, OpcodeWithLoad, TLoad { final override string toString() { result = "Load" } } /** - * An operation that returns a memory result containing a copy of its register operand. + * The `Opcode` for a `StoreInstruction`. + * + * See the `StoreInstruction` documentation for more details. */ class Store extends CopyOpcode, IndirectWriteOpcode, TStore { final override string toString() { result = "Store" } @@ -517,280 +578,342 @@ module Opcode { } /** - * An operation that computes the sum of two numeric operands. + * The `Opcode` for an `AddInstruction`. + * + * See the `AddInstruction` documentation for more details. */ class Add extends BinaryArithmeticOpcode, TAdd { final override string toString() { result = "Add" } } /** - * An operation that computes the difference of two numeric operands. + * The `Opcode` for a `SubInstruction`. + * + * See the `SubInstruction` documentation for more details. */ class Sub extends BinaryArithmeticOpcode, TSub { final override string toString() { result = "Sub" } } /** - * An operation that computes the product of two numeric operands. + * The `Opcode` for a `MulInstruction`. + * + * See the `MulInstruction` documentation for more details. */ class Mul extends BinaryArithmeticOpcode, TMul { final override string toString() { result = "Mul" } } /** - * An operation that computes the quotient of two numeric operands. + * The `Opcode` for a `DivInstruction`. + * + * See the `DivInstruction` documentation for more details. */ class Div extends BinaryArithmeticOpcode, TDiv { final override string toString() { result = "Div" } } /** - * An operation that computes the remainder of two integer operands. + * The `Opcode` for a `RemInstruction`. + * + * See the `RemInstruction` documentation for more details. */ class Rem extends BinaryArithmeticOpcode, TRem { final override string toString() { result = "Rem" } } /** - * An operation that negates a single numeric operand. + * The `Opcode` for a `NegateInstruction`. + * + * See the `NegateInstruction` documentation for more details. */ class Negate extends UnaryArithmeticOpcode, TNegate { final override string toString() { result = "Negate" } } /** - * An operation that shifts its left operand to the left by the number of bits specified by its - * right operand. + * The `Opcode` for a `ShiftLeftInstruction`. + * + * See the `ShiftLeftInstruction` documentation for more details. */ class ShiftLeft extends BinaryBitwiseOpcode, TShiftLeft { final override string toString() { result = "ShiftLeft" } } /** - * An operation that shifts its left operand to the right by the number of bits specified by its - * right operand. + * The `Opcode` for a `ShiftRightInstruction`. + * + * See the `ShiftRightInstruction` documentation for more details. */ class ShiftRight extends BinaryBitwiseOpcode, TShiftRight { final override string toString() { result = "ShiftRight" } } /** - * An operation that computes the bitwise "and" of two integer operands. + * The `Opcode` for a `BitAndInstruction`. + * + * See the `BitAndInstruction` documentation for more details. */ class BitAnd extends BinaryBitwiseOpcode, TBitAnd { final override string toString() { result = "BitAnd" } } /** - * An operation that computes the bitwise "or" of two integer operands. + * The `Opcode` for a `BitOrInstruction`. + * + * See the `BitOrInstruction` documentation for more details. */ class BitOr extends BinaryBitwiseOpcode, TBitOr { final override string toString() { result = "BitOr" } } /** - * An operation that computes the bitwise "xor" of two integer operands. + * The `Opcode` for a `BitXorInstruction`. + * + * See the `BitXorInstruction` documentation for more details. */ class BitXor extends BinaryBitwiseOpcode, TBitXor { final override string toString() { result = "BitXor" } } /** - * An operation that computes the bitwise complement of its operand. + * The `Opcode` for a `BitComplementInstruction`. + * + * See the `BitComplementInstruction` documentation for more details. */ class BitComplement extends UnaryBitwiseOpcode, TBitComplement { final override string toString() { result = "BitComplement" } } /** - * An operation that computes the logical complement of its operand. + * The `Opcode` for a `LogicalNotInstruction`. + * + * See the `LogicalNotInstruction` documentation for more details. */ class LogicalNot extends UnaryOpcode, TLogicalNot { final override string toString() { result = "LogicalNot" } } /** - * An operation that returns a `true` result if its operands are equal. + * The `Opcode` for a `CompareEQInstruction`. + * + * See the `CompareEQInstruction` documentation for more details. */ class CompareEQ extends CompareOpcode, TCompareEQ { final override string toString() { result = "CompareEQ" } } /** - * An operation that returns a `true` result if its operands are not equal. + * The `Opcode` for a `CompareNEInstruction`. + * + * See the `CompareNEInstruction` documentation for more details. */ class CompareNE extends CompareOpcode, TCompareNE { final override string toString() { result = "CompareNE" } } /** - * An operation that returns a `true` result if its left operand is less than its right operand. + * The `Opcode` for a `CompareLTInstruction`. + * + * See the `CompareLTInstruction` documentation for more details. */ class CompareLT extends RelationalOpcode, TCompareLT { final override string toString() { result = "CompareLT" } } /** - * An operation that returns a `true` result if its left operand is greater than its right operand. + * The `Opcode` for a `CompareGTInstruction`. + * + * See the `CompareGTInstruction` documentation for more details. */ class CompareGT extends RelationalOpcode, TCompareGT { final override string toString() { result = "CompareGT" } } /** - * An operation that returns a `true` result if its left operand is less than or equal to its - * right operand. + * The `Opcode` for a `CompareLEInstruction`. + * + * See the `CompareLEInstruction` documentation for more details. */ class CompareLE extends RelationalOpcode, TCompareLE { final override string toString() { result = "CompareLE" } } /** - * An operation that returns a `true` result if its left operand is greater than or equal to its - * right operand. + * The `Opcode` for a `CompareGEInstruction`. + * + * See the `CompareGEInstruction` documentation for more details. */ class CompareGE extends RelationalOpcode, TCompareGE { final override string toString() { result = "CompareGE" } } /** - * An operation that adds an integer offset to a pointer. + * The `Opcode` for a `PointerAddInstruction`. + * + * See the `PointerAddInstruction` documentation for more details. */ class PointerAdd extends PointerOffsetOpcode, TPointerAdd { final override string toString() { result = "PointerAdd" } } /** - * An operation that subtracts an integer offset from a pointer. + * The `Opcode` for a `PointerSubInstruction`. + * + * See the `PointerSubInstruction` documentation for more details. */ class PointerSub extends PointerOffsetOpcode, TPointerSub { final override string toString() { result = "PointerSub" } } /** - * An operation that computes the difference between two pointers. + * The `Opcode` for a `PointerDiffInstruction`. + * + * See the `PointerDiffInstruction` documentation for more details. */ class PointerDiff extends PointerArithmeticOpcode, TPointerDiff { final override string toString() { result = "PointerDiff" } } /** - * An operation that converts the value of its operand to a value of a different type. + * The `Opcode` for a `ConvertInstruction`. + * + * See the `ConvertInstruction` documentation for more details. */ class Convert extends UnaryOpcode, TConvert { final override string toString() { result = "Convert" } } /** - * An operation that converts from the address of a derived class to the address of a direct - * non-virtual base class. + * The `Opcode` for a `ConvertToNonVirtualBaseInstruction`. + * + * See the `ConvertToNonVirtualBaseInstruction` documentation for more details. */ class ConvertToNonVirtualBase extends ConvertToBaseOpcode, TConvertToNonVirtualBase { final override string toString() { result = "ConvertToNonVirtualBase" } } /** - * An operation that converts from the address of a derived class to the address of a virtual base - * class. + * The `Opcode` for a `ConvertToVirtualBaseInstruction`. + * + * See the `ConvertToVirtualBaseInstruction` documentation for more details. */ class ConvertToVirtualBase extends ConvertToBaseOpcode, TConvertToVirtualBase { final override string toString() { result = "ConvertToVirtualBase" } } /** - * An operation that converts from the address of a base class to the address of a direct - * non-virtual derived class. + * The `Opcode` for a `ConvertToDerivedInstruction`. + * + * See the `ConvertToDerivedInstruction` documentation for more details. */ class ConvertToDerived extends UnaryOpcode, TConvertToDerived { final override string toString() { result = "ConvertToDerived" } } /** - * An operation that converts the address of a polymorphic object to the address of a different - * subobject of the same polymorphic object, returning a null address if the dynamic type of the - * object is not compatible with the result type. + * The `Opcode` for a `CheckedConvertOrNullInstruction`. + * + * See the `CheckedConvertOrNullInstruction` documentation for more details. */ class CheckedConvertOrNull extends UnaryOpcode, TCheckedConvertOrNull { final override string toString() { result = "CheckedConvertOrNull" } } /** - * An operation that converts the address of a polymorphic object to the address of a different - * subobject of the same polymorphic object, throwing an exception if the dynamic type of the object - * is not compatible with the result type. + * The `Opcode` for a `CheckedConvertOrThrowInstruction`. + * + * See the `CheckedConvertOrThrowInstruction` documentation for more details. */ class CheckedConvertOrThrow extends UnaryOpcode, TCheckedConvertOrThrow { final override string toString() { result = "CheckedConvertOrThrow" } } /** - * An operation that returns the address of the complete object that contains the subobject - * pointed to by its operand. + * The `Opcode` for a `CompleteObjectAddressInstruction`. + * + * See the `CompleteObjectAddressInstruction` documentation for more details. */ class CompleteObjectAddress extends UnaryOpcode, TCompleteObjectAddress { final override string toString() { result = "CompleteObjectAddress" } } /** - * An operation that returns the address of a variable. + * The `Opcode` for a `VariableAddressInstruction`. + * + * See the `VariableAddressInstruction` documentation for more details. */ class VariableAddress extends Opcode, TVariableAddress { final override string toString() { result = "VariableAddress" } } /** - * An operation that computes the address of a non-static field of an object. + * The `Opcode` for a `FieldAddressInstruction`. + * + * See the `FieldAddressInstruction` documentation for more details. */ class FieldAddress extends UnaryOpcode, TFieldAddress { final override string toString() { result = "FieldAddress" } } /** - * An operation that computes the address of the first element of a managed array. + * The `Opcode` for an `ElementsAddressInstruction`. + * + * See the `ElementsAddressInstruction` documentation for more details. */ class ElementsAddress extends UnaryOpcode, TElementsAddress { final override string toString() { result = "ElementsAddress" } } /** - * An operation that returns the address of a function. + * The `Opcode` for a `FunctionAddressInstruction`. + * + * See the `FunctionAddressInstruction` documentation for more details. */ class FunctionAddress extends Opcode, TFunctionAddress { final override string toString() { result = "FunctionAddress" } } /** - * An operation whose result is a constant value. + * The `Opcode` for a `ConstantInstruction`. + * + * See the `ConstantInstruction` documentation for more details. */ class Constant extends Opcode, TConstant { final override string toString() { result = "Constant" } } /** - * An operation whose result is the address of a string literal. + * The `Opcode` for a `StringConstantInstruction`. + * + * See the `StringConstantInstruction` documentation for more details. */ class StringConstant extends Opcode, TStringConstant { final override string toString() { result = "StringConstant" } } /** - * An operation that branches to one of two successor instructions based on the value of a Boolean - * operand. + * The `Opcode` for a `ConditionalBranchInstruction`. + * + * See the `ConditionalBranchInstruction` documentation for more details. */ class ConditionalBranch extends OpcodeWithCondition, TConditionalBranch { final override string toString() { result = "ConditionalBranch" } } /** - * An operation that branches to one of multiple successor instructions based on the value of an - * integer operand. + * The `Opcode` for a `SwitchInstruction`. + * + * See the `SwitchInstruction` documentation for more details. */ class Switch extends OpcodeWithCondition, TSwitch { final override string toString() { result = "Switch" } } /** - * An operation that calls a function. + * The `Opcode` for a `CallInstruction`. + * + * See the `CallInstruction` documentation for more details. */ class Call extends Opcode, TCall { final override string toString() { result = "Call" } @@ -801,42 +924,54 @@ module Opcode { } /** - * An operation that catches an exception of a specific type. + * The `Opcode` for a `CatchByTypeInstruction`. + * + * See the `CatchByTypeInstruction` documentation for more details. */ class CatchByType extends CatchOpcode, TCatchByType { final override string toString() { result = "CatchByType" } } /** - * An operation that catches any exception. + * The `Opcode` for a `CatchAnyInstruction`. + * + * See the `CatchAnyInstruction` documentation for more details. */ class CatchAny extends CatchOpcode, TCatchAny { final override string toString() { result = "CatchAny" } } /** - * An operation that throws a new exception. + * The `Opcode` for a `ThrowValueInstruction`. + * + * See the `ThrowValueInstruction` documentation for more details. */ class ThrowValue extends ThrowOpcode, OpcodeWithLoad, TThrowValue { final override string toString() { result = "ThrowValue" } } /** - * An operation that re-throws the current exception. + * The `Opcode` for a `ReThrowInstruction`. + * + * See the `ReThrowInstruction` documentation for more details. */ class ReThrow extends ThrowOpcode, TReThrow { final override string toString() { result = "ReThrow" } } /** - * An operation that exits the current function by propagating an exception. + * The `Opcode` for an `UnwindInstruction`. + * + * See the `UnwindInstruction` documentation for more details. */ class Unwind extends Opcode, TUnwind { final override string toString() { result = "Unwind" } } /** - * An operation that initializes all escaped memory. + * The `Opcode` for an `AliasedDefinitionInstruction`. + * + * See the `AliasedDefinitionInstruction` documentation for more details. */ class AliasedDefinition extends Opcode, TAliasedDefinition { final override string toString() { result = "AliasedDefinition" } @@ -845,7 +980,9 @@ module Opcode { } /** - * An operation that initializes all memory that existed before this function was called. + * The `Opcode` for an `InitializeNonLocalInstruction`. + * + * See the `InitializeNonLocalInstruction` documentation for more details. */ class InitializeNonLocal extends Opcode, TInitializeNonLocal { final override string toString() { result = "InitializeNonLocal" } @@ -856,7 +993,9 @@ module Opcode { } /** - * An operation that consumes all escaped memory on exit from the function. + * The `Opcode` for an `AliasedUseInstruction`. + * + * See the `AliasedUseInstruction` documentation for more details. */ class AliasedUse extends Opcode, TAliasedUse { final override string toString() { result = "AliasedUse" } @@ -869,7 +1008,9 @@ module Opcode { } /** - * An operation representing the choice of one of multiple input values based on control flow. + * The `Opcode` for a `PhiInstruction`. + * + * See the `PhiInstruction` documentation for more details. */ class Phi extends Opcode, TPhi { final override string toString() { result = "Phi" } @@ -878,45 +1019,54 @@ module Opcode { } /** - * An operation representing a built-in operation that does not have a specific opcode. The - * actual operation is specified by the `getBuiltInOperation()` predicate. + * The `Opcode` for a `BuiltInInstruction`. + * + * See the `BuiltInInstruction` documentation for more details. */ class BuiltIn extends BuiltInOperationOpcode, TBuiltIn { final override string toString() { result = "BuiltIn" } } /** - * An operation that returns a `va_list` to access the arguments passed to the `...` parameter. + * The `Opcode` for a `VarArgsStartInstruction`. + * + * See the `VarArgsStartInstruction` documentation for more details. */ class VarArgsStart extends UnaryOpcode, TVarArgsStart { final override string toString() { result = "VarArgsStart" } } /** - * An operation that cleans up a `va_list` after it is no longer in use. + * The `Opcode` for a `VarArgsEndInstruction`. + * + * See the `VarArgsEndInstruction` documentation for more details. */ class VarArgsEnd extends UnaryOpcode, TVarArgsEnd { final override string toString() { result = "VarArgsEnd" } } /** - * An operation that returns the address of the argument currently pointed to by a `va_list`. + * The `Opcode` for a `VarArgInstruction`. + * + * See the `VarArgInstruction` documentation for more details. */ class VarArg extends UnaryOpcode, TVarArg { final override string toString() { result = "VarArg" } } /** - * An operation that modifies a `va_list` to point to the next argument that was passed to the - * `...` parameter. + * The `Opcode` for a `NextVarArgInstruction`. + * + * See the `NextVarArgInstruction` documentation for more details. */ class NextVarArg extends UnaryOpcode, TNextVarArg { final override string toString() { result = "NextVarArg" } } /** - * An operation representing the side effect of a function call on any memory that might be - * accessed by that call. + * The `Opcode` for a `CallSideEffectInstruction`. + * + * See the `CallSideEffectInstruction` documentation for more details. */ class CallSideEffect extends WriteSideEffectOpcode, EscapedWriteOpcode, MayWriteOpcode, ReadSideEffectOpcode, EscapedReadOpcode, MayReadOpcode, TCallSideEffect { @@ -924,8 +1074,9 @@ module Opcode { } /** - * An operation representing the side effect of a function call on any memory - * that might be read by that call. + * The `Opcode` for a `CallReadSideEffectInstruction`. + * + * See the `CallReadSideEffectInstruction` documentation for more details. */ class CallReadSideEffect extends ReadSideEffectOpcode, EscapedReadOpcode, MayReadOpcode, TCallReadSideEffect { @@ -933,7 +1084,9 @@ module Opcode { } /** - * An operation representing the read of an indirect parameter within a function call. + * The `Opcode` for an `IndirectReadSideEffectInstruction`. + * + * See the `IndirectReadSideEffectInstruction` documentation for more details. */ class IndirectReadSideEffect extends ReadSideEffectOpcode, IndirectReadOpcode, TIndirectReadSideEffect { @@ -941,7 +1094,9 @@ module Opcode { } /** - * An operation representing the write of an indirect parameter within a function call. + * The `Opcode` for an `IndirectMustWriteSideEffectInstruction`. + * + * See the `IndirectMustWriteSideEffectInstruction` documentation for more details. */ class IndirectMustWriteSideEffect extends WriteSideEffectOpcode, IndirectWriteOpcode, TIndirectMustWriteSideEffect { @@ -949,7 +1104,9 @@ module Opcode { } /** - * An operation representing the potential write of an indirect parameter within a function call. + * The `Opcode` for an `IndirectMayWriteSideEffectInstruction`. + * + * See the `IndirectMayWriteSideEffectInstruction` documentation for more details. */ class IndirectMayWriteSideEffect extends WriteSideEffectOpcode, IndirectWriteOpcode, MayWriteOpcode, TIndirectMayWriteSideEffect { @@ -957,7 +1114,9 @@ module Opcode { } /** - * An operation representing the read of an indirect buffer parameter within a function call. + * The `Opcode` for a `BufferReadSideEffectInstruction`. + * + * See the `BufferReadSideEffectInstruction` documentation for more details. */ class BufferReadSideEffect extends ReadSideEffectOpcode, UnsizedBufferReadOpcode, TBufferReadSideEffect { @@ -965,8 +1124,9 @@ module Opcode { } /** - * An operation representing the write of an indirect buffer parameter within a function call. The - * entire buffer is overwritten. + * The `Opcode` for a `BufferMustWriteSideEffectInstruction`. + * + * See the `BufferMustWriteSideEffectInstruction` documentation for more details. */ class BufferMustWriteSideEffect extends WriteSideEffectOpcode, UnsizedBufferWriteOpcode, TBufferMustWriteSideEffect { @@ -974,7 +1134,9 @@ module Opcode { } /** - * An operation representing the write of an indirect buffer parameter within a function call. + * The `Opcode` for a `BufferMayWriteSideEffectInstruction`. + * + * See the `BufferMayWriteSideEffectInstruction` documentation for more details. */ class BufferMayWriteSideEffect extends WriteSideEffectOpcode, UnsizedBufferWriteOpcode, MayWriteOpcode, TBufferMayWriteSideEffect { @@ -982,7 +1144,9 @@ module Opcode { } /** - * An operation representing the read of an indirect buffer parameter within a function call. + * The `Opcode` for a `SizedBufferReadSideEffectInstruction`. + * + * See the `SizedBufferReadSideEffectInstruction` documentation for more details. */ class SizedBufferReadSideEffect extends ReadSideEffectOpcode, SizedBufferReadOpcode, TSizedBufferReadSideEffect { @@ -990,8 +1154,9 @@ module Opcode { } /** - * An operation representing the write of an indirect buffer parameter within a function call. The - * entire buffer is overwritten. + * The `Opcode` for a `SizedBufferMustWriteSideEffectInstruction`. + * + * See the `SizedBufferMustWriteSideEffectInstruction` documentation for more details. */ class SizedBufferMustWriteSideEffect extends WriteSideEffectOpcode, SizedBufferWriteOpcode, TSizedBufferMustWriteSideEffect { @@ -999,7 +1164,9 @@ module Opcode { } /** - * An operation representing the write of an indirect buffer parameter within a function call. + * The `Opcode` for a `SizedBufferMayWriteSideEffectInstruction`. + * + * See the `SizedBufferMayWriteSideEffectInstruction` documentation for more details. */ class SizedBufferMayWriteSideEffect extends WriteSideEffectOpcode, SizedBufferWriteOpcode, MayWriteOpcode, TSizedBufferMayWriteSideEffect { @@ -1007,8 +1174,9 @@ module Opcode { } /** - * An operation representing the initial value of newly allocated memory, such as the result of a - * call to `malloc`. + * The `Opcode` for an `InitializeDynamicAllocationInstruction`. + * + * See the `InitializeDynamicAllocationInstruction` documentation for more details. */ class InitializeDynamicAllocation extends SideEffectOpcode, EntireAllocationWriteOpcode, TInitializeDynamicAllocation { @@ -1016,8 +1184,9 @@ module Opcode { } /** - * An operation representing the effect that a write to a memory may have on potential aliases of - * that memory. + * The `Opcode` for a `ChiInstruction`. + * + * See the `ChiInstruction` documentation for more details. */ class Chi extends Opcode, TChi { final override string toString() { result = "Chi" } @@ -1034,7 +1203,9 @@ module Opcode { } /** - * An operation representing a GNU or MSVC inline assembly statement. + * The `Opcode` for an `InlineAsmInstruction`. + * + * See the `InlineAsmInstruction` documentation for more details. */ class InlineAsm extends Opcode, EscapedWriteOpcode, MayWriteOpcode, EscapedReadOpcode, MayReadOpcode, TInlineAsm { @@ -1046,14 +1217,18 @@ module Opcode { } /** - * An operation representing unreachable code. + * The `Opcode` for an `UnreachedInstruction`. + * + * See the `UnreachedInstruction` documentation for more details. */ class Unreached extends Opcode, TUnreached { final override string toString() { result = "Unreached" } } /** - * An operation that allocates a new object on the managed heap. + * The `Opcode` for a `NewObjInstruction`. + * + * See the `NewObjInstruction` documentation for more details. */ class NewObj extends Opcode, TNewObj { final override string toString() { result = "NewObj" } From 77bf564136323d05f522f9e84eb7c4806dbd25fe Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Fri, 26 Jun 2020 17:44:51 -0400 Subject: [PATCH 08/20] C++: Finish `Instruction.qll` QLDoc --- .../aliased_ssa/Instruction.qll | 59 +++++++++++++++++-- .../cpp/ir/implementation/raw/Instruction.qll | 59 +++++++++++++++++-- .../unaliased_ssa/Instruction.qll | 59 +++++++++++++++++-- .../ir/implementation/raw/Instruction.qll | 59 +++++++++++++++++-- .../unaliased_ssa/Instruction.qll | 59 +++++++++++++++++-- 5 files changed, 275 insertions(+), 20 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 e331a319cf8..0d2ad2d3bea 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 @@ -215,6 +215,15 @@ class Instruction extends Construction::TStageInstruction { result = Raw::getInstructionUnconvertedResultExpression(this) } + /** + * Gets the language-specific type of the result produced by this instruction. + * + * Most consumers of the IR should use `getResultIRType()` instead. `getResultIRType()` uses a + * less complex, language-neutral type system in which all semantically equivalent types share the + * same `IRType` instance. For example, in C++, four different `Instruction`s might have three + * different values for `getResultLanguageType()`: `unsigned int`, `char32_t`, and `wchar_t`, + * whereas all four instructions would have the same value for `getResultIRType()`, `uint4`. + */ final Language::LanguageType getResultLanguageType() { result = Construction::getInstructionResultType(this) } @@ -1178,8 +1187,14 @@ class PointerDiffInstruction extends PointerArithmeticInstruction { class UnaryInstruction extends Instruction { UnaryInstruction() { getOpcode() instanceof UnaryOpcode } + /** + * Gets the sole operand of this instruction. + */ final UnaryOperand getUnaryOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the sole operand of this instruction. + */ final Instruction getUnary() { result = getUnaryOperand().getDef() } } @@ -1621,7 +1636,15 @@ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { getOpcode() instanceof Opcode::SizedBufferReadSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes read from the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes read from the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** @@ -1631,7 +1654,15 @@ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { class WriteSideEffectInstruction extends SideEffectInstruction, IndexedInstruction { WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode } - Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() } + /** + * Get the operand that holds the address of the memory to be written. + */ + final AddressOperand getDestinationAddressOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the address of the memory to be written. + */ + Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() } } /** @@ -1662,7 +1693,15 @@ class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstructi getOpcode() instanceof Opcode::SizedBufferMustWriteSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes written to the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes written to the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** @@ -1696,7 +1735,15 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio getOpcode() instanceof Opcode::SizedBufferMayWriteSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes written to the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes written to the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** @@ -1941,6 +1988,10 @@ class BuiltInOperationInstruction extends Instruction { operation = Raw::getInstructionBuiltInOperation(this) } + /** + * Gets the language-specific `BuildInOperation` object that specifies the operation that is + * performed by this instruction. + */ final Language::BuiltInOperation getBuiltInOperation() { result = operation } } 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 e331a319cf8..0d2ad2d3bea 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 @@ -215,6 +215,15 @@ class Instruction extends Construction::TStageInstruction { result = Raw::getInstructionUnconvertedResultExpression(this) } + /** + * Gets the language-specific type of the result produced by this instruction. + * + * Most consumers of the IR should use `getResultIRType()` instead. `getResultIRType()` uses a + * less complex, language-neutral type system in which all semantically equivalent types share the + * same `IRType` instance. For example, in C++, four different `Instruction`s might have three + * different values for `getResultLanguageType()`: `unsigned int`, `char32_t`, and `wchar_t`, + * whereas all four instructions would have the same value for `getResultIRType()`, `uint4`. + */ final Language::LanguageType getResultLanguageType() { result = Construction::getInstructionResultType(this) } @@ -1178,8 +1187,14 @@ class PointerDiffInstruction extends PointerArithmeticInstruction { class UnaryInstruction extends Instruction { UnaryInstruction() { getOpcode() instanceof UnaryOpcode } + /** + * Gets the sole operand of this instruction. + */ final UnaryOperand getUnaryOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the sole operand of this instruction. + */ final Instruction getUnary() { result = getUnaryOperand().getDef() } } @@ -1621,7 +1636,15 @@ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { getOpcode() instanceof Opcode::SizedBufferReadSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes read from the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes read from the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** @@ -1631,7 +1654,15 @@ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { class WriteSideEffectInstruction extends SideEffectInstruction, IndexedInstruction { WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode } - Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() } + /** + * Get the operand that holds the address of the memory to be written. + */ + final AddressOperand getDestinationAddressOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the address of the memory to be written. + */ + Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() } } /** @@ -1662,7 +1693,15 @@ class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstructi getOpcode() instanceof Opcode::SizedBufferMustWriteSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes written to the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes written to the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** @@ -1696,7 +1735,15 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio getOpcode() instanceof Opcode::SizedBufferMayWriteSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes written to the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes written to the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** @@ -1941,6 +1988,10 @@ class BuiltInOperationInstruction extends Instruction { operation = Raw::getInstructionBuiltInOperation(this) } + /** + * Gets the language-specific `BuildInOperation` object that specifies the operation that is + * performed by this instruction. + */ final Language::BuiltInOperation getBuiltInOperation() { result = operation } } 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 e331a319cf8..0d2ad2d3bea 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 @@ -215,6 +215,15 @@ class Instruction extends Construction::TStageInstruction { result = Raw::getInstructionUnconvertedResultExpression(this) } + /** + * Gets the language-specific type of the result produced by this instruction. + * + * Most consumers of the IR should use `getResultIRType()` instead. `getResultIRType()` uses a + * less complex, language-neutral type system in which all semantically equivalent types share the + * same `IRType` instance. For example, in C++, four different `Instruction`s might have three + * different values for `getResultLanguageType()`: `unsigned int`, `char32_t`, and `wchar_t`, + * whereas all four instructions would have the same value for `getResultIRType()`, `uint4`. + */ final Language::LanguageType getResultLanguageType() { result = Construction::getInstructionResultType(this) } @@ -1178,8 +1187,14 @@ class PointerDiffInstruction extends PointerArithmeticInstruction { class UnaryInstruction extends Instruction { UnaryInstruction() { getOpcode() instanceof UnaryOpcode } + /** + * Gets the sole operand of this instruction. + */ final UnaryOperand getUnaryOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the sole operand of this instruction. + */ final Instruction getUnary() { result = getUnaryOperand().getDef() } } @@ -1621,7 +1636,15 @@ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { getOpcode() instanceof Opcode::SizedBufferReadSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes read from the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes read from the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** @@ -1631,7 +1654,15 @@ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { class WriteSideEffectInstruction extends SideEffectInstruction, IndexedInstruction { WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode } - Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() } + /** + * Get the operand that holds the address of the memory to be written. + */ + final AddressOperand getDestinationAddressOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the address of the memory to be written. + */ + Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() } } /** @@ -1662,7 +1693,15 @@ class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstructi getOpcode() instanceof Opcode::SizedBufferMustWriteSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes written to the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes written to the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** @@ -1696,7 +1735,15 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio getOpcode() instanceof Opcode::SizedBufferMayWriteSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes written to the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes written to the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** @@ -1941,6 +1988,10 @@ class BuiltInOperationInstruction extends Instruction { operation = Raw::getInstructionBuiltInOperation(this) } + /** + * Gets the language-specific `BuildInOperation` object that specifies the operation that is + * performed by this instruction. + */ final Language::BuiltInOperation getBuiltInOperation() { result = operation } } diff --git a/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll b/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll index e331a319cf8..0d2ad2d3bea 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll @@ -215,6 +215,15 @@ class Instruction extends Construction::TStageInstruction { result = Raw::getInstructionUnconvertedResultExpression(this) } + /** + * Gets the language-specific type of the result produced by this instruction. + * + * Most consumers of the IR should use `getResultIRType()` instead. `getResultIRType()` uses a + * less complex, language-neutral type system in which all semantically equivalent types share the + * same `IRType` instance. For example, in C++, four different `Instruction`s might have three + * different values for `getResultLanguageType()`: `unsigned int`, `char32_t`, and `wchar_t`, + * whereas all four instructions would have the same value for `getResultIRType()`, `uint4`. + */ final Language::LanguageType getResultLanguageType() { result = Construction::getInstructionResultType(this) } @@ -1178,8 +1187,14 @@ class PointerDiffInstruction extends PointerArithmeticInstruction { class UnaryInstruction extends Instruction { UnaryInstruction() { getOpcode() instanceof UnaryOpcode } + /** + * Gets the sole operand of this instruction. + */ final UnaryOperand getUnaryOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the sole operand of this instruction. + */ final Instruction getUnary() { result = getUnaryOperand().getDef() } } @@ -1621,7 +1636,15 @@ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { getOpcode() instanceof Opcode::SizedBufferReadSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes read from the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes read from the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** @@ -1631,7 +1654,15 @@ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { class WriteSideEffectInstruction extends SideEffectInstruction, IndexedInstruction { WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode } - Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() } + /** + * Get the operand that holds the address of the memory to be written. + */ + final AddressOperand getDestinationAddressOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the address of the memory to be written. + */ + Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() } } /** @@ -1662,7 +1693,15 @@ class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstructi getOpcode() instanceof Opcode::SizedBufferMustWriteSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes written to the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes written to the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** @@ -1696,7 +1735,15 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio getOpcode() instanceof Opcode::SizedBufferMayWriteSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes written to the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes written to the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** @@ -1941,6 +1988,10 @@ class BuiltInOperationInstruction extends Instruction { operation = Raw::getInstructionBuiltInOperation(this) } + /** + * Gets the language-specific `BuildInOperation` object that specifies the operation that is + * performed by this instruction. + */ final Language::BuiltInOperation getBuiltInOperation() { result = operation } } diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll index e331a319cf8..0d2ad2d3bea 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll @@ -215,6 +215,15 @@ class Instruction extends Construction::TStageInstruction { result = Raw::getInstructionUnconvertedResultExpression(this) } + /** + * Gets the language-specific type of the result produced by this instruction. + * + * Most consumers of the IR should use `getResultIRType()` instead. `getResultIRType()` uses a + * less complex, language-neutral type system in which all semantically equivalent types share the + * same `IRType` instance. For example, in C++, four different `Instruction`s might have three + * different values for `getResultLanguageType()`: `unsigned int`, `char32_t`, and `wchar_t`, + * whereas all four instructions would have the same value for `getResultIRType()`, `uint4`. + */ final Language::LanguageType getResultLanguageType() { result = Construction::getInstructionResultType(this) } @@ -1178,8 +1187,14 @@ class PointerDiffInstruction extends PointerArithmeticInstruction { class UnaryInstruction extends Instruction { UnaryInstruction() { getOpcode() instanceof UnaryOpcode } + /** + * Gets the sole operand of this instruction. + */ final UnaryOperand getUnaryOperand() { result = getAnOperand() } + /** + * Gets the instruction whose result provides the sole operand of this instruction. + */ final Instruction getUnary() { result = getUnaryOperand().getDef() } } @@ -1621,7 +1636,15 @@ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { getOpcode() instanceof Opcode::SizedBufferReadSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes read from the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes read from the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** @@ -1631,7 +1654,15 @@ class SizedBufferReadSideEffectInstruction extends ReadSideEffectInstruction { class WriteSideEffectInstruction extends SideEffectInstruction, IndexedInstruction { WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode } - Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() } + /** + * Get the operand that holds the address of the memory to be written. + */ + final AddressOperand getDestinationAddressOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the address of the memory to be written. + */ + Instruction getDestinationAddress() { result = getDestinationAddressOperand().getDef() } } /** @@ -1662,7 +1693,15 @@ class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstructi getOpcode() instanceof Opcode::SizedBufferMustWriteSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes written to the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes written to the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** @@ -1696,7 +1735,15 @@ class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstructio getOpcode() instanceof Opcode::SizedBufferMayWriteSideEffect } - Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() } + /** + * Gets the operand that holds the number of bytes written to the buffer. + */ + final BufferSizeOperand getBufferSizeOperand() { result = getAnOperand() } + + /** + * Gets the instruction whose result provides the number of bytes written to the buffer. + */ + final Instruction getBufferSize() { result = getBufferSizeOperand().getDef() } } /** @@ -1941,6 +1988,10 @@ class BuiltInOperationInstruction extends Instruction { operation = Raw::getInstructionBuiltInOperation(this) } + /** + * Gets the language-specific `BuildInOperation` object that specifies the operation that is + * performed by this instruction. + */ final Language::BuiltInOperation getBuiltInOperation() { result = operation } } From d0af9f5808dd325a32d55abae249ee0e67827f80 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Sun, 28 Jun 2020 09:31:33 -0400 Subject: [PATCH 09/20] C++: QLDoc all of `IRBlock.qll` --- .../ir/implementation/aliased_ssa/IRBlock.qll | 78 ++++++++++++++++++- .../cpp/ir/implementation/raw/IRBlock.qll | 78 ++++++++++++++++++- .../implementation/unaliased_ssa/IRBlock.qll | 78 ++++++++++++++++++- .../ir/implementation/raw/IRBlock.qll | 78 ++++++++++++++++++- .../implementation/unaliased_ssa/IRBlock.qll | 78 ++++++++++++++++++- 5 files changed, 375 insertions(+), 15 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll index 94ef73b2769..bff7b179604 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll @@ -1,3 +1,7 @@ +/** + * Provides classes describing basic blocks in the IR of a function. + */ + private import internal.IRInternal import Instruction private import internal.IRBlockImports as Imports @@ -18,13 +22,20 @@ private import Cached class IRBlockBase extends TIRBlock { final string toString() { result = getFirstInstruction(this).toString() } + /** Gets the source location of the first non-`Phi` instruction in this block. */ final Language::Location getLocation() { result = getFirstInstruction().getLocation() } + /** + * Gets a string that uniquely identifies this block within its enclosing function. + * + * This predicate is used by debugging and printing code only. + */ final string getUniqueId() { result = getFirstInstruction(this).getUniqueId() } /** - * Gets the zero-based index of the block within its function. This is used - * by debugging and printing code only. + * Gets the zero-based index of the block within its function. + * + * This predicate is used by debugging and printing code only. */ int getDisplayIndex() { exists(IRConfiguration::IRConfiguration config | @@ -42,27 +53,51 @@ class IRBlockBase extends TIRBlock { ) } + /** + * Gets the `index`th non-`Phi` instruction in this block. + */ final Instruction getInstruction(int index) { result = getInstruction(this, index) } + /** + * Get the `Phi` instructions that appear at the start of this block. + */ final PhiInstruction getAPhiInstruction() { Construction::getPhiInstructionBlockStart(result) = getFirstInstruction() } + /** + * Get the instructions in this block, including `Phi` instructions. + */ final Instruction getAnInstruction() { result = getInstruction(_) or result = getAPhiInstruction() } + /** + * Gets the first non-`Phi` instruction in this block. + */ final Instruction getFirstInstruction() { result = getFirstInstruction(this) } + /** + * Gets the last instruction in this block. + */ final Instruction getLastInstruction() { result = getInstruction(getInstructionCount() - 1) } + /** + * Gets the number of non-`Phi` instructions in this block. + */ final int getInstructionCount() { result = getInstructionCount(this) } + /** + * Gets the `IRFunction` that contains this block. + */ final IRFunction getEnclosingIRFunction() { result = getFirstInstruction(this).getEnclosingIRFunction() } + /** + * Gets the `Function` that contains this block. + */ final Language::Function getEnclosingFunction() { result = getFirstInstruction(this).getEnclosingFunction() } @@ -74,20 +109,57 @@ class IRBlockBase extends TIRBlock { * instruction of another block. */ class IRBlock extends IRBlockBase { + /** + * Gets the blocks to which control flows directly from this block. + */ final IRBlock getASuccessor() { blockSuccessor(this, result) } + /** + * Gets the blocks from which control flows directly to this block. + */ final IRBlock getAPredecessor() { blockSuccessor(result, this) } + /** + * Gets the block to which control flows directly from this block along an edge of kind `kind`. + */ final IRBlock getSuccessor(EdgeKind kind) { blockSuccessor(this, result, kind) } + /** + * Gets the block to which control flows directly from this block along a back edge of kind + * `kind`. + */ final IRBlock getBackEdgeSuccessor(EdgeKind kind) { backEdgeSuccessor(this, result, kind) } + /** + * Holds if this block immediately dominates `block`. + * + * Block `A` immediate dominates block `B` if block `A` strictly dominates block `B` and block `B` + * is a direct successor of block `A`. + */ final predicate immediatelyDominates(IRBlock block) { blockImmediatelyDominates(this, block) } + /** + * Holds if this block strictly dominates `block`. + * + * Block `A` strictly dominates block `B` if block `A` dominates block `B` and blocks `A` and `B` + * are not the same block. + */ final predicate strictlyDominates(IRBlock block) { blockImmediatelyDominates+(this, block) } + /** + * Holds if this block dominates `block`. + * + * Block `A` dominates block `B` if any control flow path from the entry block of the function to + * block `B` must pass through block `A`. A block always dominates itself. + */ final predicate dominates(IRBlock block) { strictlyDominates(block) or this = block } + /** + * Gets the set of blocks on the dominance frontier of this block. + * + * The dominance frontier of block `A` is the set of blocks `B` such that block `A` does not + * dominate block `B`, but block `A` does dominate an immediate predecessor of block `B`. + */ pragma[noinline] final IRBlock dominanceFrontier() { dominates(result.getAPredecessor()) and @@ -95,7 +167,7 @@ class IRBlock extends IRBlockBase { } /** - * Holds if this block is reachable from the entry point of its function + * Holds if this block is reachable from the entry block of its function. */ final predicate isReachableFromFunctionEntry() { this = getEnclosingIRFunction().getEntryBlock() or diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll index 94ef73b2769..bff7b179604 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll @@ -1,3 +1,7 @@ +/** + * Provides classes describing basic blocks in the IR of a function. + */ + private import internal.IRInternal import Instruction private import internal.IRBlockImports as Imports @@ -18,13 +22,20 @@ private import Cached class IRBlockBase extends TIRBlock { final string toString() { result = getFirstInstruction(this).toString() } + /** Gets the source location of the first non-`Phi` instruction in this block. */ final Language::Location getLocation() { result = getFirstInstruction().getLocation() } + /** + * Gets a string that uniquely identifies this block within its enclosing function. + * + * This predicate is used by debugging and printing code only. + */ final string getUniqueId() { result = getFirstInstruction(this).getUniqueId() } /** - * Gets the zero-based index of the block within its function. This is used - * by debugging and printing code only. + * Gets the zero-based index of the block within its function. + * + * This predicate is used by debugging and printing code only. */ int getDisplayIndex() { exists(IRConfiguration::IRConfiguration config | @@ -42,27 +53,51 @@ class IRBlockBase extends TIRBlock { ) } + /** + * Gets the `index`th non-`Phi` instruction in this block. + */ final Instruction getInstruction(int index) { result = getInstruction(this, index) } + /** + * Get the `Phi` instructions that appear at the start of this block. + */ final PhiInstruction getAPhiInstruction() { Construction::getPhiInstructionBlockStart(result) = getFirstInstruction() } + /** + * Get the instructions in this block, including `Phi` instructions. + */ final Instruction getAnInstruction() { result = getInstruction(_) or result = getAPhiInstruction() } + /** + * Gets the first non-`Phi` instruction in this block. + */ final Instruction getFirstInstruction() { result = getFirstInstruction(this) } + /** + * Gets the last instruction in this block. + */ final Instruction getLastInstruction() { result = getInstruction(getInstructionCount() - 1) } + /** + * Gets the number of non-`Phi` instructions in this block. + */ final int getInstructionCount() { result = getInstructionCount(this) } + /** + * Gets the `IRFunction` that contains this block. + */ final IRFunction getEnclosingIRFunction() { result = getFirstInstruction(this).getEnclosingIRFunction() } + /** + * Gets the `Function` that contains this block. + */ final Language::Function getEnclosingFunction() { result = getFirstInstruction(this).getEnclosingFunction() } @@ -74,20 +109,57 @@ class IRBlockBase extends TIRBlock { * instruction of another block. */ class IRBlock extends IRBlockBase { + /** + * Gets the blocks to which control flows directly from this block. + */ final IRBlock getASuccessor() { blockSuccessor(this, result) } + /** + * Gets the blocks from which control flows directly to this block. + */ final IRBlock getAPredecessor() { blockSuccessor(result, this) } + /** + * Gets the block to which control flows directly from this block along an edge of kind `kind`. + */ final IRBlock getSuccessor(EdgeKind kind) { blockSuccessor(this, result, kind) } + /** + * Gets the block to which control flows directly from this block along a back edge of kind + * `kind`. + */ final IRBlock getBackEdgeSuccessor(EdgeKind kind) { backEdgeSuccessor(this, result, kind) } + /** + * Holds if this block immediately dominates `block`. + * + * Block `A` immediate dominates block `B` if block `A` strictly dominates block `B` and block `B` + * is a direct successor of block `A`. + */ final predicate immediatelyDominates(IRBlock block) { blockImmediatelyDominates(this, block) } + /** + * Holds if this block strictly dominates `block`. + * + * Block `A` strictly dominates block `B` if block `A` dominates block `B` and blocks `A` and `B` + * are not the same block. + */ final predicate strictlyDominates(IRBlock block) { blockImmediatelyDominates+(this, block) } + /** + * Holds if this block dominates `block`. + * + * Block `A` dominates block `B` if any control flow path from the entry block of the function to + * block `B` must pass through block `A`. A block always dominates itself. + */ final predicate dominates(IRBlock block) { strictlyDominates(block) or this = block } + /** + * Gets the set of blocks on the dominance frontier of this block. + * + * The dominance frontier of block `A` is the set of blocks `B` such that block `A` does not + * dominate block `B`, but block `A` does dominate an immediate predecessor of block `B`. + */ pragma[noinline] final IRBlock dominanceFrontier() { dominates(result.getAPredecessor()) and @@ -95,7 +167,7 @@ class IRBlock extends IRBlockBase { } /** - * Holds if this block is reachable from the entry point of its function + * Holds if this block is reachable from the entry block of its function. */ final predicate isReachableFromFunctionEntry() { this = getEnclosingIRFunction().getEntryBlock() or diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll index 94ef73b2769..bff7b179604 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll @@ -1,3 +1,7 @@ +/** + * Provides classes describing basic blocks in the IR of a function. + */ + private import internal.IRInternal import Instruction private import internal.IRBlockImports as Imports @@ -18,13 +22,20 @@ private import Cached class IRBlockBase extends TIRBlock { final string toString() { result = getFirstInstruction(this).toString() } + /** Gets the source location of the first non-`Phi` instruction in this block. */ final Language::Location getLocation() { result = getFirstInstruction().getLocation() } + /** + * Gets a string that uniquely identifies this block within its enclosing function. + * + * This predicate is used by debugging and printing code only. + */ final string getUniqueId() { result = getFirstInstruction(this).getUniqueId() } /** - * Gets the zero-based index of the block within its function. This is used - * by debugging and printing code only. + * Gets the zero-based index of the block within its function. + * + * This predicate is used by debugging and printing code only. */ int getDisplayIndex() { exists(IRConfiguration::IRConfiguration config | @@ -42,27 +53,51 @@ class IRBlockBase extends TIRBlock { ) } + /** + * Gets the `index`th non-`Phi` instruction in this block. + */ final Instruction getInstruction(int index) { result = getInstruction(this, index) } + /** + * Get the `Phi` instructions that appear at the start of this block. + */ final PhiInstruction getAPhiInstruction() { Construction::getPhiInstructionBlockStart(result) = getFirstInstruction() } + /** + * Get the instructions in this block, including `Phi` instructions. + */ final Instruction getAnInstruction() { result = getInstruction(_) or result = getAPhiInstruction() } + /** + * Gets the first non-`Phi` instruction in this block. + */ final Instruction getFirstInstruction() { result = getFirstInstruction(this) } + /** + * Gets the last instruction in this block. + */ final Instruction getLastInstruction() { result = getInstruction(getInstructionCount() - 1) } + /** + * Gets the number of non-`Phi` instructions in this block. + */ final int getInstructionCount() { result = getInstructionCount(this) } + /** + * Gets the `IRFunction` that contains this block. + */ final IRFunction getEnclosingIRFunction() { result = getFirstInstruction(this).getEnclosingIRFunction() } + /** + * Gets the `Function` that contains this block. + */ final Language::Function getEnclosingFunction() { result = getFirstInstruction(this).getEnclosingFunction() } @@ -74,20 +109,57 @@ class IRBlockBase extends TIRBlock { * instruction of another block. */ class IRBlock extends IRBlockBase { + /** + * Gets the blocks to which control flows directly from this block. + */ final IRBlock getASuccessor() { blockSuccessor(this, result) } + /** + * Gets the blocks from which control flows directly to this block. + */ final IRBlock getAPredecessor() { blockSuccessor(result, this) } + /** + * Gets the block to which control flows directly from this block along an edge of kind `kind`. + */ final IRBlock getSuccessor(EdgeKind kind) { blockSuccessor(this, result, kind) } + /** + * Gets the block to which control flows directly from this block along a back edge of kind + * `kind`. + */ final IRBlock getBackEdgeSuccessor(EdgeKind kind) { backEdgeSuccessor(this, result, kind) } + /** + * Holds if this block immediately dominates `block`. + * + * Block `A` immediate dominates block `B` if block `A` strictly dominates block `B` and block `B` + * is a direct successor of block `A`. + */ final predicate immediatelyDominates(IRBlock block) { blockImmediatelyDominates(this, block) } + /** + * Holds if this block strictly dominates `block`. + * + * Block `A` strictly dominates block `B` if block `A` dominates block `B` and blocks `A` and `B` + * are not the same block. + */ final predicate strictlyDominates(IRBlock block) { blockImmediatelyDominates+(this, block) } + /** + * Holds if this block dominates `block`. + * + * Block `A` dominates block `B` if any control flow path from the entry block of the function to + * block `B` must pass through block `A`. A block always dominates itself. + */ final predicate dominates(IRBlock block) { strictlyDominates(block) or this = block } + /** + * Gets the set of blocks on the dominance frontier of this block. + * + * The dominance frontier of block `A` is the set of blocks `B` such that block `A` does not + * dominate block `B`, but block `A` does dominate an immediate predecessor of block `B`. + */ pragma[noinline] final IRBlock dominanceFrontier() { dominates(result.getAPredecessor()) and @@ -95,7 +167,7 @@ class IRBlock extends IRBlockBase { } /** - * Holds if this block is reachable from the entry point of its function + * Holds if this block is reachable from the entry block of its function. */ final predicate isReachableFromFunctionEntry() { this = getEnclosingIRFunction().getEntryBlock() or diff --git a/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll b/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll index 94ef73b2769..bff7b179604 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll @@ -1,3 +1,7 @@ +/** + * Provides classes describing basic blocks in the IR of a function. + */ + private import internal.IRInternal import Instruction private import internal.IRBlockImports as Imports @@ -18,13 +22,20 @@ private import Cached class IRBlockBase extends TIRBlock { final string toString() { result = getFirstInstruction(this).toString() } + /** Gets the source location of the first non-`Phi` instruction in this block. */ final Language::Location getLocation() { result = getFirstInstruction().getLocation() } + /** + * Gets a string that uniquely identifies this block within its enclosing function. + * + * This predicate is used by debugging and printing code only. + */ final string getUniqueId() { result = getFirstInstruction(this).getUniqueId() } /** - * Gets the zero-based index of the block within its function. This is used - * by debugging and printing code only. + * Gets the zero-based index of the block within its function. + * + * This predicate is used by debugging and printing code only. */ int getDisplayIndex() { exists(IRConfiguration::IRConfiguration config | @@ -42,27 +53,51 @@ class IRBlockBase extends TIRBlock { ) } + /** + * Gets the `index`th non-`Phi` instruction in this block. + */ final Instruction getInstruction(int index) { result = getInstruction(this, index) } + /** + * Get the `Phi` instructions that appear at the start of this block. + */ final PhiInstruction getAPhiInstruction() { Construction::getPhiInstructionBlockStart(result) = getFirstInstruction() } + /** + * Get the instructions in this block, including `Phi` instructions. + */ final Instruction getAnInstruction() { result = getInstruction(_) or result = getAPhiInstruction() } + /** + * Gets the first non-`Phi` instruction in this block. + */ final Instruction getFirstInstruction() { result = getFirstInstruction(this) } + /** + * Gets the last instruction in this block. + */ final Instruction getLastInstruction() { result = getInstruction(getInstructionCount() - 1) } + /** + * Gets the number of non-`Phi` instructions in this block. + */ final int getInstructionCount() { result = getInstructionCount(this) } + /** + * Gets the `IRFunction` that contains this block. + */ final IRFunction getEnclosingIRFunction() { result = getFirstInstruction(this).getEnclosingIRFunction() } + /** + * Gets the `Function` that contains this block. + */ final Language::Function getEnclosingFunction() { result = getFirstInstruction(this).getEnclosingFunction() } @@ -74,20 +109,57 @@ class IRBlockBase extends TIRBlock { * instruction of another block. */ class IRBlock extends IRBlockBase { + /** + * Gets the blocks to which control flows directly from this block. + */ final IRBlock getASuccessor() { blockSuccessor(this, result) } + /** + * Gets the blocks from which control flows directly to this block. + */ final IRBlock getAPredecessor() { blockSuccessor(result, this) } + /** + * Gets the block to which control flows directly from this block along an edge of kind `kind`. + */ final IRBlock getSuccessor(EdgeKind kind) { blockSuccessor(this, result, kind) } + /** + * Gets the block to which control flows directly from this block along a back edge of kind + * `kind`. + */ final IRBlock getBackEdgeSuccessor(EdgeKind kind) { backEdgeSuccessor(this, result, kind) } + /** + * Holds if this block immediately dominates `block`. + * + * Block `A` immediate dominates block `B` if block `A` strictly dominates block `B` and block `B` + * is a direct successor of block `A`. + */ final predicate immediatelyDominates(IRBlock block) { blockImmediatelyDominates(this, block) } + /** + * Holds if this block strictly dominates `block`. + * + * Block `A` strictly dominates block `B` if block `A` dominates block `B` and blocks `A` and `B` + * are not the same block. + */ final predicate strictlyDominates(IRBlock block) { blockImmediatelyDominates+(this, block) } + /** + * Holds if this block dominates `block`. + * + * Block `A` dominates block `B` if any control flow path from the entry block of the function to + * block `B` must pass through block `A`. A block always dominates itself. + */ final predicate dominates(IRBlock block) { strictlyDominates(block) or this = block } + /** + * Gets the set of blocks on the dominance frontier of this block. + * + * The dominance frontier of block `A` is the set of blocks `B` such that block `A` does not + * dominate block `B`, but block `A` does dominate an immediate predecessor of block `B`. + */ pragma[noinline] final IRBlock dominanceFrontier() { dominates(result.getAPredecessor()) and @@ -95,7 +167,7 @@ class IRBlock extends IRBlockBase { } /** - * Holds if this block is reachable from the entry point of its function + * Holds if this block is reachable from the entry block of its function. */ final predicate isReachableFromFunctionEntry() { this = getEnclosingIRFunction().getEntryBlock() or diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll index 94ef73b2769..bff7b179604 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll @@ -1,3 +1,7 @@ +/** + * Provides classes describing basic blocks in the IR of a function. + */ + private import internal.IRInternal import Instruction private import internal.IRBlockImports as Imports @@ -18,13 +22,20 @@ private import Cached class IRBlockBase extends TIRBlock { final string toString() { result = getFirstInstruction(this).toString() } + /** Gets the source location of the first non-`Phi` instruction in this block. */ final Language::Location getLocation() { result = getFirstInstruction().getLocation() } + /** + * Gets a string that uniquely identifies this block within its enclosing function. + * + * This predicate is used by debugging and printing code only. + */ final string getUniqueId() { result = getFirstInstruction(this).getUniqueId() } /** - * Gets the zero-based index of the block within its function. This is used - * by debugging and printing code only. + * Gets the zero-based index of the block within its function. + * + * This predicate is used by debugging and printing code only. */ int getDisplayIndex() { exists(IRConfiguration::IRConfiguration config | @@ -42,27 +53,51 @@ class IRBlockBase extends TIRBlock { ) } + /** + * Gets the `index`th non-`Phi` instruction in this block. + */ final Instruction getInstruction(int index) { result = getInstruction(this, index) } + /** + * Get the `Phi` instructions that appear at the start of this block. + */ final PhiInstruction getAPhiInstruction() { Construction::getPhiInstructionBlockStart(result) = getFirstInstruction() } + /** + * Get the instructions in this block, including `Phi` instructions. + */ final Instruction getAnInstruction() { result = getInstruction(_) or result = getAPhiInstruction() } + /** + * Gets the first non-`Phi` instruction in this block. + */ final Instruction getFirstInstruction() { result = getFirstInstruction(this) } + /** + * Gets the last instruction in this block. + */ final Instruction getLastInstruction() { result = getInstruction(getInstructionCount() - 1) } + /** + * Gets the number of non-`Phi` instructions in this block. + */ final int getInstructionCount() { result = getInstructionCount(this) } + /** + * Gets the `IRFunction` that contains this block. + */ final IRFunction getEnclosingIRFunction() { result = getFirstInstruction(this).getEnclosingIRFunction() } + /** + * Gets the `Function` that contains this block. + */ final Language::Function getEnclosingFunction() { result = getFirstInstruction(this).getEnclosingFunction() } @@ -74,20 +109,57 @@ class IRBlockBase extends TIRBlock { * instruction of another block. */ class IRBlock extends IRBlockBase { + /** + * Gets the blocks to which control flows directly from this block. + */ final IRBlock getASuccessor() { blockSuccessor(this, result) } + /** + * Gets the blocks from which control flows directly to this block. + */ final IRBlock getAPredecessor() { blockSuccessor(result, this) } + /** + * Gets the block to which control flows directly from this block along an edge of kind `kind`. + */ final IRBlock getSuccessor(EdgeKind kind) { blockSuccessor(this, result, kind) } + /** + * Gets the block to which control flows directly from this block along a back edge of kind + * `kind`. + */ final IRBlock getBackEdgeSuccessor(EdgeKind kind) { backEdgeSuccessor(this, result, kind) } + /** + * Holds if this block immediately dominates `block`. + * + * Block `A` immediate dominates block `B` if block `A` strictly dominates block `B` and block `B` + * is a direct successor of block `A`. + */ final predicate immediatelyDominates(IRBlock block) { blockImmediatelyDominates(this, block) } + /** + * Holds if this block strictly dominates `block`. + * + * Block `A` strictly dominates block `B` if block `A` dominates block `B` and blocks `A` and `B` + * are not the same block. + */ final predicate strictlyDominates(IRBlock block) { blockImmediatelyDominates+(this, block) } + /** + * Holds if this block dominates `block`. + * + * Block `A` dominates block `B` if any control flow path from the entry block of the function to + * block `B` must pass through block `A`. A block always dominates itself. + */ final predicate dominates(IRBlock block) { strictlyDominates(block) or this = block } + /** + * Gets the set of blocks on the dominance frontier of this block. + * + * The dominance frontier of block `A` is the set of blocks `B` such that block `A` does not + * dominate block `B`, but block `A` does dominate an immediate predecessor of block `B`. + */ pragma[noinline] final IRBlock dominanceFrontier() { dominates(result.getAPredecessor()) and @@ -95,7 +167,7 @@ class IRBlock extends IRBlockBase { } /** - * Holds if this block is reachable from the entry point of its function + * Holds if this block is reachable from the entry block of its function. */ final predicate isReachableFromFunctionEntry() { this = getEnclosingIRFunction().getEntryBlock() or From 88f89b3334a44bcfeeabfe2ebcad60c6d8a1de46 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Sun, 28 Jun 2020 09:33:16 -0400 Subject: [PATCH 10/20] C++: QLDoc for `IRFunction.qll` --- .../code/cpp/ir/implementation/aliased_ssa/IRFunction.qll | 5 +++++ .../src/semmle/code/cpp/ir/implementation/raw/IRFunction.qll | 5 +++++ .../code/cpp/ir/implementation/unaliased_ssa/IRFunction.qll | 5 +++++ .../ql/src/experimental/ir/implementation/raw/IRFunction.qll | 5 +++++ .../ir/implementation/unaliased_ssa/IRFunction.qll | 5 +++++ 5 files changed, 25 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRFunction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRFunction.qll index 6b2d32af48c..5968e58f90b 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRFunction.qll @@ -1,3 +1,8 @@ +/** + * Provides the class `IRFunction`, which represents the Intermediate Representation for the + * definition of a function. + */ + private import internal.IRInternal private import internal.IRFunctionImports as Imports import Imports::IRFunctionBase diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRFunction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRFunction.qll index 6b2d32af48c..5968e58f90b 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRFunction.qll @@ -1,3 +1,8 @@ +/** + * Provides the class `IRFunction`, which represents the Intermediate Representation for the + * definition of a function. + */ + private import internal.IRInternal private import internal.IRFunctionImports as Imports import Imports::IRFunctionBase diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRFunction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRFunction.qll index 6b2d32af48c..5968e58f90b 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRFunction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRFunction.qll @@ -1,3 +1,8 @@ +/** + * Provides the class `IRFunction`, which represents the Intermediate Representation for the + * definition of a function. + */ + private import internal.IRInternal private import internal.IRFunctionImports as Imports import Imports::IRFunctionBase diff --git a/csharp/ql/src/experimental/ir/implementation/raw/IRFunction.qll b/csharp/ql/src/experimental/ir/implementation/raw/IRFunction.qll index 6b2d32af48c..5968e58f90b 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/IRFunction.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/IRFunction.qll @@ -1,3 +1,8 @@ +/** + * Provides the class `IRFunction`, which represents the Intermediate Representation for the + * definition of a function. + */ + private import internal.IRInternal private import internal.IRFunctionImports as Imports import Imports::IRFunctionBase diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRFunction.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRFunction.qll index 6b2d32af48c..5968e58f90b 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRFunction.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRFunction.qll @@ -1,3 +1,8 @@ +/** + * Provides the class `IRFunction`, which represents the Intermediate Representation for the + * definition of a function. + */ + private import internal.IRInternal private import internal.IRFunctionImports as Imports import Imports::IRFunctionBase From 98348a935339eb9c3474065f74ac4dc9bd2f64e5 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Sun, 28 Jun 2020 09:55:38 -0400 Subject: [PATCH 11/20] C++: QLDoc for `IR.qll` --- .../cpp/ir/implementation/aliased_ssa/IR.qll | 47 ++++++++++++++++++- .../code/cpp/ir/implementation/raw/IR.qll | 47 ++++++++++++++++++- .../ir/implementation/unaliased_ssa/IR.qll | 47 ++++++++++++++++++- .../experimental/ir/implementation/raw/IR.qll | 47 ++++++++++++++++++- .../ir/implementation/unaliased_ssa/IR.qll | 47 ++++++++++++++++++- 5 files changed, 230 insertions(+), 5 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IR.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IR.qll index badd48552a5..766ec052da3 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IR.qll @@ -1,3 +1,47 @@ +/** + * Provides classes that describe the Intermediate Representation (IR) of the program. + * + * The IR is a representation of the semantics of the program, with very little dependence on the + * syntax that was used to write the program. For example, in C++, the statements `i += 1;`, `i++`, + * and `++i` all have the same semantic effect, but appear in the AST as three different types of + * `Expr` node. In the IR, all three statements are broken down into a sequence of fundamental + * operations similar to: + * + * ``` + * r1(int*) = VariableAddress[i] // Compute the address of variable `i` + * r2(int) = Load &:r1, m0 // Load the value of `i` + * r3(int) = Constant[1] // An integer constant with the value `1` + * r4(int) = Add r2, r3 // Add `1` to the value of `i` + * r5(int) = Store &r1, r4 // Store the new value back into the variable `i` + * ``` + * + * This allows IR-based analysis to focus on the fundamental operations, rather than having to be + * concerned with the various ways of expressing those operations in source code. + * + * The key classes in the IR are: + * + * - `IRFunction` - Contains the IR for an entire function definition, including all of that + * function's `Instruction`s, `IRBlock`s, and `IRVariables`. + * - `Instruction` - A single operation in the IR. An instruction specifies the operation to be + * performed, the operands that produce the inputs to that operation, and the type of the result + * of the operation. Control flows from an `Instruction` to one of a set of successor + * `Instruction`s. + * - `Operand` - An input value of an `Instruction`. All inputs of an `Instruction` are explicitly + * represented as `Operand`s, even if the input was implicit in the source code. An `Operand` has + * a link to the `Instruction` that consumes its value (its "use") and a link to the `Instruction` + * that produces its value (its "definition"). + * - `IRVariable` - A variable accessed by the IR for a particular function. An `IRVariable` is + * created for each variable directly accessed by the function. In addition, `IRVariable`s are + * created to represent certain temporary storage locations that do not have explicitly declared + * variables in the source code, such as the return value of the function. + * - `IRBlock` - A "basic block" in the control flow graph of a function. An `IRBlock` contains a + * sequence of instructions such that control flow can only enter the block at the first + * instruction, and can only leave the block from the last instruction. + * - `IRType` - The type of a value accessed in the IR. Unlike the `Type` class in the AST, `IRType` + * is language-neutral. For example, in C++, `unsigned int`, `char32_t`, and `wchar_t` might all + * be represented as the `IRType` `uint4`, a four-byte unsigned integer. + */ + import IRFunction import Instruction import IRBlock @@ -11,11 +55,12 @@ import Imports::MemoryAccessKind private newtype TIRPropertyProvider = MkIRPropertyProvider() /** - * Class that provides additional properties to be dumped for IR instructions and blocks when using + * A class that provides additional properties to be dumped for IR instructions and blocks when using * the PrintIR module. Libraries that compute additional facts about IR elements can extend the * single instance of this class to specify the additional properties computed by the library. */ class IRPropertyProvider extends TIRPropertyProvider { + /** Gets a textual representation of this element. */ string toString() { result = "IRPropertyProvider" } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IR.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IR.qll index badd48552a5..766ec052da3 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IR.qll @@ -1,3 +1,47 @@ +/** + * Provides classes that describe the Intermediate Representation (IR) of the program. + * + * The IR is a representation of the semantics of the program, with very little dependence on the + * syntax that was used to write the program. For example, in C++, the statements `i += 1;`, `i++`, + * and `++i` all have the same semantic effect, but appear in the AST as three different types of + * `Expr` node. In the IR, all three statements are broken down into a sequence of fundamental + * operations similar to: + * + * ``` + * r1(int*) = VariableAddress[i] // Compute the address of variable `i` + * r2(int) = Load &:r1, m0 // Load the value of `i` + * r3(int) = Constant[1] // An integer constant with the value `1` + * r4(int) = Add r2, r3 // Add `1` to the value of `i` + * r5(int) = Store &r1, r4 // Store the new value back into the variable `i` + * ``` + * + * This allows IR-based analysis to focus on the fundamental operations, rather than having to be + * concerned with the various ways of expressing those operations in source code. + * + * The key classes in the IR are: + * + * - `IRFunction` - Contains the IR for an entire function definition, including all of that + * function's `Instruction`s, `IRBlock`s, and `IRVariables`. + * - `Instruction` - A single operation in the IR. An instruction specifies the operation to be + * performed, the operands that produce the inputs to that operation, and the type of the result + * of the operation. Control flows from an `Instruction` to one of a set of successor + * `Instruction`s. + * - `Operand` - An input value of an `Instruction`. All inputs of an `Instruction` are explicitly + * represented as `Operand`s, even if the input was implicit in the source code. An `Operand` has + * a link to the `Instruction` that consumes its value (its "use") and a link to the `Instruction` + * that produces its value (its "definition"). + * - `IRVariable` - A variable accessed by the IR for a particular function. An `IRVariable` is + * created for each variable directly accessed by the function. In addition, `IRVariable`s are + * created to represent certain temporary storage locations that do not have explicitly declared + * variables in the source code, such as the return value of the function. + * - `IRBlock` - A "basic block" in the control flow graph of a function. An `IRBlock` contains a + * sequence of instructions such that control flow can only enter the block at the first + * instruction, and can only leave the block from the last instruction. + * - `IRType` - The type of a value accessed in the IR. Unlike the `Type` class in the AST, `IRType` + * is language-neutral. For example, in C++, `unsigned int`, `char32_t`, and `wchar_t` might all + * be represented as the `IRType` `uint4`, a four-byte unsigned integer. + */ + import IRFunction import Instruction import IRBlock @@ -11,11 +55,12 @@ import Imports::MemoryAccessKind private newtype TIRPropertyProvider = MkIRPropertyProvider() /** - * Class that provides additional properties to be dumped for IR instructions and blocks when using + * A class that provides additional properties to be dumped for IR instructions and blocks when using * the PrintIR module. Libraries that compute additional facts about IR elements can extend the * single instance of this class to specify the additional properties computed by the library. */ class IRPropertyProvider extends TIRPropertyProvider { + /** Gets a textual representation of this element. */ string toString() { result = "IRPropertyProvider" } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IR.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IR.qll index badd48552a5..766ec052da3 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IR.qll @@ -1,3 +1,47 @@ +/** + * Provides classes that describe the Intermediate Representation (IR) of the program. + * + * The IR is a representation of the semantics of the program, with very little dependence on the + * syntax that was used to write the program. For example, in C++, the statements `i += 1;`, `i++`, + * and `++i` all have the same semantic effect, but appear in the AST as three different types of + * `Expr` node. In the IR, all three statements are broken down into a sequence of fundamental + * operations similar to: + * + * ``` + * r1(int*) = VariableAddress[i] // Compute the address of variable `i` + * r2(int) = Load &:r1, m0 // Load the value of `i` + * r3(int) = Constant[1] // An integer constant with the value `1` + * r4(int) = Add r2, r3 // Add `1` to the value of `i` + * r5(int) = Store &r1, r4 // Store the new value back into the variable `i` + * ``` + * + * This allows IR-based analysis to focus on the fundamental operations, rather than having to be + * concerned with the various ways of expressing those operations in source code. + * + * The key classes in the IR are: + * + * - `IRFunction` - Contains the IR for an entire function definition, including all of that + * function's `Instruction`s, `IRBlock`s, and `IRVariables`. + * - `Instruction` - A single operation in the IR. An instruction specifies the operation to be + * performed, the operands that produce the inputs to that operation, and the type of the result + * of the operation. Control flows from an `Instruction` to one of a set of successor + * `Instruction`s. + * - `Operand` - An input value of an `Instruction`. All inputs of an `Instruction` are explicitly + * represented as `Operand`s, even if the input was implicit in the source code. An `Operand` has + * a link to the `Instruction` that consumes its value (its "use") and a link to the `Instruction` + * that produces its value (its "definition"). + * - `IRVariable` - A variable accessed by the IR for a particular function. An `IRVariable` is + * created for each variable directly accessed by the function. In addition, `IRVariable`s are + * created to represent certain temporary storage locations that do not have explicitly declared + * variables in the source code, such as the return value of the function. + * - `IRBlock` - A "basic block" in the control flow graph of a function. An `IRBlock` contains a + * sequence of instructions such that control flow can only enter the block at the first + * instruction, and can only leave the block from the last instruction. + * - `IRType` - The type of a value accessed in the IR. Unlike the `Type` class in the AST, `IRType` + * is language-neutral. For example, in C++, `unsigned int`, `char32_t`, and `wchar_t` might all + * be represented as the `IRType` `uint4`, a four-byte unsigned integer. + */ + import IRFunction import Instruction import IRBlock @@ -11,11 +55,12 @@ import Imports::MemoryAccessKind private newtype TIRPropertyProvider = MkIRPropertyProvider() /** - * Class that provides additional properties to be dumped for IR instructions and blocks when using + * A class that provides additional properties to be dumped for IR instructions and blocks when using * the PrintIR module. Libraries that compute additional facts about IR elements can extend the * single instance of this class to specify the additional properties computed by the library. */ class IRPropertyProvider extends TIRPropertyProvider { + /** Gets a textual representation of this element. */ string toString() { result = "IRPropertyProvider" } /** diff --git a/csharp/ql/src/experimental/ir/implementation/raw/IR.qll b/csharp/ql/src/experimental/ir/implementation/raw/IR.qll index badd48552a5..766ec052da3 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/IR.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/IR.qll @@ -1,3 +1,47 @@ +/** + * Provides classes that describe the Intermediate Representation (IR) of the program. + * + * The IR is a representation of the semantics of the program, with very little dependence on the + * syntax that was used to write the program. For example, in C++, the statements `i += 1;`, `i++`, + * and `++i` all have the same semantic effect, but appear in the AST as three different types of + * `Expr` node. In the IR, all three statements are broken down into a sequence of fundamental + * operations similar to: + * + * ``` + * r1(int*) = VariableAddress[i] // Compute the address of variable `i` + * r2(int) = Load &:r1, m0 // Load the value of `i` + * r3(int) = Constant[1] // An integer constant with the value `1` + * r4(int) = Add r2, r3 // Add `1` to the value of `i` + * r5(int) = Store &r1, r4 // Store the new value back into the variable `i` + * ``` + * + * This allows IR-based analysis to focus on the fundamental operations, rather than having to be + * concerned with the various ways of expressing those operations in source code. + * + * The key classes in the IR are: + * + * - `IRFunction` - Contains the IR for an entire function definition, including all of that + * function's `Instruction`s, `IRBlock`s, and `IRVariables`. + * - `Instruction` - A single operation in the IR. An instruction specifies the operation to be + * performed, the operands that produce the inputs to that operation, and the type of the result + * of the operation. Control flows from an `Instruction` to one of a set of successor + * `Instruction`s. + * - `Operand` - An input value of an `Instruction`. All inputs of an `Instruction` are explicitly + * represented as `Operand`s, even if the input was implicit in the source code. An `Operand` has + * a link to the `Instruction` that consumes its value (its "use") and a link to the `Instruction` + * that produces its value (its "definition"). + * - `IRVariable` - A variable accessed by the IR for a particular function. An `IRVariable` is + * created for each variable directly accessed by the function. In addition, `IRVariable`s are + * created to represent certain temporary storage locations that do not have explicitly declared + * variables in the source code, such as the return value of the function. + * - `IRBlock` - A "basic block" in the control flow graph of a function. An `IRBlock` contains a + * sequence of instructions such that control flow can only enter the block at the first + * instruction, and can only leave the block from the last instruction. + * - `IRType` - The type of a value accessed in the IR. Unlike the `Type` class in the AST, `IRType` + * is language-neutral. For example, in C++, `unsigned int`, `char32_t`, and `wchar_t` might all + * be represented as the `IRType` `uint4`, a four-byte unsigned integer. + */ + import IRFunction import Instruction import IRBlock @@ -11,11 +55,12 @@ import Imports::MemoryAccessKind private newtype TIRPropertyProvider = MkIRPropertyProvider() /** - * Class that provides additional properties to be dumped for IR instructions and blocks when using + * A class that provides additional properties to be dumped for IR instructions and blocks when using * the PrintIR module. Libraries that compute additional facts about IR elements can extend the * single instance of this class to specify the additional properties computed by the library. */ class IRPropertyProvider extends TIRPropertyProvider { + /** Gets a textual representation of this element. */ string toString() { result = "IRPropertyProvider" } /** diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IR.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IR.qll index badd48552a5..766ec052da3 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IR.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IR.qll @@ -1,3 +1,47 @@ +/** + * Provides classes that describe the Intermediate Representation (IR) of the program. + * + * The IR is a representation of the semantics of the program, with very little dependence on the + * syntax that was used to write the program. For example, in C++, the statements `i += 1;`, `i++`, + * and `++i` all have the same semantic effect, but appear in the AST as three different types of + * `Expr` node. In the IR, all three statements are broken down into a sequence of fundamental + * operations similar to: + * + * ``` + * r1(int*) = VariableAddress[i] // Compute the address of variable `i` + * r2(int) = Load &:r1, m0 // Load the value of `i` + * r3(int) = Constant[1] // An integer constant with the value `1` + * r4(int) = Add r2, r3 // Add `1` to the value of `i` + * r5(int) = Store &r1, r4 // Store the new value back into the variable `i` + * ``` + * + * This allows IR-based analysis to focus on the fundamental operations, rather than having to be + * concerned with the various ways of expressing those operations in source code. + * + * The key classes in the IR are: + * + * - `IRFunction` - Contains the IR for an entire function definition, including all of that + * function's `Instruction`s, `IRBlock`s, and `IRVariables`. + * - `Instruction` - A single operation in the IR. An instruction specifies the operation to be + * performed, the operands that produce the inputs to that operation, and the type of the result + * of the operation. Control flows from an `Instruction` to one of a set of successor + * `Instruction`s. + * - `Operand` - An input value of an `Instruction`. All inputs of an `Instruction` are explicitly + * represented as `Operand`s, even if the input was implicit in the source code. An `Operand` has + * a link to the `Instruction` that consumes its value (its "use") and a link to the `Instruction` + * that produces its value (its "definition"). + * - `IRVariable` - A variable accessed by the IR for a particular function. An `IRVariable` is + * created for each variable directly accessed by the function. In addition, `IRVariable`s are + * created to represent certain temporary storage locations that do not have explicitly declared + * variables in the source code, such as the return value of the function. + * - `IRBlock` - A "basic block" in the control flow graph of a function. An `IRBlock` contains a + * sequence of instructions such that control flow can only enter the block at the first + * instruction, and can only leave the block from the last instruction. + * - `IRType` - The type of a value accessed in the IR. Unlike the `Type` class in the AST, `IRType` + * is language-neutral. For example, in C++, `unsigned int`, `char32_t`, and `wchar_t` might all + * be represented as the `IRType` `uint4`, a four-byte unsigned integer. + */ + import IRFunction import Instruction import IRBlock @@ -11,11 +55,12 @@ import Imports::MemoryAccessKind private newtype TIRPropertyProvider = MkIRPropertyProvider() /** - * Class that provides additional properties to be dumped for IR instructions and blocks when using + * A class that provides additional properties to be dumped for IR instructions and blocks when using * the PrintIR module. Libraries that compute additional facts about IR elements can extend the * single instance of this class to specify the additional properties computed by the library. */ class IRPropertyProvider extends TIRPropertyProvider { + /** Gets a textual representation of this element. */ string toString() { result = "IRPropertyProvider" } /** From 1423ea0591782d1c16553533d92a0715ef8d32d5 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Sun, 28 Jun 2020 09:57:31 -0400 Subject: [PATCH 12/20] C++: More `IR.qll` QLDoc --- cpp/ql/src/semmle/code/cpp/ir/IR.qll | 46 +++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/IR.qll b/cpp/ql/src/semmle/code/cpp/ir/IR.qll index f019f20b6a8..f418923b3f0 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/IR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/IR.qll @@ -1,3 +1,47 @@ +/** + * Provides classes that describe the Intermediate Representation (IR) of the program. + * + * The IR is a representation of the semantics of the program, with very little dependence on the + * syntax that was used to write the program. For example, in C++, the statements `i += 1;`, `i++`, + * and `++i` all have the same semantic effect, but appear in the AST as three different types of + * `Expr` node. In the IR, all three statements are broken down into a sequence of fundamental + * operations similar to: + * + * ``` + * r1(int*) = VariableAddress[i] // Compute the address of variable `i` + * r2(int) = Load &:r1, m0 // Load the value of `i` + * r3(int) = Constant[1] // An integer constant with the value `1` + * r4(int) = Add r2, r3 // Add `1` to the value of `i` + * r5(int) = Store &r1, r4 // Store the new value back into the variable `i` + * ``` + * + * This allows IR-based analysis to focus on the fundamental operations, rather than having to be + * concerned with the various ways of expressing those operations in source code. + * + * The key classes in the IR are: + * + * - `IRFunction` - Contains the IR for an entire function definition, including all of that + * function's `Instruction`s, `IRBlock`s, and `IRVariables`. + * - `Instruction` - A single operation in the IR. An instruction specifies the operation to be + * performed, the operands that produce the inputs to that operation, and the type of the result + * of the operation. Control flows from an `Instruction` to one of a set of successor + * `Instruction`s. + * - `Operand` - An input value of an `Instruction`. All inputs of an `Instruction` are explicitly + * represented as `Operand`s, even if the input was implicit in the source code. An `Operand` has + * a link to the `Instruction` that consumes its value (its "use") and a link to the `Instruction` + * that produces its value (its "definition"). + * - `IRVariable` - A variable accessed by the IR for a particular function. An `IRVariable` is + * created for each variable directly accessed by the function. In addition, `IRVariable`s are + * created to represent certain temporary storage locations that do not have explicitly declared + * variables in the source code, such as the return value of the function. + * - `IRBlock` - A "basic block" in the control flow graph of a function. An `IRBlock` contains a + * sequence of instructions such that control flow can only enter the block at the first + * instruction, and can only leave the block from the last instruction. + * - `IRType` - The type of a value accessed in the IR. Unlike the `Type` class in the AST, `IRType` + * is language-neutral. For example, in C++, `unsigned int`, `char32_t`, and `wchar_t` might all + * be represented as the `IRType` `uint4`, a four-byte unsigned integer. + */ + // Most queries should operate on the aliased SSA IR, so that's what we expose -// publically as the "IR". +// publicly as the "IR". import implementation.aliased_ssa.IR From ead2a143e023c44b51b5a67ecedbf311232fb3b8 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Mon, 29 Jun 2020 11:35:13 -0400 Subject: [PATCH 13/20] C++: QLDoc for IRVariable Moved a couple of predicates that were only needed by IR construction into `TranslatedElement.qll` --- .../implementation/aliased_ssa/IRVariable.qll | 39 ++++++++++++------- .../cpp/ir/implementation/raw/IRVariable.qll | 39 ++++++++++++------- .../raw/internal/TranslatedElement.qll | 10 +++++ .../unaliased_ssa/IRVariable.qll | 39 ++++++++++++------- .../ir/implementation/raw/IRVariable.qll | 39 ++++++++++++------- .../raw/internal/TranslatedElement.qll | 10 +++++ .../unaliased_ssa/IRVariable.qll | 39 ++++++++++++------- 7 files changed, 150 insertions(+), 65 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll index a01bd2dc79a..7b7744e3af1 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll @@ -7,15 +7,11 @@ private import Imports::TTempVariableTag private import Imports::TIRVariable private import Imports::IRType -IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var) { - result.getVariable() = var and - result.getEnclosingFunction() = func -} - /** - * A variable referenced by the IR for a function. The variable may be a user-declared variable - * (`IRUserVariable`) or a temporary variable generated by the AST-to-IR translation - * (`IRTempVariable`). + * A variable referenced by the IR for a function. + * + * The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated + * by the AST-to-IR translation (`IRTempVariable`). */ class IRVariable extends TIRVariable { Language::Function func; @@ -27,6 +23,7 @@ class IRVariable extends TIRVariable { this = TIRDynamicInitializationFlag(func, _, _) } + /** Gets a textual representation of this element. */ string toString() { none() } /** @@ -162,20 +159,26 @@ class IRGeneratedVariable extends IRVariable { override string getUniqueId() { none() } + /** + * Gets a string containing the source code location of the AST that generated this variable. + * + * This is used by debugging and printing code only. + */ final string getLocationString() { result = ast.getLocation().getStartLine().toString() + ":" + ast.getLocation().getStartColumn().toString() } + /** + * Gets the string that is combined with the location of the variable to generate the string + * representation of this variable. + * + * This is used by debugging and printing code only. + */ string getBaseString() { none() } } -IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) { - result.getAST() = ast and - result.getTag() = tag -} - /** * A temporary variable introduced by IR construction. The most common examples are the variable * generated to hold the return value of a function, or the variable generated to hold the result of @@ -190,6 +193,10 @@ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVa result = "Temp: " + Construction::getTempVariableUniqueId(this) } + /** + * Gets the "tag" object that differentiates this temporary variable from other temporary + * variables generated for the same AST. + */ final TempVariableTag getTag() { result = tag } override string getBaseString() { result = "#temp" } @@ -253,6 +260,9 @@ class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral { final override string getBaseString() { result = "#string" } + /** + * Gets the AST of the string literal represented by this `IRStringLiteral`. + */ final Language::StringLiteral getLiteral() { result = literal } } @@ -270,6 +280,9 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial final override string toString() { result = var.toString() + "#init" } + /** + * Gets variable whose initialization is guarded by this flag. + */ final Language::Variable getVariable() { result = var } final override string getUniqueId() { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll index a01bd2dc79a..7b7744e3af1 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll @@ -7,15 +7,11 @@ private import Imports::TTempVariableTag private import Imports::TIRVariable private import Imports::IRType -IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var) { - result.getVariable() = var and - result.getEnclosingFunction() = func -} - /** - * A variable referenced by the IR for a function. The variable may be a user-declared variable - * (`IRUserVariable`) or a temporary variable generated by the AST-to-IR translation - * (`IRTempVariable`). + * A variable referenced by the IR for a function. + * + * The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated + * by the AST-to-IR translation (`IRTempVariable`). */ class IRVariable extends TIRVariable { Language::Function func; @@ -27,6 +23,7 @@ class IRVariable extends TIRVariable { this = TIRDynamicInitializationFlag(func, _, _) } + /** Gets a textual representation of this element. */ string toString() { none() } /** @@ -162,20 +159,26 @@ class IRGeneratedVariable extends IRVariable { override string getUniqueId() { none() } + /** + * Gets a string containing the source code location of the AST that generated this variable. + * + * This is used by debugging and printing code only. + */ final string getLocationString() { result = ast.getLocation().getStartLine().toString() + ":" + ast.getLocation().getStartColumn().toString() } + /** + * Gets the string that is combined with the location of the variable to generate the string + * representation of this variable. + * + * This is used by debugging and printing code only. + */ string getBaseString() { none() } } -IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) { - result.getAST() = ast and - result.getTag() = tag -} - /** * A temporary variable introduced by IR construction. The most common examples are the variable * generated to hold the return value of a function, or the variable generated to hold the result of @@ -190,6 +193,10 @@ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVa result = "Temp: " + Construction::getTempVariableUniqueId(this) } + /** + * Gets the "tag" object that differentiates this temporary variable from other temporary + * variables generated for the same AST. + */ final TempVariableTag getTag() { result = tag } override string getBaseString() { result = "#temp" } @@ -253,6 +260,9 @@ class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral { final override string getBaseString() { result = "#string" } + /** + * Gets the AST of the string literal represented by this `IRStringLiteral`. + */ final Language::StringLiteral getLiteral() { result = literal } } @@ -270,6 +280,9 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial final override string toString() { result = var.toString() + "#init" } + /** + * Gets variable whose initialization is guarded by this flag. + */ final Language::Variable getVariable() { result = var } final override string getUniqueId() { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll index 8bf5fa9d44b..f3c8816c19d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/TranslatedElement.qll @@ -24,6 +24,16 @@ private Element getRealParent(Expr expr) { result.(Destructor).getADestruction() = expr } +IRUserVariable getIRUserVariable(Function func, Variable var) { + result.getVariable() = var and + result.getEnclosingFunction() = func +} + +IRTempVariable getIRTempVariable(Locatable ast, TempVariableTag tag) { + result.getAST() = ast and + result.getTag() = tag +} + /** * Holds if `expr` is a constant of a type that can be replaced directly with * its value in the IR. This does not include address constants as we have no diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll index a01bd2dc79a..7b7744e3af1 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll @@ -7,15 +7,11 @@ private import Imports::TTempVariableTag private import Imports::TIRVariable private import Imports::IRType -IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var) { - result.getVariable() = var and - result.getEnclosingFunction() = func -} - /** - * A variable referenced by the IR for a function. The variable may be a user-declared variable - * (`IRUserVariable`) or a temporary variable generated by the AST-to-IR translation - * (`IRTempVariable`). + * A variable referenced by the IR for a function. + * + * The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated + * by the AST-to-IR translation (`IRTempVariable`). */ class IRVariable extends TIRVariable { Language::Function func; @@ -27,6 +23,7 @@ class IRVariable extends TIRVariable { this = TIRDynamicInitializationFlag(func, _, _) } + /** Gets a textual representation of this element. */ string toString() { none() } /** @@ -162,20 +159,26 @@ class IRGeneratedVariable extends IRVariable { override string getUniqueId() { none() } + /** + * Gets a string containing the source code location of the AST that generated this variable. + * + * This is used by debugging and printing code only. + */ final string getLocationString() { result = ast.getLocation().getStartLine().toString() + ":" + ast.getLocation().getStartColumn().toString() } + /** + * Gets the string that is combined with the location of the variable to generate the string + * representation of this variable. + * + * This is used by debugging and printing code only. + */ string getBaseString() { none() } } -IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) { - result.getAST() = ast and - result.getTag() = tag -} - /** * A temporary variable introduced by IR construction. The most common examples are the variable * generated to hold the return value of a function, or the variable generated to hold the result of @@ -190,6 +193,10 @@ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVa result = "Temp: " + Construction::getTempVariableUniqueId(this) } + /** + * Gets the "tag" object that differentiates this temporary variable from other temporary + * variables generated for the same AST. + */ final TempVariableTag getTag() { result = tag } override string getBaseString() { result = "#temp" } @@ -253,6 +260,9 @@ class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral { final override string getBaseString() { result = "#string" } + /** + * Gets the AST of the string literal represented by this `IRStringLiteral`. + */ final Language::StringLiteral getLiteral() { result = literal } } @@ -270,6 +280,9 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial final override string toString() { result = var.toString() + "#init" } + /** + * Gets variable whose initialization is guarded by this flag. + */ final Language::Variable getVariable() { result = var } final override string getUniqueId() { diff --git a/csharp/ql/src/experimental/ir/implementation/raw/IRVariable.qll b/csharp/ql/src/experimental/ir/implementation/raw/IRVariable.qll index a01bd2dc79a..7b7744e3af1 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/IRVariable.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/IRVariable.qll @@ -7,15 +7,11 @@ private import Imports::TTempVariableTag private import Imports::TIRVariable private import Imports::IRType -IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var) { - result.getVariable() = var and - result.getEnclosingFunction() = func -} - /** - * A variable referenced by the IR for a function. The variable may be a user-declared variable - * (`IRUserVariable`) or a temporary variable generated by the AST-to-IR translation - * (`IRTempVariable`). + * A variable referenced by the IR for a function. + * + * The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated + * by the AST-to-IR translation (`IRTempVariable`). */ class IRVariable extends TIRVariable { Language::Function func; @@ -27,6 +23,7 @@ class IRVariable extends TIRVariable { this = TIRDynamicInitializationFlag(func, _, _) } + /** Gets a textual representation of this element. */ string toString() { none() } /** @@ -162,20 +159,26 @@ class IRGeneratedVariable extends IRVariable { override string getUniqueId() { none() } + /** + * Gets a string containing the source code location of the AST that generated this variable. + * + * This is used by debugging and printing code only. + */ final string getLocationString() { result = ast.getLocation().getStartLine().toString() + ":" + ast.getLocation().getStartColumn().toString() } + /** + * Gets the string that is combined with the location of the variable to generate the string + * representation of this variable. + * + * This is used by debugging and printing code only. + */ string getBaseString() { none() } } -IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) { - result.getAST() = ast and - result.getTag() = tag -} - /** * A temporary variable introduced by IR construction. The most common examples are the variable * generated to hold the return value of a function, or the variable generated to hold the result of @@ -190,6 +193,10 @@ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVa result = "Temp: " + Construction::getTempVariableUniqueId(this) } + /** + * Gets the "tag" object that differentiates this temporary variable from other temporary + * variables generated for the same AST. + */ final TempVariableTag getTag() { result = tag } override string getBaseString() { result = "#temp" } @@ -253,6 +260,9 @@ class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral { final override string getBaseString() { result = "#string" } + /** + * Gets the AST of the string literal represented by this `IRStringLiteral`. + */ final Language::StringLiteral getLiteral() { result = literal } } @@ -270,6 +280,9 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial final override string toString() { result = var.toString() + "#init" } + /** + * Gets variable whose initialization is guarded by this flag. + */ final Language::Variable getVariable() { result = var } final override string getUniqueId() { diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedElement.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedElement.qll index 7171cb66c2c..0022711f79e 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedElement.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedElement.qll @@ -21,6 +21,16 @@ ArrayType getArrayOfDim(int dim, Type type) { result.getElementType() = type } +IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var) { + result.getVariable() = var and + result.getEnclosingFunction() = func +} + +IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) { + result.getAST() = ast and + result.getTag() = tag +} + private predicate canCreateCompilerGeneratedElement(Element generatedBy, int nth) { generatedBy instanceof ForeachStmt and nth in [0 .. ForeachElements::noGeneratedElements() - 1] or diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRVariable.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRVariable.qll index a01bd2dc79a..7b7744e3af1 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRVariable.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRVariable.qll @@ -7,15 +7,11 @@ private import Imports::TTempVariableTag private import Imports::TIRVariable private import Imports::IRType -IRUserVariable getIRUserVariable(Language::Function func, Language::Variable var) { - result.getVariable() = var and - result.getEnclosingFunction() = func -} - /** - * A variable referenced by the IR for a function. The variable may be a user-declared variable - * (`IRUserVariable`) or a temporary variable generated by the AST-to-IR translation - * (`IRTempVariable`). + * A variable referenced by the IR for a function. + * + * The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated + * by the AST-to-IR translation (`IRTempVariable`). */ class IRVariable extends TIRVariable { Language::Function func; @@ -27,6 +23,7 @@ class IRVariable extends TIRVariable { this = TIRDynamicInitializationFlag(func, _, _) } + /** Gets a textual representation of this element. */ string toString() { none() } /** @@ -162,20 +159,26 @@ class IRGeneratedVariable extends IRVariable { override string getUniqueId() { none() } + /** + * Gets a string containing the source code location of the AST that generated this variable. + * + * This is used by debugging and printing code only. + */ final string getLocationString() { result = ast.getLocation().getStartLine().toString() + ":" + ast.getLocation().getStartColumn().toString() } + /** + * Gets the string that is combined with the location of the variable to generate the string + * representation of this variable. + * + * This is used by debugging and printing code only. + */ string getBaseString() { none() } } -IRTempVariable getIRTempVariable(Language::AST ast, TempVariableTag tag) { - result.getAST() = ast and - result.getTag() = tag -} - /** * A temporary variable introduced by IR construction. The most common examples are the variable * generated to hold the return value of a function, or the variable generated to hold the result of @@ -190,6 +193,10 @@ class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVa result = "Temp: " + Construction::getTempVariableUniqueId(this) } + /** + * Gets the "tag" object that differentiates this temporary variable from other temporary + * variables generated for the same AST. + */ final TempVariableTag getTag() { result = tag } override string getBaseString() { result = "#temp" } @@ -253,6 +260,9 @@ class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral { final override string getBaseString() { result = "#string" } + /** + * Gets the AST of the string literal represented by this `IRStringLiteral`. + */ final Language::StringLiteral getLiteral() { result = literal } } @@ -270,6 +280,9 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial final override string toString() { result = var.toString() + "#init" } + /** + * Gets variable whose initialization is guarded by this flag. + */ final Language::Variable getVariable() { result = var } final override string getUniqueId() { From 2043d9c7c4cf07ccd40fa7c0ecbe8f9bfaff8ef9 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Mon, 29 Jun 2020 11:57:18 -0400 Subject: [PATCH 14/20] C++: QLDoc for `Operand.qll` --- .../ir/implementation/aliased_ssa/Operand.qll | 23 +++++++++++++++++++ .../cpp/ir/implementation/raw/Operand.qll | 23 +++++++++++++++++++ .../implementation/unaliased_ssa/Operand.qll | 23 +++++++++++++++++++ .../ir/implementation/raw/Operand.qll | 23 +++++++++++++++++++ .../implementation/unaliased_ssa/Operand.qll | 23 +++++++++++++++++++ 5 files changed, 115 insertions(+) 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 f82704094c8..468687b0aca 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 @@ -1,3 +1,7 @@ +/** + * Provides classes that represent the input values of IR instructions. + */ + private import internal.IRInternal private import Instruction private import IRBlock @@ -78,10 +82,17 @@ private PhiOperandBase phiOperand( * A source operand of an `Instruction`. The operand represents a value consumed by the instruction. */ class Operand extends TOperand { + /** Gets a textual representation of this element. */ string toString() { result = "Operand" } + /** + * Gets the location of the source code for this operand. + */ final Language::Location getLocation() { result = getUse().getLocation() } + /** + * Gets the function that contains this operand. + */ final IRFunction getEnclosingIRFunction() { result = getUse().getEnclosingIRFunction() } /** @@ -270,6 +281,9 @@ class NonPhiOperand extends Operand { final override int getDumpSortOrder() { result = tag.getSortOrder() } + /** + * Gets the `OperandTag` that specifies how this operand is used by its `Instruction`. + */ final OperandTag getOperandTag() { result = tag } } @@ -292,6 +306,9 @@ class RegisterOperand extends NonPhiOperand, RegisterOperandBase { } } +/** + * A memory operand other than the operand of a `Phi` instruction. + */ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOperandBase { override MemoryOperandTag tag; @@ -313,6 +330,9 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOper } } +/** + * A memory operand whose type may be different from the type of the result of its definition. + */ class TypedOperand extends NonPhiMemoryOperand { override TypedOperandTag tag; @@ -416,6 +436,9 @@ class PositionalArgumentOperand extends ArgumentOperand { final int getIndex() { result = tag.getArgIndex() } } +/** + * An operand representing memory read as a side effect of evaluating another instruction. + */ class SideEffectOperand extends TypedOperand { override SideEffectOperandTag tag; } 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 f82704094c8..468687b0aca 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 @@ -1,3 +1,7 @@ +/** + * Provides classes that represent the input values of IR instructions. + */ + private import internal.IRInternal private import Instruction private import IRBlock @@ -78,10 +82,17 @@ private PhiOperandBase phiOperand( * A source operand of an `Instruction`. The operand represents a value consumed by the instruction. */ class Operand extends TOperand { + /** Gets a textual representation of this element. */ string toString() { result = "Operand" } + /** + * Gets the location of the source code for this operand. + */ final Language::Location getLocation() { result = getUse().getLocation() } + /** + * Gets the function that contains this operand. + */ final IRFunction getEnclosingIRFunction() { result = getUse().getEnclosingIRFunction() } /** @@ -270,6 +281,9 @@ class NonPhiOperand extends Operand { final override int getDumpSortOrder() { result = tag.getSortOrder() } + /** + * Gets the `OperandTag` that specifies how this operand is used by its `Instruction`. + */ final OperandTag getOperandTag() { result = tag } } @@ -292,6 +306,9 @@ class RegisterOperand extends NonPhiOperand, RegisterOperandBase { } } +/** + * A memory operand other than the operand of a `Phi` instruction. + */ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOperandBase { override MemoryOperandTag tag; @@ -313,6 +330,9 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOper } } +/** + * A memory operand whose type may be different from the type of the result of its definition. + */ class TypedOperand extends NonPhiMemoryOperand { override TypedOperandTag tag; @@ -416,6 +436,9 @@ class PositionalArgumentOperand extends ArgumentOperand { final int getIndex() { result = tag.getArgIndex() } } +/** + * An operand representing memory read as a side effect of evaluating another instruction. + */ class SideEffectOperand extends TypedOperand { override SideEffectOperandTag tag; } 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 f82704094c8..468687b0aca 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 @@ -1,3 +1,7 @@ +/** + * Provides classes that represent the input values of IR instructions. + */ + private import internal.IRInternal private import Instruction private import IRBlock @@ -78,10 +82,17 @@ private PhiOperandBase phiOperand( * A source operand of an `Instruction`. The operand represents a value consumed by the instruction. */ class Operand extends TOperand { + /** Gets a textual representation of this element. */ string toString() { result = "Operand" } + /** + * Gets the location of the source code for this operand. + */ final Language::Location getLocation() { result = getUse().getLocation() } + /** + * Gets the function that contains this operand. + */ final IRFunction getEnclosingIRFunction() { result = getUse().getEnclosingIRFunction() } /** @@ -270,6 +281,9 @@ class NonPhiOperand extends Operand { final override int getDumpSortOrder() { result = tag.getSortOrder() } + /** + * Gets the `OperandTag` that specifies how this operand is used by its `Instruction`. + */ final OperandTag getOperandTag() { result = tag } } @@ -292,6 +306,9 @@ class RegisterOperand extends NonPhiOperand, RegisterOperandBase { } } +/** + * A memory operand other than the operand of a `Phi` instruction. + */ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOperandBase { override MemoryOperandTag tag; @@ -313,6 +330,9 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOper } } +/** + * A memory operand whose type may be different from the type of the result of its definition. + */ class TypedOperand extends NonPhiMemoryOperand { override TypedOperandTag tag; @@ -416,6 +436,9 @@ class PositionalArgumentOperand extends ArgumentOperand { final int getIndex() { result = tag.getArgIndex() } } +/** + * An operand representing memory read as a side effect of evaluating another instruction. + */ class SideEffectOperand extends TypedOperand { override SideEffectOperandTag tag; } diff --git a/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll b/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll index f82704094c8..468687b0aca 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent the input values of IR instructions. + */ + private import internal.IRInternal private import Instruction private import IRBlock @@ -78,10 +82,17 @@ private PhiOperandBase phiOperand( * A source operand of an `Instruction`. The operand represents a value consumed by the instruction. */ class Operand extends TOperand { + /** Gets a textual representation of this element. */ string toString() { result = "Operand" } + /** + * Gets the location of the source code for this operand. + */ final Language::Location getLocation() { result = getUse().getLocation() } + /** + * Gets the function that contains this operand. + */ final IRFunction getEnclosingIRFunction() { result = getUse().getEnclosingIRFunction() } /** @@ -270,6 +281,9 @@ class NonPhiOperand extends Operand { final override int getDumpSortOrder() { result = tag.getSortOrder() } + /** + * Gets the `OperandTag` that specifies how this operand is used by its `Instruction`. + */ final OperandTag getOperandTag() { result = tag } } @@ -292,6 +306,9 @@ class RegisterOperand extends NonPhiOperand, RegisterOperandBase { } } +/** + * A memory operand other than the operand of a `Phi` instruction. + */ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOperandBase { override MemoryOperandTag tag; @@ -313,6 +330,9 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOper } } +/** + * A memory operand whose type may be different from the type of the result of its definition. + */ class TypedOperand extends NonPhiMemoryOperand { override TypedOperandTag tag; @@ -416,6 +436,9 @@ class PositionalArgumentOperand extends ArgumentOperand { final int getIndex() { result = tag.getArgIndex() } } +/** + * An operand representing memory read as a side effect of evaluating another instruction. + */ class SideEffectOperand extends TypedOperand { override SideEffectOperandTag tag; } diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Operand.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Operand.qll index f82704094c8..468687b0aca 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Operand.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Operand.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent the input values of IR instructions. + */ + private import internal.IRInternal private import Instruction private import IRBlock @@ -78,10 +82,17 @@ private PhiOperandBase phiOperand( * A source operand of an `Instruction`. The operand represents a value consumed by the instruction. */ class Operand extends TOperand { + /** Gets a textual representation of this element. */ string toString() { result = "Operand" } + /** + * Gets the location of the source code for this operand. + */ final Language::Location getLocation() { result = getUse().getLocation() } + /** + * Gets the function that contains this operand. + */ final IRFunction getEnclosingIRFunction() { result = getUse().getEnclosingIRFunction() } /** @@ -270,6 +281,9 @@ class NonPhiOperand extends Operand { final override int getDumpSortOrder() { result = tag.getSortOrder() } + /** + * Gets the `OperandTag` that specifies how this operand is used by its `Instruction`. + */ final OperandTag getOperandTag() { result = tag } } @@ -292,6 +306,9 @@ class RegisterOperand extends NonPhiOperand, RegisterOperandBase { } } +/** + * A memory operand other than the operand of a `Phi` instruction. + */ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOperandBase { override MemoryOperandTag tag; @@ -313,6 +330,9 @@ class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOper } } +/** + * A memory operand whose type may be different from the type of the result of its definition. + */ class TypedOperand extends NonPhiMemoryOperand { override TypedOperandTag tag; @@ -416,6 +436,9 @@ class PositionalArgumentOperand extends ArgumentOperand { final int getIndex() { result = tag.getArgIndex() } } +/** + * An operand representing memory read as a side effect of evaluating another instruction. + */ class SideEffectOperand extends TypedOperand { override SideEffectOperandTag tag; } From 440ea6a069e1ff68120d3e32b3669d513a1ab1e8 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Mon, 29 Jun 2020 12:05:56 -0400 Subject: [PATCH 15/20] C++: QLDoc for `PrintIR.qll` --- .../ir/implementation/aliased_ssa/PrintIR.qll | 28 ++++++++++++++++--- .../cpp/ir/implementation/raw/PrintIR.qll | 28 ++++++++++++++++--- .../implementation/unaliased_ssa/PrintIR.qll | 28 ++++++++++++++++--- .../ir/implementation/raw/PrintIR.qll | 28 ++++++++++++++++--- .../implementation/unaliased_ssa/PrintIR.qll | 28 ++++++++++++++++--- 5 files changed, 120 insertions(+), 20 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.qll index d9c0df44e12..82c6538601a 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.qll @@ -1,3 +1,13 @@ +/** + * Outputs a representation of the IR as a control flow graph. + * + * This file contains the actual implementation of `PrintAST.ql`. For test cases and very small + * databases, `PrintAST.ql` can be run directly to dump the IR for the entire database. For most + * uses, however, it is better to write a query that imports `PrintAST.qll`, extends + * `PrintIRConfiguration`, and overrides `shouldPrintFunction()` to select a subset of functions to + * dump. + */ + private import internal.IRInternal private import IR private import internal.PrintIRImports as Imports @@ -47,7 +57,7 @@ private newtype TPrintableIRNode = /** * A node to be emitted in the IR graph. */ -abstract class PrintableIRNode extends TPrintableIRNode { +abstract private class PrintableIRNode extends TPrintableIRNode { abstract string toString(); /** @@ -98,7 +108,7 @@ abstract class PrintableIRNode extends TPrintableIRNode { /** * An IR graph node representing a `IRFunction` object. */ -class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { +private class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { IRFunction irFunc; PrintableIRFunction() { this = TPrintableIRFunction(irFunc) } @@ -129,7 +139,7 @@ class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { /** * An IR graph node representing an `IRBlock` object. */ -class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { +private class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { IRBlock block; PrintableIRBlock() { this = TPrintableIRBlock(block) } @@ -161,7 +171,7 @@ class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { /** * An IR graph node representing an `Instruction`. */ -class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { +private class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { Instruction instr; PrintableInstruction() { this = TPrintableInstruction(instr) } @@ -224,6 +234,9 @@ private string getPaddingString(int n) { n > 0 and n <= maxColumnWidth() and result = getPaddingString(n - 1) + " " } +/** + * Holds if `node` belongs to the output graph, and its property `key` has the given `value`. + */ query predicate nodes(PrintableIRNode node, string key, string value) { value = node.getProperty(key) } @@ -237,6 +250,10 @@ private int getSuccessorIndex(IRBlock pred, IRBlock succ) { ) } +/** + * Holds if the output graph contains an edge from `pred` to `succ`, and that edge's property `key` + * has the given `value`. + */ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, string value) { exists(EdgeKind kind, IRBlock predBlock, IRBlock succBlock | predBlock = pred.getBlock() and @@ -256,6 +273,9 @@ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, ) } +/** + * Holds if `parent` is the parent node of `child` in the output graph. + */ query predicate parents(PrintableIRNode child, PrintableIRNode parent) { parent = child.getParent() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/PrintIR.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/PrintIR.qll index d9c0df44e12..82c6538601a 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/PrintIR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/PrintIR.qll @@ -1,3 +1,13 @@ +/** + * Outputs a representation of the IR as a control flow graph. + * + * This file contains the actual implementation of `PrintAST.ql`. For test cases and very small + * databases, `PrintAST.ql` can be run directly to dump the IR for the entire database. For most + * uses, however, it is better to write a query that imports `PrintAST.qll`, extends + * `PrintIRConfiguration`, and overrides `shouldPrintFunction()` to select a subset of functions to + * dump. + */ + private import internal.IRInternal private import IR private import internal.PrintIRImports as Imports @@ -47,7 +57,7 @@ private newtype TPrintableIRNode = /** * A node to be emitted in the IR graph. */ -abstract class PrintableIRNode extends TPrintableIRNode { +abstract private class PrintableIRNode extends TPrintableIRNode { abstract string toString(); /** @@ -98,7 +108,7 @@ abstract class PrintableIRNode extends TPrintableIRNode { /** * An IR graph node representing a `IRFunction` object. */ -class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { +private class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { IRFunction irFunc; PrintableIRFunction() { this = TPrintableIRFunction(irFunc) } @@ -129,7 +139,7 @@ class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { /** * An IR graph node representing an `IRBlock` object. */ -class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { +private class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { IRBlock block; PrintableIRBlock() { this = TPrintableIRBlock(block) } @@ -161,7 +171,7 @@ class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { /** * An IR graph node representing an `Instruction`. */ -class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { +private class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { Instruction instr; PrintableInstruction() { this = TPrintableInstruction(instr) } @@ -224,6 +234,9 @@ private string getPaddingString(int n) { n > 0 and n <= maxColumnWidth() and result = getPaddingString(n - 1) + " " } +/** + * Holds if `node` belongs to the output graph, and its property `key` has the given `value`. + */ query predicate nodes(PrintableIRNode node, string key, string value) { value = node.getProperty(key) } @@ -237,6 +250,10 @@ private int getSuccessorIndex(IRBlock pred, IRBlock succ) { ) } +/** + * Holds if the output graph contains an edge from `pred` to `succ`, and that edge's property `key` + * has the given `value`. + */ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, string value) { exists(EdgeKind kind, IRBlock predBlock, IRBlock succBlock | predBlock = pred.getBlock() and @@ -256,6 +273,9 @@ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, ) } +/** + * Holds if `parent` is the parent node of `child` in the output graph. + */ query predicate parents(PrintableIRNode child, PrintableIRNode parent) { parent = child.getParent() } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/PrintIR.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/PrintIR.qll index d9c0df44e12..82c6538601a 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/PrintIR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/PrintIR.qll @@ -1,3 +1,13 @@ +/** + * Outputs a representation of the IR as a control flow graph. + * + * This file contains the actual implementation of `PrintAST.ql`. For test cases and very small + * databases, `PrintAST.ql` can be run directly to dump the IR for the entire database. For most + * uses, however, it is better to write a query that imports `PrintAST.qll`, extends + * `PrintIRConfiguration`, and overrides `shouldPrintFunction()` to select a subset of functions to + * dump. + */ + private import internal.IRInternal private import IR private import internal.PrintIRImports as Imports @@ -47,7 +57,7 @@ private newtype TPrintableIRNode = /** * A node to be emitted in the IR graph. */ -abstract class PrintableIRNode extends TPrintableIRNode { +abstract private class PrintableIRNode extends TPrintableIRNode { abstract string toString(); /** @@ -98,7 +108,7 @@ abstract class PrintableIRNode extends TPrintableIRNode { /** * An IR graph node representing a `IRFunction` object. */ -class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { +private class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { IRFunction irFunc; PrintableIRFunction() { this = TPrintableIRFunction(irFunc) } @@ -129,7 +139,7 @@ class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { /** * An IR graph node representing an `IRBlock` object. */ -class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { +private class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { IRBlock block; PrintableIRBlock() { this = TPrintableIRBlock(block) } @@ -161,7 +171,7 @@ class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { /** * An IR graph node representing an `Instruction`. */ -class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { +private class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { Instruction instr; PrintableInstruction() { this = TPrintableInstruction(instr) } @@ -224,6 +234,9 @@ private string getPaddingString(int n) { n > 0 and n <= maxColumnWidth() and result = getPaddingString(n - 1) + " " } +/** + * Holds if `node` belongs to the output graph, and its property `key` has the given `value`. + */ query predicate nodes(PrintableIRNode node, string key, string value) { value = node.getProperty(key) } @@ -237,6 +250,10 @@ private int getSuccessorIndex(IRBlock pred, IRBlock succ) { ) } +/** + * Holds if the output graph contains an edge from `pred` to `succ`, and that edge's property `key` + * has the given `value`. + */ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, string value) { exists(EdgeKind kind, IRBlock predBlock, IRBlock succBlock | predBlock = pred.getBlock() and @@ -256,6 +273,9 @@ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, ) } +/** + * Holds if `parent` is the parent node of `child` in the output graph. + */ query predicate parents(PrintableIRNode child, PrintableIRNode parent) { parent = child.getParent() } diff --git a/csharp/ql/src/experimental/ir/implementation/raw/PrintIR.qll b/csharp/ql/src/experimental/ir/implementation/raw/PrintIR.qll index d9c0df44e12..82c6538601a 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/PrintIR.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/PrintIR.qll @@ -1,3 +1,13 @@ +/** + * Outputs a representation of the IR as a control flow graph. + * + * This file contains the actual implementation of `PrintAST.ql`. For test cases and very small + * databases, `PrintAST.ql` can be run directly to dump the IR for the entire database. For most + * uses, however, it is better to write a query that imports `PrintAST.qll`, extends + * `PrintIRConfiguration`, and overrides `shouldPrintFunction()` to select a subset of functions to + * dump. + */ + private import internal.IRInternal private import IR private import internal.PrintIRImports as Imports @@ -47,7 +57,7 @@ private newtype TPrintableIRNode = /** * A node to be emitted in the IR graph. */ -abstract class PrintableIRNode extends TPrintableIRNode { +abstract private class PrintableIRNode extends TPrintableIRNode { abstract string toString(); /** @@ -98,7 +108,7 @@ abstract class PrintableIRNode extends TPrintableIRNode { /** * An IR graph node representing a `IRFunction` object. */ -class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { +private class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { IRFunction irFunc; PrintableIRFunction() { this = TPrintableIRFunction(irFunc) } @@ -129,7 +139,7 @@ class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { /** * An IR graph node representing an `IRBlock` object. */ -class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { +private class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { IRBlock block; PrintableIRBlock() { this = TPrintableIRBlock(block) } @@ -161,7 +171,7 @@ class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { /** * An IR graph node representing an `Instruction`. */ -class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { +private class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { Instruction instr; PrintableInstruction() { this = TPrintableInstruction(instr) } @@ -224,6 +234,9 @@ private string getPaddingString(int n) { n > 0 and n <= maxColumnWidth() and result = getPaddingString(n - 1) + " " } +/** + * Holds if `node` belongs to the output graph, and its property `key` has the given `value`. + */ query predicate nodes(PrintableIRNode node, string key, string value) { value = node.getProperty(key) } @@ -237,6 +250,10 @@ private int getSuccessorIndex(IRBlock pred, IRBlock succ) { ) } +/** + * Holds if the output graph contains an edge from `pred` to `succ`, and that edge's property `key` + * has the given `value`. + */ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, string value) { exists(EdgeKind kind, IRBlock predBlock, IRBlock succBlock | predBlock = pred.getBlock() and @@ -256,6 +273,9 @@ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, ) } +/** + * Holds if `parent` is the parent node of `child` in the output graph. + */ query predicate parents(PrintableIRNode child, PrintableIRNode parent) { parent = child.getParent() } diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/PrintIR.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/PrintIR.qll index d9c0df44e12..82c6538601a 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/PrintIR.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/PrintIR.qll @@ -1,3 +1,13 @@ +/** + * Outputs a representation of the IR as a control flow graph. + * + * This file contains the actual implementation of `PrintAST.ql`. For test cases and very small + * databases, `PrintAST.ql` can be run directly to dump the IR for the entire database. For most + * uses, however, it is better to write a query that imports `PrintAST.qll`, extends + * `PrintIRConfiguration`, and overrides `shouldPrintFunction()` to select a subset of functions to + * dump. + */ + private import internal.IRInternal private import IR private import internal.PrintIRImports as Imports @@ -47,7 +57,7 @@ private newtype TPrintableIRNode = /** * A node to be emitted in the IR graph. */ -abstract class PrintableIRNode extends TPrintableIRNode { +abstract private class PrintableIRNode extends TPrintableIRNode { abstract string toString(); /** @@ -98,7 +108,7 @@ abstract class PrintableIRNode extends TPrintableIRNode { /** * An IR graph node representing a `IRFunction` object. */ -class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { +private class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { IRFunction irFunc; PrintableIRFunction() { this = TPrintableIRFunction(irFunc) } @@ -129,7 +139,7 @@ class PrintableIRFunction extends PrintableIRNode, TPrintableIRFunction { /** * An IR graph node representing an `IRBlock` object. */ -class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { +private class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { IRBlock block; PrintableIRBlock() { this = TPrintableIRBlock(block) } @@ -161,7 +171,7 @@ class PrintableIRBlock extends PrintableIRNode, TPrintableIRBlock { /** * An IR graph node representing an `Instruction`. */ -class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { +private class PrintableInstruction extends PrintableIRNode, TPrintableInstruction { Instruction instr; PrintableInstruction() { this = TPrintableInstruction(instr) } @@ -224,6 +234,9 @@ private string getPaddingString(int n) { n > 0 and n <= maxColumnWidth() and result = getPaddingString(n - 1) + " " } +/** + * Holds if `node` belongs to the output graph, and its property `key` has the given `value`. + */ query predicate nodes(PrintableIRNode node, string key, string value) { value = node.getProperty(key) } @@ -237,6 +250,10 @@ private int getSuccessorIndex(IRBlock pred, IRBlock succ) { ) } +/** + * Holds if the output graph contains an edge from `pred` to `succ`, and that edge's property `key` + * has the given `value`. + */ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, string value) { exists(EdgeKind kind, IRBlock predBlock, IRBlock succBlock | predBlock = pred.getBlock() and @@ -256,6 +273,9 @@ query predicate edges(PrintableIRBlock pred, PrintableIRBlock succ, string key, ) } +/** + * Holds if `parent` is the parent node of `child` in the output graph. + */ query predicate parents(PrintableIRNode child, PrintableIRNode parent) { parent = child.getParent() } From 87f0b0ef97b35e8154c6a144508143135a49e708 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Mon, 29 Jun 2020 12:10:03 -0400 Subject: [PATCH 16/20] C++: QLDoc for `EdgeKind.qll` --- .../semmle/code/cpp/ir/implementation/EdgeKind.qll | 14 ++++++++++++-- .../experimental/ir/implementation/EdgeKind.qll | 14 ++++++++++++-- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/EdgeKind.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/EdgeKind.qll index 54059fb5b82..32e36bb6787 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/EdgeKind.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/EdgeKind.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that specify the conditions under which control flows along a given edge. + */ + private import internal.EdgeKindInternal private newtype TEdgeKind = @@ -77,9 +81,15 @@ class CaseEdge extends EdgeKind, TCaseEdge { else result = "Case[" + minValue + ".." + maxValue + "]" } - string getMinValue() { result = minValue } + /** + * Gets the smallest value of the switch expression for which control will flow along this edge. + */ + final string getMinValue() { result = minValue } - string getMaxValue() { result = maxValue } + /** + * Gets the largest value of the switch expression for which control will flow along this edge. + */ + final string getMaxValue() { result = maxValue } } /** diff --git a/csharp/ql/src/experimental/ir/implementation/EdgeKind.qll b/csharp/ql/src/experimental/ir/implementation/EdgeKind.qll index 54059fb5b82..32e36bb6787 100644 --- a/csharp/ql/src/experimental/ir/implementation/EdgeKind.qll +++ b/csharp/ql/src/experimental/ir/implementation/EdgeKind.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that specify the conditions under which control flows along a given edge. + */ + private import internal.EdgeKindInternal private newtype TEdgeKind = @@ -77,9 +81,15 @@ class CaseEdge extends EdgeKind, TCaseEdge { else result = "Case[" + minValue + ".." + maxValue + "]" } - string getMinValue() { result = minValue } + /** + * Gets the smallest value of the switch expression for which control will flow along this edge. + */ + final string getMinValue() { result = minValue } - string getMaxValue() { result = maxValue } + /** + * Gets the largest value of the switch expression for which control will flow along this edge. + */ + final string getMaxValue() { result = maxValue } } /** From c52653270ea618746f11e1629f827bbafb8c7567 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Mon, 29 Jun 2020 12:14:54 -0400 Subject: [PATCH 17/20] C++: QLDoc for `IRConfiguration.qll` --- .../code/cpp/ir/implementation/IRConfiguration.qll | 9 +++++++++ .../experimental/ir/implementation/IRConfiguration.qll | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/IRConfiguration.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/IRConfiguration.qll index 71bc8ec2b0f..37ac2fccdd9 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/IRConfiguration.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/IRConfiguration.qll @@ -10,6 +10,7 @@ private newtype TIRConfiguration = MkIRConfiguration() * The query can extend this class to control which functions have IR generated for them. */ class IRConfiguration extends TIRConfiguration { + /** Gets a textual representation of this element. */ string toString() { result = "IRConfiguration" } /** @@ -17,6 +18,13 @@ class IRConfiguration extends TIRConfiguration { */ predicate shouldCreateIRForFunction(Language::Function func) { any() } + /** + * Holds if the strings used as part of an IR dump should be generated for function `func`. + * + * This predicate is overridden in `PrintIR.qll` to avoid the expense of generating a large number + * of debug strings for IR that will not be dumped. We still generate the actual IR for these + * functions, however, to preserve the results of any interprocedural analysis. + */ predicate shouldEvaluateDebugStringsForFunction(Language::Function func) { any() } } @@ -26,6 +34,7 @@ private newtype TIREscapeAnalysisConfiguration = MkIREscapeAnalysisConfiguration * The query can extend this class to control what escape analysis is used when generating SSA. */ class IREscapeAnalysisConfiguration extends TIREscapeAnalysisConfiguration { + /** Gets a textual representation of this element. */ string toString() { result = "IREscapeAnalysisConfiguration" } /** diff --git a/csharp/ql/src/experimental/ir/implementation/IRConfiguration.qll b/csharp/ql/src/experimental/ir/implementation/IRConfiguration.qll index 71bc8ec2b0f..37ac2fccdd9 100644 --- a/csharp/ql/src/experimental/ir/implementation/IRConfiguration.qll +++ b/csharp/ql/src/experimental/ir/implementation/IRConfiguration.qll @@ -10,6 +10,7 @@ private newtype TIRConfiguration = MkIRConfiguration() * The query can extend this class to control which functions have IR generated for them. */ class IRConfiguration extends TIRConfiguration { + /** Gets a textual representation of this element. */ string toString() { result = "IRConfiguration" } /** @@ -17,6 +18,13 @@ class IRConfiguration extends TIRConfiguration { */ predicate shouldCreateIRForFunction(Language::Function func) { any() } + /** + * Holds if the strings used as part of an IR dump should be generated for function `func`. + * + * This predicate is overridden in `PrintIR.qll` to avoid the expense of generating a large number + * of debug strings for IR that will not be dumped. We still generate the actual IR for these + * functions, however, to preserve the results of any interprocedural analysis. + */ predicate shouldEvaluateDebugStringsForFunction(Language::Function func) { any() } } @@ -26,6 +34,7 @@ private newtype TIREscapeAnalysisConfiguration = MkIREscapeAnalysisConfiguration * The query can extend this class to control what escape analysis is used when generating SSA. */ class IREscapeAnalysisConfiguration extends TIREscapeAnalysisConfiguration { + /** Gets a textual representation of this element. */ string toString() { result = "IREscapeAnalysisConfiguration" } /** From 1fa38474e9c85d968dc1f6e375246d413886ed1b Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Mon, 29 Jun 2020 14:09:53 -0400 Subject: [PATCH 18/20] C++: Autoformat --- .../code/cpp/ir/implementation/aliased_ssa/IR.qll | 10 +++++----- .../src/semmle/code/cpp/ir/implementation/raw/IR.qll | 10 +++++----- .../code/cpp/ir/implementation/unaliased_ssa/IR.qll | 10 +++++----- .../ql/src/experimental/ir/implementation/raw/IR.qll | 10 +++++----- .../ir/implementation/unaliased_ssa/IR.qll | 10 +++++----- 5 files changed, 25 insertions(+), 25 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IR.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IR.qll index 766ec052da3..3fa0f1b78be 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IR.qll @@ -1,12 +1,12 @@ /** * Provides classes that describe the Intermediate Representation (IR) of the program. - * + * * The IR is a representation of the semantics of the program, with very little dependence on the * syntax that was used to write the program. For example, in C++, the statements `i += 1;`, `i++`, * and `++i` all have the same semantic effect, but appear in the AST as three different types of * `Expr` node. In the IR, all three statements are broken down into a sequence of fundamental * operations similar to: - * + * * ``` * r1(int*) = VariableAddress[i] // Compute the address of variable `i` * r2(int) = Load &:r1, m0 // Load the value of `i` @@ -14,12 +14,12 @@ * r4(int) = Add r2, r3 // Add `1` to the value of `i` * r5(int) = Store &r1, r4 // Store the new value back into the variable `i` * ``` - * + * * This allows IR-based analysis to focus on the fundamental operations, rather than having to be * concerned with the various ways of expressing those operations in source code. - * + * * The key classes in the IR are: - * + * * - `IRFunction` - Contains the IR for an entire function definition, including all of that * function's `Instruction`s, `IRBlock`s, and `IRVariables`. * - `Instruction` - A single operation in the IR. An instruction specifies the operation to be diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IR.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IR.qll index 766ec052da3..3fa0f1b78be 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IR.qll @@ -1,12 +1,12 @@ /** * Provides classes that describe the Intermediate Representation (IR) of the program. - * + * * The IR is a representation of the semantics of the program, with very little dependence on the * syntax that was used to write the program. For example, in C++, the statements `i += 1;`, `i++`, * and `++i` all have the same semantic effect, but appear in the AST as three different types of * `Expr` node. In the IR, all three statements are broken down into a sequence of fundamental * operations similar to: - * + * * ``` * r1(int*) = VariableAddress[i] // Compute the address of variable `i` * r2(int) = Load &:r1, m0 // Load the value of `i` @@ -14,12 +14,12 @@ * r4(int) = Add r2, r3 // Add `1` to the value of `i` * r5(int) = Store &r1, r4 // Store the new value back into the variable `i` * ``` - * + * * This allows IR-based analysis to focus on the fundamental operations, rather than having to be * concerned with the various ways of expressing those operations in source code. - * + * * The key classes in the IR are: - * + * * - `IRFunction` - Contains the IR for an entire function definition, including all of that * function's `Instruction`s, `IRBlock`s, and `IRVariables`. * - `Instruction` - A single operation in the IR. An instruction specifies the operation to be diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IR.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IR.qll index 766ec052da3..3fa0f1b78be 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IR.qll @@ -1,12 +1,12 @@ /** * Provides classes that describe the Intermediate Representation (IR) of the program. - * + * * The IR is a representation of the semantics of the program, with very little dependence on the * syntax that was used to write the program. For example, in C++, the statements `i += 1;`, `i++`, * and `++i` all have the same semantic effect, but appear in the AST as three different types of * `Expr` node. In the IR, all three statements are broken down into a sequence of fundamental * operations similar to: - * + * * ``` * r1(int*) = VariableAddress[i] // Compute the address of variable `i` * r2(int) = Load &:r1, m0 // Load the value of `i` @@ -14,12 +14,12 @@ * r4(int) = Add r2, r3 // Add `1` to the value of `i` * r5(int) = Store &r1, r4 // Store the new value back into the variable `i` * ``` - * + * * This allows IR-based analysis to focus on the fundamental operations, rather than having to be * concerned with the various ways of expressing those operations in source code. - * + * * The key classes in the IR are: - * + * * - `IRFunction` - Contains the IR for an entire function definition, including all of that * function's `Instruction`s, `IRBlock`s, and `IRVariables`. * - `Instruction` - A single operation in the IR. An instruction specifies the operation to be diff --git a/csharp/ql/src/experimental/ir/implementation/raw/IR.qll b/csharp/ql/src/experimental/ir/implementation/raw/IR.qll index 766ec052da3..3fa0f1b78be 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/IR.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/IR.qll @@ -1,12 +1,12 @@ /** * Provides classes that describe the Intermediate Representation (IR) of the program. - * + * * The IR is a representation of the semantics of the program, with very little dependence on the * syntax that was used to write the program. For example, in C++, the statements `i += 1;`, `i++`, * and `++i` all have the same semantic effect, but appear in the AST as three different types of * `Expr` node. In the IR, all three statements are broken down into a sequence of fundamental * operations similar to: - * + * * ``` * r1(int*) = VariableAddress[i] // Compute the address of variable `i` * r2(int) = Load &:r1, m0 // Load the value of `i` @@ -14,12 +14,12 @@ * r4(int) = Add r2, r3 // Add `1` to the value of `i` * r5(int) = Store &r1, r4 // Store the new value back into the variable `i` * ``` - * + * * This allows IR-based analysis to focus on the fundamental operations, rather than having to be * concerned with the various ways of expressing those operations in source code. - * + * * The key classes in the IR are: - * + * * - `IRFunction` - Contains the IR for an entire function definition, including all of that * function's `Instruction`s, `IRBlock`s, and `IRVariables`. * - `Instruction` - A single operation in the IR. An instruction specifies the operation to be diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IR.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IR.qll index 766ec052da3..3fa0f1b78be 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IR.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IR.qll @@ -1,12 +1,12 @@ /** * Provides classes that describe the Intermediate Representation (IR) of the program. - * + * * The IR is a representation of the semantics of the program, with very little dependence on the * syntax that was used to write the program. For example, in C++, the statements `i += 1;`, `i++`, * and `++i` all have the same semantic effect, but appear in the AST as three different types of * `Expr` node. In the IR, all three statements are broken down into a sequence of fundamental * operations similar to: - * + * * ``` * r1(int*) = VariableAddress[i] // Compute the address of variable `i` * r2(int) = Load &:r1, m0 // Load the value of `i` @@ -14,12 +14,12 @@ * r4(int) = Add r2, r3 // Add `1` to the value of `i` * r5(int) = Store &r1, r4 // Store the new value back into the variable `i` * ``` - * + * * This allows IR-based analysis to focus on the fundamental operations, rather than having to be * concerned with the various ways of expressing those operations in source code. - * + * * The key classes in the IR are: - * + * * - `IRFunction` - Contains the IR for an entire function definition, including all of that * function's `Instruction`s, `IRBlock`s, and `IRVariables`. * - `Instruction` - A single operation in the IR. An instruction specifies the operation to be From 42657dbe3f26de8d4e2c9c5631a34a95221e4277 Mon Sep 17 00:00:00 2001 From: Dave Bartolomeo Date: Mon, 29 Jun 2020 14:30:12 -0400 Subject: [PATCH 19/20] C++: Miscellaneous IR QLDoc --- cpp/ql/src/semmle/code/cpp/ir/IRConfiguration.qll | 4 ++++ cpp/ql/src/semmle/code/cpp/ir/PrintIR.qll | 10 ++++++++++ .../src/semmle/code/cpp/ir/implementation/IRType.qll | 1 + .../code/cpp/ir/implementation/MemoryAccessKind.qll | 7 +++++++ .../src/semmle/code/cpp/ir/implementation/Opcode.qll | 3 +++ .../code/cpp/ir/implementation/TempVariableTag.qll | 1 + .../code/cpp/ir/implementation/aliased_ssa/IRBlock.qll | 3 ++- .../cpp/ir/implementation/aliased_ssa/IRVariable.qll | 4 ++++ .../code/cpp/ir/implementation/aliased_ssa/PrintIR.qll | 7 ++++--- .../semmle/code/cpp/ir/implementation/raw/IRBlock.qll | 3 ++- .../code/cpp/ir/implementation/raw/IRVariable.qll | 4 ++++ .../semmle/code/cpp/ir/implementation/raw/PrintIR.qll | 7 ++++--- .../cpp/ir/implementation/unaliased_ssa/IRBlock.qll | 3 ++- .../cpp/ir/implementation/unaliased_ssa/IRVariable.qll | 4 ++++ .../cpp/ir/implementation/unaliased_ssa/PrintIR.qll | 7 ++++--- .../ql/src/experimental/ir/implementation/IRType.qll | 1 + .../ir/implementation/MemoryAccessKind.qll | 7 +++++++ .../ql/src/experimental/ir/implementation/Opcode.qll | 3 +++ .../experimental/ir/implementation/TempVariableTag.qll | 1 + .../src/experimental/ir/implementation/raw/IRBlock.qll | 3 ++- .../experimental/ir/implementation/raw/IRVariable.qll | 4 ++++ .../src/experimental/ir/implementation/raw/PrintIR.qll | 7 ++++--- .../ir/implementation/unaliased_ssa/IRBlock.qll | 3 ++- .../ir/implementation/unaliased_ssa/IRVariable.qll | 4 ++++ .../ir/implementation/unaliased_ssa/PrintIR.qll | 7 ++++--- 25 files changed, 88 insertions(+), 20 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/IRConfiguration.qll b/cpp/ql/src/semmle/code/cpp/ir/IRConfiguration.qll index b5b7d7de7c2..b8abef8a547 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/IRConfiguration.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/IRConfiguration.qll @@ -1 +1,5 @@ +/** + * Module used to configure the IR generation process. + */ + import implementation.IRConfiguration diff --git a/cpp/ql/src/semmle/code/cpp/ir/PrintIR.qll b/cpp/ql/src/semmle/code/cpp/ir/PrintIR.qll index 3ff80237635..c4ebf2f1eba 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/PrintIR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/PrintIR.qll @@ -1 +1,11 @@ +/** + * Outputs a representation of the IR as a control flow graph. + * + * This file contains the actual implementation of `PrintIR.ql`. For test cases and very small + * databases, `PrintIR.ql` can be run directly to dump the IR for the entire database. For most + * uses, however, it is better to write a query that imports `PrintIR.qll`, extends + * `PrintIRConfiguration`, and overrides `shouldPrintFunction()` to select a subset of functions to + * dump. + */ + import implementation.aliased_ssa.PrintIR 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 dec78b413b3..41c9ac06d82 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/IRType.qll @@ -32,6 +32,7 @@ private newtype TIRType = * all pointer types map to the same instance of `IRAddressType`. */ class IRType extends TIRType { + /** Gets a textual representation of this type. */ string toString() { none() } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/MemoryAccessKind.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/MemoryAccessKind.qll index 6852a965401..5e11a310e2f 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/MemoryAccessKind.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/MemoryAccessKind.qll @@ -1,3 +1,9 @@ +/** + * Provides classes that describe how a particular `Instruction` or its operands access memory. + */ + +private import IRConfiguration + private newtype TMemoryAccessKind = TIndirectMemoryAccess() or TBufferMemoryAccess() or @@ -14,6 +20,7 @@ private newtype TMemoryAccessKind = * memory result. */ class MemoryAccessKind extends TMemoryAccessKind { + /** Gets a textual representation of this access kind. */ string toString() { none() } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll index aca058ab47c..c4134d240ab 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/Opcode.qll @@ -91,6 +91,9 @@ private newtype TOpcode = TUnreached() or TNewObj() +/** + * An opcode that specifies the operation performed by an `Instruction`. + */ class Opcode extends TOpcode { /** Gets a textual representation of this element. */ string toString() { result = "UnknownOpcode" } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/TempVariableTag.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/TempVariableTag.qll index a0c0ca67530..5f230de560d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/TempVariableTag.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/TempVariableTag.qll @@ -12,5 +12,6 @@ private import Imports::TempVariableTag * computed on each branch. The set of possible `TempVariableTag`s is language-dependent. */ class TempVariableTag extends TTempVariableTag { + /** Gets a textual representation of this tag. */ string toString() { result = getTempVariableTagId(this) } } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll index bff7b179604..f84b5d2f98b 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll @@ -20,6 +20,7 @@ private import Cached * Most consumers should use the class `IRBlock`. */ class IRBlockBase extends TIRBlock { + /** Gets a textual representation of this block. */ final string toString() { result = getFirstInstruction(this).toString() } /** Gets the source location of the first non-`Phi` instruction in this block. */ @@ -282,4 +283,4 @@ private module Cached { idominance(isEntryBlock/1, blockSuccessor/2)(_, dominator, block) } -Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) } +private Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll index 7b7744e3af1..d317421c242 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRVariable.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent variables accessed by the IR. + */ + private import internal.IRInternal import IRFunction private import internal.IRVariableImports as Imports diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.qll index 82c6538601a..b3e3a5b1195 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/PrintIR.qll @@ -1,9 +1,9 @@ /** * Outputs a representation of the IR as a control flow graph. * - * This file contains the actual implementation of `PrintAST.ql`. For test cases and very small - * databases, `PrintAST.ql` can be run directly to dump the IR for the entire database. For most - * uses, however, it is better to write a query that imports `PrintAST.qll`, extends + * This file contains the actual implementation of `PrintIR.ql`. For test cases and very small + * databases, `PrintIR.ql` can be run directly to dump the IR for the entire database. For most + * uses, however, it is better to write a query that imports `PrintIR.qll`, extends * `PrintIRConfiguration`, and overrides `shouldPrintFunction()` to select a subset of functions to * dump. */ @@ -19,6 +19,7 @@ private newtype TPrintIRConfiguration = MkPrintIRConfiguration() * The query can extend this class to control which functions are printed. */ class PrintIRConfiguration extends TPrintIRConfiguration { + /** Gets a textual representation of this configuration. */ string toString() { result = "PrintIRConfiguration" } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll index bff7b179604..f84b5d2f98b 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll @@ -20,6 +20,7 @@ private import Cached * Most consumers should use the class `IRBlock`. */ class IRBlockBase extends TIRBlock { + /** Gets a textual representation of this block. */ final string toString() { result = getFirstInstruction(this).toString() } /** Gets the source location of the first non-`Phi` instruction in this block. */ @@ -282,4 +283,4 @@ private module Cached { idominance(isEntryBlock/1, blockSuccessor/2)(_, dominator, block) } -Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) } +private Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll index 7b7744e3af1..d317421c242 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRVariable.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent variables accessed by the IR. + */ + private import internal.IRInternal import IRFunction private import internal.IRVariableImports as Imports diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/PrintIR.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/PrintIR.qll index 82c6538601a..b3e3a5b1195 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/PrintIR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/PrintIR.qll @@ -1,9 +1,9 @@ /** * Outputs a representation of the IR as a control flow graph. * - * This file contains the actual implementation of `PrintAST.ql`. For test cases and very small - * databases, `PrintAST.ql` can be run directly to dump the IR for the entire database. For most - * uses, however, it is better to write a query that imports `PrintAST.qll`, extends + * This file contains the actual implementation of `PrintIR.ql`. For test cases and very small + * databases, `PrintIR.ql` can be run directly to dump the IR for the entire database. For most + * uses, however, it is better to write a query that imports `PrintIR.qll`, extends * `PrintIRConfiguration`, and overrides `shouldPrintFunction()` to select a subset of functions to * dump. */ @@ -19,6 +19,7 @@ private newtype TPrintIRConfiguration = MkPrintIRConfiguration() * The query can extend this class to control which functions are printed. */ class PrintIRConfiguration extends TPrintIRConfiguration { + /** Gets a textual representation of this configuration. */ string toString() { result = "PrintIRConfiguration" } /** diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll index bff7b179604..f84b5d2f98b 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll @@ -20,6 +20,7 @@ private import Cached * Most consumers should use the class `IRBlock`. */ class IRBlockBase extends TIRBlock { + /** Gets a textual representation of this block. */ final string toString() { result = getFirstInstruction(this).toString() } /** Gets the source location of the first non-`Phi` instruction in this block. */ @@ -282,4 +283,4 @@ private module Cached { idominance(isEntryBlock/1, blockSuccessor/2)(_, dominator, block) } -Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) } +private Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll index 7b7744e3af1..d317421c242 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRVariable.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent variables accessed by the IR. + */ + private import internal.IRInternal import IRFunction private import internal.IRVariableImports as Imports diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/PrintIR.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/PrintIR.qll index 82c6538601a..b3e3a5b1195 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/PrintIR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/PrintIR.qll @@ -1,9 +1,9 @@ /** * Outputs a representation of the IR as a control flow graph. * - * This file contains the actual implementation of `PrintAST.ql`. For test cases and very small - * databases, `PrintAST.ql` can be run directly to dump the IR for the entire database. For most - * uses, however, it is better to write a query that imports `PrintAST.qll`, extends + * This file contains the actual implementation of `PrintIR.ql`. For test cases and very small + * databases, `PrintIR.ql` can be run directly to dump the IR for the entire database. For most + * uses, however, it is better to write a query that imports `PrintIR.qll`, extends * `PrintIRConfiguration`, and overrides `shouldPrintFunction()` to select a subset of functions to * dump. */ @@ -19,6 +19,7 @@ private newtype TPrintIRConfiguration = MkPrintIRConfiguration() * The query can extend this class to control which functions are printed. */ class PrintIRConfiguration extends TPrintIRConfiguration { + /** Gets a textual representation of this configuration. */ string toString() { result = "PrintIRConfiguration" } /** diff --git a/csharp/ql/src/experimental/ir/implementation/IRType.qll b/csharp/ql/src/experimental/ir/implementation/IRType.qll index dec78b413b3..41c9ac06d82 100644 --- a/csharp/ql/src/experimental/ir/implementation/IRType.qll +++ b/csharp/ql/src/experimental/ir/implementation/IRType.qll @@ -32,6 +32,7 @@ private newtype TIRType = * all pointer types map to the same instance of `IRAddressType`. */ class IRType extends TIRType { + /** Gets a textual representation of this type. */ string toString() { none() } /** diff --git a/csharp/ql/src/experimental/ir/implementation/MemoryAccessKind.qll b/csharp/ql/src/experimental/ir/implementation/MemoryAccessKind.qll index 6852a965401..5e11a310e2f 100644 --- a/csharp/ql/src/experimental/ir/implementation/MemoryAccessKind.qll +++ b/csharp/ql/src/experimental/ir/implementation/MemoryAccessKind.qll @@ -1,3 +1,9 @@ +/** + * Provides classes that describe how a particular `Instruction` or its operands access memory. + */ + +private import IRConfiguration + private newtype TMemoryAccessKind = TIndirectMemoryAccess() or TBufferMemoryAccess() or @@ -14,6 +20,7 @@ private newtype TMemoryAccessKind = * memory result. */ class MemoryAccessKind extends TMemoryAccessKind { + /** Gets a textual representation of this access kind. */ string toString() { none() } /** diff --git a/csharp/ql/src/experimental/ir/implementation/Opcode.qll b/csharp/ql/src/experimental/ir/implementation/Opcode.qll index aca058ab47c..c4134d240ab 100644 --- a/csharp/ql/src/experimental/ir/implementation/Opcode.qll +++ b/csharp/ql/src/experimental/ir/implementation/Opcode.qll @@ -91,6 +91,9 @@ private newtype TOpcode = TUnreached() or TNewObj() +/** + * An opcode that specifies the operation performed by an `Instruction`. + */ class Opcode extends TOpcode { /** Gets a textual representation of this element. */ string toString() { result = "UnknownOpcode" } diff --git a/csharp/ql/src/experimental/ir/implementation/TempVariableTag.qll b/csharp/ql/src/experimental/ir/implementation/TempVariableTag.qll index a0c0ca67530..5f230de560d 100644 --- a/csharp/ql/src/experimental/ir/implementation/TempVariableTag.qll +++ b/csharp/ql/src/experimental/ir/implementation/TempVariableTag.qll @@ -12,5 +12,6 @@ private import Imports::TempVariableTag * computed on each branch. The set of possible `TempVariableTag`s is language-dependent. */ class TempVariableTag extends TTempVariableTag { + /** Gets a textual representation of this tag. */ string toString() { result = getTempVariableTagId(this) } } diff --git a/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll b/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll index bff7b179604..f84b5d2f98b 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll @@ -20,6 +20,7 @@ private import Cached * Most consumers should use the class `IRBlock`. */ class IRBlockBase extends TIRBlock { + /** Gets a textual representation of this block. */ final string toString() { result = getFirstInstruction(this).toString() } /** Gets the source location of the first non-`Phi` instruction in this block. */ @@ -282,4 +283,4 @@ private module Cached { idominance(isEntryBlock/1, blockSuccessor/2)(_, dominator, block) } -Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) } +private Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) } diff --git a/csharp/ql/src/experimental/ir/implementation/raw/IRVariable.qll b/csharp/ql/src/experimental/ir/implementation/raw/IRVariable.qll index 7b7744e3af1..d317421c242 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/IRVariable.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/IRVariable.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent variables accessed by the IR. + */ + private import internal.IRInternal import IRFunction private import internal.IRVariableImports as Imports diff --git a/csharp/ql/src/experimental/ir/implementation/raw/PrintIR.qll b/csharp/ql/src/experimental/ir/implementation/raw/PrintIR.qll index 82c6538601a..b3e3a5b1195 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/PrintIR.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/PrintIR.qll @@ -1,9 +1,9 @@ /** * Outputs a representation of the IR as a control flow graph. * - * This file contains the actual implementation of `PrintAST.ql`. For test cases and very small - * databases, `PrintAST.ql` can be run directly to dump the IR for the entire database. For most - * uses, however, it is better to write a query that imports `PrintAST.qll`, extends + * This file contains the actual implementation of `PrintIR.ql`. For test cases and very small + * databases, `PrintIR.ql` can be run directly to dump the IR for the entire database. For most + * uses, however, it is better to write a query that imports `PrintIR.qll`, extends * `PrintIRConfiguration`, and overrides `shouldPrintFunction()` to select a subset of functions to * dump. */ @@ -19,6 +19,7 @@ private newtype TPrintIRConfiguration = MkPrintIRConfiguration() * The query can extend this class to control which functions are printed. */ class PrintIRConfiguration extends TPrintIRConfiguration { + /** Gets a textual representation of this configuration. */ string toString() { result = "PrintIRConfiguration" } /** diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll index bff7b179604..f84b5d2f98b 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll @@ -20,6 +20,7 @@ private import Cached * Most consumers should use the class `IRBlock`. */ class IRBlockBase extends TIRBlock { + /** Gets a textual representation of this block. */ final string toString() { result = getFirstInstruction(this).toString() } /** Gets the source location of the first non-`Phi` instruction in this block. */ @@ -282,4 +283,4 @@ private module Cached { idominance(isEntryBlock/1, blockSuccessor/2)(_, dominator, block) } -Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) } +private Instruction getFirstInstruction(TIRBlock block) { block = MkIRBlock(result) } diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRVariable.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRVariable.qll index 7b7744e3af1..d317421c242 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRVariable.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRVariable.qll @@ -1,3 +1,7 @@ +/** + * Provides classes that represent variables accessed by the IR. + */ + private import internal.IRInternal import IRFunction private import internal.IRVariableImports as Imports diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/PrintIR.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/PrintIR.qll index 82c6538601a..b3e3a5b1195 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/PrintIR.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/PrintIR.qll @@ -1,9 +1,9 @@ /** * Outputs a representation of the IR as a control flow graph. * - * This file contains the actual implementation of `PrintAST.ql`. For test cases and very small - * databases, `PrintAST.ql` can be run directly to dump the IR for the entire database. For most - * uses, however, it is better to write a query that imports `PrintAST.qll`, extends + * This file contains the actual implementation of `PrintIR.ql`. For test cases and very small + * databases, `PrintIR.ql` can be run directly to dump the IR for the entire database. For most + * uses, however, it is better to write a query that imports `PrintIR.qll`, extends * `PrintIRConfiguration`, and overrides `shouldPrintFunction()` to select a subset of functions to * dump. */ @@ -19,6 +19,7 @@ private newtype TPrintIRConfiguration = MkPrintIRConfiguration() * The query can extend this class to control which functions are printed. */ class PrintIRConfiguration extends TPrintIRConfiguration { + /** Gets a textual representation of this configuration. */ string toString() { result = "PrintIRConfiguration" } /** From 47bb007b9a7b605a874075314f24844239cbe0fc Mon Sep 17 00:00:00 2001 From: Jonas Jensen Date: Tue, 30 Jun 2020 09:56:39 +0200 Subject: [PATCH 20/20] C++: Autoformat fixups --- cpp/ql/src/semmle/code/cpp/ir/IR.qll | 10 +++++----- .../code/cpp/ir/implementation/aliased_ssa/IRBlock.qll | 2 +- .../semmle/code/cpp/ir/implementation/raw/IRBlock.qll | 2 +- .../cpp/ir/implementation/unaliased_ssa/IRBlock.qll | 2 +- .../src/experimental/ir/implementation/raw/IRBlock.qll | 2 +- .../ir/implementation/unaliased_ssa/IRBlock.qll | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/IR.qll b/cpp/ql/src/semmle/code/cpp/ir/IR.qll index f418923b3f0..381adad5e41 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/IR.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/IR.qll @@ -1,12 +1,12 @@ /** * Provides classes that describe the Intermediate Representation (IR) of the program. - * + * * The IR is a representation of the semantics of the program, with very little dependence on the * syntax that was used to write the program. For example, in C++, the statements `i += 1;`, `i++`, * and `++i` all have the same semantic effect, but appear in the AST as three different types of * `Expr` node. In the IR, all three statements are broken down into a sequence of fundamental * operations similar to: - * + * * ``` * r1(int*) = VariableAddress[i] // Compute the address of variable `i` * r2(int) = Load &:r1, m0 // Load the value of `i` @@ -14,12 +14,12 @@ * r4(int) = Add r2, r3 // Add `1` to the value of `i` * r5(int) = Store &r1, r4 // Store the new value back into the variable `i` * ``` - * + * * This allows IR-based analysis to focus on the fundamental operations, rather than having to be * concerned with the various ways of expressing those operations in source code. - * + * * The key classes in the IR are: - * + * * - `IRFunction` - Contains the IR for an entire function definition, including all of that * function's `Instruction`s, `IRBlock`s, and `IRVariables`. * - `Instruction` - A single operation in the IR. An instruction specifies the operation to be diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll index f84b5d2f98b..f0ec0683bd6 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/IRBlock.qll @@ -126,7 +126,7 @@ class IRBlock extends IRBlockBase { final IRBlock getSuccessor(EdgeKind kind) { blockSuccessor(this, result, kind) } /** - * Gets the block to which control flows directly from this block along a back edge of kind + * Gets the block to which control flows directly from this block along a back edge of kind * `kind`. */ final IRBlock getBackEdgeSuccessor(EdgeKind kind) { backEdgeSuccessor(this, result, kind) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll index f84b5d2f98b..f0ec0683bd6 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/IRBlock.qll @@ -126,7 +126,7 @@ class IRBlock extends IRBlockBase { final IRBlock getSuccessor(EdgeKind kind) { blockSuccessor(this, result, kind) } /** - * Gets the block to which control flows directly from this block along a back edge of kind + * Gets the block to which control flows directly from this block along a back edge of kind * `kind`. */ final IRBlock getBackEdgeSuccessor(EdgeKind kind) { backEdgeSuccessor(this, result, kind) } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll index f84b5d2f98b..f0ec0683bd6 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/IRBlock.qll @@ -126,7 +126,7 @@ class IRBlock extends IRBlockBase { final IRBlock getSuccessor(EdgeKind kind) { blockSuccessor(this, result, kind) } /** - * Gets the block to which control flows directly from this block along a back edge of kind + * Gets the block to which control flows directly from this block along a back edge of kind * `kind`. */ final IRBlock getBackEdgeSuccessor(EdgeKind kind) { backEdgeSuccessor(this, result, kind) } diff --git a/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll b/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll index f84b5d2f98b..f0ec0683bd6 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/IRBlock.qll @@ -126,7 +126,7 @@ class IRBlock extends IRBlockBase { final IRBlock getSuccessor(EdgeKind kind) { blockSuccessor(this, result, kind) } /** - * Gets the block to which control flows directly from this block along a back edge of kind + * Gets the block to which control flows directly from this block along a back edge of kind * `kind`. */ final IRBlock getBackEdgeSuccessor(EdgeKind kind) { backEdgeSuccessor(this, result, kind) } diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll index f84b5d2f98b..f0ec0683bd6 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/IRBlock.qll @@ -126,7 +126,7 @@ class IRBlock extends IRBlockBase { final IRBlock getSuccessor(EdgeKind kind) { blockSuccessor(this, result, kind) } /** - * Gets the block to which control flows directly from this block along a back edge of kind + * Gets the block to which control flows directly from this block along a back edge of kind * `kind`. */ final IRBlock getBackEdgeSuccessor(EdgeKind kind) { backEdgeSuccessor(this, result, kind) }