From 1e08c11d4049219032f1f9326e907e2830a44bca Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Mon, 7 Dec 2020 17:22:10 -0800 Subject: [PATCH 001/142] C++: Share Operand IPA type across IR stages --- .../ir/implementation/aliased_ssa/Operand.qll | 89 ++--------- .../aliased_ssa/internal/OperandImports.qll | 1 + .../aliased_ssa/internal/OperandInternal.qll | 2 + .../aliased_ssa/internal/SSAConstruction.qll | 4 + .../internal/SSAConstructionImports.qll | 1 + .../internal/SSAConstructionInternal.qll | 1 + .../ir/implementation/internal/TOperand.qll | 148 ++++++++++++++++++ .../cpp/ir/implementation/raw/Operand.qll | 89 ++--------- .../raw/internal/OperandImports.qll | 1 + .../raw/internal/OperandInternal.qll | 2 + .../implementation/unaliased_ssa/Operand.qll | 89 ++--------- .../unaliased_ssa/internal/OperandImports.qll | 1 + .../internal/OperandInternal.qll | 2 + .../internal/SSAConstruction.qll | 4 + .../internal/SSAConstructionImports.qll | 1 + .../internal/SSAConstructionInternal.qll | 1 + 16 files changed, 217 insertions(+), 219 deletions(-) create mode 100644 cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/OperandInternal.qll create mode 100644 cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TOperand.qll create mode 100644 cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/OperandInternal.qll create mode 100644 cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/OperandInternal.qll 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 a12e35d471b..3a699fa3c4e 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 @@ -10,73 +10,10 @@ private import Imports::MemoryAccessKind private import Imports::IRType private import Imports::Overlap private import Imports::OperandTag +private import Imports::TOperand +private import internal.OperandInternal -cached -private newtype TOperand = - TRegisterOperand(Instruction useInstr, RegisterOperandTag tag, Instruction defInstr) { - defInstr = Construction::getRegisterOperandDefinition(useInstr, tag) and - not Construction::isInCycle(useInstr) and - strictcount(Construction::getRegisterOperandDefinition(useInstr, tag)) = 1 - } or - TNonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) { - useInstr.getOpcode().hasOperand(tag) - } or - TPhiOperand( - PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap - ) { - defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap) - } - -/** - * Base class for all register operands. This is a placeholder for the IPA union type that we will - * eventually use for this purpose. - */ -private class RegisterOperandBase extends TRegisterOperand { - /** Gets a textual representation of this element. */ - abstract string toString(); -} - -/** - * Returns the register operand with the specified parameters. - */ -private RegisterOperandBase registerOperand( - Instruction useInstr, RegisterOperandTag tag, Instruction defInstr -) { - result = TRegisterOperand(useInstr, tag, defInstr) -} - -/** - * Base class for all non-Phi memory operands. This is a placeholder for the IPA union type that we - * will eventually use for this purpose. - */ -private class NonPhiMemoryOperandBase extends TNonPhiMemoryOperand { - /** Gets a textual representation of this element. */ - abstract string toString(); -} - -/** - * Returns the non-Phi memory operand with the specified parameters. - */ -private NonPhiMemoryOperandBase nonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) { - result = TNonPhiMemoryOperand(useInstr, tag) -} - -/** - * Base class for all Phi operands. This is a placeholder for the IPA union type that we will - * eventually use for this purpose. - */ -private class PhiOperandBase extends TPhiOperand { - abstract string toString(); -} - -/** - * Returns the Phi operand with the specified parameters. - */ -private PhiOperandBase phiOperand( - Instruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap -) { - result = TPhiOperand(useInstr, defInstr, predecessorBlock, overlap) -} +class TOperand = TRegisterOperand or TNonSSAMemoryOperand or TPhiOperand or TChiOperand; /** * An operand of an `Instruction`. The operand represents a use of the result of one instruction @@ -239,8 +176,9 @@ class Operand extends TOperand { */ class MemoryOperand extends Operand { MemoryOperand() { - this instanceof NonPhiMemoryOperandBase or - this instanceof PhiOperandBase + this instanceof TNonSSAMemoryOperand or + this instanceof TPhiOperand or + this instanceof TChiOperand } /** @@ -278,7 +216,8 @@ class NonPhiOperand extends Operand { NonPhiOperand() { this = registerOperand(useInstr, tag, _) or - this = nonPhiMemoryOperand(useInstr, tag) + this = nonSSAMemoryOperand(useInstr, tag) or + this = chiOperand(useInstr, tag) } final override Instruction getUse() { result = useInstr } @@ -298,7 +237,7 @@ class NonPhiOperand extends Operand { /** * An operand that consumes a register (non-memory) result. */ -class RegisterOperand extends NonPhiOperand, RegisterOperandBase { +class RegisterOperand extends NonPhiOperand, TRegisterOperand { override RegisterOperandTag tag; Instruction defInstr; @@ -317,10 +256,14 @@ class RegisterOperand extends NonPhiOperand, RegisterOperandBase { /** * A memory operand other than the operand of a `Phi` instruction. */ -class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOperandBase { +class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand { override MemoryOperandTag tag; - NonPhiMemoryOperand() { this = nonPhiMemoryOperand(useInstr, tag) } + NonPhiMemoryOperand() { + this = nonSSAMemoryOperand(useInstr, tag) + or + this = chiOperand(useInstr, tag) + } final override string toString() { result = tag.toString() } @@ -462,7 +405,7 @@ class SideEffectOperand extends TypedOperand { /** * An operand of a `PhiInstruction`. */ -class PhiInputOperand extends MemoryOperand, PhiOperandBase { +class PhiInputOperand extends MemoryOperand, TPhiOperand { PhiInstruction useInstr; Instruction defInstr; IRBlock predecessorBlock; diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/OperandImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/OperandImports.qll index 3c781579cee..d0e013d1fba 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/OperandImports.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/OperandImports.qll @@ -2,3 +2,4 @@ import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind import semmle.code.cpp.ir.implementation.IRType as IRType import semmle.code.cpp.ir.internal.Overlap as Overlap import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag +import semmle.code.cpp.ir.implementation.internal.TOperand as TOperand diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/OperandInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/OperandInternal.qll new file mode 100644 index 00000000000..b47c20e97ef --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/OperandInternal.qll @@ -0,0 +1,2 @@ +private import semmle.code.cpp.ir.implementation.internal.TOperand +import AliasedSSAOperands diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll index 8e904ee6bc4..ad6f3fc8eb2 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll @@ -6,6 +6,7 @@ private import Imports::Overlap private import Imports::TInstruction private import Imports::RawIR as RawIR private import SSAInstructions +private import SSAOperands private import NewIR private class OldBlock = Reachability::ReachableBlock; @@ -42,6 +43,9 @@ private module Cached { class TStageInstruction = TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction; + class TStageOperand = + TRegisterOperand or TNonSSAMemoryOperand or TPhiOperand or TChiOperand; + cached predicate hasInstruction(TStageInstruction instr) { instr instanceof TRawInstruction and instr instanceof OldInstruction diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionImports.qll index f347df86ba1..2e5b8cc6ed3 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionImports.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionImports.qll @@ -3,3 +3,4 @@ import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag import semmle.code.cpp.ir.internal.Overlap as Overlap import semmle.code.cpp.ir.implementation.internal.TInstruction as TInstruction import semmle.code.cpp.ir.implementation.raw.IR as RawIR +import semmle.code.cpp.ir.implementation.internal.TOperand as TOperand \ No newline at end of file diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionInternal.qll index bb068bdd489..e42895e56b6 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionInternal.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionInternal.qll @@ -5,3 +5,4 @@ import semmle.code.cpp.ir.implementation.aliased_ssa.IR as NewIR import semmle.code.cpp.ir.implementation.internal.TInstruction::AliasedSSAInstructions as SSAInstructions import semmle.code.cpp.ir.internal.IRCppLanguage as Language import AliasedSSA as Alias +import semmle.code.cpp.ir.implementation.internal.TOperand::UnliasedSSAOperands as SSAOperands diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TOperand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TOperand.qll new file mode 100644 index 00000000000..696d372bc15 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TOperand.qll @@ -0,0 +1,148 @@ +private import TInstruction +private import OperandTag +private import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as RawConstruction +private import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.SSAConstruction as UnaliasedConstruction +private import semmle.code.cpp.ir.implementation.aliased_ssa.internal.SSAConstruction as AliasedConstruction +private import semmle.code.cpp.ir.implementation.raw.IR as Raw +private import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as Unaliased +private import semmle.code.cpp.ir.implementation.aliased_ssa.IR as Aliased +private import semmle.code.cpp.ir.internal.Overlap + +private module Internal { + cached + newtype TOperand = + // RAW + TRegisterOperand(TRawInstruction useInstr, RegisterOperandTag tag, TRawInstruction defInstr) { + defInstr = RawConstruction::getRegisterOperandDefinition(useInstr, tag) and + not RawConstruction::isInCycle(useInstr) and + strictcount(RawConstruction::getRegisterOperandDefinition(useInstr, tag)) = 1 + } or + // Placeholder for Phi and Chi operands in stages that don't have the corresponding instructions + TNoOperand() { none() } or + // Can be "removed" later when there's unreachable code + // These operands can be reused across all three stages. They just get different defs. + TNonSSAMemoryOperand(Raw::Instruction useInstr, MemoryOperandTag tag) { + // Has no definition in raw but will get definitions later + useInstr.getOpcode().hasOperand(tag) + } or + TUnaliasedPhiOperand( + Unaliased::PhiInstruction useInstr, Unaliased::Instruction defInstr, + Unaliased::IRBlock predecessorBlock, Overlap overlap + ) { + defInstr = UnaliasedConstruction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap) + } or + //// ALIASED + //// + // If we share SSA, these will be all the phis there are. Otherwise these + // will add to the ones that are already there. + // If we share SSA, be careful with the case where we remove all possible + // indirect writes to a variable because they're dead code. In that case it's + // important that we use the same definition of "is variable aliased" across + // the phases. + TAliasedPhiOperand( + TAliasedSSAPhiInstruction useInstr, Aliased::Instruction defInstr, + Aliased::IRBlock predecessorBlock, Overlap overlap + ) { + defInstr = AliasedConstruction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap) + } or + TAliasedChiOperand(TAliasedSSAChiInstruction useInstr, ChiOperandTag tag) { + // TODO: any further restrictions here? + any() + } +} + +private module Shared { + class TRegisterOperand = Internal::TRegisterOperand; + + /** + * Returns the register operand with the specified parameters. + */ + TRegisterOperand registerOperand( + TRawInstruction useInstr, RegisterOperandTag tag, TRawInstruction defInstr + ) { + result = Internal::TRegisterOperand(useInstr, tag, defInstr) + } + + class TNonSSAMemoryOperand = Internal::TNonSSAMemoryOperand; + + /** + * Returns the non-Phi memory operand with the specified parameters. + */ + TNonSSAMemoryOperand nonSSAMemoryOperand(TRawInstruction useInstr, MemoryOperandTag tag) { + result = Internal::TNonSSAMemoryOperand(useInstr, tag) + } +} + +module RawOperands { + import Shared + + class TPhiOperand = Internal::TNoOperand; + + class TChiOperand = Internal::TNoOperand; + + /** + * Returns the Phi operand with the specified parameters. + */ + TPhiOperand phiOperand( + Raw::PhiInstruction useInstr, Raw::Instruction defInstr, Raw::IRBlock predecessorBlock, + Overlap overlap + ) { + none() + } + + /** + * Returns the Chi operand with the specified parameters. + */ + TChiOperand chiOperand(Raw::Instruction useInstr, ChiOperandTag tag) { none() } +} + +// TODO: can we get everything into either here or Operand.qll? +// TODO: can we put `TStageOperand` in Construction? Might break something about the module caching setup, `Operand` is currently after everything in SSAConstruction +// TODO: share empty ChiOperand? +module UnliasedSSAOperands { + import Shared + + class TPhiOperand = Internal::TUnaliasedPhiOperand; + + class TChiOperand = Internal::TNoOperand; + + /** + * Returns the Phi operand with the specified parameters. + */ + TPhiOperand phiOperand( + Unaliased::PhiInstruction useInstr, Unaliased::Instruction defInstr, + Unaliased::IRBlock predecessorBlock, Overlap overlap + ) { + result = Internal::TUnaliasedPhiOperand(useInstr, defInstr, predecessorBlock, overlap) + } + + /** + * Returns the Chi operand with the specified parameters. + */ + TChiOperand chiOperand(Unaliased::Instruction useInstr, ChiOperandTag tag) { none() } +} + +module AliasedSSAOperands { + import Shared + + class TPhiOperand = Internal::TAliasedPhiOperand; + + class TChiOperand = Internal::TAliasedChiOperand; + + /** + * Returns the Phi operand with the specified parameters. + */ + TPhiOperand phiOperand( + TAliasedSSAPhiInstruction useInstr, Aliased::Instruction defInstr, + Aliased::IRBlock predecessorBlock, Overlap overlap + ) { + result = Internal::TAliasedPhiOperand(useInstr, defInstr, predecessorBlock, overlap) + } + + /** + * Returns the Chi operand with the specified parameters. + */ + TChiOperand chiOperand(TAliasedSSAChiInstruction useInstr, ChiOperandTag tag) { + result = Internal::TAliasedChiOperand(useInstr, 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 a12e35d471b..3a699fa3c4e 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 @@ -10,73 +10,10 @@ private import Imports::MemoryAccessKind private import Imports::IRType private import Imports::Overlap private import Imports::OperandTag +private import Imports::TOperand +private import internal.OperandInternal -cached -private newtype TOperand = - TRegisterOperand(Instruction useInstr, RegisterOperandTag tag, Instruction defInstr) { - defInstr = Construction::getRegisterOperandDefinition(useInstr, tag) and - not Construction::isInCycle(useInstr) and - strictcount(Construction::getRegisterOperandDefinition(useInstr, tag)) = 1 - } or - TNonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) { - useInstr.getOpcode().hasOperand(tag) - } or - TPhiOperand( - PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap - ) { - defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap) - } - -/** - * Base class for all register operands. This is a placeholder for the IPA union type that we will - * eventually use for this purpose. - */ -private class RegisterOperandBase extends TRegisterOperand { - /** Gets a textual representation of this element. */ - abstract string toString(); -} - -/** - * Returns the register operand with the specified parameters. - */ -private RegisterOperandBase registerOperand( - Instruction useInstr, RegisterOperandTag tag, Instruction defInstr -) { - result = TRegisterOperand(useInstr, tag, defInstr) -} - -/** - * Base class for all non-Phi memory operands. This is a placeholder for the IPA union type that we - * will eventually use for this purpose. - */ -private class NonPhiMemoryOperandBase extends TNonPhiMemoryOperand { - /** Gets a textual representation of this element. */ - abstract string toString(); -} - -/** - * Returns the non-Phi memory operand with the specified parameters. - */ -private NonPhiMemoryOperandBase nonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) { - result = TNonPhiMemoryOperand(useInstr, tag) -} - -/** - * Base class for all Phi operands. This is a placeholder for the IPA union type that we will - * eventually use for this purpose. - */ -private class PhiOperandBase extends TPhiOperand { - abstract string toString(); -} - -/** - * Returns the Phi operand with the specified parameters. - */ -private PhiOperandBase phiOperand( - Instruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap -) { - result = TPhiOperand(useInstr, defInstr, predecessorBlock, overlap) -} +class TOperand = TRegisterOperand or TNonSSAMemoryOperand or TPhiOperand or TChiOperand; /** * An operand of an `Instruction`. The operand represents a use of the result of one instruction @@ -239,8 +176,9 @@ class Operand extends TOperand { */ class MemoryOperand extends Operand { MemoryOperand() { - this instanceof NonPhiMemoryOperandBase or - this instanceof PhiOperandBase + this instanceof TNonSSAMemoryOperand or + this instanceof TPhiOperand or + this instanceof TChiOperand } /** @@ -278,7 +216,8 @@ class NonPhiOperand extends Operand { NonPhiOperand() { this = registerOperand(useInstr, tag, _) or - this = nonPhiMemoryOperand(useInstr, tag) + this = nonSSAMemoryOperand(useInstr, tag) or + this = chiOperand(useInstr, tag) } final override Instruction getUse() { result = useInstr } @@ -298,7 +237,7 @@ class NonPhiOperand extends Operand { /** * An operand that consumes a register (non-memory) result. */ -class RegisterOperand extends NonPhiOperand, RegisterOperandBase { +class RegisterOperand extends NonPhiOperand, TRegisterOperand { override RegisterOperandTag tag; Instruction defInstr; @@ -317,10 +256,14 @@ class RegisterOperand extends NonPhiOperand, RegisterOperandBase { /** * A memory operand other than the operand of a `Phi` instruction. */ -class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOperandBase { +class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand { override MemoryOperandTag tag; - NonPhiMemoryOperand() { this = nonPhiMemoryOperand(useInstr, tag) } + NonPhiMemoryOperand() { + this = nonSSAMemoryOperand(useInstr, tag) + or + this = chiOperand(useInstr, tag) + } final override string toString() { result = tag.toString() } @@ -462,7 +405,7 @@ class SideEffectOperand extends TypedOperand { /** * An operand of a `PhiInstruction`. */ -class PhiInputOperand extends MemoryOperand, PhiOperandBase { +class PhiInputOperand extends MemoryOperand, TPhiOperand { PhiInstruction useInstr; Instruction defInstr; IRBlock predecessorBlock; diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/OperandImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/OperandImports.qll index 3c781579cee..d0e013d1fba 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/OperandImports.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/OperandImports.qll @@ -2,3 +2,4 @@ import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind import semmle.code.cpp.ir.implementation.IRType as IRType import semmle.code.cpp.ir.internal.Overlap as Overlap import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag +import semmle.code.cpp.ir.implementation.internal.TOperand as TOperand diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/OperandInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/OperandInternal.qll new file mode 100644 index 00000000000..194e21e0d93 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/raw/internal/OperandInternal.qll @@ -0,0 +1,2 @@ +private import semmle.code.cpp.ir.implementation.internal.TOperand +import RawOperands 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 a12e35d471b..3a699fa3c4e 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 @@ -10,73 +10,10 @@ private import Imports::MemoryAccessKind private import Imports::IRType private import Imports::Overlap private import Imports::OperandTag +private import Imports::TOperand +private import internal.OperandInternal -cached -private newtype TOperand = - TRegisterOperand(Instruction useInstr, RegisterOperandTag tag, Instruction defInstr) { - defInstr = Construction::getRegisterOperandDefinition(useInstr, tag) and - not Construction::isInCycle(useInstr) and - strictcount(Construction::getRegisterOperandDefinition(useInstr, tag)) = 1 - } or - TNonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) { - useInstr.getOpcode().hasOperand(tag) - } or - TPhiOperand( - PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap - ) { - defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap) - } - -/** - * Base class for all register operands. This is a placeholder for the IPA union type that we will - * eventually use for this purpose. - */ -private class RegisterOperandBase extends TRegisterOperand { - /** Gets a textual representation of this element. */ - abstract string toString(); -} - -/** - * Returns the register operand with the specified parameters. - */ -private RegisterOperandBase registerOperand( - Instruction useInstr, RegisterOperandTag tag, Instruction defInstr -) { - result = TRegisterOperand(useInstr, tag, defInstr) -} - -/** - * Base class for all non-Phi memory operands. This is a placeholder for the IPA union type that we - * will eventually use for this purpose. - */ -private class NonPhiMemoryOperandBase extends TNonPhiMemoryOperand { - /** Gets a textual representation of this element. */ - abstract string toString(); -} - -/** - * Returns the non-Phi memory operand with the specified parameters. - */ -private NonPhiMemoryOperandBase nonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) { - result = TNonPhiMemoryOperand(useInstr, tag) -} - -/** - * Base class for all Phi operands. This is a placeholder for the IPA union type that we will - * eventually use for this purpose. - */ -private class PhiOperandBase extends TPhiOperand { - abstract string toString(); -} - -/** - * Returns the Phi operand with the specified parameters. - */ -private PhiOperandBase phiOperand( - Instruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap -) { - result = TPhiOperand(useInstr, defInstr, predecessorBlock, overlap) -} +class TOperand = TRegisterOperand or TNonSSAMemoryOperand or TPhiOperand or TChiOperand; /** * An operand of an `Instruction`. The operand represents a use of the result of one instruction @@ -239,8 +176,9 @@ class Operand extends TOperand { */ class MemoryOperand extends Operand { MemoryOperand() { - this instanceof NonPhiMemoryOperandBase or - this instanceof PhiOperandBase + this instanceof TNonSSAMemoryOperand or + this instanceof TPhiOperand or + this instanceof TChiOperand } /** @@ -278,7 +216,8 @@ class NonPhiOperand extends Operand { NonPhiOperand() { this = registerOperand(useInstr, tag, _) or - this = nonPhiMemoryOperand(useInstr, tag) + this = nonSSAMemoryOperand(useInstr, tag) or + this = chiOperand(useInstr, tag) } final override Instruction getUse() { result = useInstr } @@ -298,7 +237,7 @@ class NonPhiOperand extends Operand { /** * An operand that consumes a register (non-memory) result. */ -class RegisterOperand extends NonPhiOperand, RegisterOperandBase { +class RegisterOperand extends NonPhiOperand, TRegisterOperand { override RegisterOperandTag tag; Instruction defInstr; @@ -317,10 +256,14 @@ class RegisterOperand extends NonPhiOperand, RegisterOperandBase { /** * A memory operand other than the operand of a `Phi` instruction. */ -class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOperandBase { +class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand { override MemoryOperandTag tag; - NonPhiMemoryOperand() { this = nonPhiMemoryOperand(useInstr, tag) } + NonPhiMemoryOperand() { + this = nonSSAMemoryOperand(useInstr, tag) + or + this = chiOperand(useInstr, tag) + } final override string toString() { result = tag.toString() } @@ -462,7 +405,7 @@ class SideEffectOperand extends TypedOperand { /** * An operand of a `PhiInstruction`. */ -class PhiInputOperand extends MemoryOperand, PhiOperandBase { +class PhiInputOperand extends MemoryOperand, TPhiOperand { PhiInstruction useInstr; Instruction defInstr; IRBlock predecessorBlock; diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/OperandImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/OperandImports.qll index 3c781579cee..d0e013d1fba 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/OperandImports.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/OperandImports.qll @@ -2,3 +2,4 @@ import semmle.code.cpp.ir.implementation.MemoryAccessKind as MemoryAccessKind import semmle.code.cpp.ir.implementation.IRType as IRType import semmle.code.cpp.ir.internal.Overlap as Overlap import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag +import semmle.code.cpp.ir.implementation.internal.TOperand as TOperand diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/OperandInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/OperandInternal.qll new file mode 100644 index 00000000000..b668f1f04a4 --- /dev/null +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/OperandInternal.qll @@ -0,0 +1,2 @@ +private import semmle.code.cpp.ir.implementation.internal.TOperand +import UnliasedSSAOperands diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 8e904ee6bc4..ad6f3fc8eb2 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -6,6 +6,7 @@ private import Imports::Overlap private import Imports::TInstruction private import Imports::RawIR as RawIR private import SSAInstructions +private import SSAOperands private import NewIR private class OldBlock = Reachability::ReachableBlock; @@ -42,6 +43,9 @@ private module Cached { class TStageInstruction = TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction; + class TStageOperand = + TRegisterOperand or TNonSSAMemoryOperand or TPhiOperand or TChiOperand; + cached predicate hasInstruction(TStageInstruction instr) { instr instanceof TRawInstruction and instr instanceof OldInstruction diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll index f347df86ba1..2e5b8cc6ed3 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll @@ -3,3 +3,4 @@ import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag import semmle.code.cpp.ir.internal.Overlap as Overlap import semmle.code.cpp.ir.implementation.internal.TInstruction as TInstruction import semmle.code.cpp.ir.implementation.raw.IR as RawIR +import semmle.code.cpp.ir.implementation.internal.TOperand as TOperand \ No newline at end of file diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll index 73b08d1286b..480f473bb3f 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll @@ -6,3 +6,4 @@ import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as RawStage import semmle.code.cpp.ir.implementation.internal.TInstruction::UnaliasedSSAInstructions as SSAInstructions import semmle.code.cpp.ir.internal.IRCppLanguage as Language import SimpleSSA as Alias +import semmle.code.cpp.ir.implementation.internal.TOperand::UnliasedSSAOperands as SSAOperands From 89a59d5f1a200bf9ade74c5b2f5e7736197c4176 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Fri, 11 Dec 2020 15:52:07 -0800 Subject: [PATCH 002/142] C++: comments about shared Operand IPA type --- .../ir/implementation/aliased_ssa/Operand.qll | 8 +++-- .../aliased_ssa/internal/SSAConstruction.qll | 3 -- .../ir/implementation/internal/TOperand.qll | 36 +++++++++++++++++-- .../cpp/ir/implementation/raw/Operand.qll | 8 +++-- .../implementation/unaliased_ssa/Operand.qll | 8 +++-- .../internal/SSAConstruction.qll | 3 -- 6 files changed, 51 insertions(+), 15 deletions(-) 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 3a699fa3c4e..d87e513ed13 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 @@ -13,13 +13,17 @@ private import Imports::OperandTag private import Imports::TOperand private import internal.OperandInternal -class TOperand = TRegisterOperand or TNonSSAMemoryOperand or TPhiOperand or TChiOperand; +/** + * An operand of an `Instruction` in this stage of the IR. Implemented as a union of the branches + * of `TOperand` that are used in this stage. + */ +private class TStageOperand = TRegisterOperand or TNonSSAMemoryOperand or TPhiOperand or TChiOperand; /** * An operand of an `Instruction`. The operand represents a use of the result of one instruction * (the defining instruction) in another instruction (the use instruction) */ -class Operand extends TOperand { +class Operand extends TStageOperand { /** Gets a textual representation of this element. */ string toString() { result = "Operand" } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll index ad6f3fc8eb2..a1c970121d2 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstruction.qll @@ -43,9 +43,6 @@ private module Cached { class TStageInstruction = TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction; - class TStageOperand = - TRegisterOperand or TNonSSAMemoryOperand or TPhiOperand or TChiOperand; - cached predicate hasInstruction(TStageInstruction instr) { instr instanceof TRawInstruction and instr instanceof OldInstruction diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TOperand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TOperand.qll index 696d372bc15..b09ce41ffd1 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TOperand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TOperand.qll @@ -8,7 +8,18 @@ private import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as Unaliased private import semmle.code.cpp.ir.implementation.aliased_ssa.IR as Aliased private import semmle.code.cpp.ir.internal.Overlap +/** + * Provides the newtype used to represent operands across all phases of the IR. + */ private module Internal { + + /** + * An IR operand. `TOperand` is shared across all phases of the IR. There are branches of this + * type for operands created directly from the AST (`TRegisterOperand` and `TNonSSAMemoryOperand`), + * for operands computed by each stage of SSA construction (`T*PhiOperand` and + * `TAliasedChiOperand`), and a placehold branch for operands that do not exist in a given + * stage of IR construction (`TNoOperand`). + */ cached newtype TOperand = // RAW @@ -51,6 +62,10 @@ private module Internal { } } +/** + * Reexports some branches from `TOperand` so they can be used in stage modules without importing + * `TOperand` itself. + */ private module Shared { class TRegisterOperand = Internal::TRegisterOperand; @@ -73,6 +88,12 @@ private module Shared { } } +/** + * Provides wrappers for the constructors of each branch of `TOperand` that is used by the + * raw IR stage. + * These wrappers are not parameterized because it is not possible to invoke an IPA constructor via + * a class alias. + */ module RawOperands { import Shared @@ -96,9 +117,12 @@ module RawOperands { TChiOperand chiOperand(Raw::Instruction useInstr, ChiOperandTag tag) { none() } } -// TODO: can we get everything into either here or Operand.qll? -// TODO: can we put `TStageOperand` in Construction? Might break something about the module caching setup, `Operand` is currently after everything in SSAConstruction -// TODO: share empty ChiOperand? +/** + * Provides wrappers for the constructors of each branch of `TOperand` that is used by the + * unaliased SSA stage. + * These wrappers are not parameterized because it is not possible to invoke an IPA constructor via + * a class alias. + */ module UnliasedSSAOperands { import Shared @@ -122,6 +146,12 @@ module UnliasedSSAOperands { TChiOperand chiOperand(Unaliased::Instruction useInstr, ChiOperandTag tag) { none() } } +/** + * Provides wrappers for the constructors of each branch of `TOperand` that is used by the + * asliased SSA stage. + * These wrappers are not parameterized because it is not possible to invoke an IPA constructor via + * a class alias. + */ module AliasedSSAOperands { import Shared 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 3a699fa3c4e..d87e513ed13 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 @@ -13,13 +13,17 @@ private import Imports::OperandTag private import Imports::TOperand private import internal.OperandInternal -class TOperand = TRegisterOperand or TNonSSAMemoryOperand or TPhiOperand or TChiOperand; +/** + * An operand of an `Instruction` in this stage of the IR. Implemented as a union of the branches + * of `TOperand` that are used in this stage. + */ +private class TStageOperand = TRegisterOperand or TNonSSAMemoryOperand or TPhiOperand or TChiOperand; /** * An operand of an `Instruction`. The operand represents a use of the result of one instruction * (the defining instruction) in another instruction (the use instruction) */ -class Operand extends TOperand { +class Operand extends TStageOperand { /** Gets a textual representation of this element. */ string toString() { result = "Operand" } 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 3a699fa3c4e..d87e513ed13 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 @@ -13,13 +13,17 @@ private import Imports::OperandTag private import Imports::TOperand private import internal.OperandInternal -class TOperand = TRegisterOperand or TNonSSAMemoryOperand or TPhiOperand or TChiOperand; +/** + * An operand of an `Instruction` in this stage of the IR. Implemented as a union of the branches + * of `TOperand` that are used in this stage. + */ +private class TStageOperand = TRegisterOperand or TNonSSAMemoryOperand or TPhiOperand or TChiOperand; /** * An operand of an `Instruction`. The operand represents a use of the result of one instruction * (the defining instruction) in another instruction (the use instruction) */ -class Operand extends TOperand { +class Operand extends TStageOperand { /** Gets a textual representation of this element. */ string toString() { result = "Operand" } diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index ad6f3fc8eb2..a1c970121d2 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -43,9 +43,6 @@ private module Cached { class TStageInstruction = TRawInstruction or TPhiInstruction or TChiInstruction or TUnreachedInstruction; - class TStageOperand = - TRegisterOperand or TNonSSAMemoryOperand or TPhiOperand or TChiOperand; - cached predicate hasInstruction(TStageInstruction instr) { instr instanceof TRawInstruction and instr instanceof OldInstruction From 96e913031d37c63f364c2ab4922bdd7fe7dd4d02 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Fri, 11 Dec 2020 16:11:00 -0800 Subject: [PATCH 003/142] C#: share IR Operand IPA type between stages --- .../ir/implementation/internal/TOperand.qll | 127 ++++++++++++++++++ .../ir/implementation/raw/Operand.qll | 91 +++---------- .../raw/internal/OperandImports.qll | 1 + .../raw/internal/OperandInternal.qll | 2 + .../implementation/unaliased_ssa/Operand.qll | 91 +++---------- .../unaliased_ssa/internal/OperandImports.qll | 1 + .../internal/OperandInternal.qll | 2 + .../internal/SSAConstruction.qll | 1 + .../internal/SSAConstructionInternal.qll | 1 + 9 files changed, 173 insertions(+), 144 deletions(-) create mode 100644 csharp/ql/src/experimental/ir/implementation/internal/TOperand.qll create mode 100644 csharp/ql/src/experimental/ir/implementation/raw/internal/OperandInternal.qll create mode 100644 csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/OperandInternal.qll diff --git a/csharp/ql/src/experimental/ir/implementation/internal/TOperand.qll b/csharp/ql/src/experimental/ir/implementation/internal/TOperand.qll new file mode 100644 index 00000000000..361e4105ae7 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/internal/TOperand.qll @@ -0,0 +1,127 @@ +private import TInstruction +private import OperandTag +private import experimental.ir.implementation.raw.internal.IRConstruction as RawConstruction +private import experimental.ir.implementation.unaliased_ssa.internal.SSAConstruction as UnaliasedConstruction +private import experimental.ir.implementation.raw.IR as Raw +private import experimental.ir.implementation.unaliased_ssa.IR as Unaliased +private import experimental.ir.internal.Overlap + +/** + * Provides the newtype used to represent operands across all phases of the IR. + */ +private module Internal { + + /** + * An IR operand. `TOperand` is shared across all phases of the IR. There are branches of this + * type for operands created directly from the AST (`TRegisterOperand` and `TNonSSAMemoryOperand`), + * for operands computed by each stage of SSA construction (`T*PhiOperand` and + * `TAliasedChiOperand`), and a placehold branch for operands that do not exist in a given + * stage of IR construction (`TNoOperand`). + */ + cached + newtype TOperand = + // RAW + TRegisterOperand(TRawInstruction useInstr, RegisterOperandTag tag, TRawInstruction defInstr) { + defInstr = RawConstruction::getRegisterOperandDefinition(useInstr, tag) and + not RawConstruction::isInCycle(useInstr) and + strictcount(RawConstruction::getRegisterOperandDefinition(useInstr, tag)) = 1 + } or + // Placeholder for Phi and Chi operands in stages that don't have the corresponding instructions + TNoOperand() { none() } or + // Can be "removed" later when there's unreachable code + // These operands can be reused across all three stages. They just get different defs. + TNonSSAMemoryOperand(Raw::Instruction useInstr, MemoryOperandTag tag) { + // Has no definition in raw but will get definitions later + useInstr.getOpcode().hasOperand(tag) + } or + TUnaliasedPhiOperand( + Unaliased::PhiInstruction useInstr, Unaliased::Instruction defInstr, + Unaliased::IRBlock predecessorBlock, Overlap overlap + ) { + defInstr = UnaliasedConstruction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap) + } +} + +/** + * Reexports some branches from `TOperand` so they can be used in stage modules without importing + * `TOperand` itself. + */ +private module Shared { + class TRegisterOperand = Internal::TRegisterOperand; + + /** + * Returns the register operand with the specified parameters. + */ + TRegisterOperand registerOperand( + TRawInstruction useInstr, RegisterOperandTag tag, TRawInstruction defInstr + ) { + result = Internal::TRegisterOperand(useInstr, tag, defInstr) + } + + class TNonSSAMemoryOperand = Internal::TNonSSAMemoryOperand; + + /** + * Returns the non-Phi memory operand with the specified parameters. + */ + TNonSSAMemoryOperand nonSSAMemoryOperand(TRawInstruction useInstr, MemoryOperandTag tag) { + result = Internal::TNonSSAMemoryOperand(useInstr, tag) + } +} + +/** + * Provides wrappers for the constructors of each branch of `TOperand` that is used by the + * raw IR stage. + * These wrappers are not parameterized because it is not possible to invoke an IPA constructor via + * a class alias. + */ +module RawOperands { + import Shared + + class TPhiOperand = Internal::TNoOperand; + + class TChiOperand = Internal::TNoOperand; + + /** + * Returns the Phi operand with the specified parameters. + */ + TPhiOperand phiOperand( + Raw::PhiInstruction useInstr, Raw::Instruction defInstr, Raw::IRBlock predecessorBlock, + Overlap overlap + ) { + none() + } + + /** + * Returns the Chi operand with the specified parameters. + */ + TChiOperand chiOperand(Raw::Instruction useInstr, ChiOperandTag tag) { none() } +} + +/** + * Provides wrappers for the constructors of each branch of `TOperand` that is used by the + * unaliased SSA stage. + * These wrappers are not parameterized because it is not possible to invoke an IPA constructor via + * a class alias. + */ +module UnaliasedSSAOperands { + import Shared + + class TPhiOperand = Internal::TUnaliasedPhiOperand; + + class TChiOperand = Internal::TNoOperand; + + /** + * Returns the Phi operand with the specified parameters. + */ + TPhiOperand phiOperand( + Unaliased::PhiInstruction useInstr, Unaliased::Instruction defInstr, + Unaliased::IRBlock predecessorBlock, Overlap overlap + ) { + result = Internal::TUnaliasedPhiOperand(useInstr, defInstr, predecessorBlock, overlap) + } + + /** + * Returns the Chi operand with the specified parameters. + */ + TChiOperand chiOperand(Unaliased::Instruction useInstr, ChiOperandTag tag) { none() } +} diff --git a/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll b/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll index a12e35d471b..d87e513ed13 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll @@ -10,79 +10,20 @@ private import Imports::MemoryAccessKind private import Imports::IRType private import Imports::Overlap private import Imports::OperandTag - -cached -private newtype TOperand = - TRegisterOperand(Instruction useInstr, RegisterOperandTag tag, Instruction defInstr) { - defInstr = Construction::getRegisterOperandDefinition(useInstr, tag) and - not Construction::isInCycle(useInstr) and - strictcount(Construction::getRegisterOperandDefinition(useInstr, tag)) = 1 - } or - TNonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) { - useInstr.getOpcode().hasOperand(tag) - } or - TPhiOperand( - PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap - ) { - defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap) - } +private import Imports::TOperand +private import internal.OperandInternal /** - * Base class for all register operands. This is a placeholder for the IPA union type that we will - * eventually use for this purpose. + * An operand of an `Instruction` in this stage of the IR. Implemented as a union of the branches + * of `TOperand` that are used in this stage. */ -private class RegisterOperandBase extends TRegisterOperand { - /** Gets a textual representation of this element. */ - abstract string toString(); -} - -/** - * Returns the register operand with the specified parameters. - */ -private RegisterOperandBase registerOperand( - Instruction useInstr, RegisterOperandTag tag, Instruction defInstr -) { - result = TRegisterOperand(useInstr, tag, defInstr) -} - -/** - * Base class for all non-Phi memory operands. This is a placeholder for the IPA union type that we - * will eventually use for this purpose. - */ -private class NonPhiMemoryOperandBase extends TNonPhiMemoryOperand { - /** Gets a textual representation of this element. */ - abstract string toString(); -} - -/** - * Returns the non-Phi memory operand with the specified parameters. - */ -private NonPhiMemoryOperandBase nonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) { - result = TNonPhiMemoryOperand(useInstr, tag) -} - -/** - * Base class for all Phi operands. This is a placeholder for the IPA union type that we will - * eventually use for this purpose. - */ -private class PhiOperandBase extends TPhiOperand { - abstract string toString(); -} - -/** - * Returns the Phi operand with the specified parameters. - */ -private PhiOperandBase phiOperand( - Instruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap -) { - result = TPhiOperand(useInstr, defInstr, predecessorBlock, overlap) -} +private class TStageOperand = TRegisterOperand or TNonSSAMemoryOperand or TPhiOperand or TChiOperand; /** * An operand of an `Instruction`. The operand represents a use of the result of one instruction * (the defining instruction) in another instruction (the use instruction) */ -class Operand extends TOperand { +class Operand extends TStageOperand { /** Gets a textual representation of this element. */ string toString() { result = "Operand" } @@ -239,8 +180,9 @@ class Operand extends TOperand { */ class MemoryOperand extends Operand { MemoryOperand() { - this instanceof NonPhiMemoryOperandBase or - this instanceof PhiOperandBase + this instanceof TNonSSAMemoryOperand or + this instanceof TPhiOperand or + this instanceof TChiOperand } /** @@ -278,7 +220,8 @@ class NonPhiOperand extends Operand { NonPhiOperand() { this = registerOperand(useInstr, tag, _) or - this = nonPhiMemoryOperand(useInstr, tag) + this = nonSSAMemoryOperand(useInstr, tag) or + this = chiOperand(useInstr, tag) } final override Instruction getUse() { result = useInstr } @@ -298,7 +241,7 @@ class NonPhiOperand extends Operand { /** * An operand that consumes a register (non-memory) result. */ -class RegisterOperand extends NonPhiOperand, RegisterOperandBase { +class RegisterOperand extends NonPhiOperand, TRegisterOperand { override RegisterOperandTag tag; Instruction defInstr; @@ -317,10 +260,14 @@ class RegisterOperand extends NonPhiOperand, RegisterOperandBase { /** * A memory operand other than the operand of a `Phi` instruction. */ -class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOperandBase { +class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand { override MemoryOperandTag tag; - NonPhiMemoryOperand() { this = nonPhiMemoryOperand(useInstr, tag) } + NonPhiMemoryOperand() { + this = nonSSAMemoryOperand(useInstr, tag) + or + this = chiOperand(useInstr, tag) + } final override string toString() { result = tag.toString() } @@ -462,7 +409,7 @@ class SideEffectOperand extends TypedOperand { /** * An operand of a `PhiInstruction`. */ -class PhiInputOperand extends MemoryOperand, PhiOperandBase { +class PhiInputOperand extends MemoryOperand, TPhiOperand { PhiInstruction useInstr; Instruction defInstr; IRBlock predecessorBlock; diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/OperandImports.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/OperandImports.qll index 40af4631927..65676caf724 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/internal/OperandImports.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/OperandImports.qll @@ -2,3 +2,4 @@ import experimental.ir.implementation.MemoryAccessKind as MemoryAccessKind import experimental.ir.implementation.IRType as IRType import experimental.ir.internal.Overlap as Overlap import experimental.ir.implementation.internal.OperandTag as OperandTag +import experimental.ir.implementation.internal.TOperand as TOperand diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/OperandInternal.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/OperandInternal.qll new file mode 100644 index 00000000000..771aeb9033c --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/OperandInternal.qll @@ -0,0 +1,2 @@ +private import experimental.ir.implementation.internal.TOperand +import RawOperands 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 a12e35d471b..d87e513ed13 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Operand.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Operand.qll @@ -10,79 +10,20 @@ private import Imports::MemoryAccessKind private import Imports::IRType private import Imports::Overlap private import Imports::OperandTag - -cached -private newtype TOperand = - TRegisterOperand(Instruction useInstr, RegisterOperandTag tag, Instruction defInstr) { - defInstr = Construction::getRegisterOperandDefinition(useInstr, tag) and - not Construction::isInCycle(useInstr) and - strictcount(Construction::getRegisterOperandDefinition(useInstr, tag)) = 1 - } or - TNonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) { - useInstr.getOpcode().hasOperand(tag) - } or - TPhiOperand( - PhiInstruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap - ) { - defInstr = Construction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap) - } +private import Imports::TOperand +private import internal.OperandInternal /** - * Base class for all register operands. This is a placeholder for the IPA union type that we will - * eventually use for this purpose. + * An operand of an `Instruction` in this stage of the IR. Implemented as a union of the branches + * of `TOperand` that are used in this stage. */ -private class RegisterOperandBase extends TRegisterOperand { - /** Gets a textual representation of this element. */ - abstract string toString(); -} - -/** - * Returns the register operand with the specified parameters. - */ -private RegisterOperandBase registerOperand( - Instruction useInstr, RegisterOperandTag tag, Instruction defInstr -) { - result = TRegisterOperand(useInstr, tag, defInstr) -} - -/** - * Base class for all non-Phi memory operands. This is a placeholder for the IPA union type that we - * will eventually use for this purpose. - */ -private class NonPhiMemoryOperandBase extends TNonPhiMemoryOperand { - /** Gets a textual representation of this element. */ - abstract string toString(); -} - -/** - * Returns the non-Phi memory operand with the specified parameters. - */ -private NonPhiMemoryOperandBase nonPhiMemoryOperand(Instruction useInstr, MemoryOperandTag tag) { - result = TNonPhiMemoryOperand(useInstr, tag) -} - -/** - * Base class for all Phi operands. This is a placeholder for the IPA union type that we will - * eventually use for this purpose. - */ -private class PhiOperandBase extends TPhiOperand { - abstract string toString(); -} - -/** - * Returns the Phi operand with the specified parameters. - */ -private PhiOperandBase phiOperand( - Instruction useInstr, Instruction defInstr, IRBlock predecessorBlock, Overlap overlap -) { - result = TPhiOperand(useInstr, defInstr, predecessorBlock, overlap) -} +private class TStageOperand = TRegisterOperand or TNonSSAMemoryOperand or TPhiOperand or TChiOperand; /** * An operand of an `Instruction`. The operand represents a use of the result of one instruction * (the defining instruction) in another instruction (the use instruction) */ -class Operand extends TOperand { +class Operand extends TStageOperand { /** Gets a textual representation of this element. */ string toString() { result = "Operand" } @@ -239,8 +180,9 @@ class Operand extends TOperand { */ class MemoryOperand extends Operand { MemoryOperand() { - this instanceof NonPhiMemoryOperandBase or - this instanceof PhiOperandBase + this instanceof TNonSSAMemoryOperand or + this instanceof TPhiOperand or + this instanceof TChiOperand } /** @@ -278,7 +220,8 @@ class NonPhiOperand extends Operand { NonPhiOperand() { this = registerOperand(useInstr, tag, _) or - this = nonPhiMemoryOperand(useInstr, tag) + this = nonSSAMemoryOperand(useInstr, tag) or + this = chiOperand(useInstr, tag) } final override Instruction getUse() { result = useInstr } @@ -298,7 +241,7 @@ class NonPhiOperand extends Operand { /** * An operand that consumes a register (non-memory) result. */ -class RegisterOperand extends NonPhiOperand, RegisterOperandBase { +class RegisterOperand extends NonPhiOperand, TRegisterOperand { override RegisterOperandTag tag; Instruction defInstr; @@ -317,10 +260,14 @@ class RegisterOperand extends NonPhiOperand, RegisterOperandBase { /** * A memory operand other than the operand of a `Phi` instruction. */ -class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, NonPhiMemoryOperandBase { +class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand { override MemoryOperandTag tag; - NonPhiMemoryOperand() { this = nonPhiMemoryOperand(useInstr, tag) } + NonPhiMemoryOperand() { + this = nonSSAMemoryOperand(useInstr, tag) + or + this = chiOperand(useInstr, tag) + } final override string toString() { result = tag.toString() } @@ -462,7 +409,7 @@ class SideEffectOperand extends TypedOperand { /** * An operand of a `PhiInstruction`. */ -class PhiInputOperand extends MemoryOperand, PhiOperandBase { +class PhiInputOperand extends MemoryOperand, TPhiOperand { PhiInstruction useInstr; Instruction defInstr; IRBlock predecessorBlock; diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/OperandImports.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/OperandImports.qll index 40af4631927..65676caf724 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/OperandImports.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/OperandImports.qll @@ -2,3 +2,4 @@ import experimental.ir.implementation.MemoryAccessKind as MemoryAccessKind import experimental.ir.implementation.IRType as IRType import experimental.ir.internal.Overlap as Overlap import experimental.ir.implementation.internal.OperandTag as OperandTag +import experimental.ir.implementation.internal.TOperand as TOperand diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/OperandInternal.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/OperandInternal.qll new file mode 100644 index 00000000000..88a4e6f8551 --- /dev/null +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/OperandInternal.qll @@ -0,0 +1,2 @@ +private import experimental.ir.implementation.internal.TOperand +import UnaliasedSSAOperands diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll index 8e904ee6bc4..a1c970121d2 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstruction.qll @@ -6,6 +6,7 @@ private import Imports::Overlap private import Imports::TInstruction private import Imports::RawIR as RawIR private import SSAInstructions +private import SSAOperands private import NewIR private class OldBlock = Reachability::ReachableBlock; diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll index 15eaf8045a7..8f726b81345 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll @@ -6,3 +6,4 @@ import experimental.ir.implementation.raw.internal.IRConstruction as RawStage import experimental.ir.implementation.internal.TInstruction::UnaliasedSSAInstructions as SSAInstructions import experimental.ir.internal.IRCSharpLanguage as Language import SimpleSSA as Alias +import experimental.ir.implementation.internal.TOperand::UnaliasedSSAOperands as SSAOperands From a404ca66d17ccb1545e0696004a5176385fba680 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Fri, 11 Dec 2020 16:16:19 -0800 Subject: [PATCH 004/142] C++: fix typo --- .../aliased_ssa/internal/SSAConstructionInternal.qll | 2 +- .../src/semmle/code/cpp/ir/implementation/internal/TOperand.qll | 2 +- .../implementation/unaliased_ssa/internal/OperandInternal.qll | 2 +- .../unaliased_ssa/internal/SSAConstructionInternal.qll | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionInternal.qll index e42895e56b6..a1ce2629cc2 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionInternal.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionInternal.qll @@ -5,4 +5,4 @@ import semmle.code.cpp.ir.implementation.aliased_ssa.IR as NewIR import semmle.code.cpp.ir.implementation.internal.TInstruction::AliasedSSAInstructions as SSAInstructions import semmle.code.cpp.ir.internal.IRCppLanguage as Language import AliasedSSA as Alias -import semmle.code.cpp.ir.implementation.internal.TOperand::UnliasedSSAOperands as SSAOperands +import semmle.code.cpp.ir.implementation.internal.TOperand::AliasedSSAOperands as SSAOperands diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TOperand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TOperand.qll index b09ce41ffd1..295ffdfa1e0 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TOperand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TOperand.qll @@ -123,7 +123,7 @@ module RawOperands { * These wrappers are not parameterized because it is not possible to invoke an IPA constructor via * a class alias. */ -module UnliasedSSAOperands { +module UnaliasedSSAOperands { import Shared class TPhiOperand = Internal::TUnaliasedPhiOperand; diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/OperandInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/OperandInternal.qll index b668f1f04a4..80e06a381a1 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/OperandInternal.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/OperandInternal.qll @@ -1,2 +1,2 @@ private import semmle.code.cpp.ir.implementation.internal.TOperand -import UnliasedSSAOperands +import UnaliasedSSAOperands diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll index 480f473bb3f..70d44e03267 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionInternal.qll @@ -6,4 +6,4 @@ import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as RawStage import semmle.code.cpp.ir.implementation.internal.TInstruction::UnaliasedSSAInstructions as SSAInstructions import semmle.code.cpp.ir.internal.IRCppLanguage as Language import SimpleSSA as Alias -import semmle.code.cpp.ir.implementation.internal.TOperand::UnliasedSSAOperands as SSAOperands +import semmle.code.cpp.ir.implementation.internal.TOperand::UnaliasedSSAOperands as SSAOperands From fd14eb4c8c652d6d38f6268636e1136bcdf37b1f Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Tue, 15 Dec 2020 11:45:40 -0800 Subject: [PATCH 005/142] C++: remove unreachable IR operands in late stages --- .../cpp/ir/implementation/aliased_ssa/Operand.qll | 14 +++++++++++++- .../code/cpp/ir/implementation/raw/Operand.qll | 14 +++++++++++++- .../ir/implementation/unaliased_ssa/Operand.qll | 14 +++++++++++++- .../experimental/ir/implementation/raw/Operand.qll | 14 +++++++++++++- .../ir/implementation/unaliased_ssa/Operand.qll | 14 +++++++++++++- 5 files changed, 65 insertions(+), 5 deletions(-) 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 d87e513ed13..38fc6264133 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 @@ -17,13 +17,25 @@ private import internal.OperandInternal * An operand of an `Instruction` in this stage of the IR. Implemented as a union of the branches * of `TOperand` that are used in this stage. */ -private class TStageOperand = TRegisterOperand or TNonSSAMemoryOperand or TPhiOperand or TChiOperand; +private class TStageOperand = + TRegisterOperand or TNonSSAMemoryOperand or TPhiOperand or TChiOperand; /** * An operand of an `Instruction`. The operand represents a use of the result of one instruction * (the defining instruction) in another instruction (the use instruction) */ class Operand extends TStageOperand { + Operand() { + // Ensure that the operand does not refer to instructions from earlier stages that are unreachable here + exists(Instruction use, Instruction def | this = registerOperand(use, _, def)) + or + exists(Instruction use | this = nonSSAMemoryOperand(use, _)) + or + exists(Instruction use, Instruction def, IRBlock block | this = phiOperand(use, def, block, _)) + or + exists(Instruction use | this = chiOperand(use, _)) + } + /** Gets a textual representation of this element. */ string toString() { result = "Operand" } 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 d87e513ed13..38fc6264133 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 @@ -17,13 +17,25 @@ private import internal.OperandInternal * An operand of an `Instruction` in this stage of the IR. Implemented as a union of the branches * of `TOperand` that are used in this stage. */ -private class TStageOperand = TRegisterOperand or TNonSSAMemoryOperand or TPhiOperand or TChiOperand; +private class TStageOperand = + TRegisterOperand or TNonSSAMemoryOperand or TPhiOperand or TChiOperand; /** * An operand of an `Instruction`. The operand represents a use of the result of one instruction * (the defining instruction) in another instruction (the use instruction) */ class Operand extends TStageOperand { + Operand() { + // Ensure that the operand does not refer to instructions from earlier stages that are unreachable here + exists(Instruction use, Instruction def | this = registerOperand(use, _, def)) + or + exists(Instruction use | this = nonSSAMemoryOperand(use, _)) + or + exists(Instruction use, Instruction def, IRBlock block | this = phiOperand(use, def, block, _)) + or + exists(Instruction use | this = chiOperand(use, _)) + } + /** Gets a textual representation of this element. */ string toString() { result = "Operand" } 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 d87e513ed13..38fc6264133 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 @@ -17,13 +17,25 @@ private import internal.OperandInternal * An operand of an `Instruction` in this stage of the IR. Implemented as a union of the branches * of `TOperand` that are used in this stage. */ -private class TStageOperand = TRegisterOperand or TNonSSAMemoryOperand or TPhiOperand or TChiOperand; +private class TStageOperand = + TRegisterOperand or TNonSSAMemoryOperand or TPhiOperand or TChiOperand; /** * An operand of an `Instruction`. The operand represents a use of the result of one instruction * (the defining instruction) in another instruction (the use instruction) */ class Operand extends TStageOperand { + Operand() { + // Ensure that the operand does not refer to instructions from earlier stages that are unreachable here + exists(Instruction use, Instruction def | this = registerOperand(use, _, def)) + or + exists(Instruction use | this = nonSSAMemoryOperand(use, _)) + or + exists(Instruction use, Instruction def, IRBlock block | this = phiOperand(use, def, block, _)) + or + exists(Instruction use | this = chiOperand(use, _)) + } + /** Gets a textual representation of this element. */ string toString() { result = "Operand" } diff --git a/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll b/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll index d87e513ed13..38fc6264133 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll @@ -17,13 +17,25 @@ private import internal.OperandInternal * An operand of an `Instruction` in this stage of the IR. Implemented as a union of the branches * of `TOperand` that are used in this stage. */ -private class TStageOperand = TRegisterOperand or TNonSSAMemoryOperand or TPhiOperand or TChiOperand; +private class TStageOperand = + TRegisterOperand or TNonSSAMemoryOperand or TPhiOperand or TChiOperand; /** * An operand of an `Instruction`. The operand represents a use of the result of one instruction * (the defining instruction) in another instruction (the use instruction) */ class Operand extends TStageOperand { + Operand() { + // Ensure that the operand does not refer to instructions from earlier stages that are unreachable here + exists(Instruction use, Instruction def | this = registerOperand(use, _, def)) + or + exists(Instruction use | this = nonSSAMemoryOperand(use, _)) + or + exists(Instruction use, Instruction def, IRBlock block | this = phiOperand(use, def, block, _)) + or + exists(Instruction use | this = chiOperand(use, _)) + } + /** Gets a textual representation of this element. */ string toString() { result = "Operand" } 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 d87e513ed13..38fc6264133 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Operand.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Operand.qll @@ -17,13 +17,25 @@ private import internal.OperandInternal * An operand of an `Instruction` in this stage of the IR. Implemented as a union of the branches * of `TOperand` that are used in this stage. */ -private class TStageOperand = TRegisterOperand or TNonSSAMemoryOperand or TPhiOperand or TChiOperand; +private class TStageOperand = + TRegisterOperand or TNonSSAMemoryOperand or TPhiOperand or TChiOperand; /** * An operand of an `Instruction`. The operand represents a use of the result of one instruction * (the defining instruction) in another instruction (the use instruction) */ class Operand extends TStageOperand { + Operand() { + // Ensure that the operand does not refer to instructions from earlier stages that are unreachable here + exists(Instruction use, Instruction def | this = registerOperand(use, _, def)) + or + exists(Instruction use | this = nonSSAMemoryOperand(use, _)) + or + exists(Instruction use, Instruction def, IRBlock block | this = phiOperand(use, def, block, _)) + or + exists(Instruction use | this = chiOperand(use, _)) + } + /** Gets a textual representation of this element. */ string toString() { result = "Operand" } From 5d2a553059cf8b065fe212fd2a0a3205e1779ff3 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Tue, 15 Dec 2020 17:16:31 -0800 Subject: [PATCH 006/142] C++/C#: autoformat --- .../aliased_ssa/internal/SSAConstructionImports.qll | 2 +- .../src/semmle/code/cpp/ir/implementation/internal/TOperand.qll | 1 - .../unaliased_ssa/internal/SSAConstructionImports.qll | 2 +- .../ql/src/experimental/ir/implementation/internal/TOperand.qll | 1 - 4 files changed, 2 insertions(+), 4 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionImports.qll index 2e5b8cc6ed3..219180d9f4d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionImports.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/aliased_ssa/internal/SSAConstructionImports.qll @@ -3,4 +3,4 @@ import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag import semmle.code.cpp.ir.internal.Overlap as Overlap import semmle.code.cpp.ir.implementation.internal.TInstruction as TInstruction import semmle.code.cpp.ir.implementation.raw.IR as RawIR -import semmle.code.cpp.ir.implementation.internal.TOperand as TOperand \ No newline at end of file +import semmle.code.cpp.ir.implementation.internal.TOperand as TOperand diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TOperand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TOperand.qll index 295ffdfa1e0..243429603c7 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TOperand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TOperand.qll @@ -12,7 +12,6 @@ private import semmle.code.cpp.ir.internal.Overlap * Provides the newtype used to represent operands across all phases of the IR. */ private module Internal { - /** * An IR operand. `TOperand` is shared across all phases of the IR. There are branches of this * type for operands created directly from the AST (`TRegisterOperand` and `TNonSSAMemoryOperand`), diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll index 2e5b8cc6ed3..219180d9f4d 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/unaliased_ssa/internal/SSAConstructionImports.qll @@ -3,4 +3,4 @@ import semmle.code.cpp.ir.implementation.internal.OperandTag as OperandTag import semmle.code.cpp.ir.internal.Overlap as Overlap import semmle.code.cpp.ir.implementation.internal.TInstruction as TInstruction import semmle.code.cpp.ir.implementation.raw.IR as RawIR -import semmle.code.cpp.ir.implementation.internal.TOperand as TOperand \ No newline at end of file +import semmle.code.cpp.ir.implementation.internal.TOperand as TOperand diff --git a/csharp/ql/src/experimental/ir/implementation/internal/TOperand.qll b/csharp/ql/src/experimental/ir/implementation/internal/TOperand.qll index 361e4105ae7..143201eea14 100644 --- a/csharp/ql/src/experimental/ir/implementation/internal/TOperand.qll +++ b/csharp/ql/src/experimental/ir/implementation/internal/TOperand.qll @@ -10,7 +10,6 @@ private import experimental.ir.internal.Overlap * Provides the newtype used to represent operands across all phases of the IR. */ private module Internal { - /** * An IR operand. `TOperand` is shared across all phases of the IR. There are branches of this * type for operands created directly from the AST (`TRegisterOperand` and `TNonSSAMemoryOperand`), From 44bc6d7fdbd206c09909f3fdaf6140c84d514b42 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Mon, 25 Jan 2021 17:02:26 -0800 Subject: [PATCH 007/142] C++/C#: add NonPhiMemoryOperand union type This fixes a performance issue where the whole MemoryOperand table was scanned in some predicates that used only NonPhiMemoryOperand --- .../semmle/code/cpp/ir/implementation/aliased_ssa/Operand.qll | 2 +- .../semmle/code/cpp/ir/implementation/internal/TOperand.qll | 4 ++++ cpp/ql/src/semmle/code/cpp/ir/implementation/raw/Operand.qll | 2 +- .../code/cpp/ir/implementation/unaliased_ssa/Operand.qll | 2 +- .../src/experimental/ir/implementation/internal/TOperand.qll | 3 +++ csharp/ql/src/experimental/ir/implementation/raw/Operand.qll | 2 +- .../experimental/ir/implementation/unaliased_ssa/Operand.qll | 2 +- 7 files changed, 12 insertions(+), 5 deletions(-) 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 38fc6264133..a35c4a5c286 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 @@ -272,7 +272,7 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand { /** * A memory operand other than the operand of a `Phi` instruction. */ -class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand { +class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand { override MemoryOperandTag tag; NonPhiMemoryOperand() { diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TOperand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TOperand.qll index 243429603c7..4d6141cef06 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TOperand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TOperand.qll @@ -100,6 +100,8 @@ module RawOperands { class TChiOperand = Internal::TNoOperand; + class TNonPhiMemoryOperand = TNonSSAMemoryOperand or TChiOperand; + /** * Returns the Phi operand with the specified parameters. */ @@ -129,6 +131,7 @@ module UnaliasedSSAOperands { class TChiOperand = Internal::TNoOperand; + class TNonPhiMemoryOperand = TNonSSAMemoryOperand or TChiOperand; /** * Returns the Phi operand with the specified parameters. */ @@ -158,6 +161,7 @@ module AliasedSSAOperands { class TChiOperand = Internal::TAliasedChiOperand; + class TNonPhiMemoryOperand = TNonSSAMemoryOperand or TChiOperand; /** * Returns the Phi operand with the specified parameters. */ 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 38fc6264133..a35c4a5c286 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 @@ -272,7 +272,7 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand { /** * A memory operand other than the operand of a `Phi` instruction. */ -class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand { +class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand { override MemoryOperandTag tag; NonPhiMemoryOperand() { 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 38fc6264133..a35c4a5c286 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 @@ -272,7 +272,7 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand { /** * A memory operand other than the operand of a `Phi` instruction. */ -class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand { +class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand { override MemoryOperandTag tag; NonPhiMemoryOperand() { diff --git a/csharp/ql/src/experimental/ir/implementation/internal/TOperand.qll b/csharp/ql/src/experimental/ir/implementation/internal/TOperand.qll index 143201eea14..027e37f4dd3 100644 --- a/csharp/ql/src/experimental/ir/implementation/internal/TOperand.qll +++ b/csharp/ql/src/experimental/ir/implementation/internal/TOperand.qll @@ -80,6 +80,7 @@ module RawOperands { class TChiOperand = Internal::TNoOperand; + class TNonPhiMemoryOperand = TNonSSAMemoryOperand or TChiOperand; /** * Returns the Phi operand with the specified parameters. */ @@ -109,6 +110,8 @@ module UnaliasedSSAOperands { class TChiOperand = Internal::TNoOperand; + class TNonPhiMemoryOperand = TNonSSAMemoryOperand or TChiOperand; + /** * Returns the Phi operand with the specified parameters. */ diff --git a/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll b/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll index 38fc6264133..a35c4a5c286 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll @@ -272,7 +272,7 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand { /** * A memory operand other than the operand of a `Phi` instruction. */ -class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand { +class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand { override MemoryOperandTag tag; NonPhiMemoryOperand() { 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 38fc6264133..a35c4a5c286 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Operand.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Operand.qll @@ -272,7 +272,7 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand { /** * A memory operand other than the operand of a `Phi` instruction. */ -class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand { +class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand { override MemoryOperandTag tag; NonPhiMemoryOperand() { From 8919e5546b1976e5b575f8dfc0102a8fa1d2d4a0 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Tue, 26 Jan 2021 14:12:49 -0800 Subject: [PATCH 008/142] C++ Use dontcare instead of one-use exists Co-authored-by: Mathias Vorreiter Pedersen --- .../src/semmle/code/cpp/ir/implementation/raw/Operand.qll | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 a35c4a5c286..be72eeeabe0 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 @@ -27,13 +27,13 @@ private class TStageOperand = class Operand extends TStageOperand { Operand() { // Ensure that the operand does not refer to instructions from earlier stages that are unreachable here - exists(Instruction use, Instruction def | this = registerOperand(use, _, def)) + this = registerOperand(_, _, _) or - exists(Instruction use | this = nonSSAMemoryOperand(use, _)) + this = nonSSAMemoryOperand(_, _) or - exists(Instruction use, Instruction def, IRBlock block | this = phiOperand(use, def, block, _)) + this = phiOperand(_, _, _, _) or - exists(Instruction use | this = chiOperand(use, _)) + this = chiOperand(_, _) } /** Gets a textual representation of this element. */ From 50edf44e843e393f33454b24784d0f5dd0ba091f Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Tue, 2 Feb 2021 09:06:44 -0800 Subject: [PATCH 009/142] C++/C#: autoformat and sync files --- .../code/cpp/ir/implementation/aliased_ssa/Operand.qll | 8 ++++---- .../code/cpp/ir/implementation/internal/TOperand.qll | 2 ++ .../code/cpp/ir/implementation/unaliased_ssa/Operand.qll | 8 ++++---- .../experimental/ir/implementation/internal/TOperand.qll | 1 + .../ql/src/experimental/ir/implementation/raw/Operand.qll | 8 ++++---- .../ir/implementation/unaliased_ssa/Operand.qll | 8 ++++---- 6 files changed, 19 insertions(+), 16 deletions(-) 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 a35c4a5c286..be72eeeabe0 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 @@ -27,13 +27,13 @@ private class TStageOperand = class Operand extends TStageOperand { Operand() { // Ensure that the operand does not refer to instructions from earlier stages that are unreachable here - exists(Instruction use, Instruction def | this = registerOperand(use, _, def)) + this = registerOperand(_, _, _) or - exists(Instruction use | this = nonSSAMemoryOperand(use, _)) + this = nonSSAMemoryOperand(_, _) or - exists(Instruction use, Instruction def, IRBlock block | this = phiOperand(use, def, block, _)) + this = phiOperand(_, _, _, _) or - exists(Instruction use | this = chiOperand(use, _)) + this = chiOperand(_, _) } /** Gets a textual representation of this element. */ diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TOperand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TOperand.qll index 4d6141cef06..90d951a40e5 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TOperand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TOperand.qll @@ -132,6 +132,7 @@ module UnaliasedSSAOperands { class TChiOperand = Internal::TNoOperand; class TNonPhiMemoryOperand = TNonSSAMemoryOperand or TChiOperand; + /** * Returns the Phi operand with the specified parameters. */ @@ -162,6 +163,7 @@ module AliasedSSAOperands { class TChiOperand = Internal::TAliasedChiOperand; class TNonPhiMemoryOperand = TNonSSAMemoryOperand or TChiOperand; + /** * Returns the Phi operand with the specified parameters. */ 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 a35c4a5c286..be72eeeabe0 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 @@ -27,13 +27,13 @@ private class TStageOperand = class Operand extends TStageOperand { Operand() { // Ensure that the operand does not refer to instructions from earlier stages that are unreachable here - exists(Instruction use, Instruction def | this = registerOperand(use, _, def)) + this = registerOperand(_, _, _) or - exists(Instruction use | this = nonSSAMemoryOperand(use, _)) + this = nonSSAMemoryOperand(_, _) or - exists(Instruction use, Instruction def, IRBlock block | this = phiOperand(use, def, block, _)) + this = phiOperand(_, _, _, _) or - exists(Instruction use | this = chiOperand(use, _)) + this = chiOperand(_, _) } /** Gets a textual representation of this element. */ diff --git a/csharp/ql/src/experimental/ir/implementation/internal/TOperand.qll b/csharp/ql/src/experimental/ir/implementation/internal/TOperand.qll index 027e37f4dd3..9c3e7620186 100644 --- a/csharp/ql/src/experimental/ir/implementation/internal/TOperand.qll +++ b/csharp/ql/src/experimental/ir/implementation/internal/TOperand.qll @@ -81,6 +81,7 @@ module RawOperands { class TChiOperand = Internal::TNoOperand; class TNonPhiMemoryOperand = TNonSSAMemoryOperand or TChiOperand; + /** * Returns the Phi operand with the specified parameters. */ diff --git a/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll b/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll index a35c4a5c286..be72eeeabe0 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll @@ -27,13 +27,13 @@ private class TStageOperand = class Operand extends TStageOperand { Operand() { // Ensure that the operand does not refer to instructions from earlier stages that are unreachable here - exists(Instruction use, Instruction def | this = registerOperand(use, _, def)) + this = registerOperand(_, _, _) or - exists(Instruction use | this = nonSSAMemoryOperand(use, _)) + this = nonSSAMemoryOperand(_, _) or - exists(Instruction use, Instruction def, IRBlock block | this = phiOperand(use, def, block, _)) + this = phiOperand(_, _, _, _) or - exists(Instruction use | this = chiOperand(use, _)) + this = chiOperand(_, _) } /** Gets a textual representation of this element. */ 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 a35c4a5c286..be72eeeabe0 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Operand.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Operand.qll @@ -27,13 +27,13 @@ private class TStageOperand = class Operand extends TStageOperand { Operand() { // Ensure that the operand does not refer to instructions from earlier stages that are unreachable here - exists(Instruction use, Instruction def | this = registerOperand(use, _, def)) + this = registerOperand(_, _, _) or - exists(Instruction use | this = nonSSAMemoryOperand(use, _)) + this = nonSSAMemoryOperand(_, _) or - exists(Instruction use, Instruction def, IRBlock block | this = phiOperand(use, def, block, _)) + this = phiOperand(_, _, _, _) or - exists(Instruction use | this = chiOperand(use, _)) + this = chiOperand(_, _) } /** Gets a textual representation of this element. */ From 631ee28cae1b803585d29d4184db206e15500b71 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Tue, 2 Feb 2021 09:11:21 -0800 Subject: [PATCH 010/142] C++: update comments about SSA sharing --- .../semmle/code/cpp/ir/implementation/internal/TOperand.qll | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TOperand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TOperand.qll index 90d951a40e5..0a55587e436 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TOperand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TOperand.qll @@ -43,8 +43,8 @@ private module Internal { } or //// ALIASED //// - // If we share SSA, these will be all the phis there are. Otherwise these - // will add to the ones that are already there. + // Until we share SSA, these will be all the phis there are. With SSA + // sharing, these will add to the ones that are already there. // If we share SSA, be careful with the case where we remove all possible // indirect writes to a variable because they're dead code. In that case it's // important that we use the same definition of "is variable aliased" across @@ -56,7 +56,6 @@ private module Internal { defInstr = AliasedConstruction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap) } or TAliasedChiOperand(TAliasedSSAChiInstruction useInstr, ChiOperandTag tag) { - // TODO: any further restrictions here? any() } } From 79855157b3ce7713fda492577243301349c71639 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 11 Feb 2021 15:34:13 +0100 Subject: [PATCH 011/142] Python: Move django response test to django v2/v3 That's really the django version I care about :P --- .../frameworks/{django-v1 => django-v2-v3}/response_test.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename python/ql/test/experimental/library-tests/frameworks/{django-v1 => django-v2-v3}/response_test.py (100%) diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v1/response_test.py b/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/response_test.py similarity index 100% rename from python/ql/test/experimental/library-tests/frameworks/django-v1/response_test.py rename to python/ql/test/experimental/library-tests/frameworks/django-v2-v3/response_test.py From 6934d5e642fec37ae62bf6eb235b51ba3274b5cb Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Thu, 11 Feb 2021 15:40:06 +0100 Subject: [PATCH 012/142] Python: Add django test of RedirectView subclass --- .../frameworks/django-v2-v3/response_test.py | 8 ++++++++ .../frameworks/django-v2-v3/testapp/urls.py | 3 +++ .../frameworks/django-v2-v3/testapp/views.py | 15 ++++++++++++++- 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/response_test.py b/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/response_test.py index 99dc97624aa..8d73184702d 100644 --- a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/response_test.py +++ b/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/response_test.py @@ -1,4 +1,5 @@ from django.http.response import HttpResponse, HttpResponseRedirect, HttpResponsePermanentRedirect, JsonResponse, HttpResponseNotFound +from django.views.generic import RedirectView import django.shortcuts # Not an XSS sink, since the Content-Type is not "text/html" @@ -54,6 +55,13 @@ def redirect_shortcut(request): return django.shortcuts.redirect(next) # $ HttpResponse HttpRedirectResponse redirectLocation=next +class CustomRedirectView(RedirectView): + + def get_redirect_url(self, foo): # $ MISSING: routedParameter=foo + next = "https://example.com/{}".format(foo) + return next # $ MISSING: HttpResponse HttpRedirectResponse redirectLocation=next + + # Ensure that simple subclasses are still vuln to XSS def xss__not_found(request): return HttpResponseNotFound(request.GET.get("name")) # $HttpResponse mimetype=text/html responseBody=Attribute() diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testapp/urls.py b/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testapp/urls.py index 0f5c360b9d8..2f0d978c97a 100644 --- a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testapp/urls.py +++ b/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testapp/urls.py @@ -15,4 +15,7 @@ urlpatterns = [ path("basic-view-handler/", views.MyBasicViewHandler.as_view()), # $routeSetup="basic-view-handler/" path("custom-inheritance-view-handler/", views.MyViewHandlerWithCustomInheritance.as_view()), # $routeSetup="custom-inheritance-view-handler/" + + path("CustomRedirectView/", views.CustomRedirectView.as_view()), # $routeSetup="CustomRedirectView/" + path("CustomRedirectView2/", views.CustomRedirectView2.as_view()), # $routeSetup="CustomRedirectView2/" ] diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testapp/views.py b/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testapp/views.py index d2028d0dd03..c51d07cef2a 100644 --- a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testapp/views.py +++ b/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testapp/views.py @@ -1,5 +1,5 @@ from django.http import HttpRequest, HttpResponse -from django.views import View +from django.views.generic import View, RedirectView from django.views.decorators.csrf import csrf_exempt @@ -32,3 +32,16 @@ class MyViewHandlerWithCustomInheritance(MyCustomViewBaseClass): def get(self, request: HttpRequest): # $ requestHandler print(self.request.GET) return HttpResponse("MyViewHandlerWithCustomInheritance: GET") # $ HttpResponse + +# RedirectView +# See docs at https://docs.djangoproject.com/en/3.1/ref/class-based-views/base/#redirectview +class CustomRedirectView(RedirectView): + + def get_redirect_url(self, foo): # $ MISSING: routedParameter=foo + next = "https://example.com/{}".format(foo) + return next # $ MISSING: HttpResponse HttpRedirectResponse redirectLocation=next + + +class CustomRedirectView2(RedirectView): + + url = "https://example.com/%(foo)s" From 745148474a6b90d2468acfd5a1c832f41fc90c54 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Fri, 12 Feb 2021 10:25:33 +0100 Subject: [PATCH 013/142] Python: Model get_redirect_url in django --- .../2021-02-12-django-get_redirect_url.md | 2 + .../src/semmle/python/frameworks/Django.qll | 73 +++++++++++++++++-- .../django-v2-v3/TestTaint.expected | 1 + .../frameworks/django-v2-v3/response_test.py | 5 +- .../frameworks/django-v2-v3/testapp/views.py | 4 +- 5 files changed, 76 insertions(+), 9 deletions(-) create mode 100644 python/change-notes/2021-02-12-django-get_redirect_url.md diff --git a/python/change-notes/2021-02-12-django-get_redirect_url.md b/python/change-notes/2021-02-12-django-get_redirect_url.md new file mode 100644 index 00000000000..e2aef502c67 --- /dev/null +++ b/python/change-notes/2021-02-12-django-get_redirect_url.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* Improved modeling of `django` to recognize request redirects from `get_redirect_url` on a `RedirectView` subclass. diff --git a/python/ql/src/semmle/python/frameworks/Django.qll b/python/ql/src/semmle/python/frameworks/Django.qll index 6e90d5adee0..b68f7b5e43e 100644 --- a/python/ql/src/semmle/python/frameworks/Django.qll +++ b/python/ql/src/semmle/python/frameworks/Django.qll @@ -2074,7 +2074,11 @@ private module Django { // TODO: This doesn't handle attribute assignment. Should be OK, but analysis is not as complete as with // points-to and `.lookup`, which would handle `post = my_post_handler` inside class def result = this.getAMethod() and - result.getName() = HTTP::httpVerbLower() + ( + result.getName() = HTTP::httpVerbLower() + or + result.getName() = "get_redirect_url" + ) } /** @@ -2124,6 +2128,8 @@ private module Django { /** * A function that is a django route handler, meaning it handles incoming requests * with the django framework. + * + * Most functions take a django HttpRequest as a parameter (but not all). */ private class DjangoRouteHandler extends Function { DjangoRouteHandler() { @@ -2132,6 +2138,12 @@ private module Django { any(DjangoViewClass vc).getARequestHandler() = this } + /** + * Gets the index of the parameter where the first routed parameter can be passed -- + * that is, the one just after any possible `self` or HttpRequest parameters. + */ + int getFirstPossibleRoutedParamIndex() { result = 1 + this.getRequestParamIndex() } + /** Gets the index of the request parameter. */ int getRequestParamIndex() { not this.isMethod() and @@ -2145,6 +2157,26 @@ private module Django { Parameter getRequestParam() { result = this.getArg(this.getRequestParamIndex()) } } + /** + * A method named `get_redirect_url` on a django view class. + * + * See https://docs.djangoproject.com/en/3.1/ref/class-based-views/base/#django.views.generic.base.RedirectView.get_redirect_url + * + * Note: this function only does something on a subclass of `RedirectView`, but since + * classes can be considered django view classes without us knowing their super-classes, + * we need to consider _any_ django view class. I don't expect any problems to come from this. + */ + private class GetRedirectUrlFunction extends DjangoRouteHandler { + GetRedirectUrlFunction() { + this.getName() = "get_redirect_url" and + any(DjangoViewClass vc).getARequestHandler() = this + } + + override int getFirstPossibleRoutedParamIndex() { result = 1 } + + override int getRequestParamIndex() { none() } + } + /** A data-flow node that sets up a route on a server, using the django framework. */ abstract private class DjangoRouteSetup extends HTTP::Server::RouteSetup::Range, DataFlow::CfgNode { /** Gets the data-flow node that is used as the argument for the view handler. */ @@ -2173,7 +2205,7 @@ private module Django { // parameter. This should give us more RemoteFlowSources but could also lead to // more FPs. If this turns out to be the wrong tradeoff, we can always change our mind. result in [this.getArg(_), this.getArgByName(_)] and - not result = any(int i | i <= this.getRequestParamIndex() | this.getArg(i)) + not result = any(int i | i < this.getFirstPossibleRoutedParamIndex() | this.getArg(i)) } } @@ -2211,7 +2243,8 @@ private module Django { exists(DjangoRouteHandler routeHandler | routeHandler = this.getARequestHandler() | not exists(this.getUrlPattern()) and result in [routeHandler.getArg(_), routeHandler.getArgByName(_)] and - not result = any(int i | i <= routeHandler.getRequestParamIndex() | routeHandler.getArg(i)) + not result = + any(int i | i < routeHandler.getFirstPossibleRoutedParamIndex() | routeHandler.getArg(i)) ) or exists(string name | @@ -2233,7 +2266,8 @@ private module Django { exists(DjangoRouteHandler routeHandler | routeHandler = this.getARequestHandler() | not exists(this.getUrlPattern()) and result in [routeHandler.getArg(_), routeHandler.getArgByName(_)] and - not result = any(int i | i <= routeHandler.getRequestParamIndex() | routeHandler.getArg(i)) + not result = + any(int i | i < routeHandler.getFirstPossibleRoutedParamIndex() | routeHandler.getArg(i)) ) or exists(DjangoRouteHandler routeHandler, DjangoRouteRegex regex | @@ -2245,7 +2279,9 @@ private module Django { not exists(regex.getGroupName(_, _)) and // first group will have group number 1 result = - routeHandler.getArg(routeHandler.getRequestParamIndex() + regex.getGroupNumber(_, _)) + routeHandler + .getArg(routeHandler.getFirstPossibleRoutedParamIndex() - 1 + + regex.getGroupNumber(_, _)) or result = routeHandler.getArgByName(regex.getGroupName(_, _)) ) @@ -2441,4 +2477,31 @@ private module Django { override string getMimetypeDefault() { none() } } + + // --------------------------------------------------------------------------- + // RedirectView handling + // --------------------------------------------------------------------------- + /** + * A return from a method named `get_redirect_url` on a django view class. + * + * Note that in reality, this only does something on a subclass of `RedirectView` -- + * but until API graphs makes this easy to model, I took a shortcut in modeling + * preciseness. + * + * See https://docs.djangoproject.com/en/3.1/ref/class-based-views/base/#redirectview + */ + private class DjangoRedirectViewGetRedirectUrlReturn extends HTTP::Server::HttpRedirectResponse::Range, + DataFlow::CfgNode { + DjangoRedirectViewGetRedirectUrlReturn() { + node = any(GetRedirectUrlFunction f).getAReturnValueFlowNode() + } + + override DataFlow::Node getRedirectLocation() { result = this } + + override DataFlow::Node getBody() { none() } + + override DataFlow::Node getMimetypeOrContentTypeArg() { none() } + + override string getMimetypeDefault() { none() } + } } diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/TestTaint.expected b/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/TestTaint.expected index c76685c6739..0602985a392 100644 --- a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/TestTaint.expected +++ b/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/TestTaint.expected @@ -1,3 +1,4 @@ +| response_test.py:61 | ok | get_redirect_url | foo | | taint_test.py:8 | ok | test_taint | bar | | taint_test.py:8 | ok | test_taint | foo | | taint_test.py:9 | ok | test_taint | baz | diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/response_test.py b/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/response_test.py index 8d73184702d..91252378677 100644 --- a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/response_test.py +++ b/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/response_test.py @@ -57,9 +57,10 @@ def redirect_shortcut(request): class CustomRedirectView(RedirectView): - def get_redirect_url(self, foo): # $ MISSING: routedParameter=foo + def get_redirect_url(self, foo): # $ requestHandler routedParameter=foo + ensure_tainted(foo) next = "https://example.com/{}".format(foo) - return next # $ MISSING: HttpResponse HttpRedirectResponse redirectLocation=next + return next # $ HttpResponse HttpRedirectResponse redirectLocation=next # Ensure that simple subclasses are still vuln to XSS diff --git a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testapp/views.py b/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testapp/views.py index c51d07cef2a..2a3ed803507 100644 --- a/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testapp/views.py +++ b/python/ql/test/experimental/library-tests/frameworks/django-v2-v3/testapp/views.py @@ -37,9 +37,9 @@ class MyViewHandlerWithCustomInheritance(MyCustomViewBaseClass): # See docs at https://docs.djangoproject.com/en/3.1/ref/class-based-views/base/#redirectview class CustomRedirectView(RedirectView): - def get_redirect_url(self, foo): # $ MISSING: routedParameter=foo + def get_redirect_url(self, foo): # $ requestHandler routedParameter=foo next = "https://example.com/{}".format(foo) - return next # $ MISSING: HttpResponse HttpRedirectResponse redirectLocation=next + return next # $ HttpResponse HttpRedirectResponse redirectLocation=next class CustomRedirectView2(RedirectView): From 0b2daf7679c26816283dbebfc6a4d367b93a6dda Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Mon, 22 Feb 2021 14:41:21 -0800 Subject: [PATCH 014/142] C++: filter operands of removed IR instructions --- .../cpp/ir/implementation/aliased_ssa/Operand.qll | 13 ++++++------- .../code/cpp/ir/implementation/raw/Operand.qll | 13 ++++++------- .../cpp/ir/implementation/unaliased_ssa/Operand.qll | 13 ++++++------- .../experimental/ir/implementation/raw/Operand.qll | 13 ++++++------- .../ir/implementation/unaliased_ssa/Operand.qll | 13 ++++++------- 5 files changed, 30 insertions(+), 35 deletions(-) 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 be72eeeabe0..8f39d1b4c85 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 @@ -27,13 +27,12 @@ private class TStageOperand = class Operand extends TStageOperand { Operand() { // Ensure that the operand does not refer to instructions from earlier stages that are unreachable here - this = registerOperand(_, _, _) - or - this = nonSSAMemoryOperand(_, _) - or - this = phiOperand(_, _, _, _) - or - this = chiOperand(_, _) + exists(Instruction use, Instruction def | this = registerOperand(use, _, def)) or + exists(Instruction use | this = nonSSAMemoryOperand(use, _)) or + exists(Instruction use, Instruction def, IRBlock predecessorBlock | + this = phiOperand(use, def, predecessorBlock, _) + ) or + exists(Instruction use | this = chiOperand(use, _)) } /** Gets a textual representation of this element. */ 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 be72eeeabe0..8f39d1b4c85 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 @@ -27,13 +27,12 @@ private class TStageOperand = class Operand extends TStageOperand { Operand() { // Ensure that the operand does not refer to instructions from earlier stages that are unreachable here - this = registerOperand(_, _, _) - or - this = nonSSAMemoryOperand(_, _) - or - this = phiOperand(_, _, _, _) - or - this = chiOperand(_, _) + exists(Instruction use, Instruction def | this = registerOperand(use, _, def)) or + exists(Instruction use | this = nonSSAMemoryOperand(use, _)) or + exists(Instruction use, Instruction def, IRBlock predecessorBlock | + this = phiOperand(use, def, predecessorBlock, _) + ) or + exists(Instruction use | this = chiOperand(use, _)) } /** Gets a textual representation of this element. */ 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 be72eeeabe0..8f39d1b4c85 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 @@ -27,13 +27,12 @@ private class TStageOperand = class Operand extends TStageOperand { Operand() { // Ensure that the operand does not refer to instructions from earlier stages that are unreachable here - this = registerOperand(_, _, _) - or - this = nonSSAMemoryOperand(_, _) - or - this = phiOperand(_, _, _, _) - or - this = chiOperand(_, _) + exists(Instruction use, Instruction def | this = registerOperand(use, _, def)) or + exists(Instruction use | this = nonSSAMemoryOperand(use, _)) or + exists(Instruction use, Instruction def, IRBlock predecessorBlock | + this = phiOperand(use, def, predecessorBlock, _) + ) or + exists(Instruction use | this = chiOperand(use, _)) } /** Gets a textual representation of this element. */ diff --git a/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll b/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll index be72eeeabe0..8f39d1b4c85 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll @@ -27,13 +27,12 @@ private class TStageOperand = class Operand extends TStageOperand { Operand() { // Ensure that the operand does not refer to instructions from earlier stages that are unreachable here - this = registerOperand(_, _, _) - or - this = nonSSAMemoryOperand(_, _) - or - this = phiOperand(_, _, _, _) - or - this = chiOperand(_, _) + exists(Instruction use, Instruction def | this = registerOperand(use, _, def)) or + exists(Instruction use | this = nonSSAMemoryOperand(use, _)) or + exists(Instruction use, Instruction def, IRBlock predecessorBlock | + this = phiOperand(use, def, predecessorBlock, _) + ) or + exists(Instruction use | this = chiOperand(use, _)) } /** Gets a textual representation of this element. */ 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 be72eeeabe0..8f39d1b4c85 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Operand.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Operand.qll @@ -27,13 +27,12 @@ private class TStageOperand = class Operand extends TStageOperand { Operand() { // Ensure that the operand does not refer to instructions from earlier stages that are unreachable here - this = registerOperand(_, _, _) - or - this = nonSSAMemoryOperand(_, _) - or - this = phiOperand(_, _, _, _) - or - this = chiOperand(_, _) + exists(Instruction use, Instruction def | this = registerOperand(use, _, def)) or + exists(Instruction use | this = nonSSAMemoryOperand(use, _)) or + exists(Instruction use, Instruction def, IRBlock predecessorBlock | + this = phiOperand(use, def, predecessorBlock, _) + ) or + exists(Instruction use | this = chiOperand(use, _)) } /** Gets a textual representation of this element. */ From d8792f2f7f10fe2b617a5d83d5cb55c4b5ac29f0 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Tue, 23 Feb 2021 14:05:07 +0100 Subject: [PATCH 015/142] C#: Fix bug in `BaseSSA::reachesEndOf/3` --- csharp/ql/src/semmle/code/csharp/dataflow/internal/BaseSSA.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/BaseSSA.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/BaseSSA.qll index 584e0ca9c33..0a1c022513d 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/BaseSSA.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/BaseSSA.qll @@ -101,7 +101,7 @@ module BaseSsa { or exists(BasicBlock mid | reachesEndOf(def, v, mid) and - not exists(ssaRefRank(mid, _, v, SsaDef())) and + not exists(ssaRefRank(bb, _, v, SsaDef())) and bb = mid.getASuccessor() ) } From b0ee508f1036477f9870d2120a69d1faa4b9e90a Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Mon, 11 Jan 2021 10:10:37 +0100 Subject: [PATCH 016/142] C#: Use shared SSA implementation for `PreSsa` --- config/identical-files.json | 6 +- .../semmle/code/csharp/controlflow/Guards.qll | 26 +- .../controlflow/internal/PreBasicBlocks.qll | 7 - .../csharp/controlflow/internal/PreSsa.qll | 406 ++---------- .../csharp/controlflow/internal/Splitting.qll | 11 +- .../internal/pressa/SsaImplCommon.qll | 619 ++++++++++++++++++ .../internal/pressa/SsaImplSpecific.qll | 106 +++ .../dataflow/ssa/PreSsaConsistency.ql | 40 +- 8 files changed, 820 insertions(+), 401 deletions(-) create mode 100644 csharp/ql/src/semmle/code/csharp/controlflow/internal/pressa/SsaImplCommon.qll create mode 100644 csharp/ql/src/semmle/code/csharp/controlflow/internal/pressa/SsaImplSpecific.qll diff --git a/config/identical-files.json b/config/identical-files.json index d68dabba861..62c48d1fcd8 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -425,5 +425,9 @@ "java/ql/src/IDEContextual.qll", "javascript/ql/src/IDEContextual.qll", "python/ql/src/analysis/IDEContextual.qll" + ], + "SSA C#": [ + "csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImplCommon.qll", + "csharp/ql/src/semmle/code/csharp/controlflow/internal/pressa/SsaImplCommon.qll" ] -} +} \ No newline at end of file diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll b/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll index 396fb52a85d..bdcfa6ac4b7 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/Guards.qll @@ -995,7 +995,7 @@ module Internal { // pre-SSA predicates private module PreCFG { private import semmle.code.csharp.controlflow.internal.PreBasicBlocks as PreBasicBlocks - private import semmle.code.csharp.controlflow.internal.PreSsa as PreSsa + private import semmle.code.csharp.controlflow.internal.PreSsa /** * Holds if pre-basic-block `bb` only is reached when guard `g` has abstract value `v`, @@ -1081,25 +1081,25 @@ module Internal { pragma[noinline] private predicate conditionalAssign0( - Guard guard, AbstractValue vGuard, PreSsa::Definition def, Expr e, PreSsa::Definition upd, + Guard guard, AbstractValue vGuard, PreSsa::PhiNode phi, Expr e, PreSsa::Definition upd, PreBasicBlocks::PreBasicBlock bbGuard ) { e = upd.getDefinition().getSource() and - upd = def.getAPhiInput() and + upd = phi.getAnInput() and preControlsDirect(guard, upd.getBasicBlock(), vGuard) and bbGuard.getAnElement() = guard and - bbGuard.strictlyDominates(def.getBasicBlock()) and - not preControlsDirect(guard, def.getBasicBlock(), vGuard) + bbGuard.strictlyDominates(phi.getBasicBlock()) and + not preControlsDirect(guard, phi.getBasicBlock(), vGuard) } pragma[noinline] private predicate conditionalAssign1( - Guard guard, AbstractValue vGuard, PreSsa::Definition def, Expr e, PreSsa::Definition upd, + Guard guard, AbstractValue vGuard, PreSsa::PhiNode phi, Expr e, PreSsa::Definition upd, PreBasicBlocks::PreBasicBlock bbGuard, PreSsa::Definition other ) { - conditionalAssign0(guard, vGuard, def, e, upd, bbGuard) and + conditionalAssign0(guard, vGuard, phi, e, upd, bbGuard) and other != upd and - other = def.getAPhiInput() + other = phi.getAnInput() } pragma[noinline] @@ -1127,7 +1127,7 @@ module Internal { ) { conditionalAssign1(guard, vGuard, def, e, upd, bbGuard, other) and other.getBasicBlock().dominates(bbGuard) and - not PreSsa::ssaDefReachesEndOfBlock(getConditionalSuccessor(guard, vGuard), other, _) + not other.isLiveAtEndOfBlock(getConditionalSuccessor(guard, vGuard)) } /** @@ -1315,14 +1315,14 @@ module Internal { */ private PreSsa::Definition getADefinition(PreSsa::Definition def, boolean fromBackEdge) { result = def and - not exists(def.getAPhiInput()) and + not def instanceof PreSsa::PhiNode and fromBackEdge = false or exists(PreSsa::Definition input, PreBasicBlocks::PreBasicBlock pred, boolean fbe | - input = def.getAPhiInput() + input = def.(PreSsa::PhiNode).getAnInput() | pred = def.getBasicBlock().getAPredecessor() and - PreSsa::ssaDefReachesEndOfBlock(pred, input, _) and + input.isLiveAtEndOfBlock(pred) and result = getADefinition(input, fbe) and (if def.getBasicBlock().dominates(pred) then fromBackEdge = true else fromBackEdge = fbe) ) @@ -1446,7 +1446,7 @@ module Internal { private predicate firstReadSameVarUniquePredecesssor( PreSsa::Definition def, AssignableRead read ) { - PreSsa::firstReadSameVar(def, read) and + read = def.getAFirstRead() and not exists(AssignableRead other | PreSsa::adjacentReadPairSameVar(other, read) | other != read ) diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/internal/PreBasicBlocks.qll b/csharp/ql/src/semmle/code/csharp/controlflow/internal/PreBasicBlocks.qll index d1398719c15..31155dea0ae 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/internal/PreBasicBlocks.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/internal/PreBasicBlocks.qll @@ -82,13 +82,6 @@ class PreBasicBlock extends ControlFlowElement { or this.strictlyDominates(bb) } - - predicate inDominanceFrontier(PreBasicBlock df) { - this.dominatesPredecessor(df) and - not this.strictlyDominates(df) - } - - private predicate dominatesPredecessor(PreBasicBlock df) { this.dominates(df.getAPredecessor()) } } private Completion getConditionalCompletion(ConditionalCompletion cc) { diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/internal/PreSsa.qll b/csharp/ql/src/semmle/code/csharp/controlflow/internal/PreSsa.qll index 8243520aaf1..5ac313651d7 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/internal/PreSsa.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/internal/PreSsa.qll @@ -1,370 +1,74 @@ +import csharp + /** - * INTERNAL: Do not use. - * * Provides an SSA implementation based on "pre-basic-blocks", restricted * to local scope variables and fields/properties that behave like local * scope variables. - * - * The logic is duplicated from the implementation in `SSA.qll`, and - * being an internal class, all predicate documentation has been removed. */ +module PreSsa { + import pressa.SsaImplSpecific + private import pressa.SsaImplCommon as SsaImpl -import csharp -private import AssignableDefinitions -private import PreBasicBlocks -private import ControlFlowGraphImpl -private import semmle.code.csharp.controlflow.Guards as Guards + class Definition extends SsaImpl::Definition { + final AssignableRead getARead() { + exists(BasicBlock bb, int i | + SsaImpl::ssaDefReachesRead(_, this, bb, i) and + result = bb.getElement(i) + ) + } -pragma[noinline] -private predicate assignableNoCapturing(Assignable a, Callable c) { - exists(AssignableAccess aa | aa.getTarget() = a | c = aa.getEnclosingCallable()) and - forall(AssignableDefinition def | def.getTarget() = a | - c = def.getEnclosingCallable() - or - def.getEnclosingCallable() instanceof Constructor - ) -} + final AssignableDefinition getDefinition() { + exists(BasicBlock bb, int i, SourceVariable v | + this.definesAt(v, bb, i) and + definitionAt(result, bb, i, v) + ) + } -pragma[noinline] -private predicate assignableNoComplexQualifiers(Assignable a) { - forall(QualifiableExpr qe | qe.(AssignableAccess).getTarget() = a | qe.targetIsThisInstance()) -} + final AssignableRead getAFirstRead() { + exists(BasicBlock bb1, int i1, BasicBlock bb2, int i2 | + this.definesAt(_, bb1, i1) and + SsaImpl::adjacentDefRead(this, bb1, i1, bb2, i2) and + result = bb2.getElement(i2) + ) + } -/** - * A simple assignable. Either a local scope variable or a field/property - * that behaves like a local scope variable. - */ -class SimpleAssignable extends Assignable { - private Callable c; + private Definition getAPhiInputOrPriorDefinition() { + result = this.(PhiNode).getAnInput() or + SsaImpl::uncertainWriteDefinitionInput(this, result) + } - SimpleAssignable() { - ( - this instanceof LocalScopeVariable + final Definition getAnUltimateDefinition() { + result = this.getAPhiInputOrPriorDefinition*() and + not result instanceof PhiNode + } + + final predicate isLiveAtEndOfBlock(BasicBlock bb) { + SsaImpl::ssaDefReachesEndOfBlock(bb, this, _) + } + + Location getLocation() { + result = this.getDefinition().getLocation() or - this instanceof Field - or - this = any(TrivialProperty tp | not tp.isOverridableOrImplementable()) - ) and - assignableNoCapturing(this, c) and - assignableNoComplexQualifiers(this) + exists(Callable c, BasicBlock bb, SourceVariable v | + this.definesAt(v, bb, -1) and + implicitEntryDef(c, bb, v) and + result = c.getLocation() + ) + } } - /** Gets a callable in which this simple assignable can be analyzed. */ - Callable getACallable() { result = c } -} + class PhiNode extends SsaImpl::PhiNode, Definition { + final override Location getLocation() { result = this.getBasicBlock().getLocation() } -pragma[noinline] -private predicate phiNodeMaybeLive(PreBasicBlock bb, SimpleAssignable a) { - exists(PreBasicBlock def | defAt(def, _, _, a) | def.inDominanceFrontier(bb)) -} - -private newtype TPreSsaDef = - TExplicitPreSsaDef(PreBasicBlock bb, int i, AssignableDefinition def, SimpleAssignable a) { - assignableDefAtLive(bb, i, def, a) - } or - TImplicitEntryPreSsaDef(Callable c, PreBasicBlock bb, Assignable a) { - implicitEntryDef(c, bb, a) and - liveAtEntry(bb, a) - } or - TPhiPreSsaDef(PreBasicBlock bb, SimpleAssignable a) { - phiNodeMaybeLive(bb, a) and - liveAtEntry(bb, a) + final Definition getAnInput() { SsaImpl::phiHasInputFromBlock(this, result, _) } } -class Definition extends TPreSsaDef { - string toString() { - exists(AssignableDefinition def | this = TExplicitPreSsaDef(_, _, def, _) | - result = def.toString() - ) - or - exists(SimpleAssignable a | this = TImplicitEntryPreSsaDef(_, _, a) | - result = "implicit(" + a + ")" - ) - or - exists(SimpleAssignable a | this = TPhiPreSsaDef(_, a) | result = "phi(" + a.toString() + ")") - } - - SimpleAssignable getAssignable() { - this = TExplicitPreSsaDef(_, _, _, result) - or - this = TImplicitEntryPreSsaDef(_, _, result) - or - this = TPhiPreSsaDef(_, result) - } - - AssignableRead getARead() { - firstReadSameVar(this, result) - or - exists(AssignableRead read | firstReadSameVar(this, read) | - adjacentReadPairSameVar+(read, result) + predicate adjacentReadPairSameVar(AssignableRead read1, AssignableRead read2) { + exists(BasicBlock bb1, int i1, BasicBlock bb2, int i2 | + read1 = bb1.getElement(i1) and + variableRead(bb1, i1, _, true) and + SsaImpl::adjacentDefRead(_, bb1, i1, bb2, i2) and + read2 = bb2.getElement(i2) ) } - - Location getLocation() { - exists(AssignableDefinition def | this = TExplicitPreSsaDef(_, _, def, _) | - result = def.getLocation() - ) - or - exists(Callable c | this = TImplicitEntryPreSsaDef(c, _, _) | result = c.getLocation()) - or - exists(PreBasicBlock bb | this = TPhiPreSsaDef(bb, _) | result = bb.getLocation()) - } - - PreBasicBlock getBasicBlock() { - this = TExplicitPreSsaDef(result, _, _, _) - or - this = TImplicitEntryPreSsaDef(_, result, _) - or - this = TPhiPreSsaDef(result, _) - } - - Callable getCallable() { result = this.getBasicBlock().getEnclosingCallable() } - - AssignableDefinition getDefinition() { this = TExplicitPreSsaDef(_, _, result, _) } - - Definition getAPhiInput() { - exists(PreBasicBlock bb, PreBasicBlock phiPred, SimpleAssignable a | - this = TPhiPreSsaDef(bb, a) - | - bb.getAPredecessor() = phiPred and - ssaDefReachesEndOfBlock(phiPred, result, a) - ) - } - - Definition getAnUltimateDefinition() { - result = this.getAPhiInput*() and - not result = TPhiPreSsaDef(_, _) - } -} - -predicate implicitEntryDef(Callable c, PreBasicBlock bb, SimpleAssignable a) { - not a instanceof LocalScopeVariable and - c = a.getACallable() and - scopeFirst(c, bb) -} - -private predicate assignableDefAt( - PreBasicBlock bb, int i, AssignableDefinition def, SimpleAssignable a -) { - bb.getElement(i) = def.getExpr() and - a = def.getTarget() and - // In cases like `(x, x) = (0, 1)`, we discard the first (dead) definition of `x` - not exists(TupleAssignmentDefinition first, TupleAssignmentDefinition second | first = def | - second.getAssignment() = first.getAssignment() and - second.getEvaluationOrder() > first.getEvaluationOrder() and - second.getTarget() = a - ) - or - def.(ImplicitParameterDefinition).getParameter() = a and - exists(Callable c | a = c.getAParameter() | - scopeFirst(c, bb) and - i = -1 - ) -} - -private predicate readAt(PreBasicBlock bb, int i, AssignableRead read, SimpleAssignable a) { - read = bb.getElement(i) and - read.getTarget() = a -} - -pragma[noinline] -private predicate exitBlock(PreBasicBlock bb, Callable c) { - scopeLast(c, bb.getLastElement(), _) and - c = bb.getEnclosingCallable() -} - -private predicate outRefExitRead(PreBasicBlock bb, int i, LocalScopeVariable v) { - exitBlock(bb, v.getCallable()) and - i = bb.length() + 1 and - (v.isRef() or v.(Parameter).isOut()) -} - -private newtype RefKind = - Read() or - Write(boolean certain) { certain = true or certain = false } - -private predicate ref(PreBasicBlock bb, int i, SimpleAssignable a, RefKind k) { - (readAt(bb, i, _, a) or outRefExitRead(bb, i, a)) and - k = Read() - or - exists(AssignableDefinition def, boolean certain | assignableDefAt(bb, i, def, a) | - (if def.getTargetAccess().isRefArgument() then certain = false else certain = true) and - k = Write(certain) - ) -} - -private int refRank(PreBasicBlock bb, int i, SimpleAssignable a, RefKind k) { - i = rank[result](int j | ref(bb, j, a, _)) and - ref(bb, i, a, k) -} - -private int maxRefRank(PreBasicBlock bb, SimpleAssignable a) { - result = refRank(bb, _, a, _) and - not result + 1 = refRank(bb, _, a, _) -} - -private int firstReadOrCertainWrite(PreBasicBlock bb, SimpleAssignable a) { - result = - min(int r, RefKind k | - r = refRank(bb, _, a, k) and - k != Write(false) - | - r - ) -} - -predicate liveAtEntry(PreBasicBlock bb, SimpleAssignable a) { - refRank(bb, _, a, Read()) = firstReadOrCertainWrite(bb, a) - or - not exists(firstReadOrCertainWrite(bb, a)) and - liveAtExit(bb, a) -} - -private predicate liveAtExit(PreBasicBlock bb, SimpleAssignable a) { - liveAtEntry(bb.getASuccessor(), a) -} - -predicate assignableDefAtLive(PreBasicBlock bb, int i, AssignableDefinition def, SimpleAssignable a) { - assignableDefAt(bb, i, def, a) and - exists(int rnk | rnk = refRank(bb, i, a, Write(_)) | - rnk + 1 = refRank(bb, _, a, Read()) - or - rnk = maxRefRank(bb, a) and - liveAtExit(bb, a) - ) -} - -predicate defAt(PreBasicBlock bb, int i, Definition def, SimpleAssignable a) { - def = TExplicitPreSsaDef(bb, i, _, a) - or - def = TImplicitEntryPreSsaDef(_, bb, a) and i = -1 - or - def = TPhiPreSsaDef(bb, a) and i = -1 -} - -private newtype SsaRefKind = - SsaRead() or - SsaDef() - -private predicate ssaRef(PreBasicBlock bb, int i, SimpleAssignable a, SsaRefKind k) { - readAt(bb, i, _, a) and - k = SsaRead() - or - defAt(bb, i, _, a) and - k = SsaDef() -} - -private int ssaRefRank(PreBasicBlock bb, int i, SimpleAssignable a, SsaRefKind k) { - i = rank[result](int j | ssaRef(bb, j, a, _)) and - ssaRef(bb, i, a, k) -} - -private predicate defReachesRank(PreBasicBlock bb, Definition def, SimpleAssignable a, int rnk) { - exists(int i | - rnk = ssaRefRank(bb, i, a, SsaDef()) and - defAt(bb, i, def, a) - ) - or - defReachesRank(bb, def, a, rnk - 1) and - rnk = ssaRefRank(bb, _, a, SsaRead()) -} - -private int maxSsaRefRank(PreBasicBlock bb, SimpleAssignable a) { - result = ssaRefRank(bb, _, a, _) and - not result + 1 = ssaRefRank(bb, _, a, _) -} - -pragma[noinline] -private predicate ssaDefReachesEndOfBlockRec(PreBasicBlock bb, Definition def, SimpleAssignable a) { - exists(PreBasicBlock idom | ssaDefReachesEndOfBlock(idom, def, a) | idom.immediatelyDominates(bb)) -} - -predicate ssaDefReachesEndOfBlock(PreBasicBlock bb, Definition def, SimpleAssignable a) { - exists(int last | last = maxSsaRefRank(bb, a) | - defReachesRank(bb, def, a, last) and - liveAtExit(bb, a) - ) - or - ssaDefReachesEndOfBlockRec(bb, def, a) and - liveAtExit(bb, a) and - not ssaRef(bb, _, a, SsaDef()) -} - -private predicate ssaDefReachesReadWithinBlock( - SimpleAssignable a, Definition def, PreBasicBlock bb, int i -) { - defReachesRank(bb, def, a, ssaRefRank(bb, i, a, SsaRead())) -} - -private predicate ssaDefReachesRead(SimpleAssignable a, Definition def, PreBasicBlock bb, int i) { - ssaDefReachesReadWithinBlock(a, def, bb, i) - or - ssaRef(bb, i, a, SsaRead()) and - ssaDefReachesEndOfBlock(bb.getAPredecessor(), def, a) and - not ssaDefReachesReadWithinBlock(a, _, bb, i) -} - -private int ssaDefRank(Definition def, PreBasicBlock bb, int i) { - exists(SimpleAssignable a | - a = def.getAssignable() and - result = ssaRefRank(bb, i, a, _) - | - ssaDefReachesRead(a, def, bb, i) - or - defAt(bb, i, def, a) - ) -} - -private predicate varOccursInBlock(Definition def, PreBasicBlock bb, SimpleAssignable a) { - exists(ssaDefRank(def, bb, _)) and - a = def.getAssignable() -} - -pragma[noinline] -private PreBasicBlock getAMaybeLiveSuccessor(Definition def, PreBasicBlock bb) { - result = bb.getASuccessor() and - not varOccursInBlock(_, bb, def.getAssignable()) and - ssaDefReachesEndOfBlock(bb, def, _) -} - -private predicate varBlockReaches(Definition def, PreBasicBlock bb1, PreBasicBlock bb2) { - varOccursInBlock(def, bb1, _) and - bb2 = bb1.getASuccessor() - or - exists(PreBasicBlock mid | varBlockReaches(def, bb1, mid) | - bb2 = getAMaybeLiveSuccessor(def, mid) - ) -} - -private predicate varBlockReachesRead(Definition def, PreBasicBlock bb1, AssignableRead read) { - exists(PreBasicBlock bb2, int i2 | - varBlockReaches(def, bb1, bb2) and - ssaRefRank(bb2, i2, def.getAssignable(), SsaRead()) = 1 and - readAt(bb2, i2, read, _) - ) -} - -private predicate adjacentVarRead(Definition def, PreBasicBlock bb1, int i1, AssignableRead read) { - exists(int rankix, int i2 | - rankix = ssaDefRank(def, bb1, i1) and - rankix + 1 = ssaDefRank(def, bb1, i2) and - readAt(bb1, i2, read, _) - ) - or - ssaDefRank(def, bb1, i1) = maxSsaRefRank(bb1, def.getAssignable()) and - varBlockReachesRead(def, bb1, read) -} - -predicate firstReadSameVar(Definition def, AssignableRead read) { - exists(PreBasicBlock bb1, int i1 | - defAt(bb1, i1, def, _) and - adjacentVarRead(def, bb1, i1, read) - ) -} - -predicate adjacentReadPairSameVar(AssignableRead read1, AssignableRead read2) { - exists(Definition def, PreBasicBlock bb1, int i1 | - readAt(bb1, i1, read1, _) and - adjacentVarRead(def, bb1, i1, read2) - ) } diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/internal/Splitting.qll b/csharp/ql/src/semmle/code/csharp/controlflow/internal/Splitting.qll index c69f313c17b..0947059d873 100644 --- a/csharp/ql/src/semmle/code/csharp/controlflow/internal/Splitting.qll +++ b/csharp/ql/src/semmle/code/csharp/controlflow/internal/Splitting.qll @@ -6,10 +6,10 @@ import csharp private import Completion -private import PreSsa as PreSsa private import ControlFlowGraphImpl private import SuccessorTypes private import semmle.code.csharp.controlflow.ControlFlowGraph::ControlFlow +private import semmle.code.csharp.controlflow.internal.PreSsa /** The maximum number of splits allowed for a given node. */ private int maxSplits() { result = 5 } @@ -1143,9 +1143,7 @@ module BooleanSplitting { * another condition that reads the same SSA variable. */ private predicate firstDefCondition(ConditionBlock cb) { - exists(AssignableRead read | this.defConditionReachableFromRead(cb, read) | - PreSsa::firstReadSameVar(def, read) - ) + this.defConditionReachableFromRead(cb, def.getAFirstRead()) } override predicate correlatesConditions(ConditionBlock cb1, ConditionBlock cb2, boolean inverted) { @@ -1168,9 +1166,9 @@ module BooleanSplitting { ) } - override Callable getEnclosingCallable() { result = def.getCallable() } + override Callable getEnclosingCallable() { result = def.getBasicBlock().getEnclosingCallable() } - override string toString() { result = def.getAssignable().toString() } + override string toString() { result = def.getSourceVariable().toString() } override Location getLocation() { result = def.getLocation() } } @@ -1321,7 +1319,6 @@ module BooleanSplitting { module LoopSplitting { private import semmle.code.csharp.controlflow.Guards as Guards private import PreBasicBlocks - private import PreSsa /** Holds if `ce` is guarded by a (non-)empty check, as specified by `v`. */ private predicate emptinessGuarded( diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/internal/pressa/SsaImplCommon.qll b/csharp/ql/src/semmle/code/csharp/controlflow/internal/pressa/SsaImplCommon.qll new file mode 100644 index 00000000000..be01c05b8fa --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/controlflow/internal/pressa/SsaImplCommon.qll @@ -0,0 +1,619 @@ +/** + * Provides a language-independant implementation of static single assignment + * (SSA) form. + */ + +private import SsaImplSpecific + +private BasicBlock getABasicBlockPredecessor(BasicBlock bb) { getABasicBlockSuccessor(result) = bb } + +/** + * Liveness analysis (based on source variables) to restrict the size of the + * SSA representation. + */ +private module Liveness { + /** + * A classification of variable references into reads (of a given kind) and + * (certain or uncertain) writes. + */ + private newtype TRefKind = + Read(boolean certain) { certain in [false, true] } or + Write(boolean certain) { certain in [false, true] } + + private class RefKind extends TRefKind { + string toString() { + exists(boolean certain | this = Read(certain) and result = "read (" + certain + ")") + or + exists(boolean certain | this = Write(certain) and result = "write (" + certain + ")") + } + + int getOrder() { + this = Read(_) and + result = 0 + or + this = Write(_) and + result = 1 + } + } + + /** + * Holds if the `i`th node of basic block `bb` is a reference to `v` of kind `k`. + */ + private predicate ref(BasicBlock bb, int i, SourceVariable v, RefKind k) { + exists(boolean certain | variableRead(bb, i, v, certain) | k = Read(certain)) + or + exists(boolean certain | variableWrite(bb, i, v, certain) | k = Write(certain)) + } + + private newtype OrderedRefIndex = + MkOrderedRefIndex(int i, int tag) { + exists(RefKind rk | ref(_, i, _, rk) | tag = rk.getOrder()) + } + + private OrderedRefIndex refOrd(BasicBlock bb, int i, SourceVariable v, RefKind k, int ord) { + ref(bb, i, v, k) and + result = MkOrderedRefIndex(i, ord) and + ord = k.getOrder() + } + + /** + * Gets the (1-based) rank of the reference to `v` at the `i`th node of + * basic block `bb`, which has the given reference kind `k`. + * + * Reads are considered before writes when they happen at the same index. + */ + private int refRank(BasicBlock bb, int i, SourceVariable v, RefKind k) { + refOrd(bb, i, v, k, _) = + rank[result](int j, int ord, OrderedRefIndex res | + res = refOrd(bb, j, v, _, ord) + | + res order by j, ord + ) + } + + private int maxRefRank(BasicBlock bb, SourceVariable v) { + result = refRank(bb, _, v, _) and + not result + 1 = refRank(bb, _, v, _) + } + + /** + * Gets the (1-based) rank of the first reference to `v` inside basic block `bb` + * that is either a read or a certain write. + */ + private int firstReadOrCertainWrite(BasicBlock bb, SourceVariable v) { + result = + min(int r, RefKind k | + r = refRank(bb, _, v, k) and + k != Write(false) + | + r + ) + } + + /** + * Holds if source variable `v` is live at the beginning of basic block `bb`. + */ + predicate liveAtEntry(BasicBlock bb, SourceVariable v) { + // The first read or certain write to `v` inside `bb` is a read + refRank(bb, _, v, Read(_)) = firstReadOrCertainWrite(bb, v) + or + // There is no certain write to `v` inside `bb`, but `v` is live at entry + // to a successor basic block of `bb` + not exists(firstReadOrCertainWrite(bb, v)) and + liveAtExit(bb, v) + } + + /** + * Holds if source variable `v` is live at the end of basic block `bb`. + */ + predicate liveAtExit(BasicBlock bb, SourceVariable v) { + liveAtEntry(getABasicBlockSuccessor(bb), v) + } + + /** + * Holds if variable `v` is live in basic block `bb` at index `i`. + * The rank of `i` is `rnk` as defined by `refRank()`. + */ + private predicate liveAtRank(BasicBlock bb, int i, SourceVariable v, int rnk) { + exists(RefKind kind | rnk = refRank(bb, i, v, kind) | + rnk = maxRefRank(bb, v) and + liveAtExit(bb, v) + or + ref(bb, i, v, kind) and + kind = Read(_) + or + exists(RefKind nextKind | + liveAtRank(bb, _, v, rnk + 1) and + rnk + 1 = refRank(bb, _, v, nextKind) and + nextKind != Write(true) + ) + ) + } + + /** + * Holds if variable `v` is live after the (certain or uncertain) write at + * index `i` inside basic block `bb`. + */ + predicate liveAfterWrite(BasicBlock bb, int i, SourceVariable v) { + exists(int rnk | rnk = refRank(bb, i, v, Write(_)) | liveAtRank(bb, i, v, rnk)) + } +} + +private import Liveness + +/** Holds if `bb1` strictly dominates `bb2`. */ +private predicate strictlyDominates(BasicBlock bb1, BasicBlock bb2) { + bb1 = getImmediateBasicBlockDominator+(bb2) +} + +/** Holds if `bb1` dominates a predecessor of `bb2`. */ +private predicate dominatesPredecessor(BasicBlock bb1, BasicBlock bb2) { + exists(BasicBlock pred | pred = getABasicBlockPredecessor(bb2) | + bb1 = pred + or + strictlyDominates(bb1, pred) + ) +} + +/** Holds if `df` is in the dominance frontier of `bb`. */ +private predicate inDominanceFrontier(BasicBlock bb, BasicBlock df) { + dominatesPredecessor(bb, df) and + not strictlyDominates(bb, df) +} + +/** + * Holds if `bb` is in the dominance frontier of a block containing a + * definition of `v`. + */ +pragma[noinline] +private predicate inDefDominanceFrontier(BasicBlock bb, SourceVariable v) { + exists(BasicBlock defbb, Definition def | + def.definesAt(v, defbb, _) and + inDominanceFrontier(defbb, bb) + ) +} + +cached +newtype TDefinition = + TWriteDef(SourceVariable v, BasicBlock bb, int i) { + variableWrite(bb, i, v, _) and + liveAfterWrite(bb, i, v) + } or + TPhiNode(SourceVariable v, BasicBlock bb) { + inDefDominanceFrontier(bb, v) and + liveAtEntry(bb, v) + } + +private module SsaDefReaches { + newtype TSsaRefKind = + SsaRead() or + SsaDef() + + /** + * A classification of SSA variable references into reads and definitions. + */ + class SsaRefKind extends TSsaRefKind { + string toString() { + this = SsaRead() and + result = "SsaRead" + or + this = SsaDef() and + result = "SsaDef" + } + + int getOrder() { + this = SsaRead() and + result = 0 + or + this = SsaDef() and + result = 1 + } + } + + /** + * Holds if the `i`th node of basic block `bb` is a reference to `v`, + * either a read (when `k` is `SsaRead()`) or an SSA definition (when `k` + * is `SsaDef()`). + * + * Unlike `Liveness::ref`, this includes `phi` nodes. + */ + predicate ssaRef(BasicBlock bb, int i, SourceVariable v, SsaRefKind k) { + variableRead(bb, i, v, _) and + k = SsaRead() + or + exists(Definition def | def.definesAt(v, bb, i)) and + k = SsaDef() + } + + private newtype OrderedSsaRefIndex = + MkOrderedSsaRefIndex(int i, SsaRefKind k) { ssaRef(_, i, _, k) } + + private OrderedSsaRefIndex ssaRefOrd(BasicBlock bb, int i, SourceVariable v, SsaRefKind k, int ord) { + ssaRef(bb, i, v, k) and + result = MkOrderedSsaRefIndex(i, k) and + ord = k.getOrder() + } + + /** + * Gets the (1-based) rank of the reference to `v` at the `i`th node of basic + * block `bb`, which has the given reference kind `k`. + * + * For example, if `bb` is a basic block with a phi node for `v` (considered + * to be at index -1), reads `v` at node 2, and defines it at node 5, we have: + * + * ```ql + * ssaRefRank(bb, -1, v, SsaDef()) = 1 // phi node + * ssaRefRank(bb, 2, v, Read()) = 2 // read at node 2 + * ssaRefRank(bb, 5, v, SsaDef()) = 3 // definition at node 5 + * ``` + * + * Reads are considered before writes when they happen at the same index. + */ + int ssaRefRank(BasicBlock bb, int i, SourceVariable v, SsaRefKind k) { + ssaRefOrd(bb, i, v, k, _) = + rank[result](int j, int ord, OrderedSsaRefIndex res | + res = ssaRefOrd(bb, j, v, _, ord) + | + res order by j, ord + ) + } + + int maxSsaRefRank(BasicBlock bb, SourceVariable v) { + result = ssaRefRank(bb, _, v, _) and + not result + 1 = ssaRefRank(bb, _, v, _) + } + + /** + * Holds if the SSA definition `def` reaches rank index `rnk` in its own + * basic block `bb`. + */ + predicate ssaDefReachesRank(BasicBlock bb, Definition def, int rnk, SourceVariable v) { + exists(int i | + rnk = ssaRefRank(bb, i, v, SsaDef()) and + def.definesAt(v, bb, i) + ) + or + ssaDefReachesRank(bb, def, rnk - 1, v) and + rnk = ssaRefRank(bb, _, v, SsaRead()) + } + + /** + * Holds if the SSA definition of `v` at `def` reaches index `i` in the same + * basic block `bb`, without crossing another SSA definition of `v`. + */ + predicate ssaDefReachesReadWithinBlock(SourceVariable v, Definition def, BasicBlock bb, int i) { + exists(int rnk | + ssaDefReachesRank(bb, def, rnk, v) and + rnk = ssaRefRank(bb, i, v, SsaRead()) and + variableRead(bb, i, v, _) + ) + } + + /** + * Holds if the SSA definition of `v` at `def` reaches uncertain SSA definition + * `redef` in the same basic block, without crossing another SSA definition of `v`. + */ + predicate ssaDefReachesUncertainDefWithinBlock( + SourceVariable v, Definition def, UncertainWriteDefinition redef + ) { + exists(BasicBlock bb, int rnk, int i | + ssaDefReachesRank(bb, def, rnk, v) and + rnk = ssaRefRank(bb, i, v, SsaDef()) - 1 and + redef.definesAt(v, bb, i) + ) + } + + /** + * Same as `ssaRefRank()`, but restricted to a particular SSA definition `def`. + */ + int ssaDefRank(Definition def, SourceVariable v, BasicBlock bb, int i, SsaRefKind k) { + v = def.getSourceVariable() and + result = ssaRefRank(bb, i, v, k) and + ( + ssaDefReachesRead(_, def, bb, i) + or + def.definesAt(_, bb, i) + ) + } + + predicate defOccursInBlock(Definition def, BasicBlock bb, SourceVariable v) { + exists(ssaDefRank(def, v, bb, _, _)) + } + + pragma[noinline] + private BasicBlock getAMaybeLiveSuccessor(Definition def, BasicBlock bb) { + result = getABasicBlockSuccessor(bb) and + not defOccursInBlock(_, bb, def.getSourceVariable()) and + ssaDefReachesEndOfBlock(bb, def, _) + } + + /** + * Holds if `def` is accessed in basic block `bb1` (either a read or a write), + * `bb2` is a transitive successor of `bb1`, `def` is live at the end of `bb1`, + * and the underlying variable for `def` is neither read nor written in any block + * on the path between `bb1` and `bb2`. + */ + predicate varBlockReaches(Definition def, BasicBlock bb1, BasicBlock bb2) { + defOccursInBlock(def, bb1, _) and + bb2 = getABasicBlockSuccessor(bb1) + or + exists(BasicBlock mid | varBlockReaches(def, bb1, mid) | bb2 = getAMaybeLiveSuccessor(def, mid)) + } + + /** + * Holds if `def` is accessed in basic block `bb1` (either a read or a write), + * `def` is read at index `i2` in basic block `bb2`, `bb2` is in a transitive + * successor block of `bb1`, and `def` is neither read nor written in any block + * on a path between `bb1` and `bb2`. + */ + predicate defAdjacentRead(Definition def, BasicBlock bb1, BasicBlock bb2, int i2) { + varBlockReaches(def, bb1, bb2) and + ssaRefRank(bb2, i2, def.getSourceVariable(), SsaRead()) = 1 and + variableRead(bb2, i2, _, _) + } +} + +private import SsaDefReaches + +pragma[noinline] +private predicate ssaDefReachesEndOfBlockRec(BasicBlock bb, Definition def, SourceVariable v) { + exists(BasicBlock idom | ssaDefReachesEndOfBlock(idom, def, v) | + // The construction of SSA form ensures that each read of a variable is + // dominated by its definition. An SSA definition therefore reaches a + // control flow node if it is the _closest_ SSA definition that dominates + // the node. If two definitions dominate a node then one must dominate the + // other, so therefore the definition of _closest_ is given by the dominator + // tree. Thus, reaching definitions can be calculated in terms of dominance. + idom = getImmediateBasicBlockDominator(bb) + ) +} + +/** + * NB: If this predicate is exposed, it should be cached. + * + * Holds if the SSA definition of `v` at `def` reaches the end of basic + * block `bb`, at which point it is still live, without crossing another + * SSA definition of `v`. + */ +pragma[nomagic] +predicate ssaDefReachesEndOfBlock(BasicBlock bb, Definition def, SourceVariable v) { + exists(int last | last = maxSsaRefRank(bb, v) | + ssaDefReachesRank(bb, def, last, v) and + liveAtExit(bb, v) + ) + or + ssaDefReachesEndOfBlockRec(bb, def, v) and + liveAtExit(bb, v) and + not ssaRef(bb, _, v, SsaDef()) +} + +/** + * NB: If this predicate is exposed, it should be cached. + * + * Holds if `inp` is an input to the phi node `phi` along the edge originating in `bb`. + */ +pragma[nomagic] +predicate phiHasInputFromBlock(PhiNode phi, Definition inp, BasicBlock bb) { + exists(SourceVariable v, BasicBlock bbDef | + phi.definesAt(v, bbDef, _) and + getABasicBlockPredecessor(bbDef) = bb and + ssaDefReachesEndOfBlock(bb, inp, v) + ) +} + +/** + * NB: If this predicate is exposed, it should be cached. + * + * Holds if the SSA definition of `v` at `def` reaches a read at index `i` in + * basic block `bb`, without crossing another SSA definition of `v`. The read + * is of kind `rk`. + */ +pragma[nomagic] +predicate ssaDefReachesRead(SourceVariable v, Definition def, BasicBlock bb, int i) { + ssaDefReachesReadWithinBlock(v, def, bb, i) + or + variableRead(bb, i, v, _) and + ssaDefReachesEndOfBlock(getABasicBlockPredecessor(bb), def, v) and + not ssaDefReachesReadWithinBlock(v, _, bb, i) +} + +/** + * NB: If this predicate is exposed, it should be cached. + * + * Holds if `def` is accessed at index `i1` in basic block `bb1` (either a read + * or a write), `def` is read at index `i2` in basic block `bb2`, and there is a + * path between them without any read of `def`. + */ +pragma[nomagic] +predicate adjacentDefRead(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) { + exists(int rnk | + rnk = ssaDefRank(def, _, bb1, i1, _) and + rnk + 1 = ssaDefRank(def, _, bb1, i2, SsaRead()) and + variableRead(bb1, i2, _, _) and + bb2 = bb1 + ) + or + exists(SourceVariable v | ssaDefRank(def, v, bb1, i1, _) = maxSsaRefRank(bb1, v)) and + defAdjacentRead(def, bb1, bb2, i2) +} + +private predicate adjacentDefReachesRead( + Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2 +) { + adjacentDefRead(def, bb1, i1, bb2, i2) and + exists(SourceVariable v | v = def.getSourceVariable() | + ssaRef(bb1, i1, v, SsaDef()) + or + variableRead(bb1, i1, v, true) + ) + or + exists(BasicBlock bb3, int i3 | + adjacentDefReachesRead(def, bb1, i1, bb3, i3) and + variableRead(bb3, i3, _, false) and + adjacentDefRead(def, bb3, i3, bb2, i2) + ) +} + +/** + * NB: If this predicate is exposed, it should be cached. + * + * Same as `adjacentDefRead`, but ignores uncertain reads. + */ +pragma[nomagic] +predicate adjacentDefNoUncertainReads(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) { + adjacentDefReachesRead(def, bb1, i1, bb2, i2) and + variableRead(bb2, i2, _, true) +} + +/** + * NB: If this predicate is exposed, it should be cached. + * + * Holds if the node at index `i` in `bb` is a last reference to SSA definition + * `def`. The reference is last because it can reach another write `next`, + * without passing through another read or write. + */ +pragma[nomagic] +predicate lastRefRedef(Definition def, BasicBlock bb, int i, Definition next) { + exists(int rnk, SourceVariable v, int j | rnk = ssaDefRank(def, v, bb, i, _) | + // Next reference to `v` inside `bb` is a write + next.definesAt(v, bb, j) and + rnk + 1 = ssaRefRank(bb, j, v, SsaDef()) + or + // Can reach a write using one or more steps + rnk = maxSsaRefRank(bb, v) and + exists(BasicBlock bb2 | + varBlockReaches(def, bb, bb2) and + next.definesAt(v, bb2, j) and + 1 = ssaRefRank(bb2, j, v, SsaDef()) + ) + ) +} + +/** + * NB: If this predicate is exposed, it should be cached. + * + * Holds if `inp` is an immediately preceding definition of uncertain definition + * `def`. Since `def` is uncertain, the value from the preceding definition might + * still be valid. + */ +pragma[nomagic] +predicate uncertainWriteDefinitionInput(UncertainWriteDefinition def, Definition inp) { + lastRefRedef(inp, _, _, def) +} + +private predicate adjacentDefReachesUncertainRead( + Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2 +) { + adjacentDefReachesRead(def, bb1, i1, bb2, i2) and + variableRead(bb2, i2, _, false) +} + +/** + * NB: If this predicate is exposed, it should be cached. + * + * Same as `lastRefRedef`, but ignores uncertain reads. + */ +pragma[nomagic] +predicate lastRefRedefNoUncertainReads(Definition def, BasicBlock bb, int i, Definition next) { + lastRefRedef(def, bb, i, next) and + not variableRead(bb, i, def.getSourceVariable(), false) + or + exists(BasicBlock bb0, int i0 | + lastRefRedef(def, bb0, i0, next) and + adjacentDefReachesUncertainRead(def, bb, i, bb0, i0) + ) +} + +/** + * NB: If this predicate is exposed, it should be cached. + * + * Holds if the node at index `i` in `bb` is a last reference to SSA + * definition `def`. + * + * That is, the node can reach the end of the enclosing callable, or another + * SSA definition for the underlying source variable, without passing through + * another read. + */ +pragma[nomagic] +predicate lastRef(Definition def, BasicBlock bb, int i) { + lastRefRedef(def, bb, i, _) + or + exists(SourceVariable v | ssaDefRank(def, v, bb, i, _) = maxSsaRefRank(bb, v) | + // Can reach exit directly + bb instanceof ExitBasicBlock + or + // Can reach a block using one or more steps, where `def` is no longer live + exists(BasicBlock bb2 | varBlockReaches(def, bb, bb2) | + not defOccursInBlock(def, bb2, _) and + not ssaDefReachesEndOfBlock(bb2, def, _) + ) + ) +} + +/** + * NB: If this predicate is exposed, it should be cached. + * + * Same as `lastRefRedef`, but ignores uncertain reads. + */ +pragma[nomagic] +predicate lastRefNoUncertainReads(Definition def, BasicBlock bb, int i) { + lastRef(def, bb, i) and + not variableRead(bb, i, def.getSourceVariable(), false) + or + exists(BasicBlock bb0, int i0 | + lastRef(def, bb0, i0) and + adjacentDefReachesUncertainRead(def, bb, i, bb0, i0) + ) +} + +/** A static single assignment (SSA) definition. */ +class Definition extends TDefinition { + /** Gets the source variable underlying this SSA definition. */ + SourceVariable getSourceVariable() { this.definesAt(result, _, _) } + + /** + * Holds if this SSA definition defines `v` at index `i` in basic block `bb`. + * Phi nodes are considered to be at index `-1`, while normal variable writes + * are at the index of the control flow node they wrap. + */ + final predicate definesAt(SourceVariable v, BasicBlock bb, int i) { + this = TWriteDef(v, bb, i) + or + this = TPhiNode(v, bb) and i = -1 + } + + /** Gets the basic block to which this SSA definition belongs. */ + final BasicBlock getBasicBlock() { this.definesAt(_, result, _) } + + /** Gets a textual representation of this SSA definition. */ + string toString() { none() } +} + +/** An SSA definition that corresponds to a write. */ +class WriteDefinition extends Definition, TWriteDef { + private SourceVariable v; + private BasicBlock bb; + private int i; + + WriteDefinition() { this = TWriteDef(v, bb, i) } + + override string toString() { result = "WriteDef" } +} + +/** A phi node. */ +class PhiNode extends Definition, TPhiNode { + override string toString() { result = "Phi" } +} + +/** + * An SSA definition that represents an uncertain update of the underlying + * source variable. + */ +class UncertainWriteDefinition extends WriteDefinition { + UncertainWriteDefinition() { + exists(SourceVariable v, BasicBlock bb, int i | + this.definesAt(v, bb, i) and + variableWrite(bb, i, v, false) + ) + } +} diff --git a/csharp/ql/src/semmle/code/csharp/controlflow/internal/pressa/SsaImplSpecific.qll b/csharp/ql/src/semmle/code/csharp/controlflow/internal/pressa/SsaImplSpecific.qll new file mode 100644 index 00000000000..610e808a640 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/controlflow/internal/pressa/SsaImplSpecific.qll @@ -0,0 +1,106 @@ +/** Provides the C# specific parameters for `SsaImplCommon.qll`. */ + +private import csharp +private import AssignableDefinitions +private import semmle.code.csharp.controlflow.internal.PreBasicBlocks as PreBasicBlocks +private import semmle.code.csharp.controlflow.internal.ControlFlowGraphImpl + +class BasicBlock = PreBasicBlocks::PreBasicBlock; + +BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result.immediatelyDominates(bb) } + +BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() } + +class ExitBasicBlock extends BasicBlock { + ExitBasicBlock() { scopeLast(_, this.getLastElement(), _) } +} + +pragma[noinline] +private predicate assignableNoCapturing(Assignable a, Callable c) { + exists(AssignableAccess aa | aa.getTarget() = a | c = aa.getEnclosingCallable()) and + forall(AssignableDefinition def | def.getTarget() = a | + c = def.getEnclosingCallable() + or + def.getEnclosingCallable() instanceof Constructor + ) +} + +pragma[noinline] +private predicate assignableNoComplexQualifiers(Assignable a) { + forall(QualifiableExpr qe | qe.(AssignableAccess).getTarget() = a | qe.targetIsThisInstance()) +} + +/** + * A simple assignable. Either a local scope variable or a field/property + * that behaves like a local scope variable. + */ +class SourceVariable extends Assignable { + private Callable c; + + SourceVariable() { + ( + this instanceof LocalScopeVariable + or + this instanceof Field + or + this = any(TrivialProperty tp | not tp.isOverridableOrImplementable()) + ) and + assignableNoCapturing(this, c) and + assignableNoComplexQualifiers(this) + } + + /** Gets a callable in which this simple assignable can be analyzed. */ + Callable getACallable() { result = c } +} + +predicate definitionAt(AssignableDefinition def, BasicBlock bb, int i, SourceVariable v) { + bb.getElement(i) = def.getExpr() and + v = def.getTarget() and + // In cases like `(x, x) = (0, 1)`, we discard the first (dead) definition of `x` + not exists(TupleAssignmentDefinition first, TupleAssignmentDefinition second | first = def | + second.getAssignment() = first.getAssignment() and + second.getEvaluationOrder() > first.getEvaluationOrder() and + second.getTarget() = v + ) + or + def.(ImplicitParameterDefinition).getParameter() = v and + exists(Callable c | v = c.getAParameter() | + scopeFirst(c, bb) and + i = -1 + ) +} + +predicate implicitEntryDef(Callable c, BasicBlock bb, SourceVariable v) { + not v instanceof LocalScopeVariable and + c = v.getACallable() and + scopeFirst(c, bb) +} + +predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) { + exists(AssignableDefinition def | + definitionAt(def, bb, i, v) and + if def.getTargetAccess().isRefArgument() then certain = false else certain = true + ) + or + exists(Callable c | + implicitEntryDef(c, bb, v) and + i = -1 and + certain = true + ) +} + +predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) { + exists(AssignableRead read | + read = bb.getElement(i) and + read.getTarget() = v and + certain = true + ) + or + v = + any(LocalScopeVariable lsv | + lsv.getCallable() = bb.(ExitBasicBlock).getEnclosingCallable() and + i = bb.length() and + (lsv.isRef() or v.(Parameter).isOut()) and + certain = false + ) +} diff --git a/csharp/ql/test/library-tests/dataflow/ssa/PreSsaConsistency.ql b/csharp/ql/test/library-tests/dataflow/ssa/PreSsaConsistency.ql index 9345525f486..849500904a0 100644 --- a/csharp/ql/test/library-tests/dataflow/ssa/PreSsaConsistency.ql +++ b/csharp/ql/test/library-tests/dataflow/ssa/PreSsaConsistency.ql @@ -1,5 +1,5 @@ import csharp -import semmle.code.csharp.controlflow.internal.PreSsa as PreSsa +import semmle.code.csharp.controlflow.internal.PreSsa import semmle.code.csharp.controlflow.internal.ControlFlowGraphImpl import semmle.code.csharp.dataflow.internal.SsaImpl as SsaImpl @@ -7,16 +7,14 @@ class CallableWithSplitting extends Callable { CallableWithSplitting() { this = any(SplitControlFlowElement e).getEnclosingCallable() } } -query predicate defReadInconsistency( - AssignableRead ar, Expr e, PreSsa::SimpleAssignable a, boolean b -) { +query predicate defReadInconsistency(AssignableRead ar, Expr e, PreSsa::SourceVariable v, boolean b) { // Exclude definitions in callables with CFG splitting, as SSA definitions may be // very different from pre-SSA definitions not ar.getEnclosingCallable() instanceof CallableWithSplitting and exists(AssignableDefinition def | e = def.getExpr() | b = true and - exists(PreSsa::Definition ssaDef | ssaDef.getAssignable() = a | - PreSsa::firstReadSameVar(ssaDef, ar) and + exists(PreSsa::Definition ssaDef | ssaDef.getSourceVariable() = v | + ar = ssaDef.getAFirstRead() and ssaDef.getDefinition() = def and not exists(Ssa::ExplicitDefinition edef | edef.getADefinition() = def and @@ -28,9 +26,9 @@ query predicate defReadInconsistency( exists(Ssa::ExplicitDefinition edef | edef.getADefinition() = def and edef.getAFirstRead() = ar and - def.getTarget() = a and + def.getTarget() = v and not exists(PreSsa::Definition ssaDef | - PreSsa::firstReadSameVar(ssaDef, ar) and + ar = ssaDef.getAFirstRead() and ssaDef.getDefinition() = def ) ) @@ -38,21 +36,21 @@ query predicate defReadInconsistency( } query predicate readReadInconsistency( - LocalScopeVariableRead read1, LocalScopeVariableRead read2, PreSsa::SimpleAssignable a, boolean b + LocalScopeVariableRead read1, LocalScopeVariableRead read2, PreSsa::SourceVariable v, boolean b ) { // Exclude definitions in callables with CFG splitting, as SSA definitions may be // very different from pre-SSA definitions not read1.getEnclosingCallable() instanceof CallableWithSplitting and ( b = true and - a = read1.getTarget() and + v = read1.getTarget() and PreSsa::adjacentReadPairSameVar(read1, read2) and not SsaImpl::adjacentReadPairSameVar(_, read1.getAControlFlowNode(), read2.getAControlFlowNode()) or b = false and - a = read1.getTarget() and + v = read1.getTarget() and SsaImpl::adjacentReadPairSameVar(_, read1.getAControlFlowNode(), read2.getAControlFlowNode()) and - read1.getTarget() instanceof PreSsa::SimpleAssignable and + read1.getTarget() instanceof PreSsa::SourceVariable and not PreSsa::adjacentReadPairSameVar(read1, read2) and // Exclude split CFG elements because SSA may be more precise than pre-SSA // in those cases @@ -61,17 +59,15 @@ query predicate readReadInconsistency( ) } -query predicate phiInconsistency( - ControlFlowElement cfe, Expr e, PreSsa::SimpleAssignable a, boolean b -) { +query predicate phiInconsistency(ControlFlowElement cfe, Expr e, PreSsa::SourceVariable v, boolean b) { // Exclude definitions in callables with CFG splitting, as SSA definitions may be // very different from pre-SSA definitions not cfe.getEnclosingCallable() instanceof CallableWithSplitting and exists(AssignableDefinition adef | e = adef.getExpr() | b = true and - exists(PreSsa::Definition def | a = def.getAssignable() | - adef = def.getAPhiInput+().getDefinition() and - cfe = def.getBasicBlock().getFirstElement() and + exists(PreSsa::PhiNode prePhi | v = prePhi.getSourceVariable() | + adef = prePhi.getAnInput+().getDefinition() and + cfe = prePhi.getBasicBlock().getFirstElement() and not exists(Ssa::PhiNode phi, ControlFlow::BasicBlock bb, Ssa::ExplicitDefinition edef | edef = phi.getAnUltimateDefinition() | @@ -83,15 +79,15 @@ query predicate phiInconsistency( or b = false and exists(Ssa::PhiNode phi, ControlFlow::BasicBlock bb, Ssa::ExplicitDefinition edef | - a = phi.getSourceVariable().getAssignable() + v = phi.getSourceVariable().getAssignable() | edef = phi.getAnUltimateDefinition() and edef.getADefinition() = adef and phi.definesAt(_, bb, _) and cfe = bb.getFirstNode().getElement() and - not exists(PreSsa::Definition def | - adef = def.getAPhiInput+().getDefinition() and - cfe = def.getBasicBlock().getFirstElement() + not exists(PreSsa::PhiNode prePhi | + adef = prePhi.getAnInput+().getDefinition() and + cfe = prePhi.getBasicBlock().getFirstElement() ) ) ) From bed66203c175cb77066f861ad432a58bbfe249da Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Fri, 5 Feb 2021 12:32:42 +0100 Subject: [PATCH 017/142] C#: Use shared SSA implementation for `BaseSsa` --- config/identical-files.json | 3 +- .../code/csharp/dataflow/internal/BaseSSA.qll | 144 +--- .../code/csharp/dataflow/internal/Steps.qll | 5 +- .../internal/basessa/SsaImplCommon.qll | 619 ++++++++++++++++++ .../internal/basessa/SsaImplSpecific.qll | 51 ++ .../semmle/code/csharp/dispatch/Dispatch.qll | 9 +- .../dataflow/ssa/BaseSsaConsistency.ql | 6 +- 7 files changed, 718 insertions(+), 119 deletions(-) create mode 100644 csharp/ql/src/semmle/code/csharp/dataflow/internal/basessa/SsaImplCommon.qll create mode 100644 csharp/ql/src/semmle/code/csharp/dataflow/internal/basessa/SsaImplSpecific.qll diff --git a/config/identical-files.json b/config/identical-files.json index 62c48d1fcd8..2109588fb36 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -428,6 +428,7 @@ ], "SSA C#": [ "csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImplCommon.qll", - "csharp/ql/src/semmle/code/csharp/controlflow/internal/pressa/SsaImplCommon.qll" + "csharp/ql/src/semmle/code/csharp/controlflow/internal/pressa/SsaImplCommon.qll", + "csharp/ql/src/semmle/code/csharp/dataflow/internal/basessa/SsaImplCommon.qll" ] } \ No newline at end of file diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/BaseSSA.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/BaseSSA.qll index 0a1c022513d..281523a2fbd 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/BaseSSA.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/BaseSSA.qll @@ -1,125 +1,43 @@ import csharp /** - * INTERNAL: Do not use. - * * Provides a simple SSA implementation for local scope variables. */ module BaseSsa { - private import ControlFlow - private import AssignableDefinitions + import basessa.SsaImplSpecific + private import basessa.SsaImplCommon as SsaImpl - pragma[noinline] - Callable getAnAssigningCallable(LocalScopeVariable v) { - result = any(AssignableDefinition def | def.getTarget() = v).getEnclosingCallable() + class Definition extends SsaImpl::Definition { + final AssignableRead getARead() { + exists(BasicBlock bb, int i | + SsaImpl::ssaDefReachesRead(_, this, bb, i) and + result.getAControlFlowNode() = bb.getNode(i) + ) + } + + final AssignableDefinition getDefinition() { + exists(BasicBlock bb, int i, SourceVariable v | + this.definesAt(v, bb, i) and + definitionAt(result, bb, i, v) + ) + } + + private Definition getAPhiInputOrPriorDefinition() { + result = this.(PhiNode).getAnInput() or + SsaImpl::uncertainWriteDefinitionInput(this, result) + } + + final Definition getAnUltimateDefinition() { + result = this.getAPhiInputOrPriorDefinition*() and + not result instanceof PhiNode + } + + Location getLocation() { result = this.getDefinition().getLocation() } } - private class SimpleLocalScopeVariable extends LocalScopeVariable { - SimpleLocalScopeVariable() { not getAnAssigningCallable(this) != getAnAssigningCallable(this) } - } + class PhiNode extends SsaImpl::PhiNode, Definition { + override Location getLocation() { result = this.getBasicBlock().getLocation() } - /** - * Holds if the `i`th node of basic block `bb` is assignable definition `def`, - * targeting local scope variable `v`. - */ - private predicate defAt(BasicBlock bb, int i, AssignableDefinition def, SimpleLocalScopeVariable v) { - bb.getNode(i) = def.getAControlFlowNode() and - v = def.getTarget() and - // In cases like `(x, x) = (0, 1)`, we discard the first (dead) definition of `x` - not exists(TupleAssignmentDefinition first, TupleAssignmentDefinition second | first = def | - second.getAssignment() = first.getAssignment() and - second.getEvaluationOrder() > first.getEvaluationOrder() and - second.getTarget() = v - ) - } - - /** - * Holds if basic block `bb` would need to start with a phi node for local scope - * variable `v` in an SSA representation. - */ - private predicate needsPhiNode(BasicBlock bb, SimpleLocalScopeVariable v) { - exists(BasicBlock def | def.inDominanceFrontier(bb) | - defAt(def, _, _, v) or - needsPhiNode(def, v) - ) - } - - private newtype SsaRefKind = - SsaRead() or - SsaDef() - - /** - * Holds if the `i`th node of basic block `bb` is a reference to `v`, - * either a read (when `k` is `SsaRead()`) or a write including phi nodes - * (when `k` is `SsaDef()`). - */ - private predicate ssaRef(BasicBlock bb, int i, SimpleLocalScopeVariable v, SsaRefKind k) { - bb.getNode(i).getElement() = v.getAnAccess().(VariableRead) and - k = SsaRead() - or - defAt(bb, i, _, v) and - k = SsaDef() - or - needsPhiNode(bb, v) and - i = -1 and - k = SsaDef() - } - - /** - * Gets the (1-based) rank of the reference to `v` at the `i`th node of basic - * block `bb`, which has the given reference kind `k`. - */ - private int ssaRefRank(BasicBlock bb, int i, SimpleLocalScopeVariable v, SsaRefKind k) { - i = rank[result](int j | ssaRef(bb, j, v, _)) and - ssaRef(bb, i, v, k) - } - - /** - * Holds if definition `def` of local scope variable `v` inside basic block - * `bb` reaches the reference at rank `rnk`, without passing through another - * definition of `v`, including phi nodes. - */ - private predicate defReachesRank( - BasicBlock bb, AssignableDefinition def, SimpleLocalScopeVariable v, int rnk - ) { - exists(int i | rnk = ssaRefRank(bb, i, v, SsaDef()) | defAt(bb, i, def, v)) - or - defReachesRank(bb, def, v, rnk - 1) and - rnk = ssaRefRank(bb, _, v, SsaRead()) - } - - /** - * Holds if definition `def` of local scope variable `v` reaches the end of - * basic block `bb` without passing through another definition of `v`, including - * phi nodes. - */ - private predicate reachesEndOf(AssignableDefinition def, SimpleLocalScopeVariable v, BasicBlock bb) { - exists(int rnk | - defReachesRank(bb, def, v, rnk) and - rnk = max(ssaRefRank(bb, _, v, _)) - ) - or - exists(BasicBlock mid | - reachesEndOf(def, v, mid) and - not exists(ssaRefRank(bb, _, v, SsaDef())) and - bb = mid.getASuccessor() - ) - } - - /** - * Gets a read of the SSA definition for variable `v` at definition `def`. That is, - * a read that is guaranteed to read the value assigned at definition `def`. - */ - cached - AssignableRead getARead(AssignableDefinition def, SimpleLocalScopeVariable v) { - exists(BasicBlock bb, int i, int rnk | - result.getAControlFlowNode() = bb.getNode(i) and - rnk = ssaRefRank(bb, i, v, SsaRead()) - | - defReachesRank(bb, def, v, rnk) - or - reachesEndOf(def, v, bb.getAPredecessor()) and - not ssaRefRank(bb, _, v, SsaDef()) < rnk - ) + final Definition getAnInput() { SsaImpl::phiHasInputFromBlock(this, result, _) } } } diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/Steps.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/Steps.qll index d29d6b1e10b..54cafff994a 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/Steps.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/Steps.qll @@ -16,7 +16,10 @@ module Steps { * Gets a read that is guaranteed to read the value assigned at definition `def`. */ private AssignableRead getARead(AssignableDefinition def) { - result = BaseSsa::getARead(def, _) + exists(BaseSsa::Definition ssaDef | + ssaDef.getDefinition() = def and + result = ssaDef.getARead() + ) or exists(LocalScopeVariable v | def.getTarget() = v | result = v.getAnAccess() and diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/basessa/SsaImplCommon.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/basessa/SsaImplCommon.qll new file mode 100644 index 00000000000..be01c05b8fa --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/basessa/SsaImplCommon.qll @@ -0,0 +1,619 @@ +/** + * Provides a language-independant implementation of static single assignment + * (SSA) form. + */ + +private import SsaImplSpecific + +private BasicBlock getABasicBlockPredecessor(BasicBlock bb) { getABasicBlockSuccessor(result) = bb } + +/** + * Liveness analysis (based on source variables) to restrict the size of the + * SSA representation. + */ +private module Liveness { + /** + * A classification of variable references into reads (of a given kind) and + * (certain or uncertain) writes. + */ + private newtype TRefKind = + Read(boolean certain) { certain in [false, true] } or + Write(boolean certain) { certain in [false, true] } + + private class RefKind extends TRefKind { + string toString() { + exists(boolean certain | this = Read(certain) and result = "read (" + certain + ")") + or + exists(boolean certain | this = Write(certain) and result = "write (" + certain + ")") + } + + int getOrder() { + this = Read(_) and + result = 0 + or + this = Write(_) and + result = 1 + } + } + + /** + * Holds if the `i`th node of basic block `bb` is a reference to `v` of kind `k`. + */ + private predicate ref(BasicBlock bb, int i, SourceVariable v, RefKind k) { + exists(boolean certain | variableRead(bb, i, v, certain) | k = Read(certain)) + or + exists(boolean certain | variableWrite(bb, i, v, certain) | k = Write(certain)) + } + + private newtype OrderedRefIndex = + MkOrderedRefIndex(int i, int tag) { + exists(RefKind rk | ref(_, i, _, rk) | tag = rk.getOrder()) + } + + private OrderedRefIndex refOrd(BasicBlock bb, int i, SourceVariable v, RefKind k, int ord) { + ref(bb, i, v, k) and + result = MkOrderedRefIndex(i, ord) and + ord = k.getOrder() + } + + /** + * Gets the (1-based) rank of the reference to `v` at the `i`th node of + * basic block `bb`, which has the given reference kind `k`. + * + * Reads are considered before writes when they happen at the same index. + */ + private int refRank(BasicBlock bb, int i, SourceVariable v, RefKind k) { + refOrd(bb, i, v, k, _) = + rank[result](int j, int ord, OrderedRefIndex res | + res = refOrd(bb, j, v, _, ord) + | + res order by j, ord + ) + } + + private int maxRefRank(BasicBlock bb, SourceVariable v) { + result = refRank(bb, _, v, _) and + not result + 1 = refRank(bb, _, v, _) + } + + /** + * Gets the (1-based) rank of the first reference to `v` inside basic block `bb` + * that is either a read or a certain write. + */ + private int firstReadOrCertainWrite(BasicBlock bb, SourceVariable v) { + result = + min(int r, RefKind k | + r = refRank(bb, _, v, k) and + k != Write(false) + | + r + ) + } + + /** + * Holds if source variable `v` is live at the beginning of basic block `bb`. + */ + predicate liveAtEntry(BasicBlock bb, SourceVariable v) { + // The first read or certain write to `v` inside `bb` is a read + refRank(bb, _, v, Read(_)) = firstReadOrCertainWrite(bb, v) + or + // There is no certain write to `v` inside `bb`, but `v` is live at entry + // to a successor basic block of `bb` + not exists(firstReadOrCertainWrite(bb, v)) and + liveAtExit(bb, v) + } + + /** + * Holds if source variable `v` is live at the end of basic block `bb`. + */ + predicate liveAtExit(BasicBlock bb, SourceVariable v) { + liveAtEntry(getABasicBlockSuccessor(bb), v) + } + + /** + * Holds if variable `v` is live in basic block `bb` at index `i`. + * The rank of `i` is `rnk` as defined by `refRank()`. + */ + private predicate liveAtRank(BasicBlock bb, int i, SourceVariable v, int rnk) { + exists(RefKind kind | rnk = refRank(bb, i, v, kind) | + rnk = maxRefRank(bb, v) and + liveAtExit(bb, v) + or + ref(bb, i, v, kind) and + kind = Read(_) + or + exists(RefKind nextKind | + liveAtRank(bb, _, v, rnk + 1) and + rnk + 1 = refRank(bb, _, v, nextKind) and + nextKind != Write(true) + ) + ) + } + + /** + * Holds if variable `v` is live after the (certain or uncertain) write at + * index `i` inside basic block `bb`. + */ + predicate liveAfterWrite(BasicBlock bb, int i, SourceVariable v) { + exists(int rnk | rnk = refRank(bb, i, v, Write(_)) | liveAtRank(bb, i, v, rnk)) + } +} + +private import Liveness + +/** Holds if `bb1` strictly dominates `bb2`. */ +private predicate strictlyDominates(BasicBlock bb1, BasicBlock bb2) { + bb1 = getImmediateBasicBlockDominator+(bb2) +} + +/** Holds if `bb1` dominates a predecessor of `bb2`. */ +private predicate dominatesPredecessor(BasicBlock bb1, BasicBlock bb2) { + exists(BasicBlock pred | pred = getABasicBlockPredecessor(bb2) | + bb1 = pred + or + strictlyDominates(bb1, pred) + ) +} + +/** Holds if `df` is in the dominance frontier of `bb`. */ +private predicate inDominanceFrontier(BasicBlock bb, BasicBlock df) { + dominatesPredecessor(bb, df) and + not strictlyDominates(bb, df) +} + +/** + * Holds if `bb` is in the dominance frontier of a block containing a + * definition of `v`. + */ +pragma[noinline] +private predicate inDefDominanceFrontier(BasicBlock bb, SourceVariable v) { + exists(BasicBlock defbb, Definition def | + def.definesAt(v, defbb, _) and + inDominanceFrontier(defbb, bb) + ) +} + +cached +newtype TDefinition = + TWriteDef(SourceVariable v, BasicBlock bb, int i) { + variableWrite(bb, i, v, _) and + liveAfterWrite(bb, i, v) + } or + TPhiNode(SourceVariable v, BasicBlock bb) { + inDefDominanceFrontier(bb, v) and + liveAtEntry(bb, v) + } + +private module SsaDefReaches { + newtype TSsaRefKind = + SsaRead() or + SsaDef() + + /** + * A classification of SSA variable references into reads and definitions. + */ + class SsaRefKind extends TSsaRefKind { + string toString() { + this = SsaRead() and + result = "SsaRead" + or + this = SsaDef() and + result = "SsaDef" + } + + int getOrder() { + this = SsaRead() and + result = 0 + or + this = SsaDef() and + result = 1 + } + } + + /** + * Holds if the `i`th node of basic block `bb` is a reference to `v`, + * either a read (when `k` is `SsaRead()`) or an SSA definition (when `k` + * is `SsaDef()`). + * + * Unlike `Liveness::ref`, this includes `phi` nodes. + */ + predicate ssaRef(BasicBlock bb, int i, SourceVariable v, SsaRefKind k) { + variableRead(bb, i, v, _) and + k = SsaRead() + or + exists(Definition def | def.definesAt(v, bb, i)) and + k = SsaDef() + } + + private newtype OrderedSsaRefIndex = + MkOrderedSsaRefIndex(int i, SsaRefKind k) { ssaRef(_, i, _, k) } + + private OrderedSsaRefIndex ssaRefOrd(BasicBlock bb, int i, SourceVariable v, SsaRefKind k, int ord) { + ssaRef(bb, i, v, k) and + result = MkOrderedSsaRefIndex(i, k) and + ord = k.getOrder() + } + + /** + * Gets the (1-based) rank of the reference to `v` at the `i`th node of basic + * block `bb`, which has the given reference kind `k`. + * + * For example, if `bb` is a basic block with a phi node for `v` (considered + * to be at index -1), reads `v` at node 2, and defines it at node 5, we have: + * + * ```ql + * ssaRefRank(bb, -1, v, SsaDef()) = 1 // phi node + * ssaRefRank(bb, 2, v, Read()) = 2 // read at node 2 + * ssaRefRank(bb, 5, v, SsaDef()) = 3 // definition at node 5 + * ``` + * + * Reads are considered before writes when they happen at the same index. + */ + int ssaRefRank(BasicBlock bb, int i, SourceVariable v, SsaRefKind k) { + ssaRefOrd(bb, i, v, k, _) = + rank[result](int j, int ord, OrderedSsaRefIndex res | + res = ssaRefOrd(bb, j, v, _, ord) + | + res order by j, ord + ) + } + + int maxSsaRefRank(BasicBlock bb, SourceVariable v) { + result = ssaRefRank(bb, _, v, _) and + not result + 1 = ssaRefRank(bb, _, v, _) + } + + /** + * Holds if the SSA definition `def` reaches rank index `rnk` in its own + * basic block `bb`. + */ + predicate ssaDefReachesRank(BasicBlock bb, Definition def, int rnk, SourceVariable v) { + exists(int i | + rnk = ssaRefRank(bb, i, v, SsaDef()) and + def.definesAt(v, bb, i) + ) + or + ssaDefReachesRank(bb, def, rnk - 1, v) and + rnk = ssaRefRank(bb, _, v, SsaRead()) + } + + /** + * Holds if the SSA definition of `v` at `def` reaches index `i` in the same + * basic block `bb`, without crossing another SSA definition of `v`. + */ + predicate ssaDefReachesReadWithinBlock(SourceVariable v, Definition def, BasicBlock bb, int i) { + exists(int rnk | + ssaDefReachesRank(bb, def, rnk, v) and + rnk = ssaRefRank(bb, i, v, SsaRead()) and + variableRead(bb, i, v, _) + ) + } + + /** + * Holds if the SSA definition of `v` at `def` reaches uncertain SSA definition + * `redef` in the same basic block, without crossing another SSA definition of `v`. + */ + predicate ssaDefReachesUncertainDefWithinBlock( + SourceVariable v, Definition def, UncertainWriteDefinition redef + ) { + exists(BasicBlock bb, int rnk, int i | + ssaDefReachesRank(bb, def, rnk, v) and + rnk = ssaRefRank(bb, i, v, SsaDef()) - 1 and + redef.definesAt(v, bb, i) + ) + } + + /** + * Same as `ssaRefRank()`, but restricted to a particular SSA definition `def`. + */ + int ssaDefRank(Definition def, SourceVariable v, BasicBlock bb, int i, SsaRefKind k) { + v = def.getSourceVariable() and + result = ssaRefRank(bb, i, v, k) and + ( + ssaDefReachesRead(_, def, bb, i) + or + def.definesAt(_, bb, i) + ) + } + + predicate defOccursInBlock(Definition def, BasicBlock bb, SourceVariable v) { + exists(ssaDefRank(def, v, bb, _, _)) + } + + pragma[noinline] + private BasicBlock getAMaybeLiveSuccessor(Definition def, BasicBlock bb) { + result = getABasicBlockSuccessor(bb) and + not defOccursInBlock(_, bb, def.getSourceVariable()) and + ssaDefReachesEndOfBlock(bb, def, _) + } + + /** + * Holds if `def` is accessed in basic block `bb1` (either a read or a write), + * `bb2` is a transitive successor of `bb1`, `def` is live at the end of `bb1`, + * and the underlying variable for `def` is neither read nor written in any block + * on the path between `bb1` and `bb2`. + */ + predicate varBlockReaches(Definition def, BasicBlock bb1, BasicBlock bb2) { + defOccursInBlock(def, bb1, _) and + bb2 = getABasicBlockSuccessor(bb1) + or + exists(BasicBlock mid | varBlockReaches(def, bb1, mid) | bb2 = getAMaybeLiveSuccessor(def, mid)) + } + + /** + * Holds if `def` is accessed in basic block `bb1` (either a read or a write), + * `def` is read at index `i2` in basic block `bb2`, `bb2` is in a transitive + * successor block of `bb1`, and `def` is neither read nor written in any block + * on a path between `bb1` and `bb2`. + */ + predicate defAdjacentRead(Definition def, BasicBlock bb1, BasicBlock bb2, int i2) { + varBlockReaches(def, bb1, bb2) and + ssaRefRank(bb2, i2, def.getSourceVariable(), SsaRead()) = 1 and + variableRead(bb2, i2, _, _) + } +} + +private import SsaDefReaches + +pragma[noinline] +private predicate ssaDefReachesEndOfBlockRec(BasicBlock bb, Definition def, SourceVariable v) { + exists(BasicBlock idom | ssaDefReachesEndOfBlock(idom, def, v) | + // The construction of SSA form ensures that each read of a variable is + // dominated by its definition. An SSA definition therefore reaches a + // control flow node if it is the _closest_ SSA definition that dominates + // the node. If two definitions dominate a node then one must dominate the + // other, so therefore the definition of _closest_ is given by the dominator + // tree. Thus, reaching definitions can be calculated in terms of dominance. + idom = getImmediateBasicBlockDominator(bb) + ) +} + +/** + * NB: If this predicate is exposed, it should be cached. + * + * Holds if the SSA definition of `v` at `def` reaches the end of basic + * block `bb`, at which point it is still live, without crossing another + * SSA definition of `v`. + */ +pragma[nomagic] +predicate ssaDefReachesEndOfBlock(BasicBlock bb, Definition def, SourceVariable v) { + exists(int last | last = maxSsaRefRank(bb, v) | + ssaDefReachesRank(bb, def, last, v) and + liveAtExit(bb, v) + ) + or + ssaDefReachesEndOfBlockRec(bb, def, v) and + liveAtExit(bb, v) and + not ssaRef(bb, _, v, SsaDef()) +} + +/** + * NB: If this predicate is exposed, it should be cached. + * + * Holds if `inp` is an input to the phi node `phi` along the edge originating in `bb`. + */ +pragma[nomagic] +predicate phiHasInputFromBlock(PhiNode phi, Definition inp, BasicBlock bb) { + exists(SourceVariable v, BasicBlock bbDef | + phi.definesAt(v, bbDef, _) and + getABasicBlockPredecessor(bbDef) = bb and + ssaDefReachesEndOfBlock(bb, inp, v) + ) +} + +/** + * NB: If this predicate is exposed, it should be cached. + * + * Holds if the SSA definition of `v` at `def` reaches a read at index `i` in + * basic block `bb`, without crossing another SSA definition of `v`. The read + * is of kind `rk`. + */ +pragma[nomagic] +predicate ssaDefReachesRead(SourceVariable v, Definition def, BasicBlock bb, int i) { + ssaDefReachesReadWithinBlock(v, def, bb, i) + or + variableRead(bb, i, v, _) and + ssaDefReachesEndOfBlock(getABasicBlockPredecessor(bb), def, v) and + not ssaDefReachesReadWithinBlock(v, _, bb, i) +} + +/** + * NB: If this predicate is exposed, it should be cached. + * + * Holds if `def` is accessed at index `i1` in basic block `bb1` (either a read + * or a write), `def` is read at index `i2` in basic block `bb2`, and there is a + * path between them without any read of `def`. + */ +pragma[nomagic] +predicate adjacentDefRead(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) { + exists(int rnk | + rnk = ssaDefRank(def, _, bb1, i1, _) and + rnk + 1 = ssaDefRank(def, _, bb1, i2, SsaRead()) and + variableRead(bb1, i2, _, _) and + bb2 = bb1 + ) + or + exists(SourceVariable v | ssaDefRank(def, v, bb1, i1, _) = maxSsaRefRank(bb1, v)) and + defAdjacentRead(def, bb1, bb2, i2) +} + +private predicate adjacentDefReachesRead( + Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2 +) { + adjacentDefRead(def, bb1, i1, bb2, i2) and + exists(SourceVariable v | v = def.getSourceVariable() | + ssaRef(bb1, i1, v, SsaDef()) + or + variableRead(bb1, i1, v, true) + ) + or + exists(BasicBlock bb3, int i3 | + adjacentDefReachesRead(def, bb1, i1, bb3, i3) and + variableRead(bb3, i3, _, false) and + adjacentDefRead(def, bb3, i3, bb2, i2) + ) +} + +/** + * NB: If this predicate is exposed, it should be cached. + * + * Same as `adjacentDefRead`, but ignores uncertain reads. + */ +pragma[nomagic] +predicate adjacentDefNoUncertainReads(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) { + adjacentDefReachesRead(def, bb1, i1, bb2, i2) and + variableRead(bb2, i2, _, true) +} + +/** + * NB: If this predicate is exposed, it should be cached. + * + * Holds if the node at index `i` in `bb` is a last reference to SSA definition + * `def`. The reference is last because it can reach another write `next`, + * without passing through another read or write. + */ +pragma[nomagic] +predicate lastRefRedef(Definition def, BasicBlock bb, int i, Definition next) { + exists(int rnk, SourceVariable v, int j | rnk = ssaDefRank(def, v, bb, i, _) | + // Next reference to `v` inside `bb` is a write + next.definesAt(v, bb, j) and + rnk + 1 = ssaRefRank(bb, j, v, SsaDef()) + or + // Can reach a write using one or more steps + rnk = maxSsaRefRank(bb, v) and + exists(BasicBlock bb2 | + varBlockReaches(def, bb, bb2) and + next.definesAt(v, bb2, j) and + 1 = ssaRefRank(bb2, j, v, SsaDef()) + ) + ) +} + +/** + * NB: If this predicate is exposed, it should be cached. + * + * Holds if `inp` is an immediately preceding definition of uncertain definition + * `def`. Since `def` is uncertain, the value from the preceding definition might + * still be valid. + */ +pragma[nomagic] +predicate uncertainWriteDefinitionInput(UncertainWriteDefinition def, Definition inp) { + lastRefRedef(inp, _, _, def) +} + +private predicate adjacentDefReachesUncertainRead( + Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2 +) { + adjacentDefReachesRead(def, bb1, i1, bb2, i2) and + variableRead(bb2, i2, _, false) +} + +/** + * NB: If this predicate is exposed, it should be cached. + * + * Same as `lastRefRedef`, but ignores uncertain reads. + */ +pragma[nomagic] +predicate lastRefRedefNoUncertainReads(Definition def, BasicBlock bb, int i, Definition next) { + lastRefRedef(def, bb, i, next) and + not variableRead(bb, i, def.getSourceVariable(), false) + or + exists(BasicBlock bb0, int i0 | + lastRefRedef(def, bb0, i0, next) and + adjacentDefReachesUncertainRead(def, bb, i, bb0, i0) + ) +} + +/** + * NB: If this predicate is exposed, it should be cached. + * + * Holds if the node at index `i` in `bb` is a last reference to SSA + * definition `def`. + * + * That is, the node can reach the end of the enclosing callable, or another + * SSA definition for the underlying source variable, without passing through + * another read. + */ +pragma[nomagic] +predicate lastRef(Definition def, BasicBlock bb, int i) { + lastRefRedef(def, bb, i, _) + or + exists(SourceVariable v | ssaDefRank(def, v, bb, i, _) = maxSsaRefRank(bb, v) | + // Can reach exit directly + bb instanceof ExitBasicBlock + or + // Can reach a block using one or more steps, where `def` is no longer live + exists(BasicBlock bb2 | varBlockReaches(def, bb, bb2) | + not defOccursInBlock(def, bb2, _) and + not ssaDefReachesEndOfBlock(bb2, def, _) + ) + ) +} + +/** + * NB: If this predicate is exposed, it should be cached. + * + * Same as `lastRefRedef`, but ignores uncertain reads. + */ +pragma[nomagic] +predicate lastRefNoUncertainReads(Definition def, BasicBlock bb, int i) { + lastRef(def, bb, i) and + not variableRead(bb, i, def.getSourceVariable(), false) + or + exists(BasicBlock bb0, int i0 | + lastRef(def, bb0, i0) and + adjacentDefReachesUncertainRead(def, bb, i, bb0, i0) + ) +} + +/** A static single assignment (SSA) definition. */ +class Definition extends TDefinition { + /** Gets the source variable underlying this SSA definition. */ + SourceVariable getSourceVariable() { this.definesAt(result, _, _) } + + /** + * Holds if this SSA definition defines `v` at index `i` in basic block `bb`. + * Phi nodes are considered to be at index `-1`, while normal variable writes + * are at the index of the control flow node they wrap. + */ + final predicate definesAt(SourceVariable v, BasicBlock bb, int i) { + this = TWriteDef(v, bb, i) + or + this = TPhiNode(v, bb) and i = -1 + } + + /** Gets the basic block to which this SSA definition belongs. */ + final BasicBlock getBasicBlock() { this.definesAt(_, result, _) } + + /** Gets a textual representation of this SSA definition. */ + string toString() { none() } +} + +/** An SSA definition that corresponds to a write. */ +class WriteDefinition extends Definition, TWriteDef { + private SourceVariable v; + private BasicBlock bb; + private int i; + + WriteDefinition() { this = TWriteDef(v, bb, i) } + + override string toString() { result = "WriteDef" } +} + +/** A phi node. */ +class PhiNode extends Definition, TPhiNode { + override string toString() { result = "Phi" } +} + +/** + * An SSA definition that represents an uncertain update of the underlying + * source variable. + */ +class UncertainWriteDefinition extends WriteDefinition { + UncertainWriteDefinition() { + exists(SourceVariable v, BasicBlock bb, int i | + this.definesAt(v, bb, i) and + variableWrite(bb, i, v, false) + ) + } +} diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/basessa/SsaImplSpecific.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/basessa/SsaImplSpecific.qll new file mode 100644 index 00000000000..f095926e2a4 --- /dev/null +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/basessa/SsaImplSpecific.qll @@ -0,0 +1,51 @@ +/** Provides the C# specific parameters for `SsaImplCommon.qll`. */ + +private import csharp +private import AssignableDefinitions + +class BasicBlock = ControlFlow::BasicBlock; + +BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result = bb.getImmediateDominator() } + +BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() } + +class ExitBasicBlock = ControlFlow::BasicBlocks::ExitBlock; + +pragma[noinline] +private Callable getAnAssigningCallable(LocalScopeVariable v) { + result = any(AssignableDefinition def | def.getTarget() = v).getEnclosingCallable() +} + +class SourceVariable extends LocalScopeVariable { + SourceVariable() { not getAnAssigningCallable(this) != getAnAssigningCallable(this) } +} + +/** + * Holds if the `i`th node of basic block `bb` is assignable definition `def`, + * targeting local scope variable `v`. + */ +predicate definitionAt(AssignableDefinition def, BasicBlock bb, int i, SourceVariable v) { + bb.getNode(i) = def.getAControlFlowNode() and + v = def.getTarget() and + // In cases like `(x, x) = (0, 1)`, we discard the first (dead) definition of `x` + not exists(TupleAssignmentDefinition first, TupleAssignmentDefinition second | first = def | + second.getAssignment() = first.getAssignment() and + second.getEvaluationOrder() > first.getEvaluationOrder() and + second.getTarget() = v + ) +} + +predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) { + exists(AssignableDefinition def | + definitionAt(def, bb, i, v) and + if def.isCertain() then certain = true else certain = false + ) +} + +predicate variableRead(BasicBlock bb, int i, SourceVariable v, boolean certain) { + exists(AssignableRead read | + read.getAControlFlowNode() = bb.getNode(i) and + read.getTarget() = v and + certain = true + ) +} diff --git a/csharp/ql/src/semmle/code/csharp/dispatch/Dispatch.qll b/csharp/ql/src/semmle/code/csharp/dispatch/Dispatch.qll index fd460adf508..1e0eaaf8017 100644 --- a/csharp/ql/src/semmle/code/csharp/dispatch/Dispatch.qll +++ b/csharp/ql/src/semmle/code/csharp/dispatch/Dispatch.qll @@ -312,8 +312,13 @@ private module Internal { 1 < strictcount(this.getADynamicTarget().getUnboundDeclaration()) and c = this.getCall().getEnclosingCallable().getUnboundDeclaration() and ( - exists(AssignableDefinitions::ImplicitParameterDefinition pdef, Parameter p | - this.getQualifier() = BaseSsa::getARead(pdef, p) and + exists( + BaseSsa::Definition def, AssignableDefinitions::ImplicitParameterDefinition pdef, + Parameter p + | + pdef = def.getDefinition() and + p = pdef.getTarget() and + this.getQualifier() = def.getARead() and p.getPosition() = i and c.getAParameter() = p and not p.isParams() diff --git a/csharp/ql/test/library-tests/dataflow/ssa/BaseSsaConsistency.ql b/csharp/ql/test/library-tests/dataflow/ssa/BaseSsaConsistency.ql index f2c262fb185..86e13215b0c 100644 --- a/csharp/ql/test/library-tests/dataflow/ssa/BaseSsaConsistency.ql +++ b/csharp/ql/test/library-tests/dataflow/ssa/BaseSsaConsistency.ql @@ -1,9 +1,11 @@ import csharp import semmle.code.csharp.dataflow.internal.BaseSSA -from AssignableRead ar, AssignableDefinition def, LocalScopeVariable v +from AssignableRead ar, BaseSsa::Definition ssaDef, AssignableDefinition def, LocalScopeVariable v where - ar = BaseSsa::getARead(def, v) and + ar = ssaDef.getARead() and + def = ssaDef.getDefinition() and + v = def.getTarget() and not exists(Ssa::ExplicitDefinition edef | edef.getADefinition() = def and edef.getARead() = ar From 4184ebd091d903a585cdc6c0ab0b9af7f39c0df8 Mon Sep 17 00:00:00 2001 From: Joe Farebrother Date: Thu, 28 Jan 2021 15:17:08 +0000 Subject: [PATCH 018/142] Java: Add HttpRequestHandler as a remote flow source --- .../src/semmle/code/java/dataflow/FlowSources.qll | 8 ++++++++ .../src/semmle/code/java/frameworks/ApacheHttp.qll | 14 ++++++++++++++ 2 files changed, 22 insertions(+) diff --git a/java/ql/src/semmle/code/java/dataflow/FlowSources.qll b/java/ql/src/semmle/code/java/dataflow/FlowSources.qll index b4235cb2635..7ea6278e489 100644 --- a/java/ql/src/semmle/code/java/dataflow/FlowSources.qll +++ b/java/ql/src/semmle/code/java/dataflow/FlowSources.qll @@ -163,6 +163,14 @@ private class GuiceRequestParameterSource extends RemoteFlowSource { override string getSourceType() { result = "Guice request parameter" } } +private class ApacheHttpRequestParameterSource extends RemoteFlowSource { + ApacheHttpRequestParameterSource() { + this.asParameter() instanceof ApacheHttpRequestHandlerParameter + } + + override string getSourceType() { result = "Apache HTTP request parameter" } +} + private class Struts2ActionSupportClassFieldReadSource extends RemoteFlowSource { Struts2ActionSupportClassFieldReadSource() { exists(Struts2ActionSupportClass c | diff --git a/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll b/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll index bf31a707add..daa0f5c95a6 100644 --- a/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll +++ b/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll @@ -39,3 +39,17 @@ class TypeApacheHttpRequestBuilder extends Class { this.hasQualifiedName("org.apache.http.client.methods", "RequestBuilder") } } + +/** + * The `request` parameter of an implementation of `org.apache.http.protocol.HttpRequestHandler.handle` + */ +class ApacheHttpRequestHandlerParameter extends Parameter { + ApacheHttpRequestHandlerParameter() { + exists(Method m, Interface i | + i.hasQualifiedName("org.apache.http.protocol", "HttpRequestHandler") and + m.getDeclaringType().extendsOrImplements+(i) and + m.hasName("handle") and + this = m.getParameter(0) + ) + } +} From 561679611e4ba9ce3d035b9779bbf7509e5104bb Mon Sep 17 00:00:00 2001 From: Joe Farebrother Date: Tue, 2 Feb 2021 16:21:07 +0000 Subject: [PATCH 019/142] Java: Model flow source for apache http requests, Model flow steps for associated getters Fix rebase conflict --- .../semmle/code/java/dataflow/FlowSteps.qll | 1 + .../code/java/frameworks/ApacheHttp.qll | 61 +++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/java/ql/src/semmle/code/java/dataflow/FlowSteps.qll b/java/ql/src/semmle/code/java/dataflow/FlowSteps.qll index cb219650414..d10ee9fc832 100644 --- a/java/ql/src/semmle/code/java/dataflow/FlowSteps.qll +++ b/java/ql/src/semmle/code/java/dataflow/FlowSteps.qll @@ -17,6 +17,7 @@ module Frameworks { private import semmle.code.java.frameworks.Protobuf private import semmle.code.java.frameworks.guava.Guava private import semmle.code.java.frameworks.apache.Lang + private import semmle.code.java.frameworks.ApacheHttp } /** diff --git a/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll b/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll index daa0f5c95a6..91da01ae097 100644 --- a/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll +++ b/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll @@ -3,6 +3,7 @@ */ import java +private import semmle.code.java.dataflow.FlowSteps class ApacheHttpGetParams extends Method { ApacheHttpGetParams() { @@ -53,3 +54,63 @@ class ApacheHttpRequestHandlerParameter extends Parameter { ) } } + +private class ApacheHttpGetter extends TaintPreservingCallable { + ApacheHttpGetter() { + exists(string pkg, string ty, string mtd, Method m | + this.(Method).overrides*(m) and + m.getDeclaringType().hasQualifiedName(pkg, ty) and + m.hasName(mtd) + | + pkg = "org.apache.http" and + ( + ty = "HttpMessage" and + mtd = + [ + "getAllHeaders", "getFirstHeader", "getHeaders", "getLastHeader", "getParams", + "headerIterator" + ] + or + ty = "HttpRequest" and + mtd = "getRequestLine" + or + ty = "HttpEntityEnclosingRequest" and + mtd = "getEntity" + or + ty = "Header" and + mtd = "getElements" + or + ty = "HeaderElement" and + mtd = ["getName", "getParameter", "getParameterByName", "getParameters", "getValue"] + or + ty = "NameValuePair" and + mtd = ["getName", "getValue"] + or + ty = "HeaderIterator" and + mtd = "nextHeader" + or + ty = "HttpEntity" and + mtd = ["getContent", "getContentEncoding", "getContentType"] + or + ty = "RequestLine" and + mtd = ["getMethod", "getUri"] + ) + or + pkg = "org.apache.http.params" and + ty = "HttpParams" and + mtd.matches("get%Parameter") + ) + } + + override predicate returnsTaintFrom(int arg) { arg = -1 } +} + +private class EntityUtilMethod extends TaintPreservingCallable { + EntityUtilMethod() { + this.getDeclaringType().hasQualifiedName("org.apache.http.util", "EntityUtils") and + this.isStatic() and + this.hasName(["toString", "toByteArray"]) + } + + override predicate returnsTaintFrom(int arg) { arg = 0 } +} From da6e9492a0091356a1ee9da24d96949fd821e749 Mon Sep 17 00:00:00 2001 From: Joe Farebrother Date: Mon, 8 Feb 2021 16:24:50 +0000 Subject: [PATCH 020/142] Model XSS sinks and utility methods --- .../code/java/frameworks/ApacheHttp.qll | 93 +++++++++++++++++-- java/ql/src/semmle/code/java/security/XSS.qll | 3 + 2 files changed, 90 insertions(+), 6 deletions(-) diff --git a/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll b/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll index 91da01ae097..2bd8d19f5e1 100644 --- a/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll +++ b/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll @@ -42,7 +42,7 @@ class TypeApacheHttpRequestBuilder extends Class { } /** - * The `request` parameter of an implementation of `org.apache.http.protocol.HttpRequestHandler.handle` + * The `request` parameter of an implementation of `org.apache.http.protocol.HttpRequestHandler.handle`. */ class ApacheHttpRequestHandlerParameter extends Parameter { ApacheHttpRequestHandlerParameter() { @@ -55,6 +55,30 @@ class ApacheHttpRequestHandlerParameter extends Parameter { } } +/** + * A call that sets the entity of an instance of `org.apache.http.HttpResponse`. + */ +class ApacheHttpResponseSetEntityCall extends MethodAccess { + int arg; + + ApacheHttpResponseSetEntityCall() { + exists(Method m | this.getMethod().overrides*(m) | + m.getDeclaringType().hasQualifiedName("org.apache.http", "HttpResponse") and + m.hasName("setEntity") and + arg = 0 + or + m.getDeclaringType().hasQualifiedName("org.apache.http.util", "EntityUtils") and + m.hasName("updateEntity") and + arg = 1 + ) + } + + /** + * Gets the entity that is set by this call. + */ + Expr getEntity() { result = this.getArgument(arg) } +} + private class ApacheHttpGetter extends TaintPreservingCallable { ApacheHttpGetter() { exists(string pkg, string ty, string mtd, Method m | @@ -105,12 +129,69 @@ private class ApacheHttpGetter extends TaintPreservingCallable { override predicate returnsTaintFrom(int arg) { arg = -1 } } -private class EntityUtilMethod extends TaintPreservingCallable { - EntityUtilMethod() { - this.getDeclaringType().hasQualifiedName("org.apache.http.util", "EntityUtils") and - this.isStatic() and - this.hasName(["toString", "toByteArray"]) +private class UtilMethod extends TaintPreservingCallable { + UtilMethod() { + exists(string ty, string mtd | + this.isStatic() and + this.getDeclaringType().hasQualifiedName("org.apache.http.util", ty) and + this.hasName(mtd) + | + ty = "EntityUtils" and + mtd = ["toString", "toByteArray"] + or + ty = "EncodingUtils" and + mtd = ["getAsciiBytes", "getAsciiString", "getBytes", "getString"] + or + ty = "Args" and + mtd = ["containsNoBlanks", "notBlank", "notEmpty", "notNull"] + ) } override predicate returnsTaintFrom(int arg) { arg = 0 } } + +private class EntitySetter extends TaintPreservingCallable { + EntitySetter() { + this.getDeclaringType() + .getASourceSupertype*() + .hasQualifiedName("org.apache.http.entity", "BasicHttpEntity") and + this.hasName("setContent") + } + + override predicate transfersTaint(int src, int sink) { src = 0 and sink = -1 } +} + +private class EntityConsructor extends TaintPreservingCallable, Constructor { + EntityConsructor() { + this.getDeclaringType() + .hasQualifiedName("org.apache.http.entity", + [ + "BufferedHttpEntity", "ByteArrayEntity", "HttpEntityWrapper", "InputStreamEntity", + "StringEntity" + ]) + } + + override predicate returnsTaintFrom(int arg) { arg = 0 } +} + +private class BufferMethod extends TaintPreservingCallable { + BufferMethod() { + exists(Method m | + this.(Method).overrides*(m) and + m.getDeclaringType() + .hasQualifiedName("org.apache.http.util", ["ByteArrayBuffer", "CharArrayBuffer"]) and + m.hasName([ + "append", "buffer", "subSequence", "substring", "substringTrimmed", "toByteAray", + "toCharArray", "toString" + ]) + ) + } + + override predicate returnsTaintFrom(int arg) { arg = -1 } + + override predicate transfersTaint(int src, int sink) { + this.hasName("append") and + src = 0 and + sink = -1 + } +} diff --git a/java/ql/src/semmle/code/java/security/XSS.qll b/java/ql/src/semmle/code/java/security/XSS.qll index a9141965f9b..986995cdfe1 100644 --- a/java/ql/src/semmle/code/java/security/XSS.qll +++ b/java/ql/src/semmle/code/java/security/XSS.qll @@ -5,6 +5,7 @@ import semmle.code.java.frameworks.Servlets import semmle.code.java.frameworks.android.WebView import semmle.code.java.frameworks.spring.SpringController import semmle.code.java.frameworks.spring.SpringHttp +import semmle.code.java.frameworks.ApacheHttp import semmle.code.java.dataflow.DataFlow import semmle.code.java.dataflow.TaintTracking2 @@ -94,6 +95,8 @@ private class DefaultXssSink extends XssSink { returnType instanceof RawClass ) ) + or + this.asExpr() = any(ApacheHttpResponseSetEntityCall c).getEntity() } } From 5bba7f6df7e631c1a1cca2feb46679b7c6802a3f Mon Sep 17 00:00:00 2001 From: Joe Farebrother Date: Wed, 10 Feb 2021 17:28:49 +0000 Subject: [PATCH 021/142] Add unit tests --- .../code/java/frameworks/ApacheHttp.qll | 2 +- .../frameworks/apache-http/A.java | 41 +++++++++ .../frameworks/apache-http/flow.expected | 23 +++++ .../frameworks/apache-http/flow.ql | 24 +++++ .../frameworks/apache-http/options | 1 + .../org/apache/http/Header.java | 37 +++----- .../org/apache/http/HttpResponse.java | 55 ++++++++++++ .../http/entity/AbstractHttpEntity.java | 74 ++++++++++++++++ .../apache/http/entity/ByteArrayEntity.java | 78 +++++++++++++++++ .../org/apache/http/entity/ContentType.java | 35 ++++++++ .../org/apache/http/entity/StringEntity.java | 87 +++++++++++++++++++ .../org/apache/http/protocol/HttpContext.java | 37 ++++++++ .../http/protocol/HttpRequestHandler.java | 38 ++++++++ .../org/apache/http/util/EntityUtils.java | 72 +++++++++++++++ 14 files changed, 576 insertions(+), 28 deletions(-) create mode 100644 java/ql/test/library-tests/frameworks/apache-http/A.java create mode 100644 java/ql/test/library-tests/frameworks/apache-http/flow.expected create mode 100644 java/ql/test/library-tests/frameworks/apache-http/flow.ql create mode 100644 java/ql/test/library-tests/frameworks/apache-http/options create mode 100644 java/ql/test/stubs/apache-http-4.4.13/org/apache/http/HttpResponse.java create mode 100644 java/ql/test/stubs/apache-http-4.4.13/org/apache/http/entity/AbstractHttpEntity.java create mode 100644 java/ql/test/stubs/apache-http-4.4.13/org/apache/http/entity/ByteArrayEntity.java create mode 100644 java/ql/test/stubs/apache-http-4.4.13/org/apache/http/entity/ContentType.java create mode 100644 java/ql/test/stubs/apache-http-4.4.13/org/apache/http/entity/StringEntity.java create mode 100644 java/ql/test/stubs/apache-http-4.4.13/org/apache/http/protocol/HttpContext.java create mode 100644 java/ql/test/stubs/apache-http-4.4.13/org/apache/http/protocol/HttpRequestHandler.java create mode 100644 java/ql/test/stubs/apache-http-4.4.13/org/apache/http/util/EntityUtils.java diff --git a/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll b/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll index 2bd8d19f5e1..5d7ad59b560 100644 --- a/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll +++ b/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll @@ -137,7 +137,7 @@ private class UtilMethod extends TaintPreservingCallable { this.hasName(mtd) | ty = "EntityUtils" and - mtd = ["toString", "toByteArray"] + mtd = ["toString", "toByteArray", "getContentCharSet", "getContentMimeType"] or ty = "EncodingUtils" and mtd = ["getAsciiBytes", "getAsciiString", "getBytes", "getString"] diff --git a/java/ql/test/library-tests/frameworks/apache-http/A.java b/java/ql/test/library-tests/frameworks/apache-http/A.java new file mode 100644 index 00000000000..01cabeffa78 --- /dev/null +++ b/java/ql/test/library-tests/frameworks/apache-http/A.java @@ -0,0 +1,41 @@ +import org.apache.http.*; +import org.apache.http.protocol.*; +import org.apache.http.util.*; +import org.apache.http.entity.*; + +class A { + static Object taint() { return null; } + + static void sink(Object o) { } + + class Test1 implements HttpRequestHandler { + public void handle(HttpRequest req, HttpResponse res, HttpContext ctx) { + A.sink(req.getRequestLine()); + A.sink(req.getRequestLine().getUri()); + A.sink(req.getRequestLine().getMethod()); + A.sink(req.getAllHeaders()); + HeaderIterator it = req.headerIterator(); + A.sink(it.next()); + A.sink(it.nextHeader()); + Header h = req.getHeaders("abc")[3]; + A.sink(h.getName()); + A.sink(h.getValue()); + HeaderElement el = h.getElements()[0]; + A.sink(el.getName()); + A.sink(el.getValue()); + A.sink(el.getParameters()); + A.sink(el.getParameterByName("abc").getValue()); + A.sink(el.getParameter(0).getName()); + HttpEntity ent = ((HttpEntityEnclosingRequest)req).getEntity(); + A.sink(ent.getContent()); + A.sink(ent.getContentEncoding()); + A.sink(ent.getContentType()); + A.sink(EntityUtils.toString(ent)); + A.sink(EntityUtils.toByteArray(ent)); + A.sink(EntityUtils.getContentCharSet(ent)); + A.sink(EntityUtils.getContentMimeType(ent)); + res.setEntity(new StringEntity("a")); + EntityUtils.updateEntity(res, new ByteArrayEntity(EntityUtils.toByteArray(ent))); + } + } +} \ No newline at end of file diff --git a/java/ql/test/library-tests/frameworks/apache-http/flow.expected b/java/ql/test/library-tests/frameworks/apache-http/flow.expected new file mode 100644 index 00000000000..8d2afdcd331 --- /dev/null +++ b/java/ql/test/library-tests/frameworks/apache-http/flow.expected @@ -0,0 +1,23 @@ +| A.java:12:28:12:42 | req | A.java:13:20:13:39 | getRequestLine(...) | +| A.java:12:28:12:42 | req | A.java:14:20:14:48 | getUri(...) | +| A.java:12:28:12:42 | req | A.java:15:20:15:51 | getMethod(...) | +| A.java:12:28:12:42 | req | A.java:16:20:16:38 | getAllHeaders(...) | +| A.java:12:28:12:42 | req | A.java:18:20:18:28 | next(...) | +| A.java:12:28:12:42 | req | A.java:19:20:19:34 | nextHeader(...) | +| A.java:12:28:12:42 | req | A.java:21:20:21:30 | getName(...) | +| A.java:12:28:12:42 | req | A.java:22:20:22:31 | getValue(...) | +| A.java:12:28:12:42 | req | A.java:24:20:24:31 | getName(...) | +| A.java:12:28:12:42 | req | A.java:25:20:25:32 | getValue(...) | +| A.java:12:28:12:42 | req | A.java:26:20:26:37 | getParameters(...) | +| A.java:12:28:12:42 | req | A.java:27:20:27:58 | getValue(...) | +| A.java:12:28:12:42 | req | A.java:28:20:28:47 | getName(...) | +| A.java:12:28:12:42 | req | A.java:30:20:30:35 | getContent(...) | +| A.java:12:28:12:42 | req | A.java:31:20:31:43 | getContentEncoding(...) | +| A.java:12:28:12:42 | req | A.java:32:20:32:39 | getContentType(...) | +| A.java:12:28:12:42 | req | A.java:33:20:33:44 | toString(...) | +| A.java:12:28:12:42 | req | A.java:34:20:34:47 | toByteArray(...) | +| A.java:12:28:12:42 | req | A.java:35:20:35:53 | getContentCharSet(...) | +| A.java:12:28:12:42 | req | A.java:36:20:36:54 | getContentMimeType(...) | +| A.java:12:28:12:42 | req | A.java:37:27:37:99 | new StringEntity(...) | +| A.java:12:28:12:42 | req | A.java:38:43:38:91 | new ByteArrayEntity(...) | +| A.java:30:20:30:35 | getContent(...) | A.java:30:20:30:35 | getContent(...) | diff --git a/java/ql/test/library-tests/frameworks/apache-http/flow.ql b/java/ql/test/library-tests/frameworks/apache-http/flow.ql new file mode 100644 index 00000000000..c8d1589159a --- /dev/null +++ b/java/ql/test/library-tests/frameworks/apache-http/flow.ql @@ -0,0 +1,24 @@ +import java +import semmle.code.java.dataflow.TaintTracking +import semmle.code.java.dataflow.FlowSources +import semmle.code.java.security.XSS + +class Conf extends TaintTracking::Configuration { + Conf() { this = "qltest:frameworks:apache-http" } + + override predicate isSource(DataFlow::Node n) { + n.asExpr().(MethodAccess).getMethod().hasName("taint") + or + n instanceof RemoteFlowSource + } + + override predicate isSink(DataFlow::Node n) { + exists(MethodAccess ma | ma.getMethod().hasName("sink") | n.asExpr() = ma.getAnArgument()) + or + n instanceof XssSink + } +} + +from DataFlow::Node src, DataFlow::Node sink, Conf conf +where conf.hasFlow(src, sink) +select src, sink diff --git a/java/ql/test/library-tests/frameworks/apache-http/options b/java/ql/test/library-tests/frameworks/apache-http/options new file mode 100644 index 00000000000..7a49a36a4c6 --- /dev/null +++ b/java/ql/test/library-tests/frameworks/apache-http/options @@ -0,0 +1 @@ +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/apache-http-4.4.13 \ No newline at end of file diff --git a/java/ql/test/stubs/apache-http-4.4.13/org/apache/http/Header.java b/java/ql/test/stubs/apache-http-4.4.13/org/apache/http/Header.java index b742e110a34..6e4886fc85c 100644 --- a/java/ql/test/stubs/apache-http-4.4.13/org/apache/http/Header.java +++ b/java/ql/test/stubs/apache-http-4.4.13/org/apache/http/Header.java @@ -1,8 +1,4 @@ /* - * $HeadURL: http://svn.apache.org/repos/asf/httpcomponents/httpcore/trunk/module-main/src/main/java/org/apache/http/Header.java $ - * $Revision: 569636 $ - * $Date: 2007-08-25 00:34:47 -0700 (Sat, 25 Aug 2007) $ - * * ==================================================================== * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file @@ -33,38 +29,25 @@ package org.apache.http; /** * Represents an HTTP header field. - * - *

- * The HTTP header fields follow the same generic format as that given in - * Section 3.1 of RFC 822. Each header field consists of a name followed by a - * colon (":") and the field value. Field names are case-insensitive. The field - * value MAY be preceded by any amount of LWS, though a single SP is preferred. * - *

+ * 

The HTTP header fields follow the same generic format as + * that given in Section 3.1 of RFC 822. Each header field consists + * of a name followed by a colon (":") and the field value. Field names + * are case-insensitive. The field value MAY be preceded by any amount + * of LWS, though a single SP is preferred. + * + *

  *     message-header = field-name ":" [ field-value ]
  *     field-name     = token
  *     field-value    = *( field-content | LWS )
  *     field-content  = <the OCTETs making up the field-value
  *                      and consisting of either *TEXT or combinations
  *                      of token, separators, and quoted-string>
- * 
- * - * @author Remy Maucherat - * @author Oleg Kalnichevski - * @version $Revision: 569636 $ + *
* - * @deprecated Please use {@link java.net.URL#openConnection} instead. Please - * visit this - * webpage for further details. + * @since 4.0 */ -@Deprecated -public interface Header { - - String getName(); - - String getValue(); - +public interface Header extends NameValuePair { HeaderElement[] getElements() throws ParseException; } diff --git a/java/ql/test/stubs/apache-http-4.4.13/org/apache/http/HttpResponse.java b/java/ql/test/stubs/apache-http-4.4.13/org/apache/http/HttpResponse.java new file mode 100644 index 00000000000..5dbfd6d7875 --- /dev/null +++ b/java/ql/test/stubs/apache-http-4.4.13/org/apache/http/HttpResponse.java @@ -0,0 +1,55 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.http; + +import java.util.Locale; + +public interface HttpResponse extends HttpMessage { + // StatusLine getStatusLine(); + + // void setStatusLine(StatusLine statusline); + + // void setStatusLine(ProtocolVersion ver, int code); + + // void setStatusLine(ProtocolVersion ver, int code, String reason); + + void setStatusCode(int code) + throws IllegalStateException; + + void setReasonPhrase(String reason) + throws IllegalStateException; + + HttpEntity getEntity(); + + void setEntity(HttpEntity entity); + + Locale getLocale(); + + void setLocale(Locale loc); + +} diff --git a/java/ql/test/stubs/apache-http-4.4.13/org/apache/http/entity/AbstractHttpEntity.java b/java/ql/test/stubs/apache-http-4.4.13/org/apache/http/entity/AbstractHttpEntity.java new file mode 100644 index 00000000000..455882abfe7 --- /dev/null +++ b/java/ql/test/stubs/apache-http-4.4.13/org/apache/http/entity/AbstractHttpEntity.java @@ -0,0 +1,74 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.http.entity; + +import java.io.IOException; +import org.apache.http.HttpEntity; +import org.apache.http.Header; + +public abstract class AbstractHttpEntity implements HttpEntity { + @Override + public Header getContentType() { + return null; + } + + @Override + public Header getContentEncoding() { + return null; + } + + @Override + public boolean isChunked() { + return false; + } + + public void setContentType(final Header contentType) { + } + + public void setContentType(final String ctString) { + } + + public void setContentEncoding(final Header contentEncoding) { + } + + public void setContentEncoding(final String ceString) { + } + + public void setChunked(final boolean b) { + } + + @Override + public void consumeContent() throws IOException { + } + + @Override + public String toString() { + return null; + } + +} diff --git a/java/ql/test/stubs/apache-http-4.4.13/org/apache/http/entity/ByteArrayEntity.java b/java/ql/test/stubs/apache-http-4.4.13/org/apache/http/entity/ByteArrayEntity.java new file mode 100644 index 00000000000..44c946fc2f6 --- /dev/null +++ b/java/ql/test/stubs/apache-http-4.4.13/org/apache/http/entity/ByteArrayEntity.java @@ -0,0 +1,78 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.http.entity; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; + + +public class ByteArrayEntity extends AbstractHttpEntity implements Cloneable { + public ByteArrayEntity(final byte[] b, final ContentType contentType) { + } + + public ByteArrayEntity(final byte[] b, final int off, final int len, final ContentType contentType) { + } + + public ByteArrayEntity(final byte[] b) { + } + + public ByteArrayEntity(final byte[] b, final int off, final int len) { + } + + @Override + public boolean isRepeatable() { + return false; + } + + @Override + public long getContentLength() { + return 0; + } + + @Override + public InputStream getContent() { + return null; + } + + @Override + public void writeTo(final OutputStream outStream) throws IOException { + } + + @Override + public boolean isStreaming() { + return false; + } + + @Override + public Object clone() throws CloneNotSupportedException { + return null; + } + +} diff --git a/java/ql/test/stubs/apache-http-4.4.13/org/apache/http/entity/ContentType.java b/java/ql/test/stubs/apache-http-4.4.13/org/apache/http/entity/ContentType.java new file mode 100644 index 00000000000..6f4554e4d59 --- /dev/null +++ b/java/ql/test/stubs/apache-http-4.4.13/org/apache/http/entity/ContentType.java @@ -0,0 +1,35 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.http.entity; + +import java.io.Serializable; + + +public final class ContentType implements Serializable { + +} diff --git a/java/ql/test/stubs/apache-http-4.4.13/org/apache/http/entity/StringEntity.java b/java/ql/test/stubs/apache-http-4.4.13/org/apache/http/entity/StringEntity.java new file mode 100644 index 00000000000..3c4d8515e24 --- /dev/null +++ b/java/ql/test/stubs/apache-http-4.4.13/org/apache/http/entity/StringEntity.java @@ -0,0 +1,87 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.http.entity; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.UnsupportedEncodingException; +import java.nio.charset.Charset; +import java.nio.charset.UnsupportedCharsetException; + + +public class StringEntity extends AbstractHttpEntity implements Cloneable { + public StringEntity(final String string, final ContentType contentType) throws UnsupportedCharsetException { + } + + public StringEntity( + final String string, final String mimeType, final String charset) throws UnsupportedEncodingException { + } + + public StringEntity(final String string, final String charset) + throws UnsupportedCharsetException { + } + + public StringEntity(final String string, final Charset charset) { + } + + public StringEntity(final String string) + throws UnsupportedEncodingException { + } + + @Override + public boolean isRepeatable() { + return false; + } + + @Override + public long getContentLength() { + return 0; + } + + @Override + public InputStream getContent() throws IOException { + return null; + } + + @Override + public void writeTo(final OutputStream outStream) throws IOException { + } + + @Override + public boolean isStreaming() { + return false; + } + + @Override + public Object clone() throws CloneNotSupportedException { + return null; + } + +} diff --git a/java/ql/test/stubs/apache-http-4.4.13/org/apache/http/protocol/HttpContext.java b/java/ql/test/stubs/apache-http-4.4.13/org/apache/http/protocol/HttpContext.java new file mode 100644 index 00000000000..4c0ad5b9cd8 --- /dev/null +++ b/java/ql/test/stubs/apache-http-4.4.13/org/apache/http/protocol/HttpContext.java @@ -0,0 +1,37 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.http.protocol; + +public interface HttpContext { + Object getAttribute(String id); + + void setAttribute(String id, Object obj); + + Object removeAttribute(String id); + +} diff --git a/java/ql/test/stubs/apache-http-4.4.13/org/apache/http/protocol/HttpRequestHandler.java b/java/ql/test/stubs/apache-http-4.4.13/org/apache/http/protocol/HttpRequestHandler.java new file mode 100644 index 00000000000..e7fee4ca031 --- /dev/null +++ b/java/ql/test/stubs/apache-http-4.4.13/org/apache/http/protocol/HttpRequestHandler.java @@ -0,0 +1,38 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.http.protocol; + +import java.io.IOException; +import org.apache.http.HttpRequest; +import org.apache.http.HttpResponse; + +public interface HttpRequestHandler { + void handle(HttpRequest request, HttpResponse response, HttpContext context) + throws IOException; + +} diff --git a/java/ql/test/stubs/apache-http-4.4.13/org/apache/http/util/EntityUtils.java b/java/ql/test/stubs/apache-http-4.4.13/org/apache/http/util/EntityUtils.java new file mode 100644 index 00000000000..1af8795c3f3 --- /dev/null +++ b/java/ql/test/stubs/apache-http-4.4.13/org/apache/http/util/EntityUtils.java @@ -0,0 +1,72 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.http.util; + +import java.io.IOException; +import java.nio.charset.Charset; +import org.apache.http.*; + + +public final class EntityUtils { + public static void consumeQuietly(final HttpEntity entity) { + } + + public static void consume(final HttpEntity entity) throws IOException { + } + + public static void updateEntity( + final HttpResponse response, final HttpEntity entity) throws IOException { + } + + public static byte[] toByteArray(final HttpEntity entity) throws IOException { + return null; + } + + public static String getContentCharSet(final HttpEntity entity) { + return null; + } + + public static String getContentMimeType(final HttpEntity entity) { + return null; + } + + public static String toString( + final HttpEntity entity, final Charset defaultCharset) throws IOException { + return null; + } + + public static String toString( + final HttpEntity entity, final String defaultCharset) throws IOException { + return null; + } + + public static String toString(final HttpEntity entity) throws IOException, ParseException { + return null; + } + +} From e3fe6350040cccd49e6fb459e98d972fc88f91ba Mon Sep 17 00:00:00 2001 From: Joe Farebrother Date: Thu, 11 Feb 2021 15:28:05 +0000 Subject: [PATCH 022/142] Add support for httpcomponents 5.x --- .../code/java/frameworks/ApacheHttp.qll | 78 +++++++++++++++---- 1 file changed, 65 insertions(+), 13 deletions(-) diff --git a/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll b/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll index 5d7ad59b560..da3e52def54 100644 --- a/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll +++ b/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll @@ -1,5 +1,5 @@ /** - * Provides classes and predicates related to `org.apache.http.*`. + * Provides classes and predicates related to `org.apache.http.*` and `org.apache.hc.*`. */ import java @@ -42,12 +42,13 @@ class TypeApacheHttpRequestBuilder extends Class { } /** - * The `request` parameter of an implementation of `org.apache.http.protocol.HttpRequestHandler.handle`. + * The `request` parameter of an implementation of `HttpRequestHandler.handle`. */ class ApacheHttpRequestHandlerParameter extends Parameter { ApacheHttpRequestHandlerParameter() { exists(Method m, Interface i | - i.hasQualifiedName("org.apache.http.protocol", "HttpRequestHandler") and + i.hasQualifiedName(["org.apache.http.protocol", "org.apache.hc.core5.http.io"], + "HttpRequestHandler") and m.getDeclaringType().extendsOrImplements+(i) and m.hasName("handle") and this = m.getParameter(0) @@ -56,7 +57,7 @@ class ApacheHttpRequestHandlerParameter extends Parameter { } /** - * A call that sets the entity of an instance of `org.apache.http.HttpResponse`. + * A call that sets the entity of an instance of `org.apache.http.HttpResponse` / `org.apache.hc.core5.http.ClassicHttpResponse`. */ class ApacheHttpResponseSetEntityCall extends MethodAccess { int arg; @@ -70,6 +71,10 @@ class ApacheHttpResponseSetEntityCall extends MethodAccess { m.getDeclaringType().hasQualifiedName("org.apache.http.util", "EntityUtils") and m.hasName("updateEntity") and arg = 1 + or + m.getDeclaringType().hasQualifiedName("org.apache.hc.core5.http", "HttpEntityContainer") and + m.hasName("setEntity") and + arg = 0 ) } @@ -79,6 +84,7 @@ class ApacheHttpResponseSetEntityCall extends MethodAccess { Expr getEntity() { result = this.getArgument(arg) } } +/** A getter that returns tainted data when its qualifier is tainted. */ private class ApacheHttpGetter extends TaintPreservingCallable { ApacheHttpGetter() { exists(string pkg, string ty, string mtd, Method m | @@ -123,6 +129,36 @@ private class ApacheHttpGetter extends TaintPreservingCallable { pkg = "org.apache.http.params" and ty = "HttpParams" and mtd.matches("get%Parameter") + or + pkg = "org.apache.hc.core5.http" and + ( + ty = "MessageHeaders" and + mtd = ["getFirstHeader", "getHeader", "getHeaders", "getLastHeader", "headerIterator"] + or + ty = "HttpRequest" and + mtd = ["getAuthority", "getPath", "getRequestUri", "getScheme", "getUri"] + or + ty = "HttpEntityContainer" and + mtd = "getEntity" + or + ty = "NameValuePair" and + mtd = ["getName", "getValue"] + or + ty = "HttpEntity" and + mtd = ["getContent", "getTrailers"] + ) + or + pkg = "org.apache.hc.core5.message" and + ty = "RequestLine" and + mtd = ["getMethod", "getUri", "toString"] + or + pkg = "org.apache.hc.core5.function" and + ty = "Supplier" and + mtd = "get" + or + pkg = "org.apache.hc.core5.net" and + ty = "UriAuthority" and + mtd = ["getHostName", "toString"] ) } @@ -131,19 +167,26 @@ private class ApacheHttpGetter extends TaintPreservingCallable { private class UtilMethod extends TaintPreservingCallable { UtilMethod() { - exists(string ty, string mtd | + exists(string pkg, string ty, string mtd | this.isStatic() and - this.getDeclaringType().hasQualifiedName("org.apache.http.util", ty) and + this.getDeclaringType().hasQualifiedName(pkg, ty) and this.hasName(mtd) | + pkg = ["org.apache.http.util", "org.apache.hc.core5.io.entity"] and ty = "EntityUtils" and - mtd = ["toString", "toByteArray", "getContentCharSet", "getContentMimeType"] + mtd = ["toString", "toByteArray", "getContentCharSet", "getContentMimeType", "parse"] or + pkg = ["org.apache.http.util", "org.apache.hc.core5.util"] and ty = "EncodingUtils" and mtd = ["getAsciiBytes", "getAsciiString", "getBytes", "getString"] or + pkg = ["org.apache.http.util", "org.apache.hc.core5.util"] and ty = "Args" and mtd = ["containsNoBlanks", "notBlank", "notEmpty", "notNull"] + or + pkg = "org.apache.hc.core5.io.entity" and + ty = "HttpEntities" and + mtd = ["create", "createGziped", "createUrlEncoded", "gzip", "withTrailers"] ) } @@ -161,25 +204,34 @@ private class EntitySetter extends TaintPreservingCallable { override predicate transfersTaint(int src, int sink) { src = 0 and sink = -1 } } -private class EntityConsructor extends TaintPreservingCallable, Constructor { - EntityConsructor() { +private class EntityConstructor extends TaintPreservingCallable, Constructor { + EntityConstructor() { this.getDeclaringType() - .hasQualifiedName("org.apache.http.entity", + .hasQualifiedName(["org.apache.http.entity", "org.apache.hc.core5.io.entity"], [ - "BufferedHttpEntity", "ByteArrayEntity", "HttpEntityWrapper", "InputStreamEntity", - "StringEntity" + "BasicHttpEntity", "BufferedHttpEntity", "ByteArrayEntity", "HttpEntityWrapper", + "InputStreamEntity", "StringEntity" ]) } override predicate returnsTaintFrom(int arg) { arg = 0 } } +private class RequestLineConstructor extends TaintPreservingCallable, Constructor { + RequestLineConstructor() { + this.getDeclaringType().hasQualifiedName("org.apache.hc.core5.http.message", "RequestLine") + } + + override predicate returnsTaintFrom(int arg) { arg = [0, 1] } +} + private class BufferMethod extends TaintPreservingCallable { BufferMethod() { exists(Method m | this.(Method).overrides*(m) and m.getDeclaringType() - .hasQualifiedName("org.apache.http.util", ["ByteArrayBuffer", "CharArrayBuffer"]) and + .hasQualifiedName(["org.apache.http.util", "org.apache.hc.core5.util"], + ["ByteArrayBuffer", "CharArrayBuffer"]) and m.hasName([ "append", "buffer", "subSequence", "substring", "substringTrimmed", "toByteAray", "toCharArray", "toString" From e5d624d1e8913349a25bc07f80f7d142ea684f71 Mon Sep 17 00:00:00 2001 From: Joe Farebrother Date: Fri, 12 Feb 2021 14:14:52 +0000 Subject: [PATCH 023/142] Add open redirect sinks --- .../code/java/frameworks/ApacheHttp.qll | 31 +++++++++++++++++++ .../semmle/code/java/security/UrlRedirect.qll | 11 +++++++ 2 files changed, 42 insertions(+) diff --git a/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll b/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll index da3e52def54..9dcac9c6efb 100644 --- a/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll +++ b/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll @@ -56,6 +56,34 @@ class ApacheHttpRequestHandlerParameter extends Parameter { } } +/** + * A call that sets a header of an `HttpResponse`. + */ +class ApacheHttpSetHeader extends Call { + ApacheHttpSetHeader() { + exists(Method m | + this.getCallee().(Method).overrides*(m) and + m.getDeclaringType() + .hasQualifiedName(["org.apache.http", "org.apache.hc.core5.http"], "HttpMessage") and + m.hasName(["addHeader", "setHeader"]) and + m.getNumberOfParameters() = 2 + ) + or + exists(Constructor c | + this.getCallee() = c and + c.getDeclaringType() + .hasQualifiedName(["org.apache.http.message", "org.apache.hc.core5.http.message"], + "BasicHeader") + ) + } + + /** Gets the expression used as the name of this header. */ + Expr getName() { result = this.getArgument(0) } + + /** Gets the expression used as the value of this header. */ + Expr getValue() { result = this.getArgument(1) } +} + /** * A call that sets the entity of an instance of `org.apache.http.HttpResponse` / `org.apache.hc.core5.http.ClassicHttpResponse`. */ @@ -146,6 +174,9 @@ private class ApacheHttpGetter extends TaintPreservingCallable { or ty = "HttpEntity" and mtd = ["getContent", "getTrailers"] + or + ty = "EntityDetails" and + mtd = ["getContentType", "getTrailerNames"] ) or pkg = "org.apache.hc.core5.message" and diff --git a/java/ql/src/semmle/code/java/security/UrlRedirect.qll b/java/ql/src/semmle/code/java/security/UrlRedirect.qll index 3f6609159ac..d2be51d2fae 100644 --- a/java/ql/src/semmle/code/java/security/UrlRedirect.qll +++ b/java/ql/src/semmle/code/java/security/UrlRedirect.qll @@ -3,6 +3,7 @@ import java import semmle.code.java.dataflow.DataFlow import semmle.code.java.frameworks.Servlets +import semmle.code.java.frameworks.ApacheHttp /** A URL redirection sink */ abstract class UrlRedirectSink extends DataFlow::Node { } @@ -24,3 +25,13 @@ private class ServletUrlRedirectSink extends UrlRedirectSink { ) } } + +/** A URL redirection sink from Apache Http components. */ +private class ApacheUrlRedirectSink extends UrlRedirectSink { + ApacheUrlRedirectSink() { + exists(ApacheHttpSetHeader c | + c.getName().(CompileTimeConstantExpr).getStringValue() = "Location" and + this.asExpr() = c.getValue() + ) + } +} From cf58a90d7468cd5d56afb0511f27247cb40585f4 Mon Sep 17 00:00:00 2001 From: Joe Farebrother Date: Mon, 15 Feb 2021 15:21:27 +0000 Subject: [PATCH 024/142] Add unit tests for utility methods --- .../code/java/frameworks/ApacheHttp.qll | 4 +- .../frameworks/apache-http/A.java | 23 ++++ .../frameworks/apache-http/flow.expected | 58 ++++---- .../frameworks/apache-http/flow.ql | 3 + .../org/apache/http/message/BasicHeader.java | 65 +++++++++ .../org/apache/http/util/Args.java | 78 +++++++++++ .../org/apache/http/util/ByteArrayBuffer.java | 93 +++++++++++++ .../org/apache/http/util/ByteBuffer.java | 0 .../org/apache/http/util/CharArrayBuffer.java | 127 ++++++++++++++++++ 9 files changed, 426 insertions(+), 25 deletions(-) create mode 100644 java/ql/test/stubs/apache-http-4.4.13/org/apache/http/message/BasicHeader.java create mode 100644 java/ql/test/stubs/apache-http-4.4.13/org/apache/http/util/Args.java create mode 100644 java/ql/test/stubs/apache-http-4.4.13/org/apache/http/util/ByteArrayBuffer.java create mode 100644 java/ql/test/stubs/apache-http-4.4.13/org/apache/http/util/ByteBuffer.java create mode 100644 java/ql/test/stubs/apache-http-4.4.13/org/apache/http/util/CharArrayBuffer.java diff --git a/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll b/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll index 9dcac9c6efb..26c3cd23b41 100644 --- a/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll +++ b/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll @@ -48,7 +48,7 @@ class ApacheHttpRequestHandlerParameter extends Parameter { ApacheHttpRequestHandlerParameter() { exists(Method m, Interface i | i.hasQualifiedName(["org.apache.http.protocol", "org.apache.hc.core5.http.io"], - "HttpRequestHandler") and + ["HttpRequestHandler", "HttpServerRequestHandler"]) and m.getDeclaringType().extendsOrImplements+(i) and m.hasName("handle") and this = m.getParameter(0) @@ -264,7 +264,7 @@ private class BufferMethod extends TaintPreservingCallable { .hasQualifiedName(["org.apache.http.util", "org.apache.hc.core5.util"], ["ByteArrayBuffer", "CharArrayBuffer"]) and m.hasName([ - "append", "buffer", "subSequence", "substring", "substringTrimmed", "toByteAray", + "append", "buffer", "subSequence", "substring", "substringTrimmed", "toByteArray", "toCharArray", "toString" ]) ) diff --git a/java/ql/test/library-tests/frameworks/apache-http/A.java b/java/ql/test/library-tests/frameworks/apache-http/A.java index 01cabeffa78..dcd574e5fd9 100644 --- a/java/ql/test/library-tests/frameworks/apache-http/A.java +++ b/java/ql/test/library-tests/frameworks/apache-http/A.java @@ -1,5 +1,6 @@ import org.apache.http.*; import org.apache.http.protocol.*; +import org.apache.http.message.BasicHeader; import org.apache.http.util.*; import org.apache.http.entity.*; @@ -36,6 +37,28 @@ class A { A.sink(EntityUtils.getContentMimeType(ent)); res.setEntity(new StringEntity("a")); EntityUtils.updateEntity(res, new ByteArrayEntity(EntityUtils.toByteArray(ent))); + res.setHeader("Location", req.getRequestLine().getUri()); + res.setHeader(new BasicHeader("Location", req.getRequestLine().getUri())); } } + + void test2() { + ByteArrayBuffer bbuf = new ByteArrayBuffer(42); + bbuf.append((byte[]) taint(), 0, 3); + sink(bbuf.buffer()); + sink(bbuf.toByteArray()); + + CharArrayBuffer cbuf = new CharArrayBuffer(42); + cbuf.append(bbuf.toByteArray(), 0, 3); + sink(cbuf.toCharArray()); + sink(cbuf.toString()); + sink(cbuf.subSequence(0, 3)); + sink(cbuf.substring(0, 3)); + sink(cbuf.substringTrimmed(0, 3)); + + sink(Args.notNull(taint(), "x")); + sink(Args.notEmpty((String) taint(), "x")); + sink(Args.notBlank((String) taint(), "x")); + sink(Args.notNull("x", (String) taint())); // Good + } } \ No newline at end of file diff --git a/java/ql/test/library-tests/frameworks/apache-http/flow.expected b/java/ql/test/library-tests/frameworks/apache-http/flow.expected index 8d2afdcd331..0ae98734ee4 100644 --- a/java/ql/test/library-tests/frameworks/apache-http/flow.expected +++ b/java/ql/test/library-tests/frameworks/apache-http/flow.expected @@ -1,23 +1,35 @@ -| A.java:12:28:12:42 | req | A.java:13:20:13:39 | getRequestLine(...) | -| A.java:12:28:12:42 | req | A.java:14:20:14:48 | getUri(...) | -| A.java:12:28:12:42 | req | A.java:15:20:15:51 | getMethod(...) | -| A.java:12:28:12:42 | req | A.java:16:20:16:38 | getAllHeaders(...) | -| A.java:12:28:12:42 | req | A.java:18:20:18:28 | next(...) | -| A.java:12:28:12:42 | req | A.java:19:20:19:34 | nextHeader(...) | -| A.java:12:28:12:42 | req | A.java:21:20:21:30 | getName(...) | -| A.java:12:28:12:42 | req | A.java:22:20:22:31 | getValue(...) | -| A.java:12:28:12:42 | req | A.java:24:20:24:31 | getName(...) | -| A.java:12:28:12:42 | req | A.java:25:20:25:32 | getValue(...) | -| A.java:12:28:12:42 | req | A.java:26:20:26:37 | getParameters(...) | -| A.java:12:28:12:42 | req | A.java:27:20:27:58 | getValue(...) | -| A.java:12:28:12:42 | req | A.java:28:20:28:47 | getName(...) | -| A.java:12:28:12:42 | req | A.java:30:20:30:35 | getContent(...) | -| A.java:12:28:12:42 | req | A.java:31:20:31:43 | getContentEncoding(...) | -| A.java:12:28:12:42 | req | A.java:32:20:32:39 | getContentType(...) | -| A.java:12:28:12:42 | req | A.java:33:20:33:44 | toString(...) | -| A.java:12:28:12:42 | req | A.java:34:20:34:47 | toByteArray(...) | -| A.java:12:28:12:42 | req | A.java:35:20:35:53 | getContentCharSet(...) | -| A.java:12:28:12:42 | req | A.java:36:20:36:54 | getContentMimeType(...) | -| A.java:12:28:12:42 | req | A.java:37:27:37:99 | new StringEntity(...) | -| A.java:12:28:12:42 | req | A.java:38:43:38:91 | new ByteArrayEntity(...) | -| A.java:30:20:30:35 | getContent(...) | A.java:30:20:30:35 | getContent(...) | +| A.java:13:28:13:42 | req | A.java:14:20:14:39 | getRequestLine(...) | +| A.java:13:28:13:42 | req | A.java:15:20:15:48 | getUri(...) | +| A.java:13:28:13:42 | req | A.java:16:20:16:51 | getMethod(...) | +| A.java:13:28:13:42 | req | A.java:17:20:17:38 | getAllHeaders(...) | +| A.java:13:28:13:42 | req | A.java:19:20:19:28 | next(...) | +| A.java:13:28:13:42 | req | A.java:20:20:20:34 | nextHeader(...) | +| A.java:13:28:13:42 | req | A.java:22:20:22:30 | getName(...) | +| A.java:13:28:13:42 | req | A.java:23:20:23:31 | getValue(...) | +| A.java:13:28:13:42 | req | A.java:25:20:25:31 | getName(...) | +| A.java:13:28:13:42 | req | A.java:26:20:26:32 | getValue(...) | +| A.java:13:28:13:42 | req | A.java:27:20:27:37 | getParameters(...) | +| A.java:13:28:13:42 | req | A.java:28:20:28:58 | getValue(...) | +| A.java:13:28:13:42 | req | A.java:29:20:29:47 | getName(...) | +| A.java:13:28:13:42 | req | A.java:31:20:31:35 | getContent(...) | +| A.java:13:28:13:42 | req | A.java:32:20:32:43 | getContentEncoding(...) | +| A.java:13:28:13:42 | req | A.java:33:20:33:39 | getContentType(...) | +| A.java:13:28:13:42 | req | A.java:34:20:34:44 | toString(...) | +| A.java:13:28:13:42 | req | A.java:35:20:35:47 | toByteArray(...) | +| A.java:13:28:13:42 | req | A.java:36:20:36:53 | getContentCharSet(...) | +| A.java:13:28:13:42 | req | A.java:37:20:37:54 | getContentMimeType(...) | +| A.java:13:28:13:42 | req | A.java:38:27:38:99 | new StringEntity(...) | +| A.java:13:28:13:42 | req | A.java:39:43:39:91 | new ByteArrayEntity(...) | +| A.java:13:28:13:42 | req | A.java:40:39:40:67 | getUri(...) | +| A.java:13:28:13:42 | req | A.java:41:55:41:83 | getUri(...) | +| A.java:31:20:31:35 | getContent(...) | A.java:31:20:31:35 | getContent(...) | +| A.java:47:30:47:36 | taint(...) | A.java:48:14:48:26 | buffer(...) | +| A.java:47:30:47:36 | taint(...) | A.java:49:14:49:31 | toByteArray(...) | +| A.java:47:30:47:36 | taint(...) | A.java:53:14:53:31 | toCharArray(...) | +| A.java:47:30:47:36 | taint(...) | A.java:54:14:54:28 | toString(...) | +| A.java:47:30:47:36 | taint(...) | A.java:55:14:55:35 | subSequence(...) | +| A.java:47:30:47:36 | taint(...) | A.java:56:14:56:33 | substring(...) | +| A.java:47:30:47:36 | taint(...) | A.java:57:14:57:40 | substringTrimmed(...) | +| A.java:59:27:59:33 | taint(...) | A.java:59:14:59:39 | notNull(...) | +| A.java:60:37:60:43 | taint(...) | A.java:60:14:60:49 | notEmpty(...) | +| A.java:61:37:61:43 | taint(...) | A.java:61:14:61:49 | notBlank(...) | diff --git a/java/ql/test/library-tests/frameworks/apache-http/flow.ql b/java/ql/test/library-tests/frameworks/apache-http/flow.ql index c8d1589159a..0648efeac8f 100644 --- a/java/ql/test/library-tests/frameworks/apache-http/flow.ql +++ b/java/ql/test/library-tests/frameworks/apache-http/flow.ql @@ -2,6 +2,7 @@ import java import semmle.code.java.dataflow.TaintTracking import semmle.code.java.dataflow.FlowSources import semmle.code.java.security.XSS +import semmle.code.java.security.UrlRedirect class Conf extends TaintTracking::Configuration { Conf() { this = "qltest:frameworks:apache-http" } @@ -16,6 +17,8 @@ class Conf extends TaintTracking::Configuration { exists(MethodAccess ma | ma.getMethod().hasName("sink") | n.asExpr() = ma.getAnArgument()) or n instanceof XssSink + or + n instanceof UrlRedirectSink } } diff --git a/java/ql/test/stubs/apache-http-4.4.13/org/apache/http/message/BasicHeader.java b/java/ql/test/stubs/apache-http-4.4.13/org/apache/http/message/BasicHeader.java new file mode 100644 index 00000000000..052c3abc0f8 --- /dev/null +++ b/java/ql/test/stubs/apache-http-4.4.13/org/apache/http/message/BasicHeader.java @@ -0,0 +1,65 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.http.message; + +import java.io.Serializable; + +import org.apache.http.Header; +import org.apache.http.HeaderElement; +import org.apache.http.ParseException; + +public class BasicHeader implements Header, Cloneable, Serializable { + public BasicHeader(final String name, final String value) { + } + + @Override + public Object clone() throws CloneNotSupportedException { + return null; + } + + @Override + public HeaderElement[] getElements() throws ParseException { + return null; + } + + @Override + public String getName() { + return null; + } + + @Override + public String getValue() { + return null; + } + + @Override + public String toString() { + return null; + } + +} diff --git a/java/ql/test/stubs/apache-http-4.4.13/org/apache/http/util/Args.java b/java/ql/test/stubs/apache-http-4.4.13/org/apache/http/util/Args.java new file mode 100644 index 00000000000..60b314d1ca0 --- /dev/null +++ b/java/ql/test/stubs/apache-http-4.4.13/org/apache/http/util/Args.java @@ -0,0 +1,78 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.http.util; + +import java.util.Collection; + +public class Args { + public static void check(final boolean expression, final String message) { + } + + public static void check(final boolean expression, final String message, final Object... args) { + } + + public static void check(final boolean expression, final String message, final Object arg) { + } + + public static T notNull(final T argument, final String name) { + return null; + } + + public static T notEmpty(final T argument, final String name) { + return null; + } + + public static T notBlank(final T argument, final String name) { + return null; + } + + public static T containsNoBlanks(final T argument, final String name) { + return null; + } + + public static > T notEmpty(final T argument, final String name) { + return null; + } + + public static int positive(final int n, final String name) { + return 0; + } + + public static long positive(final long n, final String name) { + return 0; + } + + public static int notNegative(final int n, final String name) { + return 0; + } + + public static long notNegative(final long n, final String name) { + return 0; + } + +} diff --git a/java/ql/test/stubs/apache-http-4.4.13/org/apache/http/util/ByteArrayBuffer.java b/java/ql/test/stubs/apache-http-4.4.13/org/apache/http/util/ByteArrayBuffer.java new file mode 100644 index 00000000000..9bc34144de1 --- /dev/null +++ b/java/ql/test/stubs/apache-http-4.4.13/org/apache/http/util/ByteArrayBuffer.java @@ -0,0 +1,93 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.http.util; + +import java.io.Serializable; + +public final class ByteArrayBuffer implements Serializable { + public ByteArrayBuffer(final int capacity) { + } + + public void append(final byte[] b, final int off, final int len) { + } + + public void append(final int b) { + } + + public void append(final char[] b, final int off, final int len) { + } + + public void append(final CharArrayBuffer b, final int off, final int len) { + } + + public void clear() { + } + + public byte[] toByteArray() { + return null; + } + + public int byteAt(final int i) { + return 0; + } + + public int capacity() { + return 0; + } + + public int length() { + return 0; + } + + public void ensureCapacity(final int required) { + } + + public byte[] buffer() { + return null; + } + + public void setLength(final int len) { + } + + public boolean isEmpty() { + return false; + } + + public boolean isFull() { + return false; + } + + public int indexOf(final byte b, final int from, final int to) { + return 0; + } + + public int indexOf(final byte b) { + return 0; + } + +} diff --git a/java/ql/test/stubs/apache-http-4.4.13/org/apache/http/util/ByteBuffer.java b/java/ql/test/stubs/apache-http-4.4.13/org/apache/http/util/ByteBuffer.java new file mode 100644 index 00000000000..e69de29bb2d diff --git a/java/ql/test/stubs/apache-http-4.4.13/org/apache/http/util/CharArrayBuffer.java b/java/ql/test/stubs/apache-http-4.4.13/org/apache/http/util/CharArrayBuffer.java new file mode 100644 index 00000000000..465962e362e --- /dev/null +++ b/java/ql/test/stubs/apache-http-4.4.13/org/apache/http/util/CharArrayBuffer.java @@ -0,0 +1,127 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.http.util; + +import java.io.Serializable; +import java.nio.CharBuffer; + + +public final class CharArrayBuffer implements CharSequence, Serializable { + public CharArrayBuffer(final int capacity) { + } + + public void append(final char[] b, final int off, final int len) { + } + + public void append(final String str) { + } + + public void append(final CharArrayBuffer b, final int off, final int len) { + } + + public void append(final CharArrayBuffer b) { + } + + public void append(final char ch) { + } + + public void append(final byte[] b, final int off, final int len) { + } + + public void append(final ByteArrayBuffer b, final int off, final int len) { + } + + public void append(final Object obj) { + } + + public void clear() { + } + + public char[] toCharArray() { + return null; + } + + @Override + public char charAt(final int i) { + return 0; + } + + public char[] buffer() { + return null; + } + + public int capacity() { + return 0; + } + + @Override + public int length() { + return 0; + } + + public void ensureCapacity(final int required) { + } + + public void setLength(final int len) { + } + + public boolean isEmpty() { + return false; + } + + public boolean isFull() { + return false; + } + + public int indexOf(final int ch, final int from, final int to) { + return 0; + } + + public int indexOf(final int ch) { + return 0; + } + + public String substring(final int beginIndex, final int endIndex) { + return null; + } + + public String substringTrimmed(final int beginIndex, final int endIndex) { + return null; + } + + @Override + public CharSequence subSequence(final int beginIndex, final int endIndex) { + return null; + } + + @Override + public String toString() { + return null; + } + +} From 7b5961769a79a23ef8a62ec53238209a4bc9247c Mon Sep 17 00:00:00 2001 From: Joe Farebrother Date: Wed, 17 Feb 2021 14:52:52 +0000 Subject: [PATCH 025/142] Add unit tests for version 5.x --- .../code/java/frameworks/ApacheHttp.qll | 5 +- .../frameworks/apache-http/A.java | 3 +- .../frameworks/apache-http/B.java | 68 ++++++++ .../frameworks/apache-http/flow.expected | 94 +++++++---- .../frameworks/apache-http/options | 2 +- .../apache/hc/core5/function/Supplier.java | 33 ++++ .../hc/core5/http/ClassicHttpRequest.java | 36 ++++ .../hc/core5/http/ClassicHttpResponse.java | 33 ++++ .../org/apache/hc/core5/http/ContentType.java | 159 ++++++++++++++++++ .../apache/hc/core5/http/EntityDetails.java | 43 +++++ .../org/apache/hc/core5/http/Header.java | 39 +++++ .../org/apache/hc/core5/http/HttpEntity.java | 48 ++++++ .../hc/core5/http/HttpEntityContainer.java | 40 +++++ .../apache/hc/core5/http/HttpException.java | 48 ++++++ .../org/apache/hc/core5/http/HttpMessage.java | 55 ++++++ .../org/apache/hc/core5/http/HttpRequest.java | 56 ++++++ .../apache/hc/core5/http/HttpResponse.java | 45 +++++ .../apache/hc/core5/http/MessageHeaders.java | 51 ++++++ .../apache/hc/core5/http/NameValuePair.java | 40 +++++ .../apache/hc/core5/http/ParseException.java | 52 ++++++ .../hc/core5/http/ProtocolException.java | 49 ++++++ .../apache/hc/core5/http/ProtocolVersion.java | 87 ++++++++++ .../hc/core5/http/io/HttpRequestHandler.java | 41 +++++ .../http/io/entity/AbstractHttpEntity.java | 86 ++++++++++ .../core5/http/io/entity/ByteArrayEntity.java | 92 ++++++++++ .../http/io/entity/ByteBufferEntity.java | 65 +++++++ .../hc/core5/http/io/entity/EntityUtils.java | 89 ++++++++++ .../hc/core5/http/io/entity/HttpEntities.java | 152 +++++++++++++++++ .../hc/core5/http/io/entity/StringEntity.java | 83 +++++++++ .../hc/core5/http/message/BasicHeader.java | 59 +++++++ .../hc/core5/http/message/RequestLine.java | 61 +++++++ .../hc/core5/http/protocol/HttpContext.java | 42 +++++ .../org/apache/hc/core5/io/IOCallback.java | 34 ++++ .../org/apache/hc/core5/net/URIAuthority.java | 55 ++++++ .../org/apache/hc/core5/util/Args.java | 93 ++++++++++ .../apache/hc/core5/util/ByteArrayBuffer.java | 97 +++++++++++ .../apache/hc/core5/util/CharArrayBuffer.java | 125 ++++++++++++++ 37 files changed, 2221 insertions(+), 39 deletions(-) create mode 100644 java/ql/test/library-tests/frameworks/apache-http/B.java create mode 100644 java/ql/test/stubs/apache-http-5/org/apache/hc/core5/function/Supplier.java create mode 100644 java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/ClassicHttpRequest.java create mode 100644 java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/ClassicHttpResponse.java create mode 100644 java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/ContentType.java create mode 100644 java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/EntityDetails.java create mode 100644 java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/Header.java create mode 100644 java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/HttpEntity.java create mode 100644 java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/HttpEntityContainer.java create mode 100644 java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/HttpException.java create mode 100644 java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/HttpMessage.java create mode 100644 java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/HttpRequest.java create mode 100644 java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/HttpResponse.java create mode 100644 java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/MessageHeaders.java create mode 100644 java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/NameValuePair.java create mode 100644 java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/ParseException.java create mode 100644 java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/ProtocolException.java create mode 100644 java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/ProtocolVersion.java create mode 100644 java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/io/HttpRequestHandler.java create mode 100644 java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/io/entity/AbstractHttpEntity.java create mode 100644 java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/io/entity/ByteArrayEntity.java create mode 100644 java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/io/entity/ByteBufferEntity.java create mode 100644 java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/io/entity/EntityUtils.java create mode 100644 java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/io/entity/HttpEntities.java create mode 100644 java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/io/entity/StringEntity.java create mode 100644 java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/message/BasicHeader.java create mode 100644 java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/message/RequestLine.java create mode 100644 java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/protocol/HttpContext.java create mode 100644 java/ql/test/stubs/apache-http-5/org/apache/hc/core5/io/IOCallback.java create mode 100644 java/ql/test/stubs/apache-http-5/org/apache/hc/core5/net/URIAuthority.java create mode 100644 java/ql/test/stubs/apache-http-5/org/apache/hc/core5/util/Args.java create mode 100644 java/ql/test/stubs/apache-http-5/org/apache/hc/core5/util/ByteArrayBuffer.java create mode 100644 java/ql/test/stubs/apache-http-5/org/apache/hc/core5/util/CharArrayBuffer.java diff --git a/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll b/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll index 26c3cd23b41..ccbdcf99d69 100644 --- a/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll +++ b/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll @@ -41,6 +41,7 @@ class TypeApacheHttpRequestBuilder extends Class { } } +// TODO: Other sources /** * The `request` parameter of an implementation of `HttpRequestHandler.handle`. */ @@ -264,8 +265,8 @@ private class BufferMethod extends TaintPreservingCallable { .hasQualifiedName(["org.apache.http.util", "org.apache.hc.core5.util"], ["ByteArrayBuffer", "CharArrayBuffer"]) and m.hasName([ - "append", "buffer", "subSequence", "substring", "substringTrimmed", "toByteArray", - "toCharArray", "toString" + "append", "array", "buffer", "subSequence", "substring", "substringTrimmed", + "toByteArray", "toCharArray", "toString" ]) ) } diff --git a/java/ql/test/library-tests/frameworks/apache-http/A.java b/java/ql/test/library-tests/frameworks/apache-http/A.java index dcd574e5fd9..1dcfd3d8fa3 100644 --- a/java/ql/test/library-tests/frameworks/apache-http/A.java +++ b/java/ql/test/library-tests/frameworks/apache-http/A.java @@ -3,6 +3,7 @@ import org.apache.http.protocol.*; import org.apache.http.message.BasicHeader; import org.apache.http.util.*; import org.apache.http.entity.*; +import java.io.IOException; class A { static Object taint() { return null; } @@ -10,7 +11,7 @@ class A { static void sink(Object o) { } class Test1 implements HttpRequestHandler { - public void handle(HttpRequest req, HttpResponse res, HttpContext ctx) { + public void handle(HttpRequest req, HttpResponse res, HttpContext ctx) throws IOException { A.sink(req.getRequestLine()); A.sink(req.getRequestLine().getUri()); A.sink(req.getRequestLine().getMethod()); diff --git a/java/ql/test/library-tests/frameworks/apache-http/B.java b/java/ql/test/library-tests/frameworks/apache-http/B.java new file mode 100644 index 00000000000..abb6ccd0a4b --- /dev/null +++ b/java/ql/test/library-tests/frameworks/apache-http/B.java @@ -0,0 +1,68 @@ +import org.apache.hc.core5.http.*; +import org.apache.hc.core5.http.protocol.HttpContext; +import org.apache.hc.core5.http.io.HttpRequestHandler; +import org.apache.hc.core5.http.message.*; +import org.apache.hc.core5.http.io.entity.*; +import org.apache.hc.core5.util.*; +import java.io.IOException; + +class B { + static Object taint() { return null; } + + static void sink(Object o) { } + + class Test1 implements HttpRequestHandler { + public void handle(ClassicHttpRequest req, ClassicHttpResponse res, HttpContext ctx) throws IOException, ParseException { + B.sink(req.getAuthority().getHostName()); + B.sink(req.getAuthority().toString()); + B.sink(req.getMethod()); + B.sink(req.getPath()); + B.sink(req.getScheme()); + B.sink(req.getRequestUri()); + RequestLine line = new RequestLine(req); + B.sink(line.getUri()); + B.sink(line.getMethod()); + B.sink(req.getHeaders()); + B.sink(req.headerIterator()); + Header h = req.getHeaders("abc")[3]; + B.sink(h.getName()); + B.sink(h.getValue()); + B.sink(req.getFirstHeader("abc")); + B.sink(req.getLastHeader("abc")); + HttpEntity ent = req.getEntity(); + B.sink(ent.getContent()); + B.sink(ent.getContentEncoding()); + B.sink(ent.getContentType()); + B.sink(ent.getTrailerNames()); + B.sink(ent.getTrailers().get()); + B.sink(EntityUtils.toString(ent)); + B.sink(EntityUtils.toByteArray(ent)); + B.sink(EntityUtils.parse(ent)); + res.setEntity(new StringEntity("a")); + res.setEntity(new ByteArrayEntity(EntityUtils.toByteArray(ent), ContentType.TEXT_HTML)); + res.setEntity(HttpEntities.create("a")); + res.setHeader("Location", req.getRequestUri()); + res.setHeader(new BasicHeader("Location", req.getRequestUri())); + } + } + + void test2() { + ByteArrayBuffer bbuf = new ByteArrayBuffer(42); + bbuf.append((byte[]) taint(), 0, 3); + sink(bbuf.array()); + sink(bbuf.toByteArray()); + + CharArrayBuffer cbuf = new CharArrayBuffer(42); + cbuf.append(bbuf.toByteArray(), 0, 3); + sink(cbuf.toCharArray()); + sink(cbuf.toString()); + sink(cbuf.subSequence(0, 3)); + sink(cbuf.substring(0, 3)); + sink(cbuf.substringTrimmed(0, 3)); + + sink(Args.notNull(taint(), "x")); + sink(Args.notEmpty((String) taint(), "x")); + sink(Args.notBlank((String) taint(), "x")); + sink(Args.notNull("x", (String) taint())); // Good + } +} \ No newline at end of file diff --git a/java/ql/test/library-tests/frameworks/apache-http/flow.expected b/java/ql/test/library-tests/frameworks/apache-http/flow.expected index 0ae98734ee4..23cb0296211 100644 --- a/java/ql/test/library-tests/frameworks/apache-http/flow.expected +++ b/java/ql/test/library-tests/frameworks/apache-http/flow.expected @@ -1,35 +1,59 @@ -| A.java:13:28:13:42 | req | A.java:14:20:14:39 | getRequestLine(...) | -| A.java:13:28:13:42 | req | A.java:15:20:15:48 | getUri(...) | -| A.java:13:28:13:42 | req | A.java:16:20:16:51 | getMethod(...) | -| A.java:13:28:13:42 | req | A.java:17:20:17:38 | getAllHeaders(...) | -| A.java:13:28:13:42 | req | A.java:19:20:19:28 | next(...) | -| A.java:13:28:13:42 | req | A.java:20:20:20:34 | nextHeader(...) | -| A.java:13:28:13:42 | req | A.java:22:20:22:30 | getName(...) | -| A.java:13:28:13:42 | req | A.java:23:20:23:31 | getValue(...) | -| A.java:13:28:13:42 | req | A.java:25:20:25:31 | getName(...) | -| A.java:13:28:13:42 | req | A.java:26:20:26:32 | getValue(...) | -| A.java:13:28:13:42 | req | A.java:27:20:27:37 | getParameters(...) | -| A.java:13:28:13:42 | req | A.java:28:20:28:58 | getValue(...) | -| A.java:13:28:13:42 | req | A.java:29:20:29:47 | getName(...) | -| A.java:13:28:13:42 | req | A.java:31:20:31:35 | getContent(...) | -| A.java:13:28:13:42 | req | A.java:32:20:32:43 | getContentEncoding(...) | -| A.java:13:28:13:42 | req | A.java:33:20:33:39 | getContentType(...) | -| A.java:13:28:13:42 | req | A.java:34:20:34:44 | toString(...) | -| A.java:13:28:13:42 | req | A.java:35:20:35:47 | toByteArray(...) | -| A.java:13:28:13:42 | req | A.java:36:20:36:53 | getContentCharSet(...) | -| A.java:13:28:13:42 | req | A.java:37:20:37:54 | getContentMimeType(...) | -| A.java:13:28:13:42 | req | A.java:38:27:38:99 | new StringEntity(...) | -| A.java:13:28:13:42 | req | A.java:39:43:39:91 | new ByteArrayEntity(...) | -| A.java:13:28:13:42 | req | A.java:40:39:40:67 | getUri(...) | -| A.java:13:28:13:42 | req | A.java:41:55:41:83 | getUri(...) | -| A.java:31:20:31:35 | getContent(...) | A.java:31:20:31:35 | getContent(...) | -| A.java:47:30:47:36 | taint(...) | A.java:48:14:48:26 | buffer(...) | -| A.java:47:30:47:36 | taint(...) | A.java:49:14:49:31 | toByteArray(...) | -| A.java:47:30:47:36 | taint(...) | A.java:53:14:53:31 | toCharArray(...) | -| A.java:47:30:47:36 | taint(...) | A.java:54:14:54:28 | toString(...) | -| A.java:47:30:47:36 | taint(...) | A.java:55:14:55:35 | subSequence(...) | -| A.java:47:30:47:36 | taint(...) | A.java:56:14:56:33 | substring(...) | -| A.java:47:30:47:36 | taint(...) | A.java:57:14:57:40 | substringTrimmed(...) | -| A.java:59:27:59:33 | taint(...) | A.java:59:14:59:39 | notNull(...) | -| A.java:60:37:60:43 | taint(...) | A.java:60:14:60:49 | notEmpty(...) | -| A.java:61:37:61:43 | taint(...) | A.java:61:14:61:49 | notBlank(...) | +| A.java:14:28:14:42 | req | A.java:15:20:15:39 | getRequestLine(...) | +| A.java:14:28:14:42 | req | A.java:16:20:16:48 | getUri(...) | +| A.java:14:28:14:42 | req | A.java:17:20:17:51 | getMethod(...) | +| A.java:14:28:14:42 | req | A.java:18:20:18:38 | getAllHeaders(...) | +| A.java:14:28:14:42 | req | A.java:20:20:20:28 | next(...) | +| A.java:14:28:14:42 | req | A.java:21:20:21:34 | nextHeader(...) | +| A.java:14:28:14:42 | req | A.java:23:20:23:30 | getName(...) | +| A.java:14:28:14:42 | req | A.java:24:20:24:31 | getValue(...) | +| A.java:14:28:14:42 | req | A.java:26:20:26:31 | getName(...) | +| A.java:14:28:14:42 | req | A.java:27:20:27:32 | getValue(...) | +| A.java:14:28:14:42 | req | A.java:28:20:28:37 | getParameters(...) | +| A.java:14:28:14:42 | req | A.java:29:20:29:58 | getValue(...) | +| A.java:14:28:14:42 | req | A.java:30:20:30:47 | getName(...) | +| A.java:14:28:14:42 | req | A.java:32:20:32:35 | getContent(...) | +| A.java:14:28:14:42 | req | A.java:33:20:33:43 | getContentEncoding(...) | +| A.java:14:28:14:42 | req | A.java:34:20:34:39 | getContentType(...) | +| A.java:14:28:14:42 | req | A.java:35:20:35:44 | toString(...) | +| A.java:14:28:14:42 | req | A.java:36:20:36:47 | toByteArray(...) | +| A.java:14:28:14:42 | req | A.java:37:20:37:53 | getContentCharSet(...) | +| A.java:14:28:14:42 | req | A.java:38:20:38:54 | getContentMimeType(...) | +| A.java:14:28:14:42 | req | A.java:39:27:39:99 | new StringEntity(...) | +| A.java:14:28:14:42 | req | A.java:40:43:40:91 | new ByteArrayEntity(...) | +| A.java:14:28:14:42 | req | A.java:41:39:41:67 | getUri(...) | +| A.java:14:28:14:42 | req | A.java:42:55:42:83 | getUri(...) | +| A.java:32:20:32:35 | getContent(...) | A.java:32:20:32:35 | getContent(...) | +| A.java:48:30:48:36 | taint(...) | A.java:49:14:49:26 | buffer(...) | +| A.java:48:30:48:36 | taint(...) | A.java:50:14:50:31 | toByteArray(...) | +| A.java:48:30:48:36 | taint(...) | A.java:54:14:54:31 | toCharArray(...) | +| A.java:48:30:48:36 | taint(...) | A.java:55:14:55:28 | toString(...) | +| A.java:48:30:48:36 | taint(...) | A.java:56:14:56:35 | subSequence(...) | +| A.java:48:30:48:36 | taint(...) | A.java:57:14:57:33 | substring(...) | +| A.java:48:30:48:36 | taint(...) | A.java:58:14:58:40 | substringTrimmed(...) | +| A.java:60:27:60:33 | taint(...) | A.java:60:14:60:39 | notNull(...) | +| A.java:61:37:61:43 | taint(...) | A.java:61:14:61:49 | notEmpty(...) | +| A.java:62:37:62:43 | taint(...) | A.java:62:14:62:49 | notBlank(...) | +| B.java:15:28:15:49 | req | B.java:19:20:19:32 | getPath(...) | +| B.java:15:28:15:49 | req | B.java:20:20:20:34 | getScheme(...) | +| B.java:15:28:15:49 | req | B.java:21:20:21:38 | getRequestUri(...) | +| B.java:15:28:15:49 | req | B.java:25:20:25:35 | getHeaders(...) | +| B.java:15:28:15:49 | req | B.java:26:20:26:39 | headerIterator(...) | +| B.java:15:28:15:49 | req | B.java:28:20:28:30 | getName(...) | +| B.java:15:28:15:49 | req | B.java:29:20:29:31 | getValue(...) | +| B.java:15:28:15:49 | req | B.java:30:20:30:44 | getFirstHeader(...) | +| B.java:15:28:15:49 | req | B.java:31:20:31:43 | getLastHeader(...) | +| B.java:15:28:15:49 | req | B.java:33:20:33:35 | getContent(...) | +| B.java:15:28:15:49 | req | B.java:35:20:35:39 | getContentType(...) | +| B.java:15:28:15:49 | req | B.java:36:20:36:40 | getTrailerNames(...) | +| B.java:15:28:15:49 | req | B.java:44:39:44:57 | getRequestUri(...) | +| B.java:15:28:15:49 | req | B.java:45:55:45:73 | getRequestUri(...) | +| B.java:51:30:51:36 | taint(...) | B.java:52:14:52:25 | array(...) | +| B.java:51:30:51:36 | taint(...) | B.java:53:14:53:31 | toByteArray(...) | +| B.java:51:30:51:36 | taint(...) | B.java:57:14:57:31 | toCharArray(...) | +| B.java:51:30:51:36 | taint(...) | B.java:58:14:58:28 | toString(...) | +| B.java:51:30:51:36 | taint(...) | B.java:59:14:59:35 | subSequence(...) | +| B.java:51:30:51:36 | taint(...) | B.java:60:14:60:33 | substring(...) | +| B.java:51:30:51:36 | taint(...) | B.java:61:14:61:40 | substringTrimmed(...) | +| B.java:63:27:63:33 | taint(...) | B.java:63:14:63:39 | notNull(...) | +| B.java:64:37:64:43 | taint(...) | B.java:64:14:64:49 | notEmpty(...) | +| B.java:65:37:65:43 | taint(...) | B.java:65:14:65:49 | notBlank(...) | diff --git a/java/ql/test/library-tests/frameworks/apache-http/options b/java/ql/test/library-tests/frameworks/apache-http/options index 7a49a36a4c6..50ea0f87825 100644 --- a/java/ql/test/library-tests/frameworks/apache-http/options +++ b/java/ql/test/library-tests/frameworks/apache-http/options @@ -1 +1 @@ -//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/apache-http-4.4.13 \ No newline at end of file +//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/apache-http-4.4.13:${testdir}/../../../stubs/apache-http-5 \ No newline at end of file diff --git a/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/function/Supplier.java b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/function/Supplier.java new file mode 100644 index 00000000000..c847728f32f --- /dev/null +++ b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/function/Supplier.java @@ -0,0 +1,33 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.core5.function; + +public interface Supplier { + T get(); + +} diff --git a/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/ClassicHttpRequest.java b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/ClassicHttpRequest.java new file mode 100644 index 00000000000..9997a4f0cb1 --- /dev/null +++ b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/ClassicHttpRequest.java @@ -0,0 +1,36 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.core5.http; + +/** + * 'Classic' {@link HttpRequest} message that can enclose {@link HttpEntity}. + * + * @since 5.0 + */ +public interface ClassicHttpRequest extends HttpRequest, HttpEntityContainer { +} diff --git a/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/ClassicHttpResponse.java b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/ClassicHttpResponse.java new file mode 100644 index 00000000000..571f1b0c420 --- /dev/null +++ b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/ClassicHttpResponse.java @@ -0,0 +1,33 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.core5.http; + +import java.io.Closeable; + +public interface ClassicHttpResponse extends HttpResponse, HttpEntityContainer, Closeable { +} diff --git a/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/ContentType.java b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/ContentType.java new file mode 100644 index 00000000000..f7d3ffc21a3 --- /dev/null +++ b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/ContentType.java @@ -0,0 +1,159 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.core5.http; +import java.io.Serializable; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.charset.UnsupportedCharsetException; + +public final class ContentType implements Serializable { + public static final ContentType APPLICATION_ATOM_XML = null; + + public static final ContentType APPLICATION_FORM_URLENCODED = null; + + public static final ContentType APPLICATION_JSON = null; + + public static final ContentType APPLICATION_NDJSON = null; + + public static final ContentType APPLICATION_OCTET_STREAM = null; + + public static final ContentType APPLICATION_PDF = null; + + public static final ContentType APPLICATION_SOAP_XML = null; + + public static final ContentType APPLICATION_SVG_XML = null; + + public static final ContentType APPLICATION_XHTML_XML = null; + + public static final ContentType APPLICATION_XML = null; + + public static final ContentType APPLICATION_PROBLEM_JSON = null; + + public static final ContentType APPLICATION_PROBLEM_XML = null; + + public static final ContentType APPLICATION_RSS_XML = null; + + public static final ContentType IMAGE_BMP = null; + + public static final ContentType IMAGE_GIF = null; + + public static final ContentType IMAGE_JPEG = null; + + public static final ContentType IMAGE_PNG = null; + + public static final ContentType IMAGE_SVG = null; + + public static final ContentType IMAGE_TIFF = null; + + public static final ContentType IMAGE_WEBP = null; + + public static final ContentType MULTIPART_FORM_DATA = null; + + public static final ContentType MULTIPART_MIXED = null; + + public static final ContentType MULTIPART_RELATED = null; + + public static final ContentType TEXT_HTML = null; + + public static final ContentType TEXT_MARKDOWN = null; + + public static final ContentType TEXT_PLAIN = null; + + public static final ContentType TEXT_XML = null; + + public static final ContentType TEXT_EVENT_STREAM = null; + + public static final ContentType WILDCARD = null; + + private static final NameValuePair[] EMPTY_NAME_VALUE_PAIR_ARRAY = new NameValuePair[0]; + + public String getMimeType() { + return null; + } + + public Charset getCharset() { + return null; + } + + public String getParameter(final String name) { + return null; + } + + @Override + public String toString() { + return null; + } + + public static ContentType create(final String mimeType, final Charset charset) { + return null; + } + + public static ContentType create(final String mimeType) { + return null; + } + + public static ContentType create( + final String mimeType, final String charset) throws UnsupportedCharsetException { + return null; + } + + public static ContentType create( + final String mimeType, final NameValuePair... params) throws UnsupportedCharsetException { + return null; + } + + public static ContentType parse(final CharSequence s) throws UnsupportedCharsetException { + return null; + } + + public static ContentType parseLenient(final CharSequence s) throws UnsupportedCharsetException { + return null; + } + + public static ContentType getByMimeType(final String mimeType) { + return null; + } + + public ContentType withCharset(final Charset charset) { + return null; + } + + public ContentType withCharset(final String charset) { + return null; + } + + public ContentType withParameters( + final NameValuePair... params) throws UnsupportedCharsetException { + return null; + } + + public boolean isSameMimeType(final ContentType contentType) { + return false; + } + +} diff --git a/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/EntityDetails.java b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/EntityDetails.java new file mode 100644 index 00000000000..bed26e033f7 --- /dev/null +++ b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/EntityDetails.java @@ -0,0 +1,43 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.core5.http; + +import java.util.Set; + +public interface EntityDetails { + long getContentLength(); + + String getContentType(); + + String getContentEncoding(); + + boolean isChunked(); + + Set getTrailerNames(); + +} diff --git a/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/Header.java b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/Header.java new file mode 100644 index 00000000000..888e80e1748 --- /dev/null +++ b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/Header.java @@ -0,0 +1,39 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.core5.http; + +/** + * Represents an HTTP header field consisting of a field name and a field + * value. + * + * @since 4.0 + */ +public interface Header extends NameValuePair { + boolean isSensitive(); + +} diff --git a/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/HttpEntity.java b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/HttpEntity.java new file mode 100644 index 00000000000..02f47cd4e41 --- /dev/null +++ b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/HttpEntity.java @@ -0,0 +1,48 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.core5.http; + +import java.io.Closeable; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.List; + +import org.apache.hc.core5.function.Supplier; + +public interface HttpEntity extends EntityDetails, Closeable { + boolean isRepeatable(); + + InputStream getContent() throws IOException, UnsupportedOperationException; + + void writeTo(OutputStream outStream) throws IOException; + + boolean isStreaming(); + Supplier> getTrailers(); + +} diff --git a/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/HttpEntityContainer.java b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/HttpEntityContainer.java new file mode 100644 index 00000000000..dbde2e9966c --- /dev/null +++ b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/HttpEntityContainer.java @@ -0,0 +1,40 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.core5.http; + +/** + * Contains an {@link HttpEntity}. + * + * @since 5.0 + */ +public interface HttpEntityContainer { + HttpEntity getEntity(); + + void setEntity(HttpEntity entity); + +} diff --git a/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/HttpException.java b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/HttpException.java new file mode 100644 index 00000000000..a5943cf543f --- /dev/null +++ b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/HttpException.java @@ -0,0 +1,48 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.core5.http; + +/** + * Signals that an HTTP exception has occurred. + * + * @since 4.0 + */ +public class HttpException extends Exception { + public HttpException() { + } + + public HttpException(final String message) { + } + + public HttpException(final String format, final Object... args) { + } + + public HttpException(final String message, final Throwable cause) { + } + +} diff --git a/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/HttpMessage.java b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/HttpMessage.java new file mode 100644 index 00000000000..425e3a2719c --- /dev/null +++ b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/HttpMessage.java @@ -0,0 +1,55 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.core5.http; + +/** + * HTTP messages consist of requests from client to server and responses + * from server to client. + * + * @since 4.0 + */ +public interface HttpMessage extends MessageHeaders { + void setVersion(ProtocolVersion version); + + ProtocolVersion getVersion(); + + void addHeader(Header header); + + void addHeader(String name, Object value); + + void setHeader(Header header); + + void setHeader(String name, Object value); + + void setHeaders(Header... headers); + + boolean removeHeader(Header header); + + boolean removeHeaders(String name); + +} diff --git a/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/HttpRequest.java b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/HttpRequest.java new file mode 100644 index 00000000000..e16c157b030 --- /dev/null +++ b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/HttpRequest.java @@ -0,0 +1,56 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.core5.http; + +import java.net.URI; +import java.net.URISyntaxException; + +import org.apache.hc.core5.net.URIAuthority; + +public interface HttpRequest extends HttpMessage { + String getMethod(); + + String getPath(); + + void setPath(String path); + + String getScheme(); + + void setScheme(String scheme); + + URIAuthority getAuthority(); + + void setAuthority(URIAuthority authority); + + String getRequestUri(); + + URI getUri() throws URISyntaxException; + + void setUri(final URI requestUri); + +} diff --git a/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/HttpResponse.java b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/HttpResponse.java new file mode 100644 index 00000000000..4a962d484ff --- /dev/null +++ b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/HttpResponse.java @@ -0,0 +1,45 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.core5.http; + +import java.util.Locale; + +public interface HttpResponse extends HttpMessage { + int getCode(); + + void setCode(int code); + + String getReasonPhrase(); + + void setReasonPhrase(String reason); + + Locale getLocale(); + + void setLocale(Locale loc); + +} diff --git a/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/MessageHeaders.java b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/MessageHeaders.java new file mode 100644 index 00000000000..374910f5f2b --- /dev/null +++ b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/MessageHeaders.java @@ -0,0 +1,51 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.core5.http; + +import java.util.Iterator; + +public interface MessageHeaders { + boolean containsHeader(String name); + + int countHeaders(String name); + + Header getFirstHeader(String name); + + Header getHeader(String name) throws ProtocolException; + + Header[] getHeaders(); + + Header[] getHeaders(String name); + + Header getLastHeader(String name); + + Iterator
headerIterator(); + + Iterator
headerIterator(String name); + +} diff --git a/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/NameValuePair.java b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/NameValuePair.java new file mode 100644 index 00000000000..b7e793994db --- /dev/null +++ b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/NameValuePair.java @@ -0,0 +1,40 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.core5.http; + +/** + * A name-value pair parameter used as an element of HTTP messages. + * + * @since 4.0 + */ +public interface NameValuePair { + String getName(); + + String getValue(); + +} diff --git a/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/ParseException.java b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/ParseException.java new file mode 100644 index 00000000000..c0c180c7a8c --- /dev/null +++ b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/ParseException.java @@ -0,0 +1,52 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.core5.http; + +/** + * Signals a protocol exception due to failure to parse a message element. + * + * @since 4.0 + */ +public class ParseException extends ProtocolException { + public ParseException() { + } + + public ParseException(final String message) { + } + + public ParseException(final String description, final CharSequence text, final int off, final int len, final int errorOffset) { + } + + public ParseException(final String description, final CharSequence text, final int off, final int len) { + } + + public int getErrorOffset() { + return 0; + } + +} diff --git a/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/ProtocolException.java b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/ProtocolException.java new file mode 100644 index 00000000000..fee74e55bba --- /dev/null +++ b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/ProtocolException.java @@ -0,0 +1,49 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.core5.http; + +/** + * Signals that an HTTP protocol violation has occurred. + * For example a malformed status line or headers, a missing message body, etc. + * + * @since 4.0 + */ +public class ProtocolException extends HttpException { + public ProtocolException() { + } + + public ProtocolException(final String message) { + } + + public ProtocolException(final String format, final Object... args) { + } + + public ProtocolException(final String message, final Throwable cause) { + } + +} diff --git a/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/ProtocolVersion.java b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/ProtocolVersion.java new file mode 100644 index 00000000000..37f17cf8b8d --- /dev/null +++ b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/ProtocolVersion.java @@ -0,0 +1,87 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.core5.http; + +import java.io.Serializable; + +public class ProtocolVersion implements Serializable { + public ProtocolVersion(final String protocol, final int major, final int minor) { + } + + public final String getProtocol() { + return null; + } + + public final int getMajor() { + return 0; + } + + public final int getMinor() { + return 0; + } + + @Override + public final int hashCode() { + return 0; + } + + public final boolean equals(final int major, final int minor) { + return false; + } + + @Override + public final boolean equals(final Object obj) { + return false; + } + + public String format() { + return null; + } + + public boolean isComparable(final ProtocolVersion that) { + return false; + } + + public int compareToVersion(final ProtocolVersion that) { + return 0; + } + + public final boolean greaterEquals(final ProtocolVersion version) { + return false; + } + + public final boolean lessEquals(final ProtocolVersion version) { + return false; + } + + @Override + public String toString() { + return null; + } + +} diff --git a/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/io/HttpRequestHandler.java b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/io/HttpRequestHandler.java new file mode 100644 index 00000000000..13197bc3de4 --- /dev/null +++ b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/io/HttpRequestHandler.java @@ -0,0 +1,41 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.core5.http.io; + +import java.io.IOException; + +import org.apache.hc.core5.http.ClassicHttpRequest; +import org.apache.hc.core5.http.ClassicHttpResponse; +import org.apache.hc.core5.http.HttpException; +import org.apache.hc.core5.http.protocol.HttpContext; + +public interface HttpRequestHandler { + void handle(ClassicHttpRequest request, ClassicHttpResponse response, HttpContext context) + throws HttpException, IOException; + +} diff --git a/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/io/entity/AbstractHttpEntity.java b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/io/entity/AbstractHttpEntity.java new file mode 100644 index 00000000000..68af8819fe0 --- /dev/null +++ b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/io/entity/AbstractHttpEntity.java @@ -0,0 +1,86 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.core5.http.io.entity; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.Collections; +import java.util.List; +import java.util.Set; + +import org.apache.hc.core5.function.Supplier; +import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.Header; +import org.apache.hc.core5.http.HttpEntity; +import org.apache.hc.core5.util.Args; + +public abstract class AbstractHttpEntity implements HttpEntity { + public static void writeTo(final HttpEntity entity, final OutputStream outStream) throws IOException { + } + + @Override + public void writeTo(final OutputStream outStream) throws IOException { + } + + @Override + public final String getContentType() { + return null; + } + + @Override + public final String getContentEncoding() { + return null; + } + + @Override + public final boolean isChunked() { + return false; + } + + @Override + public boolean isRepeatable() { + return false; + } + + @Override + public Supplier> getTrailers() { + return null; + } + + @Override + public Set getTrailerNames() { + return null; + } + + @Override + public String toString() { + return null; + } + +} diff --git a/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/io/entity/ByteArrayEntity.java b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/io/entity/ByteArrayEntity.java new file mode 100644 index 00000000000..d0f9b715050 --- /dev/null +++ b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/io/entity/ByteArrayEntity.java @@ -0,0 +1,92 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.core5.http.io.entity; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import org.apache.hc.core5.http.ContentType; + +public class ByteArrayEntity extends AbstractHttpEntity { + public ByteArrayEntity( + final byte[] b, final int off, final int len, final ContentType contentType, final String contentEncoding, + final boolean chunked) { + } + + public ByteArrayEntity( + final byte[] b, final int off, final int len, final ContentType contentType, final String contentEncoding) { + } + + public ByteArrayEntity( + final byte[] b, final ContentType contentType, final String contentEncoding, final boolean chunked) { + } + + public ByteArrayEntity(final byte[] b, final ContentType contentType, final String contentEncoding) { + } + + public ByteArrayEntity(final byte[] b, final ContentType contentType, final boolean chunked) { + } + + public ByteArrayEntity(final byte[] b, final ContentType contentType) { + } + + public ByteArrayEntity( + final byte[] b, final int off, final int len, final ContentType contentType, final boolean chunked) { + } + + public ByteArrayEntity(final byte[] b, final int off, final int len, final ContentType contentType) { + } + + @Override + public final boolean isRepeatable() { + return false; + } + + @Override + public final long getContentLength() { + return 0; + } + + @Override + public final InputStream getContent() { + return null; + } + + @Override + public final void writeTo(final OutputStream outStream) throws IOException { + } + + @Override + public final boolean isStreaming() { + return false; + } + + @Override + public final void close() throws IOException { + } + +} diff --git a/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/io/entity/ByteBufferEntity.java b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/io/entity/ByteBufferEntity.java new file mode 100644 index 00000000000..555ccd69fe5 --- /dev/null +++ b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/io/entity/ByteBufferEntity.java @@ -0,0 +1,65 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.core5.http.io.entity; +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import org.apache.hc.core5.http.ContentType; + +public class ByteBufferEntity extends AbstractHttpEntity { + public ByteBufferEntity(final ByteBuffer buffer, final ContentType contentType, final String contentEncoding) { + } + + public ByteBufferEntity(final ByteBuffer buffer, final ContentType contentType) { + } + + @Override + public final boolean isRepeatable() { + return false; + } + + @Override + public final long getContentLength() { + return 0; + } + + @Override + public final InputStream getContent() throws IOException, UnsupportedOperationException { + return null; + } + + @Override + public final boolean isStreaming() { + return false; + } + + @Override + public final void close() throws IOException { + } + +} diff --git a/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/io/entity/EntityUtils.java b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/io/entity/EntityUtils.java new file mode 100644 index 00000000000..cbf7bfda9bb --- /dev/null +++ b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/io/entity/EntityUtils.java @@ -0,0 +1,89 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.core5.http.io.entity; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.util.List; + +import org.apache.hc.core5.http.HttpEntity; +import org.apache.hc.core5.http.NameValuePair; +import org.apache.hc.core5.http.ParseException; + +public final class EntityUtils { + public static void consumeQuietly(final HttpEntity entity) { + } + + public static void consume(final HttpEntity entity) throws IOException { + } + + public static byte[] toByteArray(final HttpEntity entity) throws IOException { + return null; + } + + public static byte[] toByteArray(final HttpEntity entity, final int maxResultLength) throws IOException { + return null; + } + + public static String toString( + final HttpEntity entity, final Charset defaultCharset) throws IOException, ParseException { + return null; + } + + public static String toString( + final HttpEntity entity, final Charset defaultCharset, final int maxResultLength) throws IOException, ParseException { + return null; + } + + public static String toString( + final HttpEntity entity, final String defaultCharset) throws IOException, ParseException { + return null; + } + + public static String toString( + final HttpEntity entity, final String defaultCharset, final int maxResultLength) throws IOException, ParseException { + return null; + } + + public static String toString(final HttpEntity entity) throws IOException, ParseException { + return null; + } + + public static String toString(final HttpEntity entity, final int maxResultLength) throws IOException, ParseException { + return null; + } + + public static List parse(final HttpEntity entity) throws IOException { + return null; + } + + public static List parse(final HttpEntity entity, final int maxStreamLength) throws IOException { + return null; + } + +} diff --git a/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/io/entity/HttpEntities.java b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/io/entity/HttpEntities.java new file mode 100644 index 00000000000..d7e532439f4 --- /dev/null +++ b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/io/entity/HttpEntities.java @@ -0,0 +1,152 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.core5.http.io.entity; +import java.io.File; +import java.io.OutputStream; +import java.io.Serializable; +import java.nio.charset.Charset; +import java.nio.file.Path; +import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.Header; +import org.apache.hc.core5.http.HttpEntity; +import org.apache.hc.core5.http.NameValuePair; +import org.apache.hc.core5.io.IOCallback; + +public final class HttpEntities { + public static HttpEntity create(final String content, final ContentType contentType) { + return null; + } + + public static HttpEntity create(final String content, final Charset charset) { + return null; + } + + public static HttpEntity create(final String content) { + return null; + } + + public static HttpEntity create(final byte[] content, final ContentType contentType) { + return null; + } + + public static HttpEntity create(final File content, final ContentType contentType) { + return null; + } + + public static HttpEntity create(final Serializable serializable, final ContentType contentType) { + return null; + } + + public static HttpEntity createUrlEncoded( + final Iterable parameters, final Charset charset) { + return null; + } + + public static HttpEntity create(final IOCallback callback, final ContentType contentType) { + return null; + } + + public static HttpEntity gzip(final HttpEntity entity) { + return null; + } + + public static HttpEntity createGzipped(final String content, final ContentType contentType) { + return null; + } + + public static HttpEntity createGzipped(final String content, final Charset charset) { + return null; + } + + public static HttpEntity createGzipped(final String content) { + return null; + } + + public static HttpEntity createGzipped(final byte[] content, final ContentType contentType) { + return null; + } + + public static HttpEntity createGzipped(final File content, final ContentType contentType) { + return null; + } + + public static HttpEntity createGzipped(final Serializable serializable, final ContentType contentType) { + return null; + } + + public static HttpEntity createGzipped(final IOCallback callback, final ContentType contentType) { + return null; + } + + public static HttpEntity createGzipped(final Path content, final ContentType contentType) { + return null; + } + + public static HttpEntity withTrailers(final HttpEntity entity, final Header... trailers) { + return null; + } + + public static HttpEntity create(final String content, final ContentType contentType, final Header... trailers) { + return null; + } + + public static HttpEntity create(final String content, final Charset charset, final Header... trailers) { + return null; + } + + public static HttpEntity create(final String content, final Header... trailers) { + return null; + } + + public static HttpEntity create(final byte[] content, final ContentType contentType, final Header... trailers) { + return null; + } + + public static HttpEntity create(final File content, final ContentType contentType, final Header... trailers) { + return null; + } + + public static HttpEntity create( + final Serializable serializable, final ContentType contentType, final Header... trailers) { + return null; + } + + public static HttpEntity create( + final IOCallback callback, final ContentType contentType, final Header... trailers) { + return null; + } + + public static HttpEntity create(final Path content, final ContentType contentType) { + return null; + } + + public static HttpEntity create(final Path content, final ContentType contentType, final Header... trailers) { + return null; + } + +} diff --git a/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/io/entity/StringEntity.java b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/io/entity/StringEntity.java new file mode 100644 index 00000000000..649ce534350 --- /dev/null +++ b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/io/entity/StringEntity.java @@ -0,0 +1,83 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.core5.http.io.entity; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.charset.Charset; +import org.apache.hc.core5.http.ContentType; + +public class StringEntity extends AbstractHttpEntity { + public StringEntity( + final String string, final ContentType contentType, final String contentEncoding, final boolean chunked) { + } + + public StringEntity(final String string, final ContentType contentType, final boolean chunked) { + } + + public StringEntity(final String string, final ContentType contentType) { + } + + public StringEntity(final String string, final Charset charset) { + } + + public StringEntity(final String string, final Charset charset, final boolean chunked) { + } + + public StringEntity(final String string) { + } + + @Override + public final boolean isRepeatable() { + return false; + } + + @Override + public final long getContentLength() { + return 0; + } + + @Override + public final InputStream getContent() throws IOException { + return null; + } + + @Override + public final void writeTo(final OutputStream outStream) throws IOException { + } + + @Override + public final boolean isStreaming() { + return false; + } + + @Override + public final void close() throws IOException { + } + +} diff --git a/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/message/BasicHeader.java b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/message/BasicHeader.java new file mode 100644 index 00000000000..64a2d3d8668 --- /dev/null +++ b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/message/BasicHeader.java @@ -0,0 +1,59 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.core5.http.message; +import java.io.Serializable; +import org.apache.hc.core5.http.Header; + +public class BasicHeader implements Header, Cloneable, Serializable { + public BasicHeader(final String name, final Object value) { + } + + public BasicHeader(final String name, final Object value, final boolean sensitive) { + } + + @Override + public String getName() { + return null; + } + + @Override + public String getValue() { + return null; + } + + @Override + public boolean isSensitive() { + return false; + } + + @Override + public String toString() { + return null; + } + +} diff --git a/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/message/RequestLine.java b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/message/RequestLine.java new file mode 100644 index 00000000000..86f1aaab695 --- /dev/null +++ b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/message/RequestLine.java @@ -0,0 +1,61 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.core5.http.message; + +import java.io.Serializable; + +import org.apache.hc.core5.http.HttpRequest; +import org.apache.hc.core5.http.ProtocolVersion; + +public final class RequestLine implements Serializable { + public RequestLine(final HttpRequest request) { + } + + public RequestLine(final String method, + final String uri, + final ProtocolVersion version) { + } + + public String getMethod() { + return null; + } + + public ProtocolVersion getProtocolVersion() { + return null; + } + + public String getUri() { + return null; + } + + @Override + public String toString() { + return null; + } + +} diff --git a/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/protocol/HttpContext.java b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/protocol/HttpContext.java new file mode 100644 index 00000000000..1506409dc25 --- /dev/null +++ b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/protocol/HttpContext.java @@ -0,0 +1,42 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.core5.http.protocol; +import org.apache.hc.core5.http.ProtocolVersion; + +public interface HttpContext { + ProtocolVersion getProtocolVersion(); + + void setProtocolVersion(ProtocolVersion version); + + Object getAttribute(String id); + + Object setAttribute(String id, Object obj); + + Object removeAttribute(String id); + +} diff --git a/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/io/IOCallback.java b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/io/IOCallback.java new file mode 100644 index 00000000000..9e1f7f9c7ac --- /dev/null +++ b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/io/IOCallback.java @@ -0,0 +1,34 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.core5.io; +import java.io.IOException; + +public interface IOCallback { + void execute(T object) throws IOException; + +} diff --git a/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/net/URIAuthority.java b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/net/URIAuthority.java new file mode 100644 index 00000000000..3bb5158370a --- /dev/null +++ b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/net/URIAuthority.java @@ -0,0 +1,55 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.core5.net; + +public final class URIAuthority { + public String getUserInfo() { + return null; + } + + public String getHostName() { + return null; + } + + public int getPort() { + return 0; + } + + public String toString() { + return null; + } + + public boolean equals(final Object obj) { + return false; + } + + public int hashCode() { + return 0; + } + +} diff --git a/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/util/Args.java b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/util/Args.java new file mode 100644 index 00000000000..3e1a70bfca3 --- /dev/null +++ b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/util/Args.java @@ -0,0 +1,93 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.core5.util; + +import org.apache.hc.core5.http.EntityDetails; + +import java.util.Collection; + +public class Args { + public static void check(final boolean expression, final String message) { + } + + public static void check(final boolean expression, final String message, final Object... args) { + } + + public static void check(final boolean expression, final String message, final Object arg) { + } + + public static long checkContentLength(final EntityDetails entityDetails) { + return 0; + } + + public static int checkRange(final int value, final int lowInclusive, final int highInclusive, + final String message) { + return 0; + } + + public static long checkRange(final long value, final long lowInclusive, final long highInclusive, + final String message) { + return 0; + } + + public static T containsNoBlanks(final T argument, final String name) { + return null; + } + + public static T notBlank(final T argument, final String name) { + return null; + } + + public static T notEmpty(final T argument, final String name) { + return null; + } + + public static > T notEmpty(final T argument, final String name) { + return null; + } + + public static int notNegative(final int n, final String name) { + return 0; + } + + public static long notNegative(final long n, final String name) { + return 0; + } + + public static T notNull(final T argument, final String name) { + return null; + } + + public static int positive(final int n, final String name) { + return 0; + } + + public static long positive(final long n, final String name) { + return 0; + } +} diff --git a/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/util/ByteArrayBuffer.java b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/util/ByteArrayBuffer.java new file mode 100644 index 00000000000..43f131d9405 --- /dev/null +++ b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/util/ByteArrayBuffer.java @@ -0,0 +1,97 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.core5.util; + +import java.io.Serializable; +import java.nio.ByteBuffer; + +public final class ByteArrayBuffer implements Serializable { + public ByteArrayBuffer(final int capacity) { + } + + public void append(final byte[] b, final int off, final int len) { + } + + public void append(final int b) { + } + + public void append(final char[] b, final int off, final int len) { + } + + public void append(final CharArrayBuffer b, final int off, final int len) { + } + + public void append(final ByteBuffer buffer) { + } + + public void clear() { + } + + public byte[] toByteArray() { + return null; + } + + public int byteAt(final int i) { + return 0; + } + + public int capacity() { + return 0; + } + + public int length() { + return 0; + } + + public void ensureCapacity(final int required) { + } + + public byte[] array() { + return null; + } + + public void setLength(final int len) { + } + + public boolean isEmpty() { + return false; + } + + public boolean isFull() { + return false; + } + + public int indexOf(final byte b, final int from, final int to) { + return 0; + } + + public int indexOf(final byte b) { + return 0; + } + +} diff --git a/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/util/CharArrayBuffer.java b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/util/CharArrayBuffer.java new file mode 100644 index 00000000000..41b51b2113d --- /dev/null +++ b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/util/CharArrayBuffer.java @@ -0,0 +1,125 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ + +package org.apache.hc.core5.util; + +import java.io.Serializable; + +public final class CharArrayBuffer implements CharSequence, Serializable { + public CharArrayBuffer(final int capacity) { + } + + public void append(final char[] b, final int off, final int len) { + } + + public void append(final String str) { + } + + public void append(final CharArrayBuffer b, final int off, final int len) { + } + + public void append(final CharArrayBuffer b) { + } + + public void append(final char ch) { + } + + public void append(final byte[] b, final int off, final int len) { + } + + public void append(final ByteArrayBuffer b, final int off, final int len) { + } + + public void append(final Object obj) { + } + + public void clear() { + } + + public char[] toCharArray() { + return null; + } + + @Override + public char charAt(final int i) { + return 0; + } + + public char[] array() { + return null; + } + + public int capacity() { + return 0; + } + + @Override + public int length() { + return 0; + } + + public void ensureCapacity(final int required) { + } + + public void setLength(final int len) { + } + + public boolean isEmpty() { + return false; + } + + public boolean isFull() { + return false; + } + + public int indexOf(final int ch, final int from, final int to) { + return 0; + } + + public int indexOf(final int ch) { + return 0; + } + + public String substring(final int beginIndex, final int endIndex) { + return null; + } + + public String substringTrimmed(final int beginIndex, final int endIndex) { + return null; + } + + @Override + public CharSequence subSequence(final int beginIndex, final int endIndex) { + return null; + } + + @Override + public String toString() { + return null; + } + +} From a3b8d4ab2dabc9b6e1b92ffa2b9e79b99977d5ff Mon Sep 17 00:00:00 2001 From: Joe Farebrother Date: Wed, 17 Feb 2021 17:54:57 +0000 Subject: [PATCH 026/142] Switch to inline test expectations; fix failing test outputs --- .../code/java/frameworks/ApacheHttp.qll | 16 ++-- .../frameworks/apache-http/A.java | 68 ++++++++-------- .../frameworks/apache-http/B.java | 78 +++++++++---------- .../frameworks/apache-http/flow.expected | 59 -------------- .../frameworks/apache-http/flow.ql | 18 ++++- 5 files changed, 96 insertions(+), 143 deletions(-) diff --git a/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll b/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll index ccbdcf99d69..14978b97072 100644 --- a/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll +++ b/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll @@ -118,7 +118,7 @@ private class ApacheHttpGetter extends TaintPreservingCallable { ApacheHttpGetter() { exists(string pkg, string ty, string mtd, Method m | this.(Method).overrides*(m) and - m.getDeclaringType().hasQualifiedName(pkg, ty) and + m.getDeclaringType().getSourceDeclaration().hasQualifiedName(pkg, ty) and m.hasName(mtd) | pkg = "org.apache.http" and @@ -165,7 +165,7 @@ private class ApacheHttpGetter extends TaintPreservingCallable { mtd = ["getFirstHeader", "getHeader", "getHeaders", "getLastHeader", "headerIterator"] or ty = "HttpRequest" and - mtd = ["getAuthority", "getPath", "getRequestUri", "getScheme", "getUri"] + mtd = ["getAuthority", "getMethod", "getPath", "getRequestUri", "getUri"] or ty = "HttpEntityContainer" and mtd = "getEntity" @@ -177,10 +177,10 @@ private class ApacheHttpGetter extends TaintPreservingCallable { mtd = ["getContent", "getTrailers"] or ty = "EntityDetails" and - mtd = ["getContentType", "getTrailerNames"] + mtd = ["getContentType", "getContentEncoding", "getTrailerNames"] ) or - pkg = "org.apache.hc.core5.message" and + pkg = "org.apache.hc.core5.http.message" and ty = "RequestLine" and mtd = ["getMethod", "getUri", "toString"] or @@ -189,7 +189,7 @@ private class ApacheHttpGetter extends TaintPreservingCallable { mtd = "get" or pkg = "org.apache.hc.core5.net" and - ty = "UriAuthority" and + ty = "URIAuthority" and mtd = ["getHostName", "toString"] ) } @@ -204,7 +204,7 @@ private class UtilMethod extends TaintPreservingCallable { this.getDeclaringType().hasQualifiedName(pkg, ty) and this.hasName(mtd) | - pkg = ["org.apache.http.util", "org.apache.hc.core5.io.entity"] and + pkg = ["org.apache.http.util", "org.apache.hc.core5.http.io.entity"] and ty = "EntityUtils" and mtd = ["toString", "toByteArray", "getContentCharSet", "getContentMimeType", "parse"] or @@ -216,7 +216,7 @@ private class UtilMethod extends TaintPreservingCallable { ty = "Args" and mtd = ["containsNoBlanks", "notBlank", "notEmpty", "notNull"] or - pkg = "org.apache.hc.core5.io.entity" and + pkg = "org.apache.hc.core5.http.io.entity" and ty = "HttpEntities" and mtd = ["create", "createGziped", "createUrlEncoded", "gzip", "withTrailers"] ) @@ -239,7 +239,7 @@ private class EntitySetter extends TaintPreservingCallable { private class EntityConstructor extends TaintPreservingCallable, Constructor { EntityConstructor() { this.getDeclaringType() - .hasQualifiedName(["org.apache.http.entity", "org.apache.hc.core5.io.entity"], + .hasQualifiedName(["org.apache.http.entity", "org.apache.hc.core5.http.io.entity"], [ "BasicHttpEntity", "BufferedHttpEntity", "ByteArrayEntity", "HttpEntityWrapper", "InputStreamEntity", "StringEntity" diff --git a/java/ql/test/library-tests/frameworks/apache-http/A.java b/java/ql/test/library-tests/frameworks/apache-http/A.java index 1dcfd3d8fa3..cb09b291860 100644 --- a/java/ql/test/library-tests/frameworks/apache-http/A.java +++ b/java/ql/test/library-tests/frameworks/apache-http/A.java @@ -12,54 +12,54 @@ class A { class Test1 implements HttpRequestHandler { public void handle(HttpRequest req, HttpResponse res, HttpContext ctx) throws IOException { - A.sink(req.getRequestLine()); - A.sink(req.getRequestLine().getUri()); - A.sink(req.getRequestLine().getMethod()); - A.sink(req.getAllHeaders()); + A.sink(req.getRequestLine()); //$hasTaintFlow=y + A.sink(req.getRequestLine().getUri()); //$hasTaintFlow=y + A.sink(req.getRequestLine().getMethod()); //$hasTaintFlow=y + A.sink(req.getAllHeaders()); //$hasTaintFlow=y HeaderIterator it = req.headerIterator(); - A.sink(it.next()); - A.sink(it.nextHeader()); + A.sink(it.next()); //$hasTaintFlow=y + A.sink(it.nextHeader()); //$hasTaintFlow=y Header h = req.getHeaders("abc")[3]; - A.sink(h.getName()); - A.sink(h.getValue()); + A.sink(h.getName()); //$hasTaintFlow=y + A.sink(h.getValue()); //$hasTaintFlow=y HeaderElement el = h.getElements()[0]; - A.sink(el.getName()); - A.sink(el.getValue()); - A.sink(el.getParameters()); - A.sink(el.getParameterByName("abc").getValue()); - A.sink(el.getParameter(0).getName()); + A.sink(el.getName()); //$hasTaintFlow=y + A.sink(el.getValue()); //$hasTaintFlow=y + A.sink(el.getParameters()); //$hasTaintFlow=y + A.sink(el.getParameterByName("abc").getValue()); //$hasTaintFlow=y + A.sink(el.getParameter(0).getName()); //$hasTaintFlow=y HttpEntity ent = ((HttpEntityEnclosingRequest)req).getEntity(); - A.sink(ent.getContent()); - A.sink(ent.getContentEncoding()); - A.sink(ent.getContentType()); - A.sink(EntityUtils.toString(ent)); - A.sink(EntityUtils.toByteArray(ent)); - A.sink(EntityUtils.getContentCharSet(ent)); - A.sink(EntityUtils.getContentMimeType(ent)); - res.setEntity(new StringEntity("a")); - EntityUtils.updateEntity(res, new ByteArrayEntity(EntityUtils.toByteArray(ent))); - res.setHeader("Location", req.getRequestLine().getUri()); - res.setHeader(new BasicHeader("Location", req.getRequestLine().getUri())); + A.sink(ent.getContent()); //$hasTaintFlow=y + A.sink(ent.getContentEncoding()); //$hasTaintFlow=y + A.sink(ent.getContentType()); //$hasTaintFlow=y + A.sink(EntityUtils.toString(ent)); //$hasTaintFlow=y + A.sink(EntityUtils.toByteArray(ent)); //$hasTaintFlow=y + A.sink(EntityUtils.getContentCharSet(ent)); //$hasTaintFlow=y + A.sink(EntityUtils.getContentMimeType(ent)); //$hasTaintFlow=y + res.setEntity(new StringEntity("a")); //$hasTaintFlow=y + EntityUtils.updateEntity(res, new ByteArrayEntity(EntityUtils.toByteArray(ent))); //$hasTaintFlow=y + res.setHeader("Location", req.getRequestLine().getUri()); //$hasTaintFlow=y + res.setHeader(new BasicHeader("Location", req.getRequestLine().getUri())); //$hasTaintFlow=y } } void test2() { ByteArrayBuffer bbuf = new ByteArrayBuffer(42); bbuf.append((byte[]) taint(), 0, 3); - sink(bbuf.buffer()); - sink(bbuf.toByteArray()); + sink(bbuf.buffer()); //$hasTaintFlow=y + sink(bbuf.toByteArray()); //$hasTaintFlow=y CharArrayBuffer cbuf = new CharArrayBuffer(42); cbuf.append(bbuf.toByteArray(), 0, 3); - sink(cbuf.toCharArray()); - sink(cbuf.toString()); - sink(cbuf.subSequence(0, 3)); - sink(cbuf.substring(0, 3)); - sink(cbuf.substringTrimmed(0, 3)); + sink(cbuf.toCharArray()); //$hasTaintFlow=y + sink(cbuf.toString()); //$hasTaintFlow=y + sink(cbuf.subSequence(0, 3)); //$hasTaintFlow=y + sink(cbuf.substring(0, 3)); //$hasTaintFlow=y + sink(cbuf.substringTrimmed(0, 3)); //$hasTaintFlow=y - sink(Args.notNull(taint(), "x")); - sink(Args.notEmpty((String) taint(), "x")); - sink(Args.notBlank((String) taint(), "x")); + sink(Args.notNull(taint(), "x")); //$hasTaintFlow=y + sink(Args.notEmpty((String) taint(), "x")); //$hasTaintFlow=y + sink(Args.notBlank((String) taint(), "x")); //$hasTaintFlow=y sink(Args.notNull("x", (String) taint())); // Good } } \ No newline at end of file diff --git a/java/ql/test/library-tests/frameworks/apache-http/B.java b/java/ql/test/library-tests/frameworks/apache-http/B.java index abb6ccd0a4b..09cb24797e5 100644 --- a/java/ql/test/library-tests/frameworks/apache-http/B.java +++ b/java/ql/test/library-tests/frameworks/apache-http/B.java @@ -13,56 +13,56 @@ class B { class Test1 implements HttpRequestHandler { public void handle(ClassicHttpRequest req, ClassicHttpResponse res, HttpContext ctx) throws IOException, ParseException { - B.sink(req.getAuthority().getHostName()); - B.sink(req.getAuthority().toString()); - B.sink(req.getMethod()); - B.sink(req.getPath()); - B.sink(req.getScheme()); - B.sink(req.getRequestUri()); + B.sink(req.getAuthority().getHostName()); //$hasTaintFlow=y + B.sink(req.getAuthority().toString()); //$hasTaintFlow=y + B.sink(req.getMethod()); //$hasTaintFlow=y + B.sink(req.getPath()); //$hasTaintFlow=y + B.sink(req.getScheme()); + B.sink(req.getRequestUri()); //$hasTaintFlow=y RequestLine line = new RequestLine(req); - B.sink(line.getUri()); - B.sink(line.getMethod()); - B.sink(req.getHeaders()); - B.sink(req.headerIterator()); + B.sink(line.getUri()); //$hasTaintFlow=y + B.sink(line.getMethod()); //$hasTaintFlow=y + B.sink(req.getHeaders()); //$hasTaintFlow=y + B.sink(req.headerIterator()); //$hasTaintFlow=y Header h = req.getHeaders("abc")[3]; - B.sink(h.getName()); - B.sink(h.getValue()); - B.sink(req.getFirstHeader("abc")); - B.sink(req.getLastHeader("abc")); + B.sink(h.getName()); //$hasTaintFlow=y + B.sink(h.getValue()); //$hasTaintFlow=y + B.sink(req.getFirstHeader("abc")); //$hasTaintFlow=y + B.sink(req.getLastHeader("abc")); //$hasTaintFlow=y HttpEntity ent = req.getEntity(); - B.sink(ent.getContent()); - B.sink(ent.getContentEncoding()); - B.sink(ent.getContentType()); - B.sink(ent.getTrailerNames()); - B.sink(ent.getTrailers().get()); - B.sink(EntityUtils.toString(ent)); - B.sink(EntityUtils.toByteArray(ent)); - B.sink(EntityUtils.parse(ent)); - res.setEntity(new StringEntity("a")); - res.setEntity(new ByteArrayEntity(EntityUtils.toByteArray(ent), ContentType.TEXT_HTML)); - res.setEntity(HttpEntities.create("a")); - res.setHeader("Location", req.getRequestUri()); - res.setHeader(new BasicHeader("Location", req.getRequestUri())); + B.sink(ent.getContent()); //$hasTaintFlow=y + B.sink(ent.getContentEncoding()); //$hasTaintFlow=y + B.sink(ent.getContentType()); //$hasTaintFlow=y + B.sink(ent.getTrailerNames()); //$hasTaintFlow=y + B.sink(ent.getTrailers().get()); //$hasTaintFlow=y + B.sink(EntityUtils.toString(ent)); //$hasTaintFlow=y + B.sink(EntityUtils.toByteArray(ent)); //$hasTaintFlow=y + B.sink(EntityUtils.parse(ent)); //$hasTaintFlow=y + res.setEntity(new StringEntity("a")); //$hasTaintFlow=y + res.setEntity(new ByteArrayEntity(EntityUtils.toByteArray(ent), ContentType.TEXT_HTML)); //$hasTaintFlow=y + res.setEntity(HttpEntities.create("a")); //$hasTaintFlow=y + res.setHeader("Location", req.getRequestUri()); //$hasTaintFlow=y + res.setHeader(new BasicHeader("Location", req.getRequestUri())); //$hasTaintFlow=y } } void test2() { ByteArrayBuffer bbuf = new ByteArrayBuffer(42); - bbuf.append((byte[]) taint(), 0, 3); - sink(bbuf.array()); - sink(bbuf.toByteArray()); + bbuf.append((byte[]) taint(), 0, 3); + sink(bbuf.array()); //$hasTaintFlow=y + sink(bbuf.toByteArray()); //$hasTaintFlow=y CharArrayBuffer cbuf = new CharArrayBuffer(42); - cbuf.append(bbuf.toByteArray(), 0, 3); - sink(cbuf.toCharArray()); - sink(cbuf.toString()); - sink(cbuf.subSequence(0, 3)); - sink(cbuf.substring(0, 3)); - sink(cbuf.substringTrimmed(0, 3)); + cbuf.append(bbuf.toByteArray(), 0, 3); + sink(cbuf.toCharArray()); //$hasTaintFlow=y + sink(cbuf.toString()); //$hasTaintFlow=y + sink(cbuf.subSequence(0, 3)); //$hasTaintFlow=y + sink(cbuf.substring(0, 3)); //$hasTaintFlow=y + sink(cbuf.substringTrimmed(0, 3)); //$hasTaintFlow=y - sink(Args.notNull(taint(), "x")); - sink(Args.notEmpty((String) taint(), "x")); - sink(Args.notBlank((String) taint(), "x")); + sink(Args.notNull(taint(), "x")); //$hasTaintFlow=y + sink(Args.notEmpty((String) taint(), "x")); //$hasTaintFlow=y + sink(Args.notBlank((String) taint(), "x")); //$hasTaintFlow=y sink(Args.notNull("x", (String) taint())); // Good } } \ No newline at end of file diff --git a/java/ql/test/library-tests/frameworks/apache-http/flow.expected b/java/ql/test/library-tests/frameworks/apache-http/flow.expected index 23cb0296211..e69de29bb2d 100644 --- a/java/ql/test/library-tests/frameworks/apache-http/flow.expected +++ b/java/ql/test/library-tests/frameworks/apache-http/flow.expected @@ -1,59 +0,0 @@ -| A.java:14:28:14:42 | req | A.java:15:20:15:39 | getRequestLine(...) | -| A.java:14:28:14:42 | req | A.java:16:20:16:48 | getUri(...) | -| A.java:14:28:14:42 | req | A.java:17:20:17:51 | getMethod(...) | -| A.java:14:28:14:42 | req | A.java:18:20:18:38 | getAllHeaders(...) | -| A.java:14:28:14:42 | req | A.java:20:20:20:28 | next(...) | -| A.java:14:28:14:42 | req | A.java:21:20:21:34 | nextHeader(...) | -| A.java:14:28:14:42 | req | A.java:23:20:23:30 | getName(...) | -| A.java:14:28:14:42 | req | A.java:24:20:24:31 | getValue(...) | -| A.java:14:28:14:42 | req | A.java:26:20:26:31 | getName(...) | -| A.java:14:28:14:42 | req | A.java:27:20:27:32 | getValue(...) | -| A.java:14:28:14:42 | req | A.java:28:20:28:37 | getParameters(...) | -| A.java:14:28:14:42 | req | A.java:29:20:29:58 | getValue(...) | -| A.java:14:28:14:42 | req | A.java:30:20:30:47 | getName(...) | -| A.java:14:28:14:42 | req | A.java:32:20:32:35 | getContent(...) | -| A.java:14:28:14:42 | req | A.java:33:20:33:43 | getContentEncoding(...) | -| A.java:14:28:14:42 | req | A.java:34:20:34:39 | getContentType(...) | -| A.java:14:28:14:42 | req | A.java:35:20:35:44 | toString(...) | -| A.java:14:28:14:42 | req | A.java:36:20:36:47 | toByteArray(...) | -| A.java:14:28:14:42 | req | A.java:37:20:37:53 | getContentCharSet(...) | -| A.java:14:28:14:42 | req | A.java:38:20:38:54 | getContentMimeType(...) | -| A.java:14:28:14:42 | req | A.java:39:27:39:99 | new StringEntity(...) | -| A.java:14:28:14:42 | req | A.java:40:43:40:91 | new ByteArrayEntity(...) | -| A.java:14:28:14:42 | req | A.java:41:39:41:67 | getUri(...) | -| A.java:14:28:14:42 | req | A.java:42:55:42:83 | getUri(...) | -| A.java:32:20:32:35 | getContent(...) | A.java:32:20:32:35 | getContent(...) | -| A.java:48:30:48:36 | taint(...) | A.java:49:14:49:26 | buffer(...) | -| A.java:48:30:48:36 | taint(...) | A.java:50:14:50:31 | toByteArray(...) | -| A.java:48:30:48:36 | taint(...) | A.java:54:14:54:31 | toCharArray(...) | -| A.java:48:30:48:36 | taint(...) | A.java:55:14:55:28 | toString(...) | -| A.java:48:30:48:36 | taint(...) | A.java:56:14:56:35 | subSequence(...) | -| A.java:48:30:48:36 | taint(...) | A.java:57:14:57:33 | substring(...) | -| A.java:48:30:48:36 | taint(...) | A.java:58:14:58:40 | substringTrimmed(...) | -| A.java:60:27:60:33 | taint(...) | A.java:60:14:60:39 | notNull(...) | -| A.java:61:37:61:43 | taint(...) | A.java:61:14:61:49 | notEmpty(...) | -| A.java:62:37:62:43 | taint(...) | A.java:62:14:62:49 | notBlank(...) | -| B.java:15:28:15:49 | req | B.java:19:20:19:32 | getPath(...) | -| B.java:15:28:15:49 | req | B.java:20:20:20:34 | getScheme(...) | -| B.java:15:28:15:49 | req | B.java:21:20:21:38 | getRequestUri(...) | -| B.java:15:28:15:49 | req | B.java:25:20:25:35 | getHeaders(...) | -| B.java:15:28:15:49 | req | B.java:26:20:26:39 | headerIterator(...) | -| B.java:15:28:15:49 | req | B.java:28:20:28:30 | getName(...) | -| B.java:15:28:15:49 | req | B.java:29:20:29:31 | getValue(...) | -| B.java:15:28:15:49 | req | B.java:30:20:30:44 | getFirstHeader(...) | -| B.java:15:28:15:49 | req | B.java:31:20:31:43 | getLastHeader(...) | -| B.java:15:28:15:49 | req | B.java:33:20:33:35 | getContent(...) | -| B.java:15:28:15:49 | req | B.java:35:20:35:39 | getContentType(...) | -| B.java:15:28:15:49 | req | B.java:36:20:36:40 | getTrailerNames(...) | -| B.java:15:28:15:49 | req | B.java:44:39:44:57 | getRequestUri(...) | -| B.java:15:28:15:49 | req | B.java:45:55:45:73 | getRequestUri(...) | -| B.java:51:30:51:36 | taint(...) | B.java:52:14:52:25 | array(...) | -| B.java:51:30:51:36 | taint(...) | B.java:53:14:53:31 | toByteArray(...) | -| B.java:51:30:51:36 | taint(...) | B.java:57:14:57:31 | toCharArray(...) | -| B.java:51:30:51:36 | taint(...) | B.java:58:14:58:28 | toString(...) | -| B.java:51:30:51:36 | taint(...) | B.java:59:14:59:35 | subSequence(...) | -| B.java:51:30:51:36 | taint(...) | B.java:60:14:60:33 | substring(...) | -| B.java:51:30:51:36 | taint(...) | B.java:61:14:61:40 | substringTrimmed(...) | -| B.java:63:27:63:33 | taint(...) | B.java:63:14:63:39 | notNull(...) | -| B.java:64:37:64:43 | taint(...) | B.java:64:14:64:49 | notEmpty(...) | -| B.java:65:37:65:43 | taint(...) | B.java:65:14:65:49 | notBlank(...) | diff --git a/java/ql/test/library-tests/frameworks/apache-http/flow.ql b/java/ql/test/library-tests/frameworks/apache-http/flow.ql index 0648efeac8f..46856ee648d 100644 --- a/java/ql/test/library-tests/frameworks/apache-http/flow.ql +++ b/java/ql/test/library-tests/frameworks/apache-http/flow.ql @@ -3,6 +3,7 @@ import semmle.code.java.dataflow.TaintTracking import semmle.code.java.dataflow.FlowSources import semmle.code.java.security.XSS import semmle.code.java.security.UrlRedirect +import TestUtilities.InlineExpectationsTest class Conf extends TaintTracking::Configuration { Conf() { this = "qltest:frameworks:apache-http" } @@ -22,6 +23,17 @@ class Conf extends TaintTracking::Configuration { } } -from DataFlow::Node src, DataFlow::Node sink, Conf conf -where conf.hasFlow(src, sink) -select src, sink +class HasFlowTest extends InlineExpectationsTest { + HasFlowTest() { this = "HasFlowTest" } + + override string getARelevantTag() { result = "hasTaintFlow" } + + override predicate hasActualResult(Location location, string element, string tag, string value) { + tag = "hasTaintFlow" and + exists(DataFlow::Node src, DataFlow::Node sink, Conf conf | conf.hasFlow(src, sink) | + sink.getLocation() = location and + element = sink.toString() and + value = "y" + ) + } +} From 459c0afc5500c078a0766b6caf42669fd634d0ac Mon Sep 17 00:00:00 2001 From: Joe Farebrother Date: Wed, 17 Feb 2021 17:59:41 +0000 Subject: [PATCH 027/142] Add change note --- java/change-notes/2021-02-17-apache-http.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 java/change-notes/2021-02-17-apache-http.md diff --git a/java/change-notes/2021-02-17-apache-http.md b/java/change-notes/2021-02-17-apache-http.md new file mode 100644 index 00000000000..3397dd37df6 --- /dev/null +++ b/java/change-notes/2021-02-17-apache-http.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* Added support for the Apache Http components core library (`org.apache.http.*` and `org.apache.hc.core5.*`); adding additional remote flow sources, sinks for the XSS and Open Redirect queries, and additional taint steps. \ No newline at end of file From ee651da23f644d0d4bbf18b18c55c8103c04652d Mon Sep 17 00:00:00 2001 From: Joe Farebrother Date: Tue, 23 Feb 2021 14:27:11 +0000 Subject: [PATCH 028/142] Remove TODO comment --- java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll | 1 - 1 file changed, 1 deletion(-) diff --git a/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll b/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll index 14978b97072..c882c69c31c 100644 --- a/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll +++ b/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll @@ -41,7 +41,6 @@ class TypeApacheHttpRequestBuilder extends Class { } } -// TODO: Other sources /** * The `request` parameter of an implementation of `HttpRequestHandler.handle`. */ From e13c779f0f93c602d50a1791691da5d8f405260f Mon Sep 17 00:00:00 2001 From: Joe Farebrother Date: Tue, 23 Feb 2021 16:17:13 +0000 Subject: [PATCH 029/142] Add additional unit tests --- .../frameworks/apache-http/B.java | 10 +++- .../http/io/HttpServerRequestHandler.java | 46 +++++++++++++++++++ 2 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/io/HttpServerRequestHandler.java diff --git a/java/ql/test/library-tests/frameworks/apache-http/B.java b/java/ql/test/library-tests/frameworks/apache-http/B.java index 09cb24797e5..bfba6f5a7d0 100644 --- a/java/ql/test/library-tests/frameworks/apache-http/B.java +++ b/java/ql/test/library-tests/frameworks/apache-http/B.java @@ -1,6 +1,7 @@ import org.apache.hc.core5.http.*; import org.apache.hc.core5.http.protocol.HttpContext; import org.apache.hc.core5.http.io.HttpRequestHandler; +import org.apache.hc.core5.http.io.HttpServerRequestHandler; import org.apache.hc.core5.http.message.*; import org.apache.hc.core5.http.io.entity.*; import org.apache.hc.core5.util.*; @@ -51,6 +52,7 @@ class B { bbuf.append((byte[]) taint(), 0, 3); sink(bbuf.array()); //$hasTaintFlow=y sink(bbuf.toByteArray()); //$hasTaintFlow=y + sink(bbuf.toString()); //SPURIOUS: $hasTaintFlow=y CharArrayBuffer cbuf = new CharArrayBuffer(42); cbuf.append(bbuf.toByteArray(), 0, 3); @@ -63,6 +65,12 @@ class B { sink(Args.notNull(taint(), "x")); //$hasTaintFlow=y sink(Args.notEmpty((String) taint(), "x")); //$hasTaintFlow=y sink(Args.notBlank((String) taint(), "x")); //$hasTaintFlow=y - sink(Args.notNull("x", (String) taint())); // Good + sink(Args.notNull("x", (String) taint())); + } + + class Test3 implements HttpServerRequestHandler { + public void handle(ClassicHttpRequest req, HttpServerRequestHandler.ResponseTrigger restr, HttpContext ctx) throws HttpException, IOException { + B.sink(req.getEntity()); //$hasTaintFlow=y + } } } \ No newline at end of file diff --git a/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/io/HttpServerRequestHandler.java b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/io/HttpServerRequestHandler.java new file mode 100644 index 00000000000..007bf18568d --- /dev/null +++ b/java/ql/test/stubs/apache-http-5/org/apache/hc/core5/http/io/HttpServerRequestHandler.java @@ -0,0 +1,46 @@ +/* + * ==================================================================== + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * ==================================================================== + * + * This software consists of voluntary contributions made by many + * individuals on behalf of the Apache Software Foundation. For more + * information on the Apache Software Foundation, please see + * . + * + */ +package org.apache.hc.core5.http.io; +import java.io.IOException; +import org.apache.hc.core5.http.ClassicHttpRequest; +import org.apache.hc.core5.http.ClassicHttpResponse; +import org.apache.hc.core5.http.HttpException; +import org.apache.hc.core5.http.protocol.HttpContext; + +public interface HttpServerRequestHandler { + interface ResponseTrigger { + void sendInformation(ClassicHttpResponse response) throws HttpException, IOException; + + void submitResponse(ClassicHttpResponse response) throws HttpException, IOException; + + } + void handle( + ClassicHttpRequest request, + ResponseTrigger responseTrigger, + HttpContext context) throws HttpException, IOException; + +} From 8cf28c618607b1213dd6c41512d9fdcee4f64a6d Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 18 Feb 2021 12:06:16 +0100 Subject: [PATCH 030/142] update TypeScript to 4.2 --- javascript/extractor/lib/typescript/package.json | 2 +- javascript/extractor/lib/typescript/yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/javascript/extractor/lib/typescript/package.json b/javascript/extractor/lib/typescript/package.json index 0f6fc082bb4..cb3119c7ab2 100644 --- a/javascript/extractor/lib/typescript/package.json +++ b/javascript/extractor/lib/typescript/package.json @@ -2,7 +2,7 @@ "name": "typescript-parser-wrapper", "private": true, "dependencies": { - "typescript": "4.1.2" + "typescript": "4.2.2" }, "scripts": { "build": "tsc --project tsconfig.json", diff --git a/javascript/extractor/lib/typescript/yarn.lock b/javascript/extractor/lib/typescript/yarn.lock index be708347dab..84f20b2c51c 100644 --- a/javascript/extractor/lib/typescript/yarn.lock +++ b/javascript/extractor/lib/typescript/yarn.lock @@ -6,7 +6,7 @@ version "12.7.11" resolved node-12.7.11.tgz#be879b52031cfb5d295b047f5462d8ef1a716446 -typescript@4.1.2: - version "4.1.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.1.2.tgz#6369ef22516fe5e10304aae5a5c4862db55380e9" - integrity sha512-thGloWsGH3SOxv1SoY7QojKi0tc+8FnOmiarEGMbd/lar7QOEd3hvlx3Fp5y6FlDUGl9L+pd4n2e+oToGMmhRQ== +typescript@4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.2.2.tgz#1450f020618f872db0ea17317d16d8da8ddb8c4c" + integrity sha512-tbb+NVrLfnsJy3M59lsDgrzWIflR4d4TIUjz+heUnHZwdF7YsrMTKoRERiIvI2lvBG95dfpLxB21WZhys1bgaQ== From 74630b0fd8f78436d4ba76b3ae78237ae5900149 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 18 Feb 2021 10:08:52 +0100 Subject: [PATCH 031/142] fix file lookup for exclude patterns --- javascript/extractor/src/com/semmle/js/extractor/Main.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/extractor/src/com/semmle/js/extractor/Main.java b/javascript/extractor/src/com/semmle/js/extractor/Main.java index b9fb9237556..1590fca821b 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/Main.java +++ b/javascript/extractor/src/com/semmle/js/extractor/Main.java @@ -344,7 +344,7 @@ public class Main { for (String pattern : ap.getZeroOrMore(P_EXCLUDE)) addPathPattern(excludes, System.getProperty("user.dir"), pattern); for (String excl : ap.getZeroOrMore(P_EXCLUDE_PATH)) { - File exclFile = new File(excl).getAbsoluteFile(); + File exclFile = new File(new File(System.getProperty("user.dir")), excl).getAbsoluteFile(); String base = exclFile.getParent(); for (String pattern : NEWLINE.split(new WholeIO().strictread(exclFile))) addPathPattern(excludes, base, pattern); From f385c55f2ce90b32281fcc46d0cffa1b4b9d80f9 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 18 Feb 2021 11:08:15 +0100 Subject: [PATCH 032/142] add support for rest types elements in the middle of a tuple --- .../lib/typescript/src/type_table.ts | 9 +- .../semmle/ts/extractor/TypeExtractor.java | 7 +- .../ql/src/semmle/javascript/TypeScript.qll | 15 +- .../ql/src/semmlecode.javascript.dbscheme | 5 +- .../TypeScript/Types/middle-rest.ts | 3 + .../TypeScript/Types/tests.expected | 25 + .../old.dbscheme | 1206 ++++++++++++++++ .../semmlecode.javascript.dbscheme | 1207 +++++++++++++++++ .../tuple_type_rest_index.ql | 9 + .../upgrade.properties | 4 + 10 files changed, 2479 insertions(+), 11 deletions(-) create mode 100644 javascript/ql/test/library-tests/TypeScript/Types/middle-rest.ts create mode 100644 javascript/upgrades/930898a4fe07cb48de46800904922ca118b31e50/old.dbscheme create mode 100644 javascript/upgrades/930898a4fe07cb48de46800904922ca118b31e50/semmlecode.javascript.dbscheme create mode 100644 javascript/upgrades/930898a4fe07cb48de46800904922ca118b31e50/tuple_type_rest_index.ql create mode 100644 javascript/upgrades/930898a4fe07cb48de46800904922ca118b31e50/upgrade.properties diff --git a/javascript/extractor/lib/typescript/src/type_table.ts b/javascript/extractor/lib/typescript/src/type_table.ts index b750d5a0d85..5f2a8d7fce8 100644 --- a/javascript/extractor/lib/typescript/src/type_table.ts +++ b/javascript/extractor/lib/typescript/src/type_table.ts @@ -632,7 +632,14 @@ export class TypeTable { ? tupleType.minLength : this.typeChecker.getTypeArguments(tupleReference).length; let hasRestElement = tupleType.hasRestElement ? 't' : 'f'; - let prefix = `tuple;${minLength};${hasRestElement}`; + let restIndex = -1; + for (let i = 0; i < tupleType.elementFlags.length; i++) { + if (tupleType.elementFlags[i] & ts.ElementFlags.Rest) { + restIndex = i; + break; + } + } + let prefix = `tuple;${minLength};${restIndex}`; return this.makeTypeStringVectorFromTypeReferenceArguments(prefix, type); } if (objectFlags & ts.ObjectFlags.Anonymous) { diff --git a/javascript/extractor/src/com/semmle/ts/extractor/TypeExtractor.java b/javascript/extractor/src/com/semmle/ts/extractor/TypeExtractor.java index 08f261b71de..3333bd97254 100644 --- a/javascript/extractor/src/com/semmle/ts/extractor/TypeExtractor.java +++ b/javascript/extractor/src/com/semmle/ts/extractor/TypeExtractor.java @@ -118,10 +118,11 @@ public class TypeExtractor { } case tupleKind: { - // The first two parts denote minimum length and presence of rest element. + // The first two parts denote minimum length and index of rest element (or -1 if no rest element). trapWriter.addTuple("tuple_type_min_length", lbl, Integer.parseInt(parts[1])); - if (parts[2].equals("t")) { - trapWriter.addTuple("tuple_type_rest", lbl); + int restIndex = Integer.parseInt(parts[2]); + if (restIndex != -1) { + trapWriter.addTuple("tuple_type_rest_index", lbl, restIndex); } firstChild += 2; break; diff --git a/javascript/ql/src/semmle/javascript/TypeScript.qll b/javascript/ql/src/semmle/javascript/TypeScript.qll index a1b312411ac..6fe47221c97 100644 --- a/javascript/ql/src/semmle/javascript/TypeScript.qll +++ b/javascript/ql/src/semmle/javascript/TypeScript.qll @@ -2149,18 +2149,23 @@ class TupleType extends ArrayType, @tuple_type { int getMinimumLength() { tuple_type_min_length(this, result) } /** - * Holds if this tuple type ends with a rest element, such as `[number, ...string[]]`. + * Gets the index of the rest element. + * E.g. for a type `[number, ...string[]]` the result is 1, + * or for a type `[...number[], string]` the result is 0. */ - predicate hasRestElement() { tuple_type_rest(this) } + int getRestElementIndex() { tuple_type_rest_index(this, result) } + + /** + * Holds if this tuple type has a rest element, such as `[number, ...string[]]` or `[...number[], string]`. + */ + predicate hasRestElement() { exists(getRestElementIndex()) } /** * Gets the type of the rest element, if there is one. * * For example, the rest element of `[number, ...string[]]` is `string`. */ - Type getRestElementType() { - hasRestElement() and result = getElementType(getNumElementType() - 1) - } + Type getRestElementType() { result = getElementType(getRestElementIndex()) } } /** diff --git a/javascript/ql/src/semmlecode.javascript.dbscheme b/javascript/ql/src/semmlecode.javascript.dbscheme index 930898a4fe0..72028aa6f0b 100644 --- a/javascript/ql/src/semmlecode.javascript.dbscheme +++ b/javascript/ql/src/semmlecode.javascript.dbscheme @@ -799,8 +799,9 @@ tuple_type_min_length( int minLength: int ref ); -tuple_type_rest( - unique int typ: @type ref +tuple_type_rest_index( + unique int typ: @type ref, + int index: int ref ); // comments diff --git a/javascript/ql/test/library-tests/TypeScript/Types/middle-rest.ts b/javascript/ql/test/library-tests/TypeScript/Types/middle-rest.ts new file mode 100644 index 00000000000..4ca8c74d334 --- /dev/null +++ b/javascript/ql/test/library-tests/TypeScript/Types/middle-rest.ts @@ -0,0 +1,3 @@ +let foo: [boolean, ...string[], number]; + +foo = [true, "hello", 123]; \ No newline at end of file diff --git a/javascript/ql/test/library-tests/TypeScript/Types/tests.expected b/javascript/ql/test/library-tests/TypeScript/Types/tests.expected index dab0592c334..02b78425dfd 100644 --- a/javascript/ql/test/library-tests/TypeScript/Types/tests.expected +++ b/javascript/ql/test/library-tests/TypeScript/Types/tests.expected @@ -15,6 +15,13 @@ getExprType | boolean-type.ts:15:5:15:12 | boolean6 | boolean | | dummy.ts:2:12:2:12 | x | number | | dummy.ts:2:16:2:16 | 5 | 5 | +| middle-rest.ts:1:5:1:7 | foo | [boolean, ...string[], number] | +| middle-rest.ts:3:1:3:3 | foo | [boolean, ...string[], number] | +| middle-rest.ts:3:1:3:26 | foo = [ ... ", 123] | [true, string, number] | +| middle-rest.ts:3:7:3:26 | [true, "hello", 123] | [boolean, ...string[], number] | +| middle-rest.ts:3:8:3:11 | true | true | +| middle-rest.ts:3:14:3:20 | "hello" | "hello" | +| middle-rest.ts:3:23:3:25 | 123 | 123 | | tst.ts:1:13:1:17 | dummy | typeof library-tests/TypeScript/Types/dummy.ts | | tst.ts:1:24:1:32 | "./dummy" | any | | tst.ts:3:5:3:10 | numVar | number | @@ -185,6 +192,12 @@ getTypeExprType | boolean-type.ts:15:15:15:19 | false | false | | boolean-type.ts:15:15:15:29 | false \| boolean | boolean | | boolean-type.ts:15:23:15:29 | boolean | boolean | +| middle-rest.ts:1:10:1:39 | [boolea ... number] | [boolean, ...string[], number] | +| middle-rest.ts:1:11:1:17 | boolean | boolean | +| middle-rest.ts:1:20:1:30 | ...string[] | string | +| middle-rest.ts:1:23:1:28 | string | string | +| middle-rest.ts:1:23:1:30 | string[] | string[] | +| middle-rest.ts:1:33:1:38 | number | number | | tst.ts:3:13:3:18 | number | number | | tst.ts:9:13:9:18 | string | string | | tst.ts:14:20:14:25 | string | string | @@ -311,6 +324,18 @@ referenceDefinition | ValueOrArray | type_alias.ts:5:1:5:50 | type Va ... ay>; | | VirtualNode | type_alias.ts:19:1:21:57 | type Vi ... ode[]]; | tupleTypes +| middle-rest.ts:1:5:1:7 | foo | [boolean, ...string[], number] | 0 | boolean | 2 | string | +| middle-rest.ts:1:5:1:7 | foo | [boolean, ...string[], number] | 1 | string | 2 | string | +| middle-rest.ts:1:5:1:7 | foo | [boolean, ...string[], number] | 2 | number | 2 | string | +| middle-rest.ts:3:1:3:3 | foo | [boolean, ...string[], number] | 0 | boolean | 2 | string | +| middle-rest.ts:3:1:3:3 | foo | [boolean, ...string[], number] | 1 | string | 2 | string | +| middle-rest.ts:3:1:3:3 | foo | [boolean, ...string[], number] | 2 | number | 2 | string | +| middle-rest.ts:3:1:3:26 | foo = [ ... ", 123] | [true, string, number] | 0 | true | 3 | no-rest | +| middle-rest.ts:3:1:3:26 | foo = [ ... ", 123] | [true, string, number] | 1 | string | 3 | no-rest | +| middle-rest.ts:3:1:3:26 | foo = [ ... ", 123] | [true, string, number] | 2 | number | 3 | no-rest | +| middle-rest.ts:3:7:3:26 | [true, "hello", 123] | [boolean, ...string[], number] | 0 | boolean | 2 | string | +| middle-rest.ts:3:7:3:26 | [true, "hello", 123] | [boolean, ...string[], number] | 1 | string | 2 | string | +| middle-rest.ts:3:7:3:26 | [true, "hello", 123] | [boolean, ...string[], number] | 2 | number | 2 | string | | tst.ts:34:5:34:9 | tuple | [number, string] | 0 | number | 2 | no-rest | | tst.ts:34:5:34:9 | tuple | [number, string] | 1 | string | 2 | no-rest | | tst.ts:36:5:36:28 | tupleWi ... Element | [number, string, number?] | 0 | number | 2 | no-rest | diff --git a/javascript/upgrades/930898a4fe07cb48de46800904922ca118b31e50/old.dbscheme b/javascript/upgrades/930898a4fe07cb48de46800904922ca118b31e50/old.dbscheme new file mode 100644 index 00000000000..930898a4fe0 --- /dev/null +++ b/javascript/upgrades/930898a4fe07cb48de46800904922ca118b31e50/old.dbscheme @@ -0,0 +1,1206 @@ +/*** Standard fragments ***/ + +/** Files and folders **/ + +@location = @location_default; + +locations_default(unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref + ); + +@sourceline = @locatable; + +numlines(int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref + ); + + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files(unique int id: @file, + varchar(900) name: string ref, + varchar(900) simple: string ref, + varchar(900) ext: string ref, + int fromSource: int ref); + +folders(unique int id: @folder, + varchar(900) name: string ref, + varchar(900) simple: string ref); + + +@container = @folder | @file ; + + +containerparent(int parent: @container ref, + unique int child: @container ref); + +/** Duplicate code **/ + +duplicateCode( + unique int id : @duplication, + varchar(900) relativePath : string ref, + int equivClass : int ref); + +similarCode( + unique int id : @similarity, + varchar(900) relativePath : string ref, + int equivClass : int ref); + +@duplication_or_similarity = @duplication | @similarity; + +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref); + +/** External data **/ + +externalData( + int id : @externalDataElement, + varchar(900) path : string ref, + int column: int ref, + varchar(900) value : string ref +); + +snapshotDate(unique date snapshotDate : date ref); + +sourceLocationPrefix(varchar(900) prefix : string ref); + +/** Version control data **/ + +svnentries( + int id : @svnentry, + varchar(500) revision : string ref, + varchar(500) author : string ref, + date revisionDate : date ref, + int changeSize : int ref +); + +svnaffectedfiles( + int id : @svnentry ref, + int file : @file ref, + varchar(500) action : string ref +); + +svnentrymsg( + int id : @svnentry ref, + varchar(500) message : string ref +); + +svnchurn( + int commit : @svnentry ref, + int file : @file ref, + int addedLines : int ref, + int deletedLines : int ref +); + + +/*** JavaScript-specific part ***/ + +filetype( + int file: @file ref, + string filetype: string ref +) + +// top-level code fragments +toplevels (unique int id: @toplevel, + int kind: int ref); + +is_externs (int toplevel: @toplevel ref); + +case @toplevel.kind of + 0 = @script +| 1 = @inline_script +| 2 = @event_handler +| 3 = @javascript_url +| 4 = @angular_template_toplevel; + +is_module (int tl: @toplevel ref); +is_nodejs (int tl: @toplevel ref); +is_es2015_module (int tl: @toplevel ref); +is_closure_module (int tl: @toplevel ref); + +@xml_node_with_code = @xmlelement | @xmlattribute; +toplevel_parent_xml_node( + unique int toplevel: @toplevel ref, + int xmlnode: @xml_node_with_code ref); + +xml_element_parent_expression( + unique int xmlnode: @xmlelement ref, + int expression: @expr ref, + int index: int ref); + +// statements +#keyset[parent, idx] +stmts (unique int id: @stmt, + int kind: int ref, + int parent: @stmt_parent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +stmt_containers (unique int stmt: @stmt ref, + int container: @stmt_container ref); + +jump_targets (unique int jump: @stmt ref, + int target: @stmt ref); + +@stmt_parent = @stmt | @toplevel | @function_expr | @arrow_function_expr; +@stmt_container = @toplevel | @function | @namespace_declaration | @external_module_declaration | @global_augmentation_declaration; + +case @stmt.kind of + 0 = @empty_stmt +| 1 = @block_stmt +| 2 = @expr_stmt +| 3 = @if_stmt +| 4 = @labeled_stmt +| 5 = @break_stmt +| 6 = @continue_stmt +| 7 = @with_stmt +| 8 = @switch_stmt +| 9 = @return_stmt +| 10 = @throw_stmt +| 11 = @try_stmt +| 12 = @while_stmt +| 13 = @do_while_stmt +| 14 = @for_stmt +| 15 = @for_in_stmt +| 16 = @debugger_stmt +| 17 = @function_decl_stmt +| 18 = @var_decl_stmt +| 19 = @case +| 20 = @catch_clause +| 21 = @for_of_stmt +| 22 = @const_decl_stmt +| 23 = @let_stmt +| 24 = @legacy_let_stmt +| 25 = @for_each_stmt +| 26 = @class_decl_stmt +| 27 = @import_declaration +| 28 = @export_all_declaration +| 29 = @export_default_declaration +| 30 = @export_named_declaration +| 31 = @namespace_declaration +| 32 = @import_equals_declaration +| 33 = @export_assign_declaration +| 34 = @interface_declaration +| 35 = @type_alias_declaration +| 36 = @enum_declaration +| 37 = @external_module_declaration +| 38 = @export_as_namespace_declaration +| 39 = @global_augmentation_declaration +; + +@decl_stmt = @var_decl_stmt | @const_decl_stmt | @let_stmt | @legacy_let_stmt; + +@export_declaration = @export_all_declaration | @export_default_declaration | @export_named_declaration; + +@namespace_definition = @namespace_declaration | @enum_declaration; +@type_definition = @class_definition | @interface_declaration | @enum_declaration | @type_alias_declaration | @enum_member; + +is_instantiated(unique int decl: @namespace_declaration ref); + +@declarable_node = @decl_stmt | @namespace_declaration | @class_decl_stmt | @function_decl_stmt | @enum_declaration | @external_module_declaration | @global_augmentation_declaration | @field; +has_declare_keyword(unique int stmt: @declarable_node ref); + +is_for_await_of(unique int forof: @for_of_stmt ref); + +// expressions +#keyset[parent, idx] +exprs (unique int id: @expr, + int kind: int ref, + int parent: @expr_parent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +literals (varchar(900) value: string ref, + varchar(900) raw: string ref, + unique int expr: @expr_or_type ref); + +enclosing_stmt (unique int expr: @expr_or_type ref, + int stmt: @stmt ref); + +expr_containers (unique int expr: @expr_or_type ref, + int container: @stmt_container ref); + +array_size (unique int ae: @arraylike ref, + int sz: int ref); + +is_delegating (int yield: @yield_expr ref); + +@expr_or_stmt = @expr | @stmt; +@expr_or_type = @expr | @typeexpr; +@expr_parent = @expr_or_stmt | @property | @function_typeexpr; +@arraylike = @array_expr | @array_pattern; +@type_annotation = @typeexpr | @jsdoc_type_expr; +@node_in_stmt_container = @cfg_node | @type_annotation | @toplevel; + +case @expr.kind of + 0 = @label +| 1 = @null_literal +| 2 = @boolean_literal +| 3 = @number_literal +| 4 = @string_literal +| 5 = @regexp_literal +| 6 = @this_expr +| 7 = @array_expr +| 8 = @obj_expr +| 9 = @function_expr +| 10 = @seq_expr +| 11 = @conditional_expr +| 12 = @new_expr +| 13 = @call_expr +| 14 = @dot_expr +| 15 = @index_expr +| 16 = @neg_expr +| 17 = @plus_expr +| 18 = @log_not_expr +| 19 = @bit_not_expr +| 20 = @typeof_expr +| 21 = @void_expr +| 22 = @delete_expr +| 23 = @eq_expr +| 24 = @neq_expr +| 25 = @eqq_expr +| 26 = @neqq_expr +| 27 = @lt_expr +| 28 = @le_expr +| 29 = @gt_expr +| 30 = @ge_expr +| 31 = @lshift_expr +| 32 = @rshift_expr +| 33 = @urshift_expr +| 34 = @add_expr +| 35 = @sub_expr +| 36 = @mul_expr +| 37 = @div_expr +| 38 = @mod_expr +| 39 = @bitor_expr +| 40 = @xor_expr +| 41 = @bitand_expr +| 42 = @in_expr +| 43 = @instanceof_expr +| 44 = @logand_expr +| 45 = @logor_expr +| 47 = @assign_expr +| 48 = @assign_add_expr +| 49 = @assign_sub_expr +| 50 = @assign_mul_expr +| 51 = @assign_div_expr +| 52 = @assign_mod_expr +| 53 = @assign_lshift_expr +| 54 = @assign_rshift_expr +| 55 = @assign_urshift_expr +| 56 = @assign_or_expr +| 57 = @assign_xor_expr +| 58 = @assign_and_expr +| 59 = @preinc_expr +| 60 = @postinc_expr +| 61 = @predec_expr +| 62 = @postdec_expr +| 63 = @par_expr +| 64 = @var_declarator +| 65 = @arrow_function_expr +| 66 = @spread_element +| 67 = @array_pattern +| 68 = @object_pattern +| 69 = @yield_expr +| 70 = @tagged_template_expr +| 71 = @template_literal +| 72 = @template_element +| 73 = @array_comprehension_expr +| 74 = @generator_expr +| 75 = @for_in_comprehension_block +| 76 = @for_of_comprehension_block +| 77 = @legacy_letexpr +| 78 = @var_decl +| 79 = @proper_varaccess +| 80 = @class_expr +| 81 = @super_expr +| 82 = @newtarget_expr +| 83 = @named_import_specifier +| 84 = @import_default_specifier +| 85 = @import_namespace_specifier +| 86 = @named_export_specifier +| 87 = @exp_expr +| 88 = @assign_exp_expr +| 89 = @jsx_element +| 90 = @jsx_qualified_name +| 91 = @jsx_empty_expr +| 92 = @await_expr +| 93 = @function_sent_expr +| 94 = @decorator +| 95 = @export_default_specifier +| 96 = @export_namespace_specifier +| 97 = @bind_expr +| 98 = @external_module_reference +| 99 = @dynamic_import +| 100 = @expression_with_type_arguments +| 101 = @prefix_type_assertion +| 102 = @as_type_assertion +| 103 = @export_varaccess +| 104 = @decorator_list +| 105 = @non_null_assertion +| 106 = @bigint_literal +| 107 = @nullishcoalescing_expr +| 108 = @e4x_xml_anyname +| 109 = @e4x_xml_static_attribute_selector +| 110 = @e4x_xml_dynamic_attribute_selector +| 111 = @e4x_xml_filter_expression +| 112 = @e4x_xml_static_qualident +| 113 = @e4x_xml_dynamic_qualident +| 114 = @e4x_xml_dotdotexpr +| 115 = @import_meta_expr +| 116 = @assignlogandexpr +| 117 = @assignlogorexpr +| 118 = @assignnullishcoalescingexpr +| 119 = @angular_pipe_ref +; + +@varaccess = @proper_varaccess | @export_varaccess; +@varref = @var_decl | @varaccess; + +@identifier = @label | @varref | @type_identifier; + +@literal = @null_literal | @boolean_literal | @number_literal | @string_literal | @regexp_literal | @bigint_literal; + +@propaccess = @dot_expr | @index_expr; + +@invokeexpr = @new_expr | @call_expr; + +@unaryexpr = @neg_expr | @plus_expr | @log_not_expr | @bit_not_expr | @typeof_expr | @void_expr | @delete_expr | @spread_element; + +@equality_test = @eq_expr | @neq_expr | @eqq_expr | @neqq_expr; + +@comparison = @equality_test | @lt_expr | @le_expr | @gt_expr | @ge_expr; + +@binaryexpr = @comparison | @lshift_expr | @rshift_expr | @urshift_expr | @add_expr | @sub_expr | @mul_expr | @div_expr | @mod_expr | @exp_expr | @bitor_expr | @xor_expr | @bitand_expr | @in_expr | @instanceof_expr | @logand_expr | @logor_expr | @nullishcoalescing_expr; + +@assignment = @assign_expr | @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr | @assign_mod_expr | @assign_exp_expr | @assign_lshift_expr | @assign_rshift_expr | @assign_urshift_expr | @assign_or_expr | @assign_xor_expr | @assign_and_expr | @assignlogandexpr | @assignlogorexpr | @assignnullishcoalescingexpr; + +@updateexpr = @preinc_expr | @postinc_expr | @predec_expr | @postdec_expr; + +@pattern = @varref | @array_pattern | @object_pattern; + +@comprehension_expr = @array_comprehension_expr | @generator_expr; + +@comprehension_block = @for_in_comprehension_block | @for_of_comprehension_block; + +@import_specifier = @named_import_specifier | @import_default_specifier | @import_namespace_specifier; + +@exportspecifier = @named_export_specifier | @export_default_specifier | @export_namespace_specifier; + +@import_or_export_declaration = @import_declaration | @export_declaration; + +@type_assertion = @as_type_assertion | @prefix_type_assertion; + +@class_definition = @class_decl_stmt | @class_expr; +@interface_definition = @interface_declaration | @interface_typeexpr; +@class_or_interface = @class_definition | @interface_definition; + +@lexical_decl = @var_decl | @type_decl; +@lexical_access = @varaccess | @local_type_access | @local_var_type_access | @local_namespace_access; +@lexical_ref = @lexical_decl | @lexical_access; + +@e4x_xml_attribute_selector = @e4x_xml_static_attribute_selector | @e4x_xml_dynamic_attribute_selector; +@e4x_xml_qualident = @e4x_xml_static_qualident | @e4x_xml_dynamic_qualident; + +// scopes +scopes (unique int id: @scope, + int kind: int ref); + +case @scope.kind of + 0 = @global_scope +| 1 = @function_scope +| 2 = @catch_scope +| 3 = @module_scope +| 4 = @block_scope +| 5 = @for_scope +| 6 = @for_in_scope // for-of scopes work the same as for-in scopes +| 7 = @comprehension_block_scope +| 8 = @class_expr_scope +| 9 = @namespace_scope +| 10 = @class_decl_scope +| 11 = @interface_scope +| 12 = @type_alias_scope +| 13 = @mapped_type_scope +| 14 = @enum_scope +| 15 = @external_module_scope +| 16 = @conditional_type_scope; + +scopenodes (unique int node: @ast_node ref, + int scope: @scope ref); + +scopenesting (unique int inner: @scope ref, + int outer: @scope ref); + +// functions +@function = @function_decl_stmt | @function_expr | @arrow_function_expr; + +@parameterized = @function | @catch_clause; +@type_parameterized = @function | @class_or_interface | @type_alias_declaration | @mapped_typeexpr | @infer_typeexpr; + +is_generator (int fun: @function ref); +has_rest_parameter (int fun: @function ref); +is_async (int fun: @function ref); + +// variables and lexically scoped type names +#keyset[scope, name] +variables (unique int id: @variable, + varchar(900) name: string ref, + int scope: @scope ref); + +#keyset[scope, name] +local_type_names (unique int id: @local_type_name, + varchar(900) name: string ref, + int scope: @scope ref); + +#keyset[scope, name] +local_namespace_names (unique int id: @local_namespace_name, + varchar(900) name: string ref, + int scope: @scope ref); + +is_arguments_object (int id: @variable ref); + +@lexical_name = @variable | @local_type_name | @local_namespace_name; + +@bind_id = @varaccess | @local_var_type_access; +bind (unique int id: @bind_id ref, + int decl: @variable ref); + +decl (unique int id: @var_decl ref, + int decl: @variable ref); + +@typebind_id = @local_type_access | @export_varaccess; +typebind (unique int id: @typebind_id ref, + int decl: @local_type_name ref); + +@typedecl_id = @type_decl | @var_decl; +typedecl (unique int id: @typedecl_id ref, + int decl: @local_type_name ref); + +namespacedecl (unique int id: @var_decl ref, + int decl: @local_namespace_name ref); + +@namespacebind_id = @local_namespace_access | @export_varaccess; +namespacebind (unique int id: @namespacebind_id ref, + int decl: @local_namespace_name ref); + + +// properties in object literals, property patterns in object patterns, and method declarations in classes +#keyset[parent, index] +properties (unique int id: @property, + int parent: @property_parent ref, + int index: int ref, + int kind: int ref, + varchar(900) tostring: string ref); + +case @property.kind of + 0 = @value_property +| 1 = @property_getter +| 2 = @property_setter +| 3 = @jsx_attribute +| 4 = @function_call_signature +| 5 = @constructor_call_signature +| 6 = @index_signature +| 7 = @enum_member +| 8 = @proper_field +| 9 = @parameter_field +; + +@property_parent = @obj_expr | @object_pattern | @class_definition | @jsx_element | @interface_definition | @enum_declaration; +@property_accessor = @property_getter | @property_setter; +@call_signature = @function_call_signature | @constructor_call_signature; +@field = @proper_field | @parameter_field; +@field_or_vardeclarator = @field | @var_declarator; + +is_computed (int id: @property ref); +is_method (int id: @property ref); +is_static (int id: @property ref); +is_abstract_member (int id: @property ref); +is_const_enum (int id: @enum_declaration ref); +is_abstract_class (int id: @class_decl_stmt ref); + +has_public_keyword (int id: @property ref); +has_private_keyword (int id: @property ref); +has_protected_keyword (int id: @property ref); +has_readonly_keyword (int id: @property ref); +has_type_keyword (int id: @import_or_export_declaration ref); +is_optional_member (int id: @property ref); +has_definite_assignment_assertion (int id: @field_or_vardeclarator ref); +is_optional_parameter_declaration (unique int parameter: @pattern ref); + +#keyset[constructor, param_index] +parameter_fields( + unique int field: @parameter_field ref, + int constructor: @function_expr ref, + int param_index: int ref +); + +// types +#keyset[parent, idx] +typeexprs ( + unique int id: @typeexpr, + int kind: int ref, + int parent: @typeexpr_parent ref, + int idx: int ref, + varchar(900) tostring: string ref +); + +case @typeexpr.kind of + 0 = @local_type_access +| 1 = @type_decl +| 2 = @keyword_typeexpr +| 3 = @string_literal_typeexpr +| 4 = @number_literal_typeexpr +| 5 = @boolean_literal_typeexpr +| 6 = @array_typeexpr +| 7 = @union_typeexpr +| 8 = @indexed_access_typeexpr +| 9 = @intersection_typeexpr +| 10 = @parenthesized_typeexpr +| 11 = @tuple_typeexpr +| 12 = @keyof_typeexpr +| 13 = @qualified_type_access +| 14 = @generic_typeexpr +| 15 = @type_label +| 16 = @typeof_typeexpr +| 17 = @local_var_type_access +| 18 = @qualified_var_type_access +| 19 = @this_var_type_access +| 20 = @predicate_typeexpr +| 21 = @interface_typeexpr +| 22 = @type_parameter +| 23 = @plain_function_typeexpr +| 24 = @constructor_typeexpr +| 25 = @local_namespace_access +| 26 = @qualified_namespace_access +| 27 = @mapped_typeexpr +| 28 = @conditional_typeexpr +| 29 = @infer_typeexpr +| 30 = @import_type_access +| 31 = @import_namespace_access +| 32 = @import_var_type_access +| 33 = @optional_typeexpr +| 34 = @rest_typeexpr +| 35 = @bigint_literal_typeexpr +| 36 = @readonly_typeexpr +| 37 = @template_literal_typeexpr +; + +@typeref = @typeaccess | @type_decl; +@type_identifier = @type_decl | @local_type_access | @type_label | @local_var_type_access | @local_namespace_access; +@typeexpr_parent = @expr | @stmt | @property | @typeexpr; +@literal_typeexpr = @string_literal_typeexpr | @number_literal_typeexpr | @boolean_literal_typeexpr | @bigint_literal_typeexpr; +@typeaccess = @local_type_access | @qualified_type_access | @import_type_access; +@vartypeaccess = @local_var_type_access | @qualified_var_type_access | @this_var_type_access | @import_var_type_access; +@namespace_access = @local_namespace_access | @qualified_namespace_access | @import_namespace_access; +@import_typeexpr = @import_type_access | @import_namespace_access | @import_var_type_access; + +@function_typeexpr = @plain_function_typeexpr | @constructor_typeexpr; + +// types +types ( + unique int id: @type, + int kind: int ref, + varchar(900) tostring: string ref +); + +#keyset[parent, idx] +type_child ( + int child: @type ref, + int parent: @type ref, + int idx: int ref +); + +case @type.kind of + 0 = @any_type +| 1 = @string_type +| 2 = @number_type +| 3 = @union_type +| 4 = @true_type +| 5 = @false_type +| 6 = @type_reference +| 7 = @object_type +| 8 = @canonical_type_variable_type +| 9 = @typeof_type +| 10 = @void_type +| 11 = @undefined_type +| 12 = @null_type +| 13 = @never_type +| 14 = @plain_symbol_type +| 15 = @unique_symbol_type +| 16 = @objectkeyword_type +| 17 = @intersection_type +| 18 = @tuple_type +| 19 = @lexical_type_variable_type +| 20 = @this_type +| 21 = @number_literal_type +| 22 = @string_literal_type +| 23 = @unknown_type +| 24 = @bigint_type +| 25 = @bigint_literal_type +; + +@boolean_literal_type = @true_type | @false_type; +@symbol_type = @plain_symbol_type | @unique_symbol_type; +@union_or_intersection_type = @union_type | @intersection_type; +@typevariable_type = @canonical_type_variable_type | @lexical_type_variable_type; + +has_asserts_keyword(int node: @predicate_typeexpr ref); + +@typed_ast_node = @expr | @typeexpr | @function; +ast_node_type( + unique int node: @typed_ast_node ref, + int typ: @type ref); + +declared_function_signature( + unique int node: @function ref, + int sig: @signature_type ref +); + +invoke_expr_signature( + unique int node: @invokeexpr ref, + int sig: @signature_type ref +); + +invoke_expr_overload_index( + unique int node: @invokeexpr ref, + int index: int ref +); + +symbols ( + unique int id: @symbol, + int kind: int ref, + varchar(900) name: string ref +); + +symbol_parent ( + unique int symbol: @symbol ref, + int parent: @symbol ref +); + +symbol_module ( + int symbol: @symbol ref, + varchar(900) moduleName: string ref +); + +symbol_global ( + int symbol: @symbol ref, + varchar(900) globalName: string ref +); + +case @symbol.kind of + 0 = @root_symbol +| 1 = @member_symbol +| 2 = @other_symbol +; + +@type_with_symbol = @type_reference | @typevariable_type | @typeof_type | @unique_symbol_type; +@ast_node_with_symbol = @type_definition | @namespace_definition | @toplevel | @typeaccess | @namespace_access | @var_decl | @function | @invokeexpr | @import_declaration | @external_module_reference; + +ast_node_symbol( + unique int node: @ast_node_with_symbol ref, + int symbol: @symbol ref); + +type_symbol( + unique int typ: @type_with_symbol ref, + int symbol: @symbol ref); + +#keyset[typ, name] +type_property( + int typ: @type ref, + varchar(900) name: string ref, + int propertyType: @type ref); + +type_alias( + unique int aliasType: @type ref, + int underlyingType: @type ref); + +@literal_type = @string_literal_type | @number_literal_type | @boolean_literal_type | @bigint_literal_type; +@type_with_literal_value = @string_literal_type | @number_literal_type | @bigint_literal_type; +type_literal_value( + unique int typ: @type_with_literal_value ref, + varchar(900) value: string ref); + +signature_types ( + unique int id: @signature_type, + int kind: int ref, + varchar(900) tostring: string ref, + int type_parameters: int ref, + int required_params: int ref +); + +signature_rest_parameter( + unique int sig: @signature_type ref, + int rest_param_arra_type: @type ref +); + +case @signature_type.kind of + 0 = @function_signature_type +| 1 = @constructor_signature_type +; + +#keyset[typ, kind, index] +type_contains_signature ( + int typ: @type ref, + int kind: int ref, // constructor/call/index + int index: int ref, // ordering of overloaded signatures + int sig: @signature_type ref +); + +#keyset[parent, index] +signature_contains_type ( + int child: @type ref, + int parent: @signature_type ref, + int index: int ref +); + +#keyset[sig, index] +signature_parameter_name ( + int sig: @signature_type ref, + int index: int ref, + varchar(900) name: string ref +); + +number_index_type ( + unique int baseType: @type ref, + int propertyType: @type ref +); + +string_index_type ( + unique int baseType: @type ref, + int propertyType: @type ref +); + +base_type_names( + int typeName: @symbol ref, + int baseTypeName: @symbol ref +); + +self_types( + int typeName: @symbol ref, + int selfType: @type_reference ref +); + +tuple_type_min_length( + unique int typ: @type ref, + int minLength: int ref +); + +tuple_type_rest( + unique int typ: @type ref +); + +// comments +comments (unique int id: @comment, + int kind: int ref, + int toplevel: @toplevel ref, + varchar(900) text: string ref, + varchar(900) tostring: string ref); + +case @comment.kind of + 0 = @slashslash_comment +| 1 = @slashstar_comment +| 2 = @doc_comment +| 3 = @html_comment_start +| 4 = @htmlcommentend; + +@html_comment = @html_comment_start | @htmlcommentend; +@line_comment = @slashslash_comment | @html_comment; +@block_comment = @slashstar_comment | @doc_comment; + +// source lines +lines (unique int id: @line, + int toplevel: @toplevel ref, + varchar(900) text: string ref, + varchar(2) terminator: string ref); +indentation (int file: @file ref, + int lineno: int ref, + varchar(1) indentChar: string ref, + int indentDepth: int ref); + +// JavaScript parse errors +js_parse_errors (unique int id: @js_parse_error, + int toplevel: @toplevel ref, + varchar(900) message: string ref, + varchar(900) line: string ref); + +// regular expressions +#keyset[parent, idx] +regexpterm (unique int id: @regexpterm, + int kind: int ref, + int parent: @regexpparent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +@regexpparent = @regexpterm | @regexp_literal | @string_literal; + +case @regexpterm.kind of + 0 = @regexp_alt +| 1 = @regexp_seq +| 2 = @regexp_caret +| 3 = @regexp_dollar +| 4 = @regexp_wordboundary +| 5 = @regexp_nonwordboundary +| 6 = @regexp_positive_lookahead +| 7 = @regexp_negative_lookahead +| 8 = @regexp_star +| 9 = @regexp_plus +| 10 = @regexp_opt +| 11 = @regexp_range +| 12 = @regexp_dot +| 13 = @regexp_group +| 14 = @regexp_normal_constant +| 15 = @regexp_hex_escape +| 16 = @regexp_unicode_escape +| 17 = @regexp_dec_escape +| 18 = @regexp_oct_escape +| 19 = @regexp_ctrl_escape +| 20 = @regexp_char_class_escape +| 21 = @regexp_id_escape +| 22 = @regexp_backref +| 23 = @regexp_char_class +| 24 = @regexp_char_range +| 25 = @regexp_positive_lookbehind +| 26 = @regexp_negative_lookbehind +| 27 = @regexp_unicode_property_escape; + +regexp_parse_errors (unique int id: @regexp_parse_error, + int regexp: @regexpterm ref, + varchar(900) message: string ref); + +@regexp_quantifier = @regexp_star | @regexp_plus | @regexp_opt | @regexp_range; +@regexp_escape = @regexp_char_escape | @regexp_char_class_escape | @regexp_unicode_property_escape; +@regexp_char_escape = @regexp_hex_escape | @regexp_unicode_escape | @regexp_dec_escape | @regexp_oct_escape | @regexp_ctrl_escape | @regexp_id_escape; +@regexp_constant = @regexp_normal_constant | @regexp_char_escape; +@regexp_lookahead = @regexp_positive_lookahead | @regexp_negative_lookahead; +@regexp_lookbehind = @regexp_positive_lookbehind | @regexp_negative_lookbehind; +@regexp_subpattern = @regexp_lookahead | @regexp_lookbehind; +@regexp_anchor = @regexp_dollar | @regexp_caret; + +is_greedy (int id: @regexp_quantifier ref); +range_quantifier_lower_bound (unique int id: @regexp_range ref, int lo: int ref); +range_quantifier_upper_bound (unique int id: @regexp_range ref, int hi: int ref); +is_capture (unique int id: @regexp_group ref, int number: int ref); +is_named_capture (unique int id: @regexp_group ref, string name: string ref); +is_inverted (int id: @regexp_char_class ref); +regexp_const_value (unique int id: @regexp_constant ref, varchar(1) value: string ref); +char_class_escape (unique int id: @regexp_char_class_escape ref, varchar(1) value: string ref); +backref (unique int id: @regexp_backref ref, int value: int ref); +named_backref (unique int id: @regexp_backref ref, string name: string ref); +unicode_property_escapename (unique int id: @regexp_unicode_property_escape ref, string name: string ref); +unicode_property_escapevalue (unique int id: @regexp_unicode_property_escape ref, string value: string ref); + +// tokens +#keyset[toplevel, idx] +tokeninfo (unique int id: @token, + int kind: int ref, + int toplevel: @toplevel ref, + int idx: int ref, + varchar(900) value: string ref); + +case @token.kind of + 0 = @token_eof +| 1 = @token_null_literal +| 2 = @token_boolean_literal +| 3 = @token_numeric_literal +| 4 = @token_string_literal +| 5 = @token_regular_expression +| 6 = @token_identifier +| 7 = @token_keyword +| 8 = @token_punctuator; + +// associate comments with the token immediately following them (which may be EOF) +next_token (int comment: @comment ref, int token: @token ref); + +// JSON +#keyset[parent, idx] +json (unique int id: @json_value, + int kind: int ref, + int parent: @json_parent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +json_literals (varchar(900) value: string ref, + varchar(900) raw: string ref, + unique int expr: @json_value ref); + +json_properties (int obj: @json_object ref, + varchar(900) property: string ref, + int value: @json_value ref); + +json_errors (unique int id: @json_parse_error, + varchar(900) message: string ref); + +json_locations(unique int locatable: @json_locatable ref, + int location: @location_default ref); + +case @json_value.kind of + 0 = @json_null +| 1 = @json_boolean +| 2 = @json_number +| 3 = @json_string +| 4 = @json_array +| 5 = @json_object; + +@json_parent = @json_object | @json_array | @file; + +@json_locatable = @json_value | @json_parse_error; + +// locations +@ast_node = @toplevel | @stmt | @expr | @property | @typeexpr; + +@locatable = @file + | @ast_node + | @comment + | @line + | @js_parse_error | @regexp_parse_error + | @regexpterm + | @json_locatable + | @token + | @cfg_node + | @jsdoc | @jsdoc_type_expr | @jsdoc_tag + | @yaml_locatable + | @xmllocatable + | @configLocatable; + +hasLocation (unique int locatable: @locatable ref, + int location: @location ref); + +// CFG +entry_cfg_node (unique int id: @entry_node, int container: @stmt_container ref); +exit_cfg_node (unique int id: @exit_node, int container: @stmt_container ref); +guard_node (unique int id: @guard_node, int kind: int ref, int test: @expr ref); +case @guard_node.kind of + 0 = @falsy_guard +| 1 = @truthy_guard; +@condition_guard = @falsy_guard | @truthy_guard; + +@synthetic_cfg_node = @entry_node | @exit_node | @guard_node; +@cfg_node = @synthetic_cfg_node | @expr_parent; + +successor (int pred: @cfg_node ref, int succ: @cfg_node ref); + +// JSDoc comments +jsdoc (unique int id: @jsdoc, varchar(900) description: string ref, int comment: @comment ref); +#keyset[parent, idx] +jsdoc_tags (unique int id: @jsdoc_tag, varchar(900) title: string ref, + int parent: @jsdoc ref, int idx: int ref, varchar(900) tostring: string ref); +jsdoc_tag_descriptions (unique int tag: @jsdoc_tag ref, varchar(900) text: string ref); +jsdoc_tag_names (unique int tag: @jsdoc_tag ref, varchar(900) text: string ref); + +#keyset[parent, idx] +jsdoc_type_exprs (unique int id: @jsdoc_type_expr, + int kind: int ref, + int parent: @jsdoc_type_expr_parent ref, + int idx: int ref, + varchar(900) tostring: string ref); +case @jsdoc_type_expr.kind of + 0 = @jsdoc_any_type_expr +| 1 = @jsdoc_null_type_expr +| 2 = @jsdoc_undefined_type_expr +| 3 = @jsdoc_unknown_type_expr +| 4 = @jsdoc_void_type_expr +| 5 = @jsdoc_named_type_expr +| 6 = @jsdoc_applied_type_expr +| 7 = @jsdoc_nullable_type_expr +| 8 = @jsdoc_non_nullable_type_expr +| 9 = @jsdoc_record_type_expr +| 10 = @jsdoc_array_type_expr +| 11 = @jsdoc_union_type_expr +| 12 = @jsdoc_function_type_expr +| 13 = @jsdoc_optional_type_expr +| 14 = @jsdoc_rest_type_expr +; + +#keyset[id, idx] +jsdoc_record_field_name (int id: @jsdoc_record_type_expr ref, int idx: int ref, varchar(900) name: string ref); +jsdoc_prefix_qualifier (int id: @jsdoc_type_expr ref); +jsdoc_has_new_parameter (int fn: @jsdoc_function_type_expr ref); + +@jsdoc_type_expr_parent = @jsdoc_type_expr | @jsdoc_tag; + +jsdoc_errors (unique int id: @jsdoc_error, int tag: @jsdoc_tag ref, varchar(900) message: string ref, varchar(900) tostring: string ref); + +// YAML +#keyset[parent, idx] +yaml (unique int id: @yaml_node, + int kind: int ref, + int parent: @yaml_node_parent ref, + int idx: int ref, + varchar(900) tag: string ref, + varchar(900) tostring: string ref); + +case @yaml_node.kind of + 0 = @yaml_scalar_node +| 1 = @yaml_mapping_node +| 2 = @yaml_sequence_node +| 3 = @yaml_alias_node +; + +@yaml_collection_node = @yaml_mapping_node | @yaml_sequence_node; + +@yaml_node_parent = @yaml_collection_node | @file; + +yaml_anchors (unique int node: @yaml_node ref, + varchar(900) anchor: string ref); + +yaml_aliases (unique int alias: @yaml_alias_node ref, + varchar(900) target: string ref); + +yaml_scalars (unique int scalar: @yaml_scalar_node ref, + int style: int ref, + varchar(900) value: string ref); + +yaml_errors (unique int id: @yaml_error, + varchar(900) message: string ref); + +yaml_locations(unique int locatable: @yaml_locatable ref, + int location: @location_default ref); + +@yaml_locatable = @yaml_node | @yaml_error; + +/* XML Files */ + +xmlEncoding( + unique int id: @file ref, + varchar(900) encoding: string ref +); + +xmlDTDs( + unique int id: @xmldtd, + varchar(900) root: string ref, + varchar(900) publicId: string ref, + varchar(900) systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + varchar(900) name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + varchar(900) name: string ref, + varchar(3600) value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + varchar(900) prefixName: string ref, + varchar(900) URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + varchar(3600) text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + varchar(3600) text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; + +@dataflownode = @expr | @function_decl_stmt | @class_decl_stmt | @namespace_declaration | @enum_declaration | @property; + +@optionalchainable = @call_expr | @propaccess; + +isOptionalChaining(int id: @optionalchainable ref); + +/* + * configuration files with key value pairs + */ + +configs( + unique int id: @config +); + +configNames( + unique int id: @configName, + int config: @config ref, + string name: string ref +); + +configValues( + unique int id: @configValue, + int config: @config ref, + string value: string ref +); + +configLocations( + int locatable: @configLocatable ref, + int location: @location_default ref +); + +@configLocatable = @config | @configName | @configValue; + +/** + * The time taken for the extraction of a file. + * This table contains non-deterministic content. + * + * The sum of the `time` column for each (`file`, `timerKind`) pair + * is the total time taken for extraction of `file`. The `extractionPhase` + * column provides a granular view of the extraction time of the file. + */ +extraction_time( + int file : @file ref, + // see `com.semmle.js.extractor.ExtractionMetrics.ExtractionPhase`. + int extractionPhase: int ref, + // 0 for the elapsed CPU time in nanoseconds, 1 for the elapsed wallclock time in nanoseconds + int timerKind: int ref, + float time: float ref +) + +/** + * Non-timing related data for the extraction of a single file. + * This table contains non-deterministic content. + */ +extraction_data( + int file : @file ref, + // the absolute path to the cache file + varchar(900) cacheFile: string ref, + boolean fromCache: boolean ref, + int length: int ref +) diff --git a/javascript/upgrades/930898a4fe07cb48de46800904922ca118b31e50/semmlecode.javascript.dbscheme b/javascript/upgrades/930898a4fe07cb48de46800904922ca118b31e50/semmlecode.javascript.dbscheme new file mode 100644 index 00000000000..72028aa6f0b --- /dev/null +++ b/javascript/upgrades/930898a4fe07cb48de46800904922ca118b31e50/semmlecode.javascript.dbscheme @@ -0,0 +1,1207 @@ +/*** Standard fragments ***/ + +/** Files and folders **/ + +@location = @location_default; + +locations_default(unique int id: @location_default, + int file: @file ref, + int beginLine: int ref, + int beginColumn: int ref, + int endLine: int ref, + int endColumn: int ref + ); + +@sourceline = @locatable; + +numlines(int element_id: @sourceline ref, + int num_lines: int ref, + int num_code: int ref, + int num_comment: int ref + ); + + +/* + fromSource(0) = unknown, + fromSource(1) = from source, + fromSource(2) = from library +*/ +files(unique int id: @file, + varchar(900) name: string ref, + varchar(900) simple: string ref, + varchar(900) ext: string ref, + int fromSource: int ref); + +folders(unique int id: @folder, + varchar(900) name: string ref, + varchar(900) simple: string ref); + + +@container = @folder | @file ; + + +containerparent(int parent: @container ref, + unique int child: @container ref); + +/** Duplicate code **/ + +duplicateCode( + unique int id : @duplication, + varchar(900) relativePath : string ref, + int equivClass : int ref); + +similarCode( + unique int id : @similarity, + varchar(900) relativePath : string ref, + int equivClass : int ref); + +@duplication_or_similarity = @duplication | @similarity; + +tokens( + int id : @duplication_or_similarity ref, + int offset : int ref, + int beginLine : int ref, + int beginColumn : int ref, + int endLine : int ref, + int endColumn : int ref); + +/** External data **/ + +externalData( + int id : @externalDataElement, + varchar(900) path : string ref, + int column: int ref, + varchar(900) value : string ref +); + +snapshotDate(unique date snapshotDate : date ref); + +sourceLocationPrefix(varchar(900) prefix : string ref); + +/** Version control data **/ + +svnentries( + int id : @svnentry, + varchar(500) revision : string ref, + varchar(500) author : string ref, + date revisionDate : date ref, + int changeSize : int ref +); + +svnaffectedfiles( + int id : @svnentry ref, + int file : @file ref, + varchar(500) action : string ref +); + +svnentrymsg( + int id : @svnentry ref, + varchar(500) message : string ref +); + +svnchurn( + int commit : @svnentry ref, + int file : @file ref, + int addedLines : int ref, + int deletedLines : int ref +); + + +/*** JavaScript-specific part ***/ + +filetype( + int file: @file ref, + string filetype: string ref +) + +// top-level code fragments +toplevels (unique int id: @toplevel, + int kind: int ref); + +is_externs (int toplevel: @toplevel ref); + +case @toplevel.kind of + 0 = @script +| 1 = @inline_script +| 2 = @event_handler +| 3 = @javascript_url +| 4 = @angular_template_toplevel; + +is_module (int tl: @toplevel ref); +is_nodejs (int tl: @toplevel ref); +is_es2015_module (int tl: @toplevel ref); +is_closure_module (int tl: @toplevel ref); + +@xml_node_with_code = @xmlelement | @xmlattribute; +toplevel_parent_xml_node( + unique int toplevel: @toplevel ref, + int xmlnode: @xml_node_with_code ref); + +xml_element_parent_expression( + unique int xmlnode: @xmlelement ref, + int expression: @expr ref, + int index: int ref); + +// statements +#keyset[parent, idx] +stmts (unique int id: @stmt, + int kind: int ref, + int parent: @stmt_parent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +stmt_containers (unique int stmt: @stmt ref, + int container: @stmt_container ref); + +jump_targets (unique int jump: @stmt ref, + int target: @stmt ref); + +@stmt_parent = @stmt | @toplevel | @function_expr | @arrow_function_expr; +@stmt_container = @toplevel | @function | @namespace_declaration | @external_module_declaration | @global_augmentation_declaration; + +case @stmt.kind of + 0 = @empty_stmt +| 1 = @block_stmt +| 2 = @expr_stmt +| 3 = @if_stmt +| 4 = @labeled_stmt +| 5 = @break_stmt +| 6 = @continue_stmt +| 7 = @with_stmt +| 8 = @switch_stmt +| 9 = @return_stmt +| 10 = @throw_stmt +| 11 = @try_stmt +| 12 = @while_stmt +| 13 = @do_while_stmt +| 14 = @for_stmt +| 15 = @for_in_stmt +| 16 = @debugger_stmt +| 17 = @function_decl_stmt +| 18 = @var_decl_stmt +| 19 = @case +| 20 = @catch_clause +| 21 = @for_of_stmt +| 22 = @const_decl_stmt +| 23 = @let_stmt +| 24 = @legacy_let_stmt +| 25 = @for_each_stmt +| 26 = @class_decl_stmt +| 27 = @import_declaration +| 28 = @export_all_declaration +| 29 = @export_default_declaration +| 30 = @export_named_declaration +| 31 = @namespace_declaration +| 32 = @import_equals_declaration +| 33 = @export_assign_declaration +| 34 = @interface_declaration +| 35 = @type_alias_declaration +| 36 = @enum_declaration +| 37 = @external_module_declaration +| 38 = @export_as_namespace_declaration +| 39 = @global_augmentation_declaration +; + +@decl_stmt = @var_decl_stmt | @const_decl_stmt | @let_stmt | @legacy_let_stmt; + +@export_declaration = @export_all_declaration | @export_default_declaration | @export_named_declaration; + +@namespace_definition = @namespace_declaration | @enum_declaration; +@type_definition = @class_definition | @interface_declaration | @enum_declaration | @type_alias_declaration | @enum_member; + +is_instantiated(unique int decl: @namespace_declaration ref); + +@declarable_node = @decl_stmt | @namespace_declaration | @class_decl_stmt | @function_decl_stmt | @enum_declaration | @external_module_declaration | @global_augmentation_declaration | @field; +has_declare_keyword(unique int stmt: @declarable_node ref); + +is_for_await_of(unique int forof: @for_of_stmt ref); + +// expressions +#keyset[parent, idx] +exprs (unique int id: @expr, + int kind: int ref, + int parent: @expr_parent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +literals (varchar(900) value: string ref, + varchar(900) raw: string ref, + unique int expr: @expr_or_type ref); + +enclosing_stmt (unique int expr: @expr_or_type ref, + int stmt: @stmt ref); + +expr_containers (unique int expr: @expr_or_type ref, + int container: @stmt_container ref); + +array_size (unique int ae: @arraylike ref, + int sz: int ref); + +is_delegating (int yield: @yield_expr ref); + +@expr_or_stmt = @expr | @stmt; +@expr_or_type = @expr | @typeexpr; +@expr_parent = @expr_or_stmt | @property | @function_typeexpr; +@arraylike = @array_expr | @array_pattern; +@type_annotation = @typeexpr | @jsdoc_type_expr; +@node_in_stmt_container = @cfg_node | @type_annotation | @toplevel; + +case @expr.kind of + 0 = @label +| 1 = @null_literal +| 2 = @boolean_literal +| 3 = @number_literal +| 4 = @string_literal +| 5 = @regexp_literal +| 6 = @this_expr +| 7 = @array_expr +| 8 = @obj_expr +| 9 = @function_expr +| 10 = @seq_expr +| 11 = @conditional_expr +| 12 = @new_expr +| 13 = @call_expr +| 14 = @dot_expr +| 15 = @index_expr +| 16 = @neg_expr +| 17 = @plus_expr +| 18 = @log_not_expr +| 19 = @bit_not_expr +| 20 = @typeof_expr +| 21 = @void_expr +| 22 = @delete_expr +| 23 = @eq_expr +| 24 = @neq_expr +| 25 = @eqq_expr +| 26 = @neqq_expr +| 27 = @lt_expr +| 28 = @le_expr +| 29 = @gt_expr +| 30 = @ge_expr +| 31 = @lshift_expr +| 32 = @rshift_expr +| 33 = @urshift_expr +| 34 = @add_expr +| 35 = @sub_expr +| 36 = @mul_expr +| 37 = @div_expr +| 38 = @mod_expr +| 39 = @bitor_expr +| 40 = @xor_expr +| 41 = @bitand_expr +| 42 = @in_expr +| 43 = @instanceof_expr +| 44 = @logand_expr +| 45 = @logor_expr +| 47 = @assign_expr +| 48 = @assign_add_expr +| 49 = @assign_sub_expr +| 50 = @assign_mul_expr +| 51 = @assign_div_expr +| 52 = @assign_mod_expr +| 53 = @assign_lshift_expr +| 54 = @assign_rshift_expr +| 55 = @assign_urshift_expr +| 56 = @assign_or_expr +| 57 = @assign_xor_expr +| 58 = @assign_and_expr +| 59 = @preinc_expr +| 60 = @postinc_expr +| 61 = @predec_expr +| 62 = @postdec_expr +| 63 = @par_expr +| 64 = @var_declarator +| 65 = @arrow_function_expr +| 66 = @spread_element +| 67 = @array_pattern +| 68 = @object_pattern +| 69 = @yield_expr +| 70 = @tagged_template_expr +| 71 = @template_literal +| 72 = @template_element +| 73 = @array_comprehension_expr +| 74 = @generator_expr +| 75 = @for_in_comprehension_block +| 76 = @for_of_comprehension_block +| 77 = @legacy_letexpr +| 78 = @var_decl +| 79 = @proper_varaccess +| 80 = @class_expr +| 81 = @super_expr +| 82 = @newtarget_expr +| 83 = @named_import_specifier +| 84 = @import_default_specifier +| 85 = @import_namespace_specifier +| 86 = @named_export_specifier +| 87 = @exp_expr +| 88 = @assign_exp_expr +| 89 = @jsx_element +| 90 = @jsx_qualified_name +| 91 = @jsx_empty_expr +| 92 = @await_expr +| 93 = @function_sent_expr +| 94 = @decorator +| 95 = @export_default_specifier +| 96 = @export_namespace_specifier +| 97 = @bind_expr +| 98 = @external_module_reference +| 99 = @dynamic_import +| 100 = @expression_with_type_arguments +| 101 = @prefix_type_assertion +| 102 = @as_type_assertion +| 103 = @export_varaccess +| 104 = @decorator_list +| 105 = @non_null_assertion +| 106 = @bigint_literal +| 107 = @nullishcoalescing_expr +| 108 = @e4x_xml_anyname +| 109 = @e4x_xml_static_attribute_selector +| 110 = @e4x_xml_dynamic_attribute_selector +| 111 = @e4x_xml_filter_expression +| 112 = @e4x_xml_static_qualident +| 113 = @e4x_xml_dynamic_qualident +| 114 = @e4x_xml_dotdotexpr +| 115 = @import_meta_expr +| 116 = @assignlogandexpr +| 117 = @assignlogorexpr +| 118 = @assignnullishcoalescingexpr +| 119 = @angular_pipe_ref +; + +@varaccess = @proper_varaccess | @export_varaccess; +@varref = @var_decl | @varaccess; + +@identifier = @label | @varref | @type_identifier; + +@literal = @null_literal | @boolean_literal | @number_literal | @string_literal | @regexp_literal | @bigint_literal; + +@propaccess = @dot_expr | @index_expr; + +@invokeexpr = @new_expr | @call_expr; + +@unaryexpr = @neg_expr | @plus_expr | @log_not_expr | @bit_not_expr | @typeof_expr | @void_expr | @delete_expr | @spread_element; + +@equality_test = @eq_expr | @neq_expr | @eqq_expr | @neqq_expr; + +@comparison = @equality_test | @lt_expr | @le_expr | @gt_expr | @ge_expr; + +@binaryexpr = @comparison | @lshift_expr | @rshift_expr | @urshift_expr | @add_expr | @sub_expr | @mul_expr | @div_expr | @mod_expr | @exp_expr | @bitor_expr | @xor_expr | @bitand_expr | @in_expr | @instanceof_expr | @logand_expr | @logor_expr | @nullishcoalescing_expr; + +@assignment = @assign_expr | @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr | @assign_mod_expr | @assign_exp_expr | @assign_lshift_expr | @assign_rshift_expr | @assign_urshift_expr | @assign_or_expr | @assign_xor_expr | @assign_and_expr | @assignlogandexpr | @assignlogorexpr | @assignnullishcoalescingexpr; + +@updateexpr = @preinc_expr | @postinc_expr | @predec_expr | @postdec_expr; + +@pattern = @varref | @array_pattern | @object_pattern; + +@comprehension_expr = @array_comprehension_expr | @generator_expr; + +@comprehension_block = @for_in_comprehension_block | @for_of_comprehension_block; + +@import_specifier = @named_import_specifier | @import_default_specifier | @import_namespace_specifier; + +@exportspecifier = @named_export_specifier | @export_default_specifier | @export_namespace_specifier; + +@import_or_export_declaration = @import_declaration | @export_declaration; + +@type_assertion = @as_type_assertion | @prefix_type_assertion; + +@class_definition = @class_decl_stmt | @class_expr; +@interface_definition = @interface_declaration | @interface_typeexpr; +@class_or_interface = @class_definition | @interface_definition; + +@lexical_decl = @var_decl | @type_decl; +@lexical_access = @varaccess | @local_type_access | @local_var_type_access | @local_namespace_access; +@lexical_ref = @lexical_decl | @lexical_access; + +@e4x_xml_attribute_selector = @e4x_xml_static_attribute_selector | @e4x_xml_dynamic_attribute_selector; +@e4x_xml_qualident = @e4x_xml_static_qualident | @e4x_xml_dynamic_qualident; + +// scopes +scopes (unique int id: @scope, + int kind: int ref); + +case @scope.kind of + 0 = @global_scope +| 1 = @function_scope +| 2 = @catch_scope +| 3 = @module_scope +| 4 = @block_scope +| 5 = @for_scope +| 6 = @for_in_scope // for-of scopes work the same as for-in scopes +| 7 = @comprehension_block_scope +| 8 = @class_expr_scope +| 9 = @namespace_scope +| 10 = @class_decl_scope +| 11 = @interface_scope +| 12 = @type_alias_scope +| 13 = @mapped_type_scope +| 14 = @enum_scope +| 15 = @external_module_scope +| 16 = @conditional_type_scope; + +scopenodes (unique int node: @ast_node ref, + int scope: @scope ref); + +scopenesting (unique int inner: @scope ref, + int outer: @scope ref); + +// functions +@function = @function_decl_stmt | @function_expr | @arrow_function_expr; + +@parameterized = @function | @catch_clause; +@type_parameterized = @function | @class_or_interface | @type_alias_declaration | @mapped_typeexpr | @infer_typeexpr; + +is_generator (int fun: @function ref); +has_rest_parameter (int fun: @function ref); +is_async (int fun: @function ref); + +// variables and lexically scoped type names +#keyset[scope, name] +variables (unique int id: @variable, + varchar(900) name: string ref, + int scope: @scope ref); + +#keyset[scope, name] +local_type_names (unique int id: @local_type_name, + varchar(900) name: string ref, + int scope: @scope ref); + +#keyset[scope, name] +local_namespace_names (unique int id: @local_namespace_name, + varchar(900) name: string ref, + int scope: @scope ref); + +is_arguments_object (int id: @variable ref); + +@lexical_name = @variable | @local_type_name | @local_namespace_name; + +@bind_id = @varaccess | @local_var_type_access; +bind (unique int id: @bind_id ref, + int decl: @variable ref); + +decl (unique int id: @var_decl ref, + int decl: @variable ref); + +@typebind_id = @local_type_access | @export_varaccess; +typebind (unique int id: @typebind_id ref, + int decl: @local_type_name ref); + +@typedecl_id = @type_decl | @var_decl; +typedecl (unique int id: @typedecl_id ref, + int decl: @local_type_name ref); + +namespacedecl (unique int id: @var_decl ref, + int decl: @local_namespace_name ref); + +@namespacebind_id = @local_namespace_access | @export_varaccess; +namespacebind (unique int id: @namespacebind_id ref, + int decl: @local_namespace_name ref); + + +// properties in object literals, property patterns in object patterns, and method declarations in classes +#keyset[parent, index] +properties (unique int id: @property, + int parent: @property_parent ref, + int index: int ref, + int kind: int ref, + varchar(900) tostring: string ref); + +case @property.kind of + 0 = @value_property +| 1 = @property_getter +| 2 = @property_setter +| 3 = @jsx_attribute +| 4 = @function_call_signature +| 5 = @constructor_call_signature +| 6 = @index_signature +| 7 = @enum_member +| 8 = @proper_field +| 9 = @parameter_field +; + +@property_parent = @obj_expr | @object_pattern | @class_definition | @jsx_element | @interface_definition | @enum_declaration; +@property_accessor = @property_getter | @property_setter; +@call_signature = @function_call_signature | @constructor_call_signature; +@field = @proper_field | @parameter_field; +@field_or_vardeclarator = @field | @var_declarator; + +is_computed (int id: @property ref); +is_method (int id: @property ref); +is_static (int id: @property ref); +is_abstract_member (int id: @property ref); +is_const_enum (int id: @enum_declaration ref); +is_abstract_class (int id: @class_decl_stmt ref); + +has_public_keyword (int id: @property ref); +has_private_keyword (int id: @property ref); +has_protected_keyword (int id: @property ref); +has_readonly_keyword (int id: @property ref); +has_type_keyword (int id: @import_or_export_declaration ref); +is_optional_member (int id: @property ref); +has_definite_assignment_assertion (int id: @field_or_vardeclarator ref); +is_optional_parameter_declaration (unique int parameter: @pattern ref); + +#keyset[constructor, param_index] +parameter_fields( + unique int field: @parameter_field ref, + int constructor: @function_expr ref, + int param_index: int ref +); + +// types +#keyset[parent, idx] +typeexprs ( + unique int id: @typeexpr, + int kind: int ref, + int parent: @typeexpr_parent ref, + int idx: int ref, + varchar(900) tostring: string ref +); + +case @typeexpr.kind of + 0 = @local_type_access +| 1 = @type_decl +| 2 = @keyword_typeexpr +| 3 = @string_literal_typeexpr +| 4 = @number_literal_typeexpr +| 5 = @boolean_literal_typeexpr +| 6 = @array_typeexpr +| 7 = @union_typeexpr +| 8 = @indexed_access_typeexpr +| 9 = @intersection_typeexpr +| 10 = @parenthesized_typeexpr +| 11 = @tuple_typeexpr +| 12 = @keyof_typeexpr +| 13 = @qualified_type_access +| 14 = @generic_typeexpr +| 15 = @type_label +| 16 = @typeof_typeexpr +| 17 = @local_var_type_access +| 18 = @qualified_var_type_access +| 19 = @this_var_type_access +| 20 = @predicate_typeexpr +| 21 = @interface_typeexpr +| 22 = @type_parameter +| 23 = @plain_function_typeexpr +| 24 = @constructor_typeexpr +| 25 = @local_namespace_access +| 26 = @qualified_namespace_access +| 27 = @mapped_typeexpr +| 28 = @conditional_typeexpr +| 29 = @infer_typeexpr +| 30 = @import_type_access +| 31 = @import_namespace_access +| 32 = @import_var_type_access +| 33 = @optional_typeexpr +| 34 = @rest_typeexpr +| 35 = @bigint_literal_typeexpr +| 36 = @readonly_typeexpr +| 37 = @template_literal_typeexpr +; + +@typeref = @typeaccess | @type_decl; +@type_identifier = @type_decl | @local_type_access | @type_label | @local_var_type_access | @local_namespace_access; +@typeexpr_parent = @expr | @stmt | @property | @typeexpr; +@literal_typeexpr = @string_literal_typeexpr | @number_literal_typeexpr | @boolean_literal_typeexpr | @bigint_literal_typeexpr; +@typeaccess = @local_type_access | @qualified_type_access | @import_type_access; +@vartypeaccess = @local_var_type_access | @qualified_var_type_access | @this_var_type_access | @import_var_type_access; +@namespace_access = @local_namespace_access | @qualified_namespace_access | @import_namespace_access; +@import_typeexpr = @import_type_access | @import_namespace_access | @import_var_type_access; + +@function_typeexpr = @plain_function_typeexpr | @constructor_typeexpr; + +// types +types ( + unique int id: @type, + int kind: int ref, + varchar(900) tostring: string ref +); + +#keyset[parent, idx] +type_child ( + int child: @type ref, + int parent: @type ref, + int idx: int ref +); + +case @type.kind of + 0 = @any_type +| 1 = @string_type +| 2 = @number_type +| 3 = @union_type +| 4 = @true_type +| 5 = @false_type +| 6 = @type_reference +| 7 = @object_type +| 8 = @canonical_type_variable_type +| 9 = @typeof_type +| 10 = @void_type +| 11 = @undefined_type +| 12 = @null_type +| 13 = @never_type +| 14 = @plain_symbol_type +| 15 = @unique_symbol_type +| 16 = @objectkeyword_type +| 17 = @intersection_type +| 18 = @tuple_type +| 19 = @lexical_type_variable_type +| 20 = @this_type +| 21 = @number_literal_type +| 22 = @string_literal_type +| 23 = @unknown_type +| 24 = @bigint_type +| 25 = @bigint_literal_type +; + +@boolean_literal_type = @true_type | @false_type; +@symbol_type = @plain_symbol_type | @unique_symbol_type; +@union_or_intersection_type = @union_type | @intersection_type; +@typevariable_type = @canonical_type_variable_type | @lexical_type_variable_type; + +has_asserts_keyword(int node: @predicate_typeexpr ref); + +@typed_ast_node = @expr | @typeexpr | @function; +ast_node_type( + unique int node: @typed_ast_node ref, + int typ: @type ref); + +declared_function_signature( + unique int node: @function ref, + int sig: @signature_type ref +); + +invoke_expr_signature( + unique int node: @invokeexpr ref, + int sig: @signature_type ref +); + +invoke_expr_overload_index( + unique int node: @invokeexpr ref, + int index: int ref +); + +symbols ( + unique int id: @symbol, + int kind: int ref, + varchar(900) name: string ref +); + +symbol_parent ( + unique int symbol: @symbol ref, + int parent: @symbol ref +); + +symbol_module ( + int symbol: @symbol ref, + varchar(900) moduleName: string ref +); + +symbol_global ( + int symbol: @symbol ref, + varchar(900) globalName: string ref +); + +case @symbol.kind of + 0 = @root_symbol +| 1 = @member_symbol +| 2 = @other_symbol +; + +@type_with_symbol = @type_reference | @typevariable_type | @typeof_type | @unique_symbol_type; +@ast_node_with_symbol = @type_definition | @namespace_definition | @toplevel | @typeaccess | @namespace_access | @var_decl | @function | @invokeexpr | @import_declaration | @external_module_reference; + +ast_node_symbol( + unique int node: @ast_node_with_symbol ref, + int symbol: @symbol ref); + +type_symbol( + unique int typ: @type_with_symbol ref, + int symbol: @symbol ref); + +#keyset[typ, name] +type_property( + int typ: @type ref, + varchar(900) name: string ref, + int propertyType: @type ref); + +type_alias( + unique int aliasType: @type ref, + int underlyingType: @type ref); + +@literal_type = @string_literal_type | @number_literal_type | @boolean_literal_type | @bigint_literal_type; +@type_with_literal_value = @string_literal_type | @number_literal_type | @bigint_literal_type; +type_literal_value( + unique int typ: @type_with_literal_value ref, + varchar(900) value: string ref); + +signature_types ( + unique int id: @signature_type, + int kind: int ref, + varchar(900) tostring: string ref, + int type_parameters: int ref, + int required_params: int ref +); + +signature_rest_parameter( + unique int sig: @signature_type ref, + int rest_param_arra_type: @type ref +); + +case @signature_type.kind of + 0 = @function_signature_type +| 1 = @constructor_signature_type +; + +#keyset[typ, kind, index] +type_contains_signature ( + int typ: @type ref, + int kind: int ref, // constructor/call/index + int index: int ref, // ordering of overloaded signatures + int sig: @signature_type ref +); + +#keyset[parent, index] +signature_contains_type ( + int child: @type ref, + int parent: @signature_type ref, + int index: int ref +); + +#keyset[sig, index] +signature_parameter_name ( + int sig: @signature_type ref, + int index: int ref, + varchar(900) name: string ref +); + +number_index_type ( + unique int baseType: @type ref, + int propertyType: @type ref +); + +string_index_type ( + unique int baseType: @type ref, + int propertyType: @type ref +); + +base_type_names( + int typeName: @symbol ref, + int baseTypeName: @symbol ref +); + +self_types( + int typeName: @symbol ref, + int selfType: @type_reference ref +); + +tuple_type_min_length( + unique int typ: @type ref, + int minLength: int ref +); + +tuple_type_rest_index( + unique int typ: @type ref, + int index: int ref +); + +// comments +comments (unique int id: @comment, + int kind: int ref, + int toplevel: @toplevel ref, + varchar(900) text: string ref, + varchar(900) tostring: string ref); + +case @comment.kind of + 0 = @slashslash_comment +| 1 = @slashstar_comment +| 2 = @doc_comment +| 3 = @html_comment_start +| 4 = @htmlcommentend; + +@html_comment = @html_comment_start | @htmlcommentend; +@line_comment = @slashslash_comment | @html_comment; +@block_comment = @slashstar_comment | @doc_comment; + +// source lines +lines (unique int id: @line, + int toplevel: @toplevel ref, + varchar(900) text: string ref, + varchar(2) terminator: string ref); +indentation (int file: @file ref, + int lineno: int ref, + varchar(1) indentChar: string ref, + int indentDepth: int ref); + +// JavaScript parse errors +js_parse_errors (unique int id: @js_parse_error, + int toplevel: @toplevel ref, + varchar(900) message: string ref, + varchar(900) line: string ref); + +// regular expressions +#keyset[parent, idx] +regexpterm (unique int id: @regexpterm, + int kind: int ref, + int parent: @regexpparent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +@regexpparent = @regexpterm | @regexp_literal | @string_literal; + +case @regexpterm.kind of + 0 = @regexp_alt +| 1 = @regexp_seq +| 2 = @regexp_caret +| 3 = @regexp_dollar +| 4 = @regexp_wordboundary +| 5 = @regexp_nonwordboundary +| 6 = @regexp_positive_lookahead +| 7 = @regexp_negative_lookahead +| 8 = @regexp_star +| 9 = @regexp_plus +| 10 = @regexp_opt +| 11 = @regexp_range +| 12 = @regexp_dot +| 13 = @regexp_group +| 14 = @regexp_normal_constant +| 15 = @regexp_hex_escape +| 16 = @regexp_unicode_escape +| 17 = @regexp_dec_escape +| 18 = @regexp_oct_escape +| 19 = @regexp_ctrl_escape +| 20 = @regexp_char_class_escape +| 21 = @regexp_id_escape +| 22 = @regexp_backref +| 23 = @regexp_char_class +| 24 = @regexp_char_range +| 25 = @regexp_positive_lookbehind +| 26 = @regexp_negative_lookbehind +| 27 = @regexp_unicode_property_escape; + +regexp_parse_errors (unique int id: @regexp_parse_error, + int regexp: @regexpterm ref, + varchar(900) message: string ref); + +@regexp_quantifier = @regexp_star | @regexp_plus | @regexp_opt | @regexp_range; +@regexp_escape = @regexp_char_escape | @regexp_char_class_escape | @regexp_unicode_property_escape; +@regexp_char_escape = @regexp_hex_escape | @regexp_unicode_escape | @regexp_dec_escape | @regexp_oct_escape | @regexp_ctrl_escape | @regexp_id_escape; +@regexp_constant = @regexp_normal_constant | @regexp_char_escape; +@regexp_lookahead = @regexp_positive_lookahead | @regexp_negative_lookahead; +@regexp_lookbehind = @regexp_positive_lookbehind | @regexp_negative_lookbehind; +@regexp_subpattern = @regexp_lookahead | @regexp_lookbehind; +@regexp_anchor = @regexp_dollar | @regexp_caret; + +is_greedy (int id: @regexp_quantifier ref); +range_quantifier_lower_bound (unique int id: @regexp_range ref, int lo: int ref); +range_quantifier_upper_bound (unique int id: @regexp_range ref, int hi: int ref); +is_capture (unique int id: @regexp_group ref, int number: int ref); +is_named_capture (unique int id: @regexp_group ref, string name: string ref); +is_inverted (int id: @regexp_char_class ref); +regexp_const_value (unique int id: @regexp_constant ref, varchar(1) value: string ref); +char_class_escape (unique int id: @regexp_char_class_escape ref, varchar(1) value: string ref); +backref (unique int id: @regexp_backref ref, int value: int ref); +named_backref (unique int id: @regexp_backref ref, string name: string ref); +unicode_property_escapename (unique int id: @regexp_unicode_property_escape ref, string name: string ref); +unicode_property_escapevalue (unique int id: @regexp_unicode_property_escape ref, string value: string ref); + +// tokens +#keyset[toplevel, idx] +tokeninfo (unique int id: @token, + int kind: int ref, + int toplevel: @toplevel ref, + int idx: int ref, + varchar(900) value: string ref); + +case @token.kind of + 0 = @token_eof +| 1 = @token_null_literal +| 2 = @token_boolean_literal +| 3 = @token_numeric_literal +| 4 = @token_string_literal +| 5 = @token_regular_expression +| 6 = @token_identifier +| 7 = @token_keyword +| 8 = @token_punctuator; + +// associate comments with the token immediately following them (which may be EOF) +next_token (int comment: @comment ref, int token: @token ref); + +// JSON +#keyset[parent, idx] +json (unique int id: @json_value, + int kind: int ref, + int parent: @json_parent ref, + int idx: int ref, + varchar(900) tostring: string ref); + +json_literals (varchar(900) value: string ref, + varchar(900) raw: string ref, + unique int expr: @json_value ref); + +json_properties (int obj: @json_object ref, + varchar(900) property: string ref, + int value: @json_value ref); + +json_errors (unique int id: @json_parse_error, + varchar(900) message: string ref); + +json_locations(unique int locatable: @json_locatable ref, + int location: @location_default ref); + +case @json_value.kind of + 0 = @json_null +| 1 = @json_boolean +| 2 = @json_number +| 3 = @json_string +| 4 = @json_array +| 5 = @json_object; + +@json_parent = @json_object | @json_array | @file; + +@json_locatable = @json_value | @json_parse_error; + +// locations +@ast_node = @toplevel | @stmt | @expr | @property | @typeexpr; + +@locatable = @file + | @ast_node + | @comment + | @line + | @js_parse_error | @regexp_parse_error + | @regexpterm + | @json_locatable + | @token + | @cfg_node + | @jsdoc | @jsdoc_type_expr | @jsdoc_tag + | @yaml_locatable + | @xmllocatable + | @configLocatable; + +hasLocation (unique int locatable: @locatable ref, + int location: @location ref); + +// CFG +entry_cfg_node (unique int id: @entry_node, int container: @stmt_container ref); +exit_cfg_node (unique int id: @exit_node, int container: @stmt_container ref); +guard_node (unique int id: @guard_node, int kind: int ref, int test: @expr ref); +case @guard_node.kind of + 0 = @falsy_guard +| 1 = @truthy_guard; +@condition_guard = @falsy_guard | @truthy_guard; + +@synthetic_cfg_node = @entry_node | @exit_node | @guard_node; +@cfg_node = @synthetic_cfg_node | @expr_parent; + +successor (int pred: @cfg_node ref, int succ: @cfg_node ref); + +// JSDoc comments +jsdoc (unique int id: @jsdoc, varchar(900) description: string ref, int comment: @comment ref); +#keyset[parent, idx] +jsdoc_tags (unique int id: @jsdoc_tag, varchar(900) title: string ref, + int parent: @jsdoc ref, int idx: int ref, varchar(900) tostring: string ref); +jsdoc_tag_descriptions (unique int tag: @jsdoc_tag ref, varchar(900) text: string ref); +jsdoc_tag_names (unique int tag: @jsdoc_tag ref, varchar(900) text: string ref); + +#keyset[parent, idx] +jsdoc_type_exprs (unique int id: @jsdoc_type_expr, + int kind: int ref, + int parent: @jsdoc_type_expr_parent ref, + int idx: int ref, + varchar(900) tostring: string ref); +case @jsdoc_type_expr.kind of + 0 = @jsdoc_any_type_expr +| 1 = @jsdoc_null_type_expr +| 2 = @jsdoc_undefined_type_expr +| 3 = @jsdoc_unknown_type_expr +| 4 = @jsdoc_void_type_expr +| 5 = @jsdoc_named_type_expr +| 6 = @jsdoc_applied_type_expr +| 7 = @jsdoc_nullable_type_expr +| 8 = @jsdoc_non_nullable_type_expr +| 9 = @jsdoc_record_type_expr +| 10 = @jsdoc_array_type_expr +| 11 = @jsdoc_union_type_expr +| 12 = @jsdoc_function_type_expr +| 13 = @jsdoc_optional_type_expr +| 14 = @jsdoc_rest_type_expr +; + +#keyset[id, idx] +jsdoc_record_field_name (int id: @jsdoc_record_type_expr ref, int idx: int ref, varchar(900) name: string ref); +jsdoc_prefix_qualifier (int id: @jsdoc_type_expr ref); +jsdoc_has_new_parameter (int fn: @jsdoc_function_type_expr ref); + +@jsdoc_type_expr_parent = @jsdoc_type_expr | @jsdoc_tag; + +jsdoc_errors (unique int id: @jsdoc_error, int tag: @jsdoc_tag ref, varchar(900) message: string ref, varchar(900) tostring: string ref); + +// YAML +#keyset[parent, idx] +yaml (unique int id: @yaml_node, + int kind: int ref, + int parent: @yaml_node_parent ref, + int idx: int ref, + varchar(900) tag: string ref, + varchar(900) tostring: string ref); + +case @yaml_node.kind of + 0 = @yaml_scalar_node +| 1 = @yaml_mapping_node +| 2 = @yaml_sequence_node +| 3 = @yaml_alias_node +; + +@yaml_collection_node = @yaml_mapping_node | @yaml_sequence_node; + +@yaml_node_parent = @yaml_collection_node | @file; + +yaml_anchors (unique int node: @yaml_node ref, + varchar(900) anchor: string ref); + +yaml_aliases (unique int alias: @yaml_alias_node ref, + varchar(900) target: string ref); + +yaml_scalars (unique int scalar: @yaml_scalar_node ref, + int style: int ref, + varchar(900) value: string ref); + +yaml_errors (unique int id: @yaml_error, + varchar(900) message: string ref); + +yaml_locations(unique int locatable: @yaml_locatable ref, + int location: @location_default ref); + +@yaml_locatable = @yaml_node | @yaml_error; + +/* XML Files */ + +xmlEncoding( + unique int id: @file ref, + varchar(900) encoding: string ref +); + +xmlDTDs( + unique int id: @xmldtd, + varchar(900) root: string ref, + varchar(900) publicId: string ref, + varchar(900) systemId: string ref, + int fileid: @file ref +); + +xmlElements( + unique int id: @xmlelement, + varchar(900) name: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int fileid: @file ref +); + +xmlAttrs( + unique int id: @xmlattribute, + int elementid: @xmlelement ref, + varchar(900) name: string ref, + varchar(3600) value: string ref, + int idx: int ref, + int fileid: @file ref +); + +xmlNs( + int id: @xmlnamespace, + varchar(900) prefixName: string ref, + varchar(900) URI: string ref, + int fileid: @file ref +); + +xmlHasNs( + int elementId: @xmlnamespaceable ref, + int nsId: @xmlnamespace ref, + int fileid: @file ref +); + +xmlComments( + unique int id: @xmlcomment, + varchar(3600) text: string ref, + int parentid: @xmlparent ref, + int fileid: @file ref +); + +xmlChars( + unique int id: @xmlcharacters, + varchar(3600) text: string ref, + int parentid: @xmlparent ref, + int idx: int ref, + int isCDATA: int ref, + int fileid: @file ref +); + +@xmlparent = @file | @xmlelement; +@xmlnamespaceable = @xmlelement | @xmlattribute; + +xmllocations( + int xmlElement: @xmllocatable ref, + int location: @location_default ref +); + +@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace; + +@dataflownode = @expr | @function_decl_stmt | @class_decl_stmt | @namespace_declaration | @enum_declaration | @property; + +@optionalchainable = @call_expr | @propaccess; + +isOptionalChaining(int id: @optionalchainable ref); + +/* + * configuration files with key value pairs + */ + +configs( + unique int id: @config +); + +configNames( + unique int id: @configName, + int config: @config ref, + string name: string ref +); + +configValues( + unique int id: @configValue, + int config: @config ref, + string value: string ref +); + +configLocations( + int locatable: @configLocatable ref, + int location: @location_default ref +); + +@configLocatable = @config | @configName | @configValue; + +/** + * The time taken for the extraction of a file. + * This table contains non-deterministic content. + * + * The sum of the `time` column for each (`file`, `timerKind`) pair + * is the total time taken for extraction of `file`. The `extractionPhase` + * column provides a granular view of the extraction time of the file. + */ +extraction_time( + int file : @file ref, + // see `com.semmle.js.extractor.ExtractionMetrics.ExtractionPhase`. + int extractionPhase: int ref, + // 0 for the elapsed CPU time in nanoseconds, 1 for the elapsed wallclock time in nanoseconds + int timerKind: int ref, + float time: float ref +) + +/** + * Non-timing related data for the extraction of a single file. + * This table contains non-deterministic content. + */ +extraction_data( + int file : @file ref, + // the absolute path to the cache file + varchar(900) cacheFile: string ref, + boolean fromCache: boolean ref, + int length: int ref +) diff --git a/javascript/upgrades/930898a4fe07cb48de46800904922ca118b31e50/tuple_type_rest_index.ql b/javascript/upgrades/930898a4fe07cb48de46800904922ca118b31e50/tuple_type_rest_index.ql new file mode 100644 index 00000000000..ff9dcf65489 --- /dev/null +++ b/javascript/upgrades/930898a4fe07cb48de46800904922ca118b31e50/tuple_type_rest_index.ql @@ -0,0 +1,9 @@ +class TupleType extends @tuple_type { + predicate hasChild(int i) { type_child(_, this, i) } + + string toString() { result = "" } +} + +from TupleType tuple, int index +where index = max(int i | tuple.hasChild(i)) +select tuple, index diff --git a/javascript/upgrades/930898a4fe07cb48de46800904922ca118b31e50/upgrade.properties b/javascript/upgrades/930898a4fe07cb48de46800904922ca118b31e50/upgrade.properties new file mode 100644 index 00000000000..de6695318a6 --- /dev/null +++ b/javascript/upgrades/930898a4fe07cb48de46800904922ca118b31e50/upgrade.properties @@ -0,0 +1,4 @@ +description: add support for TypeScript 4.2 +compatibility: full +tuple_type_rest_index.rel: run tuple_type_rest_index.qlo +tuple_type_rest.rel: delete \ No newline at end of file From 5ae3c5952c505b3a66b6489c1bec98bc284686c0 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 18 Feb 2021 11:52:11 +0100 Subject: [PATCH 033/142] support abstract signatures --- .../lib/typescript/src/type_table.ts | 5 ++++- .../semmle/ts/extractor/TypeExtractor.java | 18 ++++++++++------- .../ql/src/semmle/javascript/TypeScript.qll | 5 +++++ .../ql/src/semmlecode.javascript.dbscheme | 4 ++++ .../TypeScript/Types/tests.expected | 20 +++++++++++++++++++ .../library-tests/TypeScript/Types/tests.ql | 2 ++ .../library-tests/TypeScript/Types/tst.ts | 14 ++++++++++++- .../is_abstract_signature.ql | 3 +++ .../semmlecode.javascript.dbscheme | 4 ++++ .../upgrade.properties | 5 +++-- 10 files changed, 69 insertions(+), 11 deletions(-) create mode 100644 javascript/upgrades/930898a4fe07cb48de46800904922ca118b31e50/is_abstract_signature.ql diff --git a/javascript/extractor/lib/typescript/src/type_table.ts b/javascript/extractor/lib/typescript/src/type_table.ts index 5f2a8d7fce8..7b64cad09c4 100644 --- a/javascript/extractor/lib/typescript/src/type_table.ts +++ b/javascript/extractor/lib/typescript/src/type_table.ts @@ -947,6 +947,9 @@ export class TypeTable { * Returns a unique string for the given call/constructor signature. */ private getSignatureString(kind: ts.SignatureKind, signature: AugmentedSignature): string { + let modifiers : ts.ModifiersArray = signature.getDeclaration()?.modifiers; + let isAbstract = modifiers && modifiers.filter(modifier => modifier.kind == ts.SyntaxKind.AbstractKeyword).length > 0 + let parameters = signature.getParameters(); let numberOfTypeParameters = signature.typeParameters == null ? 0 @@ -978,7 +981,7 @@ export class TypeTable { if (returnTypeId == null) { return null; } - let tag = `${kind};${numberOfTypeParameters};${requiredParameters};${restParameterTag};${returnTypeId}`; + let tag = `${kind};${isAbstract ? "t" : "f"};${numberOfTypeParameters};${requiredParameters};${restParameterTag};${returnTypeId}`; for (let typeParameter of signature.typeParameters || []) { tag += ";" + typeParameter.symbol.name; let constraint = typeParameter.getConstraint(); diff --git a/javascript/extractor/src/com/semmle/ts/extractor/TypeExtractor.java b/javascript/extractor/src/com/semmle/ts/extractor/TypeExtractor.java index 3333bd97254..de0b2558c4d 100644 --- a/javascript/extractor/src/com/semmle/ts/extractor/TypeExtractor.java +++ b/javascript/extractor/src/com/semmle/ts/extractor/TypeExtractor.java @@ -202,18 +202,22 @@ public class TypeExtractor { private void extractSignature(int index) { // Format is: - // kind;numTypeParams;requiredParams;restParamType;returnType(;paramName;paramType)* + // kind;isAbstract;numTypeParams;requiredParams;restParamType;returnType(;paramName;paramType)* String[] parts = split(table.getSignatureString(index)); Label label = trapWriter.globalID("signature;" + index); int kind = Integer.parseInt(parts[0]); - int numberOfTypeParameters = Integer.parseInt(parts[1]); - int requiredParameters = Integer.parseInt(parts[2]); - String restParamTypeTag = parts[3]; + boolean isAbstract = parts[1].equals("t"); + if (isAbstract) { + trapWriter.addTuple("is_abstract_signature", label); + } + int numberOfTypeParameters = Integer.parseInt(parts[2]); + int requiredParameters = Integer.parseInt(parts[3]); + String restParamTypeTag = parts[4]; if (!restParamTypeTag.isEmpty()) { trapWriter.addTuple( "signature_rest_parameter", label, trapWriter.globalID("type;" + restParamTypeTag)); } - Label returnType = trapWriter.globalID("type;" + parts[4]); + Label returnType = trapWriter.globalID("type;" + parts[5]); trapWriter.addTuple( "signature_types", label, @@ -222,9 +226,9 @@ public class TypeExtractor { numberOfTypeParameters, requiredParameters); trapWriter.addTuple("signature_contains_type", returnType, label, -1); - int numberOfParameters = (parts.length - 5) / 2; // includes type parameters + int numberOfParameters = (parts.length - 6) / 2; // includes type parameters for (int i = 0; i < numberOfParameters; ++i) { - int partIndex = 5 + (2 * i); + int partIndex = 6 + (2 * i); String paramName = parts[partIndex]; String paramTypeId = parts[partIndex + 1]; if (paramTypeId.length() > 0) { // Unconstrained type parameters have an empty type ID. diff --git a/javascript/ql/src/semmle/javascript/TypeScript.qll b/javascript/ql/src/semmle/javascript/TypeScript.qll index 6fe47221c97..6fd72d06001 100644 --- a/javascript/ql/src/semmle/javascript/TypeScript.qll +++ b/javascript/ql/src/semmle/javascript/TypeScript.qll @@ -2794,6 +2794,11 @@ class CallSignatureType extends @signature_type { * For example, for the signature `(...y: string[])`, this gets the type `string[]`. */ PlainArrayType getRestParameterArrayType() { signature_rest_parameter(this, result) } + + /** + * Holds if this signature is abstract. + */ + predicate isAbstract() { is_abstract_signature(this) } } /** diff --git a/javascript/ql/src/semmlecode.javascript.dbscheme b/javascript/ql/src/semmlecode.javascript.dbscheme index 72028aa6f0b..fbd45f6b3c6 100644 --- a/javascript/ql/src/semmlecode.javascript.dbscheme +++ b/javascript/ql/src/semmlecode.javascript.dbscheme @@ -742,6 +742,10 @@ signature_types ( int required_params: int ref ); +is_abstract_signature( + unique int sig: @signature_type ref +); + signature_rest_parameter( unique int sig: @signature_type ref, int rest_param_arra_type: @type ref diff --git a/javascript/ql/test/library-tests/TypeScript/Types/tests.expected b/javascript/ql/test/library-tests/TypeScript/Types/tests.expected index 02b78425dfd..6851a16ca08 100644 --- a/javascript/ql/test/library-tests/TypeScript/Types/tests.expected +++ b/javascript/ql/test/library-tests/TypeScript/Types/tests.expected @@ -107,6 +107,13 @@ getExprType | tst.ts:48:20:48:27 | "string" | "string" | | tst.ts:49:11:49:11 | b | string | | tst.ts:49:24:49:24 | e | string | +| tst.ts:55:3:55:9 | getArea | () => number | +| tst.ts:55:3:55:20 | getArea(): number; | () => number | +| tst.ts:59:3:59:9 | getArea | () => number | +| tst.ts:59:3:59:20 | getArea(): number; | () => number | +| tst.ts:63:5:63:8 | Ctor | abstract new () => HasArea | +| tst.ts:63:11:63:36 | abstrac ... HasArea | abstract new () => HasArea | +| tst.ts:63:40:63:44 | Shape | any | | type_alias.ts:3:5:3:5 | b | boolean | | type_alias.ts:7:5:7:5 | c | ValueOrArray | | type_alias.ts:14:9:14:32 | [proper ... ]: Json | any | @@ -156,6 +163,8 @@ getExprType | type_definitions.ts:19:5:19:5 | e | EnumWithOneMember | | type_definitions.ts:22:5:22:23 | aliasForNumberArray | Alias | getTypeDefinitionType +| tst.ts:54:1:56:1 | interfa ... mber;\\n} | NonAbstractDummy | +| tst.ts:58:1:60:1 | interfa ... mber;\\n} | HasArea | | type_alias.ts:1:1:1:17 | type B = boolean; | boolean | | type_alias.ts:5:1:5:50 | type Va ... ay>; | ValueOrArray | | type_alias.ts:9:1:15:13 | type Js ... Json[]; | Json | @@ -245,6 +254,12 @@ getTypeExprType | tst.ts:39:60:39:67 | number[] | number[] | | tst.ts:40:18:40:24 | unknown | unknown | | tst.ts:49:15:49:20 | string | string | +| tst.ts:54:11:54:26 | NonAbstractDummy | NonAbstractDummy | +| tst.ts:55:14:55:19 | number | number | +| tst.ts:58:11:58:17 | HasArea | HasArea | +| tst.ts:59:14:59:19 | number | number | +| tst.ts:63:11:63:36 | abstrac ... HasArea | abstract new () => HasArea | +| tst.ts:63:30:63:36 | HasArea | HasArea | | type_alias.ts:1:6:1:6 | B | boolean | | type_alias.ts:1:10:1:16 | boolean | boolean | | type_alias.ts:3:8:3:8 | B | boolean | @@ -317,9 +332,11 @@ referenceDefinition | Color.red | type_definitions.ts:14:3:14:5 | red | | E | type_definition_objects.ts:6:8:6:16 | enum E {} | | EnumWithOneMember | type_definitions.ts:18:26:18:31 | member | +| HasArea | tst.ts:58:1:60:1 | interfa ... mber;\\n} | | I | type_definitions.ts:3:1:5:1 | interfa ... x: S;\\n} | | I | type_definitions.ts:3:1:5:1 | interfa ... x: S;\\n} | | Json | type_alias.ts:9:1:15:13 | type Js ... Json[]; | +| NonAbstractDummy | tst.ts:54:1:56:1 | interfa ... mber;\\n} | | ValueOrArray | type_alias.ts:5:1:5:50 | type Va ... ay>; | | ValueOrArray | type_alias.ts:5:1:5:50 | type Va ... ay>; | | VirtualNode | type_alias.ts:19:1:21:57 | type Vi ... ode[]]; | @@ -356,3 +373,6 @@ unknownType | tst.ts:40:5:40:15 | unknownType | unknown | | tst.ts:47:8:47:8 | e | unknown | | tst.ts:48:14:48:14 | e | unknown | +abstractSignature +| (): HasArea | +| new (): HasArea | diff --git a/javascript/ql/test/library-tests/TypeScript/Types/tests.ql b/javascript/ql/test/library-tests/TypeScript/Types/tests.ql index e5f86c059e5..25f3a9aec7a 100644 --- a/javascript/ql/test/library-tests/TypeScript/Types/tests.ql +++ b/javascript/ql/test/library-tests/TypeScript/Types/tests.ql @@ -35,3 +35,5 @@ query predicate unknownType(Expr e, Type type) { type = e.getType() and e.getType() instanceof UnknownType } + +query CallSignatureType abstractSignature() { result.isAbstract() } diff --git a/javascript/ql/test/library-tests/TypeScript/Types/tst.ts b/javascript/ql/test/library-tests/TypeScript/Types/tst.ts index 04968386c99..ac1b1b81263 100644 --- a/javascript/ql/test/library-tests/TypeScript/Types/tst.ts +++ b/javascript/ql/test/library-tests/TypeScript/Types/tst.ts @@ -48,4 +48,16 @@ catch (e: unknown) { if (typeof e === "string") { let b : string = e; } -} \ No newline at end of file +} + + +interface NonAbstractDummy { + getArea(): number; +} + +interface HasArea { + getArea(): number; +} + +// abstract construct signature! +let Ctor: abstract new () => HasArea = Shape; diff --git a/javascript/upgrades/930898a4fe07cb48de46800904922ca118b31e50/is_abstract_signature.ql b/javascript/upgrades/930898a4fe07cb48de46800904922ca118b31e50/is_abstract_signature.ql new file mode 100644 index 00000000000..a5e5c7c8f11 --- /dev/null +++ b/javascript/upgrades/930898a4fe07cb48de46800904922ca118b31e50/is_abstract_signature.ql @@ -0,0 +1,3 @@ +from int a, int b +where none() +select a, b diff --git a/javascript/upgrades/930898a4fe07cb48de46800904922ca118b31e50/semmlecode.javascript.dbscheme b/javascript/upgrades/930898a4fe07cb48de46800904922ca118b31e50/semmlecode.javascript.dbscheme index 72028aa6f0b..fbd45f6b3c6 100644 --- a/javascript/upgrades/930898a4fe07cb48de46800904922ca118b31e50/semmlecode.javascript.dbscheme +++ b/javascript/upgrades/930898a4fe07cb48de46800904922ca118b31e50/semmlecode.javascript.dbscheme @@ -742,6 +742,10 @@ signature_types ( int required_params: int ref ); +is_abstract_signature( + unique int sig: @signature_type ref +); + signature_rest_parameter( unique int sig: @signature_type ref, int rest_param_arra_type: @type ref diff --git a/javascript/upgrades/930898a4fe07cb48de46800904922ca118b31e50/upgrade.properties b/javascript/upgrades/930898a4fe07cb48de46800904922ca118b31e50/upgrade.properties index de6695318a6..82e10769eb9 100644 --- a/javascript/upgrades/930898a4fe07cb48de46800904922ca118b31e50/upgrade.properties +++ b/javascript/upgrades/930898a4fe07cb48de46800904922ca118b31e50/upgrade.properties @@ -1,4 +1,5 @@ description: add support for TypeScript 4.2 -compatibility: full +compatibility: backwards tuple_type_rest_index.rel: run tuple_type_rest_index.qlo -tuple_type_rest.rel: delete \ No newline at end of file +tuple_type_rest.rel: delete +is_abstract_signature: run is_abstract_signature.qlo \ No newline at end of file From 85ed402b1abe6fff0e48c3a20857d9632bfc8ac1 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 18 Feb 2021 11:59:48 +0100 Subject: [PATCH 034/142] add test for union types --- .../TypeScript/Types/tests.expected | 39 +++++++++++++++++++ .../library-tests/TypeScript/Types/tests.ql | 2 + 2 files changed, 41 insertions(+) diff --git a/javascript/ql/test/library-tests/TypeScript/Types/tests.expected b/javascript/ql/test/library-tests/TypeScript/Types/tests.expected index 6851a16ca08..31b7fb83ff2 100644 --- a/javascript/ql/test/library-tests/TypeScript/Types/tests.expected +++ b/javascript/ql/test/library-tests/TypeScript/Types/tests.expected @@ -376,3 +376,42 @@ unknownType abstractSignature | (): HasArea | | new (): HasArea | +unionIndex +| 1 | 0 | 1 \| 2 | +| 2 | 1 | 1 \| 2 | +| "bigint" | 2 | "string" \| "number" \| "bigint" \| "boolean" \| "s... | +| "boolean" | 3 | "string" \| "number" \| "bigint" \| "boolean" \| "s... | +| "function" | 7 | "string" \| "number" \| "bigint" \| "boolean" \| "s... | +| "number" | 1 | "string" \| "number" \| "bigint" \| "boolean" \| "s... | +| "object" | 6 | "string" \| "number" \| "bigint" \| "boolean" \| "s... | +| "string" | 0 | "string" \| "number" \| "bigint" \| "boolean" \| "s... | +| "symbol" | 4 | "string" \| "number" \| "bigint" \| "boolean" \| "s... | +| "undefined" | 5 | "string" \| "number" \| "bigint" \| "boolean" \| "s... | +| Json[] | 5 | string \| number \| boolean \| { [property: string... | +| T | 0 | T \| ValueOrArray[] | +| ValueOrArray[] | 1 | T \| ValueOrArray[] | +| ValueOrArray[] | 1 | number \| ValueOrArray[] | +| [string, { [key: string]: any; }, ...VirtualNod... | 1 | VirtualNode \| { [key: string]: any; } | +| [string, { [key: string]: any; }, ...VirtualNod... | 1 | string \| [string, { [key: string]: any; }, ...V... | +| false | 0 | boolean | +| false | 2 | string \| number \| boolean | +| false | 2 | string \| number \| boolean \| { [property: string... | +| number | 0 | number \| ValueOrArray[] | +| number | 1 | string \| number | +| number | 1 | string \| number \| boolean | +| number | 1 | string \| number \| boolean \| { [property: string... | +| number | 1 | string \| number \| true | +| string | 0 | VirtualNode \| { [key: string]: any; } | +| string | 0 | string \| [string, { [key: string]: any; }, ...V... | +| string | 0 | string \| number | +| string | 0 | string \| number \| boolean | +| string | 0 | string \| number \| boolean \| { [property: string... | +| string | 0 | string \| number \| true | +| string | 0 | string \| { [key: string]: any; } | +| true | 1 | boolean | +| true | 2 | string \| number \| true | +| true | 3 | string \| number \| boolean | +| true | 3 | string \| number \| boolean \| { [property: string... | +| { [key: string]: any; } | 1 | string \| { [key: string]: any; } | +| { [key: string]: any; } | 2 | VirtualNode \| { [key: string]: any; } | +| { [property: string]: Json; } | 4 | string \| number \| boolean \| { [property: string... | diff --git a/javascript/ql/test/library-tests/TypeScript/Types/tests.ql b/javascript/ql/test/library-tests/TypeScript/Types/tests.ql index 25f3a9aec7a..0f31295ce50 100644 --- a/javascript/ql/test/library-tests/TypeScript/Types/tests.ql +++ b/javascript/ql/test/library-tests/TypeScript/Types/tests.ql @@ -37,3 +37,5 @@ query predicate unknownType(Expr e, Type type) { } query CallSignatureType abstractSignature() { result.isAbstract() } + +query UnionType unionIndex(Type element, int i) { result.getElementType(i) = element } From bcb3d5aec27ecba0981ccaa962605d048e5b1e9e Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 18 Feb 2021 12:05:53 +0100 Subject: [PATCH 035/142] add tests for nested type unions through aliases --- .../TypeScript/Types/tests.expected | 33 +++++++++++++++++++ .../library-tests/TypeScript/Types/tst.ts | 6 ++++ 2 files changed, 39 insertions(+) diff --git a/javascript/ql/test/library-tests/TypeScript/Types/tests.expected b/javascript/ql/test/library-tests/TypeScript/Types/tests.expected index 31b7fb83ff2..c9cad8a1443 100644 --- a/javascript/ql/test/library-tests/TypeScript/Types/tests.expected +++ b/javascript/ql/test/library-tests/TypeScript/Types/tests.expected @@ -114,6 +114,17 @@ getExprType | tst.ts:63:5:63:8 | Ctor | abstract new () => HasArea | | tst.ts:63:11:63:36 | abstrac ... HasArea | abstract new () => HasArea | | tst.ts:63:40:63:44 | Shape | any | +| tst.ts:65:17:65:23 | myUnion | true | +| tst.ts:65:35:65:46 | stillMyUnion | true | +| tst.ts:66:5:66:10 | union1 | MyUnion | +| tst.ts:66:23:66:37 | {myUnion: true} | MyUnion | +| tst.ts:66:24:66:30 | myUnion | true | +| tst.ts:66:33:66:36 | true | true | +| tst.ts:68:28:68:41 | yetAnotherType | true | +| tst.ts:69:5:69:10 | union2 | MyUnion2 | +| tst.ts:69:24:69:45 | {yetAno ... : true} | MyUnion2 | +| tst.ts:69:25:69:38 | yetAnotherType | true | +| tst.ts:69:41:69:44 | true | true | | type_alias.ts:3:5:3:5 | b | boolean | | type_alias.ts:7:5:7:5 | c | ValueOrArray | | type_alias.ts:14:9:14:32 | [proper ... ]: Json | any | @@ -165,6 +176,8 @@ getExprType getTypeDefinitionType | tst.ts:54:1:56:1 | interfa ... mber;\\n} | NonAbstractDummy | | tst.ts:58:1:60:1 | interfa ... mber;\\n} | HasArea | +| tst.ts:65:1:65:54 | type My ... true}; | MyUnion | +| tst.ts:68:1:68:49 | type My ... true}; | MyUnion2 | | type_alias.ts:1:1:1:17 | type B = boolean; | boolean | | type_alias.ts:5:1:5:50 | type Va ... ay>; | ValueOrArray | | type_alias.ts:9:1:15:13 | type Js ... Json[]; | Json | @@ -260,6 +273,19 @@ getTypeExprType | tst.ts:59:14:59:19 | number | number | | tst.ts:63:11:63:36 | abstrac ... HasArea | abstract new () => HasArea | | tst.ts:63:30:63:36 | HasArea | HasArea | +| tst.ts:65:6:65:12 | MyUnion | MyUnion | +| tst.ts:65:16:65:30 | {myUnion: true} | { myUnion: true; } | +| tst.ts:65:16:65:53 | {myUnio ... : true} | { myUnion: true; } \| { stillMyUnion: true; } | +| tst.ts:65:26:65:29 | true | true | +| tst.ts:65:34:65:53 | {stillMyUnion: true} | { stillMyUnion: true; } | +| tst.ts:65:49:65:52 | true | true | +| tst.ts:66:13:66:19 | MyUnion | MyUnion | +| tst.ts:68:6:68:13 | MyUnion2 | MyUnion2 | +| tst.ts:68:17:68:23 | MyUnion | MyUnion | +| tst.ts:68:17:68:48 | MyUnion ... : true} | MyUnion \| { yetAnotherType: true; } | +| tst.ts:68:27:68:48 | {yetAno ... : true} | { yetAnotherType: true; } | +| tst.ts:68:44:68:47 | true | true | +| tst.ts:69:13:69:20 | MyUnion2 | MyUnion2 | | type_alias.ts:1:6:1:6 | B | boolean | | type_alias.ts:1:10:1:16 | boolean | boolean | | type_alias.ts:3:8:3:8 | B | boolean | @@ -336,6 +362,8 @@ referenceDefinition | I | type_definitions.ts:3:1:5:1 | interfa ... x: S;\\n} | | I | type_definitions.ts:3:1:5:1 | interfa ... x: S;\\n} | | Json | type_alias.ts:9:1:15:13 | type Js ... Json[]; | +| MyUnion | tst.ts:65:1:65:54 | type My ... true}; | +| MyUnion2 | tst.ts:68:1:68:49 | type My ... true}; | | NonAbstractDummy | tst.ts:54:1:56:1 | interfa ... mber;\\n} | | ValueOrArray | type_alias.ts:5:1:5:50 | type Va ... ay>; | | ValueOrArray | type_alias.ts:5:1:5:50 | type Va ... ay>; | @@ -415,3 +443,8 @@ unionIndex | { [key: string]: any; } | 1 | string \| { [key: string]: any; } | | { [key: string]: any; } | 2 | VirtualNode \| { [key: string]: any; } | | { [property: string]: Json; } | 4 | string \| number \| boolean \| { [property: string... | +| { myUnion: true; } | 0 | MyUnion \| { yetAnotherType: true; } | +| { myUnion: true; } | 0 | { myUnion: true; } \| { stillMyUnion: true; } | +| { stillMyUnion: true; } | 1 | MyUnion \| { yetAnotherType: true; } | +| { stillMyUnion: true; } | 1 | { myUnion: true; } \| { stillMyUnion: true; } | +| { yetAnotherType: true; } | 2 | MyUnion \| { yetAnotherType: true; } | diff --git a/javascript/ql/test/library-tests/TypeScript/Types/tst.ts b/javascript/ql/test/library-tests/TypeScript/Types/tst.ts index ac1b1b81263..68c4ca6ebdd 100644 --- a/javascript/ql/test/library-tests/TypeScript/Types/tst.ts +++ b/javascript/ql/test/library-tests/TypeScript/Types/tst.ts @@ -61,3 +61,9 @@ interface HasArea { // abstract construct signature! let Ctor: abstract new () => HasArea = Shape; + +type MyUnion = {myUnion: true} | {stillMyUnion: true}; +let union1: MyUnion = {myUnion: true}; + +type MyUnion2 = MyUnion | {yetAnotherType: true}; +let union2: MyUnion2 = {yetAnotherType: true}; \ No newline at end of file From 971ce83f8e2dbf53906da23a9266213aedf0edcc Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 18 Feb 2021 12:07:30 +0100 Subject: [PATCH 036/142] add change note --- javascript/change-notes/2021-02-18-typescript-4.2.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 javascript/change-notes/2021-02-18-typescript-4.2.md diff --git a/javascript/change-notes/2021-02-18-typescript-4.2.md b/javascript/change-notes/2021-02-18-typescript-4.2.md new file mode 100644 index 00000000000..6641d259f23 --- /dev/null +++ b/javascript/change-notes/2021-02-18-typescript-4.2.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* TypeScript 4.2 is now supported. From 5091bb652ff17814e957087bf0935f26953cd8d4 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 24 Feb 2021 09:39:09 +0100 Subject: [PATCH 037/142] bump extractor version --- javascript/extractor/src/com/semmle/js/extractor/Main.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/extractor/src/com/semmle/js/extractor/Main.java b/javascript/extractor/src/com/semmle/js/extractor/Main.java index 1590fca821b..0450366043e 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/Main.java +++ b/javascript/extractor/src/com/semmle/js/extractor/Main.java @@ -43,7 +43,7 @@ public class Main { * A version identifier that should be updated every time the extractor changes in such a way that * it may produce different tuples for the same file under the same {@link ExtractorConfig}. */ - public static final String EXTRACTOR_VERSION = "2021-02-05"; + public static final String EXTRACTOR_VERSION = "2021-02-24"; public static final Pattern NEWLINE = Pattern.compile("\n"); From ed47697c09cfe99ef089c5a86e3bcb978bc84077 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 24 Feb 2021 10:29:12 +0100 Subject: [PATCH 038/142] update expected output --- .../TypeScript/Nullability/Types.expected | 3 ++- .../TypeScript/TypeAliases/TypeAliases.expected | 12 ++++++------ 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/javascript/ql/test/library-tests/TypeScript/Nullability/Types.expected b/javascript/ql/test/library-tests/TypeScript/Nullability/Types.expected index f887b4a24c6..6db617b3e77 100644 --- a/javascript/ql/test/library-tests/TypeScript/Nullability/Types.expected +++ b/javascript/ql/test/library-tests/TypeScript/Nullability/Types.expected @@ -3,7 +3,8 @@ exprType | tst.ts:2:5:2:21 | stringOrUndefined | string \| undefined | | tst.ts:3:5:3:27 | stringO ... defined | string \| null \| undefined | | tst.ts:4:5:4:16 | stringOrVoid | string \| void | -| tst.ts:7:5:7:21 | stringOrNullAlias | string \| null | +| tst.ts:7:5:7:21 | stringOrNullAlias | StringOrNullAlias | | tst.ts:8:5:8:32 | stringO ... defined | string \| null \| undefined | | tst.ts:10:5:10:23 | arrayOfStringOrNull | (string \| null)[] | unaliasedType +| StringOrNullAlias | string \| null | diff --git a/javascript/ql/test/library-tests/TypeScript/TypeAliases/TypeAliases.expected b/javascript/ql/test/library-tests/TypeScript/TypeAliases/TypeAliases.expected index 009f58a5bdc..e856d0a1ffa 100644 --- a/javascript/ql/test/library-tests/TypeScript/TypeAliases/TypeAliases.expected +++ b/javascript/ql/test/library-tests/TypeScript/TypeAliases/TypeAliases.expected @@ -3,16 +3,16 @@ rightHandSide | tst.ts:2:1:2:16 | type B = T[]; | T[] | | tst.ts:8:10:8:20 | type C = A; | number | | tst.ts:15:1:15:23 | type Un ... \| Two; | One \| Two | -| tst.ts:17:1:17:36 | type Un ... mber }; | (One & { x: number; }) \| (Two & { x: number; }) | -| tst.ts:18:1:18:21 | type Un ... Union2; | (One & { x: number; }) \| (Two & { x: number; }) | -| tst.ts:19:1:19:21 | type Un ... Union3; | (One & { x: number; }) \| (Two & { x: number; }) | -| tst.ts:20:1:20:30 | type Un ... number; | number \| (One & { x: number; }) \| (Two & { x: n... | +| tst.ts:17:1:17:36 | type Un ... mber }; | Union & { x: number; } | +| tst.ts:18:1:18:21 | type Un ... Union2; | Union & { x: number; } | +| tst.ts:19:1:19:21 | type Un ... Union3; | Union & { x: number; } | +| tst.ts:20:1:20:30 | type Un ... number; | number \| Union2 | getAliasedType | B | T[] | | B | number[] | | Union | One \| Two | -| Union2 | (One & { x: number; }) \| (Two & { x: number; }) | -| Union5 | number \| (One & { x: number; }) \| (Two & { x: n... | +| Union2 | Union & { x: number; } | +| Union5 | number \| Union2 | getTypeArgument | B | 0 | T | | B | 0 | number | From 16150a6419ce66c0911c753150d65e796d24114d Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 24 Feb 2021 10:29:29 +0100 Subject: [PATCH 039/142] update printAst expected output --- .../TypeScript/Types/printAst.expected | 317 ++++++++++++++---- 1 file changed, 259 insertions(+), 58 deletions(-) diff --git a/javascript/ql/test/library-tests/TypeScript/Types/printAst.expected b/javascript/ql/test/library-tests/TypeScript/Types/printAst.expected index 357da6a0263..bd50eaa28ec 100644 --- a/javascript/ql/test/library-tests/TypeScript/Types/printAst.expected +++ b/javascript/ql/test/library-tests/TypeScript/Types/printAst.expected @@ -84,50 +84,68 @@ nodes | file://:0:0:0:0 | (TypeParameters) | semmle.label | (TypeParameters) | | file://:0:0:0:0 | (TypeParameters) | semmle.label | (TypeParameters) | | file://:0:0:0:0 | (TypeParameters) | semmle.label | (TypeParameters) | +| middle-rest.ts:1:1:1:40 | [DeclStmt] let foo = ... | semmle.label | [DeclStmt] let foo = ... | +| middle-rest.ts:1:1:1:40 | [DeclStmt] let foo = ... | semmle.order | 13 | +| middle-rest.ts:1:5:1:7 | [VarDecl] foo | semmle.label | [VarDecl] foo | +| middle-rest.ts:1:5:1:39 | [VariableDeclarator] foo: [b ... number] | semmle.label | [VariableDeclarator] foo: [b ... number] | +| middle-rest.ts:1:10:1:39 | [TupleTypeExpr] [boolea ... number] | semmle.label | [TupleTypeExpr] [boolea ... number] | +| middle-rest.ts:1:11:1:17 | [KeywordTypeExpr] boolean | semmle.label | [KeywordTypeExpr] boolean | +| middle-rest.ts:1:20:1:30 | [RestTypeExpr] ...string[] | semmle.label | [RestTypeExpr] ...string[] | +| middle-rest.ts:1:23:1:28 | [KeywordTypeExpr] string | semmle.label | [KeywordTypeExpr] string | +| middle-rest.ts:1:23:1:30 | [ArrayTypeExpr] string[] | semmle.label | [ArrayTypeExpr] string[] | +| middle-rest.ts:1:33:1:38 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number | +| middle-rest.ts:3:1:3:3 | [VarRef] foo | semmle.label | [VarRef] foo | +| middle-rest.ts:3:1:3:26 | [AssignExpr] foo = [ ... ", 123] | semmle.label | [AssignExpr] foo = [ ... ", 123] | +| middle-rest.ts:3:1:3:27 | [ExprStmt] foo = [ ... , 123]; | semmle.label | [ExprStmt] foo = [ ... , 123]; | +| middle-rest.ts:3:1:3:27 | [ExprStmt] foo = [ ... , 123]; | semmle.order | 14 | +| middle-rest.ts:3:7:3:26 | [ArrayExpr] [true, "hello", 123] | semmle.label | [ArrayExpr] [true, "hello", 123] | +| middle-rest.ts:3:8:3:11 | [Literal] true | semmle.label | [Literal] true | +| middle-rest.ts:3:14:3:20 | [Literal] "hello" | semmle.label | [Literal] "hello" | +| middle-rest.ts:3:23:3:25 | [Literal] 123 | semmle.label | [Literal] 123 | | tst.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.label | [ImportDeclaration] import ... dummy"; | -| tst.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.order | 13 | +| tst.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.order | 15 | | tst.ts:1:8:1:17 | [ImportSpecifier] * as dummy | semmle.label | [ImportSpecifier] * as dummy | | tst.ts:1:13:1:17 | [VarDecl] dummy | semmle.label | [VarDecl] dummy | | tst.ts:1:24:1:32 | [Literal] "./dummy" | semmle.label | [Literal] "./dummy" | | tst.ts:3:1:3:19 | [DeclStmt] var numVar = ... | semmle.label | [DeclStmt] var numVar = ... | -| tst.ts:3:1:3:19 | [DeclStmt] var numVar = ... | semmle.order | 14 | +| tst.ts:3:1:3:19 | [DeclStmt] var numVar = ... | semmle.order | 16 | | tst.ts:3:5:3:10 | [VarDecl] numVar | semmle.label | [VarDecl] numVar | | tst.ts:3:5:3:18 | [VariableDeclarator] numVar: number | semmle.label | [VariableDeclarator] numVar: number | | tst.ts:3:13:3:18 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number | | tst.ts:5:1:5:18 | [DeclStmt] var num1 = ... | semmle.label | [DeclStmt] var num1 = ... | -| tst.ts:5:1:5:18 | [DeclStmt] var num1 = ... | semmle.order | 15 | +| tst.ts:5:1:5:18 | [DeclStmt] var num1 = ... | semmle.order | 17 | | tst.ts:5:5:5:8 | [VarDecl] num1 | semmle.label | [VarDecl] num1 | | tst.ts:5:5:5:17 | [VariableDeclarator] num1 = numVar | semmle.label | [VariableDeclarator] num1 = numVar | | tst.ts:5:12:5:17 | [VarRef] numVar | semmle.label | [VarRef] numVar | | tst.ts:6:1:6:13 | [DeclStmt] var num2 = ... | semmle.label | [DeclStmt] var num2 = ... | -| tst.ts:6:1:6:13 | [DeclStmt] var num2 = ... | semmle.order | 16 | +| tst.ts:6:1:6:13 | [DeclStmt] var num2 = ... | semmle.order | 18 | | tst.ts:6:5:6:8 | [VarDecl] num2 | semmle.label | [VarDecl] num2 | | tst.ts:6:5:6:12 | [VariableDeclarator] num2 = 5 | semmle.label | [VariableDeclarator] num2 = 5 | | tst.ts:6:12:6:12 | [Literal] 5 | semmle.label | [Literal] 5 | | tst.ts:7:1:7:23 | [DeclStmt] var num3 = ... | semmle.label | [DeclStmt] var num3 = ... | -| tst.ts:7:1:7:23 | [DeclStmt] var num3 = ... | semmle.order | 17 | +| tst.ts:7:1:7:23 | [DeclStmt] var num3 = ... | semmle.order | 19 | | tst.ts:7:5:7:8 | [VarDecl] num3 | semmle.label | [VarDecl] num3 | | tst.ts:7:5:7:22 | [VariableDeclarator] num3 = num1 + num2 | semmle.label | [VariableDeclarator] num3 = num1 + num2 | | tst.ts:7:12:7:15 | [VarRef] num1 | semmle.label | [VarRef] num1 | | tst.ts:7:12:7:22 | [BinaryExpr] num1 + num2 | semmle.label | [BinaryExpr] num1 + num2 | | tst.ts:7:19:7:22 | [VarRef] num2 | semmle.label | [VarRef] num2 | | tst.ts:9:1:9:19 | [DeclStmt] var strVar = ... | semmle.label | [DeclStmt] var strVar = ... | -| tst.ts:9:1:9:19 | [DeclStmt] var strVar = ... | semmle.order | 18 | +| tst.ts:9:1:9:19 | [DeclStmt] var strVar = ... | semmle.order | 20 | | tst.ts:9:5:9:10 | [VarDecl] strVar | semmle.label | [VarDecl] strVar | | tst.ts:9:5:9:18 | [VariableDeclarator] strVar: string | semmle.label | [VariableDeclarator] strVar: string | | tst.ts:9:13:9:18 | [KeywordTypeExpr] string | semmle.label | [KeywordTypeExpr] string | | tst.ts:10:1:10:20 | [DeclStmt] var hello = ... | semmle.label | [DeclStmt] var hello = ... | -| tst.ts:10:1:10:20 | [DeclStmt] var hello = ... | semmle.order | 19 | +| tst.ts:10:1:10:20 | [DeclStmt] var hello = ... | semmle.order | 21 | | tst.ts:10:5:10:9 | [VarDecl] hello | semmle.label | [VarDecl] hello | | tst.ts:10:5:10:19 | [VariableDeclarator] hello = "hello" | semmle.label | [VariableDeclarator] hello = "hello" | | tst.ts:10:13:10:19 | [Literal] "hello" | semmle.label | [Literal] "hello" | | tst.ts:11:1:11:20 | [DeclStmt] var world = ... | semmle.label | [DeclStmt] var world = ... | -| tst.ts:11:1:11:20 | [DeclStmt] var world = ... | semmle.order | 20 | +| tst.ts:11:1:11:20 | [DeclStmt] var world = ... | semmle.order | 22 | | tst.ts:11:5:11:9 | [VarDecl] world | semmle.label | [VarDecl] world | | tst.ts:11:5:11:19 | [VariableDeclarator] world = "world" | semmle.label | [VariableDeclarator] world = "world" | | tst.ts:11:13:11:19 | [Literal] "world" | semmle.label | [Literal] "world" | | tst.ts:12:1:12:30 | [DeclStmt] var msg = ... | semmle.label | [DeclStmt] var msg = ... | -| tst.ts:12:1:12:30 | [DeclStmt] var msg = ... | semmle.order | 21 | +| tst.ts:12:1:12:30 | [DeclStmt] var msg = ... | semmle.order | 23 | | tst.ts:12:5:12:7 | [VarDecl] msg | semmle.label | [VarDecl] msg | | tst.ts:12:5:12:29 | [VariableDeclarator] msg = h ... + world | semmle.label | [VariableDeclarator] msg = h ... + world | | tst.ts:12:11:12:15 | [VarRef] hello | semmle.label | [VarRef] hello | @@ -136,7 +154,7 @@ nodes | tst.ts:12:19:12:21 | [Literal] " " | semmle.label | [Literal] " " | | tst.ts:12:25:12:29 | [VarRef] world | semmle.label | [VarRef] world | | tst.ts:14:1:14:63 | [FunctionDeclStmt] functio ... + y; } | semmle.label | [FunctionDeclStmt] functio ... + y; } | -| tst.ts:14:1:14:63 | [FunctionDeclStmt] functio ... + y; } | semmle.order | 22 | +| tst.ts:14:1:14:63 | [FunctionDeclStmt] functio ... + y; } | semmle.order | 24 | | tst.ts:14:10:14:15 | [VarDecl] concat | semmle.label | [VarDecl] concat | | tst.ts:14:17:14:17 | [SimpleParameter] x | semmle.label | [SimpleParameter] x | | tst.ts:14:20:14:25 | [KeywordTypeExpr] string | semmle.label | [KeywordTypeExpr] string | @@ -149,7 +167,7 @@ nodes | tst.ts:14:56:14:60 | [BinaryExpr] x + y | semmle.label | [BinaryExpr] x + y | | tst.ts:14:60:14:60 | [VarRef] y | semmle.label | [VarRef] y | | tst.ts:16:1:16:60 | [FunctionDeclStmt] functio ... + y; } | semmle.label | [FunctionDeclStmt] functio ... + y; } | -| tst.ts:16:1:16:60 | [FunctionDeclStmt] functio ... + y; } | semmle.order | 23 | +| tst.ts:16:1:16:60 | [FunctionDeclStmt] functio ... + y; } | semmle.order | 25 | | tst.ts:16:10:16:12 | [VarDecl] add | semmle.label | [VarDecl] add | | tst.ts:16:14:16:14 | [SimpleParameter] x | semmle.label | [SimpleParameter] x | | tst.ts:16:17:16:22 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number | @@ -162,7 +180,7 @@ nodes | tst.ts:16:53:16:57 | [BinaryExpr] x + y | semmle.label | [BinaryExpr] x + y | | tst.ts:16:57:16:57 | [VarRef] y | semmle.label | [VarRef] y | | tst.ts:18:1:18:40 | [FunctionDeclStmt] functio ... + y; } | semmle.label | [FunctionDeclStmt] functio ... + y; } | -| tst.ts:18:1:18:40 | [FunctionDeclStmt] functio ... + y; } | semmle.order | 24 | +| tst.ts:18:1:18:40 | [FunctionDeclStmt] functio ... + y; } | semmle.order | 26 | | tst.ts:18:10:18:16 | [VarDecl] untyped | semmle.label | [VarDecl] untyped | | tst.ts:18:18:18:18 | [SimpleParameter] x | semmle.label | [SimpleParameter] x | | tst.ts:18:21:18:21 | [SimpleParameter] y | semmle.label | [SimpleParameter] y | @@ -172,7 +190,7 @@ nodes | tst.ts:18:33:18:37 | [BinaryExpr] x + y | semmle.label | [BinaryExpr] x + y | | tst.ts:18:37:18:37 | [VarRef] y | semmle.label | [VarRef] y | | tst.ts:20:1:20:53 | [FunctionDeclStmt] functio ... + y; } | semmle.label | [FunctionDeclStmt] functio ... + y; } | -| tst.ts:20:1:20:53 | [FunctionDeclStmt] functio ... + y; } | semmle.order | 25 | +| tst.ts:20:1:20:53 | [FunctionDeclStmt] functio ... + y; } | semmle.order | 27 | | tst.ts:20:10:20:21 | [VarDecl] partialTyped | semmle.label | [VarDecl] partialTyped | | tst.ts:20:23:20:23 | [SimpleParameter] x | semmle.label | [SimpleParameter] x | | tst.ts:20:26:20:26 | [SimpleParameter] y | semmle.label | [SimpleParameter] y | @@ -183,7 +201,7 @@ nodes | tst.ts:20:46:20:50 | [BinaryExpr] x + y | semmle.label | [BinaryExpr] x + y | | tst.ts:20:50:20:50 | [VarRef] y | semmle.label | [VarRef] y | | tst.ts:22:1:22:34 | [ForOfStmt] for (le ... 2]) {} | semmle.label | [ForOfStmt] for (le ... 2]) {} | -| tst.ts:22:1:22:34 | [ForOfStmt] for (le ... 2]) {} | semmle.order | 26 | +| tst.ts:22:1:22:34 | [ForOfStmt] for (le ... 2]) {} | semmle.order | 28 | | tst.ts:22:6:22:20 | [DeclStmt] let numFromLoop = ... | semmle.label | [DeclStmt] let numFromLoop = ... | | tst.ts:22:10:22:20 | [VarDecl] numFromLoop | semmle.label | [VarDecl] numFromLoop | | tst.ts:22:10:22:20 | [VariableDeclarator] numFromLoop | semmle.label | [VariableDeclarator] numFromLoop | @@ -192,54 +210,54 @@ nodes | tst.ts:22:29:22:29 | [Literal] 2 | semmle.label | [Literal] 2 | | tst.ts:22:33:22:34 | [BlockStmt] {} | semmle.label | [BlockStmt] {} | | tst.ts:24:1:24:20 | [DeclStmt] let array = ... | semmle.label | [DeclStmt] let array = ... | -| tst.ts:24:1:24:20 | [DeclStmt] let array = ... | semmle.order | 27 | +| tst.ts:24:1:24:20 | [DeclStmt] let array = ... | semmle.order | 29 | | tst.ts:24:5:24:9 | [VarDecl] array | semmle.label | [VarDecl] array | | tst.ts:24:5:24:19 | [VariableDeclarator] array: number[] | semmle.label | [VariableDeclarator] array: number[] | | tst.ts:24:12:24:17 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number | | tst.ts:24:12:24:19 | [ArrayTypeExpr] number[] | semmle.label | [ArrayTypeExpr] number[] | | tst.ts:26:1:26:25 | [DeclStmt] let voidType = ... | semmle.label | [DeclStmt] let voidType = ... | -| tst.ts:26:1:26:25 | [DeclStmt] let voidType = ... | semmle.order | 28 | +| tst.ts:26:1:26:25 | [DeclStmt] let voidType = ... | semmle.order | 30 | | tst.ts:26:5:26:12 | [VarDecl] voidType | semmle.label | [VarDecl] voidType | | tst.ts:26:5:26:24 | [VariableDeclarator] voidType: () => void | semmle.label | [VariableDeclarator] voidType: () => void | | tst.ts:26:15:26:24 | [FunctionExpr] () => void | semmle.label | [FunctionExpr] () => void | | tst.ts:26:15:26:24 | [FunctionTypeExpr] () => void | semmle.label | [FunctionTypeExpr] () => void | | tst.ts:26:21:26:24 | [KeywordTypeExpr] void | semmle.label | [KeywordTypeExpr] void | | tst.ts:27:1:27:29 | [DeclStmt] let undefinedType = ... | semmle.label | [DeclStmt] let undefinedType = ... | -| tst.ts:27:1:27:29 | [DeclStmt] let undefinedType = ... | semmle.order | 29 | +| tst.ts:27:1:27:29 | [DeclStmt] let undefinedType = ... | semmle.order | 31 | | tst.ts:27:5:27:17 | [VarDecl] undefinedType | semmle.label | [VarDecl] undefinedType | | tst.ts:27:5:27:28 | [VariableDeclarator] undefin ... defined | semmle.label | [VariableDeclarator] undefin ... defined | | tst.ts:27:20:27:28 | [KeywordTypeExpr] undefined | semmle.label | [KeywordTypeExpr] undefined | | tst.ts:28:1:28:26 | [DeclStmt] let nullType = ... | semmle.label | [DeclStmt] let nullType = ... | -| tst.ts:28:1:28:26 | [DeclStmt] let nullType = ... | semmle.order | 30 | +| tst.ts:28:1:28:26 | [DeclStmt] let nullType = ... | semmle.order | 32 | | tst.ts:28:5:28:12 | [VarDecl] nullType | semmle.label | [VarDecl] nullType | | tst.ts:28:5:28:25 | [VariableDeclarator] nullTyp ... = null | semmle.label | [VariableDeclarator] nullTyp ... = null | | tst.ts:28:15:28:18 | [KeywordTypeExpr] null | semmle.label | [KeywordTypeExpr] null | | tst.ts:28:22:28:25 | [Literal] null | semmle.label | [Literal] null | | tst.ts:29:1:29:27 | [DeclStmt] let neverType = ... | semmle.label | [DeclStmt] let neverType = ... | -| tst.ts:29:1:29:27 | [DeclStmt] let neverType = ... | semmle.order | 31 | +| tst.ts:29:1:29:27 | [DeclStmt] let neverType = ... | semmle.order | 33 | | tst.ts:29:5:29:13 | [VarDecl] neverType | semmle.label | [VarDecl] neverType | | tst.ts:29:5:29:26 | [VariableDeclarator] neverTy ... > never | semmle.label | [VariableDeclarator] neverTy ... > never | | tst.ts:29:16:29:26 | [FunctionExpr] () => never | semmle.label | [FunctionExpr] () => never | | tst.ts:29:16:29:26 | [FunctionTypeExpr] () => never | semmle.label | [FunctionTypeExpr] () => never | | tst.ts:29:22:29:26 | [KeywordTypeExpr] never | semmle.label | [KeywordTypeExpr] never | | tst.ts:30:1:30:23 | [DeclStmt] let symbolType = ... | semmle.label | [DeclStmt] let symbolType = ... | -| tst.ts:30:1:30:23 | [DeclStmt] let symbolType = ... | semmle.order | 32 | +| tst.ts:30:1:30:23 | [DeclStmt] let symbolType = ... | semmle.order | 34 | | tst.ts:30:5:30:14 | [VarDecl] symbolType | semmle.label | [VarDecl] symbolType | | tst.ts:30:5:30:22 | [VariableDeclarator] symbolType: symbol | semmle.label | [VariableDeclarator] symbolType: symbol | | tst.ts:30:17:30:22 | [KeywordTypeExpr] symbol | semmle.label | [KeywordTypeExpr] symbol | | tst.ts:31:1:31:45 | [DeclStmt] const uniqueSymbolType = ... | semmle.label | [DeclStmt] const uniqueSymbolType = ... | -| tst.ts:31:1:31:45 | [DeclStmt] const uniqueSymbolType = ... | semmle.order | 33 | +| tst.ts:31:1:31:45 | [DeclStmt] const uniqueSymbolType = ... | semmle.order | 35 | | tst.ts:31:7:31:22 | [VarDecl] uniqueSymbolType | semmle.label | [VarDecl] uniqueSymbolType | | tst.ts:31:7:31:44 | [VariableDeclarator] uniqueS ... = null | semmle.label | [VariableDeclarator] uniqueS ... = null | | tst.ts:31:25:31:37 | [KeywordTypeExpr] unique symbol | semmle.label | [KeywordTypeExpr] unique symbol | | tst.ts:31:41:31:44 | [Literal] null | semmle.label | [Literal] null | | tst.ts:32:1:32:23 | [DeclStmt] let objectType = ... | semmle.label | [DeclStmt] let objectType = ... | -| tst.ts:32:1:32:23 | [DeclStmt] let objectType = ... | semmle.order | 34 | +| tst.ts:32:1:32:23 | [DeclStmt] let objectType = ... | semmle.order | 36 | | tst.ts:32:5:32:14 | [VarDecl] objectType | semmle.label | [VarDecl] objectType | | tst.ts:32:5:32:22 | [VariableDeclarator] objectType: object | semmle.label | [VariableDeclarator] objectType: object | | tst.ts:32:17:32:22 | [KeywordTypeExpr] object | semmle.label | [KeywordTypeExpr] object | | tst.ts:33:1:33:39 | [DeclStmt] let intersection = ... | semmle.label | [DeclStmt] let intersection = ... | -| tst.ts:33:1:33:39 | [DeclStmt] let intersection = ... | semmle.order | 35 | +| tst.ts:33:1:33:39 | [DeclStmt] let intersection = ... | semmle.order | 37 | | tst.ts:33:5:33:16 | [VarDecl] intersection | semmle.label | [VarDecl] intersection | | tst.ts:33:5:33:38 | [VariableDeclarator] interse ... string} | semmle.label | [VariableDeclarator] interse ... string} | | tst.ts:33:19:33:24 | [KeywordTypeExpr] string | semmle.label | [KeywordTypeExpr] string | @@ -249,14 +267,14 @@ nodes | tst.ts:33:29:33:37 | [FieldDeclaration] x: string | semmle.label | [FieldDeclaration] x: string | | tst.ts:33:32:33:37 | [KeywordTypeExpr] string | semmle.label | [KeywordTypeExpr] string | | tst.ts:34:1:34:28 | [DeclStmt] let tuple = ... | semmle.label | [DeclStmt] let tuple = ... | -| tst.ts:34:1:34:28 | [DeclStmt] let tuple = ... | semmle.order | 36 | +| tst.ts:34:1:34:28 | [DeclStmt] let tuple = ... | semmle.order | 38 | | tst.ts:34:5:34:9 | [VarDecl] tuple | semmle.label | [VarDecl] tuple | | tst.ts:34:5:34:27 | [VariableDeclarator] tuple: ... string] | semmle.label | [VariableDeclarator] tuple: ... string] | | tst.ts:34:12:34:27 | [TupleTypeExpr] [number, string] | semmle.label | [TupleTypeExpr] [number, string] | | tst.ts:34:13:34:18 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number | | tst.ts:34:21:34:26 | [KeywordTypeExpr] string | semmle.label | [KeywordTypeExpr] string | | tst.ts:36:1:36:56 | [DeclStmt] let tupleWithOptionalElement = ... | semmle.label | [DeclStmt] let tupleWithOptionalElement = ... | -| tst.ts:36:1:36:56 | [DeclStmt] let tupleWithOptionalElement = ... | semmle.order | 37 | +| tst.ts:36:1:36:56 | [DeclStmt] let tupleWithOptionalElement = ... | semmle.order | 39 | | tst.ts:36:5:36:28 | [VarDecl] tupleWithOptionalElement | semmle.label | [VarDecl] tupleWithOptionalElement | | tst.ts:36:5:36:55 | [VariableDeclarator] tupleWi ... umber?] | semmle.label | [VariableDeclarator] tupleWi ... umber?] | | tst.ts:36:31:36:55 | [TupleTypeExpr] [number ... umber?] | semmle.label | [TupleTypeExpr] [number ... umber?] | @@ -265,12 +283,12 @@ nodes | tst.ts:36:48:36:53 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number | | tst.ts:36:48:36:54 | [OptionalTypeExpr] number? | semmle.label | [OptionalTypeExpr] number? | | tst.ts:37:1:37:19 | [DeclStmt] let emptyTuple = ... | semmle.label | [DeclStmt] let emptyTuple = ... | -| tst.ts:37:1:37:19 | [DeclStmt] let emptyTuple = ... | semmle.order | 38 | +| tst.ts:37:1:37:19 | [DeclStmt] let emptyTuple = ... | semmle.order | 40 | | tst.ts:37:5:37:14 | [VarDecl] emptyTuple | semmle.label | [VarDecl] emptyTuple | | tst.ts:37:5:37:18 | [VariableDeclarator] emptyTuple: [] | semmle.label | [VariableDeclarator] emptyTuple: [] | | tst.ts:37:17:37:18 | [TupleTypeExpr] [] | semmle.label | [TupleTypeExpr] [] | | tst.ts:38:1:38:48 | [DeclStmt] let tupleWithRestElement = ... | semmle.label | [DeclStmt] let tupleWithRestElement = ... | -| tst.ts:38:1:38:48 | [DeclStmt] let tupleWithRestElement = ... | semmle.order | 39 | +| tst.ts:38:1:38:48 | [DeclStmt] let tupleWithRestElement = ... | semmle.order | 41 | | tst.ts:38:5:38:24 | [VarDecl] tupleWithRestElement | semmle.label | [VarDecl] tupleWithRestElement | | tst.ts:38:5:38:47 | [VariableDeclarator] tupleWi ... ring[]] | semmle.label | [VariableDeclarator] tupleWi ... ring[]] | | tst.ts:38:27:38:47 | [TupleTypeExpr] [number ... ring[]] | semmle.label | [TupleTypeExpr] [number ... ring[]] | @@ -279,7 +297,7 @@ nodes | tst.ts:38:39:38:44 | [KeywordTypeExpr] string | semmle.label | [KeywordTypeExpr] string | | tst.ts:38:39:38:46 | [ArrayTypeExpr] string[] | semmle.label | [ArrayTypeExpr] string[] | | tst.ts:39:1:39:69 | [DeclStmt] let tupleWithOptionalAndRestElements = ... | semmle.label | [DeclStmt] let tupleWithOptionalAndRestElements = ... | -| tst.ts:39:1:39:69 | [DeclStmt] let tupleWithOptionalAndRestElements = ... | semmle.order | 40 | +| tst.ts:39:1:39:69 | [DeclStmt] let tupleWithOptionalAndRestElements = ... | semmle.order | 42 | | tst.ts:39:5:39:36 | [VarDecl] tupleWithOptionalAndRestElements | semmle.label | [VarDecl] tupleWithOptionalAndRestElements | | tst.ts:39:5:39:68 | [VariableDeclarator] tupleWi ... mber[]] | semmle.label | [VariableDeclarator] tupleWi ... mber[]] | | tst.ts:39:39:39:68 | [TupleTypeExpr] [number ... mber[]] | semmle.label | [TupleTypeExpr] [number ... mber[]] | @@ -290,12 +308,12 @@ nodes | tst.ts:39:60:39:65 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number | | tst.ts:39:60:39:67 | [ArrayTypeExpr] number[] | semmle.label | [ArrayTypeExpr] number[] | | tst.ts:40:1:40:25 | [DeclStmt] let unknownType = ... | semmle.label | [DeclStmt] let unknownType = ... | -| tst.ts:40:1:40:25 | [DeclStmt] let unknownType = ... | semmle.order | 41 | +| tst.ts:40:1:40:25 | [DeclStmt] let unknownType = ... | semmle.order | 43 | | tst.ts:40:5:40:15 | [VarDecl] unknownType | semmle.label | [VarDecl] unknownType | | tst.ts:40:5:40:24 | [VariableDeclarator] unknownType: unknown | semmle.label | [VariableDeclarator] unknownType: unknown | | tst.ts:40:18:40:24 | [KeywordTypeExpr] unknown | semmle.label | [KeywordTypeExpr] unknown | | tst.ts:42:1:42:40 | [DeclStmt] let constArrayLiteral = ... | semmle.label | [DeclStmt] let constArrayLiteral = ... | -| tst.ts:42:1:42:40 | [DeclStmt] let constArrayLiteral = ... | semmle.order | 42 | +| tst.ts:42:1:42:40 | [DeclStmt] let constArrayLiteral = ... | semmle.order | 44 | | tst.ts:42:5:42:21 | [VarDecl] constArrayLiteral | semmle.label | [VarDecl] constArrayLiteral | | tst.ts:42:5:42:39 | [VariableDeclarator] constAr ... s const | semmle.label | [VariableDeclarator] constAr ... s const | | tst.ts:42:25:42:30 | [ArrayExpr] [1, 2] | semmle.label | [ArrayExpr] [1, 2] | @@ -304,7 +322,7 @@ nodes | tst.ts:42:29:42:29 | [Literal] 2 | semmle.label | [Literal] 2 | | tst.ts:42:35:42:39 | [KeywordTypeExpr] const | semmle.label | [KeywordTypeExpr] const | | tst.ts:43:1:43:49 | [DeclStmt] let constObjectLiteral = ... | semmle.label | [DeclStmt] let constObjectLiteral = ... | -| tst.ts:43:1:43:49 | [DeclStmt] let constObjectLiteral = ... | semmle.order | 43 | +| tst.ts:43:1:43:49 | [DeclStmt] let constObjectLiteral = ... | semmle.order | 45 | | tst.ts:43:5:43:22 | [VarDecl] constObjectLiteral | semmle.label | [VarDecl] constObjectLiteral | | tst.ts:43:5:43:48 | [VariableDeclarator] constOb ... s const | semmle.label | [VariableDeclarator] constOb ... s const | | tst.ts:43:26:43:39 | [ObjectExpr] {foo: ...} | semmle.label | [ObjectExpr] {foo: ...} | @@ -314,7 +332,7 @@ nodes | tst.ts:43:33:43:37 | [Literal] "foo" | semmle.label | [Literal] "foo" | | tst.ts:43:44:43:48 | [KeywordTypeExpr] const | semmle.label | [KeywordTypeExpr] const | | tst.ts:46:1:51:1 | [TryStmt] try { } ... ; } } | semmle.label | [TryStmt] try { } ... ; } } | -| tst.ts:46:1:51:1 | [TryStmt] try { } ... ; } } | semmle.order | 44 | +| tst.ts:46:1:51:1 | [TryStmt] try { } ... ; } } | semmle.order | 46 | | tst.ts:46:5:46:7 | [BlockStmt] { } | semmle.label | [BlockStmt] { } | | tst.ts:47:1:51:1 | [CatchClause] catch ( ... ; } } | semmle.label | [CatchClause] catch ( ... ; } } | | tst.ts:47:8:47:8 | [SimpleParameter] e | semmle.label | [SimpleParameter] e | @@ -330,17 +348,78 @@ nodes | tst.ts:49:11:49:24 | [VariableDeclarator] b : string = e | semmle.label | [VariableDeclarator] b : string = e | | tst.ts:49:15:49:20 | [KeywordTypeExpr] string | semmle.label | [KeywordTypeExpr] string | | tst.ts:49:24:49:24 | [VarRef] e | semmle.label | [VarRef] e | +| tst.ts:54:1:56:1 | [InterfaceDeclaration,TypeDefinition] interfa ... mber; } | semmle.label | [InterfaceDeclaration,TypeDefinition] interfa ... mber; } | +| tst.ts:54:1:56:1 | [InterfaceDeclaration,TypeDefinition] interfa ... mber; } | semmle.order | 47 | +| tst.ts:54:11:54:26 | [Identifier] NonAbstractDummy | semmle.label | [Identifier] NonAbstractDummy | +| tst.ts:55:3:55:9 | [Label] getArea | semmle.label | [Label] getArea | +| tst.ts:55:3:55:20 | [FunctionExpr] getArea(): number; | semmle.label | [FunctionExpr] getArea(): number; | +| tst.ts:55:3:55:20 | [MethodSignature] getArea(): number; | semmle.label | [MethodSignature] getArea(): number; | +| tst.ts:55:14:55:19 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number | +| tst.ts:58:1:60:1 | [InterfaceDeclaration,TypeDefinition] interfa ... mber; } | semmle.label | [InterfaceDeclaration,TypeDefinition] interfa ... mber; } | +| tst.ts:58:1:60:1 | [InterfaceDeclaration,TypeDefinition] interfa ... mber; } | semmle.order | 48 | +| tst.ts:58:11:58:17 | [Identifier] HasArea | semmle.label | [Identifier] HasArea | +| tst.ts:59:3:59:9 | [Label] getArea | semmle.label | [Label] getArea | +| tst.ts:59:3:59:20 | [FunctionExpr] getArea(): number; | semmle.label | [FunctionExpr] getArea(): number; | +| tst.ts:59:3:59:20 | [MethodSignature] getArea(): number; | semmle.label | [MethodSignature] getArea(): number; | +| tst.ts:59:14:59:19 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number | +| tst.ts:63:1:63:45 | [DeclStmt] let Ctor = ... | semmle.label | [DeclStmt] let Ctor = ... | +| tst.ts:63:1:63:45 | [DeclStmt] let Ctor = ... | semmle.order | 49 | +| tst.ts:63:5:63:8 | [VarDecl] Ctor | semmle.label | [VarDecl] Ctor | +| tst.ts:63:5:63:44 | [VariableDeclarator] Ctor: a ... = Shape | semmle.label | [VariableDeclarator] Ctor: a ... = Shape | +| tst.ts:63:11:63:36 | [FunctionExpr] abstrac ... HasArea | semmle.label | [FunctionExpr] abstrac ... HasArea | +| tst.ts:63:11:63:36 | [FunctionTypeExpr] abstrac ... HasArea | semmle.label | [FunctionTypeExpr] abstrac ... HasArea | +| tst.ts:63:30:63:36 | [LocalTypeAccess] HasArea | semmle.label | [LocalTypeAccess] HasArea | +| tst.ts:63:40:63:44 | [VarRef] Shape | semmle.label | [VarRef] Shape | +| tst.ts:65:1:65:54 | [TypeAliasDeclaration,TypeDefinition] type My ... true}; | semmle.label | [TypeAliasDeclaration,TypeDefinition] type My ... true}; | +| tst.ts:65:1:65:54 | [TypeAliasDeclaration,TypeDefinition] type My ... true}; | semmle.order | 50 | +| tst.ts:65:6:65:12 | [Identifier] MyUnion | semmle.label | [Identifier] MyUnion | +| tst.ts:65:16:65:30 | [InterfaceTypeExpr] {myUnion: true} | semmle.label | [InterfaceTypeExpr] {myUnion: true} | +| tst.ts:65:16:65:53 | [UnionTypeExpr] {myUnio ... : true} | semmle.label | [UnionTypeExpr] {myUnio ... : true} | +| tst.ts:65:17:65:23 | [Label] myUnion | semmle.label | [Label] myUnion | +| tst.ts:65:17:65:29 | [FieldDeclaration] myUnion: true | semmle.label | [FieldDeclaration] myUnion: true | +| tst.ts:65:26:65:29 | [LiteralTypeExpr] true | semmle.label | [LiteralTypeExpr] true | +| tst.ts:65:34:65:53 | [InterfaceTypeExpr] {stillMyUnion: true} | semmle.label | [InterfaceTypeExpr] {stillMyUnion: true} | +| tst.ts:65:35:65:46 | [Label] stillMyUnion | semmle.label | [Label] stillMyUnion | +| tst.ts:65:35:65:52 | [FieldDeclaration] stillMyUnion: true | semmle.label | [FieldDeclaration] stillMyUnion: true | +| tst.ts:65:49:65:52 | [LiteralTypeExpr] true | semmle.label | [LiteralTypeExpr] true | +| tst.ts:66:1:66:38 | [DeclStmt] let union1 = ... | semmle.label | [DeclStmt] let union1 = ... | +| tst.ts:66:1:66:38 | [DeclStmt] let union1 = ... | semmle.order | 51 | +| tst.ts:66:5:66:10 | [VarDecl] union1 | semmle.label | [VarDecl] union1 | +| tst.ts:66:5:66:37 | [VariableDeclarator] union1: ... : true} | semmle.label | [VariableDeclarator] union1: ... : true} | +| tst.ts:66:13:66:19 | [LocalTypeAccess] MyUnion | semmle.label | [LocalTypeAccess] MyUnion | +| tst.ts:66:23:66:37 | [ObjectExpr] {myUnion: ...} | semmle.label | [ObjectExpr] {myUnion: ...} | +| tst.ts:66:24:66:30 | [Label] myUnion | semmle.label | [Label] myUnion | +| tst.ts:66:24:66:36 | [Property] myUnion: true | semmle.label | [Property] myUnion: true | +| tst.ts:66:33:66:36 | [Literal] true | semmle.label | [Literal] true | +| tst.ts:68:1:68:49 | [TypeAliasDeclaration,TypeDefinition] type My ... true}; | semmle.label | [TypeAliasDeclaration,TypeDefinition] type My ... true}; | +| tst.ts:68:1:68:49 | [TypeAliasDeclaration,TypeDefinition] type My ... true}; | semmle.order | 52 | +| tst.ts:68:6:68:13 | [Identifier] MyUnion2 | semmle.label | [Identifier] MyUnion2 | +| tst.ts:68:17:68:23 | [LocalTypeAccess] MyUnion | semmle.label | [LocalTypeAccess] MyUnion | +| tst.ts:68:17:68:48 | [UnionTypeExpr] MyUnion ... : true} | semmle.label | [UnionTypeExpr] MyUnion ... : true} | +| tst.ts:68:27:68:48 | [InterfaceTypeExpr] {yetAno ... : true} | semmle.label | [InterfaceTypeExpr] {yetAno ... : true} | +| tst.ts:68:28:68:41 | [Label] yetAnotherType | semmle.label | [Label] yetAnotherType | +| tst.ts:68:28:68:47 | [FieldDeclaration] yetAnotherType: true | semmle.label | [FieldDeclaration] yetAnotherType: true | +| tst.ts:68:44:68:47 | [LiteralTypeExpr] true | semmle.label | [LiteralTypeExpr] true | +| tst.ts:69:1:69:46 | [DeclStmt] let union2 = ... | semmle.label | [DeclStmt] let union2 = ... | +| tst.ts:69:1:69:46 | [DeclStmt] let union2 = ... | semmle.order | 53 | +| tst.ts:69:5:69:10 | [VarDecl] union2 | semmle.label | [VarDecl] union2 | +| tst.ts:69:5:69:45 | [VariableDeclarator] union2: ... : true} | semmle.label | [VariableDeclarator] union2: ... : true} | +| tst.ts:69:13:69:20 | [LocalTypeAccess] MyUnion2 | semmle.label | [LocalTypeAccess] MyUnion2 | +| tst.ts:69:24:69:45 | [ObjectExpr] {yetAnotherType: ...} | semmle.label | [ObjectExpr] {yetAnotherType: ...} | +| tst.ts:69:25:69:38 | [Label] yetAnotherType | semmle.label | [Label] yetAnotherType | +| tst.ts:69:25:69:44 | [Property] yetAnotherType: true | semmle.label | [Property] yetAnotherType: true | +| tst.ts:69:41:69:44 | [Literal] true | semmle.label | [Literal] true | | type_alias.ts:1:1:1:17 | [TypeAliasDeclaration,TypeDefinition] type B = boolean; | semmle.label | [TypeAliasDeclaration,TypeDefinition] type B = boolean; | -| type_alias.ts:1:1:1:17 | [TypeAliasDeclaration,TypeDefinition] type B = boolean; | semmle.order | 45 | +| type_alias.ts:1:1:1:17 | [TypeAliasDeclaration,TypeDefinition] type B = boolean; | semmle.order | 54 | | type_alias.ts:1:6:1:6 | [Identifier] B | semmle.label | [Identifier] B | | type_alias.ts:1:10:1:16 | [KeywordTypeExpr] boolean | semmle.label | [KeywordTypeExpr] boolean | | type_alias.ts:3:1:3:9 | [DeclStmt] var b = ... | semmle.label | [DeclStmt] var b = ... | -| type_alias.ts:3:1:3:9 | [DeclStmt] var b = ... | semmle.order | 46 | +| type_alias.ts:3:1:3:9 | [DeclStmt] var b = ... | semmle.order | 55 | | type_alias.ts:3:5:3:5 | [VarDecl] b | semmle.label | [VarDecl] b | | type_alias.ts:3:5:3:8 | [VariableDeclarator] b: B | semmle.label | [VariableDeclarator] b: B | | type_alias.ts:3:8:3:8 | [LocalTypeAccess] B | semmle.label | [LocalTypeAccess] B | | type_alias.ts:5:1:5:50 | [TypeAliasDeclaration,TypeDefinition] type Va ... ay>; | semmle.label | [TypeAliasDeclaration,TypeDefinition] type Va ... ay>; | -| type_alias.ts:5:1:5:50 | [TypeAliasDeclaration,TypeDefinition] type Va ... ay>; | semmle.order | 47 | +| type_alias.ts:5:1:5:50 | [TypeAliasDeclaration,TypeDefinition] type Va ... ay>; | semmle.order | 56 | | type_alias.ts:5:6:5:17 | [Identifier] ValueOrArray | semmle.label | [Identifier] ValueOrArray | | type_alias.ts:5:19:5:19 | [Identifier] T | semmle.label | [Identifier] T | | type_alias.ts:5:19:5:19 | [TypeParameter] T | semmle.label | [TypeParameter] T | @@ -352,14 +431,14 @@ nodes | type_alias.ts:5:34:5:48 | [GenericTypeExpr] ValueOrArray | semmle.label | [GenericTypeExpr] ValueOrArray | | type_alias.ts:5:47:5:47 | [LocalTypeAccess] T | semmle.label | [LocalTypeAccess] T | | type_alias.ts:7:1:7:28 | [DeclStmt] var c = ... | semmle.label | [DeclStmt] var c = ... | -| type_alias.ts:7:1:7:28 | [DeclStmt] var c = ... | semmle.order | 48 | +| type_alias.ts:7:1:7:28 | [DeclStmt] var c = ... | semmle.order | 57 | | type_alias.ts:7:5:7:5 | [VarDecl] c | semmle.label | [VarDecl] c | | type_alias.ts:7:5:7:27 | [VariableDeclarator] c: Valu ... number> | semmle.label | [VariableDeclarator] c: Valu ... number> | | type_alias.ts:7:8:7:19 | [LocalTypeAccess] ValueOrArray | semmle.label | [LocalTypeAccess] ValueOrArray | | type_alias.ts:7:8:7:27 | [GenericTypeExpr] ValueOrArray | semmle.label | [GenericTypeExpr] ValueOrArray | | type_alias.ts:7:21:7:26 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number | | type_alias.ts:9:1:15:13 | [TypeAliasDeclaration,TypeDefinition] type Js ... Json[]; | semmle.label | [TypeAliasDeclaration,TypeDefinition] type Js ... Json[]; | -| type_alias.ts:9:1:15:13 | [TypeAliasDeclaration,TypeDefinition] type Js ... Json[]; | semmle.order | 49 | +| type_alias.ts:9:1:15:13 | [TypeAliasDeclaration,TypeDefinition] type Js ... Json[]; | semmle.order | 58 | | type_alias.ts:9:6:9:9 | [Identifier] Json | semmle.label | [Identifier] Json | | type_alias.ts:10:5:15:12 | [UnionTypeExpr] \| strin ... Json[] | semmle.label | [UnionTypeExpr] \| strin ... Json[] | | type_alias.ts:10:7:10:12 | [KeywordTypeExpr] string | semmle.label | [KeywordTypeExpr] string | @@ -375,12 +454,12 @@ nodes | type_alias.ts:15:7:15:10 | [LocalTypeAccess] Json | semmle.label | [LocalTypeAccess] Json | | type_alias.ts:15:7:15:12 | [ArrayTypeExpr] Json[] | semmle.label | [ArrayTypeExpr] Json[] | | type_alias.ts:17:1:17:15 | [DeclStmt] var json = ... | semmle.label | [DeclStmt] var json = ... | -| type_alias.ts:17:1:17:15 | [DeclStmt] var json = ... | semmle.order | 50 | +| type_alias.ts:17:1:17:15 | [DeclStmt] var json = ... | semmle.order | 59 | | type_alias.ts:17:5:17:8 | [VarDecl] json | semmle.label | [VarDecl] json | | type_alias.ts:17:5:17:14 | [VariableDeclarator] json: Json | semmle.label | [VariableDeclarator] json: Json | | type_alias.ts:17:11:17:14 | [LocalTypeAccess] Json | semmle.label | [LocalTypeAccess] Json | | type_alias.ts:19:1:21:57 | [TypeAliasDeclaration,TypeDefinition] type Vi ... ode[]]; | semmle.label | [TypeAliasDeclaration,TypeDefinition] type Vi ... ode[]]; | -| type_alias.ts:19:1:21:57 | [TypeAliasDeclaration,TypeDefinition] type Vi ... ode[]]; | semmle.order | 51 | +| type_alias.ts:19:1:21:57 | [TypeAliasDeclaration,TypeDefinition] type Vi ... ode[]]; | semmle.order | 60 | | type_alias.ts:19:6:19:16 | [Identifier] VirtualNode | semmle.label | [Identifier] VirtualNode | | type_alias.ts:20:5:21:56 | [UnionTypeExpr] \| strin ... Node[]] | semmle.label | [UnionTypeExpr] \| strin ... Node[]] | | type_alias.ts:20:7:20:12 | [KeywordTypeExpr] string | semmle.label | [KeywordTypeExpr] string | @@ -396,7 +475,7 @@ nodes | type_alias.ts:21:43:21:53 | [LocalTypeAccess] VirtualNode | semmle.label | [LocalTypeAccess] VirtualNode | | type_alias.ts:21:43:21:55 | [ArrayTypeExpr] VirtualNode[] | semmle.label | [ArrayTypeExpr] VirtualNode[] | | type_alias.ts:23:1:27:6 | [DeclStmt] const myNode = ... | semmle.label | [DeclStmt] const myNode = ... | -| type_alias.ts:23:1:27:6 | [DeclStmt] const myNode = ... | semmle.order | 52 | +| type_alias.ts:23:1:27:6 | [DeclStmt] const myNode = ... | semmle.order | 61 | | type_alias.ts:23:7:23:12 | [VarDecl] myNode | semmle.label | [VarDecl] myNode | | type_alias.ts:23:7:27:5 | [VariableDeclarator] myNode: ... ] ] | semmle.label | [VariableDeclarator] myNode: ... ] ] | | type_alias.ts:23:15:23:25 | [LocalTypeAccess] VirtualNode | semmle.label | [LocalTypeAccess] VirtualNode | @@ -421,12 +500,12 @@ nodes | type_alias.ts:26:23:26:36 | [Literal] "second-child" | semmle.label | [Literal] "second-child" | | type_alias.ts:26:41:26:62 | [Literal] "I'm the second child" | semmle.label | [Literal] "I'm the second child" | | type_definition_objects.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.label | [ImportDeclaration] import ... dummy"; | -| type_definition_objects.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.order | 53 | +| type_definition_objects.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.order | 62 | | type_definition_objects.ts:1:8:1:17 | [ImportSpecifier] * as dummy | semmle.label | [ImportSpecifier] * as dummy | | type_definition_objects.ts:1:13:1:17 | [VarDecl] dummy | semmle.label | [VarDecl] dummy | | type_definition_objects.ts:1:24:1:32 | [Literal] "./dummy" | semmle.label | [Literal] "./dummy" | | type_definition_objects.ts:3:1:3:17 | [ExportDeclaration] export class C {} | semmle.label | [ExportDeclaration] export class C {} | -| type_definition_objects.ts:3:1:3:17 | [ExportDeclaration] export class C {} | semmle.order | 54 | +| type_definition_objects.ts:3:1:3:17 | [ExportDeclaration] export class C {} | semmle.order | 63 | | type_definition_objects.ts:3:8:3:17 | [ClassDefinition,TypeDefinition] class C {} | semmle.label | [ClassDefinition,TypeDefinition] class C {} | | type_definition_objects.ts:3:14:3:14 | [VarDecl] C | semmle.label | [VarDecl] C | | type_definition_objects.ts:3:16:3:15 | [BlockStmt] {} | semmle.label | [BlockStmt] {} | @@ -434,36 +513,36 @@ nodes | type_definition_objects.ts:3:16:3:15 | [FunctionExpr] () {} | semmle.label | [FunctionExpr] () {} | | type_definition_objects.ts:3:16:3:15 | [Label] constructor | semmle.label | [Label] constructor | | type_definition_objects.ts:4:1:4:17 | [DeclStmt] let classObj = ... | semmle.label | [DeclStmt] let classObj = ... | -| type_definition_objects.ts:4:1:4:17 | [DeclStmt] let classObj = ... | semmle.order | 55 | +| type_definition_objects.ts:4:1:4:17 | [DeclStmt] let classObj = ... | semmle.order | 64 | | type_definition_objects.ts:4:5:4:12 | [VarDecl] classObj | semmle.label | [VarDecl] classObj | | type_definition_objects.ts:4:5:4:16 | [VariableDeclarator] classObj = C | semmle.label | [VariableDeclarator] classObj = C | | type_definition_objects.ts:4:16:4:16 | [VarRef] C | semmle.label | [VarRef] C | | type_definition_objects.ts:6:1:6:16 | [ExportDeclaration] export enum E {} | semmle.label | [ExportDeclaration] export enum E {} | -| type_definition_objects.ts:6:1:6:16 | [ExportDeclaration] export enum E {} | semmle.order | 56 | +| type_definition_objects.ts:6:1:6:16 | [ExportDeclaration] export enum E {} | semmle.order | 65 | | type_definition_objects.ts:6:8:6:16 | [EnumDeclaration,TypeDefinition] enum E {} | semmle.label | [EnumDeclaration,TypeDefinition] enum E {} | | type_definition_objects.ts:6:13:6:13 | [VarDecl] E | semmle.label | [VarDecl] E | | type_definition_objects.ts:7:1:7:16 | [DeclStmt] let enumObj = ... | semmle.label | [DeclStmt] let enumObj = ... | -| type_definition_objects.ts:7:1:7:16 | [DeclStmt] let enumObj = ... | semmle.order | 57 | +| type_definition_objects.ts:7:1:7:16 | [DeclStmt] let enumObj = ... | semmle.order | 66 | | type_definition_objects.ts:7:5:7:11 | [VarDecl] enumObj | semmle.label | [VarDecl] enumObj | | type_definition_objects.ts:7:5:7:15 | [VariableDeclarator] enumObj = E | semmle.label | [VariableDeclarator] enumObj = E | | type_definition_objects.ts:7:15:7:15 | [VarRef] E | semmle.label | [VarRef] E | | type_definition_objects.ts:9:1:9:22 | [ExportDeclaration] export ... e N {;} | semmle.label | [ExportDeclaration] export ... e N {;} | -| type_definition_objects.ts:9:1:9:22 | [ExportDeclaration] export ... e N {;} | semmle.order | 58 | +| type_definition_objects.ts:9:1:9:22 | [ExportDeclaration] export ... e N {;} | semmle.order | 67 | | type_definition_objects.ts:9:8:9:22 | [NamespaceDeclaration] namespace N {;} | semmle.label | [NamespaceDeclaration] namespace N {;} | | type_definition_objects.ts:9:18:9:18 | [VarDecl] N | semmle.label | [VarDecl] N | | type_definition_objects.ts:9:21:9:21 | [EmptyStmt] ; | semmle.label | [EmptyStmt] ; | | type_definition_objects.ts:10:1:10:21 | [DeclStmt] let namespaceObj = ... | semmle.label | [DeclStmt] let namespaceObj = ... | -| type_definition_objects.ts:10:1:10:21 | [DeclStmt] let namespaceObj = ... | semmle.order | 59 | +| type_definition_objects.ts:10:1:10:21 | [DeclStmt] let namespaceObj = ... | semmle.order | 68 | | type_definition_objects.ts:10:5:10:16 | [VarDecl] namespaceObj | semmle.label | [VarDecl] namespaceObj | | type_definition_objects.ts:10:5:10:20 | [VariableDeclarator] namespaceObj = N | semmle.label | [VariableDeclarator] namespaceObj = N | | type_definition_objects.ts:10:20:10:20 | [VarRef] N | semmle.label | [VarRef] N | | type_definitions.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.label | [ImportDeclaration] import ... dummy"; | -| type_definitions.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.order | 60 | +| type_definitions.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | semmle.order | 69 | | type_definitions.ts:1:8:1:17 | [ImportSpecifier] * as dummy | semmle.label | [ImportSpecifier] * as dummy | | type_definitions.ts:1:13:1:17 | [VarDecl] dummy | semmle.label | [VarDecl] dummy | | type_definitions.ts:1:24:1:32 | [Literal] "./dummy" | semmle.label | [Literal] "./dummy" | | type_definitions.ts:3:1:5:1 | [InterfaceDeclaration,TypeDefinition] interfa ... x: S; } | semmle.label | [InterfaceDeclaration,TypeDefinition] interfa ... x: S; } | -| type_definitions.ts:3:1:5:1 | [InterfaceDeclaration,TypeDefinition] interfa ... x: S; } | semmle.order | 61 | +| type_definitions.ts:3:1:5:1 | [InterfaceDeclaration,TypeDefinition] interfa ... x: S; } | semmle.order | 70 | | type_definitions.ts:3:11:3:11 | [Identifier] I | semmle.label | [Identifier] I | | type_definitions.ts:3:13:3:13 | [Identifier] S | semmle.label | [Identifier] S | | type_definitions.ts:3:13:3:13 | [TypeParameter] S | semmle.label | [TypeParameter] S | @@ -471,14 +550,14 @@ nodes | type_definitions.ts:4:3:4:7 | [FieldDeclaration] x: S; | semmle.label | [FieldDeclaration] x: S; | | type_definitions.ts:4:6:4:6 | [LocalTypeAccess] S | semmle.label | [LocalTypeAccess] S | | type_definitions.ts:6:1:6:16 | [DeclStmt] let i = ... | semmle.label | [DeclStmt] let i = ... | -| type_definitions.ts:6:1:6:16 | [DeclStmt] let i = ... | semmle.order | 62 | +| type_definitions.ts:6:1:6:16 | [DeclStmt] let i = ... | semmle.order | 71 | | type_definitions.ts:6:5:6:5 | [VarDecl] i | semmle.label | [VarDecl] i | | type_definitions.ts:6:5:6:16 | [VariableDeclarator] i: I | semmle.label | [VariableDeclarator] i: I | | type_definitions.ts:6:8:6:8 | [LocalTypeAccess] I | semmle.label | [LocalTypeAccess] I | | type_definitions.ts:6:8:6:16 | [GenericTypeExpr] I | semmle.label | [GenericTypeExpr] I | | type_definitions.ts:6:10:6:15 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number | | type_definitions.ts:8:1:10:1 | [ClassDefinition,TypeDefinition] class C ... x: T } | semmle.label | [ClassDefinition,TypeDefinition] class C ... x: T } | -| type_definitions.ts:8:1:10:1 | [ClassDefinition,TypeDefinition] class C ... x: T } | semmle.order | 63 | +| type_definitions.ts:8:1:10:1 | [ClassDefinition,TypeDefinition] class C ... x: T } | semmle.order | 72 | | type_definitions.ts:8:7:8:7 | [VarDecl] C | semmle.label | [VarDecl] C | | type_definitions.ts:8:8:8:7 | [BlockStmt] {} | semmle.label | [BlockStmt] {} | | type_definitions.ts:8:8:8:7 | [ClassInitializedMember,ConstructorDefinition] constructor() {} | semmle.label | [ClassInitializedMember,ConstructorDefinition] constructor() {} | @@ -490,14 +569,14 @@ nodes | type_definitions.ts:9:3:9:6 | [FieldDeclaration] x: T | semmle.label | [FieldDeclaration] x: T | | type_definitions.ts:9:6:9:6 | [LocalTypeAccess] T | semmle.label | [LocalTypeAccess] T | | type_definitions.ts:11:1:11:17 | [DeclStmt] let c = ... | semmle.label | [DeclStmt] let c = ... | -| type_definitions.ts:11:1:11:17 | [DeclStmt] let c = ... | semmle.order | 64 | +| type_definitions.ts:11:1:11:17 | [DeclStmt] let c = ... | semmle.order | 73 | | type_definitions.ts:11:5:11:5 | [VarDecl] c | semmle.label | [VarDecl] c | | type_definitions.ts:11:5:11:16 | [VariableDeclarator] c: C | semmle.label | [VariableDeclarator] c: C | | type_definitions.ts:11:8:11:8 | [LocalTypeAccess] C | semmle.label | [LocalTypeAccess] C | | type_definitions.ts:11:8:11:16 | [GenericTypeExpr] C | semmle.label | [GenericTypeExpr] C | | type_definitions.ts:11:10:11:15 | [KeywordTypeExpr] number | semmle.label | [KeywordTypeExpr] number | | type_definitions.ts:13:1:15:1 | [EnumDeclaration,TypeDefinition] enum Co ... blue } | semmle.label | [EnumDeclaration,TypeDefinition] enum Co ... blue } | -| type_definitions.ts:13:1:15:1 | [EnumDeclaration,TypeDefinition] enum Co ... blue } | semmle.order | 65 | +| type_definitions.ts:13:1:15:1 | [EnumDeclaration,TypeDefinition] enum Co ... blue } | semmle.order | 74 | | type_definitions.ts:13:6:13:10 | [VarDecl] Color | semmle.label | [VarDecl] Color | | type_definitions.ts:14:3:14:5 | [EnumMember,TypeDefinition] red | semmle.label | [EnumMember,TypeDefinition] red | | type_definitions.ts:14:3:14:5 | [VarDecl] red | semmle.label | [VarDecl] red | @@ -506,29 +585,29 @@ nodes | type_definitions.ts:14:15:14:18 | [EnumMember,TypeDefinition] blue | semmle.label | [EnumMember,TypeDefinition] blue | | type_definitions.ts:14:15:14:18 | [VarDecl] blue | semmle.label | [VarDecl] blue | | type_definitions.ts:16:1:16:17 | [DeclStmt] let color = ... | semmle.label | [DeclStmt] let color = ... | -| type_definitions.ts:16:1:16:17 | [DeclStmt] let color = ... | semmle.order | 66 | +| type_definitions.ts:16:1:16:17 | [DeclStmt] let color = ... | semmle.order | 75 | | type_definitions.ts:16:5:16:9 | [VarDecl] color | semmle.label | [VarDecl] color | | type_definitions.ts:16:5:16:16 | [VariableDeclarator] color: Color | semmle.label | [VariableDeclarator] color: Color | | type_definitions.ts:16:12:16:16 | [LocalTypeAccess] Color | semmle.label | [LocalTypeAccess] Color | | type_definitions.ts:18:1:18:33 | [EnumDeclaration,TypeDefinition] enum En ... ember } | semmle.label | [EnumDeclaration,TypeDefinition] enum En ... ember } | -| type_definitions.ts:18:1:18:33 | [EnumDeclaration,TypeDefinition] enum En ... ember } | semmle.order | 67 | +| type_definitions.ts:18:1:18:33 | [EnumDeclaration,TypeDefinition] enum En ... ember } | semmle.order | 76 | | type_definitions.ts:18:6:18:22 | [VarDecl] EnumWithOneMember | semmle.label | [VarDecl] EnumWithOneMember | | type_definitions.ts:18:26:18:31 | [EnumMember,TypeDefinition] member | semmle.label | [EnumMember,TypeDefinition] member | | type_definitions.ts:18:26:18:31 | [VarDecl] member | semmle.label | [VarDecl] member | | type_definitions.ts:19:1:19:25 | [DeclStmt] let e = ... | semmle.label | [DeclStmt] let e = ... | -| type_definitions.ts:19:1:19:25 | [DeclStmt] let e = ... | semmle.order | 68 | +| type_definitions.ts:19:1:19:25 | [DeclStmt] let e = ... | semmle.order | 77 | | type_definitions.ts:19:5:19:5 | [VarDecl] e | semmle.label | [VarDecl] e | | type_definitions.ts:19:5:19:24 | [VariableDeclarator] e: EnumWithOneMember | semmle.label | [VariableDeclarator] e: EnumWithOneMember | | type_definitions.ts:19:8:19:24 | [LocalTypeAccess] EnumWithOneMember | semmle.label | [LocalTypeAccess] EnumWithOneMember | | type_definitions.ts:21:1:21:20 | [TypeAliasDeclaration,TypeDefinition] type Alias = T[]; | semmle.label | [TypeAliasDeclaration,TypeDefinition] type Alias = T[]; | -| type_definitions.ts:21:1:21:20 | [TypeAliasDeclaration,TypeDefinition] type Alias = T[]; | semmle.order | 69 | +| type_definitions.ts:21:1:21:20 | [TypeAliasDeclaration,TypeDefinition] type Alias = T[]; | semmle.order | 78 | | type_definitions.ts:21:6:21:10 | [Identifier] Alias | semmle.label | [Identifier] Alias | | type_definitions.ts:21:12:21:12 | [Identifier] T | semmle.label | [Identifier] T | | type_definitions.ts:21:12:21:12 | [TypeParameter] T | semmle.label | [TypeParameter] T | | type_definitions.ts:21:17:21:17 | [LocalTypeAccess] T | semmle.label | [LocalTypeAccess] T | | type_definitions.ts:21:17:21:19 | [ArrayTypeExpr] T[] | semmle.label | [ArrayTypeExpr] T[] | | type_definitions.ts:22:1:22:39 | [DeclStmt] let aliasForNumberArray = ... | semmle.label | [DeclStmt] let aliasForNumberArray = ... | -| type_definitions.ts:22:1:22:39 | [DeclStmt] let aliasForNumberArray = ... | semmle.order | 70 | +| type_definitions.ts:22:1:22:39 | [DeclStmt] let aliasForNumberArray = ... | semmle.order | 79 | | type_definitions.ts:22:5:22:23 | [VarDecl] aliasForNumberArray | semmle.label | [VarDecl] aliasForNumberArray | | type_definitions.ts:22:5:22:38 | [VariableDeclarator] aliasFo ... number> | semmle.label | [VariableDeclarator] aliasFo ... number> | | type_definitions.ts:22:26:22:30 | [LocalTypeAccess] Alias | semmle.label | [LocalTypeAccess] Alias | @@ -665,6 +744,34 @@ edges | file://:0:0:0:0 | (TypeParameters) | type_definitions.ts:8:9:8:9 | [TypeParameter] T | semmle.order | 0 | | file://:0:0:0:0 | (TypeParameters) | type_definitions.ts:21:12:21:12 | [TypeParameter] T | semmle.label | 0 | | file://:0:0:0:0 | (TypeParameters) | type_definitions.ts:21:12:21:12 | [TypeParameter] T | semmle.order | 0 | +| middle-rest.ts:1:1:1:40 | [DeclStmt] let foo = ... | middle-rest.ts:1:5:1:39 | [VariableDeclarator] foo: [b ... number] | semmle.label | 1 | +| middle-rest.ts:1:1:1:40 | [DeclStmt] let foo = ... | middle-rest.ts:1:5:1:39 | [VariableDeclarator] foo: [b ... number] | semmle.order | 1 | +| middle-rest.ts:1:5:1:39 | [VariableDeclarator] foo: [b ... number] | middle-rest.ts:1:5:1:7 | [VarDecl] foo | semmle.label | 1 | +| middle-rest.ts:1:5:1:39 | [VariableDeclarator] foo: [b ... number] | middle-rest.ts:1:5:1:7 | [VarDecl] foo | semmle.order | 1 | +| middle-rest.ts:1:5:1:39 | [VariableDeclarator] foo: [b ... number] | middle-rest.ts:1:10:1:39 | [TupleTypeExpr] [boolea ... number] | semmle.label | 2 | +| middle-rest.ts:1:5:1:39 | [VariableDeclarator] foo: [b ... number] | middle-rest.ts:1:10:1:39 | [TupleTypeExpr] [boolea ... number] | semmle.order | 2 | +| middle-rest.ts:1:10:1:39 | [TupleTypeExpr] [boolea ... number] | middle-rest.ts:1:11:1:17 | [KeywordTypeExpr] boolean | semmle.label | 1 | +| middle-rest.ts:1:10:1:39 | [TupleTypeExpr] [boolea ... number] | middle-rest.ts:1:11:1:17 | [KeywordTypeExpr] boolean | semmle.order | 1 | +| middle-rest.ts:1:10:1:39 | [TupleTypeExpr] [boolea ... number] | middle-rest.ts:1:20:1:30 | [RestTypeExpr] ...string[] | semmle.label | 2 | +| middle-rest.ts:1:10:1:39 | [TupleTypeExpr] [boolea ... number] | middle-rest.ts:1:20:1:30 | [RestTypeExpr] ...string[] | semmle.order | 2 | +| middle-rest.ts:1:10:1:39 | [TupleTypeExpr] [boolea ... number] | middle-rest.ts:1:33:1:38 | [KeywordTypeExpr] number | semmle.label | 3 | +| middle-rest.ts:1:10:1:39 | [TupleTypeExpr] [boolea ... number] | middle-rest.ts:1:33:1:38 | [KeywordTypeExpr] number | semmle.order | 3 | +| middle-rest.ts:1:20:1:30 | [RestTypeExpr] ...string[] | middle-rest.ts:1:23:1:30 | [ArrayTypeExpr] string[] | semmle.label | 1 | +| middle-rest.ts:1:20:1:30 | [RestTypeExpr] ...string[] | middle-rest.ts:1:23:1:30 | [ArrayTypeExpr] string[] | semmle.order | 1 | +| middle-rest.ts:1:23:1:30 | [ArrayTypeExpr] string[] | middle-rest.ts:1:23:1:28 | [KeywordTypeExpr] string | semmle.label | 1 | +| middle-rest.ts:1:23:1:30 | [ArrayTypeExpr] string[] | middle-rest.ts:1:23:1:28 | [KeywordTypeExpr] string | semmle.order | 1 | +| middle-rest.ts:3:1:3:26 | [AssignExpr] foo = [ ... ", 123] | middle-rest.ts:3:1:3:3 | [VarRef] foo | semmle.label | 1 | +| middle-rest.ts:3:1:3:26 | [AssignExpr] foo = [ ... ", 123] | middle-rest.ts:3:1:3:3 | [VarRef] foo | semmle.order | 1 | +| middle-rest.ts:3:1:3:26 | [AssignExpr] foo = [ ... ", 123] | middle-rest.ts:3:7:3:26 | [ArrayExpr] [true, "hello", 123] | semmle.label | 2 | +| middle-rest.ts:3:1:3:26 | [AssignExpr] foo = [ ... ", 123] | middle-rest.ts:3:7:3:26 | [ArrayExpr] [true, "hello", 123] | semmle.order | 2 | +| middle-rest.ts:3:1:3:27 | [ExprStmt] foo = [ ... , 123]; | middle-rest.ts:3:1:3:26 | [AssignExpr] foo = [ ... ", 123] | semmle.label | 1 | +| middle-rest.ts:3:1:3:27 | [ExprStmt] foo = [ ... , 123]; | middle-rest.ts:3:1:3:26 | [AssignExpr] foo = [ ... ", 123] | semmle.order | 1 | +| middle-rest.ts:3:7:3:26 | [ArrayExpr] [true, "hello", 123] | middle-rest.ts:3:8:3:11 | [Literal] true | semmle.label | 1 | +| middle-rest.ts:3:7:3:26 | [ArrayExpr] [true, "hello", 123] | middle-rest.ts:3:8:3:11 | [Literal] true | semmle.order | 1 | +| middle-rest.ts:3:7:3:26 | [ArrayExpr] [true, "hello", 123] | middle-rest.ts:3:14:3:20 | [Literal] "hello" | semmle.label | 2 | +| middle-rest.ts:3:7:3:26 | [ArrayExpr] [true, "hello", 123] | middle-rest.ts:3:14:3:20 | [Literal] "hello" | semmle.order | 2 | +| middle-rest.ts:3:7:3:26 | [ArrayExpr] [true, "hello", 123] | middle-rest.ts:3:23:3:25 | [Literal] 123 | semmle.label | 3 | +| middle-rest.ts:3:7:3:26 | [ArrayExpr] [true, "hello", 123] | middle-rest.ts:3:23:3:25 | [Literal] 123 | semmle.order | 3 | | tst.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | tst.ts:1:8:1:17 | [ImportSpecifier] * as dummy | semmle.label | 1 | | tst.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | tst.ts:1:8:1:17 | [ImportSpecifier] * as dummy | semmle.order | 1 | | tst.ts:1:1:1:33 | [ImportDeclaration] import ... dummy"; | tst.ts:1:24:1:32 | [Literal] "./dummy" | semmle.label | 2 | @@ -1021,6 +1128,100 @@ edges | tst.ts:49:11:49:24 | [VariableDeclarator] b : string = e | tst.ts:49:15:49:20 | [KeywordTypeExpr] string | semmle.order | 2 | | tst.ts:49:11:49:24 | [VariableDeclarator] b : string = e | tst.ts:49:24:49:24 | [VarRef] e | semmle.label | 3 | | tst.ts:49:11:49:24 | [VariableDeclarator] b : string = e | tst.ts:49:24:49:24 | [VarRef] e | semmle.order | 3 | +| tst.ts:54:1:56:1 | [InterfaceDeclaration,TypeDefinition] interfa ... mber; } | tst.ts:54:11:54:26 | [Identifier] NonAbstractDummy | semmle.label | 1 | +| tst.ts:54:1:56:1 | [InterfaceDeclaration,TypeDefinition] interfa ... mber; } | tst.ts:54:11:54:26 | [Identifier] NonAbstractDummy | semmle.order | 1 | +| tst.ts:54:1:56:1 | [InterfaceDeclaration,TypeDefinition] interfa ... mber; } | tst.ts:55:3:55:20 | [MethodSignature] getArea(): number; | semmle.label | 2 | +| tst.ts:54:1:56:1 | [InterfaceDeclaration,TypeDefinition] interfa ... mber; } | tst.ts:55:3:55:20 | [MethodSignature] getArea(): number; | semmle.order | 2 | +| tst.ts:55:3:55:20 | [FunctionExpr] getArea(): number; | tst.ts:55:14:55:19 | [KeywordTypeExpr] number | semmle.label | 4 | +| tst.ts:55:3:55:20 | [FunctionExpr] getArea(): number; | tst.ts:55:14:55:19 | [KeywordTypeExpr] number | semmle.order | 4 | +| tst.ts:55:3:55:20 | [MethodSignature] getArea(): number; | tst.ts:55:3:55:9 | [Label] getArea | semmle.label | 1 | +| tst.ts:55:3:55:20 | [MethodSignature] getArea(): number; | tst.ts:55:3:55:9 | [Label] getArea | semmle.order | 1 | +| tst.ts:55:3:55:20 | [MethodSignature] getArea(): number; | tst.ts:55:3:55:20 | [FunctionExpr] getArea(): number; | semmle.label | 2 | +| tst.ts:55:3:55:20 | [MethodSignature] getArea(): number; | tst.ts:55:3:55:20 | [FunctionExpr] getArea(): number; | semmle.order | 2 | +| tst.ts:58:1:60:1 | [InterfaceDeclaration,TypeDefinition] interfa ... mber; } | tst.ts:58:11:58:17 | [Identifier] HasArea | semmle.label | 1 | +| tst.ts:58:1:60:1 | [InterfaceDeclaration,TypeDefinition] interfa ... mber; } | tst.ts:58:11:58:17 | [Identifier] HasArea | semmle.order | 1 | +| tst.ts:58:1:60:1 | [InterfaceDeclaration,TypeDefinition] interfa ... mber; } | tst.ts:59:3:59:20 | [MethodSignature] getArea(): number; | semmle.label | 2 | +| tst.ts:58:1:60:1 | [InterfaceDeclaration,TypeDefinition] interfa ... mber; } | tst.ts:59:3:59:20 | [MethodSignature] getArea(): number; | semmle.order | 2 | +| tst.ts:59:3:59:20 | [FunctionExpr] getArea(): number; | tst.ts:59:14:59:19 | [KeywordTypeExpr] number | semmle.label | 4 | +| tst.ts:59:3:59:20 | [FunctionExpr] getArea(): number; | tst.ts:59:14:59:19 | [KeywordTypeExpr] number | semmle.order | 4 | +| tst.ts:59:3:59:20 | [MethodSignature] getArea(): number; | tst.ts:59:3:59:9 | [Label] getArea | semmle.label | 1 | +| tst.ts:59:3:59:20 | [MethodSignature] getArea(): number; | tst.ts:59:3:59:9 | [Label] getArea | semmle.order | 1 | +| tst.ts:59:3:59:20 | [MethodSignature] getArea(): number; | tst.ts:59:3:59:20 | [FunctionExpr] getArea(): number; | semmle.label | 2 | +| tst.ts:59:3:59:20 | [MethodSignature] getArea(): number; | tst.ts:59:3:59:20 | [FunctionExpr] getArea(): number; | semmle.order | 2 | +| tst.ts:63:1:63:45 | [DeclStmt] let Ctor = ... | tst.ts:63:5:63:44 | [VariableDeclarator] Ctor: a ... = Shape | semmle.label | 1 | +| tst.ts:63:1:63:45 | [DeclStmt] let Ctor = ... | tst.ts:63:5:63:44 | [VariableDeclarator] Ctor: a ... = Shape | semmle.order | 1 | +| tst.ts:63:5:63:44 | [VariableDeclarator] Ctor: a ... = Shape | tst.ts:63:5:63:8 | [VarDecl] Ctor | semmle.label | 1 | +| tst.ts:63:5:63:44 | [VariableDeclarator] Ctor: a ... = Shape | tst.ts:63:5:63:8 | [VarDecl] Ctor | semmle.order | 1 | +| tst.ts:63:5:63:44 | [VariableDeclarator] Ctor: a ... = Shape | tst.ts:63:11:63:36 | [FunctionTypeExpr] abstrac ... HasArea | semmle.label | 2 | +| tst.ts:63:5:63:44 | [VariableDeclarator] Ctor: a ... = Shape | tst.ts:63:11:63:36 | [FunctionTypeExpr] abstrac ... HasArea | semmle.order | 2 | +| tst.ts:63:5:63:44 | [VariableDeclarator] Ctor: a ... = Shape | tst.ts:63:40:63:44 | [VarRef] Shape | semmle.label | 3 | +| tst.ts:63:5:63:44 | [VariableDeclarator] Ctor: a ... = Shape | tst.ts:63:40:63:44 | [VarRef] Shape | semmle.order | 3 | +| tst.ts:63:11:63:36 | [FunctionExpr] abstrac ... HasArea | tst.ts:63:30:63:36 | [LocalTypeAccess] HasArea | semmle.label | 4 | +| tst.ts:63:11:63:36 | [FunctionExpr] abstrac ... HasArea | tst.ts:63:30:63:36 | [LocalTypeAccess] HasArea | semmle.order | 4 | +| tst.ts:63:11:63:36 | [FunctionTypeExpr] abstrac ... HasArea | tst.ts:63:11:63:36 | [FunctionExpr] abstrac ... HasArea | semmle.label | 1 | +| tst.ts:63:11:63:36 | [FunctionTypeExpr] abstrac ... HasArea | tst.ts:63:11:63:36 | [FunctionExpr] abstrac ... HasArea | semmle.order | 1 | +| tst.ts:65:1:65:54 | [TypeAliasDeclaration,TypeDefinition] type My ... true}; | tst.ts:65:6:65:12 | [Identifier] MyUnion | semmle.label | 1 | +| tst.ts:65:1:65:54 | [TypeAliasDeclaration,TypeDefinition] type My ... true}; | tst.ts:65:6:65:12 | [Identifier] MyUnion | semmle.order | 1 | +| tst.ts:65:1:65:54 | [TypeAliasDeclaration,TypeDefinition] type My ... true}; | tst.ts:65:16:65:53 | [UnionTypeExpr] {myUnio ... : true} | semmle.label | 2 | +| tst.ts:65:1:65:54 | [TypeAliasDeclaration,TypeDefinition] type My ... true}; | tst.ts:65:16:65:53 | [UnionTypeExpr] {myUnio ... : true} | semmle.order | 2 | +| tst.ts:65:16:65:30 | [InterfaceTypeExpr] {myUnion: true} | tst.ts:65:17:65:29 | [FieldDeclaration] myUnion: true | semmle.label | 1 | +| tst.ts:65:16:65:30 | [InterfaceTypeExpr] {myUnion: true} | tst.ts:65:17:65:29 | [FieldDeclaration] myUnion: true | semmle.order | 1 | +| tst.ts:65:16:65:53 | [UnionTypeExpr] {myUnio ... : true} | tst.ts:65:16:65:30 | [InterfaceTypeExpr] {myUnion: true} | semmle.label | 1 | +| tst.ts:65:16:65:53 | [UnionTypeExpr] {myUnio ... : true} | tst.ts:65:16:65:30 | [InterfaceTypeExpr] {myUnion: true} | semmle.order | 1 | +| tst.ts:65:16:65:53 | [UnionTypeExpr] {myUnio ... : true} | tst.ts:65:34:65:53 | [InterfaceTypeExpr] {stillMyUnion: true} | semmle.label | 2 | +| tst.ts:65:16:65:53 | [UnionTypeExpr] {myUnio ... : true} | tst.ts:65:34:65:53 | [InterfaceTypeExpr] {stillMyUnion: true} | semmle.order | 2 | +| tst.ts:65:17:65:29 | [FieldDeclaration] myUnion: true | tst.ts:65:17:65:23 | [Label] myUnion | semmle.label | 1 | +| tst.ts:65:17:65:29 | [FieldDeclaration] myUnion: true | tst.ts:65:17:65:23 | [Label] myUnion | semmle.order | 1 | +| tst.ts:65:17:65:29 | [FieldDeclaration] myUnion: true | tst.ts:65:26:65:29 | [LiteralTypeExpr] true | semmle.label | 2 | +| tst.ts:65:17:65:29 | [FieldDeclaration] myUnion: true | tst.ts:65:26:65:29 | [LiteralTypeExpr] true | semmle.order | 2 | +| tst.ts:65:34:65:53 | [InterfaceTypeExpr] {stillMyUnion: true} | tst.ts:65:35:65:52 | [FieldDeclaration] stillMyUnion: true | semmle.label | 1 | +| tst.ts:65:34:65:53 | [InterfaceTypeExpr] {stillMyUnion: true} | tst.ts:65:35:65:52 | [FieldDeclaration] stillMyUnion: true | semmle.order | 1 | +| tst.ts:65:35:65:52 | [FieldDeclaration] stillMyUnion: true | tst.ts:65:35:65:46 | [Label] stillMyUnion | semmle.label | 1 | +| tst.ts:65:35:65:52 | [FieldDeclaration] stillMyUnion: true | tst.ts:65:35:65:46 | [Label] stillMyUnion | semmle.order | 1 | +| tst.ts:65:35:65:52 | [FieldDeclaration] stillMyUnion: true | tst.ts:65:49:65:52 | [LiteralTypeExpr] true | semmle.label | 2 | +| tst.ts:65:35:65:52 | [FieldDeclaration] stillMyUnion: true | tst.ts:65:49:65:52 | [LiteralTypeExpr] true | semmle.order | 2 | +| tst.ts:66:1:66:38 | [DeclStmt] let union1 = ... | tst.ts:66:5:66:37 | [VariableDeclarator] union1: ... : true} | semmle.label | 1 | +| tst.ts:66:1:66:38 | [DeclStmt] let union1 = ... | tst.ts:66:5:66:37 | [VariableDeclarator] union1: ... : true} | semmle.order | 1 | +| tst.ts:66:5:66:37 | [VariableDeclarator] union1: ... : true} | tst.ts:66:5:66:10 | [VarDecl] union1 | semmle.label | 1 | +| tst.ts:66:5:66:37 | [VariableDeclarator] union1: ... : true} | tst.ts:66:5:66:10 | [VarDecl] union1 | semmle.order | 1 | +| tst.ts:66:5:66:37 | [VariableDeclarator] union1: ... : true} | tst.ts:66:13:66:19 | [LocalTypeAccess] MyUnion | semmle.label | 2 | +| tst.ts:66:5:66:37 | [VariableDeclarator] union1: ... : true} | tst.ts:66:13:66:19 | [LocalTypeAccess] MyUnion | semmle.order | 2 | +| tst.ts:66:5:66:37 | [VariableDeclarator] union1: ... : true} | tst.ts:66:23:66:37 | [ObjectExpr] {myUnion: ...} | semmle.label | 3 | +| tst.ts:66:5:66:37 | [VariableDeclarator] union1: ... : true} | tst.ts:66:23:66:37 | [ObjectExpr] {myUnion: ...} | semmle.order | 3 | +| tst.ts:66:23:66:37 | [ObjectExpr] {myUnion: ...} | tst.ts:66:24:66:36 | [Property] myUnion: true | semmle.label | 1 | +| tst.ts:66:23:66:37 | [ObjectExpr] {myUnion: ...} | tst.ts:66:24:66:36 | [Property] myUnion: true | semmle.order | 1 | +| tst.ts:66:24:66:36 | [Property] myUnion: true | tst.ts:66:24:66:30 | [Label] myUnion | semmle.label | 1 | +| tst.ts:66:24:66:36 | [Property] myUnion: true | tst.ts:66:24:66:30 | [Label] myUnion | semmle.order | 1 | +| tst.ts:66:24:66:36 | [Property] myUnion: true | tst.ts:66:33:66:36 | [Literal] true | semmle.label | 2 | +| tst.ts:66:24:66:36 | [Property] myUnion: true | tst.ts:66:33:66:36 | [Literal] true | semmle.order | 2 | +| tst.ts:68:1:68:49 | [TypeAliasDeclaration,TypeDefinition] type My ... true}; | tst.ts:68:6:68:13 | [Identifier] MyUnion2 | semmle.label | 1 | +| tst.ts:68:1:68:49 | [TypeAliasDeclaration,TypeDefinition] type My ... true}; | tst.ts:68:6:68:13 | [Identifier] MyUnion2 | semmle.order | 1 | +| tst.ts:68:1:68:49 | [TypeAliasDeclaration,TypeDefinition] type My ... true}; | tst.ts:68:17:68:48 | [UnionTypeExpr] MyUnion ... : true} | semmle.label | 2 | +| tst.ts:68:1:68:49 | [TypeAliasDeclaration,TypeDefinition] type My ... true}; | tst.ts:68:17:68:48 | [UnionTypeExpr] MyUnion ... : true} | semmle.order | 2 | +| tst.ts:68:17:68:48 | [UnionTypeExpr] MyUnion ... : true} | tst.ts:68:17:68:23 | [LocalTypeAccess] MyUnion | semmle.label | 1 | +| tst.ts:68:17:68:48 | [UnionTypeExpr] MyUnion ... : true} | tst.ts:68:17:68:23 | [LocalTypeAccess] MyUnion | semmle.order | 1 | +| tst.ts:68:17:68:48 | [UnionTypeExpr] MyUnion ... : true} | tst.ts:68:27:68:48 | [InterfaceTypeExpr] {yetAno ... : true} | semmle.label | 2 | +| tst.ts:68:17:68:48 | [UnionTypeExpr] MyUnion ... : true} | tst.ts:68:27:68:48 | [InterfaceTypeExpr] {yetAno ... : true} | semmle.order | 2 | +| tst.ts:68:27:68:48 | [InterfaceTypeExpr] {yetAno ... : true} | tst.ts:68:28:68:47 | [FieldDeclaration] yetAnotherType: true | semmle.label | 1 | +| tst.ts:68:27:68:48 | [InterfaceTypeExpr] {yetAno ... : true} | tst.ts:68:28:68:47 | [FieldDeclaration] yetAnotherType: true | semmle.order | 1 | +| tst.ts:68:28:68:47 | [FieldDeclaration] yetAnotherType: true | tst.ts:68:28:68:41 | [Label] yetAnotherType | semmle.label | 1 | +| tst.ts:68:28:68:47 | [FieldDeclaration] yetAnotherType: true | tst.ts:68:28:68:41 | [Label] yetAnotherType | semmle.order | 1 | +| tst.ts:68:28:68:47 | [FieldDeclaration] yetAnotherType: true | tst.ts:68:44:68:47 | [LiteralTypeExpr] true | semmle.label | 2 | +| tst.ts:68:28:68:47 | [FieldDeclaration] yetAnotherType: true | tst.ts:68:44:68:47 | [LiteralTypeExpr] true | semmle.order | 2 | +| tst.ts:69:1:69:46 | [DeclStmt] let union2 = ... | tst.ts:69:5:69:45 | [VariableDeclarator] union2: ... : true} | semmle.label | 1 | +| tst.ts:69:1:69:46 | [DeclStmt] let union2 = ... | tst.ts:69:5:69:45 | [VariableDeclarator] union2: ... : true} | semmle.order | 1 | +| tst.ts:69:5:69:45 | [VariableDeclarator] union2: ... : true} | tst.ts:69:5:69:10 | [VarDecl] union2 | semmle.label | 1 | +| tst.ts:69:5:69:45 | [VariableDeclarator] union2: ... : true} | tst.ts:69:5:69:10 | [VarDecl] union2 | semmle.order | 1 | +| tst.ts:69:5:69:45 | [VariableDeclarator] union2: ... : true} | tst.ts:69:13:69:20 | [LocalTypeAccess] MyUnion2 | semmle.label | 2 | +| tst.ts:69:5:69:45 | [VariableDeclarator] union2: ... : true} | tst.ts:69:13:69:20 | [LocalTypeAccess] MyUnion2 | semmle.order | 2 | +| tst.ts:69:5:69:45 | [VariableDeclarator] union2: ... : true} | tst.ts:69:24:69:45 | [ObjectExpr] {yetAnotherType: ...} | semmle.label | 3 | +| tst.ts:69:5:69:45 | [VariableDeclarator] union2: ... : true} | tst.ts:69:24:69:45 | [ObjectExpr] {yetAnotherType: ...} | semmle.order | 3 | +| tst.ts:69:24:69:45 | [ObjectExpr] {yetAnotherType: ...} | tst.ts:69:25:69:44 | [Property] yetAnotherType: true | semmle.label | 1 | +| tst.ts:69:24:69:45 | [ObjectExpr] {yetAnotherType: ...} | tst.ts:69:25:69:44 | [Property] yetAnotherType: true | semmle.order | 1 | +| tst.ts:69:25:69:44 | [Property] yetAnotherType: true | tst.ts:69:25:69:38 | [Label] yetAnotherType | semmle.label | 1 | +| tst.ts:69:25:69:44 | [Property] yetAnotherType: true | tst.ts:69:25:69:38 | [Label] yetAnotherType | semmle.order | 1 | +| tst.ts:69:25:69:44 | [Property] yetAnotherType: true | tst.ts:69:41:69:44 | [Literal] true | semmle.label | 2 | +| tst.ts:69:25:69:44 | [Property] yetAnotherType: true | tst.ts:69:41:69:44 | [Literal] true | semmle.order | 2 | | type_alias.ts:1:1:1:17 | [TypeAliasDeclaration,TypeDefinition] type B = boolean; | type_alias.ts:1:6:1:6 | [Identifier] B | semmle.label | 1 | | type_alias.ts:1:1:1:17 | [TypeAliasDeclaration,TypeDefinition] type B = boolean; | type_alias.ts:1:6:1:6 | [Identifier] B | semmle.order | 1 | | type_alias.ts:1:1:1:17 | [TypeAliasDeclaration,TypeDefinition] type B = boolean; | type_alias.ts:1:10:1:16 | [KeywordTypeExpr] boolean | semmle.label | 2 | From 055275b971360db54e7088cc47d1e3de09edb68f Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 24 Feb 2021 11:12:31 +0100 Subject: [PATCH 040/142] change stats file --- .../ql/src/semmlecode.javascript.dbscheme.stats | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/javascript/ql/src/semmlecode.javascript.dbscheme.stats b/javascript/ql/src/semmlecode.javascript.dbscheme.stats index f5520c0a9e2..f65c0fe46b9 100644 --- a/javascript/ql/src/semmlecode.javascript.dbscheme.stats +++ b/javascript/ql/src/semmlecode.javascript.dbscheme.stats @@ -14480,6 +14480,17 @@ +is_abstract_signature +12 + + +sig +12 + + + + + signature_rest_parameter 19521 @@ -15898,6 +15909,10 @@ typ 100 + +index +100 + From 8c19f7810db88fa0bc9dba73321f5410528f2226 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 24 Feb 2021 17:59:38 +0100 Subject: [PATCH 041/142] replace forex with unique in DOM.qll --- javascript/ql/src/semmle/javascript/DOM.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/DOM.qll b/javascript/ql/src/semmle/javascript/DOM.qll index 5b1b9c30542..bc61174695c 100644 --- a/javascript/ql/src/semmle/javascript/DOM.qll +++ b/javascript/ql/src/semmle/javascript/DOM.qll @@ -344,7 +344,7 @@ module DOM { or exists(JQuery::MethodCall call | this = call and call.getMethodName() = "get" | call.getNumArgument() = 1 and - forex(InferredType t | t = call.getArgument(0).analyze().getAType() | t = TTNumber()) + unique(InferredType t | t = call.getArgument(0).analyze().getAType()) = TTNumber() ) or // A `this` node from a callback given to a `$().each(callback)` call. From caa6f002925c6767964c60e3996b423684525c57 Mon Sep 17 00:00:00 2001 From: Joe Farebrother Date: Wed, 24 Feb 2021 16:59:12 +0000 Subject: [PATCH 042/142] Switch to CSV based modelling --- .../code/java/dataflow/ExternalFlow.qll | 8 + .../semmle/code/java/dataflow/FlowSources.qll | 8 - .../semmle/code/java/dataflow/FlowSteps.qll | 2 +- .../code/java/frameworks/ApacheHttp.qll | 360 ++++++++---------- java/ql/src/semmle/code/java/security/XSS.qll | 6 +- 5 files changed, 168 insertions(+), 216 deletions(-) diff --git a/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll b/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll index 0df58641ad6..3f97a6e59db 100644 --- a/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll +++ b/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll @@ -64,6 +64,14 @@ import java private import semmle.code.java.dataflow.DataFlow::DataFlow private import internal.DataFlowPrivate +/** + * A module importing the frameworks that provide external flow data, + * ensuring that they are visible to the taint tracking / data flow library. + */ +private module Frameworks { + private import semmle.code.java.frameworks.ApacheHttp +} + private predicate sourceModelCsv(string row) { row = [ diff --git a/java/ql/src/semmle/code/java/dataflow/FlowSources.qll b/java/ql/src/semmle/code/java/dataflow/FlowSources.qll index 7ea6278e489..b4235cb2635 100644 --- a/java/ql/src/semmle/code/java/dataflow/FlowSources.qll +++ b/java/ql/src/semmle/code/java/dataflow/FlowSources.qll @@ -163,14 +163,6 @@ private class GuiceRequestParameterSource extends RemoteFlowSource { override string getSourceType() { result = "Guice request parameter" } } -private class ApacheHttpRequestParameterSource extends RemoteFlowSource { - ApacheHttpRequestParameterSource() { - this.asParameter() instanceof ApacheHttpRequestHandlerParameter - } - - override string getSourceType() { result = "Apache HTTP request parameter" } -} - private class Struts2ActionSupportClassFieldReadSource extends RemoteFlowSource { Struts2ActionSupportClassFieldReadSource() { exists(Struts2ActionSupportClass c | diff --git a/java/ql/src/semmle/code/java/dataflow/FlowSteps.qll b/java/ql/src/semmle/code/java/dataflow/FlowSteps.qll index d10ee9fc832..39de26ae014 100644 --- a/java/ql/src/semmle/code/java/dataflow/FlowSteps.qll +++ b/java/ql/src/semmle/code/java/dataflow/FlowSteps.qll @@ -9,7 +9,7 @@ private import semmle.code.java.dataflow.DataFlow * A module importing the frameworks that implement additional flow steps, * ensuring that they are visible to the taint tracking library. */ -module Frameworks { +private module Frameworks { private import semmle.code.java.frameworks.jackson.JacksonSerializability private import semmle.code.java.frameworks.android.Intent private import semmle.code.java.frameworks.android.SQLite diff --git a/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll b/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll index c882c69c31c..2dc1077cb4e 100644 --- a/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll +++ b/java/ql/src/semmle/code/java/frameworks/ApacheHttp.qll @@ -4,6 +4,7 @@ import java private import semmle.code.java.dataflow.FlowSteps +private import semmle.code.java.dataflow.ExternalFlow class ApacheHttpGetParams extends Method { ApacheHttpGetParams() { @@ -41,18 +42,14 @@ class TypeApacheHttpRequestBuilder extends Class { } } -/** - * The `request` parameter of an implementation of `HttpRequestHandler.handle`. - */ -class ApacheHttpRequestHandlerParameter extends Parameter { - ApacheHttpRequestHandlerParameter() { - exists(Method m, Interface i | - i.hasQualifiedName(["org.apache.http.protocol", "org.apache.hc.core5.http.io"], - ["HttpRequestHandler", "HttpServerRequestHandler"]) and - m.getDeclaringType().extendsOrImplements+(i) and - m.hasName("handle") and - this = m.getParameter(0) - ) +private class ApacheHttpSource extends SourceModelCsv { + override predicate row(string row) { + row = + [ + "org.apache.http.protocol;HttpRequestHandler;true;handle;(HttpRequest,HttpResponse,HttpContext);;Parameter[0];remote", + "org.apache.hc.core5.http.io;HttpRequestHandler;true;handle;(ClassicHttpRequest,ClassicHttpResponse,HttpContext);;Parameter[0];remote", + "org.apache.hc.core5.http.io;HttpServerRequestHandler;true;handle;(ClassicHttpRequest,ResponseTrigger,HttpContext);;Parameter[0];remote" + ] } } @@ -84,197 +81,152 @@ class ApacheHttpSetHeader extends Call { Expr getValue() { result = this.getArgument(1) } } -/** - * A call that sets the entity of an instance of `org.apache.http.HttpResponse` / `org.apache.hc.core5.http.ClassicHttpResponse`. - */ -class ApacheHttpResponseSetEntityCall extends MethodAccess { - int arg; - - ApacheHttpResponseSetEntityCall() { - exists(Method m | this.getMethod().overrides*(m) | - m.getDeclaringType().hasQualifiedName("org.apache.http", "HttpResponse") and - m.hasName("setEntity") and - arg = 0 - or - m.getDeclaringType().hasQualifiedName("org.apache.http.util", "EntityUtils") and - m.hasName("updateEntity") and - arg = 1 - or - m.getDeclaringType().hasQualifiedName("org.apache.hc.core5.http", "HttpEntityContainer") and - m.hasName("setEntity") and - arg = 0 - ) - } - - /** - * Gets the entity that is set by this call. - */ - Expr getEntity() { result = this.getArgument(arg) } -} - -/** A getter that returns tainted data when its qualifier is tainted. */ -private class ApacheHttpGetter extends TaintPreservingCallable { - ApacheHttpGetter() { - exists(string pkg, string ty, string mtd, Method m | - this.(Method).overrides*(m) and - m.getDeclaringType().getSourceDeclaration().hasQualifiedName(pkg, ty) and - m.hasName(mtd) - | - pkg = "org.apache.http" and - ( - ty = "HttpMessage" and - mtd = - [ - "getAllHeaders", "getFirstHeader", "getHeaders", "getLastHeader", "getParams", - "headerIterator" - ] - or - ty = "HttpRequest" and - mtd = "getRequestLine" - or - ty = "HttpEntityEnclosingRequest" and - mtd = "getEntity" - or - ty = "Header" and - mtd = "getElements" - or - ty = "HeaderElement" and - mtd = ["getName", "getParameter", "getParameterByName", "getParameters", "getValue"] - or - ty = "NameValuePair" and - mtd = ["getName", "getValue"] - or - ty = "HeaderIterator" and - mtd = "nextHeader" - or - ty = "HttpEntity" and - mtd = ["getContent", "getContentEncoding", "getContentType"] - or - ty = "RequestLine" and - mtd = ["getMethod", "getUri"] - ) - or - pkg = "org.apache.http.params" and - ty = "HttpParams" and - mtd.matches("get%Parameter") - or - pkg = "org.apache.hc.core5.http" and - ( - ty = "MessageHeaders" and - mtd = ["getFirstHeader", "getHeader", "getHeaders", "getLastHeader", "headerIterator"] - or - ty = "HttpRequest" and - mtd = ["getAuthority", "getMethod", "getPath", "getRequestUri", "getUri"] - or - ty = "HttpEntityContainer" and - mtd = "getEntity" - or - ty = "NameValuePair" and - mtd = ["getName", "getValue"] - or - ty = "HttpEntity" and - mtd = ["getContent", "getTrailers"] - or - ty = "EntityDetails" and - mtd = ["getContentType", "getContentEncoding", "getTrailerNames"] - ) - or - pkg = "org.apache.hc.core5.http.message" and - ty = "RequestLine" and - mtd = ["getMethod", "getUri", "toString"] - or - pkg = "org.apache.hc.core5.function" and - ty = "Supplier" and - mtd = "get" - or - pkg = "org.apache.hc.core5.net" and - ty = "URIAuthority" and - mtd = ["getHostName", "toString"] - ) - } - - override predicate returnsTaintFrom(int arg) { arg = -1 } -} - -private class UtilMethod extends TaintPreservingCallable { - UtilMethod() { - exists(string pkg, string ty, string mtd | - this.isStatic() and - this.getDeclaringType().hasQualifiedName(pkg, ty) and - this.hasName(mtd) - | - pkg = ["org.apache.http.util", "org.apache.hc.core5.http.io.entity"] and - ty = "EntityUtils" and - mtd = ["toString", "toByteArray", "getContentCharSet", "getContentMimeType", "parse"] - or - pkg = ["org.apache.http.util", "org.apache.hc.core5.util"] and - ty = "EncodingUtils" and - mtd = ["getAsciiBytes", "getAsciiString", "getBytes", "getString"] - or - pkg = ["org.apache.http.util", "org.apache.hc.core5.util"] and - ty = "Args" and - mtd = ["containsNoBlanks", "notBlank", "notEmpty", "notNull"] - or - pkg = "org.apache.hc.core5.http.io.entity" and - ty = "HttpEntities" and - mtd = ["create", "createGziped", "createUrlEncoded", "gzip", "withTrailers"] - ) - } - - override predicate returnsTaintFrom(int arg) { arg = 0 } -} - -private class EntitySetter extends TaintPreservingCallable { - EntitySetter() { - this.getDeclaringType() - .getASourceSupertype*() - .hasQualifiedName("org.apache.http.entity", "BasicHttpEntity") and - this.hasName("setContent") - } - - override predicate transfersTaint(int src, int sink) { src = 0 and sink = -1 } -} - -private class EntityConstructor extends TaintPreservingCallable, Constructor { - EntityConstructor() { - this.getDeclaringType() - .hasQualifiedName(["org.apache.http.entity", "org.apache.hc.core5.http.io.entity"], - [ - "BasicHttpEntity", "BufferedHttpEntity", "ByteArrayEntity", "HttpEntityWrapper", - "InputStreamEntity", "StringEntity" - ]) - } - - override predicate returnsTaintFrom(int arg) { arg = 0 } -} - -private class RequestLineConstructor extends TaintPreservingCallable, Constructor { - RequestLineConstructor() { - this.getDeclaringType().hasQualifiedName("org.apache.hc.core5.http.message", "RequestLine") - } - - override predicate returnsTaintFrom(int arg) { arg = [0, 1] } -} - -private class BufferMethod extends TaintPreservingCallable { - BufferMethod() { - exists(Method m | - this.(Method).overrides*(m) and - m.getDeclaringType() - .hasQualifiedName(["org.apache.http.util", "org.apache.hc.core5.util"], - ["ByteArrayBuffer", "CharArrayBuffer"]) and - m.hasName([ - "append", "array", "buffer", "subSequence", "substring", "substringTrimmed", - "toByteArray", "toCharArray", "toString" - ]) - ) - } - - override predicate returnsTaintFrom(int arg) { arg = -1 } - - override predicate transfersTaint(int src, int sink) { - this.hasName("append") and - src = 0 and - sink = -1 +private class ApacheHttpXssSink extends SinkModelCsv { + override predicate row(string row) { + row = + [ + "org.apache.http;HttpResponse;true;setEntity;(HttpEntity);;Argument[0];xss", + "org.apache.http.util;EntityUtils;true;updateEntity;(HttpResponse,HttpEntity);;Argument[1];xss", + "org.apache.hc.core5.http;HttpEntityContainer;true;setEntity;(HttpEntity);;Argument[0];xss" + ] + } +} + +private class ApacheHttpFlowStep extends SummaryModelCsv { + override predicate row(string row) { + row = + [ + "org.apache.http;HttpMessage;true;getAllHeaders;();;Argument[-1];ReturnValue;taint", + "org.apache.http;HttpMessage;true;getFirstHeader;(String);;Argument[-1];ReturnValue;taint", + "org.apache.http;HttpMessage;true;getLastHeader;(String);;Argument[-1];ReturnValue;taint", + "org.apache.http;HttpMessage;true;getHeaders;(String);;Argument[-1];ReturnValue;taint", + "org.apache.http;HttpMessage;true;getParams;();;Argument[-1];ReturnValue;taint", + "org.apache.http;HttpMessage;true;headerIterator;();;Argument[-1];ReturnValue;taint", + "org.apache.http;HttpMessage;true;headerIterator;(String);;Argument[-1];ReturnValue;taint", + "org.apache.http;HttpRequest;true;getRequestLine;();;Argument[-1];ReturnValue;taint", + "org.apache.http;HttpEntityEnclosingRequest;true;getEntity;();;Argument[-1];ReturnValue;taint", + "org.apache.http;Header;true;getElements;();;Argument[-1];ReturnValue;taint", + "org.apache.http;HeaderElement;true;getName;();;Argument[-1];ReturnValue;taint", + "org.apache.http;HeaderElement;true;getValue;();;Argument[-1];ReturnValue;taint", + "org.apache.http;HeaderElement;true;getParameter;(int);;Argument[-1];ReturnValue;taint", + "org.apache.http;HeaderElement;true;getParameterByName;(String);;Argument[-1];ReturnValue;taint", + "org.apache.http;HeaderElement;true;getParameters;();;Argument[-1];ReturnValue;taint", + "org.apache.http;NameValuePair;true;getName;();;Argument[-1];ReturnValue;taint", + "org.apache.http;NameValuePair;true;getValue;();;Argument[-1];ReturnValue;taint", + "org.apache.http;HeaderIterator;true;nextHeader;();;Argument[-1];ReturnValue;taint", + "org.apache.http;HttpEntity;true;getContent;();;Argument[-1];ReturnValue;taint", + "org.apache.http;HttpEntity;true;getContentEncoding;();;Argument[-1];ReturnValue;taint", + "org.apache.http;HttpEntity;true;getContentType;();;Argument[-1];ReturnValue;taint", + "org.apache.http;RequestLine;true;getMethod;();;Argument[-1];ReturnValue;taint", + "org.apache.http;RequestLine;true;getUri;();;Argument[-1];ReturnValue;taint", + "org.apache.http.params;HttpParams;true;getParameter;(String);;Argument[-1];ReturnValue;taint", + "org.apache.http.params;HttpParams;true;getDoubleParameter;(String,double);;Argument[-1];ReturnValue;taint", + "org.apache.http.params;HttpParams;true;getIntParameter;(String,int);;Argument[-1];ReturnValue;taint", + "org.apache.http.params;HttpParams;true;getLongParameter;(String,long);;Argument[-1];ReturnValue;taint", + "org.apache.http.params;HttpParams;true;getDoubleParameter;(String,double);;Argument[1];ReturnValue;value", + "org.apache.http.params;HttpParams;true;getIntParameter;(String,int);;Argument[1];ReturnValue;value", + "org.apache.http.params;HttpParams;true;getLongParameter;(String,long);;Argument[1];ReturnValue;value", + "org.apache.hc.core5.http;MessageHeaders;true;getFirstHeader;(String);;Argument[-1];ReturnValue;taint", + "org.apache.hc.core5.http;MessageHeaders;true;getLastHeader;(String);;Argument[-1];ReturnValue;taint", + "org.apache.hc.core5.http;MessageHeaders;true;getHeader;(String);;Argument[-1];ReturnValue;taint", + "org.apache.hc.core5.http;MessageHeaders;true;getHeaders;();;Argument[-1];ReturnValue;taint", + "org.apache.hc.core5.http;MessageHeaders;true;getHeaders;(String);;Argument[-1];ReturnValue;taint", + "org.apache.hc.core5.http;MessageHeaders;true;headerIterator;();;Argument[-1];ReturnValue;taint", + "org.apache.hc.core5.http;MessageHeaders;true;headerIterator;(String);;Argument[-1];ReturnValue;taint", + "org.apache.hc.core5.http;HttpRequest;true;getAuthority;();;Argument[-1];ReturnValue;taint", + "org.apache.hc.core5.http;HttpRequest;true;getMethod;();;Argument[-1];ReturnValue;taint", + "org.apache.hc.core5.http;HttpRequest;true;getPath;();;Argument[-1];ReturnValue;taint", + "org.apache.hc.core5.http;HttpRequest;true;getUri;();;Argument[-1];ReturnValue;taint", + "org.apache.hc.core5.http;HttpRequest;true;getRequestUri;();;Argument[-1];ReturnValue;taint", + "org.apache.hc.core5.http;HttpEntityContainer;true;getEntity;();;Argument[-1];ReturnValue;taint", + "org.apache.hc.core5.http;NameValuePair;true;getName;();;Argument[-1];ReturnValue;taint", + "org.apache.hc.core5.http;NameValuePair;true;getValue;();;Argument[-1];ReturnValue;taint", + "org.apache.hc.core5.http;HttpEntity;true;getContent;();;Argument[-1];ReturnValue;taint", + "org.apache.hc.core5.http;HttpEntity;true;getTrailers;();;Argument[-1];ReturnValue;taint", + "org.apache.hc.core5.http;EntityDetails;true;getContentType;();;Argument[-1];ReturnValue;taint", + "org.apache.hc.core5.http;EntityDetails;true;getContentEncoding;();;Argument[-1];ReturnValue;taint", + "org.apache.hc.core5.http;EntityDetails;true;getTrailerNames;();;Argument[-1];ReturnValue;taint", + "org.apache.hc.core5.http.message;RequestLine;true;getMethod;();;Argument[-1];ReturnValue;taint", + "org.apache.hc.core5.http.message;RequestLine;true;getUri;();;Argument[-1];ReturnValue;taint", + "org.apache.hc.core5.http.message;RequestLine;true;toString;();;Argument[-1];ReturnValue;taint", + "org.apache.hc.core5.http.message;RequestLine;true;RequestLine;(HttpRequest);;Argument[0];ReturnValue;taint", + "org.apache.hc.core5.http.message;RequestLine;true;RequestLine;(String,String,ProtocolVersion);;Argument[1];ReturnValue;taint", + "org.apache.hc.core5.http.message;RequestLine;true;RequestLine;(String,String,ProtocolVersion);;Argument[1];ReturnValue;taint", + "org.apache.hc.core5.function;Supplier;true;get;();;Argument[-1];ReturnValue;taint", + "org.apache.hc.core5.net;URIAuthority;true;getHostName;();;Argument[-1];ReturnValue;taint", + "org.apache.hc.core5.net;URIAuthority;true;toString;();;Argument[-1];ReturnValue;taint", + "org.apache.http.util;EntityUtils;true;toString;;;Argument[0];ReturnValue;taint", + "org.apache.http.util;EntityUtils;true;toByteArray;(HttpEntity);;Argument[0];ReturnValue;taint", + "org.apache.http.util;EntityUtils;true;getContentCharSet;(HttpEntity);;Argument[0];ReturnValue;taint", + "org.apache.http.util;EntityUtils;true;getContentMimeType;(HttpEntity);;Argument[0];ReturnValue;taint", + "org.apache.hc.core5.http.io.entity;EntityUtils;true;toString;;;Argument[0];ReturnValue;taint", + "org.apache.hc.core5.http.io.entity;EntityUtils;true;toByteArray;;;Argument[0];ReturnValue;taint", + "org.apache.hc.core5.http.io.entity;EntityUtils;true;parse;;;Argument[0];ReturnValue;taint", + "org.apache.http.util;EncodingUtils;true;getAsciiBytes;(String);;Argument[0];ReturnValue;taint", + "org.apache.http.util;EncodingUtils;true;getAsciiString;;;Argument[0];ReturnValue;taint", + "org.apache.http.util;EncodingUtils;true;getBytes;(String,String);;Argument[0];ReturnValue;taint", + "org.apache.http.util;EncodingUtils;true;getString;;;Argument[0];ReturnValue;taint", + "org.apache.http.util;Args;true;containsNoBlanks;(T,String);;Argument[0];ReturnValue;value", + "org.apache.http.util;Args;true;notNull;(T,String);;Argument[0];ReturnValue;value", + "org.apache.http.util;Args;true;notEmpty;(T,String);;Argument[0];ReturnValue;value", + "org.apache.http.util;Args;true;notBlank;(T,String);;Argument[0];ReturnValue;value", + "org.apache.hc.core5.util;Args;true;containsNoBlanks;(T,String);;Argument[0];ReturnValue;value", + "org.apache.hc.core5.util;Args;true;notNull;(T,String);;Argument[0];ReturnValue;value", + "org.apache.hc.core5.util;Args;true;notEmpty;(T,String);;Argument[0];ReturnValue;value", + "org.apache.hc.core5.util;Args;true;notBlank;(T,String);;Argument[0];ReturnValue;value", + "org.apache.hc.core5.http.io.entity;HttpEntities;true;create;;;Argument[0];ReturnValue;taint", + "org.apache.hc.core5.http.io.entity;HttpEntities;true;createGzipped;;;Argument[0];ReturnValue;taint", + "org.apache.hc.core5.http.io.entity;HttpEntities;true;createUrlEncoded;;;Argument[0];ReturnValue;taint", + "org.apache.hc.core5.http.io.entity;HttpEntities;true;gzip;(HttpEntity);;Argument[0];ReturnValue;taint", + "org.apache.hc.core5.http.io.entity;HttpEntities;true;withTrailers;;;Argument[0];ReturnValue;taint", + "org.apache.http.entity;BasicHttpEntity;true;setContent;(InputStream);;Argument[0];Argument[-1];taint", + "org.apache.http.entity;BufferedHttpEntity;true;BufferedHttpEntity;(HttpEntity);;Argument[0];ReturnValue;taint", + "org.apache.http.entity;ByteArrayEntity;true;ByteArrayEntity;;;Argument[0];ReturnValue;taint", + "org.apache.http.entity;HttpEntityWrapper;true;HttpEntityWrapper;(HttpEntity);;Argument[0];ReturnValue;taint", + "org.apache.http.entity;InputStreamEntity;true;InputStreamEntity;;;Argument[0];ReturnValue;taint", + "org.apache.http.entity;StringEntity;true;StringEntity;;;Argument[0];ReturnValue;taint", + "org.apache.hc.core5.http.io.entity;BasicHttpEntity;true;BasicHttpEntity;;;Argument[0];ReturnValue;taint", + "org.apache.hc.core5.http.io.entity;BufferedHttpEntity;true;BufferedHttpEntity;(HttpEntity);;Argument[0];ReturnValue;taint", + "org.apache.hc.core5.http.io.entity;ByteArrayEntity;true;ByteArrayEntity;;;Argument[0];ReturnValue;taint", + "org.apache.hc.core5.http.io.entity;HttpEntityWrapper;true;HttpEntityWrapper;(HttpEntity);;Argument[0];ReturnValue;taint", + "org.apache.hc.core5.http.io.entity;InputStreamEntity;true;InputStreamEntity;;;Argument[0];ReturnValue;taint", + "org.apache.hc.core5.http.io.entity;StringEntity;true;StringEntity;;;Argument[0];ReturnValue;taint", + "org.apache.http.util;ByteArrayBuffer;true;append;(byte[],int,int);;Argument[0];Argument[-1];taint", + "org.apache.http.util;ByteArrayBuffer;true;append;(char[],int,int);;Argument[0];Argument[-1];taint", + "org.apache.http.util;ByteArrayBuffer;true;append;(CharArrayBuffer,int,int);;Argument[0];Argument[-1];taint", + "org.apache.http.util;ByteArrayBuffer;true;buffer;();;Argument[-1];ReturnValue;taint", + "org.apache.http.util;ByteArrayBuffer;true;toByteArray;();;Argument[-1];ReturnValue;taint", + "org.apache.http.util;CharArrayBuffer;true;append;(byte[],int,int);;Argument[0];Argument[-1];taint", + "org.apache.http.util;CharArrayBuffer;true;append;(char[],int,int);;Argument[0];Argument[-1];taint", + "org.apache.http.util;CharArrayBuffer;true;append;(CharArrayBuffer,int,int);;Argument[0];Argument[-1];taint", + "org.apache.http.util;CharArrayBuffer;true;append;(ByteArrayBuffer,int,int);;Argument[0];Argument[-1];taint", + "org.apache.http.util;CharArrayBuffer;true;append;(CharArrayBuffer);;Argument[0];Argument[-1];taint", + "org.apache.http.util;CharArrayBuffer;true;append;(String);;Argument[0];Argument[-1];taint", + "org.apache.http.util;CharArrayBuffer;true;append;(Object);;Argument[0];Argument[-1];taint", + "org.apache.http.util;CharArrayBuffer;true;buffer;();;Argument[-1];ReturnValue;taint", + "org.apache.http.util;CharArrayBuffer;true;toCharArray;();;Argument[-1];ReturnValue;taint", + "org.apache.http.util;CharArrayBuffer;true;toString;();;Argument[-1];ReturnValue;taint", + "org.apache.http.util;CharArrayBuffer;true;substring;(int,int);;Argument[-1];ReturnValue;taint", + "org.apache.http.util;CharArrayBuffer;true;subSequence;(int,int);;Argument[-1];ReturnValue;taint", + "org.apache.http.util;CharArrayBuffer;true;substringTrimmed;(int,int);;Argument[-1];ReturnValue;taint", + "org.apache.hc.core5.util;ByteArrayBuffer;true;append;(byte[],int,int);;Argument[0];Argument[-1];taint", + "org.apache.hc.core5.util;ByteArrayBuffer;true;append;(char[],int,int);;Argument[0];Argument[-1];taint", + "org.apache.hc.core5.util;ByteArrayBuffer;true;append;(CharArrayBuffer,int,int);;Argument[0];Argument[-1];taint", + "org.apache.hc.core5.util;ByteArrayBuffer;true;array;();;Argument[-1];ReturnValue;taint", + "org.apache.hc.core5.util;ByteArrayBuffer;true;toByteArray;();;Argument[-1];ReturnValue;taint", + "org.apache.hc.core5.util;CharArrayBuffer;true;append;(byte[],int,int);;Argument[0];Argument[-1];taint", + "org.apache.hc.core5.util;CharArrayBuffer;true;append;(char[],int,int);;Argument[0];Argument[-1];taint", + "org.apache.hc.core5.util;CharArrayBuffer;true;append;(CharArrayBuffer,int,int);;Argument[0];Argument[-1];taint", + "org.apache.hc.core5.util;CharArrayBuffer;true;append;(ByteArrayBuffer,int,int);;Argument[0];Argument[-1];taint", + "org.apache.hc.core5.util;CharArrayBuffer;true;append;(CharArrayBuffer);;Argument[0];Argument[-1];taint", + "org.apache.hc.core5.util;CharArrayBuffer;true;append;(String);;Argument[0];Argument[-1];taint", + "org.apache.hc.core5.util;CharArrayBuffer;true;append;(Object);;Argument[0];Argument[-1];taint", + "org.apache.hc.core5.util;CharArrayBuffer;true;array;();;Argument[-1];ReturnValue;taint", + "org.apache.hc.core5.util;CharArrayBuffer;true;toCharArray;();;Argument[-1];ReturnValue;taint", + "org.apache.hc.core5.util;CharArrayBuffer;true;toString;();;Argument[-1];ReturnValue;taint", + "org.apache.hc.core5.util;CharArrayBuffer;true;substring;(int,int);;Argument[-1];ReturnValue;taint", + "org.apache.hc.core5.util;CharArrayBuffer;true;subSequence;(int,int);;Argument[-1];ReturnValue;taint", + "org.apache.hc.core5.util;CharArrayBuffer;true;substringTrimmed;(int,int);;Argument[-1];ReturnValue;taint" + ] } } diff --git a/java/ql/src/semmle/code/java/security/XSS.qll b/java/ql/src/semmle/code/java/security/XSS.qll index 986995cdfe1..f51bc0bbdf5 100644 --- a/java/ql/src/semmle/code/java/security/XSS.qll +++ b/java/ql/src/semmle/code/java/security/XSS.qll @@ -5,9 +5,9 @@ import semmle.code.java.frameworks.Servlets import semmle.code.java.frameworks.android.WebView import semmle.code.java.frameworks.spring.SpringController import semmle.code.java.frameworks.spring.SpringHttp -import semmle.code.java.frameworks.ApacheHttp import semmle.code.java.dataflow.DataFlow import semmle.code.java.dataflow.TaintTracking2 +import semmle.code.java.dataflow.ExternalFlow /** A sink that represent a method that outputs data without applying contextual output encoding. */ abstract class XssSink extends DataFlow::Node { } @@ -32,6 +32,8 @@ class XssAdditionalTaintStep extends Unit { /** A default sink representing methods susceptible to XSS attacks. */ private class DefaultXssSink extends XssSink { DefaultXssSink() { + sinkNode(this, "xss") + or exists(HttpServletResponseSendErrorMethod m, MethodAccess ma | ma.getMethod() = m and this.asExpr() = ma.getArgument(1) @@ -95,8 +97,6 @@ private class DefaultXssSink extends XssSink { returnType instanceof RawClass ) ) - or - this.asExpr() = any(ApacheHttpResponseSetEntityCall c).getEntity() } } From fd9d738d53544549b775389eb216fce369022140 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 24 Feb 2021 18:00:41 +0100 Subject: [PATCH 043/142] use Expr instead of mising DataFlow-nodes and Exprs in charpred --- .../semmle/javascript/MembershipCandidates.qll | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/MembershipCandidates.qll b/javascript/ql/src/semmle/javascript/MembershipCandidates.qll index 568651c3f1a..89573252ab5 100644 --- a/javascript/ql/src/semmle/javascript/MembershipCandidates.qll +++ b/javascript/ql/src/semmle/javascript/MembershipCandidates.qll @@ -222,27 +222,27 @@ module MembershipCandidate { */ class ObjectPropertyNameMembershipCandidate extends MembershipCandidate::Range, DataFlow::ValueNode { - DataFlow::ValueNode test; - DataFlow::ValueNode membersNode; + Expr test; + Expr membersNode; ObjectPropertyNameMembershipCandidate() { exists(InExpr inExpr | this = inExpr.getLeftOperand().flow() and - test = inExpr.flow() and - membersNode = inExpr.getRightOperand().flow() + test = inExpr and + membersNode = inExpr.getRightOperand() ) or - exists(DataFlow::MethodCallNode hasOwn | - this = hasOwn.getArgument(0) and + exists(MethodCallExpr hasOwn | + this = hasOwn.getArgument(0).flow() and test = hasOwn and hasOwn.calls(membersNode, "hasOwnProperty") ) } - override DataFlow::Node getTest() { result = test } + override DataFlow::Node getTest() { result = test.flow() } override string getAMemberString() { - exists(membersNode.getALocalSource().getAPropertyWrite(result)) + exists(membersNode.flow().getALocalSource().getAPropertyWrite(result)) } } From 8443b8e42194317ef814e405e89cc9e104621c11 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 24 Feb 2021 18:01:16 +0100 Subject: [PATCH 044/142] cache Module::getAnExportedValue --- javascript/ql/src/semmle/javascript/Modules.qll | 1 + 1 file changed, 1 insertion(+) diff --git a/javascript/ql/src/semmle/javascript/Modules.qll b/javascript/ql/src/semmle/javascript/Modules.qll index 068b3de8dca..038b4d56faf 100644 --- a/javascript/ql/src/semmle/javascript/Modules.qll +++ b/javascript/ql/src/semmle/javascript/Modules.qll @@ -107,6 +107,7 @@ abstract class Module extends TopLevel { * Symbols defined in another module that are re-exported by * this module are only sometimes considered. */ + cached abstract DataFlow::Node getAnExportedValue(string name); /** From 69348b191484cba36169e889477929e8655c6b8c Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 24 Feb 2021 18:01:35 +0100 Subject: [PATCH 045/142] remove redundant hasLocationInfo --- javascript/ql/src/semmle/javascript/SSA.qll | 8 -------- 1 file changed, 8 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/SSA.qll b/javascript/ql/src/semmle/javascript/SSA.qll index adf53803241..4c672fef1f7 100644 --- a/javascript/ql/src/semmle/javascript/SSA.qll +++ b/javascript/ql/src/semmle/javascript/SSA.qll @@ -660,14 +660,6 @@ class SsaPhiNode extends SsaPseudoDefinition, TPhi { override string prettyPrintDef() { result = getSourceVariable() + " = phi(" + ppInputs() + ")" } - override predicate hasLocationInfo( - string filepath, int startline, int startcolumn, int endline, int endcolumn - ) { - endline = startline and - endcolumn = startcolumn and - getBasicBlock().getLocation().hasLocationInfo(filepath, startline, startcolumn, _, _) - } - /** * If all inputs to this phi node are (transitive) refinements of the same variable, * gets that variable. From c44fbaaf3c593101ba143858faa3dc34299174a9 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 24 Feb 2021 15:59:31 +0100 Subject: [PATCH 046/142] C++: Promote memset query out of experimental. --- .../CWE/CWE-014/MemsetMayBeDeleted-bad.c | 4 + .../CWE/CWE-014/MemsetMayBeDeleted-good.c | 4 + .../CWE/CWE-014/MemsetMayBeDeleted.qhelp | 41 ++++++ .../CWE/CWE-014/MemsetMayBeDeleted.ql | 49 +++++++ .../CompilerRemovalOfCodeToClearBuffers.c | 35 ----- .../CompilerRemovalOfCodeToClearBuffers.qhelp | 31 ----- .../CompilerRemovalOfCodeToClearBuffers.ql | 127 ------------------ 7 files changed, 98 insertions(+), 193 deletions(-) create mode 100644 cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted-bad.c create mode 100644 cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted-good.c create mode 100644 cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.qhelp create mode 100644 cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.ql delete mode 100644 cpp/ql/src/experimental/Security/CWE/CWE-14/CompilerRemovalOfCodeToClearBuffers.c delete mode 100644 cpp/ql/src/experimental/Security/CWE/CWE-14/CompilerRemovalOfCodeToClearBuffers.qhelp delete mode 100644 cpp/ql/src/experimental/Security/CWE/CWE-14/CompilerRemovalOfCodeToClearBuffers.ql diff --git a/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted-bad.c b/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted-bad.c new file mode 100644 index 00000000000..514b23241c9 --- /dev/null +++ b/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted-bad.c @@ -0,0 +1,4 @@ +char * password = malloc(PASSWORD_SIZE); +// ... read and check password +memset(password, 0, PASSWORD_SIZE); +free(password); diff --git a/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted-good.c b/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted-good.c new file mode 100644 index 00000000000..3d6628bf060 --- /dev/null +++ b/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted-good.c @@ -0,0 +1,4 @@ +char * password = malloc(PASSWORD_SIZE); +// ... read and check password +memset_s(password, PASSWORD_SIZE, 0, PASSWORD_SIZE); +free(password); diff --git a/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.qhelp b/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.qhelp new file mode 100644 index 00000000000..9cd1fd14143 --- /dev/null +++ b/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.qhelp @@ -0,0 +1,41 @@ + + + +

Calling memset or bzero on a buffer to clear its contents may get optimized +away by the compiler if the buffer is not subsequently used. This is not desirable behavior if the buffer +contains sensitive data that could somehow be retrieved by an attacker.

+ +
+ + +

Use alternative platform-supplied functions that will not get optimized away. Examples of such +functions include memset_s, SecureZeroMemory, and bzero_explicit. +Alternatively, passing the -fno-builtin-memset option to the GCC/Clang compiler usually +also prevents the optimization. Finally, the public-domain secure_memzero function (see +below) can be used. This function, however, is not guaranteed to work on all platforms and compilers.

+ +
+ +

The following program fragment uses memset to erase sensitive information after it is no +longer needed:

+ +

Because of dead store elimination, the call to memset may be removed by the compiler +(since the buffer is not subsequently used), resulting in potentially sensitive data remaining in memory. +

+ +

The best solution to this problem is to use the memset_s function instead of +memset:

+ + +
+ + +
  • +CERT C Coding Standard: +MSC06-C. Beware of compiler optimizations. +
  • + +
    +
    diff --git a/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.ql b/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.ql new file mode 100644 index 00000000000..a0b3e816239 --- /dev/null +++ b/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.ql @@ -0,0 +1,49 @@ +/** + * @name Call to `memset` may be deleted + * @description Using memset the function to clear private data in a variable that has no subsequent use + * is potentially dangerous because the compiler can remove the call. + * @kind problem + * @id cpp/memset-may-be-deleted + * @problem.severity warning + * @precision high + * @tags security + * external/cwe/cwe-14 + */ + +import cpp +import semmle.code.cpp.dataflow.EscapesTree +import semmle.code.cpp.commons.Exclusions + +class MemsetFunction extends Function { + MemsetFunction() { + this.hasGlobalOrStdOrBslName("memset") + or + this.hasGlobalOrStdName("wmemset") + or + this.hasGlobalName(["bzero", "__builtin_memset"]) + } +} + +from FunctionCall call, LocalVariable v, MemsetFunction memset +where + call.getTarget() = memset and + not isFromMacroDefinition(call) and + // `v` only escapes as the argument to `memset`. + forall(Expr escape | variableAddressEscapesTree(v.getAnAccess(), escape) | + call.getArgument(0) = escape.getUnconverted() + ) and + // `v` is a stack-allocated array or a struct. + ( + v.getUnspecifiedType() instanceof ArrayType and call.getArgument(0) = v.getAnAccess() + or + v.getUnspecifiedType() instanceof Struct and + call.getArgument(0).(AddressOfExpr).getAddressable() = v + ) and + // There is no later use of `v`. + not v.getAnAccess() = call.getASuccessor*() and + // Not using the `-fno-builtin-memset` flag + exists(Compilation c | + c.getAFileCompiled() = call.getFile() and + not c.getAnArgument() = "-fno-builtin-memset" + ) +select call, "Call to " + memset.getName() + " may be deleted by the compiler." diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-14/CompilerRemovalOfCodeToClearBuffers.c b/cpp/ql/src/experimental/Security/CWE/CWE-14/CompilerRemovalOfCodeToClearBuffers.c deleted file mode 100644 index 14dd07a573e..00000000000 --- a/cpp/ql/src/experimental/Security/CWE/CWE-14/CompilerRemovalOfCodeToClearBuffers.c +++ /dev/null @@ -1,35 +0,0 @@ -// BAD: the memset call will probably be removed. -void getPassword(void) { - char pwd[64]; - if (GetPassword(pwd, sizeof(pwd))) { - /* Checking of password, secure operations, etc. */ - } - memset(pwd, 0, sizeof(pwd)); -} -// GOOD: in this case the memset will not be removed. -void getPassword(void) { - char pwd[64]; - - if (retrievePassword(pwd, sizeof(pwd))) { - /* Checking of password, secure operations, etc. */ - } - memset_s(pwd, 0, sizeof(pwd)); -} -// GOOD: in this case the memset will not be removed. -void getPassword(void) { - char pwd[64]; - if (retrievePassword(pwd, sizeof(pwd))) { - /* Checking of password, secure operations, etc. */ - } - SecureZeroMemory(pwd, sizeof(pwd)); -} -// GOOD: in this case the memset will not be removed. -void getPassword(void) { - char pwd[64]; - if (retrievePassword(pwd, sizeof(pwd))) { - /* Checking of password, secure operations, etc. */ - } -#pragma optimize("", off) - memset(pwd, 0, sizeof(pwd)); -#pragma optimize("", on) -} diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-14/CompilerRemovalOfCodeToClearBuffers.qhelp b/cpp/ql/src/experimental/Security/CWE/CWE-14/CompilerRemovalOfCodeToClearBuffers.qhelp deleted file mode 100644 index df0ed151d8f..00000000000 --- a/cpp/ql/src/experimental/Security/CWE/CWE-14/CompilerRemovalOfCodeToClearBuffers.qhelp +++ /dev/null @@ -1,31 +0,0 @@ - - - -

    Compiler optimization will exclude the cleaning of private information. -Using the memset function to clear private data in a variable that has no subsequent use is potentially dangerous, since the compiler can remove the call. -For some compilers, optimization is also possible when using calls to free memory after the memset function.

    - -

    It is possible to miss detection of vulnerabilities if used to clear fields of structures or parts of a buffer.

    - -
    - - -

    We recommend to use the RtlSecureZeroMemory or memset_s functions, or compilation flags that exclude optimization of memset calls (e.g. -fno-builtin-memset).

    - -
    - -

    The following example demonstrates an erroneous and corrected use of the memset function.

    - - -
    - - -
  • - CERT C Coding Standard: - MSC06-C. Beware of compiler optimizations. -
  • - -
    -
    diff --git a/cpp/ql/src/experimental/Security/CWE/CWE-14/CompilerRemovalOfCodeToClearBuffers.ql b/cpp/ql/src/experimental/Security/CWE/CWE-14/CompilerRemovalOfCodeToClearBuffers.ql deleted file mode 100644 index db09de9430d..00000000000 --- a/cpp/ql/src/experimental/Security/CWE/CWE-14/CompilerRemovalOfCodeToClearBuffers.ql +++ /dev/null @@ -1,127 +0,0 @@ -/** - * @name Compiler Removal Of Code To Clear Buffers - * @description Using memset the function to clear private data in a variable that has no subsequent use - * is potentially dangerous because the compiler can remove the call. - * @kind problem - * @id cpp/compiler-removal-of-code-to-clear-buffers - * @problem.severity warning - * @precision medium - * @tags security - * external/cwe/cwe-14 - */ - -import cpp -import semmle.code.cpp.dataflow.DataFlow -import semmle.code.cpp.dataflow.StackAddress - -/** - * A call to `memset` of the form `memset(ptr, value, num)`, for some local variable `ptr`. - */ -class CompilerRemovaMemset extends FunctionCall { - CompilerRemovaMemset() { - this.getTarget().hasGlobalOrStdName("memset") and - exists(DataFlow::Node source, DataFlow::Node sink, LocalVariable isv, Expr exp | - DataFlow::localFlow(source, sink) and - this.getArgument(0) = isv.getAnAccess() and - ( - source.asExpr() = exp - or - // handle the case where exp is defined by an address being passed into some function. - source.asDefiningArgument() = exp - ) and - exp.getLocation().getEndLine() < this.getArgument(0).getLocation().getStartLine() and - sink.asExpr() = this.getArgument(0) - ) - } - - predicate isExistsAllocForThisVariable() { - exists(AllocationExpr alloc, Variable v | - alloc = v.getAnAssignedValue() and - this.getArgument(0) = v.getAnAccess() and - alloc.getASuccessor+() = this - ) - or - not stackPointerFlowsToUse(this.getArgument(0), _, _, _) - } - - predicate isExistsFreeForThisVariable() { - exists(DeallocationExpr free, Variable v | - this.getArgument(0) = v.getAnAccess() and - free.getFreedExpr() = v.getAnAccess() and - this.getASuccessor+() = free - ) - } - - predicate isExistsCallWithThisVariableExcludingDeallocationCalls() { - exists(FunctionCall fc, Variable v | - not fc instanceof DeallocationExpr and - this.getArgument(0) = v.getAnAccess() and - fc.getAnArgument() = v.getAnAccess() and - this.getASuccessor+() = fc - ) - } - - predicate isVariableUseAfterMemsetExcludingCalls() { - exists(DataFlow::Node source, DataFlow::Node sink, LocalVariable isv, Expr exp | - DataFlow::localFlow(source, sink) and - this.getArgument(0) = isv.getAnAccess() and - source.asExpr() = isv.getAnAccess() and - exp.getLocation().getStartLine() > this.getArgument(2).getLocation().getEndLine() and - not exp.getParent() instanceof FunctionCall and - sink.asExpr() = exp - ) - } - - predicate isVariableUseBoundWithArgumentFunction() { - exists(DataFlow::Node source, DataFlow::Node sink, LocalVariable isv, Parameter p, Expr exp | - DataFlow::localFlow(source, sink) and - this.getArgument(0) = isv.getAnAccess() and - this.getEnclosingFunction().getAParameter() = p and - exp.getAChild*() = p.getAnAccess() and - source.asExpr() = exp and - sink.asExpr() = isv.getAnAccess() - ) - } - - predicate isVariableUseBoundWithGlobalVariable() { - exists( - DataFlow::Node source, DataFlow::Node sink, LocalVariable isv, GlobalVariable gv, Expr exp - | - DataFlow::localFlow(source, sink) and - this.getArgument(0) = isv.getAnAccess() and - exp.getAChild*() = gv.getAnAccess() and - source.asExpr() = exp and - sink.asExpr() = isv.getAnAccess() - ) - } - - predicate isExistsCompilationFlagsBlockingRemoval() { - exists(Compilation c | - c.getAFileCompiled() = this.getFile() and - c.getAnArgument() = "-fno-builtin-memset" - ) - } - - predicate isUseVCCompilation() { - exists(Compilation c | - c.getAFileCompiled() = this.getFile() and - ( - c.getArgument(2).matches("%gcc%") or - c.getArgument(2).matches("%g++%") or - c.getArgument(2).matches("%clang%") or - c.getArgument(2) = "--force-recompute" - ) - ) - } -} - -from CompilerRemovaMemset fc -where - not (fc.isExistsAllocForThisVariable() and not fc.isExistsFreeForThisVariable()) and - not (fc.isExistsFreeForThisVariable() and not fc.isUseVCCompilation()) and - not fc.isVariableUseAfterMemsetExcludingCalls() and - not fc.isExistsCallWithThisVariableExcludingDeallocationCalls() and - not fc.isVariableUseBoundWithArgumentFunction() and - not fc.isVariableUseBoundWithGlobalVariable() and - not fc.isExistsCompilationFlagsBlockingRemoval() -select fc.getArgument(0), "This variable will not be cleared." From ef8b7348633ad373e1e9d323ad1812869badcadb Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 24 Feb 2021 16:38:37 +0100 Subject: [PATCH 047/142] C++: Move tests out of experimental and merge with old existing tests from the other memset PRs. --- ...mpilerRemovalOfCodeToClearBuffers.expected | 3 - .../CompilerRemovalOfCodeToClearBuffers.qlref | 1 - .../Security/CWE/CWE-14/semmle/tests/test.c | 201 ---------- .../CWE/CWE-014/MemsetMayBeDeleted.expected | 3 + .../CWE/CWE-014/MemsetMayBeDeleted.qlref | 1 + .../query-tests/Security/CWE/CWE-014/test.c | 140 +++++++ .../query-tests/Security/CWE/CWE-014/test.cpp | 366 ++++++++++++++++++ 7 files changed, 510 insertions(+), 205 deletions(-) delete mode 100644 cpp/ql/test/experimental/query-tests/Security/CWE/CWE-14/semmle/tests/CompilerRemovalOfCodeToClearBuffers.expected delete mode 100644 cpp/ql/test/experimental/query-tests/Security/CWE/CWE-14/semmle/tests/CompilerRemovalOfCodeToClearBuffers.qlref delete mode 100644 cpp/ql/test/experimental/query-tests/Security/CWE/CWE-14/semmle/tests/test.c create mode 100644 cpp/ql/test/query-tests/Security/CWE/CWE-014/MemsetMayBeDeleted.expected create mode 100644 cpp/ql/test/query-tests/Security/CWE/CWE-014/MemsetMayBeDeleted.qlref create mode 100644 cpp/ql/test/query-tests/Security/CWE/CWE-014/test.c create mode 100644 cpp/ql/test/query-tests/Security/CWE/CWE-014/test.cpp diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-14/semmle/tests/CompilerRemovalOfCodeToClearBuffers.expected b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-14/semmle/tests/CompilerRemovalOfCodeToClearBuffers.expected deleted file mode 100644 index 8d98d94ff46..00000000000 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-14/semmle/tests/CompilerRemovalOfCodeToClearBuffers.expected +++ /dev/null @@ -1,3 +0,0 @@ -| test.c:13:9:13:13 | buff1 | This variable will not be cleared. | -| test.c:35:9:35:13 | buff1 | This variable will not be cleared. | -| test.c:43:9:43:13 | buff1 | This variable will not be cleared. | diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-14/semmle/tests/CompilerRemovalOfCodeToClearBuffers.qlref b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-14/semmle/tests/CompilerRemovalOfCodeToClearBuffers.qlref deleted file mode 100644 index 61d2a29b126..00000000000 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-14/semmle/tests/CompilerRemovalOfCodeToClearBuffers.qlref +++ /dev/null @@ -1 +0,0 @@ -experimental/Security/CWE/CWE-14/CompilerRemovalOfCodeToClearBuffers.ql diff --git a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-14/semmle/tests/test.c b/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-14/semmle/tests/test.c deleted file mode 100644 index 221072330c3..00000000000 --- a/cpp/ql/test/experimental/query-tests/Security/CWE/CWE-14/semmle/tests/test.c +++ /dev/null @@ -1,201 +0,0 @@ -struct buffers -{ - unsigned char buff1[50]; - unsigned char *buff2; -} globalBuff1,*globalBuff2; - -unsigned char * globalBuff; -void badFunc0_0(){ - unsigned char buff1[12]; - int i; - for(i=0;i<12;i++) - buff1[i]=13; - memset(buff1,12,12); -} -void nobadFunc0_0(){ - unsigned char buff1[12]; - memset(buff1,12,12); -} -void nobadFunc0_1(){ - unsigned char buff1[12]; - int i; - memset(buff1,12,12); - for(i=0;i<12;i++) - buff1[i]=13; - free(buff1); -} -void nobadFunc1_0(){ - unsigned char * buff1; - buff1 = (unsigned char *) malloc(12); - memset(buff1,12,12); -} -void badFunc1_0(){ - unsigned char * buff1; - buff1 = (unsigned char *) malloc(12); - memset(buff1,12,12); - free(buff1); -} -void badFunc1_1(){ - unsigned char buff1[12]; - int i; - for(i=0;i<12;i++) - buff1[i]=13; - memset(buff1,12,12); - free(buff1); -} -void nobadFunc2_0_0(){ - unsigned char buff1[12]; - int i; - for(i=0;i<12;i++) - buff1[i]=13; - memset(buff1,12,12); - printf(buff1); -} - -void nobadFunc2_0_1(){ - unsigned char buff1[12]; - int i; - for(i=0;i<12;i++) - buff1[i]=13; - memset(buff1,12,12); - printf(buff1+3); -} - -void nobadFunc2_0_2(){ - unsigned char buff1[12]; - int i; - for(i=0;i<12;i++) - buff1[i]=13; - memset(buff1,12,12); - printf(*buff1); -} - -void nobadFunc2_0_3(){ - unsigned char buff1[12]; - int i; - for(i=0;i<12;i++) - buff1[i]=13; - memset(buff1,12,12); - printf(*(buff1+3)); -} -unsigned char * nobadFunc2_0_4(){ - unsigned char buff1[12]; - int i; - for(i=0;i<12;i++) - buff1[i]=13; - memset(buff1,12,12); - return buff1; -} - -unsigned char * nobadFunc2_0_5(){ - unsigned char buff1[12]; - int i; - for(i=0;i<12;i++) - buff1[i]=13; - memset(buff1,12,12); - return buff1+3; -} -unsigned char nobadFunc2_0_6(){ - unsigned char buff1[12]; - int i; - for(i=0;i<12;i++) - buff1[i]=13; - memset(buff1,12,12); - return *buff1; -} - -unsigned char nobadFunc2_0_7(){ - unsigned char buff1[12]; - int i; - for(i=0;i<12;i++) - buff1[i]=13; - memset(buff1,12,12); - return *(buff1+3); -} -void nobadFunc2_1_0(){ - unsigned char buff1[12]; - int i; - for(i=0;i<12;i++) - buff1[i]=13; - memset(buff1,12,12); - if(*buff1==0) - printf("123123"); -} -void nobadFunc2_1_1(){ - unsigned char buff1[12]; - int i; - for(i=0;i<12;i++) - buff1[i]=13; - memset(buff1,12,12); - if(*(buff1+3)==0) - printf("123123"); -} -void nobadFunc2_1_2(){ - unsigned char buff1[12]; - int i; - for(i=0;i<12;i++) - buff1[i]=13; - memset(buff1,12,12); - buff1[2]=5; -} -void nobadFunc3_0(unsigned char * buffAll){ - unsigned char * buff1 = buffAll; - memset(buff1,12,12); -} -void nobadFunc3_1(unsigned char * buffAll){ - unsigned char * buff1 = buffAll+3; - memset(buff1,12,12); -} -void nobadFunc3_2(struct buffers buffAll){ - unsigned char * buff1 = buffAll.buff1; - memset(buff1,12,12); -} -void nobadFunc3_3(struct buffers buffAll){ - unsigned char * buff1 = buffAll.buff2; - memset(buff1,12,12); -} -void nobadFunc3_4(struct buffers buffAll){ - unsigned char * buff1 = buffAll.buff2+3; - memset(buff1,12,12); -} -void nobadFunc3_5(struct buffers * buffAll){ - unsigned char * buff1 = buffAll->buff1; - memset(buff1,12,12); -} -void nobadFunc3_6(struct buffers *buffAll){ - unsigned char * buff1 = buffAll->buff2; - memset(buff1,12,12); -} -void nobadFunc4(){ - unsigned char * buff1 = globalBuff; - memset(buff1,12,12); -} -void nobadFunc4_0(){ - unsigned char * buff1 = globalBuff; - memset(buff1,12,12); -} -void nobadFunc4_1(){ - unsigned char * buff1 = globalBuff+3; - memset(buff1,12,12); -} -void nobadFunc4_2(){ - unsigned char * buff1 = globalBuff1.buff1; - memset(buff1,12,12); -} -void nobadFunc4_3(){ - unsigned char * buff1 = globalBuff1.buff2; - memset(buff1,12,12); -} -void nobadFunc4_4(){ - unsigned char * buff1 = globalBuff1.buff2+3; - memset(buff1,12,12); -} -void nobadFunc4_5(){ - unsigned char * buff1 = globalBuff2->buff1; - memset(buff1,12,12); -} -void nobadFunc4_6(){ - unsigned char * buff1 = globalBuff2->buff2; - memset(buff1,12,12); -} - diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-014/MemsetMayBeDeleted.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-014/MemsetMayBeDeleted.expected new file mode 100644 index 00000000000..5506bf8acb4 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-014/MemsetMayBeDeleted.expected @@ -0,0 +1,3 @@ +| test.cpp:44:5:44:10 | call to memset | Call to memset may be deleted by the compiler. | +| test.cpp:72:5:72:10 | call to memset | Call to memset may be deleted by the compiler. | +| test.cpp:192:2:192:7 | call to memset | Call to memset may be deleted by the compiler. | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-014/MemsetMayBeDeleted.qlref b/cpp/ql/test/query-tests/Security/CWE/CWE-014/MemsetMayBeDeleted.qlref new file mode 100644 index 00000000000..e81526fe6d9 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-014/MemsetMayBeDeleted.qlref @@ -0,0 +1 @@ +Security/CWE/CWE-014/MemsetMayBeDeleted.ql diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-014/test.c b/cpp/ql/test/query-tests/Security/CWE/CWE-014/test.c new file mode 100644 index 00000000000..4cfa093cc54 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-014/test.c @@ -0,0 +1,140 @@ +typedef unsigned long long size_t; +void *memset(void *s, int c, unsigned long n); +void *__builtin_memset(void *s, int c, unsigned long n); +typedef int errno_t; +typedef unsigned int rsize_t; +errno_t memset_s(void *dest, rsize_t destsz, int ch, rsize_t count); +char *strcpy(char *dest, const char *src); + +extern void use_pw(char *pw); + +#define PW_SIZE 32 + +// x86-64 gcc 9.2: deleted +// x86-64 clang 9.0.0: deleted +// x64 msvc v19.14 (WINE): deleted +int func1(void) { + char pw1[PW_SIZE]; + use_pw(pw1); + memset(pw1, 0, PW_SIZE); // BAD [NOT DETECTED] + return 0; +} + +// x86-64 gcc 9.2: deleted +// x86-64 clang 9.0.0: deleted +// x64 msvc v19.14 (WINE): not deleted +int func1a(void) { + char pw1a[PW_SIZE]; + use_pw(pw1a); + __builtin_memset(pw1a, 0, PW_SIZE); // BAD [NOT DETECTED] + return 0; +} + +// x86-64 gcc 9.2: deleted +// x86-64 clang 9.0.0: deleted +// x64 msvc v19.14 (WINE): deleted +char *func1b(void) { + char pw1b[PW_SIZE]; + use_pw(pw1b); + memset(pw1b, 0, PW_SIZE); // BAD [NOT DETECTED] + pw1b[0] = pw1b[3] = 'a'; + return 0; +} + +// x86-64 gcc 9.2: not deleted +// x86-64 clang 9.0.0: not deleted +// x64 msvc v19.14 (WINE): not deleted +int func1c(char pw1c[PW_SIZE]) { + use_pw(pw1c); + memset(pw1c, 0, PW_SIZE); // GOOD + return 0; +} + +// x86-64 gcc 9.2: not deleted +// x86-64 clang 9.0.0: not deleted +// x64 msvc v19.14 (WINE): not deleted +char pw1d[PW_SIZE]; +int func1d() { + use_pw(pw1d); + memset(pw1d, 0, PW_SIZE); // GOOD + return 0; +} +// x86-64 gcc 9.2: not deleted +// x86-64 clang 9.0.0: not deleted +// x64 msvc v19.14 (WINE): not deleted +char *func2(void) { + char pw2[PW_SIZE]; + use_pw(pw2); + memset(pw2, 1, PW_SIZE); // BAD [NOT DETECTED] + return pw2; +} + +// x86-64 gcc 9.2: deleted +// x86-64 clang 9.0.0: deleted +// x64 msvc v19.14 (WINE): partially deleted +int func3(void) { + char pw3[PW_SIZE]; + use_pw(pw3); + memset(pw3, 4, PW_SIZE); // BAD [NOT DETECTED] + return pw3[2]; +} + +// x86-64 gcc 9.2: deleted +// x86-64 clang 9.0.0: deleted +// x64 msvc v19.14 (WINE): not deleted +int func4(void) { + char pw1a[PW_SIZE]; + use_pw(pw1a); + __builtin_memset(pw1a + 3, 0, PW_SIZE - 3); // BAD [NOT DETECTED] + return 0; +} + +// x86-64 gcc 9.2: deleted +// x86-64 clang 9.0.0: deleted +// x64 msvc v19.14 (WINE): not deleted +int func6(void) { + char pw1a[PW_SIZE]; + use_pw(pw1a); + __builtin_memset(&pw1a[3], 0, PW_SIZE - 3); // BAD [NOT DETECTED] + return pw1a[2]; +} + +// x86-64 gcc 9.2: deleted +// x86-64 clang 9.0.0: deleted +// x64 msvc v19.14 (WINE): not deleted +int func5(void) { + char pw1a[PW_SIZE]; + use_pw(pw1a); + __builtin_memset(pw1a + 3, 0, PW_SIZE - 4); // GOOD + return pw1a[4]; +} + +// x86-64 gcc 9.2: deleted +// x86-64 clang 9.0.0: deleted +// x64 msvc v19.14 (WINE): not deleted +int func7(void) { + char pw1a[PW_SIZE]; + use_pw(pw1a); + __builtin_memset(&pw1a[3], 0, PW_SIZE - 5); // BAD [NOT DETECTED] + return 0; +} + +// x86-64 gcc 9.2: not deleted +// x86-64 clang 9.0.0: not deleted +// x64 msvc v19.14 (WINE): not deleted +int func8(void) { + char pw1a[PW_SIZE]; + use_pw(pw1a); + __builtin_memset(pw1a + pw1a[3], 0, PW_SIZE - 4); // GOOD + return pw1a[4]; +} + +// x86-64 gcc 9.2: not deleted +// x86-64 clang 9.0.0: not deleted +// x64 msvc v19.14 (WINE): not deleted +char *func9(void) { + char pw1[PW_SIZE]; + use_pw(pw1); + memset(pw1, 0, PW_SIZE); // BAD [NOT DETECTED] + return 0; +} diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-014/test.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-014/test.cpp new file mode 100644 index 00000000000..e5011d91865 --- /dev/null +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-014/test.cpp @@ -0,0 +1,366 @@ +extern "C" { + typedef unsigned long long size_t; + void *memset(void *s, int c, unsigned long n); + void *__builtin_memset(void *s, int c, unsigned long n); + typedef int errno_t; + typedef unsigned int rsize_t; + errno_t memset_s(void *dest, rsize_t destsz, int ch, rsize_t count); + char *strcpy(char *dest, const char *src); + void *memcpy(void *dest, const void *src, unsigned long n); + void *malloc(unsigned long size); + void free(void *ptr); + extern void use_pw(char *pw); + int printf(const char* format, ...); +} + +#define PW_SIZE 32 + +struct mem { + int a; + char b[PW_SIZE]; + int c; +}; + +// x86-64 gcc 9.2: not deleted +// x86-64 clang 9.0.0: not deleted +// x64 msvc v19.22: not deleted +void func(char buff[128], unsigned long long sz) { + memset(buff, 0, PW_SIZE); // GOOD +} + +// x86-64 gcc 9.2: not deleted +// x86-64 clang 9.0.0: not deleted +// x64 msvc v19.22: not deleted +char *func2(char buff[128], unsigned long long sz) { + memset(buff, 0, PW_SIZE); // GOOD + return buff; +} + +// x86-64 gcc 9.2: deleted +// x86-64 clang 9.0.0: deleted +// x64 msvc v19.22: deleted +void func3(unsigned long long sz) { + char buff[128]; + memset(buff, 0, PW_SIZE); // BAD +} + +// x86-64 gcc 9.2: deleted +// x86-64 clang 9.0.0: deleted +// x64 msvc v19.22: deleted +void func4(unsigned long long sz) { + char buff[128]; + memset(buff, 0, PW_SIZE); // BAD [NOT DETECTED] + strcpy(buff, "Hello"); +} + +// x86-64 gcc 9.2: deleted +// x86-64 clang 9.0.0: deleted +// x64 msvc v19.22: deleted +void func5(unsigned long long sz) { + char buff[128]; + memset(buff, 0, PW_SIZE); // BAD [NOT DETECTED] + if (sz > 5) { + strcpy(buff, "Hello"); + } +} + +// x86-64 gcc 9.2: deleted +// x86-64 clang 9.0.0: deleted +// x64 msvc v19.22: deleted +void func6(unsigned long long sz) { + struct mem m; + memset(&m, 0, PW_SIZE); // BAD +} + +// x86-64 gcc 9.2: deleted +// x86-64 clang 9.0.0: deleted +// x64 msvc v19.22: deleted +void func7(unsigned long long sz) { + struct mem m; + memset(&m, 0, PW_SIZE); // BAD [NOT DETECTED] + m.a = 15; +} + +// x86-64 gcc 9.2: deleted +// x86-64 clang 9.0.0: deleted +// x64 msvc v19.22: not deleted +void func8(unsigned long long sz) { + struct mem *m = (struct mem *)malloc(sizeof(struct mem)); + memset(m, 0, PW_SIZE); // BAD [NOT DETECTED] +} + +// x86-64 gcc 9.2: deleted +// x86-64 clang 9.0.0: deleted +// x64 msvc v19.22: not deleted +void func9(unsigned long long sz) { + struct mem *m = (struct mem *)malloc(sizeof(struct mem)); + memset(m, 0, PW_SIZE); // BAD [NOT DETECTED] + free(m); +} + +// x86-64 gcc 9.2: deleted +// x86-64 clang 9.0.0: deleted +// x64 msvc v19.22: not deleted +void func10(unsigned long long sz) { + struct mem *m = (struct mem *)malloc(sizeof(struct mem)); + memset(m, 0, PW_SIZE); // BAD [NOT DETECTED] + m->a = sz; + m->c = m->a + 1; +} + +// x86-64 gcc 9.2: deleted +// x86-64 clang 9.0.0: deleted +// x64 msvc v19.22: not deleted +void func11(unsigned long long sz) { + struct mem *m = (struct mem *)malloc(sizeof(struct mem)); + ::memset(m, 0, PW_SIZE); // BAD [NOT DETECTED] + if (sz > 5) { + strcpy(m->b, "Hello"); + } +} + +// x86-64 gcc 9.2: not deleted +// x86-64 clang 9.0.0: not deleted +// x64 msvc v19.22: not deleted +int func12(unsigned long long sz) { + struct mem *m = (struct mem *)malloc(sizeof(struct mem)); + memset(m, 0, sz); // GOOD + return m->c; +} + +int funcN1() { + char pw[PW_SIZE]; + char *pw_ptr = pw; + memset(pw, 0, PW_SIZE); // GOOD + use_pw(pw_ptr); + return 0; +} + +char pw_global[PW_SIZE]; +int funcN2() { + use_pw(pw_global); + memset(pw_global, 0, PW_SIZE); // GOOD + return 0; +} + +int funcN3(unsigned long long sz) { + struct mem m; + memset(&m, 0, sizeof(m)); // GOOD + return m.a; +} + +void funcN(int num) { + char pw[PW_SIZE]; + int i; + + for (i = 0; i < num; i++) + { + use_pw(pw); + memset(pw, 0, PW_SIZE); // GOOD + } +} + +class MyClass +{ +public: + void set(int _x) { + x = _x; + } + + int get() + { + return x; + } + + void clear1() { + memset(&x, 0, sizeof(x)); // GOOD + } + + void clear2() { + memset(&(this->x), 0, sizeof(this->x)); // GOOD + } + +private: + int x; +}; + +void badFunc0_0(){ + unsigned char buff1[PW_SIZE]; + for(int i = 0; i < PW_SIZE; i++) { + buff1[i] = 13; + } + memset(buff1, 0, PW_SIZE); // BAD +} + +void nobadFunc1_0() { + unsigned char* buff1 = (unsigned char *) malloc(PW_SIZE); + memset(buff1, 0, PW_SIZE); // BAD [NOT DETECTED] +} +void badFunc1_0(){ + unsigned char * buff1 = (unsigned char *) malloc(PW_SIZE); + memset(buff1, 0, PW_SIZE); // BAD [NOT DETECTED] + free(buff1); +} +void badFunc1_1(){ + unsigned char buff1[PW_SIZE]; + for(int i = 0; i < PW_SIZE; i++) { + buff1[i] = 'a' + i; + } + memset(buff1, 0, PW_SIZE); // BAD [NOT DETECTED] + free(buff1); +} +void nobadFunc2_0_0(){ + unsigned char buff1[PW_SIZE]; + buff1[sizeof(buff1) - 1] = '\0'; + memset(buff1, 0, PW_SIZE); // GOOD + printf("%s", buff1); +} + +void nobadFunc2_0_1(){ + unsigned char buff1[PW_SIZE]; + memset(buff1, '\0', sizeof(buff1)); + memset(buff1, 0, PW_SIZE); // GOOD + printf("%s", buff1 + 3); +} + +void nobadFunc2_0_2(){ + unsigned char buff1[PW_SIZE]; + memset(buff1, 0, PW_SIZE); // GOOD + printf("%c", *buff1); +} + +void nobadFunc2_0_3(char ch){ + unsigned char buff1[PW_SIZE]; + for(int i = 0; i < PW_SIZE; i++) { + buff1[i] = ch; + } + memset(buff1, 0, PW_SIZE); // GOOD + printf("%c", *(buff1 + 3)); +} + +unsigned char * nobadFunc2_0_4(){ + unsigned char buff1[PW_SIZE]; + memset(buff1, 0, PW_SIZE); // GOOD + return buff1; +} + +unsigned char * nobadFunc2_0_5(){ + unsigned char buff1[PW_SIZE]; + memset(buff1, 0, PW_SIZE); // GOOD + + return buff1+3; +} + +unsigned char nobadFunc2_0_6(){ + unsigned char buff1[PW_SIZE]; + buff1[0] = 'z'; + int i; + memset(buff1, 0, PW_SIZE); // GOOD + + return *buff1; +} + +unsigned char nobadFunc2_0_7(){ + unsigned char buff1[PW_SIZE]; + memset(buff1, 0, PW_SIZE); // GOOD + + return *(buff1 + 3); +} + +bool nobadFunc2_1_0(unsigned char ch){ + unsigned char buff1[PW_SIZE]; + + memset(buff1, 0, PW_SIZE); // GOOD + if(*buff1 == ch) { return true; } + return false; +} + +void nobadFunc2_1_2(){ + unsigned char buff1[PW_SIZE]; + memset(buff1, 0, PW_SIZE); // GOOD + buff1[2] = 5; +} + +void nobadFunc3_0(unsigned char * buffAll){ + unsigned char * buff1 = buffAll; + memset(buff1, 0, PW_SIZE); // GOOD +} + +void nobadFunc3_1(unsigned char * buffAll){ + unsigned char * buff1 = buffAll + 3; + memset(buff1, 0, PW_SIZE); // GOOD +} + +struct buffers +{ + unsigned char buff1[50]; + unsigned char *buff2; +}; + +void nobadFunc3_2(struct buffers buffAll) { + unsigned char * buff1 = buffAll.buff1; + memset(buff1, 0, PW_SIZE); // GOOD +} + +void nobadFunc3_3(struct buffers buffAll) { + unsigned char * buff1 = buffAll.buff2; + memset(buff1, 0, PW_SIZE); // GOOD +} + +void nobadFunc3_4(struct buffers buffAll) { + unsigned char * buff1 = buffAll.buff2 + 3; + memset(buff1, 0, PW_SIZE); // GOOD +} + +void nobadFunc3_5(struct buffers * buffAll) { + unsigned char * buff1 = buffAll->buff1; + memset(buff1, 0, PW_SIZE); // GOOD +} + +void nobadFunc3_6(struct buffers *buffAll){ + unsigned char * buff1 = buffAll->buff2; + memset(buff1, 0, PW_SIZE); // GOOD +} + +unsigned char * globalBuff; + +void nobadFunc4(){ + unsigned char * buff1 = globalBuff; + memset(buff1, 0, PW_SIZE); // GOOD +} + +void nobadFunc4_0(){ + unsigned char * buff1 = globalBuff; + memset(buff1, 0, PW_SIZE); // GOOD +} +void nobadFunc4_1(){ + unsigned char * buff1 = globalBuff + 3; + memset(buff1, 0, PW_SIZE); // GOOD +} + +buffers globalBuff1, *globalBuff2; + +void nobadFunc4_2(){ + unsigned char * buff1 = globalBuff1.buff1; + memset(buff1, 0, PW_SIZE); // GOOD +} + +void nobadFunc4_3(){ + unsigned char * buff1 = globalBuff1.buff2; + memset(buff1, 0, PW_SIZE); // GOOD +} + +void nobadFunc4_4(){ + unsigned char * buff1 = globalBuff1.buff2+3; + memset(buff1, 0, PW_SIZE); // GOOD +} + +void nobadFunc4_5(){ + unsigned char * buff1 = globalBuff2->buff1; + memset(buff1, 0, PW_SIZE); // GOOD +} + +void nobadFunc4_6(){ + unsigned char * buff1 = globalBuff2->buff2; + memset(buff1, 0, PW_SIZE); // GOOD +} From 70a953b63369bf0dcab33697a68adfbb718a38a6 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Wed, 24 Feb 2021 17:10:26 +0100 Subject: [PATCH 048/142] C++: Add change-note. --- cpp/change-notes/2021-02-24-memset-may-be-deleted.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 cpp/change-notes/2021-02-24-memset-may-be-deleted.md diff --git a/cpp/change-notes/2021-02-24-memset-may-be-deleted.md b/cpp/change-notes/2021-02-24-memset-may-be-deleted.md new file mode 100644 index 00000000000..aa0bf32d7d1 --- /dev/null +++ b/cpp/change-notes/2021-02-24-memset-may-be-deleted.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* A new query (`cpp/memset-may-be-deleted`) is run and displayed on LGTM. The query finds calls to memset that may be removed by compiler. This query was originally submitted as an experimental query by @ihsinme in https://github.com/github/codeql/pull/4953. From 674b9ad4fec0a17c9cd0b1cdbf3118fc319bf1c8 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 24 Feb 2021 18:04:50 +0100 Subject: [PATCH 049/142] use getALocalSource instead of smallstep in JQuery::legacyObjectSource --- .../ql/src/semmle/javascript/frameworks/jQuery.qll | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/jQuery.qll b/javascript/ql/src/semmle/javascript/frameworks/jQuery.qll index 5f5be4a2fc4..7987f2edf04 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/jQuery.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/jQuery.qll @@ -544,17 +544,17 @@ module JQuery { } /** A source of jQuery objects from the AST-based `JQueryObject` class. */ - private DataFlow::Node legacyObjectSource() { result = any(JQueryObjectInternal e).flow() } + private DataFlow::SourceNode legacyObjectSource() { + result = any(JQueryObjectInternal e).flow().getALocalSource() + } /** Gets a source of jQuery objects. */ private DataFlow::SourceNode objectSource(DataFlow::TypeTracker t) { t.start() and result instanceof ObjectSource::Range or - exists(DataFlow::TypeTracker init | - init.start() and - t = init.smallstep(legacyObjectSource(), result) - ) + t.start() and + result = legacyObjectSource() } /** Gets a data flow node referring to a jQuery object. */ From ccd706ea10c98ad18e17919ad321524d11cbcd55 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 24 Feb 2021 18:05:10 +0100 Subject: [PATCH 050/142] and pragmas to prevent bad join in RemoteFlowSource --- javascript/ql/src/semmle/javascript/security/dataflow/DOM.qll | 1 + 1 file changed, 1 insertion(+) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/DOM.qll b/javascript/ql/src/semmle/javascript/security/dataflow/DOM.qll index 57d5612f35e..f1393dd69c0 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/DOM.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/DOM.qll @@ -229,6 +229,7 @@ private class PostMessageEventParameter extends RemoteFlowSource { * even if the window is opened from a foreign domain. */ private class WindowNameAccess extends RemoteFlowSource { + pragma[nomagic, noinline] WindowNameAccess() { this = DataFlow::globalObjectRef().getAPropertyRead("name") or From be26a48a168187f65c048caa3d4f8a139d2b7c85 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 24 Feb 2021 18:05:57 +0100 Subject: [PATCH 051/142] use pragma[only_bind_into] to prevent bad join in Ssa::hasLocationInfo --- javascript/ql/src/semmle/javascript/SSA.qll | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/SSA.qll b/javascript/ql/src/semmle/javascript/SSA.qll index 4c672fef1f7..6d330f3fc01 100644 --- a/javascript/ql/src/semmle/javascript/SSA.qll +++ b/javascript/ql/src/semmle/javascript/SSA.qll @@ -520,7 +520,10 @@ class SsaExplicitDefinition extends SsaDefinition, TExplicitDef { override predicate hasLocationInfo( string filepath, int startline, int startcolumn, int endline, int endcolumn ) { - getDef().getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + exists(Location loc | + pragma[only_bind_into](loc) = pragma[only_bind_into](getDef()).getLocation() and + loc.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + ) } /** @@ -552,7 +555,10 @@ abstract class SsaImplicitDefinition extends SsaDefinition { ) { endline = startline and endcolumn = startcolumn and - getBasicBlock().getLocation().hasLocationInfo(filepath, startline, startcolumn, _, _) + exists(Location loc | + pragma[only_bind_into](loc) = pragma[only_bind_into](getBasicBlock()).getLocation() and + loc.hasLocationInfo(filepath, startline, startcolumn, _, _) + ) } } From ea17de62258760582d0ac42c4d22841cec438238 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 24 Feb 2021 18:12:55 +0100 Subject: [PATCH 052/142] prevent join between `getAValue()` and `DefiniteAbstractValue` in AMD.qll --- javascript/ql/src/semmle/javascript/AMD.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/AMD.qll b/javascript/ql/src/semmle/javascript/AMD.qll index 74ba3d204af..2b89a49a8cb 100644 --- a/javascript/ql/src/semmle/javascript/AMD.qll +++ b/javascript/ql/src/semmle/javascript/AMD.qll @@ -158,7 +158,7 @@ class AmdModuleDefinition extends CallExpr { result = [getAnImplicitExportsValue(), getAnExplicitExportsValue()] } - pragma[noinline] + pragma[noinline, nomagic] private AbstractValue getAnImplicitExportsValue() { // implicit exports: anything that is returned from the factory function result = getModuleExpr().analyze().getAValue() From a5543c689e56cdd4fb17f131ea4d4d74a329d71e Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Thu, 25 Feb 2021 10:35:49 +0100 Subject: [PATCH 053/142] C#: Fix potentially concurrent file moves --- csharp/extractor/Semmle.Util/FileUtils.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/csharp/extractor/Semmle.Util/FileUtils.cs b/csharp/extractor/Semmle.Util/FileUtils.cs index 89e35055fee..aa655a6e674 100644 --- a/csharp/extractor/Semmle.Util/FileUtils.cs +++ b/csharp/extractor/Semmle.Util/FileUtils.cs @@ -33,10 +33,7 @@ namespace Semmle.Util /// Target file. public static void MoveOrReplace(string src, string dest) { - // Potential race condition here. - // .net offers the facility to either move a file, or to replace it. - File.Delete(dest); - File.Move(src, dest); + File.Move(src, dest, overwrite: true); } /// From d35ea7fb157574f4ee21e71e4bba60642315064a Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 24 Feb 2021 18:53:53 +0100 Subject: [PATCH 054/142] always get a good join-order in `getAnAliasedSourceNode` --- javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll b/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll index 0e1e3a41065..207d6f3010a 100644 --- a/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll +++ b/javascript/ql/src/semmle/javascript/GlobalAccessPaths.qll @@ -415,7 +415,7 @@ module AccessPath { pragma[inline] DataFlow::SourceNode getAnAliasedSourceNode(DataFlow::Node node) { exists(DataFlow::SourceNode root, string accessPath | - node = AccessPath::getAReferenceTo(root, accessPath) and + node = pragma[only_bind_into](AccessPath::getAReferenceTo(root, accessPath)) and result = AccessPath::getAReferenceTo(root, accessPath) ) or From 86bc7d3e1a28bc7b1853ad5fadd63fb5e63c8415 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 24 Feb 2021 18:57:32 +0100 Subject: [PATCH 055/142] avoid a ValueNode x TypeTracker join in Hapi::RouteSetup::getARouteHandler --- javascript/ql/src/semmle/javascript/frameworks/Hapi.qll | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Hapi.qll b/javascript/ql/src/semmle/javascript/frameworks/Hapi.qll index 3d9e08a9ceb..980ee9b0970 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Hapi.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Hapi.qll @@ -196,11 +196,14 @@ module Hapi { private DataFlow::SourceNode getARouteHandler(DataFlow::TypeBackTracker t) { t.start() and - result = handler.flow().getALocalSource() + result = getRouteHandler().getALocalSource() or exists(DataFlow::TypeBackTracker t2 | result = getARouteHandler(t2).backtrack(t2, t)) } + pragma[noinline] + private DataFlow::Node getRouteHandler() { result = handler.flow() } + Expr getRouteHandlerExpr() { result = handler } override Expr getServer() { result = server } From de6b60493005751a9417cf6091e05caed3f91834 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 24 Feb 2021 19:05:01 +0100 Subject: [PATCH 056/142] cache RemoteFlowSource --- .../semmle/javascript/security/dataflow/RemoteFlowSources.qll | 3 +++ 1 file changed, 3 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/RemoteFlowSources.qll b/javascript/ql/src/semmle/javascript/security/dataflow/RemoteFlowSources.qll index de5ac14d9be..c9d115ee5ea 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/RemoteFlowSources.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/RemoteFlowSources.qll @@ -7,13 +7,16 @@ import semmle.javascript.frameworks.HTTP import semmle.javascript.security.dataflow.DOM /** A data flow source of remote user input. */ +cached abstract class RemoteFlowSource extends DataFlow::Node { /** Gets a string that describes the type of this remote flow source. */ + cached abstract string getSourceType(); /** * Holds if this can be a user-controlled object, such as a JSON object parsed from user-controlled data. */ + cached predicate isUserControlledObject() { none() } } From 41b7db144d4145151c21c623ada8ada476f5dc6a Mon Sep 17 00:00:00 2001 From: Joe Farebrother Date: Thu, 25 Feb 2021 11:40:48 +0000 Subject: [PATCH 057/142] Allow for array types in model signatures --- java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll b/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll index 3f97a6e59db..86f536f8ed7 100644 --- a/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll +++ b/java/ql/src/semmle/code/java/dataflow/ExternalFlow.qll @@ -222,7 +222,7 @@ module CsvValidation { not name.regexpMatch("[a-zA-Z0-9_]*") and msg = "Dubious name \"" + name + "\" in " + pred + " model." or - not signature.regexpMatch("|\\([a-zA-Z0-9_\\.\\$<>,]*\\)") and + not signature.regexpMatch("|\\([a-zA-Z0-9_\\.\\$<>,\\[\\]]*\\)") and msg = "Dubious signature \"" + signature + "\" in " + pred + " model." or not ext.regexpMatch("|Annotated") and From d33209388d4f9ee7f9cc622b141d2390ff5f912c Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 25 Feb 2021 13:25:11 +0100 Subject: [PATCH 058/142] C++: Fix test annotations. Also exclude static locals from the query and add a testcase for this. --- .../src/Security/CWE/CWE-014/MemsetMayBeDeleted.ql | 3 ++- cpp/ql/test/query-tests/Security/CWE/CWE-014/test.c | 12 ++++++------ .../test/query-tests/Security/CWE/CWE-014/test.cpp | 10 +++++++++- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.ql b/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.ql index a0b3e816239..4c681e64fdf 100644 --- a/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.ql +++ b/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.ql @@ -32,7 +32,8 @@ where forall(Expr escape | variableAddressEscapesTree(v.getAnAccess(), escape) | call.getArgument(0) = escape.getUnconverted() ) and - // `v` is a stack-allocated array or a struct. + // `v` is a stack-allocated array or a struct, and `v` is not static. + not v.isStatic() and ( v.getUnspecifiedType() instanceof ArrayType and call.getArgument(0) = v.getAnAccess() or diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-014/test.c b/cpp/ql/test/query-tests/Security/CWE/CWE-014/test.c index 4cfa093cc54..1ca22b5782e 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-014/test.c +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-014/test.c @@ -59,9 +59,9 @@ int func1d() { memset(pw1d, 0, PW_SIZE); // GOOD return 0; } -// x86-64 gcc 9.2: not deleted -// x86-64 clang 9.0.0: not deleted -// x64 msvc v19.14 (WINE): not deleted +// x86-64 gcc 9.2: deleted +// x86-64 clang 9.0.0: deleted +// x64 msvc v19.14 (WINE): deleted char *func2(void) { char pw2[PW_SIZE]; use_pw(pw2); @@ -129,9 +129,9 @@ int func8(void) { return pw1a[4]; } -// x86-64 gcc 9.2: not deleted -// x86-64 clang 9.0.0: not deleted -// x64 msvc v19.14 (WINE): not deleted +// x86-64 gcc 9.2: deleted +// x86-64 clang 9.0.0: deleted +// x64 msvc v19.14 (WINE): deleted char *func9(void) { char pw1[PW_SIZE]; use_pw(pw1); diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-014/test.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-014/test.cpp index e5011d91865..bac6d49742d 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-014/test.cpp +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-014/test.cpp @@ -277,7 +277,7 @@ bool nobadFunc2_1_0(unsigned char ch){ void nobadFunc2_1_2(){ unsigned char buff1[PW_SIZE]; - memset(buff1, 0, PW_SIZE); // GOOD + memset(buff1, 0, PW_SIZE); // BAD [NOT DETECTED] buff1[2] = 5; } @@ -364,3 +364,11 @@ void nobadFunc4_6(){ unsigned char * buff1 = globalBuff2->buff2; memset(buff1, 0, PW_SIZE); // GOOD } + +extern void use_byte(unsigned char); + +void test_static_func() { + static unsigned char buffer[PW_SIZE] = {0}; + use_byte(buffer[0]); + memset(buffer, 42, sizeof(buffer)); // GOOD +} From 3e651f14fdb51a6d181a134c3adcf53841f52703 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Thu, 25 Feb 2021 11:10:03 +0100 Subject: [PATCH 059/142] C#: Add more well-known enum underlying types --- .../Semmle.Extraction.CIL/Entities/CustomAttributeDecoder.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/CustomAttributeDecoder.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/CustomAttributeDecoder.cs index 9007e0b8b90..184e37a1adf 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/CustomAttributeDecoder.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/CustomAttributeDecoder.cs @@ -56,7 +56,8 @@ namespace Semmle.Extraction.CIL.Entities private static readonly Dictionary wellKnownEnums = new Dictionary { { "System.AttributeTargets", PrimitiveTypeCode.Int32 }, - { "System.ComponentModel.EditorBrowsableState", PrimitiveTypeCode.Int32 } + { "System.ComponentModel.EditorBrowsableState", PrimitiveTypeCode.Int32 }, + { "System.Diagnostics.DebuggerBrowsableState", PrimitiveTypeCode.Int32 } }; } } From 0e071b7b798cb3931a4c79058defd17e7781bc84 Mon Sep 17 00:00:00 2001 From: Geoffrey White <40627776+geoffw0@users.noreply.github.com> Date: Thu, 25 Feb 2021 14:14:11 +0000 Subject: [PATCH 060/142] JS: Fix 'is, is' and 'is is'. --- javascript/ql/src/semmle/javascript/Expr.qll | 2 +- javascript/ql/src/semmle/javascript/Stmt.qll | 2 +- .../security/dataflow/PrototypePollutionCustomizations.qll | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/Expr.qll b/javascript/ql/src/semmle/javascript/Expr.qll index a03bb54e6f6..37576ec643f 100644 --- a/javascript/ql/src/semmle/javascript/Expr.qll +++ b/javascript/ql/src/semmle/javascript/Expr.qll @@ -115,7 +115,7 @@ class Expr extends @expr, ExprOrStmt, ExprOrType, AST::ValueNode { predicate isImpure() { any() } /** - * Holds if this expression is pure, that is, is its evaluation is guaranteed + * Holds if this expression is pure, that is, its evaluation is guaranteed * to be side-effect free. */ predicate isPure() { not isImpure() } diff --git a/javascript/ql/src/semmle/javascript/Stmt.qll b/javascript/ql/src/semmle/javascript/Stmt.qll index b1f66a19bf6..1d96c2666ee 100644 --- a/javascript/ql/src/semmle/javascript/Stmt.qll +++ b/javascript/ql/src/semmle/javascript/Stmt.qll @@ -95,7 +95,7 @@ class ControlStmt extends TControlStmt, Stmt { } /** - * A loop, that is, is a while loop, a do-while loop, a for loop, or a for-in loop. + * A loop, that is, a while loop, a do-while loop, a for loop, or a for-in loop. * * Examples: * diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/PrototypePollutionCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/PrototypePollutionCustomizations.qll index 387ee8173f2..40a5202a815 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/PrototypePollutionCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/PrototypePollutionCustomizations.qll @@ -14,7 +14,7 @@ module PrototypePollution { * Label for wrappers around tainted objects, that is, objects that are * not completely user-controlled, but contain a user-controlled object. * - * For example, `options` below is is a tainted wrapper, but is not itself + * For example, `options` below is a tainted wrapper, but is not itself * a tainted object: * ``` * let options = { From 3f26b2940dd6369a4374c7418b03c5ad6d2f8caa Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 25 Feb 2021 15:48:48 +0100 Subject: [PATCH 061/142] Update cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.ql Co-authored-by: Jonas Jensen --- cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.ql b/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.ql index 4c681e64fdf..a75ccf206d1 100644 --- a/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.ql +++ b/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.ql @@ -1,7 +1,7 @@ /** * @name Call to `memset` may be deleted * @description Using memset the function to clear private data in a variable that has no subsequent use - * is potentially dangerous because the compiler can remove the call. + * can make information-leak vulnerabilities easier to exploit because the compiler can remove the call. * @kind problem * @id cpp/memset-may-be-deleted * @problem.severity warning From fa189ded9d320412de13966ad5466f7f35ebaf73 Mon Sep 17 00:00:00 2001 From: Marcono1234 Date: Thu, 25 Feb 2021 18:21:18 +0100 Subject: [PATCH 062/142] Java: Add Class and Interface.isPackageProtected() --- java/ql/src/semmle/code/java/Type.qll | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/java/ql/src/semmle/code/java/Type.qll b/java/ql/src/semmle/code/java/Type.qll index 7f48467ad9b..10d9b8b3a31 100755 --- a/java/ql/src/semmle/code/java/Type.qll +++ b/java/ql/src/semmle/code/java/Type.qll @@ -599,6 +599,13 @@ class Class extends RefType, @class { /** Holds if this class is a local class. */ predicate isLocal() { isLocalClass(this, _) } + /** Holds if this class is package protected, that is, neither public nor private nor protected. */ + predicate isPackageProtected() { + not isPrivate() and + not isProtected() and + not isPublic() + } + override RefType getSourceDeclaration() { classes(this, _, _, result) } /** @@ -816,6 +823,13 @@ class Interface extends RefType, @interface { any() } + /** Holds if this interface is package protected, that is, neither public nor private nor protected. */ + predicate isPackageProtected() { + not isPrivate() and + not isProtected() and + not isPublic() + } + override string getAPrimaryQlClass() { result = "Interface" } } From 9e7c9d0ea091b8fdcf7fd43475b5cdb69477d67d Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 25 Feb 2021 18:22:48 +0100 Subject: [PATCH 063/142] C++: Respond to review comments. Relax the escaping requirements on the local variable being used in memset. --- .../CWE/CWE-014/MemsetMayBeDeleted.ql | 32 +++++++++++++------ 1 file changed, 22 insertions(+), 10 deletions(-) diff --git a/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.ql b/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.ql index a75ccf206d1..a52ab3827e9 100644 --- a/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.ql +++ b/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.ql @@ -1,6 +1,6 @@ /** * @name Call to `memset` may be deleted - * @description Using memset the function to clear private data in a variable that has no subsequent use + * @description Using `memset` the function to clear private data in a variable that has no subsequent use * can make information-leak vulnerabilities easier to exploit because the compiler can remove the call. * @kind problem * @id cpp/memset-may-be-deleted @@ -13,6 +13,7 @@ import cpp import semmle.code.cpp.dataflow.EscapesTree import semmle.code.cpp.commons.Exclusions +import semmle.code.cpp.models.interfaces.Alias class MemsetFunction extends Function { MemsetFunction() { @@ -24,22 +25,33 @@ class MemsetFunction extends Function { } } +predicate isNonEscapingArgument(Expr escaped) { + exists(Call call, AliasFunction aliasFunction, int i | + aliasFunction = call.getTarget() and + call.getArgument(i) = escaped.getUnconverted() and + ( + aliasFunction.parameterNeverEscapes(i) + or + aliasFunction.parameterEscapesOnlyViaReturn(i) and + (call instanceof ExprInVoidContext or call.getConversion*() instanceof BoolConversion) + ) + ) +} + from FunctionCall call, LocalVariable v, MemsetFunction memset where call.getTarget() = memset and not isFromMacroDefinition(call) and - // `v` only escapes as the argument to `memset`. + // `v` escapes as the argument to `memset` + variableAddressEscapesTree(v.getAnAccess(), call.getArgument(0).getFullyConverted()) and + // ... and `v` doesn't escape anywhere else. forall(Expr escape | variableAddressEscapesTree(v.getAnAccess(), escape) | - call.getArgument(0) = escape.getUnconverted() + isNonEscapingArgument(escape) ) and - // `v` is a stack-allocated array or a struct, and `v` is not static. not v.isStatic() and - ( - v.getUnspecifiedType() instanceof ArrayType and call.getArgument(0) = v.getAnAccess() - or - v.getUnspecifiedType() instanceof Struct and - call.getArgument(0).(AddressOfExpr).getAddressable() = v - ) and + // Reference-typed variables get special treatment in `variableAddressEscapesTree` so we leave them + // out of this query. + not v.getUnspecifiedType() instanceof ReferenceType and // There is no later use of `v`. not v.getAnAccess() = call.getASuccessor*() and // Not using the `-fno-builtin-memset` flag From 2777ca445e380129edc5e3d213b375a5470c6d52 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 25 Feb 2021 19:49:58 +0100 Subject: [PATCH 064/142] Update cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.ql Co-authored-by: intrigus-lgtm <60750685+intrigus-lgtm@users.noreply.github.com> --- cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.ql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.ql b/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.ql index a52ab3827e9..249aeb8bd0e 100644 --- a/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.ql +++ b/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.ql @@ -1,6 +1,6 @@ /** * @name Call to `memset` may be deleted - * @description Using `memset` the function to clear private data in a variable that has no subsequent use + * @description Using the `memset` function to clear private data in a variable that has no subsequent use * can make information-leak vulnerabilities easier to exploit because the compiler can remove the call. * @kind problem * @id cpp/memset-may-be-deleted From faadcd913e89a39226946678e30de844769e274b Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Thu, 25 Feb 2021 21:27:12 +0100 Subject: [PATCH 065/142] C++: Exclude memsets that clear a variable that has no other uses. --- cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.ql | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.ql b/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.ql index 249aeb8bd0e..df6a614079e 100644 --- a/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.ql +++ b/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.ql @@ -52,6 +52,10 @@ where // Reference-typed variables get special treatment in `variableAddressEscapesTree` so we leave them // out of this query. not v.getUnspecifiedType() instanceof ReferenceType and + // `v` is not only just used in the call to `memset`. + exists(Access acc | + acc = v.getAnAccess() and not call.getArgument(0).getAChild*() = acc and not acc.isUnevaluated() + ) and // There is no later use of `v`. not v.getAnAccess() = call.getASuccessor*() and // Not using the `-fno-builtin-memset` flag From 141f057f7b5225e60d360d4dd3920038a444a59e Mon Sep 17 00:00:00 2001 From: intrigus Date: Thu, 25 Feb 2021 21:29:26 +0100 Subject: [PATCH 066/142] Java: Remove duplicate code. --- .../src/experimental/Security/CWE/CWE-489/EJBMain.ql | 4 ++-- .../CWE/CWE-489/{MainLib.qll => TestLib.qll} | 12 +----------- .../Security/CWE/CWE-489/WebComponentMain.ql | 4 ++-- 3 files changed, 5 insertions(+), 15 deletions(-) rename java/ql/src/experimental/Security/CWE/CWE-489/{MainLib.qll => TestLib.qll} (68%) diff --git a/java/ql/src/experimental/Security/CWE/CWE-489/EJBMain.ql b/java/ql/src/experimental/Security/CWE/CWE-489/EJBMain.ql index 3c5bac4b710..7723aea9ee2 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-489/EJBMain.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-489/EJBMain.ql @@ -9,13 +9,13 @@ import java import semmle.code.java.J2EE -import MainLib +import TestLib /** The `main` method in an Enterprise Java Bean. */ class EnterpriseBeanMainMethod extends Method { EnterpriseBeanMainMethod() { this.getDeclaringType() instanceof EnterpriseBean and - isMainMethod(this) and + this instanceof MainMethod and not isTestMethod(this) } } diff --git a/java/ql/src/experimental/Security/CWE/CWE-489/MainLib.qll b/java/ql/src/experimental/Security/CWE/CWE-489/TestLib.qll similarity index 68% rename from java/ql/src/experimental/Security/CWE/CWE-489/MainLib.qll rename to java/ql/src/experimental/Security/CWE/CWE-489/TestLib.qll index 835aff0b36f..e50f6c97f33 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-489/MainLib.qll +++ b/java/ql/src/experimental/Security/CWE/CWE-489/TestLib.qll @@ -1,17 +1,7 @@ -/** Definitions related to the main method in a test program. */ +/** Definitions related to test methods. */ import java -/** Holds if `m` is the main method of a Java class with the signature `public static void main(String[] args)`. */ -predicate isMainMethod(Method m) { - m.hasName("main") and - m.isStatic() and - m.getReturnType() instanceof VoidType and - m.isPublic() and - m.getNumberOfParameters() = 1 and - m.getParameter(0).getType() instanceof Array -} - /** * Holds if `m` is a test method indicated by: * a) in a test directory such as `src/test/java` diff --git a/java/ql/src/experimental/Security/CWE/CWE-489/WebComponentMain.ql b/java/ql/src/experimental/Security/CWE/CWE-489/WebComponentMain.ql index c3858b30b34..bb96c726147 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-489/WebComponentMain.ql +++ b/java/ql/src/experimental/Security/CWE/CWE-489/WebComponentMain.ql @@ -9,7 +9,7 @@ import java import semmle.code.java.frameworks.Servlets -import MainLib +import TestLib /** The java type `javax.servlet.Filter`. */ class ServletFilterClass extends Class { @@ -48,7 +48,7 @@ class WebComponentMainMethod extends Method { .getASupertype+() .hasQualifiedName("org.springframework.webflow.execution", "Action") // Spring actions ) and - isMainMethod(this) and + this instanceof MainMethod and not isTestMethod(this) } } From 290b1c624e3afed2575f4200ef8f5cb2cce864e2 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Thu, 25 Feb 2021 13:10:39 -0800 Subject: [PATCH 067/142] C++: cache the IR stage Operand class --- .../code/cpp/ir/implementation/aliased_ssa/Operand.qll | 10 +++++----- .../semmle/code/cpp/ir/implementation/raw/Operand.qll | 10 +++++----- .../cpp/ir/implementation/unaliased_ssa/Operand.qll | 10 +++++----- .../src/experimental/ir/implementation/raw/Operand.qll | 10 +++++----- .../ir/implementation/unaliased_ssa/Operand.qll | 10 +++++----- 5 files changed, 25 insertions(+), 25 deletions(-) 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 8f39d1b4c85..5187e5df54d 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 @@ -25,7 +25,7 @@ private class TStageOperand = * (the defining instruction) in another instruction (the use instruction) */ class Operand extends TStageOperand { - Operand() { + cached Operand() { // Ensure that the operand does not refer to instructions from earlier stages that are unreachable here exists(Instruction use, Instruction def | this = registerOperand(use, _, def)) or exists(Instruction use | this = nonSSAMemoryOperand(use, _)) or @@ -190,7 +190,7 @@ class Operand extends TStageOperand { * An operand that consumes a memory result (e.g. the `LoadOperand` on a `Load` instruction). */ class MemoryOperand extends Operand { - MemoryOperand() { + cached MemoryOperand() { this instanceof TNonSSAMemoryOperand or this instanceof TPhiOperand or this instanceof TChiOperand @@ -256,7 +256,7 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand { override RegisterOperandTag tag; Instruction defInstr; - RegisterOperand() { this = registerOperand(useInstr, tag, defInstr) } + cached RegisterOperand() { this = registerOperand(useInstr, tag, defInstr) } final override string toString() { result = tag.toString() } @@ -274,7 +274,7 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand { class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand { override MemoryOperandTag tag; - NonPhiMemoryOperand() { + cached NonPhiMemoryOperand() { this = nonSSAMemoryOperand(useInstr, tag) or this = chiOperand(useInstr, tag) @@ -426,7 +426,7 @@ class PhiInputOperand extends MemoryOperand, TPhiOperand { IRBlock predecessorBlock; Overlap overlap; - PhiInputOperand() { this = phiOperand(useInstr, defInstr, predecessorBlock, overlap) } + cached PhiInputOperand() { this = phiOperand(useInstr, defInstr, predecessorBlock, overlap) } override string toString() { result = "Phi" } 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 8f39d1b4c85..5187e5df54d 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 @@ -25,7 +25,7 @@ private class TStageOperand = * (the defining instruction) in another instruction (the use instruction) */ class Operand extends TStageOperand { - Operand() { + cached Operand() { // Ensure that the operand does not refer to instructions from earlier stages that are unreachable here exists(Instruction use, Instruction def | this = registerOperand(use, _, def)) or exists(Instruction use | this = nonSSAMemoryOperand(use, _)) or @@ -190,7 +190,7 @@ class Operand extends TStageOperand { * An operand that consumes a memory result (e.g. the `LoadOperand` on a `Load` instruction). */ class MemoryOperand extends Operand { - MemoryOperand() { + cached MemoryOperand() { this instanceof TNonSSAMemoryOperand or this instanceof TPhiOperand or this instanceof TChiOperand @@ -256,7 +256,7 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand { override RegisterOperandTag tag; Instruction defInstr; - RegisterOperand() { this = registerOperand(useInstr, tag, defInstr) } + cached RegisterOperand() { this = registerOperand(useInstr, tag, defInstr) } final override string toString() { result = tag.toString() } @@ -274,7 +274,7 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand { class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand { override MemoryOperandTag tag; - NonPhiMemoryOperand() { + cached NonPhiMemoryOperand() { this = nonSSAMemoryOperand(useInstr, tag) or this = chiOperand(useInstr, tag) @@ -426,7 +426,7 @@ class PhiInputOperand extends MemoryOperand, TPhiOperand { IRBlock predecessorBlock; Overlap overlap; - PhiInputOperand() { this = phiOperand(useInstr, defInstr, predecessorBlock, overlap) } + cached PhiInputOperand() { this = phiOperand(useInstr, defInstr, predecessorBlock, overlap) } override string toString() { result = "Phi" } 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 8f39d1b4c85..5187e5df54d 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 @@ -25,7 +25,7 @@ private class TStageOperand = * (the defining instruction) in another instruction (the use instruction) */ class Operand extends TStageOperand { - Operand() { + cached Operand() { // Ensure that the operand does not refer to instructions from earlier stages that are unreachable here exists(Instruction use, Instruction def | this = registerOperand(use, _, def)) or exists(Instruction use | this = nonSSAMemoryOperand(use, _)) or @@ -190,7 +190,7 @@ class Operand extends TStageOperand { * An operand that consumes a memory result (e.g. the `LoadOperand` on a `Load` instruction). */ class MemoryOperand extends Operand { - MemoryOperand() { + cached MemoryOperand() { this instanceof TNonSSAMemoryOperand or this instanceof TPhiOperand or this instanceof TChiOperand @@ -256,7 +256,7 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand { override RegisterOperandTag tag; Instruction defInstr; - RegisterOperand() { this = registerOperand(useInstr, tag, defInstr) } + cached RegisterOperand() { this = registerOperand(useInstr, tag, defInstr) } final override string toString() { result = tag.toString() } @@ -274,7 +274,7 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand { class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand { override MemoryOperandTag tag; - NonPhiMemoryOperand() { + cached NonPhiMemoryOperand() { this = nonSSAMemoryOperand(useInstr, tag) or this = chiOperand(useInstr, tag) @@ -426,7 +426,7 @@ class PhiInputOperand extends MemoryOperand, TPhiOperand { IRBlock predecessorBlock; Overlap overlap; - PhiInputOperand() { this = phiOperand(useInstr, defInstr, predecessorBlock, overlap) } + cached PhiInputOperand() { this = phiOperand(useInstr, defInstr, predecessorBlock, overlap) } override string toString() { result = "Phi" } diff --git a/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll b/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll index 8f39d1b4c85..5187e5df54d 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll @@ -25,7 +25,7 @@ private class TStageOperand = * (the defining instruction) in another instruction (the use instruction) */ class Operand extends TStageOperand { - Operand() { + cached Operand() { // Ensure that the operand does not refer to instructions from earlier stages that are unreachable here exists(Instruction use, Instruction def | this = registerOperand(use, _, def)) or exists(Instruction use | this = nonSSAMemoryOperand(use, _)) or @@ -190,7 +190,7 @@ class Operand extends TStageOperand { * An operand that consumes a memory result (e.g. the `LoadOperand` on a `Load` instruction). */ class MemoryOperand extends Operand { - MemoryOperand() { + cached MemoryOperand() { this instanceof TNonSSAMemoryOperand or this instanceof TPhiOperand or this instanceof TChiOperand @@ -256,7 +256,7 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand { override RegisterOperandTag tag; Instruction defInstr; - RegisterOperand() { this = registerOperand(useInstr, tag, defInstr) } + cached RegisterOperand() { this = registerOperand(useInstr, tag, defInstr) } final override string toString() { result = tag.toString() } @@ -274,7 +274,7 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand { class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand { override MemoryOperandTag tag; - NonPhiMemoryOperand() { + cached NonPhiMemoryOperand() { this = nonSSAMemoryOperand(useInstr, tag) or this = chiOperand(useInstr, tag) @@ -426,7 +426,7 @@ class PhiInputOperand extends MemoryOperand, TPhiOperand { IRBlock predecessorBlock; Overlap overlap; - PhiInputOperand() { this = phiOperand(useInstr, defInstr, predecessorBlock, overlap) } + cached PhiInputOperand() { this = phiOperand(useInstr, defInstr, predecessorBlock, overlap) } override string toString() { result = "Phi" } 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 8f39d1b4c85..5187e5df54d 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Operand.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Operand.qll @@ -25,7 +25,7 @@ private class TStageOperand = * (the defining instruction) in another instruction (the use instruction) */ class Operand extends TStageOperand { - Operand() { + cached Operand() { // Ensure that the operand does not refer to instructions from earlier stages that are unreachable here exists(Instruction use, Instruction def | this = registerOperand(use, _, def)) or exists(Instruction use | this = nonSSAMemoryOperand(use, _)) or @@ -190,7 +190,7 @@ class Operand extends TStageOperand { * An operand that consumes a memory result (e.g. the `LoadOperand` on a `Load` instruction). */ class MemoryOperand extends Operand { - MemoryOperand() { + cached MemoryOperand() { this instanceof TNonSSAMemoryOperand or this instanceof TPhiOperand or this instanceof TChiOperand @@ -256,7 +256,7 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand { override RegisterOperandTag tag; Instruction defInstr; - RegisterOperand() { this = registerOperand(useInstr, tag, defInstr) } + cached RegisterOperand() { this = registerOperand(useInstr, tag, defInstr) } final override string toString() { result = tag.toString() } @@ -274,7 +274,7 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand { class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand { override MemoryOperandTag tag; - NonPhiMemoryOperand() { + cached NonPhiMemoryOperand() { this = nonSSAMemoryOperand(useInstr, tag) or this = chiOperand(useInstr, tag) @@ -426,7 +426,7 @@ class PhiInputOperand extends MemoryOperand, TPhiOperand { IRBlock predecessorBlock; Overlap overlap; - PhiInputOperand() { this = phiOperand(useInstr, defInstr, predecessorBlock, overlap) } + cached PhiInputOperand() { this = phiOperand(useInstr, defInstr, predecessorBlock, overlap) } override string toString() { result = "Phi" } From 72daf2eef93245c5b1f3f3270e74e45c14930da1 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 26 Feb 2021 09:19:05 +0100 Subject: [PATCH 068/142] C++: Make the tests more realistic by actually using the local variable for something. Otherwise it looks like a zero-initialization of a buffer, which the query now tries to exclude. --- .../CWE/CWE-014/MemsetMayBeDeleted.expected | 6 +- .../query-tests/Security/CWE/CWE-014/test.cpp | 93 ++++++++++++------- 2 files changed, 63 insertions(+), 36 deletions(-) diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-014/MemsetMayBeDeleted.expected b/cpp/ql/test/query-tests/Security/CWE/CWE-014/MemsetMayBeDeleted.expected index 5506bf8acb4..7b469bea894 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-014/MemsetMayBeDeleted.expected +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-014/MemsetMayBeDeleted.expected @@ -1,3 +1,3 @@ -| test.cpp:44:5:44:10 | call to memset | Call to memset may be deleted by the compiler. | -| test.cpp:72:5:72:10 | call to memset | Call to memset may be deleted by the compiler. | -| test.cpp:192:2:192:7 | call to memset | Call to memset may be deleted by the compiler. | +| test.cpp:48:5:48:10 | call to memset | Call to memset may be deleted by the compiler. | +| test.cpp:79:5:79:10 | call to memset | Call to memset may be deleted by the compiler. | +| test.cpp:208:2:208:7 | call to memset | Call to memset may be deleted by the compiler. | diff --git a/cpp/ql/test/query-tests/Security/CWE/CWE-014/test.cpp b/cpp/ql/test/query-tests/Security/CWE/CWE-014/test.cpp index bac6d49742d..1e0ed7d70f0 100644 --- a/cpp/ql/test/query-tests/Security/CWE/CWE-014/test.cpp +++ b/cpp/ql/test/query-tests/Security/CWE/CWE-014/test.cpp @@ -11,6 +11,7 @@ extern "C" { void free(void *ptr); extern void use_pw(char *pw); int printf(const char* format, ...); + char* gets(char * str); } #define PW_SIZE 32 @@ -25,22 +26,25 @@ struct mem { // x86-64 clang 9.0.0: not deleted // x64 msvc v19.22: not deleted void func(char buff[128], unsigned long long sz) { - memset(buff, 0, PW_SIZE); // GOOD + gets(buff); + memset(buff, 0, PW_SIZE); // GOOD } // x86-64 gcc 9.2: not deleted // x86-64 clang 9.0.0: not deleted // x64 msvc v19.22: not deleted -char *func2(char buff[128], unsigned long long sz) { - memset(buff, 0, PW_SIZE); // GOOD - return buff; +char *func2(char buff[128], unsigned long long sz) { + gets(buff); + memset(buff, 0, PW_SIZE); // GOOD + return buff; } // x86-64 gcc 9.2: deleted // x86-64 clang 9.0.0: deleted // x64 msvc v19.22: deleted void func3(unsigned long long sz) { - char buff[128]; + char buff[128]; + gets(buff); memset(buff, 0, PW_SIZE); // BAD } @@ -48,7 +52,8 @@ void func3(unsigned long long sz) { // x86-64 clang 9.0.0: deleted // x64 msvc v19.22: deleted void func4(unsigned long long sz) { - char buff[128]; + char buff[128]; + gets(buff); memset(buff, 0, PW_SIZE); // BAD [NOT DETECTED] strcpy(buff, "Hello"); } @@ -57,7 +62,8 @@ void func4(unsigned long long sz) { // x86-64 clang 9.0.0: deleted // x64 msvc v19.22: deleted void func5(unsigned long long sz) { - char buff[128]; + char buff[128]; + gets(buff); memset(buff, 0, PW_SIZE); // BAD [NOT DETECTED] if (sz > 5) { strcpy(buff, "Hello"); @@ -68,7 +74,8 @@ void func5(unsigned long long sz) { // x86-64 clang 9.0.0: deleted // x64 msvc v19.22: deleted void func6(unsigned long long sz) { - struct mem m; + struct mem m; + gets(m.b); memset(&m, 0, PW_SIZE); // BAD } @@ -76,7 +83,8 @@ void func6(unsigned long long sz) { // x86-64 clang 9.0.0: deleted // x64 msvc v19.22: deleted void func7(unsigned long long sz) { - struct mem m; + struct mem m; + gets(m.b); memset(&m, 0, PW_SIZE); // BAD [NOT DETECTED] m.a = 15; } @@ -86,6 +94,7 @@ void func7(unsigned long long sz) { // x64 msvc v19.22: not deleted void func8(unsigned long long sz) { struct mem *m = (struct mem *)malloc(sizeof(struct mem)); + gets(m->b); memset(m, 0, PW_SIZE); // BAD [NOT DETECTED] } @@ -94,6 +103,7 @@ void func8(unsigned long long sz) { // x64 msvc v19.22: not deleted void func9(unsigned long long sz) { struct mem *m = (struct mem *)malloc(sizeof(struct mem)); + gets(m->b); memset(m, 0, PW_SIZE); // BAD [NOT DETECTED] free(m); } @@ -103,6 +113,7 @@ void func9(unsigned long long sz) { // x64 msvc v19.22: not deleted void func10(unsigned long long sz) { struct mem *m = (struct mem *)malloc(sizeof(struct mem)); + gets(m->b); memset(m, 0, PW_SIZE); // BAD [NOT DETECTED] m->a = sz; m->c = m->a + 1; @@ -113,6 +124,7 @@ void func10(unsigned long long sz) { // x64 msvc v19.22: not deleted void func11(unsigned long long sz) { struct mem *m = (struct mem *)malloc(sizeof(struct mem)); + gets(m->b); ::memset(m, 0, PW_SIZE); // BAD [NOT DETECTED] if (sz > 5) { strcpy(m->b, "Hello"); @@ -124,12 +136,14 @@ void func11(unsigned long long sz) { // x64 msvc v19.22: not deleted int func12(unsigned long long sz) { struct mem *m = (struct mem *)malloc(sizeof(struct mem)); + gets(m->b); memset(m, 0, sz); // GOOD return m->c; } int funcN1() { char pw[PW_SIZE]; + gets(pw); char *pw_ptr = pw; memset(pw, 0, PW_SIZE); // GOOD use_pw(pw_ptr); @@ -138,6 +152,7 @@ int funcN1() { char pw_global[PW_SIZE]; int funcN2() { + gets(pw_global); use_pw(pw_global); memset(pw_global, 0, PW_SIZE); // GOOD return 0; @@ -145,6 +160,7 @@ int funcN2() { int funcN3(unsigned long long sz) { struct mem m; + gets(m.b); memset(&m, 0, sizeof(m)); // GOOD return m.a; } @@ -152,9 +168,9 @@ int funcN3(unsigned long long sz) { void funcN(int num) { char pw[PW_SIZE]; int i; - for (i = 0; i < num; i++) { + gets(pw); use_pw(pw); memset(pw, 0, PW_SIZE); // GOOD } @@ -193,11 +209,13 @@ void badFunc0_0(){ } void nobadFunc1_0() { - unsigned char* buff1 = (unsigned char *) malloc(PW_SIZE); + char* buff1 = (char *) malloc(PW_SIZE); + gets(buff1); memset(buff1, 0, PW_SIZE); // BAD [NOT DETECTED] } void badFunc1_0(){ - unsigned char * buff1 = (unsigned char *) malloc(PW_SIZE); + char * buff1 = (char *) malloc(PW_SIZE); + gets(buff1); memset(buff1, 0, PW_SIZE); // BAD [NOT DETECTED] free(buff1); } @@ -217,14 +235,16 @@ void nobadFunc2_0_0(){ } void nobadFunc2_0_1(){ - unsigned char buff1[PW_SIZE]; + char buff1[PW_SIZE]; + gets(buff1); memset(buff1, '\0', sizeof(buff1)); memset(buff1, 0, PW_SIZE); // GOOD printf("%s", buff1 + 3); } void nobadFunc2_0_2(){ - unsigned char buff1[PW_SIZE]; + char buff1[PW_SIZE]; + gets(buff1); memset(buff1, 0, PW_SIZE); // GOOD printf("%c", *buff1); } @@ -238,14 +258,16 @@ void nobadFunc2_0_3(char ch){ printf("%c", *(buff1 + 3)); } -unsigned char * nobadFunc2_0_4(){ - unsigned char buff1[PW_SIZE]; +char * nobadFunc2_0_4(){ + char buff1[PW_SIZE]; + gets(buff1); memset(buff1, 0, PW_SIZE); // GOOD return buff1; } -unsigned char * nobadFunc2_0_5(){ - unsigned char buff1[PW_SIZE]; +char * nobadFunc2_0_5(){ + char buff1[PW_SIZE]; + gets(buff1); memset(buff1, 0, PW_SIZE); // GOOD return buff1+3; @@ -261,28 +283,31 @@ unsigned char nobadFunc2_0_6(){ } unsigned char nobadFunc2_0_7(){ - unsigned char buff1[PW_SIZE]; + char buff1[PW_SIZE]; + gets(buff1); memset(buff1, 0, PW_SIZE); // GOOD return *(buff1 + 3); } bool nobadFunc2_1_0(unsigned char ch){ - unsigned char buff1[PW_SIZE]; - + char buff1[PW_SIZE]; + gets(buff1); memset(buff1, 0, PW_SIZE); // GOOD if(*buff1 == ch) { return true; } return false; } void nobadFunc2_1_2(){ - unsigned char buff1[PW_SIZE]; + char buff1[PW_SIZE]; + gets(buff1); memset(buff1, 0, PW_SIZE); // BAD [NOT DETECTED] buff1[2] = 5; } -void nobadFunc3_0(unsigned char * buffAll){ - unsigned char * buff1 = buffAll; +void nobadFunc3_0(char * buffAll){ + char * buff1 = buffAll; + gets(buff1); memset(buff1, 0, PW_SIZE); // GOOD } @@ -293,12 +318,13 @@ void nobadFunc3_1(unsigned char * buffAll){ struct buffers { - unsigned char buff1[50]; + char buff1[50]; unsigned char *buff2; }; void nobadFunc3_2(struct buffers buffAll) { - unsigned char * buff1 = buffAll.buff1; + char * buff1 = buffAll.buff1; + gets(buff1); memset(buff1, 0, PW_SIZE); // GOOD } @@ -313,7 +339,7 @@ void nobadFunc3_4(struct buffers buffAll) { } void nobadFunc3_5(struct buffers * buffAll) { - unsigned char * buff1 = buffAll->buff1; + char * buff1 = buffAll->buff1; memset(buff1, 0, PW_SIZE); // GOOD } @@ -322,26 +348,27 @@ void nobadFunc3_6(struct buffers *buffAll){ memset(buff1, 0, PW_SIZE); // GOOD } -unsigned char * globalBuff; +char * globalBuff; void nobadFunc4(){ - unsigned char * buff1 = globalBuff; + char * buff1 = globalBuff; memset(buff1, 0, PW_SIZE); // GOOD } void nobadFunc4_0(){ - unsigned char * buff1 = globalBuff; + char * buff1 = globalBuff; + gets(buff1); memset(buff1, 0, PW_SIZE); // GOOD } void nobadFunc4_1(){ - unsigned char * buff1 = globalBuff + 3; + char * buff1 = globalBuff + 3; memset(buff1, 0, PW_SIZE); // GOOD } buffers globalBuff1, *globalBuff2; void nobadFunc4_2(){ - unsigned char * buff1 = globalBuff1.buff1; + char * buff1 = globalBuff1.buff1; memset(buff1, 0, PW_SIZE); // GOOD } @@ -356,7 +383,7 @@ void nobadFunc4_4(){ } void nobadFunc4_5(){ - unsigned char * buff1 = globalBuff2->buff1; + char * buff1 = globalBuff2->buff1; memset(buff1, 0, PW_SIZE); // GOOD } From 4e4ffbd790f0b49b8f19c841dcf1be1cc4624844 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 26 Feb 2021 09:48:21 +0100 Subject: [PATCH 069/142] Update cpp/change-notes/2021-02-24-memset-may-be-deleted.md Co-authored-by: Jonas Jensen --- cpp/change-notes/2021-02-24-memset-may-be-deleted.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/change-notes/2021-02-24-memset-may-be-deleted.md b/cpp/change-notes/2021-02-24-memset-may-be-deleted.md index aa0bf32d7d1..955794634c7 100644 --- a/cpp/change-notes/2021-02-24-memset-may-be-deleted.md +++ b/cpp/change-notes/2021-02-24-memset-may-be-deleted.md @@ -1,2 +1,2 @@ lgtm,codescanning -* A new query (`cpp/memset-may-be-deleted`) is run and displayed on LGTM. The query finds calls to memset that may be removed by compiler. This query was originally submitted as an experimental query by @ihsinme in https://github.com/github/codeql/pull/4953. +* A new query (`cpp/memset-may-be-deleted`) is added to the default query suite. The query finds calls to `memset` that may be removed by compiler. This query was originally [submitted as an experimental query by @ihsinme](https://github.com/github/codeql/pull/4953). From b3d6d0c12b467292cf1d4ed8b9791fe171da986f Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Fri, 26 Feb 2021 09:48:37 +0100 Subject: [PATCH 070/142] Fix method name resolution issue with nullable suppression --- .../Entities/Expressions/Name.cs | 7 ++++ .../csharp8/NameResolutionSuppressNullable.cs | 15 ++++++++ .../csharp8/NullableRefTypes.expected | 2 ++ .../library-tests/csharp8/PrintAst.expected | 36 +++++++++++++++++++ 4 files changed, 60 insertions(+) create mode 100644 csharp/ql/test/library-tests/csharp8/NameResolutionSuppressNullable.cs diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Name.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Name.cs index faf5c9e2bd1..ed875a5e836 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Name.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Name.cs @@ -13,6 +13,13 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions var target = symbolInfo.Symbol; + if (target == null && + symbolInfo.CandidateReason == CandidateReason.OverloadResolutionFailure && + info.Node.Parent.IsKind(SyntaxKind.SuppressNullableWarningExpression)) + { + target = symbolInfo.CandidateSymbols.FirstOrDefault(); + } + if (target == null && symbolInfo.CandidateReason == CandidateReason.OverloadResolutionFailure) { // The expression is probably a cast diff --git a/csharp/ql/test/library-tests/csharp8/NameResolutionSuppressNullable.cs b/csharp/ql/test/library-tests/csharp8/NameResolutionSuppressNullable.cs new file mode 100644 index 00000000000..c1b84d940bc --- /dev/null +++ b/csharp/ql/test/library-tests/csharp8/NameResolutionSuppressNullable.cs @@ -0,0 +1,15 @@ +using System; +using System.Collections.Generic; +using System.Threading; + +class MyClass2 +{ + private static WaitCallback? s_signalMethod; + private static WaitCallback SignalMethod => EnsureInitialized(ref s_signalMethod, () => new WaitCallback(M1!)); + + public static T EnsureInitialized(ref T target, System.Func valueFactory) where T : class { return target = valueFactory(); } + + static void M1(object state) + { + } +} diff --git a/csharp/ql/test/library-tests/csharp8/NullableRefTypes.expected b/csharp/ql/test/library-tests/csharp8/NullableRefTypes.expected index 9d418a70ca0..ce6192ead71 100644 --- a/csharp/ql/test/library-tests/csharp8/NullableRefTypes.expected +++ b/csharp/ql/test/library-tests/csharp8/NullableRefTypes.expected @@ -1,4 +1,5 @@ suppressNullableWarnings +| NameResolutionSuppressNullable.cs:8:110:8:112 | ...! | NameResolutionSuppressNullable.cs:8:110:8:111 | access to method M1 | | NullableRefTypes.cs:85:20:85:21 | ...! | NullableRefTypes.cs:85:20:85:20 | access to local variable x | | NullableRefTypes.cs:86:13:86:14 | ...! | NullableRefTypes.cs:86:13:86:13 | access to local variable x | | NullableRefTypes.cs:88:13:88:14 | ...! | NullableRefTypes.cs:88:13:88:13 | access to local variable x | @@ -206,6 +207,7 @@ returnTypes | NullableRefTypes.cs:215:10:215:20 | ElementTest | Void! | | NullableRefTypes.cs:223:48:223:54 | GetSelf | TestNullableFlowStates? | methodTypeArguments +| NameResolutionSuppressNullable.cs:10:21:10:40 | EnsureInitialized | 0 | WaitCallback? | | NullableRefTypes.cs:51:12:51:15 | Q | 0 | MyClass! | | NullableRefTypes.cs:51:12:51:15 | Q | 0 | MyClass? | | NullableRefTypes.cs:67:10:67:21 | GenericFn | 0 | MyClass! | diff --git a/csharp/ql/test/library-tests/csharp8/PrintAst.expected b/csharp/ql/test/library-tests/csharp8/PrintAst.expected index d38d183151d..3a4cad07fc6 100644 --- a/csharp/ql/test/library-tests/csharp8/PrintAst.expected +++ b/csharp/ql/test/library-tests/csharp8/PrintAst.expected @@ -121,6 +121,42 @@ DefaultInterfaceMethods.cs: # 26| 7: [Method] Greet # 26| -1: [TypeMention] Void # 26| 4: [BlockStmt] {...} +NameResolutionSuppressNullable.cs: +# 5| [Class] MyClass2 +# 7| 5: [Field] s_signalMethod +# 7| -1: [TypeMention] WaitCallback +# 8| 6: [Property] SignalMethod +# 8| -1: [TypeMention] WaitCallback +# 8| 3: [Getter] get_SignalMethod +# 8| 4: [MethodCall] call to method EnsureInitialized +# 8| 0: [FieldAccess] access to field s_signalMethod +# 8| 1: [LambdaExpr] (...) => ... +# 8| 4: [ExplicitDelegateCreation] delegate creation of type WaitCallback +# 8| -1: [TypeMention] WaitCallback +# 8| 0: [SuppressNullableWarningExpr] ...! +# 8| 0: [MethodAccess] access to method M1 +# 10| 7: [Method] EnsureInitialized +# 10| -1: [TypeMention] T +#-----| 1: (Type parameters) +# 10| 0: [TypeParameter] T +#-----| 2: (Parameters) +# 10| 0: [Parameter] target +# 10| -1: [TypeMention] T +# 10| 1: [Parameter] valueFactory +# 10| -1: [TypeMention] Func +# 10| 1: [TypeMention] T +# 10| 4: [BlockStmt] {...} +# 10| 0: [ReturnStmt] return ...; +# 10| 0: [AssignExpr] ... = ... +# 10| 0: [ParameterAccess] access to parameter target +# 10| 1: [DelegateCall] delegate call +# 10| -1: [ParameterAccess] access to parameter valueFactory +# 12| 9: [Method] M1 +# 12| -1: [TypeMention] Void +#-----| 2: (Parameters) +# 12| 0: [Parameter] state +# 12| -1: [TypeMention] object +# 13| 4: [BlockStmt] {...} NullCoalescingAssignment.cs: # 3| [Class] NullCoalescingAssignment # 5| 5: [Method] NullCoalescing From 42d2a673c7023b546909cafb2e24d4ee9b425cb9 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 26 Feb 2021 10:06:05 +0100 Subject: [PATCH 071/142] C++: Respond to review comments. --- cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted-bad.c | 7 +++---- cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted-good.c | 7 +++---- cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.qhelp | 4 ++++ 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted-bad.c b/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted-bad.c index 514b23241c9..ac74314eefa 100644 --- a/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted-bad.c +++ b/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted-bad.c @@ -1,4 +1,3 @@ -char * password = malloc(PASSWORD_SIZE); -// ... read and check password -memset(password, 0, PASSWORD_SIZE); -free(password); +char password[MAX_PASSWORD_LENGTH]; +// read and verify password +memset(password, 0, MAX_PASSWORD_LENGTH); diff --git a/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted-good.c b/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted-good.c index 3d6628bf060..2e72f553a4e 100644 --- a/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted-good.c +++ b/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted-good.c @@ -1,4 +1,3 @@ -char * password = malloc(PASSWORD_SIZE); -// ... read and check password -memset_s(password, PASSWORD_SIZE, 0, PASSWORD_SIZE); -free(password); +char password[MAX_PASSWORD_LENGTH]; +// read and verify password +memset_s(password, MAX_PASSWORD_LENGTH, 0, MAX_PASSWORD_LENGTH); diff --git a/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.qhelp b/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.qhelp index 9cd1fd14143..9ef348cc4b5 100644 --- a/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.qhelp +++ b/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.qhelp @@ -36,6 +36,10 @@ longer needed:

    CERT C Coding Standard: MSC06-C. Beware of compiler optimizations. +
  • +USENIX: The Advanced Computing Systems Association: +Dead Store Elimination (Still) Considered Harmfuls +
  • From 1cac692b1d080e548befa7400f0785568a3acbc6 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 26 Feb 2021 10:23:01 +0100 Subject: [PATCH 072/142] Update javascript/ql/src/semmle/javascript/TypeScript.qll Co-authored-by: Asger F --- javascript/ql/src/semmle/javascript/TypeScript.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/TypeScript.qll b/javascript/ql/src/semmle/javascript/TypeScript.qll index 6fd72d06001..4fe263c8389 100644 --- a/javascript/ql/src/semmle/javascript/TypeScript.qll +++ b/javascript/ql/src/semmle/javascript/TypeScript.qll @@ -2150,7 +2150,7 @@ class TupleType extends ArrayType, @tuple_type { /** * Gets the index of the rest element. - * E.g. for a type `[number, ...string[]]` the result is 1, + * For example, for a type `[number, ...string[]]` the result is 1, * or for a type `[...number[], string]` the result is 0. */ int getRestElementIndex() { tuple_type_rest_index(this, result) } From bd19d5a93cf53b2799d3d1628d036efb3fd409cb Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 26 Feb 2021 10:24:40 +0100 Subject: [PATCH 073/142] remove is_abstract_signature.ql --- .../is_abstract_signature.ql | 3 --- .../upgrade.properties | 1 - 2 files changed, 4 deletions(-) delete mode 100644 javascript/upgrades/930898a4fe07cb48de46800904922ca118b31e50/is_abstract_signature.ql diff --git a/javascript/upgrades/930898a4fe07cb48de46800904922ca118b31e50/is_abstract_signature.ql b/javascript/upgrades/930898a4fe07cb48de46800904922ca118b31e50/is_abstract_signature.ql deleted file mode 100644 index a5e5c7c8f11..00000000000 --- a/javascript/upgrades/930898a4fe07cb48de46800904922ca118b31e50/is_abstract_signature.ql +++ /dev/null @@ -1,3 +0,0 @@ -from int a, int b -where none() -select a, b diff --git a/javascript/upgrades/930898a4fe07cb48de46800904922ca118b31e50/upgrade.properties b/javascript/upgrades/930898a4fe07cb48de46800904922ca118b31e50/upgrade.properties index 82e10769eb9..9161fbb608f 100644 --- a/javascript/upgrades/930898a4fe07cb48de46800904922ca118b31e50/upgrade.properties +++ b/javascript/upgrades/930898a4fe07cb48de46800904922ca118b31e50/upgrade.properties @@ -2,4 +2,3 @@ description: add support for TypeScript 4.2 compatibility: backwards tuple_type_rest_index.rel: run tuple_type_rest_index.qlo tuple_type_rest.rel: delete -is_abstract_signature: run is_abstract_signature.qlo \ No newline at end of file From 4ec3289ecc7a8c3f93d169098fb458c88de6be64 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 26 Feb 2021 10:26:08 +0100 Subject: [PATCH 074/142] update relation name in .stats file --- javascript/ql/src/semmlecode.javascript.dbscheme.stats | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmlecode.javascript.dbscheme.stats b/javascript/ql/src/semmlecode.javascript.dbscheme.stats index f65c0fe46b9..2f9e3c60388 100644 --- a/javascript/ql/src/semmlecode.javascript.dbscheme.stats +++ b/javascript/ql/src/semmlecode.javascript.dbscheme.stats @@ -15902,7 +15902,7 @@ -tuple_type_rest +tuple_type_rest_index 100 From 00cfc77fc089fc2b8b760c29fe64f96fa2a48f63 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 26 Feb 2021 10:28:20 +0100 Subject: [PATCH 075/142] Revert "fix file lookup for exclude patterns" This reverts commit 74630b0fd8f78436d4ba76b3ae78237ae5900149. --- javascript/extractor/src/com/semmle/js/extractor/Main.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/extractor/src/com/semmle/js/extractor/Main.java b/javascript/extractor/src/com/semmle/js/extractor/Main.java index 0450366043e..2e80bd4d4a9 100644 --- a/javascript/extractor/src/com/semmle/js/extractor/Main.java +++ b/javascript/extractor/src/com/semmle/js/extractor/Main.java @@ -344,7 +344,7 @@ public class Main { for (String pattern : ap.getZeroOrMore(P_EXCLUDE)) addPathPattern(excludes, System.getProperty("user.dir"), pattern); for (String excl : ap.getZeroOrMore(P_EXCLUDE_PATH)) { - File exclFile = new File(new File(System.getProperty("user.dir")), excl).getAbsoluteFile(); + File exclFile = new File(excl).getAbsoluteFile(); String base = exclFile.getParent(); for (String pattern : NEWLINE.split(new WholeIO().strictread(exclFile))) addPathPattern(excludes, base, pattern); From c59e6fef80949a437f69427a091ab52ae01ac595 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 26 Feb 2021 10:54:46 +0100 Subject: [PATCH 076/142] add model for form-data --- .../change-notes/2021-02-26-form-data.md | 4 +++ .../javascript/frameworks/ClientRequests.qll | 20 ++++++++++++++ .../ClientRequests/ClientRequests.expected | 11 ++++++++ .../frameworks/ClientRequests/tst.js | 26 ++++++++++++++++++- 4 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 javascript/change-notes/2021-02-26-form-data.md diff --git a/javascript/change-notes/2021-02-26-form-data.md b/javascript/change-notes/2021-02-26-form-data.md new file mode 100644 index 00000000000..00ad017fad1 --- /dev/null +++ b/javascript/change-notes/2021-02-26-form-data.md @@ -0,0 +1,4 @@ +lgtm,codescanning +* URIs used in the form-data library are now recognized as sinks for `js/request-forgery`. + Affected packages are + [form-data](https://www.npmjs.com/package/form-data) \ No newline at end of file diff --git a/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll b/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll index ebfdc874f64..451ad3f24d2 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/ClientRequests.qll @@ -854,4 +854,24 @@ module ClientRequest { override DataFlow::Node getADataNode() { none() } } } + + /** + * A model of a URL request made using [form-data](https://www.npmjs.com/package/form-data). + */ + class FormDataRequest extends ClientRequest::Range, API::InvokeNode { + API::Node form; + + FormDataRequest() { + form = API::moduleImport("form-data").getInstance() and + this = form.getMember("submit").getACall() + } + + override DataFlow::Node getUrl() { result = getArgument(0) } + + override DataFlow::Node getHost() { result = getParameter(0).getMember("host").getARhs() } + + override DataFlow::Node getADataNode() { + result = form.getMember("append").getACall().getParameter(1).getARhs() + } + } } diff --git a/javascript/ql/test/library-tests/frameworks/ClientRequests/ClientRequests.expected b/javascript/ql/test/library-tests/frameworks/ClientRequests/ClientRequests.expected index 47c340f7a8e..dcd76c5a68d 100644 --- a/javascript/ql/test/library-tests/frameworks/ClientRequests/ClientRequests.expected +++ b/javascript/ql/test/library-tests/frameworks/ClientRequests/ClientRequests.expected @@ -76,6 +76,9 @@ test_ClientRequest | tst.js:229:5:229:67 | needle( ... ptions) | | tst.js:231:5:233:6 | needle. ... \\n }) | | tst.js:235:5:237:6 | needle. ... \\n }) | +| tst.js:247:24:247:68 | request ... o.png') | +| tst.js:249:1:251:2 | form.su ... e();\\n}) | +| tst.js:257:1:262:2 | form.su ... rs()\\n}) | test_getADataNode | tst.js:53:5:53:23 | axios({data: data}) | tst.js:53:18:53:21 | data | | tst.js:57:5:57:39 | axios.p ... data2}) | tst.js:57:19:57:23 | data1 | @@ -110,12 +113,17 @@ test_getADataNode | tst.js:229:5:229:67 | needle( ... ptions) | tst.js:229:50:229:57 | "MyData" | | tst.js:235:5:237:6 | needle. ... \\n }) | tst.js:228:32:228:70 | { 'X-Cu ... tuna' } | | tst.js:235:5:237:6 | needle. ... \\n }) | tst.js:235:44:235:49 | "data" | +| tst.js:249:1:251:2 | form.su ... e();\\n}) | tst.js:245:25:245:34 | 'my value' | +| tst.js:249:1:251:2 | form.su ... e();\\n}) | tst.js:246:26:246:43 | Buffer.from("foo") | +| tst.js:249:1:251:2 | form.su ... e();\\n}) | tst.js:247:24:247:68 | request ... o.png') | +| tst.js:257:1:262:2 | form.su ... rs()\\n}) | tst.js:255:25:255:35 | 'new_value' | test_getHost | tst.js:87:5:87:39 | http.ge ... host}) | tst.js:87:34:87:37 | host | | tst.js:89:5:89:23 | axios({host: host}) | tst.js:89:18:89:21 | host | | tst.js:91:5:91:34 | got(rel ... host}) | tst.js:91:29:91:32 | host | | tst.js:93:5:93:35 | net.req ... host }) | tst.js:93:29:93:32 | host | | tst.js:219:5:219:41 | data.so ... Host"}) | tst.js:219:32:219:39 | "myHost" | +| tst.js:257:1:262:2 | form.su ... rs()\\n}) | tst.js:259:11:259:23 | 'example.org' | test_getUrl | apollo.js:5:18:5:78 | new cre ... hql' }) | apollo.js:5:44:5:75 | 'https: ... raphql' | | apollo.js:10:1:10:54 | new Htt ... hql' }) | apollo.js:10:21:10:51 | 'http:/ ... raphql' | @@ -199,6 +207,9 @@ test_getUrl | tst.js:229:5:229:67 | needle( ... ptions) | tst.js:229:20:229:47 | "http:/ ... oo/bar" | | tst.js:231:5:233:6 | needle. ... \\n }) | tst.js:231:16:231:35 | "http://example.org" | | tst.js:235:5:237:6 | needle. ... \\n }) | tst.js:235:17:235:41 | "http:/ ... g/post" | +| tst.js:247:24:247:68 | request ... o.png') | tst.js:247:32:247:67 | 'http:/ ... go.png' | +| tst.js:249:1:251:2 | form.su ... e();\\n}) | tst.js:249:13:249:33 | 'http:/ ... e.org/' | +| tst.js:257:1:262:2 | form.su ... rs()\\n}) | tst.js:257:13:262:1 | {\\n m ... ers()\\n} | test_getAResponseDataNode | tst.js:19:5:19:23 | requestPromise(url) | tst.js:19:5:19:23 | requestPromise(url) | text | true | | tst.js:21:5:21:23 | superagent.get(url) | tst.js:21:5:21:23 | superagent.get(url) | stream | true | diff --git a/javascript/ql/test/library-tests/frameworks/ClientRequests/tst.js b/javascript/ql/test/library-tests/frameworks/ClientRequests/tst.js index a24a0dca791..a843743e53d 100644 --- a/javascript/ql/test/library-tests/frameworks/ClientRequests/tst.js +++ b/javascript/ql/test/library-tests/frameworks/ClientRequests/tst.js @@ -235,4 +235,28 @@ const needle = require("needle"); needle.post("http://example.org/post", "data", options, (err, resp, body) => { }); -})(); \ No newline at end of file +})(); + +var FormData = require('form-data'); +var request = require('request'); + +var form = new FormData(); + +form.append('my_field', 'my value'); +form.append('my_buffer', Buffer.from("foo")); +form.append('my_logo', request('http://example.org/images/logo.png')); + +form.submit('http://example.org/', (err, res) => { + res.resume(); +}); + + +var form = new FormData(); +form.append('new_form', 'new_value'); + +form.submit({ + method: 'post', + host: 'example.org', + path: '/upload', + headers: form.getHeaders() +}); \ No newline at end of file From 602f63ad458531606ca08be1a1fbb46d51f3a766 Mon Sep 17 00:00:00 2001 From: Porcupiney Hairs Date: Sat, 5 Sep 2020 20:15:50 +0530 Subject: [PATCH 077/142] [Java] Add QL for detecting Spring View Manipulation Vulnerabilities. --- .../SpringImplicitViewManipulation.qhelp | 4 + .../CWE-094/SpringImplicitViewManipulation.ql | 64 +++++++++ .../Security/CWE/CWE-094/SpringViewBad.java | 17 +++ .../Security/CWE/CWE-094/SpringViewGood.java | 20 +++ .../CWE/CWE-094/SpringViewManipulation.qhelp | 50 +++++++ .../CWE/CWE-094/SpringViewManipulation.ql | 21 +++ .../CWE/CWE-094/SpringViewManipulationLib.qll | 123 ++++++++++++++++++ .../semmle/code/java/dataflow/FlowSources.qll | 16 +++ .../frameworks/spring/SpringController.qll | 5 + .../code/java/frameworks/spring/SpringWeb.qll | 16 +++ 10 files changed, 336 insertions(+) create mode 100644 java/ql/src/experimental/Security/CWE/CWE-094/SpringImplicitViewManipulation.qhelp create mode 100644 java/ql/src/experimental/Security/CWE/CWE-094/SpringImplicitViewManipulation.ql create mode 100644 java/ql/src/experimental/Security/CWE/CWE-094/SpringViewBad.java create mode 100644 java/ql/src/experimental/Security/CWE/CWE-094/SpringViewGood.java create mode 100644 java/ql/src/experimental/Security/CWE/CWE-094/SpringViewManipulation.qhelp create mode 100644 java/ql/src/experimental/Security/CWE/CWE-094/SpringViewManipulation.ql create mode 100644 java/ql/src/experimental/Security/CWE/CWE-094/SpringViewManipulationLib.qll diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/SpringImplicitViewManipulation.qhelp b/java/ql/src/experimental/Security/CWE/CWE-094/SpringImplicitViewManipulation.qhelp new file mode 100644 index 00000000000..ffacd8f8b03 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/SpringImplicitViewManipulation.qhelp @@ -0,0 +1,4 @@ + + + + diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/SpringImplicitViewManipulation.ql b/java/ql/src/experimental/Security/CWE/CWE-094/SpringImplicitViewManipulation.ql new file mode 100644 index 00000000000..e4ec03ed956 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/SpringImplicitViewManipulation.ql @@ -0,0 +1,64 @@ +/** + * @name Spring Implicit View Manipulation + * @description Untrusted input in a Spring View Controller can lead to RCE. + * @kind problem + * @problem.severity error + * @precision high + * @id java/spring-view-manipulation-implicit + * @tags security + * external/cwe/cwe-094 + */ + +import java +import SpringViewManipulationLib + +private predicate canResultInImplicitViewConversion(Method m) { + m.getReturnType() instanceof VoidType + or + m.getReturnType() instanceof MapType + or + m.getReturnType().(RefType).hasQualifiedName("org.springframework.ui", "Model") +} + +private predicate maybeATestMethod(Method m) { + exists(string s | + s = m.getName() or + s = m.getFile().getRelativePath() or + s = m.getDeclaringType().getName() + | + s.matches(["%test%", "%example%", "%exception%"]) + ) +} + +private predicate mayBeExploitable(Method m) { + // There should be a attacker controlled parameter in the URI for the attack to be exploitable. + // This is possible only when there exists a parameter with the Spring `@PathVariable` annotation + // applied to it. + exists(Parameter p | + p = m.getAParameter() and + p.hasAnnotation("org.springframework.web.bind.annotation", "PathVariable") and + // Having a parameter of say type `Long` is non exploitable as Java type + // checking rules are applied prior to view name resolution, rendering the exploit useless. + // hence, here we check for the param type to be a Java `String`. + p.getType() instanceof TypeString and + // Exclude cases where a regex check is applied on a parameter to prevent false positives. + not m.(SpringRequestMappingMethod).getValue().matches("%{%:[%]%}%") + ) and + not maybeATestMethod(m) +} + +from SpringRequestMappingMethod m +where + thymeleafIsUsed() and + mayBeExploitable(m) and + canResultInImplicitViewConversion(m) and + // If there's a parameter of type`HttpServletResponse`, Spring Framework does not interpret + // it as a view name, but just returns this string in HTTP Response preventing exploitation + // This also applies to `@ResponseBody` annotation. + not m.getParameterType(_) instanceof HttpServletResponse and + // A spring request mapping method which does not have response body annotation applied to it + m.getAnAnnotation().getType() instanceof SpringRequestMappingAnnotationType and + not exists(SpringResponseBodyAnnotationType t | t = m.getAnAnnotation().getType()) and + // `@RestController` inherits `@ResponseBody` internally so it should be ignored. + not m.getDeclaringType() instanceof SpringRestController +select m, "This method may be vulnerable to spring view manipulation vulnerabilities" diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/SpringViewBad.java b/java/ql/src/experimental/Security/CWE/CWE-094/SpringViewBad.java new file mode 100644 index 00000000000..bb8121f7b11 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/SpringViewBad.java @@ -0,0 +1,17 @@ +@Controller +public class SptingViewManipulationController { + + Logger log = LoggerFactory.getLogger(HelloController.class); + + @GetMapping("/safe/fragment") + public String Fragment(@RequestParam String section) { + // bad as template path is attacker controlled + return "welcome :: " + section; + } + + @GetMapping("/doc/{document}") + public void getDocument(@PathVariable String document) { + // returns void, so view name is taken from URI + log.info("Retrieving " + document); + } +} diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/SpringViewGood.java b/java/ql/src/experimental/Security/CWE/CWE-094/SpringViewGood.java new file mode 100644 index 00000000000..046150cae95 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/SpringViewGood.java @@ -0,0 +1,20 @@ +@Controller +public class SptingViewManipulationController { + + Logger log = LoggerFactory.getLogger(HelloController.class); + + @GetMapping("/safe/fragment") + @ResponseBody + public String Fragment(@RequestParam String section) { + // good, as `@ResponseBody` annotation tells Spring + // to process the return values as body, instead of view name + return "welcome :: " + section; + } + + @GetMapping("/safe/doc/{document}") + public void getDocument(@PathVariable String document, HttpServletResponse response) { + // good as `HttpServletResponse param tells Spring that the response is already + // processed. + log.info("Retrieving " + document); // FP + } +} diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/SpringViewManipulation.qhelp b/java/ql/src/experimental/Security/CWE/CWE-094/SpringViewManipulation.qhelp new file mode 100644 index 00000000000..dadd20dfdb7 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/SpringViewManipulation.qhelp @@ -0,0 +1,50 @@ + + + + +

    + The Spring Expression Language (SpEL) is a powerful expression language + provided by Spring Framework. The language offers many features + including invocation of methods available in the JVM. +

    +

    + An unrestricted view name manipulation vulnerability in Spring Framework could lead to attacker-controlled arbitary SpEL expressions being evaluated using attacker-controlled data, which may in turn allow an attacker to run arbitrary code. +

    +

    + Note: two related variants of this problem are detected by different queries, `java/spring-view-manipulation` and `java/spring-view-manipulation-implicit`. The first detects taint flow problems where the return types is always String. While the latter, `java/spring-view-manipulation-implicit` detects cases where the request mapping method has a non-string return type such as void. +

    +
    + + +

    + In general, using user input to determine Spring view name should be avoided. + If user input must be included in the expression, the controller can be annotated by + a @ReponseBody annotation. In this case, Spring Framework does not interpret + it as a view name, but just returns this string in HTTP Response. The same applies to using + a @RestController annotation on a class, as internally it inherits @ResponseBody. +

    +
    + + +

    + In the following example, the Fragment method uses an externally controlled variable section to generate the view name. Hence, it is vulnerable to Spring View Manipulation attacks. +

    + +

    + This can be easily prevented by using the ResponseBody annotation which marks the reponse is already processed preventing exploitation of Spring View Manipulation vulnerabilities. Alternatively, this can also be fixed by adding a HttpServletResponse parameter to the method definition as shown in the example below. +

    + +
    + + +
  • + Veracode Research : Spring View Manipulation +
  • +
  • + Spring Framework Reference Documentation: Spring Expression Language (SpEL) +
  • +
  • + OWASP: Expression Language Injection +
  • +
    +
    diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/SpringViewManipulation.ql b/java/ql/src/experimental/Security/CWE/CWE-094/SpringViewManipulation.ql new file mode 100644 index 00000000000..3c490e6bf68 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/SpringViewManipulation.ql @@ -0,0 +1,21 @@ +/** + * @name Spring View Manipulation + * @description Untrusted input in a Spring View can lead to RCE. + * @kind path-problem + * @problem.severity error + * @precision high + * @id java/spring-view-manipulation + * @tags security + * external/cwe/cwe-094 + */ + +import java +import SpringViewManipulationLib +import DataFlow::PathGraph + +from DataFlow::PathNode source, DataFlow::PathNode sink, SpringViewManipulationConfig conf +where + thymeleafIsUsed() and + conf.hasFlowPath(source, sink) +select sink.getNode(), source, sink, "Potential Spring Expression Language injection from $@.", + source.getNode(), "this user input" diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/SpringViewManipulationLib.qll b/java/ql/src/experimental/Security/CWE/CWE-094/SpringViewManipulationLib.qll new file mode 100644 index 00000000000..b03fefbc366 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-094/SpringViewManipulationLib.qll @@ -0,0 +1,123 @@ +/** + * Provides classes for reasoning about Spring View Manipulation vulnerabilities + */ + +import java +import semmle.code.java.dataflow.FlowSources +import semmle.code.java.dataflow.TaintTracking +import semmle.code.java.frameworks.spring.Spring +import SpringFrameworkLib + +/** Holds if `Thymeleaf` templating engine is used in the project. */ +predicate thymeleafIsUsed() { + exists(Pom p | + p.getADependency().getArtifact().getValue() in [ + "spring-boot-starter-thymeleaf", "thymeleaf-spring4", "springmvc-xml-thymeleaf", + "thymeleaf-spring5" + ] + ) + or + exists(SpringBean b | b.getClassNameRaw().matches("org.thymeleaf.spring%")) +} + +/** + * A taint-tracking configuration for unsafe user input + * that can lead to Spring View Manipulation vulnerabilities. + */ +class SpringViewManipulationConfig extends TaintTracking::Configuration { + SpringViewManipulationConfig() { this = "Spring View Manipulation Config" } + + override predicate isSource(DataFlow::Node source) { + source instanceof RemoteFlowSource or + source instanceof WebRequestSource + } + + override predicate isSink(DataFlow::Node sink) { sink instanceof SpringViewManipulationSink } + + override predicate isSanitizer(DataFlow::Node node) { + // Block flows like + // ``` + // a = "redirect:" + taint` + // ``` + exists(AddExpr e, StringLiteral sl | + node.asExpr() = e.getControlFlowNode().getASuccessor*() and + sl = e.getLeftOperand*() and + sl.getRepresentedString().matches(["redirect:%", "ajaxredirect:%", "forward:%"]) + ) + or + // Block flows like + // ``` + // x.append("redirect:"); + // x.append(tainted()); + // return x.toString(); + // + // "redirect:".concat(taint) + // + // String.format("redirect:%s",taint); + // ``` + exists(Call ca, StringLiteral sl | + ( + sl = ca.getArgument(_) + or + sl = ca.getQualifier() + ) and + ca = getAStringCombiningCall() and + sl.getRepresentedString().matches(["redirect:%", "ajaxredirect:%", "forward:%"]) + | + exists(Call cc | DataFlow::localExprFlow(ca.getQualifier(), cc.getQualifier()) | + cc = node.asExpr() + ) + ) + } +} + +private Call getAStringCombiningCall() { + exists(StringCombiningMethod m | result = m.getAReference()) +} + +abstract private class StringCombiningMethod extends Method { } + +private class AppendableAppendMethod extends StringCombiningMethod { + AppendableAppendMethod() { + exists(RefType t | + t.hasQualifiedName("java.lang", "Appendable") and + this.getDeclaringType().extendsOrImplements*(t) and + this.hasName("append") + ) + } +} + +private class StringConcatMethod extends StringCombiningMethod { + StringConcatMethod() { + this.getDeclaringType() instanceof TypeString and + this.hasName("concat") + } +} + +private class StringFormatMethod extends StringCombiningMethod { + StringFormatMethod() { + this.getDeclaringType() instanceof TypeString and + this.hasName("format") + } +} + +/** + * A sink for Spring View Manipulation vulnerabilities, + */ +class SpringViewManipulationSink extends DataFlow::ExprNode { + SpringViewManipulationSink() { + exists(ReturnStmt r, SpringRequestMappingMethod m | + r.getResult() = this.asExpr() and + m.getBody().getAStmt() = r and + not m.isResponseBody() and + r.getResult().getType() instanceof TypeString + ) + or + exists(ConstructorCall c | c.getConstructedType() instanceof ModelAndView | + this.asExpr() = c.getArgument(0) and + c.getConstructor().getParameterType(0) instanceof TypeString + ) + or + exists(SpringModelAndViewSetViewNameCall c | this.asExpr() = c.getArgument(0)) + } +} diff --git a/java/ql/src/semmle/code/java/dataflow/FlowSources.qll b/java/ql/src/semmle/code/java/dataflow/FlowSources.qll index b4235cb2635..67e67289c4a 100644 --- a/java/ql/src/semmle/code/java/dataflow/FlowSources.qll +++ b/java/ql/src/semmle/code/java/dataflow/FlowSources.qll @@ -256,6 +256,7 @@ private class RemoteTaintedMethod extends Method { this instanceof ServletRequestGetParameterMethod or this instanceof ServletRequestGetParameterMapMethod or this instanceof ServletRequestGetParameterNamesMethod or + this instanceof PortletRenderRequestGetParameterMethod or this instanceof HttpServletRequestGetQueryStringMethod or this instanceof HttpServletRequestGetHeaderMethod or this instanceof HttpServletRequestGetPathMethod or @@ -308,6 +309,21 @@ class EnvReadMethod extends Method { } } +private class PortletRenderRequestGetParameterMethod extends Method { + PortletRenderRequestGetParameterMethod() { + exists(RefType c, Interface t | + c.extendsOrImplements*(t) and + t.hasQualifiedName("javax.portlet", "RenderState") and + this = c.getAMethod() + | + this.hasName([ + "getCookies", "getParameter", "getRenderParameters", "getParameterNames", + "getParameterValues", "getParameterMap" + ]) + ) + } +} + /** The type `java.net.InetAddress`. */ class TypeInetAddr extends RefType { TypeInetAddr() { this.getQualifiedName() = "java.net.InetAddress" } diff --git a/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll b/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll index 3abf325dfa2..f935a4803a9 100644 --- a/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll +++ b/java/ql/src/semmle/code/java/frameworks/spring/SpringController.qll @@ -126,6 +126,11 @@ class SpringRequestMappingMethod extends SpringControllerMethod { requestMappingAnnotation.getValue("produces").(CompileTimeConstantExpr).getStringValue() } + /** Gets the "value" @RequestMapping annotation value, if present. */ + string getValue() { + result = requestMappingAnnotation.getValue("value").(CompileTimeConstantExpr).getStringValue() + } + /** Holds if this is considered an `@ResponseBody` method. */ predicate isResponseBody() { getAnAnnotation().getType() instanceof SpringResponseBodyAnnotationType or diff --git a/java/ql/src/semmle/code/java/frameworks/spring/SpringWeb.qll b/java/ql/src/semmle/code/java/frameworks/spring/SpringWeb.qll index 4a71c71295e..ad4e00959dc 100644 --- a/java/ql/src/semmle/code/java/frameworks/spring/SpringWeb.qll +++ b/java/ql/src/semmle/code/java/frameworks/spring/SpringWeb.qll @@ -17,3 +17,19 @@ class SpringNativeWebRequest extends Class { this.hasQualifiedName("org.springframework.web.context.request", "NativeWebRequest") } } + +/** Models Spring `servlet` as well as `portlet` package's `ModelAndView` class. */ +class ModelAndView extends Class { + ModelAndView() { + hasQualifiedName(["org.springframework.web.servlet", "org.springframework.web.portlet"], + "ModelAndView") + } +} + +/** Models a call to the Spring `ModelAndView` class's `setViewName` method. */ +class SpringModelAndViewSetViewNameCall extends MethodAccess { + SpringModelAndViewSetViewNameCall() { + getMethod().getDeclaringType() instanceof ModelAndView and + getMethod().hasName("setViewName") + } +} From 42a84a18b01fd2860c5c4594328cb33688f3142d Mon Sep 17 00:00:00 2001 From: Porcupiney Hairs Date: Sun, 12 Jul 2020 03:45:15 +0530 Subject: [PATCH 078/142] JAVA : Add query to detect Apache Structs enabled DEvmode This query detects cases where the development mode is enabled for a struts configuration. I can't find a CVE per se but, at present, [Github's fuzzy search](https://github.com/search?q=%3Cconstant+name%3D%22struts.devMode%22+value%3D%22true%22+%2F%3E+language%3Axml&type=Code) returns more than 44000 results. Some of them look like they are classroom projects, so they may be ineligible for a CVE. But we should be flagging them anyways as setting the development on in a production system is a very bad practice and can often lead to remote code execution. So these should be fixed anyways. --- .../Security/CWE/CWE-489/StrutsBad.xml | 11 +++++ .../Security/CWE/CWE-489/StrutsGood.xml | 11 +++++ .../Security/CWE/CWE-489/devMode.qhelp | 32 +++++++++++++++ .../Security/CWE/CWE-489/devMode.ql | 24 +++++++++++ .../semmle/code/xml/StrutsXML.qll | 41 +++++++++++++++++++ .../security/CWE-489/StrutsBad.xml | 11 +++++ .../security/CWE-489/StrutsGood.xml | 11 +++++ .../security/CWE-489/devMode.expected | 1 + .../security/CWE-489/devMode.qlref | 1 + 9 files changed, 143 insertions(+) create mode 100644 java/ql/src/experimental/Security/CWE/CWE-489/StrutsBad.xml create mode 100644 java/ql/src/experimental/Security/CWE/CWE-489/StrutsGood.xml create mode 100644 java/ql/src/experimental/Security/CWE/CWE-489/devMode.qhelp create mode 100644 java/ql/src/experimental/Security/CWE/CWE-489/devMode.ql create mode 100644 java/ql/src/experimental/semmle/code/xml/StrutsXML.qll create mode 100644 java/ql/test/experimental/query-tests/security/CWE-489/StrutsBad.xml create mode 100644 java/ql/test/experimental/query-tests/security/CWE-489/StrutsGood.xml create mode 100644 java/ql/test/experimental/query-tests/security/CWE-489/devMode.expected create mode 100644 java/ql/test/experimental/query-tests/security/CWE-489/devMode.qlref diff --git a/java/ql/src/experimental/Security/CWE/CWE-489/StrutsBad.xml b/java/ql/src/experimental/Security/CWE/CWE-489/StrutsBad.xml new file mode 100644 index 00000000000..64e614cc525 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-489/StrutsBad.xml @@ -0,0 +1,11 @@ + + + + + + + + + diff --git a/java/ql/src/experimental/Security/CWE/CWE-489/StrutsGood.xml b/java/ql/src/experimental/Security/CWE/CWE-489/StrutsGood.xml new file mode 100644 index 00000000000..369b42a7ec9 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-489/StrutsGood.xml @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/java/ql/src/experimental/Security/CWE/CWE-489/devMode.qhelp b/java/ql/src/experimental/Security/CWE/CWE-489/devMode.qhelp new file mode 100644 index 00000000000..14d9b6311b8 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-489/devMode.qhelp @@ -0,0 +1,32 @@ + + + + +

    Turning Apache Struts' development mode configuration on while deploying applications to production environments can lead to remote code execution.

    + +
    + + +

    An application should disable the development mode at the time of deployment.

    + +
    + + +

    The following example shows a `struts.xml` file with `struts.devmode` enabled.

    + + + +

    This can be easily corrected by setting the value of the `struts.devmode` parameter to false.

    + + + +
    + + +
  • + Apache Struts: + Struts development mode configuration +
  • + +
    +
    diff --git a/java/ql/src/experimental/Security/CWE/CWE-489/devMode.ql b/java/ql/src/experimental/Security/CWE/CWE-489/devMode.ql new file mode 100644 index 00000000000..1bbb1b71ab4 --- /dev/null +++ b/java/ql/src/experimental/Security/CWE/CWE-489/devMode.ql @@ -0,0 +1,24 @@ +/** + * @name Apache Struts development mode enabled + * @description Enabling struts development mode in production environment + * can lead to remote code execution. + * @kind problem + * @problem.severity error + * @precision high + * @id java/struts-development-mode + * @tags security + * external/cwe/cwe-489 + */ + +import java +import experimental.semmle.code.xml.StrutsXML + +bindingset[path] +predicate isLikelyDemoProject(string path) { path.regexpMatch("(?i).*(demo|test|example).*") } + +from ConstantParameter c +where + c.getNameValue() = "struts.devMode" and + c.getValueValue() = "true" and + not isLikelyDemoProject(c.getFile().getRelativePath()) +select c, "Enabling development mode in production environments is dangerous" diff --git a/java/ql/src/experimental/semmle/code/xml/StrutsXML.qll b/java/ql/src/experimental/semmle/code/xml/StrutsXML.qll new file mode 100644 index 00000000000..bda7824560c --- /dev/null +++ b/java/ql/src/experimental/semmle/code/xml/StrutsXML.qll @@ -0,0 +1,41 @@ +import java + +/** + * A deployment descriptor file, typically called `struts.xml`. + */ +class StrutsXMLFile extends XMLFile { + StrutsXMLFile() { + count(XMLElement e | e = this.getAChild()) = 1 and + this.getAChild().getName() = "struts" + } +} + +/** + * An XML element in a `StrutsXMLFile`. + */ +class StrutsXMLElement extends XMLElement { + StrutsXMLElement() { this.getFile() instanceof StrutsXMLFile } + + /** + * Gets the value for this element, with leading and trailing whitespace trimmed. + */ + string getValue() { result = allCharactersString().trim() } +} + +/** + * A `` element in a `StrutsXMLFile`. + */ +class ConstantParameter extends StrutsXMLElement { + ConstantParameter() { this.getName() = "constant" } + + /** + * Gets the value of the `name` attribute of this ``. + */ + string getNameValue() { result = getAttributeValue("name") } + + /** + * Gets the value of the `value` attribute of this ``. + */ + string getValueValue() { result = getAttributeValue("value") } + +} diff --git a/java/ql/test/experimental/query-tests/security/CWE-489/StrutsBad.xml b/java/ql/test/experimental/query-tests/security/CWE-489/StrutsBad.xml new file mode 100644 index 00000000000..4ee9c1647cf --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-489/StrutsBad.xml @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-489/StrutsGood.xml b/java/ql/test/experimental/query-tests/security/CWE-489/StrutsGood.xml new file mode 100644 index 00000000000..369b42a7ec9 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-489/StrutsGood.xml @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-489/devMode.expected b/java/ql/test/experimental/query-tests/security/CWE-489/devMode.expected new file mode 100644 index 00000000000..fec3ff3c2c8 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-489/devMode.expected @@ -0,0 +1 @@ +| StrutsBad.xml:8:5:8:52 | constant | Enabling development mode in production environments is dangerous | diff --git a/java/ql/test/experimental/query-tests/security/CWE-489/devMode.qlref b/java/ql/test/experimental/query-tests/security/CWE-489/devMode.qlref new file mode 100644 index 00000000000..da70fb9a6c4 --- /dev/null +++ b/java/ql/test/experimental/query-tests/security/CWE-489/devMode.qlref @@ -0,0 +1 @@ +experimental/Security/CWE/CWE-489/devMode.ql From ae051af9d8127b2422c2ea39a40c8c9aebc30cf6 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Fri, 26 Feb 2021 14:15:30 +0100 Subject: [PATCH 079/142] remove redundant code --- javascript/ql/src/semmle/javascript/frameworks/jQuery.qll | 4 ---- 1 file changed, 4 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/jQuery.qll b/javascript/ql/src/semmle/javascript/frameworks/jQuery.qll index 7987f2edf04..1716917282f 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/jQuery.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/jQuery.qll @@ -590,10 +590,6 @@ module JQuery { read.getBase().getALocalSource() = [dollar(), objectRef()] and read.mayHavePropertyName(name) ) - or - // Handle contributed JQuery objects that aren't source nodes (usually parameter uses) - getReceiver() = legacyObjectSource() and - this.(DataFlow::MethodCallNode).getMethodName() = name } /** From ede1a40a020ac9b9b77007e9423dda71e243ce70 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 25 Feb 2021 14:23:14 +0100 Subject: [PATCH 080/142] add ClientRequst models for http-proxy --- javascript/ql/src/javascript.qll | 1 + .../javascript/frameworks/HttpProxy.qll | 54 +++++++++++++++++++ .../ClientRequests/ClientRequests.expected | 5 ++ .../frameworks/ClientRequests/tst.js | 12 ++++- 4 files changed, 71 insertions(+), 1 deletion(-) create mode 100644 javascript/ql/src/semmle/javascript/frameworks/HttpProxy.qll diff --git a/javascript/ql/src/javascript.qll b/javascript/ql/src/javascript.qll index d83f173071c..8b0996c740c 100644 --- a/javascript/ql/src/javascript.qll +++ b/javascript/ql/src/javascript.qll @@ -94,6 +94,7 @@ import semmle.javascript.frameworks.LazyCache import semmle.javascript.frameworks.LodashUnderscore import semmle.javascript.frameworks.Logging import semmle.javascript.frameworks.HttpFrameworks +import semmle.javascript.frameworks.HttpProxy import semmle.javascript.frameworks.Markdown import semmle.javascript.frameworks.NoSQL import semmle.javascript.frameworks.PkgCloud diff --git a/javascript/ql/src/semmle/javascript/frameworks/HttpProxy.qll b/javascript/ql/src/semmle/javascript/frameworks/HttpProxy.qll new file mode 100644 index 00000000000..039da993a92 --- /dev/null +++ b/javascript/ql/src/semmle/javascript/frameworks/HttpProxy.qll @@ -0,0 +1,54 @@ +/** + * Provides classes and predicates for working with the [http-proxy](https://www.npmjs.com/package/http-proxy) library. + */ + +import javascript + +/** + * Provides classes and predicates modelling the [http-proxy](https://www.npmjs.com/package/http-proxy) library. + */ +private module HttpProxy { + /** + * A call that creates a http proxy. + */ + class CreateServerCall extends API::CallNode, ClientRequest::Range { + CreateServerCall() { + this = + API::moduleImport("http-proxy") + .getMember(["createServer", "createProxyServer", "createProxy"]) + .getACall() + } + + override DataFlow::Node getUrl() { result = getParameter(0).getMember("target").getARhs() } + + override DataFlow::Node getHost() { none() } + + override DataFlow::Node getADataNode() { none() } + } + + /** + * A call that proxies a request to some target. + */ + class ProxyCall extends API::CallNode, ClientRequest::Range { + string method; + + ProxyCall() { + method = ["ws", "web"] and + this = any(CreateServerCall server).getReturn().getMember(method).getACall() + } + + override DataFlow::Node getUrl() { + exists(int optionsIndex | + method = "web" and optionsIndex = 2 + or + method = "ws" and optionsIndex = 3 + | + result = getParameter(optionsIndex).getMember("target").getARhs() + ) + } + + override DataFlow::Node getHost() { none() } + + override DataFlow::Node getADataNode() { none() } + } +} diff --git a/javascript/ql/test/library-tests/frameworks/ClientRequests/ClientRequests.expected b/javascript/ql/test/library-tests/frameworks/ClientRequests/ClientRequests.expected index dcd76c5a68d..15289413bc4 100644 --- a/javascript/ql/test/library-tests/frameworks/ClientRequests/ClientRequests.expected +++ b/javascript/ql/test/library-tests/frameworks/ClientRequests/ClientRequests.expected @@ -79,6 +79,9 @@ test_ClientRequest | tst.js:247:24:247:68 | request ... o.png') | | tst.js:249:1:251:2 | form.su ... e();\\n}) | | tst.js:257:1:262:2 | form.su ... rs()\\n}) | +| tst.js:267:1:267:61 | httpPro ... 9000'}) | +| tst.js:269:13:269:48 | httpPro ... ptions) | +| tst.js:271:3:271:61 | proxy.w ... 080' }) | test_getADataNode | tst.js:53:5:53:23 | axios({data: data}) | tst.js:53:18:53:21 | data | | tst.js:57:5:57:39 | axios.p ... data2}) | tst.js:57:19:57:23 | data1 | @@ -210,6 +213,8 @@ test_getUrl | tst.js:247:24:247:68 | request ... o.png') | tst.js:247:32:247:67 | 'http:/ ... go.png' | | tst.js:249:1:251:2 | form.su ... e();\\n}) | tst.js:249:13:249:33 | 'http:/ ... e.org/' | | tst.js:257:1:262:2 | form.su ... rs()\\n}) | tst.js:257:13:262:1 | {\\n m ... ers()\\n} | +| tst.js:267:1:267:61 | httpPro ... 9000'}) | tst.js:267:37:267:59 | 'http:/ ... t:9000' | +| tst.js:271:3:271:61 | proxy.w ... 080' }) | tst.js:271:33:271:58 | 'http:/ ... m:8080' | test_getAResponseDataNode | tst.js:19:5:19:23 | requestPromise(url) | tst.js:19:5:19:23 | requestPromise(url) | text | true | | tst.js:21:5:21:23 | superagent.get(url) | tst.js:21:5:21:23 | superagent.get(url) | stream | true | diff --git a/javascript/ql/test/library-tests/frameworks/ClientRequests/tst.js b/javascript/ql/test/library-tests/frameworks/ClientRequests/tst.js index a843743e53d..b5a36a84299 100644 --- a/javascript/ql/test/library-tests/frameworks/ClientRequests/tst.js +++ b/javascript/ql/test/library-tests/frameworks/ClientRequests/tst.js @@ -259,4 +259,14 @@ form.submit({ host: 'example.org', path: '/upload', headers: form.getHeaders() -}); \ No newline at end of file +}); + +var httpProxy = require('http-proxy'); +var http = require("http"); + +httpProxy.createProxyServer({target:'http://localhost:9000'}).listen(8000); + +var proxy = httpProxy.createProxyServer(options); +http.createServer(function(req, res) { + proxy.web(req, res, { target: 'http://mytarget.com:8080' }); +}); From cc48172fd8bdd4aec819c29a80165be7f15d0710 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 25 Feb 2021 15:07:34 +0100 Subject: [PATCH 081/142] add support for events in http-proxy --- .../javascript/frameworks/HttpProxy.qll | 37 +++++++++++++++++++ .../frameworks/NodeJSLib/src/http.js | 10 +++++ .../frameworks/NodeJSLib/tests.expected | 12 ++++++ 3 files changed, 59 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/frameworks/HttpProxy.qll b/javascript/ql/src/semmle/javascript/frameworks/HttpProxy.qll index 039da993a92..d30ec1a2946 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/HttpProxy.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/HttpProxy.qll @@ -51,4 +51,41 @@ private module HttpProxy { override DataFlow::Node getADataNode() { none() } } + + /** + * Holds if an event handler for `event` has a HTTP request parameter at `req` and a HTTP response parameter at `res`. + */ + predicate routeHandlingEventHandler(string event, int req, int res) { + event = ["start", "end"] and req = 0 and res = 1 + or + event = ["proxyReq", "proxyRes", "econnreset"] and req = 1 and res = 2 + or + event = "proxyReqWs" and req = 1 and res = -10 // -10 for non-existent. + } + + /** + * An http proxy event handler. + */ + class ProxyListenerCallback extends NodeJSLib::RouteHandler, DataFlow::FunctionNode { + string event; + API::CallNode call; + + ProxyListenerCallback() { + call = any(CreateServerCall server).getReturn().getMember(["on", "once"]).getACall() and + call.getParameter(0).getARhs().mayHaveStringValue(event) and + this = call.getParameter(1).getARhs().getAFunctionValue() + } + + override Parameter getRequestParameter() { + exists(int req | routeHandlingEventHandler(event, req, _) | + result = getFunction().getParameter(req) + ) + } + + override Parameter getResponseParameter() { + exists(int res | routeHandlingEventHandler(event, _, res) | + result = getFunction().getParameter(res) + ) + } + } } diff --git a/javascript/ql/test/library-tests/frameworks/NodeJSLib/src/http.js b/javascript/ql/test/library-tests/frameworks/NodeJSLib/src/http.js index 12dc11efcaf..c5fe90fe571 100644 --- a/javascript/ql/test/library-tests/frameworks/NodeJSLib/src/http.js +++ b/javascript/ql/test/library-tests/frameworks/NodeJSLib/src/http.js @@ -73,4 +73,14 @@ http.createServer(function (req, res) { req.on("data", chunk => { // RemoteFlowSource res.send(chunk); }) +}); + +var httpProxy = require('http-proxy'); +var proxy = httpProxy.createProxyServer({}); + +proxy.on('proxyReq', function(proxyReq, req, res, options) { + req.on("data", chunk => { // RemoteFlowSource + res.send(chunk); + }); + res.end("bla"); }); \ No newline at end of file diff --git a/javascript/ql/test/library-tests/frameworks/NodeJSLib/tests.expected b/javascript/ql/test/library-tests/frameworks/NodeJSLib/tests.expected index c80b0059cb6..7835e0280ef 100644 --- a/javascript/ql/test/library-tests/frameworks/NodeJSLib/tests.expected +++ b/javascript/ql/test/library-tests/frameworks/NodeJSLib/tests.expected @@ -56,6 +56,9 @@ test_ResponseExpr | src/http.js:68:17:68:19 | res | src/http.js:68:12:68:27 | (req,res) => f() | | src/http.js:72:34:72:36 | res | src/http.js:72:19:76:1 | functio ... \\n })\\n} | | src/http.js:74:5:74:7 | res | src/http.js:72:19:76:1 | functio ... \\n })\\n} | +| src/http.js:81:46:81:48 | res | src/http.js:81:22:86:1 | functio ... la");\\n} | +| src/http.js:83:5:83:7 | res | src/http.js:81:22:86:1 | functio ... la");\\n} | +| src/http.js:85:3:85:5 | res | src/http.js:81:22:86:1 | functio ... la");\\n} | | src/https.js:4:47:4:49 | res | src/https.js:4:33:10:1 | functio ... .foo;\\n} | | src/https.js:7:3:7:5 | res | src/https.js:4:33:10:1 | functio ... .foo;\\n} | | src/https.js:12:34:12:36 | res | src/https.js:12:20:16:1 | functio ... ar");\\n} | @@ -150,6 +153,9 @@ test_RouteHandler_getAResponseExpr | src/http.js:68:12:68:27 | (req,res) => f() | src/http.js:68:17:68:19 | res | | src/http.js:72:19:76:1 | functio ... \\n })\\n} | src/http.js:72:34:72:36 | res | | src/http.js:72:19:76:1 | functio ... \\n })\\n} | src/http.js:74:5:74:7 | res | +| src/http.js:81:22:86:1 | functio ... la");\\n} | src/http.js:81:46:81:48 | res | +| src/http.js:81:22:86:1 | functio ... la");\\n} | src/http.js:83:5:83:7 | res | +| src/http.js:81:22:86:1 | functio ... la");\\n} | src/http.js:85:3:85:5 | res | | src/https.js:4:33:10:1 | functio ... .foo;\\n} | src/https.js:4:47:4:49 | res | | src/https.js:4:33:10:1 | functio ... .foo;\\n} | src/https.js:7:3:7:5 | res | | src/https.js:12:20:16:1 | functio ... ar");\\n} | src/https.js:12:34:12:36 | res | @@ -189,6 +195,7 @@ test_ResponseSendArgument | src/http.js:14:13:14:17 | "foo" | src/http.js:12:19:16:1 | functio ... ar");\\n} | | src/http.js:15:11:15:15 | "bar" | src/http.js:12:19:16:1 | functio ... ar");\\n} | | src/http.js:64:11:64:16 | "bar2" | src/http.js:62:19:65:1 | functio ... r2");\\n} | +| src/http.js:85:11:85:15 | "bla" | src/http.js:81:22:86:1 | functio ... la");\\n} | | src/https.js:14:13:14:17 | "foo" | src/https.js:12:20:16:1 | functio ... ar");\\n} | | src/https.js:15:11:15:15 | "bar" | src/https.js:12:20:16:1 | functio ... ar");\\n} | | src/indirect.js:26:13:26:17 | "foo" | src/indirect.js:25:24:27:3 | (req, r ... ");\\n } | @@ -235,6 +242,7 @@ test_RemoteFlowSources | src/http.js:40:23:40:30 | authInfo | | src/http.js:45:23:45:27 | error | | src/http.js:73:18:73:22 | chunk | +| src/http.js:82:18:82:22 | chunk | | src/https.js:6:26:6:32 | req.url | | src/https.js:8:3:8:20 | req.headers.cookie | | src/https.js:9:3:9:17 | req.headers.foo | @@ -273,6 +281,8 @@ test_RequestExpr | src/http.js:68:13:68:15 | req | src/http.js:68:12:68:27 | (req,res) => f() | | src/http.js:72:29:72:31 | req | src/http.js:72:19:76:1 | functio ... \\n })\\n} | | src/http.js:73:3:73:5 | req | src/http.js:72:19:76:1 | functio ... \\n })\\n} | +| src/http.js:81:41:81:43 | req | src/http.js:81:22:86:1 | functio ... la");\\n} | +| src/http.js:82:3:82:5 | req | src/http.js:81:22:86:1 | functio ... la");\\n} | | src/https.js:4:42:4:44 | req | src/https.js:4:33:10:1 | functio ... .foo;\\n} | | src/https.js:6:26:6:28 | req | src/https.js:4:33:10:1 | functio ... .foo;\\n} | | src/https.js:8:3:8:5 | req | src/https.js:4:33:10:1 | functio ... .foo;\\n} | @@ -312,6 +322,8 @@ test_RouteHandler_getARequestExpr | src/http.js:68:12:68:27 | (req,res) => f() | src/http.js:68:13:68:15 | req | | src/http.js:72:19:76:1 | functio ... \\n })\\n} | src/http.js:72:29:72:31 | req | | src/http.js:72:19:76:1 | functio ... \\n })\\n} | src/http.js:73:3:73:5 | req | +| src/http.js:81:22:86:1 | functio ... la");\\n} | src/http.js:81:41:81:43 | req | +| src/http.js:81:22:86:1 | functio ... la");\\n} | src/http.js:82:3:82:5 | req | | src/https.js:4:33:10:1 | functio ... .foo;\\n} | src/https.js:4:42:4:44 | req | | src/https.js:4:33:10:1 | functio ... .foo;\\n} | src/https.js:6:26:6:28 | req | | src/https.js:4:33:10:1 | functio ... .foo;\\n} | src/https.js:8:3:8:5 | req | From 214aa072b900d6eba032cc2a634f1e8b63af31ae Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 25 Feb 2021 16:00:44 +0100 Subject: [PATCH 082/142] support host for http-proxy client requests --- .../src/semmle/javascript/frameworks/HttpProxy.qll | 14 ++++++++++---- .../ClientRequests/ClientRequests.expected | 3 +++ .../library-tests/frameworks/ClientRequests/tst.js | 11 +++++++++++ 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/HttpProxy.qll b/javascript/ql/src/semmle/javascript/frameworks/HttpProxy.qll index d30ec1a2946..25f30a876d2 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/HttpProxy.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/HttpProxy.qll @@ -21,7 +21,9 @@ private module HttpProxy { override DataFlow::Node getUrl() { result = getParameter(0).getMember("target").getARhs() } - override DataFlow::Node getHost() { none() } + override DataFlow::Node getHost() { + result = getParameter(0).getMember("target").getMember("host").getARhs() + } override DataFlow::Node getADataNode() { none() } } @@ -37,17 +39,21 @@ private module HttpProxy { this = any(CreateServerCall server).getReturn().getMember(method).getACall() } - override DataFlow::Node getUrl() { + private API::Node getOptionsObject() { exists(int optionsIndex | method = "web" and optionsIndex = 2 or method = "ws" and optionsIndex = 3 | - result = getParameter(optionsIndex).getMember("target").getARhs() + result = getParameter(optionsIndex) ) } - override DataFlow::Node getHost() { none() } + override DataFlow::Node getUrl() { result = getOptionsObject().getMember("target").getARhs() } + + override DataFlow::Node getHost() { + result = getOptionsObject().getMember("target").getMember("host").getARhs() + } override DataFlow::Node getADataNode() { none() } } diff --git a/javascript/ql/test/library-tests/frameworks/ClientRequests/ClientRequests.expected b/javascript/ql/test/library-tests/frameworks/ClientRequests/ClientRequests.expected index 15289413bc4..2bf2d305cb0 100644 --- a/javascript/ql/test/library-tests/frameworks/ClientRequests/ClientRequests.expected +++ b/javascript/ql/test/library-tests/frameworks/ClientRequests/ClientRequests.expected @@ -82,6 +82,7 @@ test_ClientRequest | tst.js:267:1:267:61 | httpPro ... 9000'}) | | tst.js:269:13:269:48 | httpPro ... ptions) | | tst.js:271:3:271:61 | proxy.w ... 080' }) | +| tst.js:274:1:283:2 | httpPro ... true\\n}) | test_getADataNode | tst.js:53:5:53:23 | axios({data: data}) | tst.js:53:18:53:21 | data | | tst.js:57:5:57:39 | axios.p ... data2}) | tst.js:57:19:57:23 | data1 | @@ -127,6 +128,7 @@ test_getHost | tst.js:93:5:93:35 | net.req ... host }) | tst.js:93:29:93:32 | host | | tst.js:219:5:219:41 | data.so ... Host"}) | tst.js:219:32:219:39 | "myHost" | | tst.js:257:1:262:2 | form.su ... rs()\\n}) | tst.js:259:11:259:23 | 'example.org' | +| tst.js:274:1:283:2 | httpPro ... true\\n}) | tst.js:277:15:277:30 | 'my-domain-name' | test_getUrl | apollo.js:5:18:5:78 | new cre ... hql' }) | apollo.js:5:44:5:75 | 'https: ... raphql' | | apollo.js:10:1:10:54 | new Htt ... hql' }) | apollo.js:10:21:10:51 | 'http:/ ... raphql' | @@ -215,6 +217,7 @@ test_getUrl | tst.js:257:1:262:2 | form.su ... rs()\\n}) | tst.js:257:13:262:1 | {\\n m ... ers()\\n} | | tst.js:267:1:267:61 | httpPro ... 9000'}) | tst.js:267:37:267:59 | 'http:/ ... t:9000' | | tst.js:271:3:271:61 | proxy.w ... 080' }) | tst.js:271:33:271:58 | 'http:/ ... m:8080' | +| tst.js:274:1:283:2 | httpPro ... true\\n}) | tst.js:275:13:281:5 | {\\n ... ,\\n } | test_getAResponseDataNode | tst.js:19:5:19:23 | requestPromise(url) | tst.js:19:5:19:23 | requestPromise(url) | text | true | | tst.js:21:5:21:23 | superagent.get(url) | tst.js:21:5:21:23 | superagent.get(url) | stream | true | diff --git a/javascript/ql/test/library-tests/frameworks/ClientRequests/tst.js b/javascript/ql/test/library-tests/frameworks/ClientRequests/tst.js index b5a36a84299..4003fd1b0a3 100644 --- a/javascript/ql/test/library-tests/frameworks/ClientRequests/tst.js +++ b/javascript/ql/test/library-tests/frameworks/ClientRequests/tst.js @@ -270,3 +270,14 @@ var proxy = httpProxy.createProxyServer(options); http.createServer(function(req, res) { proxy.web(req, res, { target: 'http://mytarget.com:8080' }); }); + +httpProxy.createProxyServer({ + target: { + protocol: 'https:', + host: 'my-domain-name', + port: 443, + pfx: fs.readFileSync('path/to/certificate.p12'), + passphrase: 'password', + }, + changeOrigin: true +}).listen(8000); \ No newline at end of file From af7a188bbd3fd866d74001d2e1c758cd3fba1db2 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Thu, 25 Feb 2021 16:03:58 +0100 Subject: [PATCH 083/142] add change note --- javascript/change-notes/2021-02-25-http-proxy.md | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 javascript/change-notes/2021-02-25-http-proxy.md diff --git a/javascript/change-notes/2021-02-25-http-proxy.md b/javascript/change-notes/2021-02-25-http-proxy.md new file mode 100644 index 00000000000..5c34368ffcb --- /dev/null +++ b/javascript/change-notes/2021-02-25-http-proxy.md @@ -0,0 +1,4 @@ +lgtm,codescanning +* Sources of user input and sinks for `js/request-forgery` in the http-proxy are now recognized. + Affected packages are + [http-proxy](https://www.npmjs.com/package/http-proxy) \ No newline at end of file From 0f7256752ac96fec5b4f7436b1010fa7b5298ada Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 26 Feb 2021 19:16:28 +0100 Subject: [PATCH 084/142] Update cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.qhelp Co-authored-by: Shati Patel <42641846+shati-patel@users.noreply.github.com> --- cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.qhelp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.qhelp b/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.qhelp index 9ef348cc4b5..2c087e37eaa 100644 --- a/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.qhelp +++ b/cpp/ql/src/Security/CWE/CWE-014/MemsetMayBeDeleted.qhelp @@ -13,8 +13,8 @@ contains sensitive data that could somehow be retrieved by an attacker.

    Use alternative platform-supplied functions that will not get optimized away. Examples of such functions include memset_s, SecureZeroMemory, and bzero_explicit. Alternatively, passing the -fno-builtin-memset option to the GCC/Clang compiler usually -also prevents the optimization. Finally, the public-domain secure_memzero function (see -below) can be used. This function, however, is not guaranteed to work on all platforms and compilers.

    +also prevents the optimization. Finally, you can use the public-domain secure_memzero function +(see references below). This function, however, is not guaranteed to work on all platforms and compilers.

    From d4f7fab7df06b2dd257f46e5c281865131ce9af0 Mon Sep 17 00:00:00 2001 From: Mathias Vorreiter Pedersen Date: Fri, 26 Feb 2021 19:17:13 +0100 Subject: [PATCH 085/142] Update cpp/change-notes/2021-02-24-memset-may-be-deleted.md Co-authored-by: Shati Patel <42641846+shati-patel@users.noreply.github.com> --- cpp/change-notes/2021-02-24-memset-may-be-deleted.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/change-notes/2021-02-24-memset-may-be-deleted.md b/cpp/change-notes/2021-02-24-memset-may-be-deleted.md index 955794634c7..3c6ec850ca6 100644 --- a/cpp/change-notes/2021-02-24-memset-may-be-deleted.md +++ b/cpp/change-notes/2021-02-24-memset-may-be-deleted.md @@ -1,2 +1,2 @@ lgtm,codescanning -* A new query (`cpp/memset-may-be-deleted`) is added to the default query suite. The query finds calls to `memset` that may be removed by compiler. This query was originally [submitted as an experimental query by @ihsinme](https://github.com/github/codeql/pull/4953). +* A new query (`cpp/memset-may-be-deleted`) is added to the default query suite. The query finds calls to `memset` that may be removed by the compiler. This behavior can make information-leak vulnerabilities easier to exploit. This query was originally [submitted as an experimental query by @ihsinme](https://github.com/github/codeql/pull/4953). From 646ea55944a18f7cf78cd81f4008dd4ed342783d Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Sat, 27 Feb 2021 11:09:59 +0100 Subject: [PATCH 086/142] Python/JS: Update Python copy of crypto algorithm modeling Now to be shared accross both languages, with sync-identical-files --- python/ql/src/semmle/crypto/Crypto.qll | 26 ++++++++++++-------------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/python/ql/src/semmle/crypto/Crypto.qll b/python/ql/src/semmle/crypto/Crypto.qll index ff13b559198..7c83f117c31 100644 --- a/python/ql/src/semmle/crypto/Crypto.qll +++ b/python/ql/src/semmle/crypto/Crypto.qll @@ -2,17 +2,14 @@ * Provides classes for modeling cryptographic libraries. */ -/* - * The following information is copied from `/semmlecode-javascript-queries/semmle/javascript/frameworks/CryptoLibraries.qll` - * which should be considered the definitive version (as of Feb 2018) - */ - /** * Names of cryptographic algorithms, separated into strong and weak variants. * * The names are normalized: upper-case, no spaces, dashes or underscores. * * The names are inspired by the names used in real world crypto libraries. + * + * The classification into strong and weak are based on Wikipedia, OWASP and google (2017). */ private module AlgorithmNames { predicate isStrongHashingAlgorithm(string name) { @@ -81,14 +78,6 @@ private module AlgorithmNames { } predicate isWeakPasswordHashingAlgorithm(string name) { none() } - - /** - * Normalizes `name`: upper-case, no spaces, dashes or underscores. - * - * All names of this module are in this normalized form. - */ - bindingset[name] - string normalizeName(string name) { result = name.toUpperCase().regexpReplaceAll("[-_ ]", "") } } private import AlgorithmNames @@ -121,10 +110,19 @@ abstract class CryptographicAlgorithm extends TCryptographicAlgorithm { string toString() { result = getName() } /** - * Gets the name of the algorithm. + * Gets the name of this algorithm. */ abstract string getName(); + /** + * Holds if the name of this algorithm matches `name` modulo case, + * white space, dashes and underscores. + */ + bindingset[name] + predicate matchesName(string name) { + name.toUpperCase().regexpReplaceAll("[-_ ]", "") = getName() + } + /** * Holds if this algorithm is weak. */ From 010488c899bc5dc90803b7bb7fd6e43e63b27130 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Sat, 27 Feb 2021 11:12:50 +0100 Subject: [PATCH 087/142] Python/JS: Update QLDoc for crypto algorithms before sharing --- python/ql/src/semmle/crypto/Crypto.qll | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/python/ql/src/semmle/crypto/Crypto.qll b/python/ql/src/semmle/crypto/Crypto.qll index 7c83f117c31..1e8e9ccf067 100644 --- a/python/ql/src/semmle/crypto/Crypto.qll +++ b/python/ql/src/semmle/crypto/Crypto.qll @@ -1,5 +1,7 @@ /** - * Provides classes for modeling cryptographic libraries. + * Provides classes modeling cryptographic algorithms, separated into strong and weak variants. + * + * The classification into strong and weak are based on Wikipedia, OWASP and google (2017). */ /** @@ -110,7 +112,7 @@ abstract class CryptographicAlgorithm extends TCryptographicAlgorithm { string toString() { result = getName() } /** - * Gets the name of this algorithm. + * Gets the normalized name of this algorithm (upper-case, no spaces, dashes or underscores). */ abstract string getName(); From 443780f27ea933ad14cde0c1eecbf77c5c1a36d3 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Sat, 27 Feb 2021 11:20:22 +0100 Subject: [PATCH 088/142] Python/JS: Share modeling of cryptographic algorithms I didn't quite know where to place it for JS, so I tried my best :) The canonical Python version might be changed in the future, but I wanted to keep this change small. --- config/identical-files.json | 6 +- .../javascript/frameworks/CryptoLibraries.qll | 170 +---------------- .../javascript/security/CryptoAlgorithms.qll | 174 ++++++++++++++++++ 3 files changed, 180 insertions(+), 170 deletions(-) create mode 100644 javascript/ql/src/semmle/javascript/security/CryptoAlgorithms.qll diff --git a/config/identical-files.json b/config/identical-files.json index 2109588fb36..76a0de4ca4d 100644 --- a/config/identical-files.json +++ b/config/identical-files.json @@ -430,5 +430,9 @@ "csharp/ql/src/semmle/code/csharp/dataflow/internal/SsaImplCommon.qll", "csharp/ql/src/semmle/code/csharp/controlflow/internal/pressa/SsaImplCommon.qll", "csharp/ql/src/semmle/code/csharp/dataflow/internal/basessa/SsaImplCommon.qll" + ], + "CryptoAlgorithms Python/JS": [ + "javascript/ql/src/semmle/javascript/security/CryptoAlgorithms.qll", + "python/ql/src/semmle/crypto/Crypto.qll" ] -} \ No newline at end of file +} diff --git a/javascript/ql/src/semmle/javascript/frameworks/CryptoLibraries.qll b/javascript/ql/src/semmle/javascript/frameworks/CryptoLibraries.qll index a48291d98e2..f8c942ff6b0 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/CryptoLibraries.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/CryptoLibraries.qll @@ -3,175 +3,7 @@ */ import javascript - -/** - * Names of cryptographic algorithms, separated into strong and weak variants. - * - * The names are normalized: upper-case, no spaces, dashes or underscores. - * - * The names are inspired by the names used in real world crypto libraries. - * - * The classification into strong and weak are based on Wikipedia, OWASP and google (2017). - */ -private module AlgorithmNames { - predicate isStrongHashingAlgorithm(string name) { - name = "DSA" or - name = "ED25519" or - name = "ES256" or - name = "ECDSA256" or - name = "ES384" or - name = "ECDSA384" or - name = "ES512" or - name = "ECDSA512" or - name = "SHA2" or - name = "SHA224" or - name = "SHA256" or - name = "SHA384" or - name = "SHA512" or - name = "SHA3" - } - - predicate isWeakHashingAlgorithm(string name) { - name = "HAVEL128" or - name = "MD2" or - name = "MD4" or - name = "MD5" or - name = "PANAMA" or - name = "RIPEMD" or - name = "RIPEMD128" or - name = "RIPEMD256" or - name = "RIPEMD160" or - name = "RIPEMD320" or - name = "SHA0" or - name = "SHA1" - } - - predicate isStrongEncryptionAlgorithm(string name) { - name = "AES" or - name = "AES128" or - name = "AES192" or - name = "AES256" or - name = "AES512" or - name = "RSA" or - name = "RABBIT" or - name = "BLOWFISH" - } - - predicate isWeakEncryptionAlgorithm(string name) { - name = "DES" or - name = "3DES" or - name = "TRIPLEDES" or - name = "TDEA" or - name = "TRIPLEDEA" or - name = "ARC2" or - name = "RC2" or - name = "ARC4" or - name = "RC4" or - name = "ARCFOUR" or - name = "ARC5" or - name = "RC5" - } - - predicate isStrongPasswordHashingAlgorithm(string name) { - name = "ARGON2" or - name = "PBKDF2" or - name = "BCRYPT" or - name = "SCRYPT" - } - - predicate isWeakPasswordHashingAlgorithm(string name) { none() } -} - -private import AlgorithmNames - -/** - * A cryptographic algorithm. - */ -private newtype TCryptographicAlgorithm = - MkHashingAlgorithm(string name, boolean isWeak) { - isStrongHashingAlgorithm(name) and isWeak = false - or - isWeakHashingAlgorithm(name) and isWeak = true - } or - MkEncryptionAlgorithm(string name, boolean isWeak) { - isStrongEncryptionAlgorithm(name) and isWeak = false - or - isWeakEncryptionAlgorithm(name) and isWeak = true - } or - MkPasswordHashingAlgorithm(string name, boolean isWeak) { - isStrongPasswordHashingAlgorithm(name) and isWeak = false - or - isWeakPasswordHashingAlgorithm(name) and isWeak = true - } - -/** - * A cryptographic algorithm. - */ -abstract class CryptographicAlgorithm extends TCryptographicAlgorithm { - /** Gets a textual representation of this element. */ - string toString() { result = getName() } - - /** - * Gets the name of this algorithm. - */ - abstract string getName(); - - /** - * Holds if the name of this algorithm matches `name` modulo case, - * white space, dashes and underscores. - */ - bindingset[name] - predicate matchesName(string name) { - name.toUpperCase().regexpReplaceAll("[-_ ]", "") = getName() - } - - /** - * Holds if this algorithm is weak. - */ - abstract predicate isWeak(); -} - -/** - * A hashing algorithm such as `MD5` or `SHA512`. - */ -class HashingAlgorithm extends MkHashingAlgorithm, CryptographicAlgorithm { - string name; - boolean isWeak; - - HashingAlgorithm() { this = MkHashingAlgorithm(name, isWeak) } - - override string getName() { result = name } - - override predicate isWeak() { isWeak = true } -} - -/** - * An encryption algorithm such as `DES` or `AES512`. - */ -class EncryptionAlgorithm extends MkEncryptionAlgorithm, CryptographicAlgorithm { - string name; - boolean isWeak; - - EncryptionAlgorithm() { this = MkEncryptionAlgorithm(name, isWeak) } - - override string getName() { result = name } - - override predicate isWeak() { isWeak = true } -} - -/** - * A password hashing algorithm such as `PBKDF2` or `SCRYPT`. - */ -class PasswordHashingAlgorithm extends MkPasswordHashingAlgorithm, CryptographicAlgorithm { - string name; - boolean isWeak; - - PasswordHashingAlgorithm() { this = MkPasswordHashingAlgorithm(name, isWeak) } - - override string getName() { result = name } - - override predicate isWeak() { isWeak = true } -} +import semmle.javascript.security.CryptoAlgorithms /** * An application of a cryptographic algorithm. diff --git a/javascript/ql/src/semmle/javascript/security/CryptoAlgorithms.qll b/javascript/ql/src/semmle/javascript/security/CryptoAlgorithms.qll new file mode 100644 index 00000000000..1e8e9ccf067 --- /dev/null +++ b/javascript/ql/src/semmle/javascript/security/CryptoAlgorithms.qll @@ -0,0 +1,174 @@ +/** + * Provides classes modeling cryptographic algorithms, separated into strong and weak variants. + * + * The classification into strong and weak are based on Wikipedia, OWASP and google (2017). + */ + +/** + * Names of cryptographic algorithms, separated into strong and weak variants. + * + * The names are normalized: upper-case, no spaces, dashes or underscores. + * + * The names are inspired by the names used in real world crypto libraries. + * + * The classification into strong and weak are based on Wikipedia, OWASP and google (2017). + */ +private module AlgorithmNames { + predicate isStrongHashingAlgorithm(string name) { + name = "DSA" or + name = "ED25519" or + name = "ES256" or + name = "ECDSA256" or + name = "ES384" or + name = "ECDSA384" or + name = "ES512" or + name = "ECDSA512" or + name = "SHA2" or + name = "SHA224" or + name = "SHA256" or + name = "SHA384" or + name = "SHA512" or + name = "SHA3" + } + + predicate isWeakHashingAlgorithm(string name) { + name = "HAVEL128" or + name = "MD2" or + name = "MD4" or + name = "MD5" or + name = "PANAMA" or + name = "RIPEMD" or + name = "RIPEMD128" or + name = "RIPEMD256" or + name = "RIPEMD160" or + name = "RIPEMD320" or + name = "SHA0" or + name = "SHA1" + } + + predicate isStrongEncryptionAlgorithm(string name) { + name = "AES" or + name = "AES128" or + name = "AES192" or + name = "AES256" or + name = "AES512" or + name = "RSA" or + name = "RABBIT" or + name = "BLOWFISH" + } + + predicate isWeakEncryptionAlgorithm(string name) { + name = "DES" or + name = "3DES" or + name = "TRIPLEDES" or + name = "TDEA" or + name = "TRIPLEDEA" or + name = "ARC2" or + name = "RC2" or + name = "ARC4" or + name = "RC4" or + name = "ARCFOUR" or + name = "ARC5" or + name = "RC5" + } + + predicate isStrongPasswordHashingAlgorithm(string name) { + name = "ARGON2" or + name = "PBKDF2" or + name = "BCRYPT" or + name = "SCRYPT" + } + + predicate isWeakPasswordHashingAlgorithm(string name) { none() } +} + +private import AlgorithmNames + +/** + * A cryptographic algorithm. + */ +private newtype TCryptographicAlgorithm = + MkHashingAlgorithm(string name, boolean isWeak) { + isStrongHashingAlgorithm(name) and isWeak = false + or + isWeakHashingAlgorithm(name) and isWeak = true + } or + MkEncryptionAlgorithm(string name, boolean isWeak) { + isStrongEncryptionAlgorithm(name) and isWeak = false + or + isWeakEncryptionAlgorithm(name) and isWeak = true + } or + MkPasswordHashingAlgorithm(string name, boolean isWeak) { + isStrongPasswordHashingAlgorithm(name) and isWeak = false + or + isWeakPasswordHashingAlgorithm(name) and isWeak = true + } + +/** + * A cryptographic algorithm. + */ +abstract class CryptographicAlgorithm extends TCryptographicAlgorithm { + /** Gets a textual representation of this element. */ + string toString() { result = getName() } + + /** + * Gets the normalized name of this algorithm (upper-case, no spaces, dashes or underscores). + */ + abstract string getName(); + + /** + * Holds if the name of this algorithm matches `name` modulo case, + * white space, dashes and underscores. + */ + bindingset[name] + predicate matchesName(string name) { + name.toUpperCase().regexpReplaceAll("[-_ ]", "") = getName() + } + + /** + * Holds if this algorithm is weak. + */ + abstract predicate isWeak(); +} + +/** + * A hashing algorithm such as `MD5` or `SHA512`. + */ +class HashingAlgorithm extends MkHashingAlgorithm, CryptographicAlgorithm { + string name; + boolean isWeak; + + HashingAlgorithm() { this = MkHashingAlgorithm(name, isWeak) } + + override string getName() { result = name } + + override predicate isWeak() { isWeak = true } +} + +/** + * An encryption algorithm such as `DES` or `AES512`. + */ +class EncryptionAlgorithm extends MkEncryptionAlgorithm, CryptographicAlgorithm { + string name; + boolean isWeak; + + EncryptionAlgorithm() { this = MkEncryptionAlgorithm(name, isWeak) } + + override string getName() { result = name } + + override predicate isWeak() { isWeak = true } +} + +/** + * A password hashing algorithm such as `PBKDF2` or `SCRYPT`. + */ +class PasswordHashingAlgorithm extends MkPasswordHashingAlgorithm, CryptographicAlgorithm { + string name; + boolean isWeak; + + PasswordHashingAlgorithm() { this = MkPasswordHashingAlgorithm(name, isWeak) } + + override string getName() { result = name } + + override predicate isWeak() { isWeak = true } +} From 1ecbbf6af33b3b27acea2709bd7ba2789abab433 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Mon, 1 Mar 2021 09:16:45 +0100 Subject: [PATCH 089/142] C#: Fix codeql analysis workflow --- .github/workflows/codeql-analysis.yml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 8ddae33fd7b..b86009ef6da 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -5,8 +5,6 @@ on: branches: - main - 'rc/*' - paths: - - 'csharp/**' pull_request: branches: - main From fadbb32bd63db545c877f19a48c70cff0a1f9c19 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Fri, 19 Feb 2021 13:59:03 +0000 Subject: [PATCH 090/142] Add backward dataflow edges through fluent function invocations. This means that much as obj.getA().setB(...) already has a side-effect on `obj`, all three setters in obj.setA(...).setB(...).setC(...) will have a side-effect on `obj`. --- .../java/dataflow/internal/DataFlowImpl.qll | 5 +- .../dataflow/internal/DataFlowImplCommon.qll | 16 ++++++ .../dataflow/fluent-methods/Test.java | 52 +++++++++++++++++++ .../dataflow/fluent-methods/flow.expected | 0 .../dataflow/fluent-methods/flow.ql | 30 +++++++++++ 5 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 java/ql/test/library-tests/dataflow/fluent-methods/Test.java create mode 100644 java/ql/test/library-tests/dataflow/fluent-methods/flow.expected create mode 100644 java/ql/test/library-tests/dataflow/fluent-methods/flow.ql diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll index 59cc8d529a7..3da77b8ba99 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll @@ -223,7 +223,10 @@ private predicate isAdditionalFlowStep( * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - simpleLocalFlowStep(node1, node2) and + ( + simpleLocalFlowStep(node1, node2) or + reverseStepThroughInputOutputAlias(node1, node2) + ) and not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll index 1d2e9052842..e8e606d9189 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll @@ -415,6 +415,22 @@ private module Cached { store(node1, tc.getContent(), node2, contentType, tc.getContainerType()) } + /** + * Holds if data can flow from `fromNode` to `toNode` because they are the post-update + * nodes of some function output and input respectively, where the output and input + * are aliases. A typical example is a function returning `this`, implementing a fluent + * interface. + */ + cached + predicate reverseStepThroughInputOutputAlias(Node fromNode, Node toNode) { + exists(Node fromPre, Node toPre | + fromPre = fromNode.(PostUpdateNode).getPreUpdateNode() and + toPre = toNode.(PostUpdateNode).getPreUpdateNode() + | + argumentValueFlowsThrough(toPre, TReadStepTypesNone(), fromPre) + ) + } + /** * Holds if the call context `call` either improves virtual dispatch in * `callable` or if it allows us to prune unreachable nodes in `callable`. diff --git a/java/ql/test/library-tests/dataflow/fluent-methods/Test.java b/java/ql/test/library-tests/dataflow/fluent-methods/Test.java new file mode 100644 index 00000000000..4c1bfad60c0 --- /dev/null +++ b/java/ql/test/library-tests/dataflow/fluent-methods/Test.java @@ -0,0 +1,52 @@ +package smowton; + +public class Test { + + private String field; + + public Test fluentNoop() { + return this; + } + + public Test indirectlyFluentNoop() { + return this.fluentNoop(); + } + + public Test fluentSet(String x) { + this.field = x; + return this; + } + + public static Test identity(Test t) { + return t; + } + + public String get() { + return field; + } + + public static String source() { + return "taint"; + } + + public static void sink(String s) {} + + public static void test1() { + Test t = new Test(); + t.fluentNoop().fluentSet(source()).fluentNoop(); + sink(t.get()); // $hasTaintFlow=y + } + + public static void test2() { + Test t = new Test(); + Test.identity(t).fluentNoop().fluentSet(source()).fluentNoop(); + sink(t.get()); // $hasTaintFlow=y + } + + public static void test3() { + Test t = new Test(); + t.indirectlyFluentNoop().fluentSet(source()).fluentNoop(); + sink(t.get()); // $hasTaintFlow=y + } + +} diff --git a/java/ql/test/library-tests/dataflow/fluent-methods/flow.expected b/java/ql/test/library-tests/dataflow/fluent-methods/flow.expected new file mode 100644 index 00000000000..e69de29bb2d diff --git a/java/ql/test/library-tests/dataflow/fluent-methods/flow.ql b/java/ql/test/library-tests/dataflow/fluent-methods/flow.ql new file mode 100644 index 00000000000..2e47268af3e --- /dev/null +++ b/java/ql/test/library-tests/dataflow/fluent-methods/flow.ql @@ -0,0 +1,30 @@ +import java +import semmle.code.java.dataflow.TaintTracking +import TestUtilities.InlineExpectationsTest + +class Conf extends TaintTracking::Configuration { + Conf() { this = "qltest:dataflow:fluent-methods" } + + override predicate isSource(DataFlow::Node n) { + n.asExpr().(MethodAccess).getMethod().hasName("source") + } + + override predicate isSink(DataFlow::Node n) { + exists(MethodAccess ma | ma.getMethod().hasName("sink") | n.asExpr() = ma.getAnArgument()) + } +} + +class HasFlowTest extends InlineExpectationsTest { + HasFlowTest() { this = "HasFlowTest" } + + override string getARelevantTag() { result = "hasTaintFlow" } + + override predicate hasActualResult(Location location, string element, string tag, string value) { + tag = "hasTaintFlow" and + exists(DataFlow::Node src, DataFlow::Node sink, Conf conf | conf.hasFlow(src, sink) | + sink.getLocation() = location and + element = sink.toString() and + value = "y" + ) + } +} From 54caf501e7e7b1387c4249744102c07476845346 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Mon, 1 Mar 2021 10:16:02 +0000 Subject: [PATCH 091/142] Switch fluent-methods test to use a plain DataFlow::Configuration No taint edges are involved, so TaintTracking was unnecessary. --- java/ql/test/library-tests/dataflow/fluent-methods/flow.ql | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/java/ql/test/library-tests/dataflow/fluent-methods/flow.ql b/java/ql/test/library-tests/dataflow/fluent-methods/flow.ql index 2e47268af3e..6d9ba50efe9 100644 --- a/java/ql/test/library-tests/dataflow/fluent-methods/flow.ql +++ b/java/ql/test/library-tests/dataflow/fluent-methods/flow.ql @@ -1,8 +1,8 @@ import java -import semmle.code.java.dataflow.TaintTracking +import semmle.code.java.dataflow.DataFlow import TestUtilities.InlineExpectationsTest -class Conf extends TaintTracking::Configuration { +class Conf extends DataFlow::Configuration { Conf() { this = "qltest:dataflow:fluent-methods" } override predicate isSource(DataFlow::Node n) { From e6b1fe9b5fd636c5e7f17351a517663ede742046 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Mon, 1 Mar 2021 10:23:38 +0000 Subject: [PATCH 092/142] Fluent interface dataflow: support argument-output flow directly declared by the simpleLocalFlowStep relation This means we will treat fluent interfaces that are modelled the same as those where we determine an argument flows to an output by inspection of the function body. --- .../code/java/dataflow/internal/DataFlowImplCommon.qll | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll index e8e606d9189..6d5c60cafe6 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll @@ -427,6 +427,14 @@ private module Cached { fromPre = fromNode.(PostUpdateNode).getPreUpdateNode() and toPre = toNode.(PostUpdateNode).getPreUpdateNode() | + exists(DataFlowCall c | + // Does the language-specific simpleLocalFlowStep already model flow + // from function input to output? + fromPre = getAnOutNode(c, _) and + toPre.(ArgumentNode).argumentOf(c, _) and + simpleLocalFlowStep(toPre.(ArgumentNode), fromPre) + ) + or argumentValueFlowsThrough(toPre, TReadStepTypesNone(), fromPre) ) } From c32514bf66e8e4d8c40294110ad56b0896099a2f Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Mon, 1 Mar 2021 10:27:28 +0000 Subject: [PATCH 093/142] Sync dataflow library files --- .../cpp/dataflow/internal/DataFlowImpl.qll | 5 +++- .../cpp/dataflow/internal/DataFlowImpl2.qll | 5 +++- .../cpp/dataflow/internal/DataFlowImpl3.qll | 5 +++- .../cpp/dataflow/internal/DataFlowImpl4.qll | 5 +++- .../dataflow/internal/DataFlowImplCommon.qll | 24 +++++++++++++++++++ .../dataflow/internal/DataFlowImplLocal.qll | 5 +++- .../cpp/ir/dataflow/internal/DataFlowImpl.qll | 5 +++- .../ir/dataflow/internal/DataFlowImpl2.qll | 5 +++- .../ir/dataflow/internal/DataFlowImpl3.qll | 5 +++- .../ir/dataflow/internal/DataFlowImpl4.qll | 5 +++- .../dataflow/internal/DataFlowImplCommon.qll | 24 +++++++++++++++++++ .../csharp/dataflow/internal/DataFlowImpl.qll | 5 +++- .../dataflow/internal/DataFlowImpl2.qll | 5 +++- .../dataflow/internal/DataFlowImpl3.qll | 5 +++- .../dataflow/internal/DataFlowImpl4.qll | 5 +++- .../dataflow/internal/DataFlowImpl5.qll | 5 +++- .../dataflow/internal/DataFlowImplCommon.qll | 24 +++++++++++++++++++ .../java/dataflow/internal/DataFlowImpl2.qll | 5 +++- .../java/dataflow/internal/DataFlowImpl3.qll | 5 +++- .../java/dataflow/internal/DataFlowImpl4.qll | 5 +++- .../java/dataflow/internal/DataFlowImpl5.qll | 5 +++- .../dataflow/new/internal/DataFlowImpl.qll | 5 +++- .../dataflow/new/internal/DataFlowImpl2.qll | 5 +++- .../dataflow/new/internal/DataFlowImpl3.qll | 5 +++- .../dataflow/new/internal/DataFlowImpl4.qll | 5 +++- .../new/internal/DataFlowImplCommon.qll | 24 +++++++++++++++++++ 26 files changed, 184 insertions(+), 22 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll index 59cc8d529a7..3da77b8ba99 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl.qll @@ -223,7 +223,10 @@ private predicate isAdditionalFlowStep( * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - simpleLocalFlowStep(node1, node2) and + ( + simpleLocalFlowStep(node1, node2) or + reverseStepThroughInputOutputAlias(node1, node2) + ) and not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll index 59cc8d529a7..3da77b8ba99 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl2.qll @@ -223,7 +223,10 @@ private predicate isAdditionalFlowStep( * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - simpleLocalFlowStep(node1, node2) and + ( + simpleLocalFlowStep(node1, node2) or + reverseStepThroughInputOutputAlias(node1, node2) + ) and not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll index 59cc8d529a7..3da77b8ba99 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl3.qll @@ -223,7 +223,10 @@ private predicate isAdditionalFlowStep( * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - simpleLocalFlowStep(node1, node2) and + ( + simpleLocalFlowStep(node1, node2) or + reverseStepThroughInputOutputAlias(node1, node2) + ) and not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll index 59cc8d529a7..3da77b8ba99 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImpl4.qll @@ -223,7 +223,10 @@ private predicate isAdditionalFlowStep( * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - simpleLocalFlowStep(node1, node2) and + ( + simpleLocalFlowStep(node1, node2) or + reverseStepThroughInputOutputAlias(node1, node2) + ) and not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll index 1d2e9052842..6d5c60cafe6 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll @@ -415,6 +415,30 @@ private module Cached { store(node1, tc.getContent(), node2, contentType, tc.getContainerType()) } + /** + * Holds if data can flow from `fromNode` to `toNode` because they are the post-update + * nodes of some function output and input respectively, where the output and input + * are aliases. A typical example is a function returning `this`, implementing a fluent + * interface. + */ + cached + predicate reverseStepThroughInputOutputAlias(Node fromNode, Node toNode) { + exists(Node fromPre, Node toPre | + fromPre = fromNode.(PostUpdateNode).getPreUpdateNode() and + toPre = toNode.(PostUpdateNode).getPreUpdateNode() + | + exists(DataFlowCall c | + // Does the language-specific simpleLocalFlowStep already model flow + // from function input to output? + fromPre = getAnOutNode(c, _) and + toPre.(ArgumentNode).argumentOf(c, _) and + simpleLocalFlowStep(toPre.(ArgumentNode), fromPre) + ) + or + argumentValueFlowsThrough(toPre, TReadStepTypesNone(), fromPre) + ) + } + /** * Holds if the call context `call` either improves virtual dispatch in * `callable` or if it allows us to prune unreachable nodes in `callable`. diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll index 59cc8d529a7..3da77b8ba99 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplLocal.qll @@ -223,7 +223,10 @@ private predicate isAdditionalFlowStep( * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - simpleLocalFlowStep(node1, node2) and + ( + simpleLocalFlowStep(node1, node2) or + reverseStepThroughInputOutputAlias(node1, node2) + ) and not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll index 59cc8d529a7..3da77b8ba99 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl.qll @@ -223,7 +223,10 @@ private predicate isAdditionalFlowStep( * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - simpleLocalFlowStep(node1, node2) and + ( + simpleLocalFlowStep(node1, node2) or + reverseStepThroughInputOutputAlias(node1, node2) + ) and not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll index 59cc8d529a7..3da77b8ba99 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl2.qll @@ -223,7 +223,10 @@ private predicate isAdditionalFlowStep( * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - simpleLocalFlowStep(node1, node2) and + ( + simpleLocalFlowStep(node1, node2) or + reverseStepThroughInputOutputAlias(node1, node2) + ) and not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll index 59cc8d529a7..3da77b8ba99 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl3.qll @@ -223,7 +223,10 @@ private predicate isAdditionalFlowStep( * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - simpleLocalFlowStep(node1, node2) and + ( + simpleLocalFlowStep(node1, node2) or + reverseStepThroughInputOutputAlias(node1, node2) + ) and not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll index 59cc8d529a7..3da77b8ba99 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImpl4.qll @@ -223,7 +223,10 @@ private predicate isAdditionalFlowStep( * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - simpleLocalFlowStep(node1, node2) and + ( + simpleLocalFlowStep(node1, node2) or + reverseStepThroughInputOutputAlias(node1, node2) + ) and not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll index 1d2e9052842..6d5c60cafe6 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll @@ -415,6 +415,30 @@ private module Cached { store(node1, tc.getContent(), node2, contentType, tc.getContainerType()) } + /** + * Holds if data can flow from `fromNode` to `toNode` because they are the post-update + * nodes of some function output and input respectively, where the output and input + * are aliases. A typical example is a function returning `this`, implementing a fluent + * interface. + */ + cached + predicate reverseStepThroughInputOutputAlias(Node fromNode, Node toNode) { + exists(Node fromPre, Node toPre | + fromPre = fromNode.(PostUpdateNode).getPreUpdateNode() and + toPre = toNode.(PostUpdateNode).getPreUpdateNode() + | + exists(DataFlowCall c | + // Does the language-specific simpleLocalFlowStep already model flow + // from function input to output? + fromPre = getAnOutNode(c, _) and + toPre.(ArgumentNode).argumentOf(c, _) and + simpleLocalFlowStep(toPre.(ArgumentNode), fromPre) + ) + or + argumentValueFlowsThrough(toPre, TReadStepTypesNone(), fromPre) + ) + } + /** * Holds if the call context `call` either improves virtual dispatch in * `callable` or if it allows us to prune unreachable nodes in `callable`. diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll index 59cc8d529a7..3da77b8ba99 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl.qll @@ -223,7 +223,10 @@ private predicate isAdditionalFlowStep( * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - simpleLocalFlowStep(node1, node2) and + ( + simpleLocalFlowStep(node1, node2) or + reverseStepThroughInputOutputAlias(node1, node2) + ) and not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll index 59cc8d529a7..3da77b8ba99 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl2.qll @@ -223,7 +223,10 @@ private predicate isAdditionalFlowStep( * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - simpleLocalFlowStep(node1, node2) and + ( + simpleLocalFlowStep(node1, node2) or + reverseStepThroughInputOutputAlias(node1, node2) + ) and not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll index 59cc8d529a7..3da77b8ba99 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl3.qll @@ -223,7 +223,10 @@ private predicate isAdditionalFlowStep( * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - simpleLocalFlowStep(node1, node2) and + ( + simpleLocalFlowStep(node1, node2) or + reverseStepThroughInputOutputAlias(node1, node2) + ) and not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll index 59cc8d529a7..3da77b8ba99 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl4.qll @@ -223,7 +223,10 @@ private predicate isAdditionalFlowStep( * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - simpleLocalFlowStep(node1, node2) and + ( + simpleLocalFlowStep(node1, node2) or + reverseStepThroughInputOutputAlias(node1, node2) + ) and not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll index 59cc8d529a7..3da77b8ba99 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImpl5.qll @@ -223,7 +223,10 @@ private predicate isAdditionalFlowStep( * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - simpleLocalFlowStep(node1, node2) and + ( + simpleLocalFlowStep(node1, node2) or + reverseStepThroughInputOutputAlias(node1, node2) + ) and not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll index 1d2e9052842..6d5c60cafe6 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll @@ -415,6 +415,30 @@ private module Cached { store(node1, tc.getContent(), node2, contentType, tc.getContainerType()) } + /** + * Holds if data can flow from `fromNode` to `toNode` because they are the post-update + * nodes of some function output and input respectively, where the output and input + * are aliases. A typical example is a function returning `this`, implementing a fluent + * interface. + */ + cached + predicate reverseStepThroughInputOutputAlias(Node fromNode, Node toNode) { + exists(Node fromPre, Node toPre | + fromPre = fromNode.(PostUpdateNode).getPreUpdateNode() and + toPre = toNode.(PostUpdateNode).getPreUpdateNode() + | + exists(DataFlowCall c | + // Does the language-specific simpleLocalFlowStep already model flow + // from function input to output? + fromPre = getAnOutNode(c, _) and + toPre.(ArgumentNode).argumentOf(c, _) and + simpleLocalFlowStep(toPre.(ArgumentNode), fromPre) + ) + or + argumentValueFlowsThrough(toPre, TReadStepTypesNone(), fromPre) + ) + } + /** * Holds if the call context `call` either improves virtual dispatch in * `callable` or if it allows us to prune unreachable nodes in `callable`. diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll index 59cc8d529a7..3da77b8ba99 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll @@ -223,7 +223,10 @@ private predicate isAdditionalFlowStep( * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - simpleLocalFlowStep(node1, node2) and + ( + simpleLocalFlowStep(node1, node2) or + reverseStepThroughInputOutputAlias(node1, node2) + ) and not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll index 59cc8d529a7..3da77b8ba99 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl3.qll @@ -223,7 +223,10 @@ private predicate isAdditionalFlowStep( * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - simpleLocalFlowStep(node1, node2) and + ( + simpleLocalFlowStep(node1, node2) or + reverseStepThroughInputOutputAlias(node1, node2) + ) and not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll index 59cc8d529a7..3da77b8ba99 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl4.qll @@ -223,7 +223,10 @@ private predicate isAdditionalFlowStep( * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - simpleLocalFlowStep(node1, node2) and + ( + simpleLocalFlowStep(node1, node2) or + reverseStepThroughInputOutputAlias(node1, node2) + ) and not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll index 59cc8d529a7..3da77b8ba99 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl5.qll @@ -223,7 +223,10 @@ private predicate isAdditionalFlowStep( * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - simpleLocalFlowStep(node1, node2) and + ( + simpleLocalFlowStep(node1, node2) or + reverseStepThroughInputOutputAlias(node1, node2) + ) and not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and diff --git a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl.qll b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl.qll index 59cc8d529a7..3da77b8ba99 100644 --- a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl.qll +++ b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl.qll @@ -223,7 +223,10 @@ private predicate isAdditionalFlowStep( * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - simpleLocalFlowStep(node1, node2) and + ( + simpleLocalFlowStep(node1, node2) or + reverseStepThroughInputOutputAlias(node1, node2) + ) and not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and diff --git a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl2.qll b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl2.qll index 59cc8d529a7..3da77b8ba99 100644 --- a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl2.qll +++ b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl2.qll @@ -223,7 +223,10 @@ private predicate isAdditionalFlowStep( * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - simpleLocalFlowStep(node1, node2) and + ( + simpleLocalFlowStep(node1, node2) or + reverseStepThroughInputOutputAlias(node1, node2) + ) and not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and diff --git a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl3.qll b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl3.qll index 59cc8d529a7..3da77b8ba99 100644 --- a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl3.qll +++ b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl3.qll @@ -223,7 +223,10 @@ private predicate isAdditionalFlowStep( * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - simpleLocalFlowStep(node1, node2) and + ( + simpleLocalFlowStep(node1, node2) or + reverseStepThroughInputOutputAlias(node1, node2) + ) and not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and diff --git a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl4.qll b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl4.qll index 59cc8d529a7..3da77b8ba99 100644 --- a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl4.qll +++ b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImpl4.qll @@ -223,7 +223,10 @@ private predicate isAdditionalFlowStep( * Holds if data can flow in one local step from `node1` to `node2`. */ private predicate localFlowStep(Node node1, Node node2, Configuration config) { - simpleLocalFlowStep(node1, node2) and + ( + simpleLocalFlowStep(node1, node2) or + reverseStepThroughInputOutputAlias(node1, node2) + ) and not outBarrier(node1, config) and not inBarrier(node2, config) and not fullBarrier(node1, config) and diff --git a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImplCommon.qll b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImplCommon.qll index 1d2e9052842..6d5c60cafe6 100644 --- a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImplCommon.qll +++ b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImplCommon.qll @@ -415,6 +415,30 @@ private module Cached { store(node1, tc.getContent(), node2, contentType, tc.getContainerType()) } + /** + * Holds if data can flow from `fromNode` to `toNode` because they are the post-update + * nodes of some function output and input respectively, where the output and input + * are aliases. A typical example is a function returning `this`, implementing a fluent + * interface. + */ + cached + predicate reverseStepThroughInputOutputAlias(Node fromNode, Node toNode) { + exists(Node fromPre, Node toPre | + fromPre = fromNode.(PostUpdateNode).getPreUpdateNode() and + toPre = toNode.(PostUpdateNode).getPreUpdateNode() + | + exists(DataFlowCall c | + // Does the language-specific simpleLocalFlowStep already model flow + // from function input to output? + fromPre = getAnOutNode(c, _) and + toPre.(ArgumentNode).argumentOf(c, _) and + simpleLocalFlowStep(toPre.(ArgumentNode), fromPre) + ) + or + argumentValueFlowsThrough(toPre, TReadStepTypesNone(), fromPre) + ) + } + /** * Holds if the call context `call` either improves virtual dispatch in * `callable` or if it allows us to prune unreachable nodes in `callable`. From aab9deceef0c9e401273d925bd248a3103b21d72 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Mon, 1 Mar 2021 10:32:44 +0000 Subject: [PATCH 094/142] Remove package from test Java file --- java/ql/test/library-tests/dataflow/fluent-methods/Test.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/java/ql/test/library-tests/dataflow/fluent-methods/Test.java b/java/ql/test/library-tests/dataflow/fluent-methods/Test.java index 4c1bfad60c0..c9c09e667b4 100644 --- a/java/ql/test/library-tests/dataflow/fluent-methods/Test.java +++ b/java/ql/test/library-tests/dataflow/fluent-methods/Test.java @@ -1,5 +1,3 @@ -package smowton; - public class Test { private String field; From 14ec1482721b7fd406a7550de326e6a59b16a7e7 Mon Sep 17 00:00:00 2001 From: Porcuiney Hairs Date: Mon, 1 Mar 2021 18:46:33 +0530 Subject: [PATCH 095/142] refactor to meet experimental guidelines. --- .../CWE/CWE-094/SpringViewManipulationLib.qll | 19 ++++++++++++++++++- .../semmle/code/java/dataflow/FlowSources.qll | 16 ---------------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-094/SpringViewManipulationLib.qll b/java/ql/src/experimental/Security/CWE/CWE-094/SpringViewManipulationLib.qll index b03fefbc366..b61d64ba7e1 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-094/SpringViewManipulationLib.qll +++ b/java/ql/src/experimental/Security/CWE/CWE-094/SpringViewManipulationLib.qll @@ -20,6 +20,22 @@ predicate thymeleafIsUsed() { exists(SpringBean b | b.getClassNameRaw().matches("org.thymeleaf.spring%")) } +/** Models methods from the `javax.portlet.RenderState` package which return data from externally controlled sources. */ +class PortletRenderRequestMethod extends Method { + PortletRenderRequestMethod() { + exists(RefType c, Interface t | + c.extendsOrImplements*(t) and + t.hasQualifiedName("javax.portlet", "RenderState") and + this = c.getAMethod() + | + this.hasName([ + "getCookies", "getParameter", "getRenderParameters", "getParameterNames", + "getParameterValues", "getParameterMap" + ]) + ) + } +} + /** * A taint-tracking configuration for unsafe user input * that can lead to Spring View Manipulation vulnerabilities. @@ -29,7 +45,8 @@ class SpringViewManipulationConfig extends TaintTracking::Configuration { override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource or - source instanceof WebRequestSource + source instanceof WebRequestSource or + source.asExpr().(MethodAccess).getMethod() instanceof PortletRenderRequestMethod } override predicate isSink(DataFlow::Node sink) { sink instanceof SpringViewManipulationSink } diff --git a/java/ql/src/semmle/code/java/dataflow/FlowSources.qll b/java/ql/src/semmle/code/java/dataflow/FlowSources.qll index 67e67289c4a..b4235cb2635 100644 --- a/java/ql/src/semmle/code/java/dataflow/FlowSources.qll +++ b/java/ql/src/semmle/code/java/dataflow/FlowSources.qll @@ -256,7 +256,6 @@ private class RemoteTaintedMethod extends Method { this instanceof ServletRequestGetParameterMethod or this instanceof ServletRequestGetParameterMapMethod or this instanceof ServletRequestGetParameterNamesMethod or - this instanceof PortletRenderRequestGetParameterMethod or this instanceof HttpServletRequestGetQueryStringMethod or this instanceof HttpServletRequestGetHeaderMethod or this instanceof HttpServletRequestGetPathMethod or @@ -309,21 +308,6 @@ class EnvReadMethod extends Method { } } -private class PortletRenderRequestGetParameterMethod extends Method { - PortletRenderRequestGetParameterMethod() { - exists(RefType c, Interface t | - c.extendsOrImplements*(t) and - t.hasQualifiedName("javax.portlet", "RenderState") and - this = c.getAMethod() - | - this.hasName([ - "getCookies", "getParameter", "getRenderParameters", "getParameterNames", - "getParameterValues", "getParameterMap" - ]) - ) - } -} - /** The type `java.net.InetAddress`. */ class TypeInetAddr extends RefType { TypeInetAddr() { this.getQualifiedName() = "java.net.InetAddress" } From 26924a3378697cef004649706526866e74cb67a3 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 1 Mar 2021 16:30:09 +0000 Subject: [PATCH 096/142] JS: Regenerate stats for tuple_type_rest_index --- .../src/semmlecode.javascript.dbscheme.stats | 46 +++++++++++++++++-- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/javascript/ql/src/semmlecode.javascript.dbscheme.stats b/javascript/ql/src/semmlecode.javascript.dbscheme.stats index 2f9e3c60388..206c9bf9fa8 100644 --- a/javascript/ql/src/semmlecode.javascript.dbscheme.stats +++ b/javascript/ql/src/semmlecode.javascript.dbscheme.stats @@ -15903,18 +15903,56 @@
    tuple_type_rest_index -100 +6 typ -100 +6 index -100 +2 - + + +typ +index + + +12 + + +1 +2 +6 + + + + + + +index +typ + + +12 + + +1 +2 +1 + + +5 +6 +1 + + + + + + comments From cdccc1a0642ded5d7e8926a30865152b71720752 Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Mon, 1 Mar 2021 16:47:34 +0000 Subject: [PATCH 097/142] Remove needless typecasts --- .../code/cpp/dataflow/internal/DataFlowImplCommon.qll | 6 +++--- .../code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll | 6 +++--- .../code/csharp/dataflow/internal/DataFlowImplCommon.qll | 6 +++--- .../code/java/dataflow/internal/DataFlowImplCommon.qll | 6 +++--- .../python/dataflow/new/internal/DataFlowImplCommon.qll | 6 +++--- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll index 6d5c60cafe6..54f41545284 100644 --- a/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll +++ b/cpp/ql/src/semmle/code/cpp/dataflow/internal/DataFlowImplCommon.qll @@ -422,10 +422,10 @@ private module Cached { * interface. */ cached - predicate reverseStepThroughInputOutputAlias(Node fromNode, Node toNode) { + predicate reverseStepThroughInputOutputAlias(PostUpdateNode fromNode, PostUpdateNode toNode) { exists(Node fromPre, Node toPre | - fromPre = fromNode.(PostUpdateNode).getPreUpdateNode() and - toPre = toNode.(PostUpdateNode).getPreUpdateNode() + fromPre = fromNode.getPreUpdateNode() and + toPre = toNode.getPreUpdateNode() | exists(DataFlowCall c | // Does the language-specific simpleLocalFlowStep already model flow diff --git a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll index 6d5c60cafe6..54f41545284 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/dataflow/internal/DataFlowImplCommon.qll @@ -422,10 +422,10 @@ private module Cached { * interface. */ cached - predicate reverseStepThroughInputOutputAlias(Node fromNode, Node toNode) { + predicate reverseStepThroughInputOutputAlias(PostUpdateNode fromNode, PostUpdateNode toNode) { exists(Node fromPre, Node toPre | - fromPre = fromNode.(PostUpdateNode).getPreUpdateNode() and - toPre = toNode.(PostUpdateNode).getPreUpdateNode() + fromPre = fromNode.getPreUpdateNode() and + toPre = toNode.getPreUpdateNode() | exists(DataFlowCall c | // Does the language-specific simpleLocalFlowStep already model flow diff --git a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll index 6d5c60cafe6..54f41545284 100644 --- a/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll +++ b/csharp/ql/src/semmle/code/csharp/dataflow/internal/DataFlowImplCommon.qll @@ -422,10 +422,10 @@ private module Cached { * interface. */ cached - predicate reverseStepThroughInputOutputAlias(Node fromNode, Node toNode) { + predicate reverseStepThroughInputOutputAlias(PostUpdateNode fromNode, PostUpdateNode toNode) { exists(Node fromPre, Node toPre | - fromPre = fromNode.(PostUpdateNode).getPreUpdateNode() and - toPre = toNode.(PostUpdateNode).getPreUpdateNode() + fromPre = fromNode.getPreUpdateNode() and + toPre = toNode.getPreUpdateNode() | exists(DataFlowCall c | // Does the language-specific simpleLocalFlowStep already model flow diff --git a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll index 6d5c60cafe6..54f41545284 100644 --- a/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll +++ b/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll @@ -422,10 +422,10 @@ private module Cached { * interface. */ cached - predicate reverseStepThroughInputOutputAlias(Node fromNode, Node toNode) { + predicate reverseStepThroughInputOutputAlias(PostUpdateNode fromNode, PostUpdateNode toNode) { exists(Node fromPre, Node toPre | - fromPre = fromNode.(PostUpdateNode).getPreUpdateNode() and - toPre = toNode.(PostUpdateNode).getPreUpdateNode() + fromPre = fromNode.getPreUpdateNode() and + toPre = toNode.getPreUpdateNode() | exists(DataFlowCall c | // Does the language-specific simpleLocalFlowStep already model flow diff --git a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImplCommon.qll b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImplCommon.qll index 6d5c60cafe6..54f41545284 100644 --- a/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImplCommon.qll +++ b/python/ql/src/semmle/python/dataflow/new/internal/DataFlowImplCommon.qll @@ -422,10 +422,10 @@ private module Cached { * interface. */ cached - predicate reverseStepThroughInputOutputAlias(Node fromNode, Node toNode) { + predicate reverseStepThroughInputOutputAlias(PostUpdateNode fromNode, PostUpdateNode toNode) { exists(Node fromPre, Node toPre | - fromPre = fromNode.(PostUpdateNode).getPreUpdateNode() and - toPre = toNode.(PostUpdateNode).getPreUpdateNode() + fromPre = fromNode.getPreUpdateNode() and + toPre = toNode.getPreUpdateNode() | exists(DataFlowCall c | // Does the language-specific simpleLocalFlowStep already model flow From 5d2f3421d85d41fef3229fa0ee7a050965ea862e Mon Sep 17 00:00:00 2001 From: Chris Smowton Date: Mon, 1 Mar 2021 16:59:20 +0000 Subject: [PATCH 098/142] Add change notes --- cpp/change-notes/2021-03-01-fluent-interface-data-flow.md | 2 ++ csharp/change-notes/2021-03-01-fluent-interface-data-flow.md | 2 ++ java/change-notes/2021-03-01-fluent-interface-data-flow.md | 2 ++ python/change-notes/2021-03-01-fluent-interface-data-flow.md | 2 ++ 4 files changed, 8 insertions(+) create mode 100644 cpp/change-notes/2021-03-01-fluent-interface-data-flow.md create mode 100644 csharp/change-notes/2021-03-01-fluent-interface-data-flow.md create mode 100644 java/change-notes/2021-03-01-fluent-interface-data-flow.md create mode 100644 python/change-notes/2021-03-01-fluent-interface-data-flow.md diff --git a/cpp/change-notes/2021-03-01-fluent-interface-data-flow.md b/cpp/change-notes/2021-03-01-fluent-interface-data-flow.md new file mode 100644 index 00000000000..f1492afcf31 --- /dev/null +++ b/cpp/change-notes/2021-03-01-fluent-interface-data-flow.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* The data-flow library now recognises more side-effects of method chaining (e.g. `someObject.setX(clean).setY(tainted).setZ...` having a side-effect on `someObject`), as well as other related circumstances where a function input is directly passed to its output. All queries that use data-flow analysis, including most security queries, may return more results accordingly. diff --git a/csharp/change-notes/2021-03-01-fluent-interface-data-flow.md b/csharp/change-notes/2021-03-01-fluent-interface-data-flow.md new file mode 100644 index 00000000000..f1492afcf31 --- /dev/null +++ b/csharp/change-notes/2021-03-01-fluent-interface-data-flow.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* The data-flow library now recognises more side-effects of method chaining (e.g. `someObject.setX(clean).setY(tainted).setZ...` having a side-effect on `someObject`), as well as other related circumstances where a function input is directly passed to its output. All queries that use data-flow analysis, including most security queries, may return more results accordingly. diff --git a/java/change-notes/2021-03-01-fluent-interface-data-flow.md b/java/change-notes/2021-03-01-fluent-interface-data-flow.md new file mode 100644 index 00000000000..f1492afcf31 --- /dev/null +++ b/java/change-notes/2021-03-01-fluent-interface-data-flow.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* The data-flow library now recognises more side-effects of method chaining (e.g. `someObject.setX(clean).setY(tainted).setZ...` having a side-effect on `someObject`), as well as other related circumstances where a function input is directly passed to its output. All queries that use data-flow analysis, including most security queries, may return more results accordingly. diff --git a/python/change-notes/2021-03-01-fluent-interface-data-flow.md b/python/change-notes/2021-03-01-fluent-interface-data-flow.md new file mode 100644 index 00000000000..f1492afcf31 --- /dev/null +++ b/python/change-notes/2021-03-01-fluent-interface-data-flow.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* The data-flow library now recognises more side-effects of method chaining (e.g. `someObject.setX(clean).setY(tainted).setZ...` having a side-effect on `someObject`), as well as other related circumstances where a function input is directly passed to its output. All queries that use data-flow analysis, including most security queries, may return more results accordingly. From 5151a528ac6d7b4b54543a6c36bbc49d32a0e62b Mon Sep 17 00:00:00 2001 From: Porcuiney Hairs Date: Mon, 1 Mar 2021 22:59:30 +0530 Subject: [PATCH 099/142] Include suggestions from review --- java/ql/src/experimental/Security/CWE/CWE-489/devMode.qhelp | 4 ++-- java/ql/src/experimental/semmle/code/xml/StrutsXML.qll | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/java/ql/src/experimental/Security/CWE/CWE-489/devMode.qhelp b/java/ql/src/experimental/Security/CWE/CWE-489/devMode.qhelp index 14d9b6311b8..4775bd8e0e2 100644 --- a/java/ql/src/experimental/Security/CWE/CWE-489/devMode.qhelp +++ b/java/ql/src/experimental/Security/CWE/CWE-489/devMode.qhelp @@ -14,11 +14,11 @@

    The following example shows a `struts.xml` file with `struts.devmode` enabled.

    - +

    This can be easily corrected by setting the value of the `struts.devmode` parameter to false.

    - + diff --git a/java/ql/src/experimental/semmle/code/xml/StrutsXML.qll b/java/ql/src/experimental/semmle/code/xml/StrutsXML.qll index bda7824560c..06e1dab79af 100644 --- a/java/ql/src/experimental/semmle/code/xml/StrutsXML.qll +++ b/java/ql/src/experimental/semmle/code/xml/StrutsXML.qll @@ -37,5 +37,4 @@ class ConstantParameter extends StrutsXMLElement { * Gets the value of the `value` attribute of this ``. */ string getValueValue() { result = getAttributeValue("value") } - } From 2b382d588add4eadd5177fe847e02ad6dfc6e63a Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Mon, 1 Mar 2021 11:13:04 -0800 Subject: [PATCH 100/142] C++: autoformat Operand.qll --- .../cpp/ir/implementation/aliased_ssa/Operand.qll | 15 ++++++++++----- .../code/cpp/ir/implementation/raw/Operand.qll | 15 ++++++++++----- .../ir/implementation/unaliased_ssa/Operand.qll | 15 ++++++++++----- .../ir/implementation/raw/Operand.qll | 15 ++++++++++----- .../ir/implementation/unaliased_ssa/Operand.qll | 15 ++++++++++----- 5 files changed, 50 insertions(+), 25 deletions(-) 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 5187e5df54d..a2ce0662dc2 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 @@ -25,7 +25,8 @@ private class TStageOperand = * (the defining instruction) in another instruction (the use instruction) */ class Operand extends TStageOperand { - cached Operand() { + cached + Operand() { // Ensure that the operand does not refer to instructions from earlier stages that are unreachable here exists(Instruction use, Instruction def | this = registerOperand(use, _, def)) or exists(Instruction use | this = nonSSAMemoryOperand(use, _)) or @@ -190,7 +191,8 @@ class Operand extends TStageOperand { * An operand that consumes a memory result (e.g. the `LoadOperand` on a `Load` instruction). */ class MemoryOperand extends Operand { - cached MemoryOperand() { + cached + MemoryOperand() { this instanceof TNonSSAMemoryOperand or this instanceof TPhiOperand or this instanceof TChiOperand @@ -256,7 +258,8 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand { override RegisterOperandTag tag; Instruction defInstr; - cached RegisterOperand() { this = registerOperand(useInstr, tag, defInstr) } + cached + RegisterOperand() { this = registerOperand(useInstr, tag, defInstr) } final override string toString() { result = tag.toString() } @@ -274,7 +277,8 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand { class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand { override MemoryOperandTag tag; - cached NonPhiMemoryOperand() { + cached + NonPhiMemoryOperand() { this = nonSSAMemoryOperand(useInstr, tag) or this = chiOperand(useInstr, tag) @@ -426,7 +430,8 @@ class PhiInputOperand extends MemoryOperand, TPhiOperand { IRBlock predecessorBlock; Overlap overlap; - cached PhiInputOperand() { this = phiOperand(useInstr, defInstr, predecessorBlock, overlap) } + cached + PhiInputOperand() { this = phiOperand(useInstr, defInstr, predecessorBlock, overlap) } override string toString() { result = "Phi" } 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 5187e5df54d..a2ce0662dc2 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 @@ -25,7 +25,8 @@ private class TStageOperand = * (the defining instruction) in another instruction (the use instruction) */ class Operand extends TStageOperand { - cached Operand() { + cached + Operand() { // Ensure that the operand does not refer to instructions from earlier stages that are unreachable here exists(Instruction use, Instruction def | this = registerOperand(use, _, def)) or exists(Instruction use | this = nonSSAMemoryOperand(use, _)) or @@ -190,7 +191,8 @@ class Operand extends TStageOperand { * An operand that consumes a memory result (e.g. the `LoadOperand` on a `Load` instruction). */ class MemoryOperand extends Operand { - cached MemoryOperand() { + cached + MemoryOperand() { this instanceof TNonSSAMemoryOperand or this instanceof TPhiOperand or this instanceof TChiOperand @@ -256,7 +258,8 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand { override RegisterOperandTag tag; Instruction defInstr; - cached RegisterOperand() { this = registerOperand(useInstr, tag, defInstr) } + cached + RegisterOperand() { this = registerOperand(useInstr, tag, defInstr) } final override string toString() { result = tag.toString() } @@ -274,7 +277,8 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand { class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand { override MemoryOperandTag tag; - cached NonPhiMemoryOperand() { + cached + NonPhiMemoryOperand() { this = nonSSAMemoryOperand(useInstr, tag) or this = chiOperand(useInstr, tag) @@ -426,7 +430,8 @@ class PhiInputOperand extends MemoryOperand, TPhiOperand { IRBlock predecessorBlock; Overlap overlap; - cached PhiInputOperand() { this = phiOperand(useInstr, defInstr, predecessorBlock, overlap) } + cached + PhiInputOperand() { this = phiOperand(useInstr, defInstr, predecessorBlock, overlap) } override string toString() { result = "Phi" } 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 5187e5df54d..a2ce0662dc2 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 @@ -25,7 +25,8 @@ private class TStageOperand = * (the defining instruction) in another instruction (the use instruction) */ class Operand extends TStageOperand { - cached Operand() { + cached + Operand() { // Ensure that the operand does not refer to instructions from earlier stages that are unreachable here exists(Instruction use, Instruction def | this = registerOperand(use, _, def)) or exists(Instruction use | this = nonSSAMemoryOperand(use, _)) or @@ -190,7 +191,8 @@ class Operand extends TStageOperand { * An operand that consumes a memory result (e.g. the `LoadOperand` on a `Load` instruction). */ class MemoryOperand extends Operand { - cached MemoryOperand() { + cached + MemoryOperand() { this instanceof TNonSSAMemoryOperand or this instanceof TPhiOperand or this instanceof TChiOperand @@ -256,7 +258,8 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand { override RegisterOperandTag tag; Instruction defInstr; - cached RegisterOperand() { this = registerOperand(useInstr, tag, defInstr) } + cached + RegisterOperand() { this = registerOperand(useInstr, tag, defInstr) } final override string toString() { result = tag.toString() } @@ -274,7 +277,8 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand { class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand { override MemoryOperandTag tag; - cached NonPhiMemoryOperand() { + cached + NonPhiMemoryOperand() { this = nonSSAMemoryOperand(useInstr, tag) or this = chiOperand(useInstr, tag) @@ -426,7 +430,8 @@ class PhiInputOperand extends MemoryOperand, TPhiOperand { IRBlock predecessorBlock; Overlap overlap; - cached PhiInputOperand() { this = phiOperand(useInstr, defInstr, predecessorBlock, overlap) } + cached + PhiInputOperand() { this = phiOperand(useInstr, defInstr, predecessorBlock, overlap) } override string toString() { result = "Phi" } diff --git a/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll b/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll index 5187e5df54d..a2ce0662dc2 100644 --- a/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll +++ b/csharp/ql/src/experimental/ir/implementation/raw/Operand.qll @@ -25,7 +25,8 @@ private class TStageOperand = * (the defining instruction) in another instruction (the use instruction) */ class Operand extends TStageOperand { - cached Operand() { + cached + Operand() { // Ensure that the operand does not refer to instructions from earlier stages that are unreachable here exists(Instruction use, Instruction def | this = registerOperand(use, _, def)) or exists(Instruction use | this = nonSSAMemoryOperand(use, _)) or @@ -190,7 +191,8 @@ class Operand extends TStageOperand { * An operand that consumes a memory result (e.g. the `LoadOperand` on a `Load` instruction). */ class MemoryOperand extends Operand { - cached MemoryOperand() { + cached + MemoryOperand() { this instanceof TNonSSAMemoryOperand or this instanceof TPhiOperand or this instanceof TChiOperand @@ -256,7 +258,8 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand { override RegisterOperandTag tag; Instruction defInstr; - cached RegisterOperand() { this = registerOperand(useInstr, tag, defInstr) } + cached + RegisterOperand() { this = registerOperand(useInstr, tag, defInstr) } final override string toString() { result = tag.toString() } @@ -274,7 +277,8 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand { class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand { override MemoryOperandTag tag; - cached NonPhiMemoryOperand() { + cached + NonPhiMemoryOperand() { this = nonSSAMemoryOperand(useInstr, tag) or this = chiOperand(useInstr, tag) @@ -426,7 +430,8 @@ class PhiInputOperand extends MemoryOperand, TPhiOperand { IRBlock predecessorBlock; Overlap overlap; - cached PhiInputOperand() { this = phiOperand(useInstr, defInstr, predecessorBlock, overlap) } + cached + PhiInputOperand() { this = phiOperand(useInstr, defInstr, predecessorBlock, overlap) } override string toString() { result = "Phi" } 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 5187e5df54d..a2ce0662dc2 100644 --- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Operand.qll +++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Operand.qll @@ -25,7 +25,8 @@ private class TStageOperand = * (the defining instruction) in another instruction (the use instruction) */ class Operand extends TStageOperand { - cached Operand() { + cached + Operand() { // Ensure that the operand does not refer to instructions from earlier stages that are unreachable here exists(Instruction use, Instruction def | this = registerOperand(use, _, def)) or exists(Instruction use | this = nonSSAMemoryOperand(use, _)) or @@ -190,7 +191,8 @@ class Operand extends TStageOperand { * An operand that consumes a memory result (e.g. the `LoadOperand` on a `Load` instruction). */ class MemoryOperand extends Operand { - cached MemoryOperand() { + cached + MemoryOperand() { this instanceof TNonSSAMemoryOperand or this instanceof TPhiOperand or this instanceof TChiOperand @@ -256,7 +258,8 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand { override RegisterOperandTag tag; Instruction defInstr; - cached RegisterOperand() { this = registerOperand(useInstr, tag, defInstr) } + cached + RegisterOperand() { this = registerOperand(useInstr, tag, defInstr) } final override string toString() { result = tag.toString() } @@ -274,7 +277,8 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand { class NonPhiMemoryOperand extends NonPhiOperand, MemoryOperand, TNonPhiMemoryOperand { override MemoryOperandTag tag; - cached NonPhiMemoryOperand() { + cached + NonPhiMemoryOperand() { this = nonSSAMemoryOperand(useInstr, tag) or this = chiOperand(useInstr, tag) @@ -426,7 +430,8 @@ class PhiInputOperand extends MemoryOperand, TPhiOperand { IRBlock predecessorBlock; Overlap overlap; - cached PhiInputOperand() { this = phiOperand(useInstr, defInstr, predecessorBlock, overlap) } + cached + PhiInputOperand() { this = phiOperand(useInstr, defInstr, predecessorBlock, overlap) } override string toString() { result = "Phi" } From dbed4a1a8bf91e86d49c13b314f763e8973224b3 Mon Sep 17 00:00:00 2001 From: Aditya Sharad Date: Fri, 26 Feb 2021 16:35:53 -0800 Subject: [PATCH 101/142] Actions: Add workflow to request docs review When a PR is labelled with 'ready-for-docs-review', this workflow comments on the PR to notify the GitHub CodeQL docs team. Runs on `pull_request_target` events so it can write comments to the PR. Since this runs in the context of the base repo, it must not check out the PR or use untrusted data from the event payload. Only runs when the PR base is github/codeql, to prevent notifications from forks. --- .github/workflows/docs-review.yml | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 .github/workflows/docs-review.yml diff --git a/.github/workflows/docs-review.yml b/.github/workflows/docs-review.yml new file mode 100644 index 00000000000..8b5f396fa9f --- /dev/null +++ b/.github/workflows/docs-review.yml @@ -0,0 +1,29 @@ +# When a PR is labelled with 'ready-for-docs-review', +# this workflow comments on the PR to notify the GitHub CodeQL docs team. +name: Request docs review +on: + # Runs in the context of the base repo. + # This gives the workflow write access to comment on PRs. + # The workflow should not check out or build the given ref, + # or use untrusted data from the event payload in a command line. + pull_request_target: + types: [labeled] + +jobs: + request-docs-review: + name: Request docs review + # Run only on labelled PRs to the main repository. + # Do not run on PRs to forks. + if: + github.event.label.name == 'ready-for-docs-review' + && github.event.pull_request.draft == false + && github.event.pull_request.base.repo.full_name == 'github/codeql' + runs-on: ubuntu-latest + steps: + - name: Comment to request docs review + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PR_NUMBER: ${{ github.event.pull_request.number }} + run: | + gh pr comment "$PR_NUMBER" --repo "github/codeql" \ + --body "Hello @github/docs-content-codeql: this PR is ready for docs review." From 71f095d6d426728eae50e8d19cfaa52dd711659b Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Wed, 10 Feb 2021 10:16:32 +0100 Subject: [PATCH 102/142] Upgrade projects to .net 5 --- .../Semmle.Autobuild.Cpp.Tests.csproj | 2 +- .../Semmle.Autobuild.Cpp/Semmle.Autobuild.Cpp.csproj | 2 +- .../Semmle.Autobuild.CSharp.Tests.csproj | 2 +- .../Semmle.Autobuild.CSharp/Semmle.Autobuild.CSharp.csproj | 2 +- .../Semmle.Autobuild.Shared/Semmle.Autobuild.Shared.csproj | 2 +- .../Semmle.Extraction.CIL.Driver.csproj | 2 +- .../Semmle.Extraction.CIL/Semmle.Extraction.CIL.csproj | 2 +- .../Semmle.Extraction.CSharp.Driver.csproj | 2 +- .../Semmle.Extraction.CSharp.Standalone.csproj | 2 +- .../Semmle.Extraction.CSharp/Semmle.Extraction.CSharp.csproj | 2 +- .../Semmle.Extraction.Tests/Semmle.Extraction.Tests.csproj | 2 +- csharp/extractor/Semmle.Extraction/Semmle.Extraction.csproj | 2 +- csharp/extractor/Semmle.Util.Tests/Semmle.Util.Tests.csproj | 2 +- csharp/extractor/Semmle.Util/Semmle.Util.csproj | 2 +- 14 files changed, 14 insertions(+), 14 deletions(-) diff --git a/cpp/autobuilder/Semmle.Autobuild.Cpp.Tests/Semmle.Autobuild.Cpp.Tests.csproj b/cpp/autobuilder/Semmle.Autobuild.Cpp.Tests/Semmle.Autobuild.Cpp.Tests.csproj index 7de677b5610..9bf293c7e8d 100644 --- a/cpp/autobuilder/Semmle.Autobuild.Cpp.Tests/Semmle.Autobuild.Cpp.Tests.csproj +++ b/cpp/autobuilder/Semmle.Autobuild.Cpp.Tests/Semmle.Autobuild.Cpp.Tests.csproj @@ -2,7 +2,7 @@ Exe - netcoreapp3.1 + net5.0 false win-x64;linux-x64;osx-x64 enable diff --git a/cpp/autobuilder/Semmle.Autobuild.Cpp/Semmle.Autobuild.Cpp.csproj b/cpp/autobuilder/Semmle.Autobuild.Cpp/Semmle.Autobuild.Cpp.csproj index aadcc07568d..68cfef57b3d 100644 --- a/cpp/autobuilder/Semmle.Autobuild.Cpp/Semmle.Autobuild.Cpp.csproj +++ b/cpp/autobuilder/Semmle.Autobuild.Cpp/Semmle.Autobuild.Cpp.csproj @@ -1,7 +1,7 @@ - netcoreapp3.1 + net5.0 Semmle.Autobuild.Cpp Semmle.Autobuild.Cpp diff --git a/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/Semmle.Autobuild.CSharp.Tests.csproj b/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/Semmle.Autobuild.CSharp.Tests.csproj index ee3324eb639..64e25a8eb64 100644 --- a/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/Semmle.Autobuild.CSharp.Tests.csproj +++ b/csharp/autobuilder/Semmle.Autobuild.CSharp.Tests/Semmle.Autobuild.CSharp.Tests.csproj @@ -2,7 +2,7 @@ Exe - netcoreapp3.1 + net5.0 false win-x64;linux-x64;osx-x64 enable diff --git a/csharp/autobuilder/Semmle.Autobuild.CSharp/Semmle.Autobuild.CSharp.csproj b/csharp/autobuilder/Semmle.Autobuild.CSharp/Semmle.Autobuild.CSharp.csproj index 82ca05504bc..b02b1a3fef1 100644 --- a/csharp/autobuilder/Semmle.Autobuild.CSharp/Semmle.Autobuild.CSharp.csproj +++ b/csharp/autobuilder/Semmle.Autobuild.CSharp/Semmle.Autobuild.CSharp.csproj @@ -1,7 +1,7 @@ - netcoreapp3.1 + net5.0 Semmle.Autobuild.CSharp Semmle.Autobuild.CSharp diff --git a/csharp/autobuilder/Semmle.Autobuild.Shared/Semmle.Autobuild.Shared.csproj b/csharp/autobuilder/Semmle.Autobuild.Shared/Semmle.Autobuild.Shared.csproj index 6663c428b03..5f59b205527 100644 --- a/csharp/autobuilder/Semmle.Autobuild.Shared/Semmle.Autobuild.Shared.csproj +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/Semmle.Autobuild.Shared.csproj @@ -1,7 +1,7 @@ - netcoreapp3.1 + net5.0 Semmle.Autobuild.Shared Semmle.Autobuild.Shared false diff --git a/csharp/extractor/Semmle.Extraction.CIL.Driver/Semmle.Extraction.CIL.Driver.csproj b/csharp/extractor/Semmle.Extraction.CIL.Driver/Semmle.Extraction.CIL.Driver.csproj index 67e40dae2d8..dea12d5d012 100644 --- a/csharp/extractor/Semmle.Extraction.CIL.Driver/Semmle.Extraction.CIL.Driver.csproj +++ b/csharp/extractor/Semmle.Extraction.CIL.Driver/Semmle.Extraction.CIL.Driver.csproj @@ -2,7 +2,7 @@ Exe - netcoreapp3.1 + net5.0 Semmle.Extraction.CIL.Driver Semmle.Extraction.CIL.Driver false diff --git a/csharp/extractor/Semmle.Extraction.CIL/Semmle.Extraction.CIL.csproj b/csharp/extractor/Semmle.Extraction.CIL/Semmle.Extraction.CIL.csproj index eb90b909b81..7cae08acc48 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Semmle.Extraction.CIL.csproj +++ b/csharp/extractor/Semmle.Extraction.CIL/Semmle.Extraction.CIL.csproj @@ -1,7 +1,7 @@  - netcoreapp3.1 + net5.0 Semmle.Extraction.CIL Semmle.Extraction.CIL false diff --git a/csharp/extractor/Semmle.Extraction.CSharp.Driver/Semmle.Extraction.CSharp.Driver.csproj b/csharp/extractor/Semmle.Extraction.CSharp.Driver/Semmle.Extraction.CSharp.Driver.csproj index 3ec25c498fe..7ae23fdcd2e 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.Driver/Semmle.Extraction.CSharp.Driver.csproj +++ b/csharp/extractor/Semmle.Extraction.CSharp.Driver/Semmle.Extraction.CSharp.Driver.csproj @@ -2,7 +2,7 @@ Exe - netcoreapp3.1 + net5.0 Semmle.Extraction.CSharp.Driver Semmle.Extraction.CSharp.Driver false diff --git a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/Semmle.Extraction.CSharp.Standalone.csproj b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/Semmle.Extraction.CSharp.Standalone.csproj index 277310cc341..adf51941ad7 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/Semmle.Extraction.CSharp.Standalone.csproj +++ b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/Semmle.Extraction.CSharp.Standalone.csproj @@ -2,7 +2,7 @@ Exe - netcoreapp3.1 + net5.0 Semmle.Extraction.CSharp.Standalone Semmle.Extraction.CSharp.Standalone false diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Semmle.Extraction.CSharp.csproj b/csharp/extractor/Semmle.Extraction.CSharp/Semmle.Extraction.CSharp.csproj index fab4da0605b..d3c46c4a714 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp/Semmle.Extraction.CSharp.csproj +++ b/csharp/extractor/Semmle.Extraction.CSharp/Semmle.Extraction.CSharp.csproj @@ -1,7 +1,7 @@ - netcoreapp3.1 + net5.0 Semmle.Extraction.CSharp Semmle.Extraction.CSharp false diff --git a/csharp/extractor/Semmle.Extraction.Tests/Semmle.Extraction.Tests.csproj b/csharp/extractor/Semmle.Extraction.Tests/Semmle.Extraction.Tests.csproj index 830529d3710..5b242d984ee 100644 --- a/csharp/extractor/Semmle.Extraction.Tests/Semmle.Extraction.Tests.csproj +++ b/csharp/extractor/Semmle.Extraction.Tests/Semmle.Extraction.Tests.csproj @@ -2,7 +2,7 @@ Exe - netcoreapp3.1 + net5.0 false win-x64;linux-x64;osx-x64 enable diff --git a/csharp/extractor/Semmle.Extraction/Semmle.Extraction.csproj b/csharp/extractor/Semmle.Extraction/Semmle.Extraction.csproj index 37df9b4dcda..795e8c2d45d 100644 --- a/csharp/extractor/Semmle.Extraction/Semmle.Extraction.csproj +++ b/csharp/extractor/Semmle.Extraction/Semmle.Extraction.csproj @@ -1,7 +1,7 @@  - netcoreapp3.1 + net5.0 Semmle.Extraction Semmle.Extraction false diff --git a/csharp/extractor/Semmle.Util.Tests/Semmle.Util.Tests.csproj b/csharp/extractor/Semmle.Util.Tests/Semmle.Util.Tests.csproj index 3acf1a1fa42..ca9599cf770 100644 --- a/csharp/extractor/Semmle.Util.Tests/Semmle.Util.Tests.csproj +++ b/csharp/extractor/Semmle.Util.Tests/Semmle.Util.Tests.csproj @@ -2,7 +2,7 @@ Exe - netcoreapp3.1 + net5.0 false win-x64;linux-x64;osx-x64 enable diff --git a/csharp/extractor/Semmle.Util/Semmle.Util.csproj b/csharp/extractor/Semmle.Util/Semmle.Util.csproj index fdcd0672395..63ac78cb7cc 100644 --- a/csharp/extractor/Semmle.Util/Semmle.Util.csproj +++ b/csharp/extractor/Semmle.Util/Semmle.Util.csproj @@ -1,7 +1,7 @@ - netcoreapp3.1 + net5.0 Semmle.Util Semmle.Util false From 4f383be13ba95679f67db16434bd7fea8a0b683c Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Wed, 10 Feb 2021 10:40:57 +0100 Subject: [PATCH 103/142] Fix new (nullability) compiler warnings --- .../Semmle.Autobuild.Shared/BuildActions.cs | 4 ++ .../Semmle.Autobuild.Shared/BuildTools.cs | 10 ++--- .../Semmle.Autobuild.Shared/Project.cs | 13 ++++-- .../Semmle.Autobuild.Shared/Solution.cs | 2 +- .../CsProjFile.cs | 41 +++++++++++++++---- .../NugetPackages.cs | 6 +++ .../extractor/Semmle.Extraction/TrapWriter.cs | 8 +++- .../extractor/Semmle.Util.Tests/LongPaths.cs | 6 +-- .../Semmle.Util/ProcessStartInfoExtensions.cs | 6 +++ 9 files changed, 74 insertions(+), 22 deletions(-) diff --git a/csharp/autobuilder/Semmle.Autobuild.Shared/BuildActions.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/BuildActions.cs index b9a5c9c17c3..b75c6413e61 100644 --- a/csharp/autobuilder/Semmle.Autobuild.Shared/BuildActions.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/BuildActions.cs @@ -170,6 +170,10 @@ namespace Semmle.Autobuild.Shared { var pi = GetProcessStartInfo(cmd, args, workingDirectory, environment, false); using var p = Process.Start(pi); + if (p is null) + { + return -1; + } p.WaitForExit(); return p.ExitCode; } diff --git a/csharp/autobuilder/Semmle.Autobuild.Shared/BuildTools.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/BuildTools.cs index 79367c90d8e..a598e6480f3 100644 --- a/csharp/autobuilder/Semmle.Autobuild.Shared/BuildTools.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/BuildTools.cs @@ -84,7 +84,7 @@ namespace Semmle.Autobuild.Shared ///
    /// The solution file. /// A compatible file, or throws an exception. - public static VcVarsBatFile FindCompatibleVcVars(IBuildActions actions, ISolution sln) => + public static VcVarsBatFile? FindCompatibleVcVars(IBuildActions actions, ISolution sln) => FindCompatibleVcVars(actions, sln.ToolsVersion.Major); /// @@ -92,9 +92,9 @@ namespace Semmle.Autobuild.Shared /// /// The tools version. /// A compatible file, or null. - public static VcVarsBatFile FindCompatibleVcVars(IBuildActions actions, int targetVersion) => - targetVersion < 10 ? - VcVarsAllBatFiles(actions).OrderByDescending(b => b.ToolsVersion).FirstOrDefault() : - VcVarsAllBatFiles(actions).Where(b => b.ToolsVersion >= targetVersion).OrderBy(b => b.ToolsVersion).FirstOrDefault(); + public static VcVarsBatFile? FindCompatibleVcVars(IBuildActions actions, int targetVersion) => + targetVersion < 10 + ? VcVarsAllBatFiles(actions).OrderByDescending(b => b.ToolsVersion).FirstOrDefault() + : VcVarsAllBatFiles(actions).Where(b => b.ToolsVersion >= targetVersion).OrderBy(b => b.ToolsVersion).FirstOrDefault(); } } diff --git a/csharp/autobuilder/Semmle.Autobuild.Shared/Project.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/Project.cs index aaaa7cdac56..bdc712d6623 100644 --- a/csharp/autobuilder/Semmle.Autobuild.Shared/Project.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/Project.cs @@ -47,7 +47,7 @@ namespace Semmle.Autobuild.Shared var root = projFile.DocumentElement; - if (root.Name == "Project") + if (root?.Name == "Project") { if (root.HasAttribute("Sdk")) { @@ -77,10 +77,17 @@ namespace Semmle.Autobuild.Shared // `` and `` is valid var mgr = new XmlNamespaceManager(projFile.NameTable); mgr.AddNamespace("msbuild", "http://schemas.microsoft.com/developer/msbuild/2003"); - var projectFileIncludes = root.SelectNodes("//msbuild:Project/msbuild:ItemGroup/msbuild:ProjectFile/@Include", mgr).OfType(); - var projectFilesIncludes = root.SelectNodes("//msbuild:Project/msbuild:ItemGroup/msbuild:ProjectFiles/@Include", mgr).OfType(); + var projectFileIncludes = root.SelectNodes("//msbuild:Project/msbuild:ItemGroup/msbuild:ProjectFile/@Include", mgr) + ?.OfType() ?? Array.Empty(); + var projectFilesIncludes = root.SelectNodes("//msbuild:Project/msbuild:ItemGroup/msbuild:ProjectFiles/@Include", mgr) + ?.OfType() ?? Array.Empty(); foreach (var include in projectFileIncludes.Concat(projectFilesIncludes)) { + if (include?.Value is null) + { + continue; + } + var includePath = builder.Actions.PathCombine(include.Value.Split('\\', StringSplitOptions.RemoveEmptyEntries)); ret.Add(new Project(builder, builder.Actions.PathCombine(DirectoryName, includePath))); } diff --git a/csharp/autobuilder/Semmle.Autobuild.Shared/Solution.cs b/csharp/autobuilder/Semmle.Autobuild.Shared/Solution.cs index c5d65794fb5..5e501a8eb99 100644 --- a/csharp/autobuilder/Semmle.Autobuild.Shared/Solution.cs +++ b/csharp/autobuilder/Semmle.Autobuild.Shared/Solution.cs @@ -90,7 +90,7 @@ namespace Semmle.Autobuild.Shared .Select(p => p.ToolsVersion); public Version ToolsVersion => ToolsVersions.Any() - ? ToolsVersions.Max() + ? ToolsVersions.Max()! : new Version(); } } diff --git a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/CsProjFile.cs b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/CsProjFile.cs index dfbe8df2f06..dc775835e70 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/CsProjFile.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/CsProjFile.cs @@ -88,6 +88,11 @@ namespace Semmle.BuildAnalyser var projDir = fileName.Directory; var root = projFile.DocumentElement; + if (root is null) + { + throw new NotSupportedException("Project file without root is not supported."); + } + // Figure out if it's dotnet core var netCoreProjectFile = root.GetAttribute("Sdk") == "Microsoft.NET.Sdk"; @@ -96,34 +101,52 @@ namespace Semmle.BuildAnalyser { var explicitCsFiles = root .SelectNodes("/Project/ItemGroup/Compile/@Include", mgr) - .NodeList() + ?.NodeList() .Select(node => node.Value) - .Select(cs => Path.DirectorySeparatorChar == '/' ? cs.Replace("\\", "/") : cs) - .Select(f => Path.GetFullPath(Path.Combine(projDir.FullName, f))); + .Select(cs => GetFullPath(cs, projDir)) + .Where(s => s is not null) + ?? Enumerable.Empty(); var additionalCsFiles = System.IO.Directory.GetFiles(directoryName, "*.cs", SearchOption.AllDirectories); +#nullable disable warnings return (explicitCsFiles.Concat(additionalCsFiles).ToArray(), Array.Empty()); +#nullable restore warnings } var references = root .SelectNodes("/msbuild:Project/msbuild:ItemGroup/msbuild:Reference/@Include", mgr) - .NodeList() + ?.NodeList() .Select(node => node.Value) - .ToArray(); + .Where(s => s is not null) + .ToArray() + ?? Array.Empty(); var relativeCsIncludes = root .SelectNodes("/msbuild:Project/msbuild:ItemGroup/msbuild:Compile/@Include", mgr) - .NodeList() + ?.NodeList() .Select(node => node.Value) - .ToArray(); + .ToArray() + ?? Array.Empty(); var csFiles = relativeCsIncludes - .Select(cs => Path.DirectorySeparatorChar == '/' ? cs.Replace("\\", "/") : cs) - .Select(f => Path.GetFullPath(Path.Combine(projDir.FullName, f))) + .Select(cs => GetFullPath(cs, projDir)) + .Where(s => s is not null) .ToArray(); +#nullable disable warnings return (csFiles, references); +#nullable restore warnings + } + + private static string? GetFullPath(string? file, DirectoryInfo? projDir) + { + if (file is null) + { + return null; + } + + return Path.GetFullPath(Path.Combine(projDir?.FullName ?? string.Empty, Path.DirectorySeparatorChar == '/' ? file.Replace("\\", "/") : file)); } private readonly string[] references; diff --git a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/NugetPackages.cs b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/NugetPackages.cs index e29b1b4ac1e..94e65d61462 100644 --- a/csharp/extractor/Semmle.Extraction.CSharp.Standalone/NugetPackages.cs +++ b/csharp/extractor/Semmle.Extraction.CSharp.Standalone/NugetPackages.cs @@ -113,6 +113,12 @@ namespace Semmle.BuildAnalyser { using var p = Process.Start(pi); + if (p is null) + { + pm.FailedNugetCommand(pi.FileName, pi.Arguments, "Couldn't start process."); + return; + } + var output = p.StandardOutput.ReadToEnd(); var error = p.StandardError.ReadToEnd(); diff --git a/csharp/extractor/Semmle.Extraction/TrapWriter.cs b/csharp/extractor/Semmle.Extraction/TrapWriter.cs index e1004e66cc7..10ebd7a56cc 100644 --- a/csharp/extractor/Semmle.Extraction/TrapWriter.cs +++ b/csharp/extractor/Semmle.Extraction/TrapWriter.cs @@ -247,7 +247,13 @@ namespace Semmle.Extraction } try { - Directory.CreateDirectory(Path.GetDirectoryName(nested)); + var directoryName = Path.GetDirectoryName(nested); + if (directoryName is null) + { + logger.Log(Severity.Warning, "Failed to get directory name from path '" + nested + "'."); + throw new InvalidOperationException(); + } + Directory.CreateDirectory(directoryName); } catch (PathTooLongException) { diff --git a/csharp/extractor/Semmle.Util.Tests/LongPaths.cs b/csharp/extractor/Semmle.Util.Tests/LongPaths.cs index 44b047b6d8d..d65dd9e6a50 100644 --- a/csharp/extractor/Semmle.Util.Tests/LongPaths.cs +++ b/csharp/extractor/Semmle.Util.Tests/LongPaths.cs @@ -72,7 +72,7 @@ namespace SemmleTests.Semmle.Util public void Move() { File.WriteAllText(shortPath, "abc"); - Directory.CreateDirectory(Path.GetDirectoryName(longPath)); + Directory.CreateDirectory(Path.GetDirectoryName(longPath)!); File.Delete(longPath); File.Move(shortPath, longPath); File.Move(longPath, shortPath); @@ -84,7 +84,7 @@ namespace SemmleTests.Semmle.Util { File.WriteAllText(shortPath, "abc"); File.Delete(longPath); - Directory.CreateDirectory(Path.GetDirectoryName(longPath)); + Directory.CreateDirectory(Path.GetDirectoryName(longPath)!); File.Move(shortPath, longPath); File.WriteAllText(shortPath, "def"); FileUtils.MoveOrReplace(shortPath, longPath); @@ -117,7 +117,7 @@ namespace SemmleTests.Semmle.Util { var buffer2 = new byte[10]; - Directory.CreateDirectory(Path.GetDirectoryName(longPath)); + Directory.CreateDirectory(Path.GetDirectoryName(longPath)!); using (var s3 = new FileStream(longPath, FileMode.Create, FileAccess.Write, FileShare.None)) { diff --git a/csharp/extractor/Semmle.Util/ProcessStartInfoExtensions.cs b/csharp/extractor/Semmle.Util/ProcessStartInfoExtensions.cs index 998b6909e10..3519080ab76 100644 --- a/csharp/extractor/Semmle.Util/ProcessStartInfoExtensions.cs +++ b/csharp/extractor/Semmle.Util/ProcessStartInfoExtensions.cs @@ -13,6 +13,12 @@ namespace Semmle.Util { stdout = new List(); using var process = Process.Start(pi); + + if (process is null) + { + return -1; + } + string? s; do { From 2b1c6faefd6b0fbe7e3b2b19c71977fb62cfc208 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Wed, 10 Feb 2021 12:21:37 +0100 Subject: [PATCH 104/142] Fix failing test --- csharp/ql/test/library-tests/csharp9/FunctionPointer.expected | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/csharp/ql/test/library-tests/csharp9/FunctionPointer.expected b/csharp/ql/test/library-tests/csharp9/FunctionPointer.expected index d39e7d7d2af..2d2c60cecd8 100644 --- a/csharp/ql/test/library-tests/csharp9/FunctionPointer.expected +++ b/csharp/ql/test/library-tests/csharp9/FunctionPointer.expected @@ -5,6 +5,7 @@ type | file://:0:0:0:0 | delegate* default | readonly int | DefaultCallingConvention | | file://:0:0:0:0 | delegate* default | Void* | DefaultCallingConvention | | file://:0:0:0:0 | delegate* default | int | DefaultCallingConvention | +| file://:0:0:0:0 | delegate* default | Void | DefaultCallingConvention | | file://:0:0:0:0 | delegate* default | int | DefaultCallingConvention | | file://:0:0:0:0 | delegate* default | int* | DefaultCallingConvention | | file://:0:0:0:0 | delegate* stdcall | Void | StdCallCallingConvention | @@ -18,6 +19,9 @@ parameter | file://:0:0:0:0 | delegate* default | 0 | file://:0:0:0:0 | | ref int! | | file://:0:0:0:0 | delegate* default | 1 | file://:0:0:0:0 | `1 | out object? | | file://:0:0:0:0 | delegate* default | 0 | file://:0:0:0:0 | | int*! | +| file://:0:0:0:0 | delegate* default | 0 | file://:0:0:0:0 | | IntPtr! | +| file://:0:0:0:0 | delegate* default | 1 | file://:0:0:0:0 | `1 | IntPtr! | +| file://:0:0:0:0 | delegate* default | 2 | file://:0:0:0:0 | `2 | IntPtr*! | | file://:0:0:0:0 | delegate* default | 0 | file://:0:0:0:0 | | T | | file://:0:0:0:0 | delegate* default | 0 | file://:0:0:0:0 | | Void*! | | file://:0:0:0:0 | delegate* stdcall | 0 | file://:0:0:0:0 | | ref int! | From 6205ec233cb7154bd24cdbbabf78da09f080d6e2 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Thu, 11 Feb 2021 14:58:21 +0100 Subject: [PATCH 105/142] Fix more failing tests --- .../assemblies/compilation.expected | 8 +- .../cil/attributes/attribute.expected | 550 +++++++++++++++--- .../cil/consistency/consistency.expected | 18 + .../cil/dataflow/CallableReturns.expected | 7 +- .../library-tests/cil/enums/enums.expected | 28 +- .../functionPointers.expected | 7 + .../init-only-prop/customModifiers.expected | 15 +- .../typeAnnotations/typeAnnotations.expected | 459 +++++++++------ .../commons/TargetFramework/HasElement.ql | 2 +- .../commons/TargetFramework/NetCore.ql | 2 +- .../TargetFramework/TargetFrameworks.ql | 1 + .../dataflow/library/FlowSummaries.expected | 73 ++- .../Stubs/MinimalStubsFromSource.expected | 2 +- 13 files changed, 844 insertions(+), 328 deletions(-) diff --git a/csharp/ql/test/library-tests/assemblies/compilation.expected b/csharp/ql/test/library-tests/assemblies/compilation.expected index 5075507382c..9fbb90c90ef 100644 --- a/csharp/ql/test/library-tests/assemblies/compilation.expected +++ b/csharp/ql/test/library-tests/assemblies/compilation.expected @@ -1,9 +1,9 @@ | Assembly1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null | no compilation | | Locations, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null | has compilation | | System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 | no compilation | -| System.Console, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a | no compilation | +| System.Console, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a | no compilation | | System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 | no compilation | -| System.Private.CoreLib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e | no compilation | -| System.Runtime, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a | no compilation | -| System.Runtime.Extensions, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a | no compilation | +| System.Private.CoreLib, Version=5.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e | no compilation | +| System.Runtime, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a | no compilation | +| System.Runtime.Extensions, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a | no compilation | | mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 | no compilation | diff --git a/csharp/ql/test/library-tests/cil/attributes/attribute.expected b/csharp/ql/test/library-tests/cil/attributes/attribute.expected index 6ec0b072ec8..b43396e796d 100644 --- a/csharp/ql/test/library-tests/cil/attributes/attribute.expected +++ b/csharp/ql/test/library-tests/cil/attributes/attribute.expected @@ -1,24 +1,32 @@ attrNoArg | !0 System.ReadOnlySpan`1.Enumerator.Current | [IsReadOnlyAttribute(...)] | | !0 System.ReadOnlySpan`1.Item | [IsReadOnlyAttribute(...)] | -| <>f__AnonymousType0`1 | [CompilerGeneratedAttribute(...)] | | | [CompilerGeneratedAttribute(...)] | -| Internal.Runtime.InteropServices.ComponentActivator.<>c__DisplayClass6_0 | [CompilerGeneratedAttribute(...)] | -| Interop.Sys.<>c__DisplayClass39_0 | [CompilerGeneratedAttribute(...)] | +| Internal.Runtime.InteropServices.ComponentActivator.<>c__DisplayClass7_0 | [CompilerGeneratedAttribute(...)] | +| Interop.HostPolicy.corehost_error_writer_fn | [UnmanagedFunctionPointerAttribute(...)] | +| Interop.HostPolicy.corehost_resolve_component_dependencies_result_fn | [UnmanagedFunctionPointerAttribute(...)] | +| Interop.PollEvents | [FlagsAttribute(...)] | +| Interop.Sys.<>c__DisplayClass37_0 | [CompilerGeneratedAttribute(...)] | | Interop.Sys.FileStatusFlags | [FlagsAttribute(...)] | | Interop.Sys.OpenFlags | [FlagsAttribute(...)] | -| Interop.Sys.PollEvents | [FlagsAttribute(...)] | +| Interop.libobjc.NSOperatingSystemVersion.majorVersion | [NativeIntegerAttribute(...)] | +| Interop.libobjc.NSOperatingSystemVersion.minorVersion | [NativeIntegerAttribute(...)] | +| Interop.libobjc.NSOperatingSystemVersion.patchVersion | [NativeIntegerAttribute(...)] | | InteropErrorExtensions | [ExtensionAttribute(...)] | | Microsoft.CodeAnalysis.EmbeddedAttribute | [CompilerGeneratedAttribute(...)] | | Microsoft.CodeAnalysis.EmbeddedAttribute | [EmbeddedAttribute(...)] | -| Microsoft.Reflection.ReflectionExtensions | [ExtensionAttribute(...)] | | Microsoft.Win32.SafeHandles.SafeFileHandle.<>c | [CompilerGeneratedAttribute(...)] | | Microsoft.Win32.SafeHandles.SafeFileHandle.k__BackingField | [CompilerGeneratedAttribute(...)] | +| Microsoft.Win32.SafeHandles.SafeFileHandle.t_lastCloseErrorInfo | [ThreadStaticAttribute(...)] | | System.AppContext.FirstChanceException | [CompilerGeneratedAttribute(...)] | | System.AppContext.ProcessExit | [CompilerGeneratedAttribute(...)] | | System.AppContext.UnhandledException | [CompilerGeneratedAttribute(...)] | | System.AppDomain.DomainUnload | [CompilerGeneratedAttribute(...)] | | System.AppDomain.ReflectionOnlyAssemblyResolve | [CompilerGeneratedAttribute(...)] | +| System.ApplicationId.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.ApplicationId.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.ApplicationId.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.ApplicationId.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.ArgIterator | [IsByRefLikeAttribute(...)] | | System.Array.SorterGenericArray | [IsReadOnlyAttribute(...)] | | System.Array.SorterObjectArray | [IsReadOnlyAttribute(...)] | @@ -35,30 +43,19 @@ attrNoArg | System.ByReference`1 | [IsByRefLikeAttribute(...)] | | System.ByReference`1 | [IsReadOnlyAttribute(...)] | | System.ByReference`1 | [NonVersionableAttribute(...)] | -| System.Collections.Concurrent.ConcurrentQueueSegment`1.Slot.Item | [AllowNullAttribute(...)] | -| System.Collections.Concurrent.ConcurrentQueueSegment`1.Slot.Item | [MaybeNullAttribute(...)] | | System.Collections.Concurrent.ConcurrentQueue`1.d__26 | [CompilerGeneratedAttribute(...)] | +| System.Collections.Generic.BitHelper | [IsByRefLikeAttribute(...)] | | System.Collections.Generic.Comparer`1.k__BackingField | [CompilerGeneratedAttribute(...)] | -| System.Collections.Generic.Dictionary`2.KeyCollection.Enumerator._currentKey | [AllowNullAttribute(...)] | -| System.Collections.Generic.Dictionary`2.KeyCollection.Enumerator._currentKey | [MaybeNullAttribute(...)] | -| System.Collections.Generic.Dictionary`2.ValueCollection.Enumerator._currentValue | [AllowNullAttribute(...)] | -| System.Collections.Generic.Dictionary`2.ValueCollection.Enumerator._currentValue | [MaybeNullAttribute(...)] | | System.Collections.Generic.EqualityComparer`1.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Collections.Generic.KeyValuePair`2 | [IsReadOnlyAttribute(...)] | -| System.Collections.Generic.List`1.Enumerator._current | [AllowNullAttribute(...)] | -| System.Collections.Generic.List`1.Enumerator._current | [MaybeNullAttribute(...)] | -| System.Collections.Generic.NonRandomizedStringEqualityComparer.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Collections.Generic.ReferenceEqualityComparer.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Collections.Generic.ValueListBuilder`1 | [IsByRefLikeAttribute(...)] | -| System.CommonlyUsedGenericInstantiations.d__4`1 | [CompilerGeneratedAttribute(...)] | -| System.CommonlyUsedGenericInstantiations.d__5 | [CompilerGeneratedAttribute(...)] | -| System.CommonlyUsedGenericInstantiations.d__3`1 | [CompilerGeneratedAttribute(...)] | | System.ComponentModel.EditorBrowsableAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | -| System.Console.<>c | [CompilerGeneratedAttribute(...)] | | System.ConsoleCancelEventArgs.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.ConsoleKeyInfo | [IsReadOnlyAttribute(...)] | | System.ConsoleModifiers | [FlagsAttribute(...)] | | System.ConsolePal.<>c | [CompilerGeneratedAttribute(...)] | -| System.ConsolePal.<>c__DisplayClass115_0 | [CompilerGeneratedAttribute(...)] | +| System.ConsolePal.<>c__DisplayClass112_0 | [CompilerGeneratedAttribute(...)] | | System.ConsolePal.ControlCHandlerRegistrar.<>c | [CompilerGeneratedAttribute(...)] | | System.ConsolePal.TerminalFormatStrings.<>c | [CompilerGeneratedAttribute(...)] | | System.Convert | [ExtensionAttribute(...)] | @@ -68,15 +65,35 @@ attrNoArg | System.DateTimeResult | [IsByRefLikeAttribute(...)] | | System.DefaultBinder.Primitives | [FlagsAttribute(...)] | | System.Diagnostics.CodeAnalysis.DoesNotReturnIfAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes | [FlagsAttribute(...)] | +| System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Diagnostics.CodeAnalysis.MemberNotNullAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Diagnostics.CodeAnalysis.MemberNotNullWhenAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Diagnostics.CodeAnalysis.MemberNotNullWhenAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Diagnostics.CodeAnalysis.NotNullWhenAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Diagnostics.CodeAnalysis.SuppressMessageAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Diagnostics.CodeAnalysis.SuppressMessageAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Diagnostics.CodeAnalysis.SuppressMessageAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Diagnostics.CodeAnalysis.SuppressMessageAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Diagnostics.CodeAnalysis.SuppressMessageAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Diagnostics.CodeAnalysis.SuppressMessageAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Diagnostics.ConditionalAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Diagnostics.Debug.t_indentLevel | [ThreadStaticAttribute(...)] | | System.Diagnostics.DebuggableAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | @@ -93,6 +110,7 @@ attrNoArg | System.Diagnostics.DebuggerVisualizerAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Diagnostics.DebuggerVisualizerAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Diagnostics.StackFrameHelper.t_reentrancy | [ThreadStaticAttribute(...)] | +| System.Diagnostics.Tracing.CounterGroup.<>c__DisplayClass21_0 | [CompilerGeneratedAttribute(...)] | | System.Diagnostics.Tracing.CounterPayload | [EventDataAttribute(...)] | | System.Diagnostics.Tracing.CounterPayload.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Diagnostics.Tracing.CounterPayload.k__BackingField | [CompilerGeneratedAttribute(...)] | @@ -139,11 +157,11 @@ attrNoArg | System.Diagnostics.Tracing.EventListener._EventSourceCreated | [CompilerGeneratedAttribute(...)] | | System.Diagnostics.Tracing.EventManifestOptions | [FlagsAttribute(...)] | | System.Diagnostics.Tracing.EventPayload.d__17 | [CompilerGeneratedAttribute(...)] | -| System.Diagnostics.Tracing.EventPipeController.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Diagnostics.Tracing.EventPipeEventDispatcher.EventListenerSubscription.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Diagnostics.Tracing.EventPipeEventDispatcher.EventListenerSubscription.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Diagnostics.Tracing.EventProvider.<>c | [CompilerGeneratedAttribute(...)] | | System.Diagnostics.Tracing.EventProvider.s_returnCode | [ThreadStaticAttribute(...)] | +| System.Diagnostics.Tracing.EventSource.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Diagnostics.Tracing.EventSource.m_EventSourceExceptionRecurenceCount | [ThreadStaticAttribute(...)] | | System.Diagnostics.Tracing.EventSource.m_EventSourceInDecodeObject | [ThreadStaticAttribute(...)] | | System.Diagnostics.Tracing.EventSourceAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | @@ -207,17 +225,14 @@ attrNoArg | System.Diagnostics.Tracing.TraceLoggingTypeInfo.threadCache | [ThreadStaticAttribute(...)] | | System.Diagnostics.Tracing.XplatEventLogger.<>c | [CompilerGeneratedAttribute(...)] | | System.Environment.<>c | [CompilerGeneratedAttribute(...)] | +| System.Environment.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Exception.DispatchState | [IsReadOnlyAttribute(...)] | -| System.GC.MemoryLoadChangeNotification | [IsReadOnlyAttribute(...)] | -| System.GC.MemoryLoadChangeNotification.k__BackingField | [CompilerGeneratedAttribute(...)] | -| System.GC.MemoryLoadChangeNotification.k__BackingField | [CompilerGeneratedAttribute(...)] | -| System.GC.MemoryLoadChangeNotification.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.GCGenerationInfo | [IsReadOnlyAttribute(...)] | +| System.GCGenerationInfo.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.GCGenerationInfo.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.GCGenerationInfo.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.GCGenerationInfo.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.GCMemoryInfo | [IsReadOnlyAttribute(...)] | -| System.GCMemoryInfo.k__BackingField | [CompilerGeneratedAttribute(...)] | -| System.GCMemoryInfo.k__BackingField | [CompilerGeneratedAttribute(...)] | -| System.GCMemoryInfo.k__BackingField | [CompilerGeneratedAttribute(...)] | -| System.GCMemoryInfo.k__BackingField | [CompilerGeneratedAttribute(...)] | -| System.GCMemoryInfo.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Globalization.CalendarData.<>c | [CompilerGeneratedAttribute(...)] | | System.Globalization.CompareOptions | [FlagsAttribute(...)] | | System.Globalization.CultureInfo.s_currentThreadCulture | [ThreadStaticAttribute(...)] | @@ -230,6 +245,7 @@ attrNoArg | System.Globalization.GlobalizationMode.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Globalization.MonthNameStyles | [FlagsAttribute(...)] | | System.Globalization.NumberStyles | [FlagsAttribute(...)] | +| System.Globalization.OrdinalCasing | [ExtensionAttribute(...)] | | System.Globalization.TextInfo.ToLowerConversion | [IsReadOnlyAttribute(...)] | | System.Globalization.TextInfo.ToUpperConversion | [IsReadOnlyAttribute(...)] | | System.Globalization.TimeSpanParse.StringParser | [IsByRefLikeAttribute(...)] | @@ -240,6 +256,15 @@ attrNoArg | System.Globalization.TimeSpanParse.TimeSpanTokenizer | [IsByRefLikeAttribute(...)] | | System.Globalization.TimeSpanStyles | [FlagsAttribute(...)] | | System.Guid | [NonVersionableAttribute(...)] | +| System.Half | [IsReadOnlyAttribute(...)] | +| System.HexConverter.<>c | [CompilerGeneratedAttribute(...)] | +| System.IO.BufferedStream.<>c | [CompilerGeneratedAttribute(...)] | +| System.IO.BufferedStream.d__70 | [CompilerGeneratedAttribute(...)] | +| System.IO.BufferedStream.d__35 | [CompilerGeneratedAttribute(...)] | +| System.IO.BufferedStream.d__38 | [CompilerGeneratedAttribute(...)] | +| System.IO.BufferedStream.d__42 | [CompilerGeneratedAttribute(...)] | +| System.IO.BufferedStream.d__51 | [CompilerGeneratedAttribute(...)] | +| System.IO.BufferedStream.d__62 | [CompilerGeneratedAttribute(...)] | | System.IO.FileAccess | [FlagsAttribute(...)] | | System.IO.FileAttributes | [FlagsAttribute(...)] | | System.IO.FileLoadException.k__BackingField | [CompilerGeneratedAttribute(...)] | @@ -250,10 +275,10 @@ attrNoArg | System.IO.FileShare | [FlagsAttribute(...)] | | System.IO.FileStream.<>c | [CompilerGeneratedAttribute(...)] | | System.IO.Path.<>c | [CompilerGeneratedAttribute(...)] | -| System.IO.Stream.<g__FinishReadAsync\|47_0>d | [CompilerGeneratedAttribute(...)] | +| System.IO.Stream.<g__FinishReadAsync\|46_0>d | [CompilerGeneratedAttribute(...)] | | System.IO.Stream.<>c | [CompilerGeneratedAttribute(...)] | -| System.IO.Stream.d__30 | [CompilerGeneratedAttribute(...)] | -| System.IO.Stream.d__60 | [CompilerGeneratedAttribute(...)] | +| System.IO.Stream.d__29 | [CompilerGeneratedAttribute(...)] | +| System.IO.Stream.d__59 | [CompilerGeneratedAttribute(...)] | | System.IO.Stream.SynchronousAsyncResult.<>c | [CompilerGeneratedAttribute(...)] | | System.IO.StreamReader.d__64 | [CompilerGeneratedAttribute(...)] | | System.IO.StreamReader.d__67 | [CompilerGeneratedAttribute(...)] | @@ -298,8 +323,19 @@ attrNoArg | System.Number.FloatingPointInfo.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Number.FloatingPointInfo.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Number.NumberBuffer | [IsByRefLikeAttribute(...)] | +| System.Numerics.Matrix3x2 | [IntrinsicAttribute(...)] | +| System.Numerics.Matrix4x4 | [IntrinsicAttribute(...)] | +| System.Numerics.Plane | [IntrinsicAttribute(...)] | +| System.Numerics.Quaternion | [IntrinsicAttribute(...)] | | System.Numerics.Vector | [IntrinsicAttribute(...)] | +| System.Numerics.Vector2 | [IntrinsicAttribute(...)] | +| System.Numerics.Vector3 | [IntrinsicAttribute(...)] | +| System.Numerics.Vector4 | [IntrinsicAttribute(...)] | | System.Numerics.Vector`1 | [IntrinsicAttribute(...)] | +| System.ObsoleteAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.ObsoleteAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.ObsoleteAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.ObsoleteAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.ParamsArray | [IsReadOnlyAttribute(...)] | | System.ParseFlags | [FlagsAttribute(...)] | | System.Progress`1.ProgressChanged | [CompilerGeneratedAttribute(...)] | @@ -404,14 +440,14 @@ attrNoArg | System.Resources.NeutralResourcesLanguageAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Resources.ResourceFallbackManager.d__5 | [CompilerGeneratedAttribute(...)] | | System.Resources.ResourceReader.<>c | [CompilerGeneratedAttribute(...)] | -| System.Resources.ResourceReader.<>c__DisplayClass49_0`1 | [CompilerGeneratedAttribute(...)] | +| System.Resources.ResourceReader.<>c__DisplayClass7_0`1 | [CompilerGeneratedAttribute(...)] | | System.Resources.SatelliteContractVersionAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Runtime.AssemblyTargetedPatchBandAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Runtime.CompilerServices.AccessedThroughPropertyAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Runtime.CompilerServices.AsyncMethodBuilderAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | -| System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.StateMachine | [AllowNullAttribute(...)] | -| System.Runtime.CompilerServices.AsyncTaskMethodBuilder`1.AsyncStateMachineBox`1.StateMachine | [MaybeNullAttribute(...)] | | System.Runtime.CompilerServices.CallerArgumentExpressionAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Runtime.CompilerServices.CastHelpers.CastCacheEntry._source | [NativeIntegerAttribute(...)] | +| System.Runtime.CompilerServices.CastHelpers.CastCacheEntry._targetAndResult | [NativeIntegerAttribute(...)] | | System.Runtime.CompilerServices.CompilationRelaxations | [FlagsAttribute(...)] | | System.Runtime.CompilerServices.CompilationRelaxationsAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Runtime.CompilerServices.ConditionalWeakTable`2.<>c | [CompilerGeneratedAttribute(...)] | @@ -434,19 +470,30 @@ attrNoArg | System.Runtime.CompilerServices.FixedBufferAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Runtime.CompilerServices.InternalsVisibleToAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Runtime.CompilerServices.InternalsVisibleToAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | -| System.Runtime.CompilerServices.JitHelpers | [ExtensionAttribute(...)] | +| System.Runtime.CompilerServices.IsUnmanagedAttribute | [CompilerGeneratedAttribute(...)] | +| System.Runtime.CompilerServices.IsUnmanagedAttribute | [EmbeddedAttribute(...)] | | System.Runtime.CompilerServices.MethodImplAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Runtime.CompilerServices.MethodImplOptions | [FlagsAttribute(...)] | +| System.Runtime.CompilerServices.NativeIntegerAttribute | [CompilerGeneratedAttribute(...)] | +| System.Runtime.CompilerServices.NativeIntegerAttribute | [EmbeddedAttribute(...)] | | System.Runtime.CompilerServices.NullableAttribute | [CompilerGeneratedAttribute(...)] | | System.Runtime.CompilerServices.NullableAttribute | [EmbeddedAttribute(...)] | | System.Runtime.CompilerServices.NullableContextAttribute | [CompilerGeneratedAttribute(...)] | | System.Runtime.CompilerServices.NullableContextAttribute | [EmbeddedAttribute(...)] | | System.Runtime.CompilerServices.NullablePublicOnlyAttribute | [CompilerGeneratedAttribute(...)] | | System.Runtime.CompilerServices.NullablePublicOnlyAttribute | [EmbeddedAttribute(...)] | +| System.Runtime.CompilerServices.ObjectHandleOnStack | [IsByRefLikeAttribute(...)] | +| System.Runtime.CompilerServices.QCallAssembly | [IsByRefLikeAttribute(...)] | +| System.Runtime.CompilerServices.QCallModule | [IsByRefLikeAttribute(...)] | +| System.Runtime.CompilerServices.QCallTypeHandle | [IsByRefLikeAttribute(...)] | | System.Runtime.CompilerServices.ReferenceAssemblyAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Runtime.CompilerServices.RuntimeCompatibilityAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Runtime.CompilerServices.RuntimeHelpers | [ExtensionAttribute(...)] | +| System.Runtime.CompilerServices.StackCrawlMarkHandle | [IsByRefLikeAttribute(...)] | | System.Runtime.CompilerServices.StateMachineAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Runtime.CompilerServices.StringHandleOnStack | [IsByRefLikeAttribute(...)] | | System.Runtime.CompilerServices.StrongBox`1.Value | [MaybeNullAttribute(...)] | +| System.Runtime.CompilerServices.SwitchExpressionException.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Runtime.CompilerServices.TaskAwaiter | [IsReadOnlyAttribute(...)] | | System.Runtime.CompilerServices.TaskAwaiter.<>c | [CompilerGeneratedAttribute(...)] | | System.Runtime.CompilerServices.TaskAwaiter`1 | [IsReadOnlyAttribute(...)] | @@ -478,6 +525,8 @@ attrNoArg | System.Runtime.InteropServices.ComTypes.TYPEFLAGS | [FlagsAttribute(...)] | | System.Runtime.InteropServices.ComTypes.VARFLAGS | [FlagsAttribute(...)] | | System.Runtime.InteropServices.ComVisibleAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Runtime.InteropServices.CreateComInterfaceFlags | [FlagsAttribute(...)] | +| System.Runtime.InteropServices.CreateObjectFlags | [FlagsAttribute(...)] | | System.Runtime.InteropServices.CurrencyWrapper.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Runtime.InteropServices.DefaultCharSetAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Runtime.InteropServices.DefaultDllImportSearchPathsAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | @@ -494,14 +543,17 @@ attrNoArg | System.Runtime.InteropServices.LCIDConversionAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Runtime.InteropServices.Marshal.<>c | [CompilerGeneratedAttribute(...)] | | System.Runtime.InteropServices.MarshalAsAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | -| System.Runtime.InteropServices.MemoryMarshal.d__3`1 | [CompilerGeneratedAttribute(...)] | +| System.Runtime.InteropServices.MemoryMarshal.d__15`1 | [CompilerGeneratedAttribute(...)] | | System.Runtime.InteropServices.ProgIdAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Runtime.InteropServices.SafeBuffer._numBytes | [NativeIntegerAttribute(...)] | | System.Runtime.InteropServices.StructLayoutAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Runtime.InteropServices.TypeIdentifierAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Runtime.InteropServices.TypeIdentifierAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Runtime.InteropServices.UnknownWrapper.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Runtime.InteropServices.VariantWrapper.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Runtime.Intrinsics.Arm.Crc32 | [IntrinsicAttribute(...)] | +| System.Runtime.Intrinsics.Arm.Crc32.Arm64 | [IntrinsicAttribute(...)] | | System.Runtime.Intrinsics.Vector64 | [ExtensionAttribute(...)] | | System.Runtime.Intrinsics.Vector64DebugView`1 | [IsReadOnlyAttribute(...)] | | System.Runtime.Intrinsics.Vector64`1 | [IntrinsicAttribute(...)] | @@ -515,33 +567,40 @@ attrNoArg | System.Runtime.Intrinsics.Vector256`1 | [IntrinsicAttribute(...)] | | System.Runtime.Intrinsics.Vector256`1 | [IsReadOnlyAttribute(...)] | | System.Runtime.Intrinsics.X86.Aes | [IntrinsicAttribute(...)] | +| System.Runtime.Intrinsics.X86.Aes.X64 | [IntrinsicAttribute(...)] | | System.Runtime.Intrinsics.X86.Avx | [IntrinsicAttribute(...)] | | System.Runtime.Intrinsics.X86.Avx2 | [IntrinsicAttribute(...)] | +| System.Runtime.Intrinsics.X86.Avx2.X64 | [IntrinsicAttribute(...)] | +| System.Runtime.Intrinsics.X86.Avx.X64 | [IntrinsicAttribute(...)] | | System.Runtime.Intrinsics.X86.Bmi1 | [IntrinsicAttribute(...)] | | System.Runtime.Intrinsics.X86.Bmi1.X64 | [IntrinsicAttribute(...)] | | System.Runtime.Intrinsics.X86.Bmi2 | [IntrinsicAttribute(...)] | | System.Runtime.Intrinsics.X86.Bmi2.X64 | [IntrinsicAttribute(...)] | | System.Runtime.Intrinsics.X86.Fma | [IntrinsicAttribute(...)] | +| System.Runtime.Intrinsics.X86.Fma.X64 | [IntrinsicAttribute(...)] | | System.Runtime.Intrinsics.X86.Lzcnt | [IntrinsicAttribute(...)] | | System.Runtime.Intrinsics.X86.Lzcnt.X64 | [IntrinsicAttribute(...)] | | System.Runtime.Intrinsics.X86.Pclmulqdq | [IntrinsicAttribute(...)] | +| System.Runtime.Intrinsics.X86.Pclmulqdq.X64 | [IntrinsicAttribute(...)] | | System.Runtime.Intrinsics.X86.Popcnt | [IntrinsicAttribute(...)] | | System.Runtime.Intrinsics.X86.Popcnt.X64 | [IntrinsicAttribute(...)] | | System.Runtime.Intrinsics.X86.Sse | [IntrinsicAttribute(...)] | | System.Runtime.Intrinsics.X86.Sse2 | [IntrinsicAttribute(...)] | | System.Runtime.Intrinsics.X86.Sse2.X64 | [IntrinsicAttribute(...)] | | System.Runtime.Intrinsics.X86.Sse3 | [IntrinsicAttribute(...)] | +| System.Runtime.Intrinsics.X86.Sse3.X64 | [IntrinsicAttribute(...)] | | System.Runtime.Intrinsics.X86.Sse41 | [IntrinsicAttribute(...)] | | System.Runtime.Intrinsics.X86.Sse41.X64 | [IntrinsicAttribute(...)] | | System.Runtime.Intrinsics.X86.Sse42 | [IntrinsicAttribute(...)] | | System.Runtime.Intrinsics.X86.Sse42.X64 | [IntrinsicAttribute(...)] | | System.Runtime.Intrinsics.X86.Sse.X64 | [IntrinsicAttribute(...)] | | System.Runtime.Intrinsics.X86.Ssse3 | [IntrinsicAttribute(...)] | +| System.Runtime.Intrinsics.X86.Ssse3.X64 | [IntrinsicAttribute(...)] | +| System.Runtime.Intrinsics.X86.X86Base | [IntrinsicAttribute(...)] | +| System.Runtime.Intrinsics.X86.X86Base.X64 | [IntrinsicAttribute(...)] | | System.Runtime.Loader.AssemblyDependencyResolver.<>c__DisplayClass6_0 | [CompilerGeneratedAttribute(...)] | -| System.Runtime.Loader.AssemblyDependencyResolver.corehost_error_writer_fn | [UnmanagedFunctionPointerAttribute(...)] | -| System.Runtime.Loader.AssemblyDependencyResolver.corehost_resolve_component_dependencies_result_fn | [UnmanagedFunctionPointerAttribute(...)] | -| System.Runtime.Loader.AssemblyLoadContext.d__88 | [CompilerGeneratedAttribute(...)] | -| System.Runtime.Loader.AssemblyLoadContext.d__58 | [CompilerGeneratedAttribute(...)] | +| System.Runtime.Loader.AssemblyLoadContext.d__83 | [CompilerGeneratedAttribute(...)] | +| System.Runtime.Loader.AssemblyLoadContext.d__53 | [CompilerGeneratedAttribute(...)] | | System.Runtime.Loader.AssemblyLoadContext.AssemblyLoad | [CompilerGeneratedAttribute(...)] | | System.Runtime.Loader.AssemblyLoadContext.AssemblyResolve | [CompilerGeneratedAttribute(...)] | | System.Runtime.Loader.AssemblyLoadContext.ResourceResolve | [CompilerGeneratedAttribute(...)] | @@ -560,9 +619,35 @@ attrNoArg | System.Runtime.Serialization.StreamingContext | [IsReadOnlyAttribute(...)] | | System.Runtime.Serialization.StreamingContextStates | [FlagsAttribute(...)] | | System.Runtime.TargetedPatchingOptOutAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Runtime.Versioning.ComponentGuaranteesAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Runtime.Versioning.ComponentGuaranteesOptions | [FlagsAttribute(...)] | +| System.Runtime.Versioning.OSPlatformAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Runtime.Versioning.ResourceConsumptionAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Runtime.Versioning.ResourceConsumptionAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Runtime.Versioning.ResourceExposureAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Runtime.Versioning.ResourceScope | [FlagsAttribute(...)] | +| System.Runtime.Versioning.SxSRequirements | [FlagsAttribute(...)] | | System.RuntimeArgumentHandle | [IsByRefLikeAttribute(...)] | | System.RuntimeType.RuntimeTypeCache.Filter | [IsReadOnlyAttribute(...)] | | System.Security.AllowPartiallyTrustedCallersAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Security.Permissions.SecurityAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Security.Permissions.SecurityAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Security.Permissions.SecurityPermissionAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Security.Permissions.SecurityPermissionAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Security.Permissions.SecurityPermissionAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Security.Permissions.SecurityPermissionAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Security.Permissions.SecurityPermissionAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Security.Permissions.SecurityPermissionAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Security.Permissions.SecurityPermissionAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Security.Permissions.SecurityPermissionAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Security.Permissions.SecurityPermissionAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Security.Permissions.SecurityPermissionAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Security.Permissions.SecurityPermissionAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Security.Permissions.SecurityPermissionAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Security.Permissions.SecurityPermissionAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Security.Permissions.SecurityPermissionAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Security.Permissions.SecurityPermissionAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Security.Permissions.SecurityPermissionFlag | [FlagsAttribute(...)] | | System.Security.SecurityCriticalAttribute.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Security.SecurityElement.<>c | [CompilerGeneratedAttribute(...)] | | System.Security.SecurityException.k__BackingField | [CompilerGeneratedAttribute(...)] | @@ -583,13 +668,13 @@ attrNoArg | System.Span`1 | [IsReadOnlyAttribute(...)] | | System.Span`1 | [NonVersionableAttribute(...)] | | System.Span`1.Enumerator | [IsByRefLikeAttribute(...)] | +| System.StringNormalizationExtensions | [ExtensionAttribute(...)] | | System.StringSplitOptions | [FlagsAttribute(...)] | | System.TermInfo.ParameterizedStrings.FormatParam | [IsReadOnlyAttribute(...)] | | System.TermInfo.ParameterizedStrings.t_cachedOneElementArgsArray | [ThreadStaticAttribute(...)] | | System.TermInfo.ParameterizedStrings.t_cachedStack | [ThreadStaticAttribute(...)] | | System.TermInfo.ParameterizedStrings.t_cachedTwoElementArgsArray | [ThreadStaticAttribute(...)] | | System.Text.CodePageDataItem.k__BackingField | [CompilerGeneratedAttribute(...)] | -| System.Text.CodePageDataItem.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Text.CodePageDataItem.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Text.CodePageDataItem.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Text.CodePageDataItem.k__BackingField | [CompilerGeneratedAttribute(...)] | @@ -599,10 +684,19 @@ attrNoArg | System.Text.EncodingInfo.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Text.EncodingInfo.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Text.EncodingInfo.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Text.EncodingInfo.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Text.Latin1Encoding.<>c | [CompilerGeneratedAttribute(...)] | | System.Text.Rune | [IsReadOnlyAttribute(...)] | | System.Text.SpanRuneEnumerator | [IsByRefLikeAttribute(...)] | | System.Text.StringBuilderCache.t_cachedInstance | [ThreadStaticAttribute(...)] | | System.Text.StringOrCharArray | [IsReadOnlyAttribute(...)] | +| System.Text.TranscodingStream.<g__DisposeAsyncCore\|30_0>d | [CompilerGeneratedAttribute(...)] | +| System.Text.TranscodingStream.<g__ReadAsyncCore\|41_0>d | [CompilerGeneratedAttribute(...)] | +| System.Text.TranscodingStream.<g__WriteAsyncCore\|50_0>d | [CompilerGeneratedAttribute(...)] | +| System.Text.TrimType | [FlagsAttribute(...)] | +| System.Text.Unicode.TextSegmentationUtility.Processor`1 | [IsByRefLikeAttribute(...)] | +| System.Text.Unicode.TextSegmentationUtility.Processor`1.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Text.Unicode.TextSegmentationUtility.Processor`1.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Text.ValueStringBuilder | [IsByRefLikeAttribute(...)] | | System.Threading.AsyncLocalValueChangedArgs`1 | [IsReadOnlyAttribute(...)] | | System.Threading.AsyncLocalValueChangedArgs`1.k__BackingField | [CompilerGeneratedAttribute(...)] | @@ -615,6 +709,7 @@ attrNoArg | System.Threading.CancellationTokenSource.<>c | [CompilerGeneratedAttribute(...)] | | System.Threading.CancellationTokenSource.CallbackNode.<>c | [CompilerGeneratedAttribute(...)] | | System.Threading.CancellationTokenSource.LinkedNCancellationTokenSource.<>c | [CompilerGeneratedAttribute(...)] | +| System.Threading.ProcessorIdCache.t_currentProcessorIdCache | [ThreadStaticAttribute(...)] | | System.Threading.QueueUserWorkItemCallback.<>c | [CompilerGeneratedAttribute(...)] | | System.Threading.ReaderWriterLockSlim.WaiterStates | [FlagsAttribute(...)] | | System.Threading.ReaderWriterLockSlim.t_rwc | [ThreadStaticAttribute(...)] | @@ -629,14 +724,11 @@ attrNoArg | System.Threading.Tasks.SingleProducerSingleConsumerQueue`1.d__11 | [CompilerGeneratedAttribute(...)] | | System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore`1.<>c | [CompilerGeneratedAttribute(...)] | | System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore`1.k__BackingField | [CompilerGeneratedAttribute(...)] | -| System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore`1._result | [AllowNullAttribute(...)] | -| System.Threading.Tasks.Sources.ManualResetValueTaskSourceCore`1._result | [MaybeNullAttribute(...)] | | System.Threading.Tasks.Sources.ValueTaskSourceOnCompletedFlags | [FlagsAttribute(...)] | | System.Threading.Tasks.SynchronizationContextAwaitTaskContinuation.<>c | [CompilerGeneratedAttribute(...)] | | System.Threading.Tasks.SynchronizationContextAwaitTaskContinuation.<>c__DisplayClass6_0 | [CompilerGeneratedAttribute(...)] | | System.Threading.Tasks.SynchronizationContextTaskScheduler.<>c | [CompilerGeneratedAttribute(...)] | | System.Threading.Tasks.Task.<>c | [CompilerGeneratedAttribute(...)] | -| System.Threading.Tasks.Task.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Threading.Tasks.Task.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Threading.Tasks.Task.DelayPromise.<>c | [CompilerGeneratedAttribute(...)] | | System.Threading.Tasks.Task.DelayPromiseWithCancellation.<>c | [CompilerGeneratedAttribute(...)] | @@ -651,13 +743,11 @@ attrNoArg | System.Threading.Tasks.TaskFactory`1.<>c__DisplayClass38_0`1 | [CompilerGeneratedAttribute(...)] | | System.Threading.Tasks.TaskFactory`1.<>c__DisplayClass41_0`2 | [CompilerGeneratedAttribute(...)] | | System.Threading.Tasks.TaskFactory`1.<>c__DisplayClass44_0`3 | [CompilerGeneratedAttribute(...)] | -| System.Threading.Tasks.TaskFactory`1.FromAsyncTrimPromise`1.m_thisRef | [AllowNullAttribute(...)] | -| System.Threading.Tasks.TaskFactory`1.FromAsyncTrimPromise`1.m_thisRef | [MaybeNullAttribute(...)] | | System.Threading.Tasks.TaskScheduler.UnobservedTaskException | [CompilerGeneratedAttribute(...)] | | System.Threading.Tasks.TaskSchedulerAwaitTaskContinuation.<>c | [CompilerGeneratedAttribute(...)] | -| System.Threading.Tasks.TaskToApm.<>c__DisplayClass3_0 | [CompilerGeneratedAttribute(...)] | +| System.Threading.Tasks.TaskToApm.TaskAsyncResult.k__BackingField | [CompilerGeneratedAttribute(...)] | +| System.Threading.Tasks.TaskToApm.TaskAsyncResult.k__BackingField | [CompilerGeneratedAttribute(...)] | | System.Threading.Tasks.Task`1.TaskWhenAnyCast.<>c | [CompilerGeneratedAttribute(...)] | -| System.Threading.Tasks.Task`1.m_result | [MaybeNullAttribute(...)] | | System.Threading.Tasks.ThreadPoolTaskScheduler.<>c | [CompilerGeneratedAttribute(...)] | | System.Threading.Tasks.ThreadPoolTaskScheduler.d__6 | [CompilerGeneratedAttribute(...)] | | System.Threading.Tasks.UnwrapPromise`1.<>c | [CompilerGeneratedAttribute(...)] | @@ -665,17 +755,13 @@ attrNoArg | System.Threading.Tasks.ValueTask.ValueTaskSourceAsTask.<>c | [CompilerGeneratedAttribute(...)] | | System.Threading.Tasks.ValueTask`1 | [IsReadOnlyAttribute(...)] | | System.Threading.Tasks.ValueTask`1.ValueTaskSourceAsTask.<>c | [CompilerGeneratedAttribute(...)] | -| System.Threading.Tasks.ValueTask`1._result | [AllowNullAttribute(...)] | -| System.Threading.Thread.t_currentProcessorIdCache | [ThreadStaticAttribute(...)] | | System.Threading.Thread.t_currentThread | [ThreadStaticAttribute(...)] | | System.Threading.ThreadHandle | [IsReadOnlyAttribute(...)] | -| System.Threading.ThreadLocal`1.LinkedSlot._value | [AllowNullAttribute(...)] | -| System.Threading.ThreadLocal`1.LinkedSlot._value | [MaybeNullAttribute(...)] | | System.Threading.ThreadLocal`1.ts_finalizationHelper | [ThreadStaticAttribute(...)] | | System.Threading.ThreadLocal`1.ts_slotArray | [ThreadStaticAttribute(...)] | -| System.Threading.ThreadPool.d__51 | [CompilerGeneratedAttribute(...)] | -| System.Threading.ThreadPool.d__50 | [CompilerGeneratedAttribute(...)] | -| System.Threading.ThreadPoolGlobals.<>c | [CompilerGeneratedAttribute(...)] | +| System.Threading.ThreadPool.<>c | [CompilerGeneratedAttribute(...)] | +| System.Threading.ThreadPool.d__52 | [CompilerGeneratedAttribute(...)] | +| System.Threading.ThreadPool.d__51 | [CompilerGeneratedAttribute(...)] | | System.Threading.ThreadPoolWorkQueueThreadLocals.threadLocals | [ThreadStaticAttribute(...)] | | System.Threading.ThreadState | [FlagsAttribute(...)] | | System.Threading.TimerQueue.k__BackingField | [CompilerGeneratedAttribute(...)] | @@ -686,7 +772,7 @@ attrNoArg | System.ThrowHelper | [StackTraceHiddenAttribute(...)] | | System.TimeSpan | [IsReadOnlyAttribute(...)] | | System.TimeZoneInfo.<>c | [CompilerGeneratedAttribute(...)] | -| System.TimeZoneInfo.<>c__DisplayClass125_0 | [CompilerGeneratedAttribute(...)] | +| System.TimeZoneInfo.<>c__DisplayClass124_0 | [CompilerGeneratedAttribute(...)] | | System.TimeZoneInfo.TransitionTime | [IsReadOnlyAttribute(...)] | | System.TimeZoneInfoOptions | [FlagsAttribute(...)] | | System.TupleExtensions | [ExtensionAttribute(...)] | @@ -694,6 +780,7 @@ attrNoArg | System.TypedReference | [IsByRefLikeAttribute(...)] | | System.TypedReference | [NonVersionableAttribute(...)] | | System.UIntPtr | [IsReadOnlyAttribute(...)] | +| System.UIntPtr System.Runtime.InteropServices.SafeBuffer.Uninitialized | [NativeIntegerAttribute(...)] | | System.UIntPtr.Zero | [IntrinsicAttribute(...)] | | System.__DTString | [IsByRefLikeAttribute(...)] | | bool | [IsReadOnlyAttribute(...)] | @@ -719,19 +806,34 @@ attrArgNamed | System.Buffers.ArrayPoolEventSource | [EventSourceAttribute(...)] | Name | System.Buffers.ArrayPoolEventSource | | System.CLSCompliantAttribute | [AttributeUsageAttribute(...)] | AllowMultiple | False | | System.CLSCompliantAttribute | [AttributeUsageAttribute(...)] | Inherited | True | +| System.CodeDom.Compiler.GeneratedCodeAttribute | [AttributeUsageAttribute(...)] | AllowMultiple | False | +| System.CodeDom.Compiler.GeneratedCodeAttribute | [AttributeUsageAttribute(...)] | Inherited | False | | System.Collections.KeyValuePairs | [DebuggerDisplayAttribute(...)] | Name | [{_key}] | +| System.ContextStaticAttribute | [AttributeUsageAttribute(...)] | Inherited | False | | System.Diagnostics.CodeAnalysis.AllowNullAttribute | [AttributeUsageAttribute(...)] | Inherited | False | | System.Diagnostics.CodeAnalysis.DisallowNullAttribute | [AttributeUsageAttribute(...)] | Inherited | False | | System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute | [AttributeUsageAttribute(...)] | Inherited | False | | System.Diagnostics.CodeAnalysis.DoesNotReturnIfAttribute | [AttributeUsageAttribute(...)] | Inherited | False | +| System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute | [AttributeUsageAttribute(...)] | AllowMultiple | True | +| System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute | [AttributeUsageAttribute(...)] | Inherited | False | +| System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute | [AttributeUsageAttribute(...)] | Inherited | False | +| System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute | [AttributeUsageAttribute(...)] | AllowMultiple | False | +| System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute | [AttributeUsageAttribute(...)] | Inherited | False | | System.Diagnostics.CodeAnalysis.MaybeNullAttribute | [AttributeUsageAttribute(...)] | Inherited | False | | System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute | [AttributeUsageAttribute(...)] | Inherited | False | +| System.Diagnostics.CodeAnalysis.MemberNotNullAttribute | [AttributeUsageAttribute(...)] | AllowMultiple | True | +| System.Diagnostics.CodeAnalysis.MemberNotNullAttribute | [AttributeUsageAttribute(...)] | Inherited | False | +| System.Diagnostics.CodeAnalysis.MemberNotNullWhenAttribute | [AttributeUsageAttribute(...)] | AllowMultiple | True | +| System.Diagnostics.CodeAnalysis.MemberNotNullWhenAttribute | [AttributeUsageAttribute(...)] | Inherited | False | | System.Diagnostics.CodeAnalysis.NotNullAttribute | [AttributeUsageAttribute(...)] | Inherited | False | | System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute | [AttributeUsageAttribute(...)] | AllowMultiple | True | | System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute | [AttributeUsageAttribute(...)] | Inherited | False | | System.Diagnostics.CodeAnalysis.NotNullWhenAttribute | [AttributeUsageAttribute(...)] | Inherited | False | +| System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute | [AttributeUsageAttribute(...)] | Inherited | False | | System.Diagnostics.CodeAnalysis.SuppressMessageAttribute | [AttributeUsageAttribute(...)] | AllowMultiple | True | | System.Diagnostics.CodeAnalysis.SuppressMessageAttribute | [AttributeUsageAttribute(...)] | Inherited | False | +| System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute | [AttributeUsageAttribute(...)] | AllowMultiple | True | +| System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute | [AttributeUsageAttribute(...)] | Inherited | False | | System.Diagnostics.ConditionalAttribute | [AttributeUsageAttribute(...)] | AllowMultiple | True | | System.Diagnostics.Contracts.ContractAbbreviatorAttribute | [AttributeUsageAttribute(...)] | AllowMultiple | False | | System.Diagnostics.Contracts.ContractArgumentValidatorAttribute | [AttributeUsageAttribute(...)] | AllowMultiple | False | @@ -827,15 +929,21 @@ attrArgNamed | System.Runtime.CompilerServices.IteratorStateMachineAttribute | [AttributeUsageAttribute(...)] | AllowMultiple | False | | System.Runtime.CompilerServices.IteratorStateMachineAttribute | [AttributeUsageAttribute(...)] | Inherited | False | | System.Runtime.CompilerServices.MethodImplAttribute | [AttributeUsageAttribute(...)] | Inherited | False | +| System.Runtime.CompilerServices.ModuleInitializerAttribute | [AttributeUsageAttribute(...)] | Inherited | False | +| System.Runtime.CompilerServices.NativeIntegerAttribute | [AttributeUsageAttribute(...)] | AllowMultiple | False | +| System.Runtime.CompilerServices.NativeIntegerAttribute | [AttributeUsageAttribute(...)] | Inherited | False | | System.Runtime.CompilerServices.NullableAttribute | [AttributeUsageAttribute(...)] | AllowMultiple | False | | System.Runtime.CompilerServices.NullableAttribute | [AttributeUsageAttribute(...)] | Inherited | False | | System.Runtime.CompilerServices.NullableContextAttribute | [AttributeUsageAttribute(...)] | AllowMultiple | False | | System.Runtime.CompilerServices.NullableContextAttribute | [AttributeUsageAttribute(...)] | Inherited | False | | System.Runtime.CompilerServices.NullablePublicOnlyAttribute | [AttributeUsageAttribute(...)] | AllowMultiple | False | | System.Runtime.CompilerServices.NullablePublicOnlyAttribute | [AttributeUsageAttribute(...)] | Inherited | False | +| System.Runtime.CompilerServices.PreserveBaseOverridesAttribute | [AttributeUsageAttribute(...)] | AllowMultiple | False | +| System.Runtime.CompilerServices.PreserveBaseOverridesAttribute | [AttributeUsageAttribute(...)] | Inherited | False | | System.Runtime.CompilerServices.ReferenceAssemblyAttribute | [AttributeUsageAttribute(...)] | AllowMultiple | False | | System.Runtime.CompilerServices.RuntimeCompatibilityAttribute | [AttributeUsageAttribute(...)] | AllowMultiple | False | | System.Runtime.CompilerServices.RuntimeCompatibilityAttribute | [AttributeUsageAttribute(...)] | Inherited | False | +| System.Runtime.CompilerServices.SkipLocalsInitAttribute | [AttributeUsageAttribute(...)] | Inherited | False | | System.Runtime.CompilerServices.StateMachineAttribute | [AttributeUsageAttribute(...)] | AllowMultiple | False | | System.Runtime.CompilerServices.StateMachineAttribute | [AttributeUsageAttribute(...)] | Inherited | False | | System.Runtime.CompilerServices.StringFreezingAttribute | [AttributeUsageAttribute(...)] | Inherited | False | @@ -845,12 +953,22 @@ attrArgNamed | System.Runtime.CompilerServices.TypeForwardedFromAttribute | [AttributeUsageAttribute(...)] | Inherited | False | | System.Runtime.CompilerServices.TypeForwardedToAttribute | [AttributeUsageAttribute(...)] | AllowMultiple | True | | System.Runtime.CompilerServices.TypeForwardedToAttribute | [AttributeUsageAttribute(...)] | Inherited | False | +| System.Runtime.ConstrainedExecution.Cer | [ObsoleteAttribute(...)] | DiagnosticId | SYSLIB0004 | +| System.Runtime.ConstrainedExecution.Cer | [ObsoleteAttribute(...)] | UrlFormat | https://aka.ms/dotnet-warnings/{0} | +| System.Runtime.ConstrainedExecution.Consistency | [ObsoleteAttribute(...)] | DiagnosticId | SYSLIB0004 | +| System.Runtime.ConstrainedExecution.Consistency | [ObsoleteAttribute(...)] | UrlFormat | https://aka.ms/dotnet-warnings/{0} | | System.Runtime.ConstrainedExecution.PrePrepareMethodAttribute | [AttributeUsageAttribute(...)] | Inherited | False | +| System.Runtime.ConstrainedExecution.PrePrepareMethodAttribute | [ObsoleteAttribute(...)] | DiagnosticId | SYSLIB0004 | +| System.Runtime.ConstrainedExecution.PrePrepareMethodAttribute | [ObsoleteAttribute(...)] | UrlFormat | https://aka.ms/dotnet-warnings/{0} | | System.Runtime.ConstrainedExecution.ReliabilityContractAttribute | [AttributeUsageAttribute(...)] | Inherited | False | +| System.Runtime.ConstrainedExecution.ReliabilityContractAttribute | [ObsoleteAttribute(...)] | DiagnosticId | SYSLIB0004 | +| System.Runtime.ConstrainedExecution.ReliabilityContractAttribute | [ObsoleteAttribute(...)] | UrlFormat | https://aka.ms/dotnet-warnings/{0} | | System.Runtime.ExceptionServices.HandleProcessCorruptedStateExceptionsAttribute | [AttributeUsageAttribute(...)] | AllowMultiple | False | | System.Runtime.ExceptionServices.HandleProcessCorruptedStateExceptionsAttribute | [AttributeUsageAttribute(...)] | Inherited | False | | System.Runtime.InteropServices.AllowReversePInvokeCallsAttribute | [AttributeUsageAttribute(...)] | AllowMultiple | False | | System.Runtime.InteropServices.AllowReversePInvokeCallsAttribute | [AttributeUsageAttribute(...)] | Inherited | False | +| System.Runtime.InteropServices.AllowReversePInvokeCallsAttribute | [ObsoleteAttribute(...)] | DiagnosticId | SYSLIB0003 | +| System.Runtime.InteropServices.AllowReversePInvokeCallsAttribute | [ObsoleteAttribute(...)] | UrlFormat | https://aka.ms/dotnet-warnings/{0} | | System.Runtime.InteropServices.BestFitMappingAttribute | [AttributeUsageAttribute(...)] | Inherited | False | | System.Runtime.InteropServices.ClassInterfaceAttribute | [AttributeUsageAttribute(...)] | Inherited | False | | System.Runtime.InteropServices.CoClassAttribute | [AttributeUsageAttribute(...)] | Inherited | False | @@ -863,6 +981,8 @@ attrArgNamed | System.Runtime.InteropServices.DefaultDllImportSearchPathsAttribute | [AttributeUsageAttribute(...)] | AllowMultiple | False | | System.Runtime.InteropServices.DispIdAttribute | [AttributeUsageAttribute(...)] | Inherited | False | | System.Runtime.InteropServices.DllImportAttribute | [AttributeUsageAttribute(...)] | Inherited | False | +| System.Runtime.InteropServices.DynamicInterfaceCastableImplementationAttribute | [AttributeUsageAttribute(...)] | AllowMultiple | False | +| System.Runtime.InteropServices.DynamicInterfaceCastableImplementationAttribute | [AttributeUsageAttribute(...)] | Inherited | False | | System.Runtime.InteropServices.FieldOffsetAttribute | [AttributeUsageAttribute(...)] | Inherited | False | | System.Runtime.InteropServices.GuidAttribute | [AttributeUsageAttribute(...)] | Inherited | False | | System.Runtime.InteropServices.InAttribute | [AttributeUsageAttribute(...)] | Inherited | False | @@ -874,8 +994,10 @@ attrArgNamed | System.Runtime.InteropServices.PreserveSigAttribute | [AttributeUsageAttribute(...)] | Inherited | False | | System.Runtime.InteropServices.ProgIdAttribute | [AttributeUsageAttribute(...)] | Inherited | False | | System.Runtime.InteropServices.StructLayoutAttribute | [AttributeUsageAttribute(...)] | Inherited | False | +| System.Runtime.InteropServices.SuppressGCTransitionAttribute | [AttributeUsageAttribute(...)] | Inherited | False | | System.Runtime.InteropServices.TypeIdentifierAttribute | [AttributeUsageAttribute(...)] | AllowMultiple | False | | System.Runtime.InteropServices.TypeIdentifierAttribute | [AttributeUsageAttribute(...)] | Inherited | False | +| System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute | [AttributeUsageAttribute(...)] | Inherited | False | | System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute | [AttributeUsageAttribute(...)] | AllowMultiple | False | | System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute | [AttributeUsageAttribute(...)] | Inherited | False | | System.Runtime.Serialization.OnDeserializedAttribute | [AttributeUsageAttribute(...)] | Inherited | False | @@ -885,12 +1007,48 @@ attrArgNamed | System.Runtime.Serialization.OptionalFieldAttribute | [AttributeUsageAttribute(...)] | Inherited | False | | System.Runtime.TargetedPatchingOptOutAttribute | [AttributeUsageAttribute(...)] | AllowMultiple | False | | System.Runtime.TargetedPatchingOptOutAttribute | [AttributeUsageAttribute(...)] | Inherited | False | +| System.Runtime.Versioning.ComponentGuaranteesAttribute | [AttributeUsageAttribute(...)] | AllowMultiple | False | +| System.Runtime.Versioning.ComponentGuaranteesAttribute | [AttributeUsageAttribute(...)] | Inherited | False | | System.Runtime.Versioning.NonVersionableAttribute | [AttributeUsageAttribute(...)] | AllowMultiple | False | | System.Runtime.Versioning.NonVersionableAttribute | [AttributeUsageAttribute(...)] | Inherited | False | +| System.Runtime.Versioning.ResourceConsumptionAttribute | [AttributeUsageAttribute(...)] | Inherited | False | +| System.Runtime.Versioning.ResourceExposureAttribute | [AttributeUsageAttribute(...)] | Inherited | False | +| System.Runtime.Versioning.SupportedOSPlatformAttribute | [AttributeUsageAttribute(...)] | AllowMultiple | True | +| System.Runtime.Versioning.SupportedOSPlatformAttribute | [AttributeUsageAttribute(...)] | Inherited | False | | System.Runtime.Versioning.TargetFrameworkAttribute | [AttributeUsageAttribute(...)] | AllowMultiple | False | | System.Runtime.Versioning.TargetFrameworkAttribute | [AttributeUsageAttribute(...)] | Inherited | False | +| System.Runtime.Versioning.TargetPlatformAttribute | [AttributeUsageAttribute(...)] | AllowMultiple | False | +| System.Runtime.Versioning.TargetPlatformAttribute | [AttributeUsageAttribute(...)] | Inherited | False | +| System.Runtime.Versioning.UnsupportedOSPlatformAttribute | [AttributeUsageAttribute(...)] | AllowMultiple | True | +| System.Runtime.Versioning.UnsupportedOSPlatformAttribute | [AttributeUsageAttribute(...)] | Inherited | False | | System.Security.AllowPartiallyTrustedCallersAttribute | [AttributeUsageAttribute(...)] | AllowMultiple | False | | System.Security.AllowPartiallyTrustedCallersAttribute | [AttributeUsageAttribute(...)] | Inherited | False | +| System.Security.IPermission | [ObsoleteAttribute(...)] | DiagnosticId | SYSLIB0003 | +| System.Security.IPermission | [ObsoleteAttribute(...)] | UrlFormat | https://aka.ms/dotnet-warnings/{0} | +| System.Security.IStackWalk | [ObsoleteAttribute(...)] | DiagnosticId | SYSLIB0003 | +| System.Security.IStackWalk | [ObsoleteAttribute(...)] | UrlFormat | https://aka.ms/dotnet-warnings/{0} | +| System.Security.PermissionSet | [ObsoleteAttribute(...)] | DiagnosticId | SYSLIB0003 | +| System.Security.PermissionSet | [ObsoleteAttribute(...)] | UrlFormat | https://aka.ms/dotnet-warnings/{0} | +| System.Security.PermissionSet System.AppDomain.PermissionSet | [ObsoleteAttribute(...)] | DiagnosticId | SYSLIB0003 | +| System.Security.PermissionSet System.AppDomain.PermissionSet | [ObsoleteAttribute(...)] | UrlFormat | https://aka.ms/dotnet-warnings/{0} | +| System.Security.Permissions.CodeAccessSecurityAttribute | [AttributeUsageAttribute(...)] | AllowMultiple | True | +| System.Security.Permissions.CodeAccessSecurityAttribute | [AttributeUsageAttribute(...)] | Inherited | False | +| System.Security.Permissions.CodeAccessSecurityAttribute | [ObsoleteAttribute(...)] | DiagnosticId | SYSLIB0003 | +| System.Security.Permissions.CodeAccessSecurityAttribute | [ObsoleteAttribute(...)] | UrlFormat | https://aka.ms/dotnet-warnings/{0} | +| System.Security.Permissions.PermissionState | [ObsoleteAttribute(...)] | DiagnosticId | SYSLIB0003 | +| System.Security.Permissions.PermissionState | [ObsoleteAttribute(...)] | UrlFormat | https://aka.ms/dotnet-warnings/{0} | +| System.Security.Permissions.SecurityAction | [ObsoleteAttribute(...)] | DiagnosticId | SYSLIB0003 | +| System.Security.Permissions.SecurityAction | [ObsoleteAttribute(...)] | UrlFormat | https://aka.ms/dotnet-warnings/{0} | +| System.Security.Permissions.SecurityAttribute | [AttributeUsageAttribute(...)] | AllowMultiple | True | +| System.Security.Permissions.SecurityAttribute | [AttributeUsageAttribute(...)] | Inherited | False | +| System.Security.Permissions.SecurityAttribute | [ObsoleteAttribute(...)] | DiagnosticId | SYSLIB0003 | +| System.Security.Permissions.SecurityAttribute | [ObsoleteAttribute(...)] | UrlFormat | https://aka.ms/dotnet-warnings/{0} | +| System.Security.Permissions.SecurityPermissionAttribute | [AttributeUsageAttribute(...)] | AllowMultiple | True | +| System.Security.Permissions.SecurityPermissionAttribute | [AttributeUsageAttribute(...)] | Inherited | False | +| System.Security.Permissions.SecurityPermissionAttribute | [ObsoleteAttribute(...)] | DiagnosticId | SYSLIB0003 | +| System.Security.Permissions.SecurityPermissionAttribute | [ObsoleteAttribute(...)] | UrlFormat | https://aka.ms/dotnet-warnings/{0} | +| System.Security.Permissions.SecurityPermissionFlag | [ObsoleteAttribute(...)] | DiagnosticId | SYSLIB0003 | +| System.Security.Permissions.SecurityPermissionFlag | [ObsoleteAttribute(...)] | UrlFormat | https://aka.ms/dotnet-warnings/{0} | | System.Security.SecurityCriticalAttribute | [AttributeUsageAttribute(...)] | AllowMultiple | False | | System.Security.SecurityCriticalAttribute | [AttributeUsageAttribute(...)] | Inherited | False | | System.Security.SecurityRulesAttribute | [AttributeUsageAttribute(...)] | AllowMultiple | False | @@ -905,22 +1063,33 @@ attrArgNamed | System.Security.UnverifiableCodeAttribute | [AttributeUsageAttribute(...)] | AllowMultiple | True | | System.Security.UnverifiableCodeAttribute | [AttributeUsageAttribute(...)] | Inherited | False | | System.SerializableAttribute | [AttributeUsageAttribute(...)] | Inherited | False | +| System.Text.Encoding System.Text.Encoding.UTF7 | [ObsoleteAttribute(...)] | DiagnosticId | SYSLIB0001 | +| System.Text.Encoding System.Text.Encoding.UTF7 | [ObsoleteAttribute(...)] | UrlFormat | https://aka.ms/dotnet-warnings/{0} | | System.Text.Encoding._isReadOnly | [OptionalFieldAttribute(...)] | VersionAdded | 2 | | System.ThreadStaticAttribute | [AttributeUsageAttribute(...)] | Inherited | False | | System.Threading.Tasks.TplEventSource | [EventSourceAttribute(...)] | Guid | 2e5dba47-a3d2-4d16-8ee0-6671ffdcd7b5 | -| System.Threading.Tasks.TplEventSource | [EventSourceAttribute(...)] | LocalizationResources | System.Private.CoreLib.Resources.Strings | +| System.Threading.Tasks.TplEventSource | [EventSourceAttribute(...)] | LocalizationResources | System.Private.CoreLib.Strings | | System.Threading.Tasks.TplEventSource | [EventSourceAttribute(...)] | Name | System.Threading.Tasks.TplEventSource | +| bool System.Reflection.Assembly.GlobalAssemblyCache | [ObsoleteAttribute(...)] | DiagnosticId | SYSLIB0005 | +| bool System.Reflection.Assembly.GlobalAssemblyCache | [ObsoleteAttribute(...)] | UrlFormat | https://aka.ms/dotnet-warnings/{0} | +| bool System.Reflection.Emit.AssemblyBuilder.GlobalAssemblyCache | [ObsoleteAttribute(...)] | DiagnosticId | SYSLIB0005 | +| bool System.Reflection.Emit.AssemblyBuilder.GlobalAssemblyCache | [ObsoleteAttribute(...)] | UrlFormat | https://aka.ms/dotnet-warnings/{0} | +| bool System.Reflection.RuntimeAssembly.GlobalAssemblyCache | [ObsoleteAttribute(...)] | DiagnosticId | SYSLIB0005 | +| bool System.Reflection.RuntimeAssembly.GlobalAssemblyCache | [ObsoleteAttribute(...)] | UrlFormat | https://aka.ms/dotnet-warnings/{0} | attrArgPositional | !0 System.ArraySegment`1.Enumerator.Current | [NullableAttribute(...)] | 0 | 1 | | !0 System.Collections.Generic.Dictionary`2.KeyCollection.Enumerator.Current | [NullableAttribute(...)] | 0 | 1 | +| !0 System.Collections.Generic.HashSet`1.Enumerator.Current | [NullableAttribute(...)] | 0 | 1 | | !0 System.Collections.Generic.IAsyncEnumerator`1.Current | [NullableAttribute(...)] | 0 | 1 | | !0 System.Collections.Generic.IEnumerator`1.Current | [NullableAttribute(...)] | 0 | 1 | | !0 System.Collections.Generic.List`1.Enumerator.Current | [NullableAttribute(...)] | 0 | 1 | | !0 System.Lazy`1.Value | [DebuggerBrowsableAttribute(...)] | 0 | 0 | +| !0 System.Lazy`1.ValueForDebugDisplay | [NullableAttribute(...)] | 0 | 2 | | !0 System.Runtime.CompilerServices.ConfiguredCancelableAsyncEnumerable`1.Enumerator.Current | [NullableAttribute(...)] | 0 | 1 | | !0 System.Threading.Tasks.Task`1.Result | [DebuggerBrowsableAttribute(...)] | 0 | 0 | | !0 System.Threading.Tasks.ValueTask`1.Result | [DebuggerBrowsableAttribute(...)] | 0 | 0 | | !0 System.Threading.ThreadLocal`1.Value | [DebuggerBrowsableAttribute(...)] | 0 | 0 | +| !0 System.Threading.ThreadLocal`1.ValueForDebugDisplay | [NullableAttribute(...)] | 0 | 2 | | !0 System.Tuple`1.Item1 | [NullableAttribute(...)] | 0 | 1 | | !0 System.Tuple`2.Item1 | [NullableAttribute(...)] | 0 | 1 | | !0[] System.ArraySegment`1.Array | [NullableAttribute(...)] | 0 | [2,1] | @@ -932,12 +1101,19 @@ attrArgPositional | !1 System.Collections.Generic.Dictionary`2.ValueCollection.Enumerator.Current | [NullableAttribute(...)] | 0 | 1 | | !1 System.Tuple`2.Item2 | [NullableAttribute(...)] | 0 | 1 | | !1[] System.Collections.Generic.DictionaryValueCollectionDebugView`2.Items | [DebuggerBrowsableAttribute(...)] | 0 | 3 | -| <>f__AnonymousType0`1.i__Field | [DebuggerBrowsableAttribute(...)] | 0 | 0 | | Internal.Runtime.CompilerServices.Unsafe | [CLSCompliantAttribute(...)] | 0 | False | | Internal.Runtime.CompilerServices.Unsafe | [NullableAttribute(...)] | 0 | 0 | | Internal.Runtime.CompilerServices.Unsafe | [NullableContextAttribute(...)] | 0 | 1 | -| Internal.Threading.Tasks.AsyncCausalitySupport | [NullableAttribute(...)] | 0 | 0 | -| Internal.Threading.Tasks.AsyncCausalitySupport | [NullableContextAttribute(...)] | 0 | 1 | +| Internal.Runtime.InteropServices.ComActivationContext | [NullableAttribute(...)] | 0 | 0 | +| Internal.Runtime.InteropServices.ComActivationContext | [NullableContextAttribute(...)] | 0 | 1 | +| Internal.Runtime.InteropServices.ComActivationContextInternal | [CLSCompliantAttribute(...)] | 0 | False | +| Internal.Runtime.InteropServices.IClassFactory | [ComVisibleAttribute(...)] | 0 | False | +| Internal.Runtime.InteropServices.IClassFactory | [GuidAttribute(...)] | 0 | 00000001-0000-0000-C000-000000000046 | +| Internal.Runtime.InteropServices.IClassFactory | [InterfaceTypeAttribute(...)] | 0 | 1 | +| Internal.Runtime.InteropServices.IClassFactory | [NullableContextAttribute(...)] | 0 | 2 | +| Internal.Runtime.InteropServices.IClassFactory2 | [ComVisibleAttribute(...)] | 0 | False | +| Internal.Runtime.InteropServices.IClassFactory2 | [GuidAttribute(...)] | 0 | B196B28F-BAB4-101A-B69C-00AA00341D07 | +| Internal.Runtime.InteropServices.IClassFactory2 | [InterfaceTypeAttribute(...)] | 0 | 1 | | Interop.Sys.MountPointFound | [UnmanagedFunctionPointerAttribute(...)] | 0 | 2 | | System.AccessViolationException | [NullableAttribute(...)] | 0 | 0 | | System.AccessViolationException | [NullableContextAttribute(...)] | 0 | 2 | @@ -979,15 +1155,26 @@ attrArgPositional | System.AppContext | [NullableContextAttribute(...)] | 0 | 2 | | System.AppContext.FirstChanceException | [NullableAttribute(...)] | 0 | [2,1] | | System.AppDomain | [NullableAttribute(...)] | 0 | 0 | -| System.AppDomain | [NullableContextAttribute(...)] | 0 | 2 | -| System.AppDomain System.AppDomain.CurrentDomain | [NullableAttribute(...)] | 0 | 1 | +| System.AppDomain | [NullableContextAttribute(...)] | 0 | 1 | +| System.AppDomain.AssemblyLoad | [NullableAttribute(...)] | 0 | 2 | +| System.AppDomain.AssemblyResolve | [NullableAttribute(...)] | 0 | 2 | +| System.AppDomain.DomainUnload | [NullableAttribute(...)] | 0 | 2 | | System.AppDomain.FirstChanceException | [NullableAttribute(...)] | 0 | [2,1] | +| System.AppDomain.ProcessExit | [NullableAttribute(...)] | 0 | 2 | +| System.AppDomain.ReflectionOnlyAssemblyResolve | [NullableAttribute(...)] | 0 | 2 | +| System.AppDomain.ResourceResolve | [NullableAttribute(...)] | 0 | 2 | +| System.AppDomain.TypeResolve | [NullableAttribute(...)] | 0 | 2 | +| System.AppDomain.UnhandledException | [NullableAttribute(...)] | 0 | 2 | | System.AppDomainSetup | [NullableAttribute(...)] | 0 | 0 | | System.AppDomainSetup | [NullableContextAttribute(...)] | 0 | 2 | -| System.AppDomainSetup System.AppDomain.SetupInformation | [NullableAttribute(...)] | 0 | 1 | +| System.AppDomainUnloadedException | [NullableAttribute(...)] | 0 | 0 | +| System.AppDomainUnloadedException | [NullableContextAttribute(...)] | 0 | 2 | +| System.AppDomainUnloadedException | [TypeForwardedFromAttribute(...)] | 0 | mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 | | System.ApplicationException | [NullableAttribute(...)] | 0 | 0 | | System.ApplicationException | [NullableContextAttribute(...)] | 0 | 2 | | System.ApplicationException | [TypeForwardedFromAttribute(...)] | 0 | mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 | +| System.ApplicationId | [NullableAttribute(...)] | 0 | 0 | +| System.ApplicationId | [NullableContextAttribute(...)] | 0 | 1 | | System.ArgumentException | [NullableAttribute(...)] | 0 | 0 | | System.ArgumentException | [NullableContextAttribute(...)] | 0 | 2 | | System.ArgumentException | [TypeForwardedFromAttribute(...)] | 0 | mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 | @@ -1035,6 +1222,11 @@ attrArgPositional | System.CannotUnloadAppDomainException | [NullableAttribute(...)] | 0 | 0 | | System.CannotUnloadAppDomainException | [NullableContextAttribute(...)] | 0 | 2 | | System.CannotUnloadAppDomainException | [TypeForwardedFromAttribute(...)] | 0 | mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 | +| System.CodeDom.Compiler.GeneratedCodeAttribute | [AttributeUsageAttribute(...)] | 0 | 32767 | +| System.CodeDom.Compiler.GeneratedCodeAttribute | [NullableAttribute(...)] | 0 | 0 | +| System.CodeDom.Compiler.GeneratedCodeAttribute | [NullableContextAttribute(...)] | 0 | 2 | +| System.CodeDom.Compiler.IndentedTextWriter | [NullableAttribute(...)] | 0 | 0 | +| System.CodeDom.Compiler.IndentedTextWriter | [NullableContextAttribute(...)] | 0 | 1 | | System.Collections.ArrayList | [DebuggerDisplayAttribute(...)] | 0 | Count = {Count} | | System.Collections.ArrayList | [DebuggerTypeProxyAttribute(...)] | 0 | System.Collections.ArrayList.ArrayListDebugView | | System.Collections.ArrayList | [DefaultMemberAttribute(...)] | 0 | Item | @@ -1066,6 +1258,8 @@ attrArgPositional | System.Collections.EmptyReadOnlyDictionaryInternal | [DefaultMemberAttribute(...)] | 0 | Item | | System.Collections.Generic.ArraySortHelper`1 | [TypeDependencyAttribute(...)] | 0 | System.Collections.Generic.GenericArraySortHelper`1 | | System.Collections.Generic.ArraySortHelper`2 | [TypeDependencyAttribute(...)] | 0 | System.Collections.Generic.GenericArraySortHelper`2 | +| System.Collections.Generic.BitHelper | [ObsoleteAttribute(...)] | 0 | Types with embedded references are not supported in this version of your compiler. | +| System.Collections.Generic.BitHelper | [ObsoleteAttribute(...)] | 1 | True | | System.Collections.Generic.ByteEqualityComparer | [TypeForwardedFromAttribute(...)] | 0 | mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 | | System.Collections.Generic.Comparer`1 | [NullableAttribute(...)] | 0 | 0 | | System.Collections.Generic.Comparer`1 | [NullableContextAttribute(...)] | 0 | 1 | @@ -1092,18 +1286,24 @@ attrArgPositional | System.Collections.Generic.EqualityComparer`1 | [TypeDependencyAttribute(...)] | 0 | System.Collections.Generic.ObjectEqualityComparer`1 | | System.Collections.Generic.EqualityComparer`1 | [TypeForwardedFromAttribute(...)] | 0 | mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 | | System.Collections.Generic.GenericComparer`1 | [NullableAttribute(...)] | 0 | [0,1] | -| System.Collections.Generic.GenericComparer`1 | [NullableContextAttribute(...)] | 0 | 1 | +| System.Collections.Generic.GenericComparer`1 | [NullableContextAttribute(...)] | 0 | 2 | | System.Collections.Generic.GenericComparer`1 | [TypeForwardedFromAttribute(...)] | 0 | mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 | | System.Collections.Generic.GenericEqualityComparer`1 | [NullableAttribute(...)] | 0 | [0,1] | +| System.Collections.Generic.GenericEqualityComparer`1 | [NullableContextAttribute(...)] | 0 | 1 | | System.Collections.Generic.GenericEqualityComparer`1 | [TypeForwardedFromAttribute(...)] | 0 | mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 | +| System.Collections.Generic.HashSet`1 | [DebuggerDisplayAttribute(...)] | 0 | Count = {Count} | +| System.Collections.Generic.HashSet`1 | [DebuggerTypeProxyAttribute(...)] | 0 | System.Collections.Generic.ICollectionDebugView`1 | +| System.Collections.Generic.HashSet`1 | [NullableAttribute(...)] | 0 | 0 | +| System.Collections.Generic.HashSet`1 | [NullableContextAttribute(...)] | 0 | 1 | +| System.Collections.Generic.HashSet`1 | [TypeForwardedFromAttribute(...)] | 0 | System.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 | +| System.Collections.Generic.HashSet`1.Enumerator | [NullableContextAttribute(...)] | 0 | 0 | | System.Collections.Generic.IAsyncEnumerable`1 | [NullableContextAttribute(...)] | 0 | 1 | | System.Collections.Generic.ICollection`1 | [NullableContextAttribute(...)] | 0 | 1 | -| System.Collections.Generic.IComparer`1 | [NullableContextAttribute(...)] | 0 | 1 | +| System.Collections.Generic.IComparer`1 | [NullableContextAttribute(...)] | 0 | 2 | | System.Collections.Generic.IDictionary System.Diagnostics.Tracing.EventCommandEventArgs.Arguments | [NullableAttribute(...)] | 0 | [2,1,2] | | System.Collections.Generic.IDictionary`2 | [DefaultMemberAttribute(...)] | 0 | Item | | System.Collections.Generic.IDictionary`2 | [NullableContextAttribute(...)] | 0 | 1 | -| System.Collections.Generic.IEqualityComparer System.Collections.Generic.NonRandomizedStringEqualityComparer.Default | [NullableAttribute(...)] | 0 | [1,2] | -| System.Collections.Generic.IEqualityComparer`1 | [NullableContextAttribute(...)] | 0 | 1 | +| System.Collections.Generic.IEqualityComparer`1 | [NullableContextAttribute(...)] | 0 | 2 | | System.Collections.Generic.IList System.Runtime.CompilerServices.TupleElementNamesAttribute.TransformNames | [NullableAttribute(...)] | 0 | [1,2] | | System.Collections.Generic.IList`1 | [DefaultMemberAttribute(...)] | 0 | Item | | System.Collections.Generic.IList`1 | [NullableContextAttribute(...)] | 0 | 1 | @@ -1111,6 +1311,7 @@ attrArgPositional | System.Collections.Generic.IReadOnlyDictionary`2 | [NullableContextAttribute(...)] | 0 | 1 | | System.Collections.Generic.IReadOnlyList`1 | [DefaultMemberAttribute(...)] | 0 | Item | | System.Collections.Generic.IReadOnlyList`1 | [NullableContextAttribute(...)] | 0 | 1 | +| System.Collections.Generic.IReadOnlySet`1 | [NullableContextAttribute(...)] | 0 | 1 | | System.Collections.Generic.ISet`1 | [NullableContextAttribute(...)] | 0 | 1 | | System.Collections.Generic.KeyNotFoundException | [NullableAttribute(...)] | 0 | 0 | | System.Collections.Generic.KeyNotFoundException | [NullableContextAttribute(...)] | 0 | 2 | @@ -1120,6 +1321,8 @@ attrArgPositional | System.Collections.Generic.KeyValuePair`2 | [NullableAttribute(...)] | 0 | 0 | | System.Collections.Generic.KeyValuePair`2 | [NullableContextAttribute(...)] | 0 | 1 | | System.Collections.Generic.KeyValuePair`2 | [TypeForwardedFromAttribute(...)] | 0 | mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 | +| System.Collections.Generic.KeyValuePair`2.key | [DebuggerBrowsableAttribute(...)] | 0 | 0 | +| System.Collections.Generic.KeyValuePair`2.value | [DebuggerBrowsableAttribute(...)] | 0 | 0 | | System.Collections.Generic.List System.Threading.ThreadLocal`1.ValuesForDebugDisplay | [NullableAttribute(...)] | 0 | [2,1] | | System.Collections.Generic.List`1 | [DebuggerDisplayAttribute(...)] | 0 | Count = {Count} | | System.Collections.Generic.List`1 | [DebuggerTypeProxyAttribute(...)] | 0 | System.Collections.Generic.ICollectionDebugView`1 | @@ -1128,16 +1331,15 @@ attrArgPositional | System.Collections.Generic.List`1 | [NullableContextAttribute(...)] | 0 | 1 | | System.Collections.Generic.List`1 | [TypeForwardedFromAttribute(...)] | 0 | mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 | | System.Collections.Generic.List`1.Enumerator | [NullableContextAttribute(...)] | 0 | 0 | -| System.Collections.Generic.NonRandomizedStringEqualityComparer | [NullableAttribute(...)] | 0 | [0,2] | -| System.Collections.Generic.NonRandomizedStringEqualityComparer | [NullableContextAttribute(...)] | 0 | 2 | | System.Collections.Generic.NullableComparer`1 | [TypeForwardedFromAttribute(...)] | 0 | mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 | | System.Collections.Generic.NullableEqualityComparer`1 | [TypeForwardedFromAttribute(...)] | 0 | mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 | | System.Collections.Generic.ObjectComparer`1 | [NullableAttribute(...)] | 0 | [0,1] | | System.Collections.Generic.ObjectComparer`1 | [NullableContextAttribute(...)] | 0 | 2 | | System.Collections.Generic.ObjectComparer`1 | [TypeForwardedFromAttribute(...)] | 0 | mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 | | System.Collections.Generic.ObjectEqualityComparer`1 | [NullableAttribute(...)] | 0 | [0,1] | -| System.Collections.Generic.ObjectEqualityComparer`1 | [NullableContextAttribute(...)] | 0 | 1 | +| System.Collections.Generic.ObjectEqualityComparer`1 | [NullableContextAttribute(...)] | 0 | 2 | | System.Collections.Generic.ObjectEqualityComparer`1 | [TypeForwardedFromAttribute(...)] | 0 | mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 | +| System.Collections.Generic.ReferenceEqualityComparer System.Collections.Generic.ReferenceEqualityComparer.Instance | [NullableAttribute(...)] | 0 | 1 | | System.Collections.Generic.ValueListBuilder`1 | [DefaultMemberAttribute(...)] | 0 | Item | | System.Collections.Generic.ValueListBuilder`1 | [ObsoleteAttribute(...)] | 0 | Types with embedded references are not supported in this version of your compiler. | | System.Collections.Generic.ValueListBuilder`1 | [ObsoleteAttribute(...)] | 1 | True | @@ -1159,7 +1361,6 @@ attrArgPositional | System.Collections.IEnumerable | [ComVisibleAttribute(...)] | 0 | True | | System.Collections.IEnumerable | [GuidAttribute(...)] | 0 | 496B0ABE-CDEE-11d3-88E8-00902754C43A | | System.Collections.IEnumerable | [NullableContextAttribute(...)] | 0 | 1 | -| System.Collections.IEnumerator | [NullableContextAttribute(...)] | 0 | 2 | | System.Collections.IEqualityComparer | [NullableContextAttribute(...)] | 0 | 1 | | System.Collections.IEqualityComparer System.Collections.Hashtable.EqualityComparer | [NullableAttribute(...)] | 0 | 2 | | System.Collections.IHashCodeProvider | [NullableContextAttribute(...)] | 0 | 1 | @@ -1196,6 +1397,16 @@ attrArgPositional | System.ComponentModel.DefaultValueAttribute | [NullableAttribute(...)] | 0 | 0 | | System.ComponentModel.DefaultValueAttribute | [NullableContextAttribute(...)] | 0 | 2 | | System.ComponentModel.EditorBrowsableAttribute | [AttributeUsageAttribute(...)] | 0 | 6140 | +| System.Console | [NullableAttribute(...)] | 0 | 0 | +| System.Console | [NullableContextAttribute(...)] | 0 | 1 | +| System.Console.CancelKeyPress | [NullableAttribute(...)] | 0 | 2 | +| System.Console.CancelKeyPress | [UnsupportedOSPlatformAttribute(...)] | 0 | browser | +| System.ConsoleColor System.Console.BackgroundColor | [UnsupportedOSPlatformAttribute(...)] | 0 | browser | +| System.ConsoleColor System.Console.ForegroundColor | [UnsupportedOSPlatformAttribute(...)] | 0 | browser | +| System.ContextMarshalException | [NullableAttribute(...)] | 0 | 0 | +| System.ContextMarshalException | [NullableContextAttribute(...)] | 0 | 2 | +| System.ContextMarshalException | [TypeForwardedFromAttribute(...)] | 0 | mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 | +| System.ContextStaticAttribute | [AttributeUsageAttribute(...)] | 0 | 256 | | System.Convert | [NullableAttribute(...)] | 0 | 0 | | System.Convert | [NullableContextAttribute(...)] | 0 | 2 | | System.Convert.DBNull | [NullableAttribute(...)] | 0 | 1 | @@ -1225,17 +1436,36 @@ attrArgPositional | System.Diagnostics.CodeAnalysis.DisallowNullAttribute | [AttributeUsageAttribute(...)] | 0 | 2432 | | System.Diagnostics.CodeAnalysis.DoesNotReturnAttribute | [AttributeUsageAttribute(...)] | 0 | 64 | | System.Diagnostics.CodeAnalysis.DoesNotReturnIfAttribute | [AttributeUsageAttribute(...)] | 0 | 2048 | +| System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute | [AttributeUsageAttribute(...)] | 0 | 352 | +| System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute | [NullableAttribute(...)] | 0 | 0 | +| System.Diagnostics.CodeAnalysis.DynamicDependencyAttribute | [NullableContextAttribute(...)] | 0 | 2 | +| System.Diagnostics.CodeAnalysis.DynamicallyAccessedMembersAttribute | [AttributeUsageAttribute(...)] | 0 | 27072 | +| System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute | [AttributeUsageAttribute(...)] | 0 | 749 | +| System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute | [NullableAttribute(...)] | 0 | 0 | +| System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverageAttribute | [NullableContextAttribute(...)] | 0 | 2 | | System.Diagnostics.CodeAnalysis.MaybeNullAttribute | [AttributeUsageAttribute(...)] | 0 | 10624 | | System.Diagnostics.CodeAnalysis.MaybeNullWhenAttribute | [AttributeUsageAttribute(...)] | 0 | 2048 | +| System.Diagnostics.CodeAnalysis.MemberNotNullAttribute | [AttributeUsageAttribute(...)] | 0 | 192 | +| System.Diagnostics.CodeAnalysis.MemberNotNullAttribute | [NullableAttribute(...)] | 0 | 0 | +| System.Diagnostics.CodeAnalysis.MemberNotNullAttribute | [NullableContextAttribute(...)] | 0 | 1 | +| System.Diagnostics.CodeAnalysis.MemberNotNullWhenAttribute | [AttributeUsageAttribute(...)] | 0 | 192 | +| System.Diagnostics.CodeAnalysis.MemberNotNullWhenAttribute | [NullableAttribute(...)] | 0 | 0 | +| System.Diagnostics.CodeAnalysis.MemberNotNullWhenAttribute | [NullableContextAttribute(...)] | 0 | 1 | | System.Diagnostics.CodeAnalysis.NotNullAttribute | [AttributeUsageAttribute(...)] | 0 | 10624 | | System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute | [AttributeUsageAttribute(...)] | 0 | 10368 | | System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute | [NullableAttribute(...)] | 0 | 0 | | System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute | [NullableContextAttribute(...)] | 0 | 1 | | System.Diagnostics.CodeAnalysis.NotNullWhenAttribute | [AttributeUsageAttribute(...)] | 0 | 2048 | +| System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute | [AttributeUsageAttribute(...)] | 0 | 96 | +| System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute | [NullableAttribute(...)] | 0 | 0 | +| System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute | [NullableContextAttribute(...)] | 0 | 1 | | System.Diagnostics.CodeAnalysis.SuppressMessageAttribute | [AttributeUsageAttribute(...)] | 0 | 32767 | | System.Diagnostics.CodeAnalysis.SuppressMessageAttribute | [ConditionalAttribute(...)] | 0 | CODE_ANALYSIS | | System.Diagnostics.CodeAnalysis.SuppressMessageAttribute | [NullableAttribute(...)] | 0 | 0 | | System.Diagnostics.CodeAnalysis.SuppressMessageAttribute | [NullableContextAttribute(...)] | 0 | 2 | +| System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute | [AttributeUsageAttribute(...)] | 0 | 32767 | +| System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute | [NullableAttribute(...)] | 0 | 0 | +| System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute | [NullableContextAttribute(...)] | 0 | 2 | | System.Diagnostics.ConditionalAttribute | [AttributeUsageAttribute(...)] | 0 | 68 | | System.Diagnostics.ConditionalAttribute | [NullableAttribute(...)] | 0 | 0 | | System.Diagnostics.ConditionalAttribute | [NullableContextAttribute(...)] | 0 | 1 | @@ -1371,7 +1601,7 @@ attrArgPositional | System.Exception | [NullableContextAttribute(...)] | 0 | 2 | | System.Exception | [TypeForwardedFromAttribute(...)] | 0 | mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 | | System.Exception.SerializeObjectState | [NullableAttribute(...)] | 0 | [2,1] | -| System.Exception[] System.Reflection.ReflectionTypeLoadException.LoaderExceptions | [NullableAttribute(...)] | 0 | 2 | +| System.Exception[] System.Reflection.ReflectionTypeLoadException.LoaderExceptions | [NullableAttribute(...)] | 0 | [1,2] | | System.ExecutionEngineException | [NullableAttribute(...)] | 0 | 0 | | System.ExecutionEngineException | [NullableContextAttribute(...)] | 0 | 2 | | System.ExecutionEngineException | [ObsoleteAttribute(...)] | 0 | This type previously indicated an unspecified fatal error in the runtime. The runtime no longer raises this exception so this type is obsolete. | @@ -1438,8 +1668,6 @@ attrArgPositional | System.Globalization.EraInfo[] System.Globalization.TaiwanLunisolarCalendar.CalEraInfo | [NullableAttribute(...)] | 0 | [2,1] | | System.Globalization.GregorianCalendar | [NullableAttribute(...)] | 0 | 0 | | System.Globalization.GregorianCalendar | [NullableContextAttribute(...)] | 0 | 1 | -| System.Globalization.HebrewCalendar | [NullableAttribute(...)] | 0 | 0 | -| System.Globalization.HebrewCalendar | [NullableContextAttribute(...)] | 0 | 1 | | System.Globalization.HijriCalendar | [NullableAttribute(...)] | 0 | 0 | | System.Globalization.HijriCalendar | [NullableContextAttribute(...)] | 0 | 1 | | System.Globalization.IdnMapping | [NullableAttribute(...)] | 0 | 0 | @@ -1492,20 +1720,23 @@ attrArgPositional | System.Guid | [TypeForwardedFromAttribute(...)] | 0 | mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 | | System.HashCode | [NullableAttribute(...)] | 0 | 0 | | System.HashCode | [NullableContextAttribute(...)] | 0 | 1 | +| System.HexConverter.<>c.<>9__4_0 | [TupleElementNamesAttribute(...)] | 0 | [Ptr,Length,casing] | | System.IAsyncResult | [NullableContextAttribute(...)] | 0 | 1 | | System.ICloneable | [NullableContextAttribute(...)] | 0 | 1 | | System.IComparable | [NullableContextAttribute(...)] | 0 | 2 | -| System.IComparable`1 | [NullableContextAttribute(...)] | 0 | 1 | +| System.IComparable`1 | [NullableContextAttribute(...)] | 0 | 2 | | System.IConvertible | [CLSCompliantAttribute(...)] | 0 | False | | System.IConvertible | [NullableContextAttribute(...)] | 0 | 2 | | System.ICustomFormatter | [NullableContextAttribute(...)] | 0 | 2 | -| System.IEquatable`1 | [NullableContextAttribute(...)] | 0 | 1 | +| System.IEquatable`1 | [NullableContextAttribute(...)] | 0 | 2 | | System.IFormatProvider | [NullableContextAttribute(...)] | 0 | 2 | | System.IFormattable | [NullableContextAttribute(...)] | 0 | 2 | | System.IO.BinaryReader | [NullableAttribute(...)] | 0 | 0 | | System.IO.BinaryReader | [NullableContextAttribute(...)] | 0 | 1 | | System.IO.BinaryWriter | [NullableAttribute(...)] | 0 | 0 | | System.IO.BinaryWriter | [NullableContextAttribute(...)] | 0 | 1 | +| System.IO.BufferedStream | [NullableAttribute(...)] | 0 | 0 | +| System.IO.BufferedStream | [NullableContextAttribute(...)] | 0 | 1 | | System.IO.DirectoryNotFoundException | [NullableAttribute(...)] | 0 | 0 | | System.IO.DirectoryNotFoundException | [NullableContextAttribute(...)] | 0 | 2 | | System.IO.DirectoryNotFoundException | [TypeForwardedFromAttribute(...)] | 0 | mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 | @@ -1523,6 +1754,9 @@ attrArgPositional | System.IO.IOException | [NullableAttribute(...)] | 0 | 0 | | System.IO.IOException | [NullableContextAttribute(...)] | 0 | 2 | | System.IO.IOException | [TypeForwardedFromAttribute(...)] | 0 | mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 | +| System.IO.InvalidDataException | [NullableAttribute(...)] | 0 | 0 | +| System.IO.InvalidDataException | [NullableContextAttribute(...)] | 0 | 2 | +| System.IO.InvalidDataException | [TypeForwardedFromAttribute(...)] | 0 | System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 | | System.IO.MemoryStream | [NullableAttribute(...)] | 0 | 0 | | System.IO.MemoryStream | [NullableContextAttribute(...)] | 0 | 1 | | System.IO.Path.<>c.<>9__37_0 | [TupleElementNamesAttribute(...)] | 0 | [First,FirstLength,Second,SecondLength,HasSeparator] | @@ -1539,8 +1773,13 @@ attrArgPositional | System.IO.StreamReader | [NullableContextAttribute(...)] | 0 | 1 | | System.IO.StreamWriter | [NullableAttribute(...)] | 0 | 0 | | System.IO.StreamWriter | [NullableContextAttribute(...)] | 0 | 1 | +| System.IO.StringReader | [NullableAttribute(...)] | 0 | 0 | +| System.IO.StringReader | [NullableContextAttribute(...)] | 0 | 1 | +| System.IO.StringWriter | [NullableAttribute(...)] | 0 | 0 | +| System.IO.StringWriter | [NullableContextAttribute(...)] | 0 | 1 | | System.IO.TextReader | [NullableAttribute(...)] | 0 | 0 | | System.IO.TextReader | [NullableContextAttribute(...)] | 0 | 1 | +| System.IO.TextReader System.Console.In | [UnsupportedOSPlatformAttribute(...)] | 0 | browser | | System.IO.TextWriter | [NullableAttribute(...)] | 0 | 0 | | System.IO.TextWriter | [NullableContextAttribute(...)] | 0 | 1 | | System.IObservable`1 | [NullableContextAttribute(...)] | 0 | 1 | @@ -1576,6 +1815,9 @@ attrArgPositional | System.Lazy`1 | [NullableContextAttribute(...)] | 0 | 1 | | System.Lazy`2 | [NullableAttribute(...)] | 0 | [0,1] | | System.Lazy`2 | [NullableContextAttribute(...)] | 0 | 1 | +| System.LoaderOptimization.DisallowBindings | [ObsoleteAttribute(...)] | 0 | This method has been deprecated. Please use Assembly.Load() instead. https://go.microsoft.com/fwlink/?linkid=14202 | +| System.LoaderOptimization.DomainMask | [ObsoleteAttribute(...)] | 0 | This method has been deprecated. Please use Assembly.Load() instead. https://go.microsoft.com/fwlink/?linkid=14202 | +| System.LoaderOptimizationAttribute | [AttributeUsageAttribute(...)] | 0 | 64 | | System.MTAThreadAttribute | [AttributeUsageAttribute(...)] | 0 | 64 | | System.MarshalByRefObject | [ClassInterfaceAttribute(...)] | 0 | 1 | | System.MarshalByRefObject | [ComVisibleAttribute(...)] | 0 | True | @@ -1612,6 +1854,8 @@ attrArgPositional | System.MulticastNotSupportedException | [NullableAttribute(...)] | 0 | 0 | | System.MulticastNotSupportedException | [NullableContextAttribute(...)] | 0 | 2 | | System.MulticastNotSupportedException | [TypeForwardedFromAttribute(...)] | 0 | mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 | +| System.Net.WebUtility | [NullableAttribute(...)] | 0 | 0 | +| System.Net.WebUtility | [NullableContextAttribute(...)] | 0 | 2 | | System.NonSerializedAttribute | [AttributeUsageAttribute(...)] | 0 | 256 | | System.NotFiniteNumberException | [NullableAttribute(...)] | 0 | 0 | | System.NotFiniteNumberException | [NullableContextAttribute(...)] | 0 | 2 | @@ -1634,6 +1878,12 @@ attrArgPositional | System.Number.DiyFp | [ObsoleteAttribute(...)] | 1 | True | | System.Number.NumberBuffer | [ObsoleteAttribute(...)] | 0 | Types with embedded references are not supported in this version of your compiler. | | System.Number.NumberBuffer | [ObsoleteAttribute(...)] | 1 | True | +| System.Numerics.Vector2 | [NullableAttribute(...)] | 0 | 0 | +| System.Numerics.Vector2 | [NullableContextAttribute(...)] | 0 | 1 | +| System.Numerics.Vector3 | [NullableAttribute(...)] | 0 | 0 | +| System.Numerics.Vector3 | [NullableContextAttribute(...)] | 0 | 1 | +| System.Numerics.Vector4 | [NullableAttribute(...)] | 0 | 0 | +| System.Numerics.Vector4 | [NullableContextAttribute(...)] | 0 | 1 | | System.Numerics.Vector`1 | [DefaultMemberAttribute(...)] | 0 | Item | | System.ObjectDisposedException | [NullableAttribute(...)] | 0 | 0 | | System.ObjectDisposedException | [NullableContextAttribute(...)] | 0 | 1 | @@ -1678,10 +1928,12 @@ attrArgPositional | System.ReadOnlyMemory`1 | [NullableContextAttribute(...)] | 0 | 1 | | System.ReadOnlySpan System.ReadOnlyMemory`1.Span | [NullableAttribute(...)] | 0 | [0,1] | | System.ReadOnlySpan System.ReadOnlySpan`1.Empty | [NullableAttribute(...)] | 0 | [0,1] | +| System.ReadOnlySpan System.Globalization.CompareInfo.HighCharTable | [NullableAttribute(...)] | 0 | 0 | | System.ReadOnlySpan System.Text.Encoding.Preamble | [NullableAttribute(...)] | 0 | 0 | | System.ReadOnlySpan System.Text.UTF32Encoding.Preamble | [NullableAttribute(...)] | 0 | 0 | | System.ReadOnlySpan System.Text.UnicodeEncoding.Preamble | [NullableAttribute(...)] | 0 | 0 | -| System.ReadOnlySpan char.CategoryForLatin1 | [NullableAttribute(...)] | 0 | 0 | +| System.ReadOnlySpan char.Latin1CharInfo | [NullableAttribute(...)] | 0 | 0 | +| System.ReadOnlySpan System.Convert.DecodingMap | [NullableAttribute(...)] | 0 | 0 | | System.ReadOnlySpan`1 | [DebuggerDisplayAttribute(...)] | 0 | {ToString(),raw} | | System.ReadOnlySpan`1 | [DebuggerTypeProxyAttribute(...)] | 0 | System.SpanDebugView`1 | | System.ReadOnlySpan`1 | [DefaultMemberAttribute(...)] | 0 | Item | @@ -1697,6 +1949,7 @@ attrArgPositional | System.Reflection.AmbiguousMatchException | [TypeForwardedFromAttribute(...)] | 0 | mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 | | System.Reflection.Assembly | [NullableAttribute(...)] | 0 | 0 | | System.Reflection.Assembly | [NullableContextAttribute(...)] | 0 | 1 | +| System.Reflection.Assembly System.ResolveEventArgs.RequestingAssembly | [NullableAttribute(...)] | 0 | 2 | | System.Reflection.Assembly.ModuleResolve | [NullableAttribute(...)] | 0 | 2 | | System.Reflection.AssemblyAlgorithmIdAttribute | [AttributeUsageAttribute(...)] | 0 | 1 | | System.Reflection.AssemblyCompanyAttribute | [AttributeUsageAttribute(...)] | 0 | 1 | @@ -1787,6 +2040,7 @@ attrArgPositional | System.Reflection.Emit.DynamicScope | [DefaultMemberAttribute(...)] | 0 | Item | | System.Reflection.Emit.EnumBuilder | [NullableAttribute(...)] | 0 | 0 | | System.Reflection.Emit.EnumBuilder | [NullableContextAttribute(...)] | 0 | 1 | +| System.Reflection.Emit.EnumBuilder.m_typeBuilder | [DynamicallyAccessedMembersAttribute(...)] | 0 | -1 | | System.Reflection.Emit.EventBuilder | [NullableAttribute(...)] | 0 | 0 | | System.Reflection.Emit.EventBuilder | [NullableContextAttribute(...)] | 0 | 1 | | System.Reflection.Emit.FieldBuilder | [NullableAttribute(...)] | 0 | 0 | @@ -1800,6 +2054,7 @@ attrArgPositional | System.Reflection.Emit.LocalBuilder | [NullableContextAttribute(...)] | 0 | 1 | | System.Reflection.Emit.MethodBuilder | [NullableAttribute(...)] | 0 | 0 | | System.Reflection.Emit.MethodBuilder | [NullableContextAttribute(...)] | 0 | 1 | +| System.Reflection.Emit.MethodBuilder.m_containingType | [DynamicallyAccessedMembersAttribute(...)] | 0 | -1 | | System.Reflection.Emit.ModuleBuilder | [NullableAttribute(...)] | 0 | 0 | | System.Reflection.Emit.ModuleBuilder | [NullableContextAttribute(...)] | 0 | 1 | | System.Reflection.Emit.OpCode | [NullableAttribute(...)] | 0 | 0 | @@ -1814,6 +2069,9 @@ attrArgPositional | System.Reflection.Emit.SignatureHelper | [NullableContextAttribute(...)] | 0 | 1 | | System.Reflection.Emit.TypeBuilder | [NullableAttribute(...)] | 0 | 0 | | System.Reflection.Emit.TypeBuilder | [NullableContextAttribute(...)] | 0 | 1 | +| System.Reflection.Emit.TypeBuilder.m_bakedRuntimeType | [DynamicallyAccessedMembersAttribute(...)] | 0 | -1 | +| System.Reflection.Emit.TypeBuilder.m_typeParent | [DynamicallyAccessedMembersAttribute(...)] | 0 | -1 | +| System.Reflection.Emit.__ExceptionInfo[] System.Reflection.Emit.ILGenerator.CurrExcStack | [NullableAttribute(...)] | 0 | [2,1] | | System.Reflection.EventInfo | [NullableAttribute(...)] | 0 | 0 | | System.Reflection.EventInfo | [NullableContextAttribute(...)] | 0 | 2 | | System.Reflection.ExceptionHandlingClause | [NullableAttribute(...)] | 0 | 0 | @@ -1831,7 +2089,7 @@ attrArgPositional | System.Reflection.LocalVariableInfo | [NullableAttribute(...)] | 0 | 0 | | System.Reflection.LocalVariableInfo | [NullableContextAttribute(...)] | 0 | 1 | | System.Reflection.ManifestResourceInfo | [NullableAttribute(...)] | 0 | 0 | -| System.Reflection.ManifestResourceInfo | [NullableContextAttribute(...)] | 0 | 1 | +| System.Reflection.ManifestResourceInfo | [NullableContextAttribute(...)] | 0 | 2 | | System.Reflection.MemberInfo | [NullableAttribute(...)] | 0 | 0 | | System.Reflection.MemberInfo | [NullableContextAttribute(...)] | 0 | 1 | | System.Reflection.MetadataEnumResult | [DefaultMemberAttribute(...)] | 0 | Item | @@ -1884,10 +2142,11 @@ attrArgPositional | System.Reflection.TargetParameterCountException | [TypeForwardedFromAttribute(...)] | 0 | mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 | | System.Reflection.TypeDelegator | [NullableAttribute(...)] | 0 | 0 | | System.Reflection.TypeDelegator | [NullableContextAttribute(...)] | 0 | 1 | +| System.Reflection.TypeDelegator.typeImpl | [DynamicallyAccessedMembersAttribute(...)] | 0 | -1 | | System.Reflection.TypeInfo | [NullableAttribute(...)] | 0 | 0 | | System.Reflection.TypeInfo | [NullableContextAttribute(...)] | 0 | 1 | | System.ResolveEventArgs | [NullableAttribute(...)] | 0 | 0 | -| System.ResolveEventArgs | [NullableContextAttribute(...)] | 0 | 2 | +| System.ResolveEventArgs | [NullableContextAttribute(...)] | 0 | 1 | | System.Resources.MissingManifestResourceException | [NullableAttribute(...)] | 0 | 0 | | System.Resources.MissingManifestResourceException | [NullableContextAttribute(...)] | 0 | 2 | | System.Resources.MissingManifestResourceException | [TypeForwardedFromAttribute(...)] | 0 | mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 | @@ -1900,6 +2159,7 @@ attrArgPositional | System.Resources.ResourceManager | [NullableAttribute(...)] | 0 | 0 | | System.Resources.ResourceManager | [NullableContextAttribute(...)] | 0 | 1 | | System.Resources.ResourceManager.MainAssembly | [NullableAttribute(...)] | 0 | 2 | +| System.Resources.ResourceManager._userResourceSet | [DynamicallyAccessedMembersAttribute(...)] | 0 | 7 | | System.Resources.ResourceSet | [NullableAttribute(...)] | 0 | 0 | | System.Resources.ResourceSet | [NullableContextAttribute(...)] | 0 | 1 | | System.Resources.SatelliteContractVersionAttribute | [AttributeUsageAttribute(...)] | 0 | 1 | @@ -1937,6 +2197,7 @@ attrArgPositional | System.Runtime.CompilerServices.CallerFilePathAttribute | [AttributeUsageAttribute(...)] | 0 | 2048 | | System.Runtime.CompilerServices.CallerLineNumberAttribute | [AttributeUsageAttribute(...)] | 0 | 2048 | | System.Runtime.CompilerServices.CallerMemberNameAttribute | [AttributeUsageAttribute(...)] | 0 | 2048 | +| System.Runtime.CompilerServices.CastHelpers.CastCacheEntry | [DebuggerDisplayAttribute(...)] | 0 | Source = {_source}; Target = {_targetAndResult & ~1}; Result = {_targetAndResult & 1}; VersionNum = {_version & ((1 << 29) - 1)}; Distance = {_version >> 29}; | | System.Runtime.CompilerServices.CompilationRelaxationsAttribute | [AttributeUsageAttribute(...)] | 0 | 71 | | System.Runtime.CompilerServices.CompilerGeneratedAttribute | [AttributeUsageAttribute(...)] | 0 | 32767 | | System.Runtime.CompilerServices.CompilerGlobalScopeAttribute | [AttributeUsageAttribute(...)] | 0 | 4 | @@ -1958,6 +2219,7 @@ attrArgPositional | System.Runtime.CompilerServices.DependencyAttribute | [NullableAttribute(...)] | 0 | 0 | | System.Runtime.CompilerServices.DependencyAttribute | [NullableContextAttribute(...)] | 0 | 1 | | System.Runtime.CompilerServices.DisablePrivateReflectionAttribute | [AttributeUsageAttribute(...)] | 0 | 1 | +| System.Runtime.CompilerServices.DiscardableAttribute | [AttributeUsageAttribute(...)] | 0 | 32767 | | System.Runtime.CompilerServices.EnumeratorCancellationAttribute | [AttributeUsageAttribute(...)] | 0 | 2048 | | System.Runtime.CompilerServices.ExtensionAttribute | [AttributeUsageAttribute(...)] | 0 | 69 | | System.Runtime.CompilerServices.FixedAddressValueTypeAttribute | [AttributeUsageAttribute(...)] | 0 | 256 | @@ -1977,13 +2239,25 @@ attrArgPositional | System.Runtime.CompilerServices.IntrinsicAttribute | [AttributeUsageAttribute(...)] | 0 | 364 | | System.Runtime.CompilerServices.IsByRefLikeAttribute | [AttributeUsageAttribute(...)] | 0 | 8 | | System.Runtime.CompilerServices.IsByRefLikeAttribute | [EditorBrowsableAttribute(...)] | 0 | 1 | +| System.Runtime.CompilerServices.IsExternalInit | [EditorBrowsableAttribute(...)] | 0 | 1 | | System.Runtime.CompilerServices.IsReadOnlyAttribute | [AttributeUsageAttribute(...)] | 0 | 32767 | | System.Runtime.CompilerServices.IsReadOnlyAttribute | [EditorBrowsableAttribute(...)] | 0 | 1 | | System.Runtime.CompilerServices.IteratorStateMachineAttribute | [AttributeUsageAttribute(...)] | 0 | 64 | | System.Runtime.CompilerServices.MethodImplAttribute | [AttributeUsageAttribute(...)] | 0 | 96 | +| System.Runtime.CompilerServices.ModuleInitializerAttribute | [AttributeUsageAttribute(...)] | 0 | 64 | +| System.Runtime.CompilerServices.NativeIntegerAttribute | [AttributeUsageAttribute(...)] | 0 | 27524 | | System.Runtime.CompilerServices.NullableAttribute | [AttributeUsageAttribute(...)] | 0 | 27524 | -| System.Runtime.CompilerServices.NullableContextAttribute | [AttributeUsageAttribute(...)] | 0 | 5198 | +| System.Runtime.CompilerServices.NullableContextAttribute | [AttributeUsageAttribute(...)] | 0 | 5196 | | System.Runtime.CompilerServices.NullablePublicOnlyAttribute | [AttributeUsageAttribute(...)] | 0 | 2 | +| System.Runtime.CompilerServices.ObjectHandleOnStack | [ObsoleteAttribute(...)] | 0 | Types with embedded references are not supported in this version of your compiler. | +| System.Runtime.CompilerServices.ObjectHandleOnStack | [ObsoleteAttribute(...)] | 1 | True | +| System.Runtime.CompilerServices.PreserveBaseOverridesAttribute | [AttributeUsageAttribute(...)] | 0 | 64 | +| System.Runtime.CompilerServices.QCallAssembly | [ObsoleteAttribute(...)] | 0 | Types with embedded references are not supported in this version of your compiler. | +| System.Runtime.CompilerServices.QCallAssembly | [ObsoleteAttribute(...)] | 1 | True | +| System.Runtime.CompilerServices.QCallModule | [ObsoleteAttribute(...)] | 0 | Types with embedded references are not supported in this version of your compiler. | +| System.Runtime.CompilerServices.QCallModule | [ObsoleteAttribute(...)] | 1 | True | +| System.Runtime.CompilerServices.QCallTypeHandle | [ObsoleteAttribute(...)] | 0 | Types with embedded references are not supported in this version of your compiler. | +| System.Runtime.CompilerServices.QCallTypeHandle | [ObsoleteAttribute(...)] | 1 | True | | System.Runtime.CompilerServices.ReferenceAssemblyAttribute | [AttributeUsageAttribute(...)] | 0 | 1 | | System.Runtime.CompilerServices.ReferenceAssemblyAttribute | [NullableAttribute(...)] | 0 | 0 | | System.Runtime.CompilerServices.ReferenceAssemblyAttribute | [NullableContextAttribute(...)] | 0 | 2 | @@ -1997,13 +2271,21 @@ attrArgPositional | System.Runtime.CompilerServices.RuntimeWrappedException | [NullableAttribute(...)] | 0 | 0 | | System.Runtime.CompilerServices.RuntimeWrappedException | [NullableContextAttribute(...)] | 0 | 1 | | System.Runtime.CompilerServices.RuntimeWrappedException | [TypeForwardedFromAttribute(...)] | 0 | mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 | +| System.Runtime.CompilerServices.SkipLocalsInitAttribute | [AttributeUsageAttribute(...)] | 0 | 1774 | | System.Runtime.CompilerServices.SpecialNameAttribute | [AttributeUsageAttribute(...)] | 0 | 972 | +| System.Runtime.CompilerServices.StackCrawlMarkHandle | [ObsoleteAttribute(...)] | 0 | Types with embedded references are not supported in this version of your compiler. | +| System.Runtime.CompilerServices.StackCrawlMarkHandle | [ObsoleteAttribute(...)] | 1 | True | | System.Runtime.CompilerServices.StateMachineAttribute | [AttributeUsageAttribute(...)] | 0 | 64 | | System.Runtime.CompilerServices.StateMachineAttribute | [NullableAttribute(...)] | 0 | 0 | | System.Runtime.CompilerServices.StateMachineAttribute | [NullableContextAttribute(...)] | 0 | 1 | | System.Runtime.CompilerServices.StringFreezingAttribute | [AttributeUsageAttribute(...)] | 0 | 1 | +| System.Runtime.CompilerServices.StringHandleOnStack | [ObsoleteAttribute(...)] | 0 | Types with embedded references are not supported in this version of your compiler. | +| System.Runtime.CompilerServices.StringHandleOnStack | [ObsoleteAttribute(...)] | 1 | True | | System.Runtime.CompilerServices.StrongBox`1.Value | [NullableAttribute(...)] | 0 | 1 | | System.Runtime.CompilerServices.SuppressIldasmAttribute | [AttributeUsageAttribute(...)] | 0 | 3 | +| System.Runtime.CompilerServices.SwitchExpressionException | [NullableAttribute(...)] | 0 | 0 | +| System.Runtime.CompilerServices.SwitchExpressionException | [NullableContextAttribute(...)] | 0 | 2 | +| System.Runtime.CompilerServices.SwitchExpressionException | [TypeForwardedFromAttribute(...)] | 0 | System.Runtime.Extensions, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a | | System.Runtime.CompilerServices.TupleElementNamesAttribute | [AttributeUsageAttribute(...)] | 0 | 11148 | | System.Runtime.CompilerServices.TupleElementNamesAttribute | [CLSCompliantAttribute(...)] | 0 | False | | System.Runtime.CompilerServices.TypeDependencyAttribute | [AttributeUsageAttribute(...)] | 0 | 1036 | @@ -2014,14 +2296,19 @@ attrArgPositional | System.Runtime.CompilerServices.TypeForwardedToAttribute | [NullableAttribute(...)] | 0 | 0 | | System.Runtime.CompilerServices.TypeForwardedToAttribute | [NullableContextAttribute(...)] | 0 | 1 | | System.Runtime.CompilerServices.UnsafeValueTypeAttribute | [AttributeUsageAttribute(...)] | 0 | 8 | +| System.Runtime.ConstrainedExecution.Cer | [ObsoleteAttribute(...)] | 0 | The Constrained Execution Region (CER) feature is not supported. | +| System.Runtime.ConstrainedExecution.Consistency | [ObsoleteAttribute(...)] | 0 | The Constrained Execution Region (CER) feature is not supported. | | System.Runtime.ConstrainedExecution.PrePrepareMethodAttribute | [AttributeUsageAttribute(...)] | 0 | 96 | +| System.Runtime.ConstrainedExecution.PrePrepareMethodAttribute | [ObsoleteAttribute(...)] | 0 | The Constrained Execution Region (CER) feature is not supported. | | System.Runtime.ConstrainedExecution.ReliabilityContractAttribute | [AttributeUsageAttribute(...)] | 0 | 1133 | +| System.Runtime.ConstrainedExecution.ReliabilityContractAttribute | [ObsoleteAttribute(...)] | 0 | The Constrained Execution Region (CER) feature is not supported. | | System.Runtime.ExceptionServices.ExceptionDispatchInfo | [NullableAttribute(...)] | 0 | 0 | | System.Runtime.ExceptionServices.ExceptionDispatchInfo | [NullableContextAttribute(...)] | 0 | 1 | | System.Runtime.ExceptionServices.FirstChanceExceptionEventArgs | [NullableAttribute(...)] | 0 | 0 | | System.Runtime.ExceptionServices.FirstChanceExceptionEventArgs | [NullableContextAttribute(...)] | 0 | 1 | | System.Runtime.ExceptionServices.HandleProcessCorruptedStateExceptionsAttribute | [AttributeUsageAttribute(...)] | 0 | 64 | | System.Runtime.InteropServices.AllowReversePInvokeCallsAttribute | [AttributeUsageAttribute(...)] | 0 | 64 | +| System.Runtime.InteropServices.AllowReversePInvokeCallsAttribute | [ObsoleteAttribute(...)] | 0 | Code Access Security is not supported or honored by the runtime. | | System.Runtime.InteropServices.ArrayWithOffset | [NullableAttribute(...)] | 0 | 0 | | System.Runtime.InteropServices.ArrayWithOffset | [NullableContextAttribute(...)] | 0 | 2 | | System.Runtime.InteropServices.BStrWrapper | [NullableAttribute(...)] | 0 | 0 | @@ -2042,6 +2329,7 @@ attrArgPositional | System.Runtime.InteropServices.ComEventInterfaceAttribute | [NullableContextAttribute(...)] | 0 | 1 | | System.Runtime.InteropServices.ComEventsHelper | [NullableAttribute(...)] | 0 | 0 | | System.Runtime.InteropServices.ComEventsHelper | [NullableContextAttribute(...)] | 0 | 1 | +| System.Runtime.InteropServices.ComEventsHelper | [SupportedOSPlatformAttribute(...)] | 0 | windows | | System.Runtime.InteropServices.ComImportAttribute | [AttributeUsageAttribute(...)] | 0 | 1028 | | System.Runtime.InteropServices.ComSourceInterfacesAttribute | [AttributeUsageAttribute(...)] | 0 | 4 | | System.Runtime.InteropServices.ComSourceInterfacesAttribute | [NullableAttribute(...)] | 0 | 0 | @@ -2074,6 +2362,7 @@ attrArgPositional | System.Runtime.InteropServices.ComTypes.IEnumVARIANT | [InterfaceTypeAttribute(...)] | 0 | 1 | | System.Runtime.InteropServices.ComTypes.IEnumVARIANT | [NullableContextAttribute(...)] | 0 | 1 | | System.Runtime.InteropServices.ComTypes.IEnumerable | [GuidAttribute(...)] | 0 | 496B0ABE-CDEE-11d3-88E8-00902754C43A | +| System.Runtime.InteropServices.ComTypes.IEnumerator | [GuidAttribute(...)] | 0 | 496B0ABF-CDEE-11d3-88E8-00902754C43A | | System.Runtime.InteropServices.ComTypes.IMoniker | [GuidAttribute(...)] | 0 | 0000000f-0000-0000-C000-000000000046 | | System.Runtime.InteropServices.ComTypes.IMoniker | [InterfaceTypeAttribute(...)] | 0 | 1 | | System.Runtime.InteropServices.ComTypes.IMoniker | [NullableContextAttribute(...)] | 0 | 1 | @@ -2104,6 +2393,12 @@ attrArgPositional | System.Runtime.InteropServices.ComTypes.STATSTG.pwcsName | [NullableAttribute(...)] | 0 | 1 | | System.Runtime.InteropServices.ComTypes.VARDESC.lpstrSchema | [NullableAttribute(...)] | 0 | 1 | | System.Runtime.InteropServices.ComVisibleAttribute | [AttributeUsageAttribute(...)] | 0 | 5597 | +| System.Runtime.InteropServices.ComWrappers | [CLSCompliantAttribute(...)] | 0 | False | +| System.Runtime.InteropServices.ComWrappers | [NullableAttribute(...)] | 0 | 0 | +| System.Runtime.InteropServices.ComWrappers | [NullableContextAttribute(...)] | 0 | 1 | +| System.Runtime.InteropServices.ComWrappers | [SupportedOSPlatformAttribute(...)] | 0 | windows | +| System.Runtime.InteropServices.ComWrappers.ComInterfaceDispatch | [NullableContextAttribute(...)] | 0 | 0 | +| System.Runtime.InteropServices.ComWrappers.ComInterfaceEntry | [NullableContextAttribute(...)] | 0 | 0 | | System.Runtime.InteropServices.DefaultCharSetAttribute | [AttributeUsageAttribute(...)] | 0 | 2 | | System.Runtime.InteropServices.DefaultDllImportSearchPathsAttribute | [AttributeUsageAttribute(...)] | 0 | 65 | | System.Runtime.InteropServices.DefaultParameterValueAttribute | [AttributeUsageAttribute(...)] | 0 | 2048 | @@ -2112,10 +2407,12 @@ attrArgPositional | System.Runtime.InteropServices.DispIdAttribute | [AttributeUsageAttribute(...)] | 0 | 960 | | System.Runtime.InteropServices.DispatchWrapper | [NullableAttribute(...)] | 0 | 0 | | System.Runtime.InteropServices.DispatchWrapper | [NullableContextAttribute(...)] | 0 | 2 | +| System.Runtime.InteropServices.DispatchWrapper | [SupportedOSPlatformAttribute(...)] | 0 | windows | | System.Runtime.InteropServices.DllImportAttribute | [AttributeUsageAttribute(...)] | 0 | 64 | | System.Runtime.InteropServices.DllImportAttribute | [NullableAttribute(...)] | 0 | 0 | | System.Runtime.InteropServices.DllImportAttribute | [NullableContextAttribute(...)] | 0 | 1 | | System.Runtime.InteropServices.DllImportAttribute.EntryPoint | [NullableAttribute(...)] | 0 | 2 | +| System.Runtime.InteropServices.DynamicInterfaceCastableImplementationAttribute | [AttributeUsageAttribute(...)] | 0 | 1024 | | System.Runtime.InteropServices.ErrorWrapper | [NullableAttribute(...)] | 0 | 0 | | System.Runtime.InteropServices.ErrorWrapper | [NullableContextAttribute(...)] | 0 | 1 | | System.Runtime.InteropServices.Expando.IExpando | [GuidAttribute(...)] | 0 | AFBF15E6-C37C-11d2-B88E-00A0C9B471B8 | @@ -2150,8 +2447,6 @@ attrArgPositional | System.Runtime.InteropServices.MarshalDirectiveException | [NullableAttribute(...)] | 0 | 0 | | System.Runtime.InteropServices.MarshalDirectiveException | [NullableContextAttribute(...)] | 0 | 2 | | System.Runtime.InteropServices.MarshalDirectiveException | [TypeForwardedFromAttribute(...)] | 0 | mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 | -| System.Runtime.InteropServices.NativeCallableAttribute | [AttributeUsageAttribute(...)] | 0 | 64 | -| System.Runtime.InteropServices.NativeCallableAttribute.EntryPoint | [NullableAttribute(...)] | 0 | 2 | | System.Runtime.InteropServices.NativeLibrary | [NullableAttribute(...)] | 0 | 0 | | System.Runtime.InteropServices.NativeLibrary | [NullableContextAttribute(...)] | 0 | 1 | | System.Runtime.InteropServices.OptionalAttribute | [AttributeUsageAttribute(...)] | 0 | 2048 | @@ -2172,19 +2467,26 @@ attrArgPositional | System.Runtime.InteropServices.SafeHandle System.Threading.ThreadPoolBoundHandle.Handle | [NullableAttribute(...)] | 0 | 1 | | System.Runtime.InteropServices.StructLayoutAttribute | [AttributeUsageAttribute(...)] | 0 | 12 | | System.Runtime.InteropServices.StructLayoutAttribute System.Type.StructLayoutAttribute | [NullableAttribute(...)] | 0 | 2 | +| System.Runtime.InteropServices.SuppressGCTransitionAttribute | [AttributeUsageAttribute(...)] | 0 | 64 | | System.Runtime.InteropServices.TypeIdentifierAttribute | [AttributeUsageAttribute(...)] | 0 | 5144 | | System.Runtime.InteropServices.TypeIdentifierAttribute | [NullableAttribute(...)] | 0 | 0 | | System.Runtime.InteropServices.TypeIdentifierAttribute | [NullableContextAttribute(...)] | 0 | 2 | | System.Runtime.InteropServices.UnknownWrapper | [NullableAttribute(...)] | 0 | 0 | | System.Runtime.InteropServices.UnknownWrapper | [NullableContextAttribute(...)] | 0 | 2 | +| System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute | [AttributeUsageAttribute(...)] | 0 | 64 | +| System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute.CallConvs | [NullableAttribute(...)] | 0 | [2,1] | +| System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute.EntryPoint | [NullableAttribute(...)] | 0 | 2 | | System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute | [AttributeUsageAttribute(...)] | 0 | 4096 | | System.Runtime.InteropServices.VariantWrapper | [NullableAttribute(...)] | 0 | 0 | | System.Runtime.InteropServices.VariantWrapper | [NullableContextAttribute(...)] | 0 | 2 | -| System.Runtime.Intrinsics.Arm.Arm64.Aes | [CLSCompliantAttribute(...)] | 0 | False | -| System.Runtime.Intrinsics.Arm.Arm64.Base | [CLSCompliantAttribute(...)] | 0 | False | -| System.Runtime.Intrinsics.Arm.Arm64.Sha1 | [CLSCompliantAttribute(...)] | 0 | False | -| System.Runtime.Intrinsics.Arm.Arm64.Sha256 | [CLSCompliantAttribute(...)] | 0 | False | -| System.Runtime.Intrinsics.Arm.Arm64.Simd | [CLSCompliantAttribute(...)] | 0 | False | +| System.Runtime.Intrinsics.Arm.AdvSimd | [CLSCompliantAttribute(...)] | 0 | False | +| System.Runtime.Intrinsics.Arm.Aes | [CLSCompliantAttribute(...)] | 0 | False | +| System.Runtime.Intrinsics.Arm.ArmBase | [CLSCompliantAttribute(...)] | 0 | False | +| System.Runtime.Intrinsics.Arm.Crc32 | [CLSCompliantAttribute(...)] | 0 | False | +| System.Runtime.Intrinsics.Arm.Dp | [CLSCompliantAttribute(...)] | 0 | False | +| System.Runtime.Intrinsics.Arm.Rdm | [CLSCompliantAttribute(...)] | 0 | False | +| System.Runtime.Intrinsics.Arm.Sha1 | [CLSCompliantAttribute(...)] | 0 | False | +| System.Runtime.Intrinsics.Arm.Sha256 | [CLSCompliantAttribute(...)] | 0 | False | | System.Runtime.Intrinsics.Vector64`1 | [DebuggerDisplayAttribute(...)] | 0 | {DisplayString,nq} | | System.Runtime.Intrinsics.Vector64`1 | [DebuggerTypeProxyAttribute(...)] | 0 | System.Runtime.Intrinsics.Vector64DebugView`1 | | System.Runtime.Intrinsics.Vector128`1 | [DebuggerDisplayAttribute(...)] | 0 | {DisplayString,nq} | @@ -2250,10 +2552,22 @@ attrArgPositional | System.Runtime.TargetedPatchingOptOutAttribute | [AttributeUsageAttribute(...)] | 0 | 96 | | System.Runtime.TargetedPatchingOptOutAttribute | [NullableAttribute(...)] | 0 | 0 | | System.Runtime.TargetedPatchingOptOutAttribute | [NullableContextAttribute(...)] | 0 | 1 | +| System.Runtime.Versioning.ComponentGuaranteesAttribute | [AttributeUsageAttribute(...)] | 0 | 5887 | +| System.Runtime.Versioning.FrameworkName | [NullableAttribute(...)] | 0 | 0 | +| System.Runtime.Versioning.FrameworkName | [NullableContextAttribute(...)] | 0 | 1 | | System.Runtime.Versioning.NonVersionableAttribute | [AttributeUsageAttribute(...)] | 0 | 108 | +| System.Runtime.Versioning.OSPlatformAttribute | [NullableAttribute(...)] | 0 | 0 | +| System.Runtime.Versioning.OSPlatformAttribute | [NullableContextAttribute(...)] | 0 | 1 | +| System.Runtime.Versioning.ResourceConsumptionAttribute | [AttributeUsageAttribute(...)] | 0 | 224 | +| System.Runtime.Versioning.ResourceConsumptionAttribute | [ConditionalAttribute(...)] | 0 | RESOURCE_ANNOTATION_WORK | +| System.Runtime.Versioning.ResourceExposureAttribute | [AttributeUsageAttribute(...)] | 0 | 480 | +| System.Runtime.Versioning.ResourceExposureAttribute | [ConditionalAttribute(...)] | 0 | RESOURCE_ANNOTATION_WORK | +| System.Runtime.Versioning.SupportedOSPlatformAttribute | [AttributeUsageAttribute(...)] | 0 | 1023 | | System.Runtime.Versioning.TargetFrameworkAttribute | [AttributeUsageAttribute(...)] | 0 | 1 | | System.Runtime.Versioning.TargetFrameworkAttribute | [NullableAttribute(...)] | 0 | 0 | | System.Runtime.Versioning.TargetFrameworkAttribute | [NullableContextAttribute(...)] | 0 | 1 | +| System.Runtime.Versioning.TargetPlatformAttribute | [AttributeUsageAttribute(...)] | 0 | 1 | +| System.Runtime.Versioning.UnsupportedOSPlatformAttribute | [AttributeUsageAttribute(...)] | 0 | 1023 | | System.RuntimeType.ListBuilder`1 | [DefaultMemberAttribute(...)] | 0 | Item | | System.RuntimeTypeHandle | [NullableAttribute(...)] | 0 | 0 | | System.RuntimeTypeHandle | [NullableContextAttribute(...)] | 0 | 2 | @@ -2263,10 +2577,22 @@ attrArgPositional | System.Security.Cryptography.CryptographicException | [NullableContextAttribute(...)] | 0 | 1 | | System.Security.Cryptography.CryptographicException | [TypeForwardedFromAttribute(...)] | 0 | mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 | | System.Security.IPermission | [NullableContextAttribute(...)] | 0 | 2 | +| System.Security.IPermission | [ObsoleteAttribute(...)] | 0 | Code Access Security is not supported or honored by the runtime. | | System.Security.ISecurityEncodable | [NullableContextAttribute(...)] | 0 | 1 | +| System.Security.IStackWalk | [ObsoleteAttribute(...)] | 0 | Code Access Security is not supported or honored by the runtime. | | System.Security.PermissionSet | [NullableAttribute(...)] | 0 | 0 | | System.Security.PermissionSet | [NullableContextAttribute(...)] | 0 | 2 | -| System.Security.PermissionSet System.AppDomain.PermissionSet | [NullableAttribute(...)] | 0 | 1 | +| System.Security.PermissionSet | [ObsoleteAttribute(...)] | 0 | Code Access Security is not supported or honored by the runtime. | +| System.Security.PermissionSet System.AppDomain.PermissionSet | [ObsoleteAttribute(...)] | 0 | Code Access Security is not supported or honored by the runtime. | +| System.Security.Permissions.CodeAccessSecurityAttribute | [AttributeUsageAttribute(...)] | 0 | 109 | +| System.Security.Permissions.CodeAccessSecurityAttribute | [ObsoleteAttribute(...)] | 0 | Code Access Security is not supported or honored by the runtime. | +| System.Security.Permissions.PermissionState | [ObsoleteAttribute(...)] | 0 | Code Access Security is not supported or honored by the runtime. | +| System.Security.Permissions.SecurityAction | [ObsoleteAttribute(...)] | 0 | Code Access Security is not supported or honored by the runtime. | +| System.Security.Permissions.SecurityAttribute | [AttributeUsageAttribute(...)] | 0 | 109 | +| System.Security.Permissions.SecurityAttribute | [ObsoleteAttribute(...)] | 0 | Code Access Security is not supported or honored by the runtime. | +| System.Security.Permissions.SecurityPermissionAttribute | [AttributeUsageAttribute(...)] | 0 | 109 | +| System.Security.Permissions.SecurityPermissionAttribute | [ObsoleteAttribute(...)] | 0 | Code Access Security is not supported or honored by the runtime. | +| System.Security.Permissions.SecurityPermissionFlag | [ObsoleteAttribute(...)] | 0 | Code Access Security is not supported or honored by the runtime. | | System.Security.Principal.IIdentity | [NullableContextAttribute(...)] | 0 | 2 | | System.Security.Principal.IPrincipal | [NullableContextAttribute(...)] | 0 | 2 | | System.Security.Principal.IPrincipal System.Threading.Thread.CurrentPrincipal | [NullableAttribute(...)] | 0 | 2 | @@ -2308,6 +2634,8 @@ attrArgPositional | System.StringComparer | [NullableAttribute(...)] | 0 | 0 | | System.StringComparer | [NullableContextAttribute(...)] | 0 | 1 | | System.StringComparer | [TypeForwardedFromAttribute(...)] | 0 | mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 | +| System.StringNormalizationExtensions | [NullableAttribute(...)] | 0 | 0 | +| System.StringNormalizationExtensions | [NullableContextAttribute(...)] | 0 | 1 | | System.SystemException | [NullableAttribute(...)] | 0 | 0 | | System.SystemException | [NullableContextAttribute(...)] | 0 | 2 | | System.SystemException | [TypeForwardedFromAttribute(...)] | 0 | mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 | @@ -2333,10 +2661,15 @@ attrArgPositional | System.Text.EncoderReplacementFallback | [NullableContextAttribute(...)] | 0 | 1 | | System.Text.Encoding | [NullableAttribute(...)] | 0 | 0 | | System.Text.Encoding | [NullableContextAttribute(...)] | 0 | 1 | +| System.Text.Encoding System.Console.InputEncoding | [UnsupportedOSPlatformAttribute(...)] | 0 | browser | +| System.Text.Encoding System.Text.Encoding.UTF7 | [ObsoleteAttribute(...)] | 0 | The UTF-7 encoding is insecure and should not be used. Consider using UTF-8 instead. | | System.Text.EncodingInfo | [NullableAttribute(...)] | 0 | 0 | | System.Text.EncodingInfo | [NullableContextAttribute(...)] | 0 | 1 | | System.Text.EncodingProvider | [NullableAttribute(...)] | 0 | 0 | | System.Text.EncodingProvider | [NullableContextAttribute(...)] | 0 | 1 | +| System.Text.EncodingProvider System.Text.EncodingInfo.Provider | [NullableAttribute(...)] | 0 | 2 | +| System.Text.Latin1Encoding.<>c.<>9__29_0 | [TupleElementNamesAttribute(...)] | 0 | [encoding,bytes] | +| System.Text.Latin1Encoding.<>c.<>9__30_0 | [TupleElementNamesAttribute(...)] | 0 | [encoding,bytes,index] | | System.Text.Rune | [DebuggerDisplayAttribute(...)] | 0 | {DebuggerDisplay,nq} | | System.Text.SpanRuneEnumerator | [ObsoleteAttribute(...)] | 0 | Types with embedded references are not supported in this version of your compiler. | | System.Text.SpanRuneEnumerator | [ObsoleteAttribute(...)] | 1 | True | @@ -2349,6 +2682,8 @@ attrArgPositional | System.Text.UTF7Encoding | [NullableContextAttribute(...)] | 0 | 1 | | System.Text.UTF32Encoding | [NullableAttribute(...)] | 0 | 0 | | System.Text.UTF32Encoding | [NullableContextAttribute(...)] | 0 | 1 | +| System.Text.Unicode.TextSegmentationUtility.Processor`1 | [ObsoleteAttribute(...)] | 0 | Types with embedded references are not supported in this version of your compiler. | +| System.Text.Unicode.TextSegmentationUtility.Processor`1 | [ObsoleteAttribute(...)] | 1 | True | | System.Text.UnicodeEncoding | [NullableAttribute(...)] | 0 | 0 | | System.Text.UnicodeEncoding | [NullableContextAttribute(...)] | 0 | 1 | | System.Text.ValueStringBuilder | [DefaultMemberAttribute(...)] | 0 | Item | @@ -2361,7 +2696,7 @@ attrArgPositional | System.Threading.ApartmentState System.Threading.Thread.ApartmentState | [ObsoleteAttribute(...)] | 0 | The ApartmentState property has been deprecated. Use GetApartmentState, SetApartmentState or TrySetApartmentState instead. | | System.Threading.ApartmentState System.Threading.Thread.ApartmentState | [ObsoleteAttribute(...)] | 1 | False | | System.Threading.AsyncLocalValueChangedArgs`1 | [NullableAttribute(...)] | 0 | 0 | -| System.Threading.AsyncLocalValueChangedArgs`1 | [NullableContextAttribute(...)] | 0 | 1 | +| System.Threading.AsyncLocalValueChangedArgs`1 | [NullableContextAttribute(...)] | 0 | 2 | | System.Threading.AsyncLocal`1 | [NullableAttribute(...)] | 0 | 0 | | System.Threading.AsyncLocal`1 | [NullableContextAttribute(...)] | 0 | 1 | | System.Threading.CancellationToken | [DebuggerDisplayAttribute(...)] | 0 | IsCancellationRequested = {IsCancellationRequested} | @@ -2373,6 +2708,8 @@ attrArgPositional | System.Threading.CompressedStack | [NullableContextAttribute(...)] | 0 | 1 | | System.Threading.EventWaitHandle | [NullableAttribute(...)] | 0 | 0 | | System.Threading.EventWaitHandle | [NullableContextAttribute(...)] | 0 | 1 | +| System.Threading.ExecutionContext | [NullableAttribute(...)] | 0 | 0 | +| System.Threading.ExecutionContext | [NullableContextAttribute(...)] | 0 | 1 | | System.Threading.ExecutionContext System.Threading.Tasks.Task.CapturedContext | [NullableAttribute(...)] | 0 | 2 | | System.Threading.ExecutionContext System.Threading.Thread.ExecutionContext | [NullableAttribute(...)] | 0 | 2 | | System.Threading.IOCompletionCallback | [CLSCompliantAttribute(...)] | 0 | False | @@ -2390,6 +2727,7 @@ attrArgPositional | System.Threading.Mutex | [NullableContextAttribute(...)] | 0 | 1 | | System.Threading.Overlapped | [NullableAttribute(...)] | 0 | 0 | | System.Threading.Overlapped | [NullableContextAttribute(...)] | 0 | 2 | +| System.Threading.RegisteredWaitHandle | [UnsupportedOSPlatformAttribute(...)] | 0 | browser | | System.Threading.Semaphore | [NullableAttribute(...)] | 0 | 0 | | System.Threading.Semaphore | [NullableContextAttribute(...)] | 0 | 1 | | System.Threading.SemaphoreFullException | [NullableAttribute(...)] | 0 | 0 | @@ -2433,6 +2771,8 @@ attrArgPositional | System.Threading.Tasks.TaskCanceledException | [NullableAttribute(...)] | 0 | 0 | | System.Threading.Tasks.TaskCanceledException | [NullableContextAttribute(...)] | 0 | 2 | | System.Threading.Tasks.TaskCanceledException | [TypeForwardedFromAttribute(...)] | 0 | mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 | +| System.Threading.Tasks.TaskCompletionSource | [NullableAttribute(...)] | 0 | 0 | +| System.Threading.Tasks.TaskCompletionSource | [NullableContextAttribute(...)] | 0 | 1 | | System.Threading.Tasks.TaskCompletionSource`1 | [NullableAttribute(...)] | 0 | 0 | | System.Threading.Tasks.TaskCompletionSource`1 | [NullableContextAttribute(...)] | 0 | 1 | | System.Threading.Tasks.TaskExtensions | [NullableAttribute(...)] | 0 | 0 | @@ -2458,7 +2798,7 @@ attrArgPositional | System.Threading.Tasks.Task`1 | [NullableAttribute(...)] | 0 | 0 | | System.Threading.Tasks.Task`1 | [NullableContextAttribute(...)] | 0 | 1 | | System.Threading.Tasks.UnobservedTaskExceptionEventArgs | [NullableAttribute(...)] | 0 | 0 | -| System.Threading.Tasks.UnobservedTaskExceptionEventArgs | [NullableContextAttribute(...)] | 0 | 2 | +| System.Threading.Tasks.UnobservedTaskExceptionEventArgs | [NullableContextAttribute(...)] | 0 | 1 | | System.Threading.Tasks.ValueTask | [AsyncMethodBuilderAttribute(...)] | 0 | System.Runtime.CompilerServices.AsyncValueTaskMethodBuilder | | System.Threading.Tasks.ValueTask | [NullableAttribute(...)] | 0 | 0 | | System.Threading.Tasks.ValueTask | [NullableContextAttribute(...)] | 0 | 1 | @@ -2471,6 +2811,8 @@ attrArgPositional | System.Threading.ThreadAbortException | [NullableAttribute(...)] | 0 | 0 | | System.Threading.ThreadAbortException | [NullableContextAttribute(...)] | 0 | 2 | | System.Threading.ThreadAbortException | [TypeForwardedFromAttribute(...)] | 0 | mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 | +| System.Threading.ThreadExceptionEventArgs | [NullableAttribute(...)] | 0 | 0 | +| System.Threading.ThreadExceptionEventArgs | [NullableContextAttribute(...)] | 0 | 1 | | System.Threading.ThreadInterruptedException | [NullableAttribute(...)] | 0 | 0 | | System.Threading.ThreadInterruptedException | [NullableContextAttribute(...)] | 0 | 2 | | System.Threading.ThreadInterruptedException | [TypeForwardedFromAttribute(...)] | 0 | mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 | @@ -2561,6 +2903,8 @@ attrArgPositional | System.Type System.Reflection.MemberInfo.ReflectedType | [NullableAttribute(...)] | 0 | 2 | | System.Type System.Reflection.PropertyInfo.PropertyType | [NullableAttribute(...)] | 0 | 1 | | System.Type System.Reflection.TypeDelegator.BaseType | [NullableAttribute(...)] | 0 | 2 | +| System.Type System.Resources.ResourceManager.ResourceManagerMediator.UserResourceSet | [DynamicallyAccessedMembersAttribute(...)] | 0 | 7 | +| System.Type System.Resources.ResourceManager.ResourceSetType | [DynamicallyAccessedMembersAttribute(...)] | 0 | 7 | | System.Type System.Type.BaseType | [NullableAttribute(...)] | 0 | 2 | | System.Type System.Type.DeclaringType | [NullableAttribute(...)] | 0 | 2 | | System.Type System.Type.ReflectedType | [NullableAttribute(...)] | 0 | 2 | @@ -2576,7 +2920,7 @@ attrArgPositional | System.TypeUnloadedException | [NullableAttribute(...)] | 0 | 0 | | System.TypeUnloadedException | [NullableContextAttribute(...)] | 0 | 2 | | System.TypeUnloadedException | [TypeForwardedFromAttribute(...)] | 0 | mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 | -| System.Type[] System.Reflection.ReflectionTypeLoadException.Types | [NullableAttribute(...)] | 0 | [2,1] | +| System.Type[] System.Reflection.ReflectionTypeLoadException.Types | [NullableAttribute(...)] | 0 | [1,2] | | System.TypedReference | [CLSCompliantAttribute(...)] | 0 | False | | System.TypedReference | [NullableAttribute(...)] | 0 | 0 | | System.TypedReference | [NullableContextAttribute(...)] | 0 | 1 | @@ -2634,6 +2978,12 @@ attrArgPositional | System.__DTString | [ObsoleteAttribute(...)] | 0 | Types with embedded references are not supported in this version of your compiler. | | System.__DTString | [ObsoleteAttribute(...)] | 1 | True | | bool | [TypeForwardedFromAttribute(...)] | 0 | mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 | +| bool System.Console.CapsLock | [SupportedOSPlatformAttribute(...)] | 0 | windows | +| bool System.Console.NumberLock | [SupportedOSPlatformAttribute(...)] | 0 | windows | +| bool System.Console.TreatControlCAsInput | [UnsupportedOSPlatformAttribute(...)] | 0 | browser | +| bool System.Reflection.Assembly.GlobalAssemblyCache | [ObsoleteAttribute(...)] | 0 | The Global Assembly Cache is not supported. | +| bool System.Reflection.Emit.AssemblyBuilder.GlobalAssemblyCache | [ObsoleteAttribute(...)] | 0 | The Global Assembly Cache is not supported. | +| bool System.Reflection.RuntimeAssembly.GlobalAssemblyCache | [ObsoleteAttribute(...)] | 0 | The Global Assembly Cache is not supported. | | bool.FalseString | [NullableAttribute(...)] | 0 | 1 | | bool.TrueString | [NullableAttribute(...)] | 0 | 1 | | byte | [TypeForwardedFromAttribute(...)] | 0 | mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 | @@ -2670,7 +3020,12 @@ attrArgPositional | double | [TypeForwardedFromAttribute(...)] | 0 | mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 | | float | [TypeForwardedFromAttribute(...)] | 0 | mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 | | int | [TypeForwardedFromAttribute(...)] | 0 | mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 | +| int System.Console.CursorLeft | [UnsupportedOSPlatformAttribute(...)] | 0 | browser | +| int System.Console.CursorTop | [UnsupportedOSPlatformAttribute(...)] | 0 | browser | +| int System.Console.LargestWindowHeight | [UnsupportedOSPlatformAttribute(...)] | 0 | browser | +| int System.Console.LargestWindowWidth | [UnsupportedOSPlatformAttribute(...)] | 0 | browser | | int System.Threading.Overlapped.EventHandle | [ObsoleteAttribute(...)] | 0 | This property is not 64-bit compatible. Use EventHandleIntPtr instead. http://go.microsoft.com/fwlink/?linkid=14202 | +| int[] System.Globalization.HebrewCalendar.Eras | [NullableAttribute(...)] | 0 | 1 | | int[] System.Globalization.StringInfo.Indexes | [NullableAttribute(...)] | 0 | 2 | | long | [TypeForwardedFromAttribute(...)] | 0 | mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 | | object | [ClassInterfaceAttribute(...)] | 0 | 1 | @@ -2690,6 +3045,7 @@ attrArgPositional | object System.Collections.Generic.Dictionary`2.KeyCollection.SyncRoot | [NullableAttribute(...)] | 0 | 1 | | object System.Collections.Generic.Dictionary`2.ValueCollection.Enumerator.Current | [NullableAttribute(...)] | 0 | 2 | | object System.Collections.Generic.Dictionary`2.ValueCollection.SyncRoot | [NullableAttribute(...)] | 0 | 1 | +| object System.Collections.Generic.HashSet`1.Enumerator.Current | [NullableAttribute(...)] | 0 | 2 | | object System.Collections.Generic.List`1.Enumerator.Current | [NullableAttribute(...)] | 0 | 2 | | object System.Collections.Generic.List`1.Item | [NullableAttribute(...)] | 0 | 2 | | object System.Collections.Hashtable.Item | [NullableAttribute(...)] | 0 | 2 | @@ -2736,15 +3092,22 @@ attrArgPositional | string | [NullableContextAttribute(...)] | 0 | 1 | | string | [TypeForwardedFromAttribute(...)] | 0 | mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 | | string System.AppContext.BaseDirectory | [NullableAttribute(...)] | 0 | 1 | -| string System.AppDomain.FriendlyName | [NullableAttribute(...)] | 0 | 1 | +| string System.AppDomain.DynamicDirectory | [NullableAttribute(...)] | 0 | 2 | +| string System.AppDomain.RelativeSearchPath | [NullableAttribute(...)] | 0 | 2 | +| string System.ApplicationId.Culture | [NullableAttribute(...)] | 0 | 2 | +| string System.ApplicationId.ProcessorArchitecture | [NullableAttribute(...)] | 0 | 2 | | string System.ArgumentException.Message | [NullableAttribute(...)] | 0 | 1 | | string System.ArgumentOutOfRangeException.Message | [NullableAttribute(...)] | 0 | 1 | | string System.BadImageFormatException.Message | [NullableAttribute(...)] | 0 | 1 | +| string System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute.Url | [NullableAttribute(...)] | 0 | 2 | | string System.Diagnostics.CodeAnalysis.SuppressMessageAttribute.Category | [NullableAttribute(...)] | 0 | 1 | | string System.Diagnostics.CodeAnalysis.SuppressMessageAttribute.CheckId | [NullableAttribute(...)] | 0 | 1 | +| string System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute.Category | [NullableAttribute(...)] | 0 | 1 | +| string System.Diagnostics.CodeAnalysis.UnconditionalSuppressMessageAttribute.CheckId | [NullableAttribute(...)] | 0 | 1 | | string System.Diagnostics.Contracts.ContractException.Failure | [NullableAttribute(...)] | 0 | 1 | | string System.Diagnostics.Contracts.ContractOptionAttribute.Value | [NullableAttribute(...)] | 0 | 2 | | string System.Diagnostics.DebuggerDisplayAttribute.Value | [NullableAttribute(...)] | 0 | 1 | +| string System.Diagnostics.DebuggerTypeProxyAttribute.ProxyTypeName | [DynamicallyAccessedMembersAttribute(...)] | 0 | -1 | | string System.Diagnostics.DebuggerTypeProxyAttribute.ProxyTypeName | [NullableAttribute(...)] | 0 | 1 | | string System.Diagnostics.DebuggerVisualizerAttribute.VisualizerTypeName | [NullableAttribute(...)] | 0 | 1 | | string System.Diagnostics.Tracing.EventFieldAttribute.Name | [NullableAttribute(...)] | 0 | 2 | @@ -2775,6 +3138,7 @@ attrArgPositional | string System.Reflection.TypeDelegator.AssemblyQualifiedName | [NullableAttribute(...)] | 0 | 2 | | string System.Reflection.TypeDelegator.FullName | [NullableAttribute(...)] | 0 | 2 | | string System.Reflection.TypeDelegator.Namespace | [NullableAttribute(...)] | 0 | 2 | +| string System.Runtime.CompilerServices.SwitchExpressionException.Message | [NullableAttribute(...)] | 0 | 1 | | string System.Runtime.Intrinsics.Vector64`1.DisplayString | [NullableAttribute(...)] | 0 | 1 | | string System.Runtime.Intrinsics.Vector128`1.DisplayString | [NullableAttribute(...)] | 0 | 1 | | string System.Runtime.Intrinsics.Vector256`1.DisplayString | [NullableAttribute(...)] | 0 | 1 | diff --git a/csharp/ql/test/library-tests/cil/consistency/consistency.expected b/csharp/ql/test/library-tests/cil/consistency/consistency.expected index 3db667efdc5..ccee053d8a4 100644 --- a/csharp/ql/test/library-tests/cil/consistency/consistency.expected +++ b/csharp/ql/test/library-tests/cil/consistency/consistency.expected @@ -1 +1,19 @@ +| DispatchTailCalls | No label | +| EnumCalendarInfo | No label | | Finalize | Overridden method from System.Object is not in a base type | +| Unknown instruction in DispatchTailCalls | Call has invalid target | +| Unknown instruction in DispatchTailCalls | Cfg node has 0 pop counts | +| Unknown instruction in DispatchTailCalls | Cfg node has 0 push counts | +| Unknown instruction in DispatchTailCalls | Inconsistent stack size | +| Unknown instruction in DispatchTailCalls | Opcode 41 is missing a QL class | +| bne.un.s | Inconsistent stack size | +| conv.u | Inconsistent stack size | +| delegate* managed | No label | +| delegate* unmanaged | No label | +| ldarg.1 | Inconsistent stack size | +| ldc.i4.0 | Inconsistent stack size | +| ldfld | Inconsistent stack size | +| ldloc.3 | Inconsistent stack size | +| leave.s | Inconsistent stack size | +| ret | Inconsistent stack size | +| starg.s | Inconsistent stack size | diff --git a/csharp/ql/test/library-tests/cil/dataflow/CallableReturns.expected b/csharp/ql/test/library-tests/cil/dataflow/CallableReturns.expected index 42ad6de6cf2..e71d177d5ef 100644 --- a/csharp/ql/test/library-tests/cil/dataflow/CallableReturns.expected +++ b/csharp/ql/test/library-tests/cil/dataflow/CallableReturns.expected @@ -24,7 +24,7 @@ alwaysNonNull | System.String System.ThrowHelper.GetArgumentName(System.ExceptionArgument) | | System.Text.Encoder System.Text.ASCIIEncoding.GetEncoder() | | System.Text.Encoder System.Text.Encoding.GetEncoder() | -| System.Text.Encoder System.Text.EncodingNLS.GetEncoder() | +| System.Text.Encoder System.Text.Latin1Encoding.GetEncoder() | | System.Text.Encoder System.Text.UTF7Encoding.GetEncoder() | | System.Text.Encoder System.Text.UTF8Encoding.GetEncoder() | | System.Text.Encoder System.Text.UTF32Encoding.GetEncoder() | @@ -38,6 +38,7 @@ alwaysThrows | System.Void System.ThrowHelper.ThrowAddingDuplicateWithKeyArgumentException`1(!0) | System.ArgumentException | 0: ldarg.0, 1: box, 2: call System.ThrowHelper.GetAddingDuplicateWithKeyArgumentException, 3: throw | | System.Void System.ThrowHelper.ThrowAggregateException(System.Collections.Generic.List) | System.AggregateException | 0: ldarg.0, 1: newobj System.AggregateException..ctor, 2: throw | | System.Void System.ThrowHelper.ThrowArgumentException_Argument_InvalidArrayType() | System.ArgumentException | 0: call System.SR.get_Argument_InvalidArrayType, 1: newobj System.ArgumentException..ctor, 2: throw | +| System.Void System.ThrowHelper.ThrowArgumentException_BadComparer(System.Object) | System.ArgumentException | 0: call System.SR.get_Arg_BogusIComparer, 1: ldarg.0, 2: call System.SR.Format, 3: newobj System.ArgumentException..ctor, 4: throw | | System.Void System.ThrowHelper.ThrowArgumentException_CannotExtractScalar(System.ExceptionArgument) | System.ArgumentException | 0: ldc.i4.s 31, 1: ldarg.0, 2: call System.ThrowHelper.GetArgumentException, 3: throw | | System.Void System.ThrowHelper.ThrowArgumentException_DestinationTooShort() | System.ArgumentException | 0: call System.SR.get_Argument_DestinationTooShort, 1: ldstr "destination", 2: newobj System.ArgumentException..ctor, 3: throw | | System.Void System.ThrowHelper.ThrowArgumentException_OverlapAlignmentMismatch() | System.ArgumentException | 0: call System.SR.get_Argument_OverlapAlignmentMismatch, 1: newobj System.ArgumentException..ctor, 2: throw | @@ -46,7 +47,11 @@ alwaysThrows | System.Void System.ThrowHelper.ThrowArgumentOutOfRangeException(System.ExceptionArgument) | System.ArgumentOutOfRangeException | 0: ldarg.0, 1: call System.ThrowHelper.GetArgumentName, 2: newobj System.ArgumentOutOfRangeException..ctor, 3: throw | | System.Void System.ThrowHelper.ThrowArgumentOutOfRangeException_PrecisionTooLarge() | System.ArgumentOutOfRangeException | 0: ldstr "precision", 1: call System.SR.get_Argument_PrecisionTooLarge, 2: ldc.i4.s 31, 3: box, 4: call System.SR.Format, 5: newobj System.ArgumentOutOfRangeException..ctor, 6: throw | | System.Void System.ThrowHelper.ThrowArgumentOutOfRangeException_SymbolDoesNotFit() | System.ArgumentOutOfRangeException | 0: ldstr "symbol", 1: call System.SR.get_Argument_BadFormatSpecifier, 2: newobj System.ArgumentOutOfRangeException..ctor, 3: throw | +| System.Void System.ThrowHelper.ThrowArgumentOutOfRange_BadHourMinuteSecond() | System.ArgumentOutOfRangeException | 0: ldnull, 1: call System.SR.get_ArgumentOutOfRange_BadHourMinuteSecond, 2: newobj System.ArgumentOutOfRangeException..ctor, 3: throw | +| System.Void System.ThrowHelper.ThrowArgumentOutOfRange_BadYearMonthDay() | System.ArgumentOutOfRangeException | 0: ldnull, 1: call System.SR.get_ArgumentOutOfRange_BadYearMonthDay, 2: newobj System.ArgumentOutOfRangeException..ctor, 3: throw | | System.Void System.ThrowHelper.ThrowArgumentOutOfRange_IndexException() | System.ArgumentOutOfRangeException | 0: ldc.i4.s 31, 1: ldc.i4.0, 2: call System.ThrowHelper.GetArgumentOutOfRangeException, 3: throw | +| System.Void System.ThrowHelper.ThrowArgumentOutOfRange_TimeSpanTooLong() | System.ArgumentOutOfRangeException | 0: ldnull, 1: call System.SR.get_Overflow_TimeSpanTooLong, 2: newobj System.ArgumentOutOfRangeException..ctor, 3: throw | +| System.Void System.ThrowHelper.ThrowArgumentOutOfRange_Year() | System.ArgumentOutOfRangeException | 0: ldc.i4.s 31, 1: ldc.i4.4, 2: call System.ThrowHelper.GetArgumentOutOfRangeException, 3: throw | | System.Void System.ThrowHelper.ThrowArraySegmentCtorValidationFailedExceptions(System.Array,System.Int32,System.Int32) | System.Exception | 0: ldarg.0, 1: ldarg.1, 2: ldarg.2, 3: call System.ThrowHelper.GetArraySegmentCtorValidationFailedException, 4: throw | | System.Void System.ThrowHelper.ThrowArrayTypeMismatchException() | System.ArrayTypeMismatchException | 0: newobj System.ArrayTypeMismatchException..ctor, 1: throw | | System.Void System.ThrowHelper.ThrowCountArgumentOutOfRange_ArgumentOutOfRange_Count() | System.ArgumentOutOfRangeException | 0: ldc.i4.s 31, 1: ldc.i4.3, 2: call System.ThrowHelper.GetArgumentOutOfRangeException, 3: throw | diff --git a/csharp/ql/test/library-tests/cil/enums/enums.expected b/csharp/ql/test/library-tests/cil/enums/enums.expected index dd2907bc5d5..6ffcb85f860 100644 --- a/csharp/ql/test/library-tests/cil/enums/enums.expected +++ b/csharp/ql/test/library-tests/cil/enums/enums.expected @@ -3,6 +3,7 @@ | Interop.Error | int | | Interop.Globalization.ResultCode | int | | Interop.Globalization.TimeZoneDisplayNameType | int | +| Interop.PollEvents | short | | Interop.Sys.AccessMode | int | | Interop.Sys.ControlCharacterNames | int | | Interop.Sys.CtrlCode | int | @@ -11,7 +12,6 @@ | Interop.Sys.LockOperations | int | | Interop.Sys.NodeType | int | | Interop.Sys.OpenFlags | int | -| Interop.Sys.PollEvents | short | | Interop.Sys.SeekWhence | int | | Interop.Sys.SysConfName | int | | Interop.Sys.SysLogPriority | int | @@ -19,7 +19,6 @@ | System.Base64FormattingOptions | int | | System.Buffers.ArrayPoolEventSource.BufferAllocatedReason | int | | System.Buffers.OperationStatus | int | -| System.Buffers.Text.FormattingHelpers.HexCasing | uint | | System.Buffers.Text.Utf8Parser.ComponentParseResult | byte | | System.Buffers.Text.Utf8Parser.ParseNumberOptions | int | | System.Buffers.TlsOverPerCoreLockedStacksArrayPool.MemoryPressure | int | @@ -39,6 +38,7 @@ | System.DayOfWeek | int | | System.DefaultBinder.Primitives | int | | System.DelegateBindingFlags | int | +| System.Diagnostics.CodeAnalysis.DynamicallyAccessedMemberTypes | int | | System.Diagnostics.Contracts.ContractFailureKind | int | | System.Diagnostics.DebuggableAttribute.DebuggingModes | int | | System.Diagnostics.DebuggerBrowsableState | int | @@ -55,6 +55,7 @@ | System.Diagnostics.Tracing.EventLevel | int | | System.Diagnostics.Tracing.EventManifestOptions | int | | System.Diagnostics.Tracing.EventOpcode | int | +| System.Diagnostics.Tracing.EventPipeMetadataGenerator.MetadataTag | int | | System.Diagnostics.Tracing.EventPipeSerializationFormat | int | | System.Diagnostics.Tracing.EventProvider.WriteEventErrorCode | int | | System.Diagnostics.Tracing.EventProviderType | int | @@ -70,10 +71,11 @@ | System.ExceptionArgument | int | | System.ExceptionResource | int | | System.GC.EndNoGCRegionStatus | int | +| System.GC.GC_ALLOC_FLAGS | int | | System.GC.StartNoGCRegionStatus | int | | System.GCCollectionMode | int | +| System.GCKind | int | | System.GCNotificationStatus | int | -| System.Globalization.BidiCategory | int | | System.Globalization.CalendarAlgorithmType | int | | System.Globalization.CalendarDataType | int | | System.Globalization.CalendarId | ushort | @@ -93,9 +95,10 @@ | System.Globalization.HebrewNumber.HS | sbyte | | System.Globalization.HebrewNumber.HebrewToken | short | | System.Globalization.HebrewNumberParsingState | int | -| System.Globalization.LocaleDataParts | int | +| System.Globalization.IcuLocaleDataParts | int | | System.Globalization.MonthNameStyles | int | | System.Globalization.NumberStyles | int | +| System.Globalization.StrongBidiCategory | int | | System.Globalization.TextInfo.Tristate | byte | | System.Globalization.TimeSpanFormat.StandardFormat | int | | System.Globalization.TimeSpanParse.TTT | byte | @@ -103,6 +106,7 @@ | System.Globalization.TimeSpanStyles | int | | System.Globalization.UnicodeCategory | int | | System.Guid.GuidParseThrowStyle | byte | +| System.HexConverter.Casing | uint | | System.IO.FileAccess | int | | System.IO.FileAttributes | int | | System.IO.FileMode | int | @@ -111,6 +115,7 @@ | System.IO.HandleInheritability | int | | System.IO.SeekOrigin | int | | System.LazyState | int | +| System.LoaderOptimization | int | | System.MidpointRounding | int | | System.Number.NumberBufferKind | byte | | System.Number.ParsingStatus | int | @@ -158,6 +163,7 @@ | System.Reflection.TypeAttributes | int | | System.Resources.ResourceTypeCode | int | | System.Resources.UltimateResourceFallbackLocation | int | +| System.Runtime.CompilerServices.CastHelpers.CastResult | int | | System.Runtime.CompilerServices.CompilationRelaxations | int | | System.Runtime.CompilerServices.LoadHint | int | | System.Runtime.CompilerServices.MethodCodeType | int | @@ -186,6 +192,8 @@ | System.Runtime.InteropServices.ComTypes.TYPEKIND | int | | System.Runtime.InteropServices.ComTypes.VARFLAGS | short | | System.Runtime.InteropServices.ComTypes.VARKIND | int | +| System.Runtime.InteropServices.CreateComInterfaceFlags | int | +| System.Runtime.InteropServices.CreateObjectFlags | int | | System.Runtime.InteropServices.CustomQueryInterfaceMode | int | | System.Runtime.InteropServices.CustomQueryInterfaceResult | int | | System.Runtime.InteropServices.DllImportSearchPath | int | @@ -196,20 +204,27 @@ | System.Runtime.Intrinsics.X86.FloatComparisonMode | byte | | System.Runtime.Loader.AssemblyLoadContext.InternalState | int | | System.Runtime.Serialization.StreamingContextStates | int | +| System.Runtime.Versioning.ComponentGuaranteesOptions | int | +| System.Runtime.Versioning.ResourceScope | int | +| System.Runtime.Versioning.SxSRequirements | int | | System.RuntimeType.MemberListType | int | | System.RuntimeType.RuntimeTypeCache.CacheType | int | | System.Security.PartialTrustVisibilityLevel | int | | System.Security.Permissions.PermissionState | int | +| System.Security.Permissions.SecurityAction | int | +| System.Security.Permissions.SecurityPermissionFlag | int | | System.Security.Principal.PrincipalPolicy | int | +| System.Security.Principal.TokenImpersonationLevel | int | | System.Security.SecurityCriticalScope | int | | System.Security.SecurityRuleSet | byte | -| System.String.TrimType | int | | System.StringComparison | int | | System.StringSplitOptions | int | | System.StubHelpers.AsAnyMarshaler.BackPropAction | int | | System.TermInfo.WellKnownNumbers | int | | System.TermInfo.WellKnownStrings | int | | System.Text.NormalizationForm | int | +| System.Text.TrimType | int | +| System.Text.Unicode.GraphemeClusterBreakType | int | | System.Threading.ApartmentState | int | | System.Threading.EventResetMode | int | | System.Threading.LazyThreadSafetyMode | int | @@ -218,6 +233,9 @@ | System.Threading.ReaderWriterLockSlim.EnterSpinLockReason | int | | System.Threading.ReaderWriterLockSlim.WaiterStates | byte | | System.Threading.StackCrawlMark | int | +| System.Threading.Tasks.AsyncCausalityStatus | int | +| System.Threading.Tasks.CausalityRelation | int | +| System.Threading.Tasks.CausalitySynchronousWork | int | | System.Threading.Tasks.ConcurrentExclusiveSchedulerPair.ProcessingMode | byte | | System.Threading.Tasks.InternalTaskOptions | int | | System.Threading.Tasks.Sources.ValueTaskSourceOnCompletedFlags | int | diff --git a/csharp/ql/test/library-tests/cil/functionPointers/functionPointers.expected b/csharp/ql/test/library-tests/cil/functionPointers/functionPointers.expected index 0e26dc0592c..aa33d68fd46 100644 --- a/csharp/ql/test/library-tests/cil/functionPointers/functionPointers.expected +++ b/csharp/ql/test/library-tests/cil/functionPointers/functionPointers.expected @@ -6,7 +6,9 @@ fnptr | delegate* managed | 2 | Int32 | 0 | | delegate* managed | 1 | Void* | 0 | | delegate* managed | 0 | Int32 | 0 | +| delegate* managed | 3 | void | 0 | | delegate* managed | 1 | Int32* | 0 | +| delegate* unmanaged | 2 | void | 9 | | delegate* unmanaged[StdCall] | 3 | void | 2 | params | delegate* managed | 0 | Parameter 0 of delegate* managed | !0 | @@ -18,7 +20,12 @@ params | delegate* managed | 0 | Parameter 0 of delegate* managed | Int32& | | delegate* managed | 1 | Parameter 1 of delegate* managed | Object& | | delegate* managed | 0 | Parameter 0 of delegate* managed | Int32* | +| delegate* managed | 0 | Parameter 0 of delegate* managed | IntPtr | +| delegate* managed | 1 | Parameter 1 of delegate* managed | IntPtr | +| delegate* managed | 2 | Parameter 2 of delegate* managed | IntPtr* | | delegate* managed | 0 | Parameter 0 of delegate* managed | Void* | +| delegate* unmanaged | 0 | Parameter 0 of delegate* unmanaged | Char* | +| delegate* unmanaged | 1 | Parameter 1 of delegate* unmanaged | IntPtr | | delegate* unmanaged[StdCall] | 0 | Parameter 0 of delegate* unmanaged[StdCall] | Int32& | | delegate* unmanaged[StdCall] | 1 | Parameter 1 of delegate* unmanaged[StdCall] | Object& | | delegate* unmanaged[StdCall] | 2 | Parameter 2 of delegate* unmanaged[StdCall] | !0 | diff --git a/csharp/ql/test/library-tests/cil/init-only-prop/customModifiers.expected b/csharp/ql/test/library-tests/cil/init-only-prop/customModifiers.expected index 8845c0e76f4..9017f391006 100644 --- a/csharp/ql/test/library-tests/cil/init-only-prop/customModifiers.expected +++ b/csharp/ql/test/library-tests/cil/init-only-prop/customModifiers.expected @@ -1,13 +1,10 @@ | AsRef | System.Runtime.InteropServices.InAttribute | modreq | -| BeginInvoke | System.Runtime.InteropServices.InAttribute | modreq | -| EndInvoke | System.Runtime.InteropServices.InAttribute | modreq | | EventWriteTransfer | System.Runtime.InteropServices.InAttribute | modreq | | GetPinnableReference | System.Runtime.InteropServices.InAttribute | modreq | | Invoke | System.Runtime.InteropServices.InAttribute | modreq | | Max | System.Runtime.InteropServices.InAttribute | modreq | | Min | System.Runtime.InteropServices.InAttribute | modreq | | Value | System.Runtime.CompilerServices.IsVolatile | modreq | -| _bufferedValues | System.Runtime.CompilerServices.IsVolatile | modreq | | _bufferedValuesIndex | System.Runtime.CompilerServices.IsVolatile | modreq | | _callbackPartitions | System.Runtime.CompilerServices.IsVolatile | modreq | | _canceled | System.Runtime.CompilerServices.IsVolatile | modreq | @@ -23,7 +20,6 @@ | _notifyWhenNoCallbacksRunning | System.Runtime.CompilerServices.IsVolatile | modreq | | _oldKeepAlive | System.Runtime.CompilerServices.IsVolatile | modreq | | _owner | System.Runtime.CompilerServices.IsVolatile | modreq | -| _pauseTicks | System.Runtime.CompilerServices.IsVolatile | modreq | | _previous | System.Runtime.CompilerServices.IsVolatile | modreq | | _queues | System.Runtime.CompilerServices.IsVolatile | modreq | | _saDurationFormats | System.Runtime.CompilerServices.IsVolatile | modreq | @@ -80,23 +76,21 @@ | s_DefaultThreadCurrentCulture | System.Runtime.CompilerServices.IsVolatile | modreq | | s_DefaultThreadCurrentUICulture | System.Runtime.CompilerServices.IsVolatile | modreq | | s_Invariant | System.Runtime.CompilerServices.IsVolatile | modreq | -| s_LcidCachedCultures | System.Runtime.CompilerServices.IsVolatile | modreq | -| s_NameCachedCultures | System.Runtime.CompilerServices.IsVolatile | modreq | | s_anonymouslyHostedDynamicMethodsModule | System.Runtime.CompilerServices.IsVolatile | modreq | | s_cachedCultures | System.Runtime.CompilerServices.IsVolatile | modreq | +| s_cachedCulturesByLcid | System.Runtime.CompilerServices.IsVolatile | modreq | +| s_cachedCulturesByName | System.Runtime.CompilerServices.IsVolatile | modreq | | s_cachedRegions | System.Runtime.CompilerServices.IsVolatile | modreq | | s_currentRegionInfo | System.Runtime.CompilerServices.IsVolatile | modreq | | s_defaultBinder | System.Runtime.CompilerServices.IsVolatile | modreq | | s_defaultInstance | System.Runtime.CompilerServices.IsVolatile | modreq | +| s_encoding | System.Runtime.CompilerServices.IsVolatile | modreq | +| s_haveProcessId | System.Runtime.CompilerServices.IsVolatile | modreq | | s_indentSize | System.Runtime.CompilerServices.IsVolatile | modreq | | s_initialized | System.Runtime.CompilerServices.IsVolatile | modreq | -| s_invariant | System.Runtime.CompilerServices.IsVolatile | modreq | | s_invariantInfo | System.Runtime.CompilerServices.IsVolatile | modreq | | s_jajpDTFI | System.Runtime.CompilerServices.IsVolatile | modreq | | s_japaneseEraInfo | System.Runtime.CompilerServices.IsVolatile | modreq | -| s_knownWords | System.Runtime.CompilerServices.IsVolatile | modreq | -| s_lastProcessorCountRefreshTicks | System.Runtime.CompilerServices.IsVolatile | modreq | -| s_processorCount | System.Runtime.CompilerServices.IsVolatile | modreq | | s_provider | System.Runtime.CompilerServices.IsVolatile | modreq | | s_providers | System.Runtime.CompilerServices.IsVolatile | modreq | | s_regionNames | System.Runtime.CompilerServices.IsVolatile | modreq | @@ -104,4 +98,3 @@ | s_userDefaultUICulture | System.Runtime.CompilerServices.IsVolatile | modreq | | s_zhtwDTFI | System.Runtime.CompilerServices.IsVolatile | modreq | | set_Prop2 | System.Runtime.CompilerServices.IsExternalInit | modreq | -| threadPoolInitialized | System.Runtime.CompilerServices.IsVolatile | modreq | diff --git a/csharp/ql/test/library-tests/cil/typeAnnotations/typeAnnotations.expected b/csharp/ql/test/library-tests/cil/typeAnnotations/typeAnnotations.expected index c2a2d3a76fe..24b111e695c 100644 --- a/csharp/ql/test/library-tests/cil/typeAnnotations/typeAnnotations.expected +++ b/csharp/ql/test/library-tests/cil/typeAnnotations/typeAnnotations.expected @@ -3,18 +3,25 @@ | As | method | 32 | | AsMutable | method | 32 | | AsRef | method | 32 | +| Element | method | 32 | +| FindValue | method | 32 | +| GetArrayDataReference | method | 32 | +| GetBucket | method | 32 | +| GetBucketRef | method | 32 | +| GetMultiDimensionalArrayBounds | method | 32 | | GetNonNullPinnableReference | method | 32 | | GetPinnableReference | method | 32 | | GetRawArrayData | method | 32 | -| GetRawArrayGeometry | method | 32 | | GetRawData | method | 32 | | GetRawStringData | method | 32 | -| GetRawSzArrayData | method | 32 | | GetReference | method | 32 | -| Local variable 0 of method g__SoftwareFallback\|66_0 | local | 32 | +| LdelemaRef | method | 32 | +| Local variable 0 of method g__SoftwareFallback\|68_0 | local | 32 | | Local variable 0 of method Add | local | 32 | | Local variable 0 of method Clear | local | 32 | -| Local variable 0 of method EnumCalendarInfoCallback | local | 32 | +| Local variable 0 of method CompareTo | local | 32 | +| Local variable 0 of method Contains | local | 32 | +| Local variable 0 of method FindValue | local | 32 | | Local variable 0 of method GetElement | local | 32 | | Local variable 0 of method GetHashCode | local | 32 | | Local variable 0 of method GetPinnableReference | local | 32 | @@ -24,18 +31,21 @@ | Local variable 0 of method Memmove | local | 32 | | Local variable 0 of method MoveNext | local | 32 | | Local variable 0 of method Multiply | local | 32 | +| Local variable 0 of method PickPivotAndPartition | local | 32 | +| Local variable 0 of method Remove | local | 32 | | Local variable 0 of method RemoveIndex | local | 32 | | Local variable 0 of method Reverse | local | 32 | | Local variable 0 of method RunOrScheduleAction | local | 32 | +| Local variable 0 of method SwapIfGreaterWithValues | local | 32 | | Local variable 0 of method ToUInt64 | local | 32 | | Local variable 0 of method TryDecodeFromUtf16 | local | 32 | +| Local variable 0 of method TryGetValue | local | 32 | | Local variable 0 of method TryParseExactD | local | 32 | | Local variable 0 of method TryParseExactN | local | 32 | | Local variable 0 of method ValueToHexString | local | 32 | | Local variable 0 of method ValueToString | local | 32 | +| Local variable 0 of method get_Item | local | 32 | | Local variable 1 of method .ctor | local | 32 | -| Local variable 1 of method g__SoftwareFallback\|32_0 | local | 32 | -| Local variable 1 of method g__SoftwareFallback\|33_0 | local | 32 | | Local variable 1 of method g__SoftwareFallback\|34_0 | local | 32 | | Local variable 1 of method g__SoftwareFallback\|35_0 | local | 32 | | Local variable 1 of method g__SoftwareFallback\|36_0 | local | 32 | @@ -44,20 +54,30 @@ | Local variable 1 of method g__SoftwareFallback\|39_0 | local | 32 | | Local variable 1 of method g__SoftwareFallback\|40_0 | local | 32 | | Local variable 1 of method g__SoftwareFallback\|41_0 | local | 32 | -| Local variable 1 of method b__32_0 | local | 32 | -| Local variable 1 of method b__113_0 | local | 32 | -| Local variable 1 of method g__SoftwareFallback\|67_0 | local | 32 | +| Local variable 1 of method g__SoftwareFallback\|42_0 | local | 32 | +| Local variable 1 of method g__SoftwareFallback\|43_0 | local | 32 | +| Local variable 1 of method g__SoftwareFallback\|44_0 | local | 32 | +| Local variable 1 of method g__SoftwareFallback\|45_0 | local | 32 | +| Local variable 1 of method g__SoftwareFallback\|46_0 | local | 32 | +| Local variable 1 of method g__SoftwareFallback\|47_0 | local | 32 | +| Local variable 1 of method g__SoftwareFallback\|48_0 | local | 32 | +| Local variable 1 of method g__SoftwareFallback\|49_0 | local | 32 | +| Local variable 1 of method b__33_0 | local | 32 | +| Local variable 1 of method b__158_0 | local | 32 | +| Local variable 1 of method b__158_1 | local | 32 | +| Local variable 1 of method g__SoftwareFallback\|69_0 | local | 32 | +| Local variable 1 of method g__SoftwareFallback\|75_0 | local | 32 | | Local variable 1 of method Add | local | 32 | | Local variable 1 of method Append | local | 32 | | Local variable 1 of method AppendHelper | local | 32 | | Local variable 1 of method AppendJoin | local | 32 | -| Local variable 1 of method CompareString | local | 32 | -| Local variable 1 of method CompareStringOrdinalIgnoreCase | local | 32 | +| Local variable 1 of method CompareIgnoreCaseInvariantMode | local | 32 | +| Local variable 1 of method CompareStringIgnoreCase | local | 32 | +| Local variable 1 of method CompareTo | local | 32 | | Local variable 1 of method Convert | local | 32 | -| Local variable 1 of method Create | local | 32 | | Local variable 1 of method CreateActivityPathGuid | local | 32 | -| Local variable 1 of method EndsWith | local | 32 | -| Local variable 1 of method FillStringChecked | local | 32 | +| Local variable 1 of method EnumCalendarInfoCallback | local | 32 | +| Local variable 1 of method FindValue | local | 32 | | Local variable 1 of method FromBase64CharArray | local | 32 | | Local variable 1 of method FromBase64String | local | 32 | | Local variable 1 of method FromUtf16 | local | 32 | @@ -67,6 +87,7 @@ | Local variable 1 of method GetBytes | local | 32 | | Local variable 1 of method GetBytesFromEncoding | local | 32 | | Local variable 1 of method GetBytesWithFallback | local | 32 | +| Local variable 1 of method GetCategoryCasingTableOffsetNoBoundsChecks | local | 32 | | Local variable 1 of method GetCharCount | local | 32 | | Local variable 1 of method GetCharCountWithFallback | local | 32 | | Local variable 1 of method GetChars | local | 32 | @@ -74,32 +95,39 @@ | Local variable 1 of method GetEnvironmentVariable | local | 32 | | Local variable 1 of method GetHashCode | local | 32 | | Local variable 1 of method GetNonRandomizedHashCode | local | 32 | +| Local variable 1 of method GetNumericGraphemeTableOffsetNoBoundsChecks | local | 32 | +| Local variable 1 of method GetNumericValueNoBoundsCheck | local | 32 | | Local variable 1 of method GetString | local | 32 | | Local variable 1 of method GetUnicode | local | 32 | +| Local variable 1 of method GetUpperBound | local | 32 | +| Local variable 1 of method IcuCompareString | local | 32 | +| Local variable 1 of method IcuEndsWith | local | 32 | +| Local variable 1 of method IcuGetSortKeyLength | local | 32 | +| Local variable 1 of method IcuIndexOfCore | local | 32 | +| Local variable 1 of method IcuStartsWith | local | 32 | | Local variable 1 of method IndexOf | local | 32 | -| Local variable 1 of method IndexOfCore | local | 32 | | Local variable 1 of method IndexOfOrdinalHelper | local | 32 | | Local variable 1 of method IndexOfOrdinalIgnoreCaseHelper | local | 32 | | Local variable 1 of method Insert | local | 32 | | Local variable 1 of method InternalCopy | local | 32 | | Local variable 1 of method InvariantIndexOf | local | 32 | -| Local variable 1 of method InvariantLastIndexOf | local | 32 | | Local variable 1 of method IsAscii | local | 32 | -| Local variable 1 of method IsSortable | local | 32 | | Local variable 1 of method Join | local | 32 | | Local variable 1 of method LastIndexOf | local | 32 | | Local variable 1 of method MatchChars | local | 32 | | Local variable 1 of method Memmove | local | 32 | +| Local variable 1 of method PickPivotAndPartition | local | 32 | | Local variable 1 of method Pow10 | local | 32 | | Local variable 1 of method ReplaceAllInChunk | local | 32 | | Local variable 1 of method Reverse | local | 32 | -| Local variable 1 of method StartsWith | local | 32 | | Local variable 1 of method TZif_ToInt32 | local | 32 | | Local variable 1 of method TZif_ToInt64 | local | 32 | | Local variable 1 of method ThreadSafeCopy | local | 32 | | Local variable 1 of method ToLowerAsciiInvariant | local | 32 | +| Local variable 1 of method ToString | local | 32 | | Local variable 1 of method ToUpperAsciiInvariant | local | 32 | | Local variable 1 of method ToUtf16 | local | 32 | +| Local variable 1 of method TraceOperationBegin | local | 32 | | Local variable 1 of method Trim | local | 32 | | Local variable 1 of method TrimEnd | local | 32 | | Local variable 1 of method TrimStart | local | 32 | @@ -107,7 +135,6 @@ | Local variable 1 of method TryStringToNumber | local | 32 | | Local variable 1 of method WaitMultipleIgnoringSyncContext | local | 32 | | Local variable 1 of method WithElement | local | 32 | -| Local variable 1 of method WithUpper | local | 32 | | Local variable 1 of method WriteEvent | local | 32 | | Local variable 1 of method WriteImpl | local | 32 | | Local variable 1 of method WriteMultiMerge | local | 32 | @@ -115,29 +142,33 @@ | Local variable 1 of method get_Item | local | 32 | | Local variable 2 of method .ctor | local | 32 | | Local variable 2 of method ChangeCaseCommon | local | 32 | +| Local variable 2 of method CompareIgnoreCaseInvariantMode | local | 32 | | Local variable 2 of method CompareOrdinalHelper | local | 32 | -| Local variable 2 of method CompareOrdinalIgnoreCase | local | 32 | +| Local variable 2 of method CompareStringIgnoreCase | local | 32 | +| Local variable 2 of method Copy | local | 32 | | Local variable 2 of method CopyTo | local | 32 | -| Local variable 2 of method CreateSortKey | local | 32 | | Local variable 2 of method Ctor | local | 32 | +| Local variable 2 of method Decompose | local | 32 | | Local variable 2 of method DoAnsiConversion | local | 32 | | Local variable 2 of method EndsWithOrdinalHelper | local | 32 | | Local variable 2 of method EndsWithOrdinalIgnoreCaseHelper | local | 32 | | Local variable 2 of method EqualStartingCharacterCount | local | 32 | +| Local variable 2 of method GenerateMetadataForNamedTypeV2 | local | 32 | | Local variable 2 of method GetByteCount | local | 32 | | Local variable 2 of method GetBytes | local | 32 | | Local variable 2 of method GetChars | local | 32 | | Local variable 2 of method GetValue | local | 32 | -| Local variable 2 of method IndexOfCore | local | 32 | -| Local variable 2 of method IndexOfOrdinalCore | local | 32 | +| Local variable 2 of method IcuCreateSortKey | local | 32 | +| Local variable 2 of method IcuGetSortKey | local | 32 | +| Local variable 2 of method IcuIsNormalized | local | 32 | | Local variable 2 of method Insert | local | 32 | -| Local variable 2 of method InternalGetNumericValue | local | 32 | -| Local variable 2 of method InternalSubString | local | 32 | -| Local variable 2 of method InvariantCreateSortKey | local | 32 | -| Local variable 2 of method LastIndexOfCore | local | 32 | -| Local variable 2 of method LastIndexOfOrdinalCore | local | 32 | +| Local variable 2 of method IntersectWithHashSetWithSameComparer | local | 32 | +| Local variable 2 of method IntroSort | local | 32 | +| Local variable 2 of method MemberwiseClone | local | 32 | | Local variable 2 of method Multiply | local | 32 | +| Local variable 2 of method PickPivotAndPartition | local | 32 | | Local variable 2 of method ReadNative | local | 32 | +| Local variable 2 of method Remove | local | 32 | | Local variable 2 of method SetValue | local | 32 | | Local variable 2 of method StartsWithOrdinalHelper | local | 32 | | Local variable 2 of method StartsWithOrdinalIgnoreCaseHelper | local | 32 | @@ -149,47 +180,51 @@ | Local variable 2 of method TryUInt32ToDecStr | local | 32 | | Local variable 2 of method TryUInt64ToDecStr | local | 32 | | Local variable 2 of method Write | local | 32 | +| Local variable 3 of method b__29_0 | local | 32 | +| Local variable 3 of method b__30_0 | local | 32 | | Local variable 3 of method AddCustomAttributes | local | 32 | -| Local variable 3 of method CompareOrdinalIgnoreCase | local | 32 | -| Local variable 3 of method CompareString | local | 32 | -| Local variable 3 of method CompareStringOrdinalIgnoreCase | local | 32 | +| Local variable 3 of method CompareStringIgnoreCase | local | 32 | | Local variable 3 of method Convert | local | 32 | | Local variable 3 of method Copy | local | 32 | | Local variable 3 of method CreateInstance | local | 32 | | Local variable 3 of method CreateStringFromEncoding | local | 32 | -| Local variable 3 of method Ctor | local | 32 | -| Local variable 3 of method EndsWith | local | 32 | +| Local variable 3 of method Enable | local | 32 | | Local variable 3 of method Fill | local | 32 | -| Local variable 3 of method FillStringChecked | local | 32 | | Local variable 3 of method FindSection | local | 32 | | Local variable 3 of method FromUtf16 | local | 32 | | Local variable 3 of method GetBytes | local | 32 | | Local variable 3 of method GetBytesWithFallback | local | 32 | | Local variable 3 of method GetChars | local | 32 | | Local variable 3 of method GetCharsWithFallback | local | 32 | +| Local variable 3 of method GetNonRandomizedHashCodeOrdinalIgnoreCase | local | 32 | +| Local variable 3 of method IcuCompareString | local | 32 | +| Local variable 3 of method IcuEndsWith | local | 32 | +| Local variable 3 of method IcuIndexOfCore | local | 32 | +| Local variable 3 of method IcuStartsWith | local | 32 | +| Local variable 3 of method IndexOf | local | 32 | | Local variable 3 of method IndexOfCharArray | local | 32 | -| Local variable 3 of method IndexOfCore | local | 32 | | Local variable 3 of method IndexOfOrdinalHelper | local | 32 | | Local variable 3 of method IndexOfOrdinalIgnoreCaseHelper | local | 32 | | Local variable 3 of method Int32ToHexStr | local | 32 | | Local variable 3 of method Int64ToHexStr | local | 32 | | Local variable 3 of method InternalLoad | local | 32 | +| Local variable 3 of method IntroSort | local | 32 | | Local variable 3 of method InvariantIndexOf | local | 32 | -| Local variable 3 of method InvariantLastIndexOf | local | 32 | | Local variable 3 of method JoinInternal | local | 32 | +| Local variable 3 of method LastIndexOf | local | 32 | | Local variable 3 of method LastIndexOfCharArray | local | 32 | +| Local variable 3 of method MemberwiseClone | local | 32 | | Local variable 3 of method NegativeInt32ToDecStr | local | 32 | +| Local variable 3 of method PickPivotAndPartition | local | 32 | | Local variable 3 of method Pin | local | 32 | | Local variable 3 of method Populate | local | 32 | | Local variable 3 of method Pow10 | local | 32 | -| Local variable 3 of method Replace | local | 32 | +| Local variable 3 of method RemoveWhere | local | 32 | | Local variable 3 of method Resize | local | 32 | -| Local variable 3 of method StartsWith | local | 32 | | Local variable 3 of method StringToCoTaskMemUni | local | 32 | | Local variable 3 of method StringToHGlobalUni | local | 32 | | Local variable 3 of method ThreadSafeCopy | local | 32 | | Local variable 3 of method ToBase64String | local | 32 | -| Local variable 3 of method ToCharArray | local | 32 | | Local variable 3 of method ToString | local | 32 | | Local variable 3 of method ToUtf16 | local | 32 | | Local variable 3 of method TryNegativeInt64ToDecStr | local | 32 | @@ -199,12 +234,14 @@ | Local variable 3 of method Write | local | 32 | | Local variable 3 of method WriteEvent | local | 32 | | Local variable 3 of method WriteStdoutAnsiString | local | 32 | -| Local variable 3 of method get_Item | local | 32 | | Local variable 4 of method .ctor | local | 32 | | Local variable 4 of method AddDivisor | local | 32 | +| Local variable 4 of method AddIfNotPresent | local | 32 | | Local variable 4 of method AddNullTerminatedString | local | 32 | +| Local variable 4 of method Append | local | 32 | | Local variable 4 of method ChangeCaseCommon | local | 32 | | Local variable 4 of method CompareOrdinalHelper | local | 32 | +| Local variable 4 of method ConstructFrom | local | 32 | | Local variable 4 of method Copy | local | 32 | | Local variable 4 of method EndsWithOrdinalHelper | local | 32 | | Local variable 4 of method EndsWithOrdinalIgnoreCaseHelper | local | 32 | @@ -212,30 +249,32 @@ | Local variable 4 of method EscapeString | local | 32 | | Local variable 4 of method FormatPrintF | local | 32 | | Local variable 4 of method GetBytes | local | 32 | +| Local variable 4 of method GetBytesForSmallInput | local | 32 | | Local variable 4 of method GetChars | local | 32 | | Local variable 4 of method GetMessage | local | 32 | -| Local variable 4 of method GetUnicodeCore | local | 32 | -| Local variable 4 of method IndexOfCore | local | 32 | -| Local variable 4 of method IndexOfOrdinalCore | local | 32 | +| Local variable 4 of method IcuGetSortKey | local | 32 | +| Local variable 4 of method IcuGetUnicodeCore | local | 32 | | Local variable 4 of method InternalLoad | local | 32 | -| Local variable 4 of method InternalSubString | local | 32 | +| Local variable 4 of method IntroSort | local | 32 | | Local variable 4 of method JoinInternal | local | 32 | -| Local variable 4 of method LastIndexOfCore | local | 32 | | Local variable 4 of method MakeRoom | local | 32 | | Local variable 4 of method NegativeInt64ToDecStr | local | 32 | | Local variable 4 of method PadLeft | local | 32 | | Local variable 4 of method PadRight | local | 32 | | Local variable 4 of method Remove | local | 32 | +| Local variable 4 of method Replace | local | 32 | +| Local variable 4 of method Resize | local | 32 | | Local variable 4 of method StartsWithOrdinalHelper | local | 32 | | Local variable 4 of method StartsWithOrdinalIgnoreCaseHelper | local | 32 | -| Local variable 4 of method ToCharArray | local | 32 | | Local variable 4 of method TryInsert | local | 32 | | Local variable 4 of method Write | local | 32 | | Local variable 4 of method WriteCore | local | 32 | | Local variable 4 of method WriteEvent | local | 32 | -| Local variable 5 of method Append | local | 32 | +| Local variable 5 of method Clear | local | 32 | | Local variable 5 of method ConvertToNative | local | 32 | +| Local variable 5 of method Copy | local | 32 | | Local variable 5 of method CreateInstance | local | 32 | +| Local variable 5 of method Enable | local | 32 | | Local variable 5 of method GetAttributeUsage | local | 32 | | Local variable 5 of method GetBytes | local | 32 | | Local variable 5 of method GetBytesWithFallback | local | 32 | @@ -244,11 +283,13 @@ | Local variable 5 of method GetHomeDirectory | local | 32 | | Local variable 5 of method Insert | local | 32 | | Local variable 5 of method JoinInternal | local | 32 | +| Local variable 5 of method PickPivotAndPartition | local | 32 | | Local variable 5 of method Pow10 | local | 32 | | Local variable 5 of method Read | local | 32 | | Local variable 5 of method ReadArray | local | 32 | | Local variable 5 of method ReadCore | local | 32 | | Local variable 5 of method Replace | local | 32 | +| Local variable 5 of method Resize | local | 32 | | Local variable 5 of method StringToCoTaskMemUTF8 | local | 32 | | Local variable 5 of method StringToHGlobalUTF8 | local | 32 | | Local variable 5 of method SubtractDivisor | local | 32 | @@ -258,111 +299,101 @@ | Local variable 5 of method TryToBase64Chars | local | 32 | | Local variable 5 of method WriteArray | local | 32 | | Local variable 5 of method WriteEvent | local | 32 | -| Local variable 5 of method get_Item | local | 32 | +| Local variable 5 of method WriteWhenEncodingIsNotUtf8 | local | 32 | | Local variable 5 of method get_UserName | local | 32 | -| Local variable 6 of method .ctor | local | 32 | -| Local variable 6 of method Clear | local | 32 | +| Local variable 6 of method Append | local | 32 | +| Local variable 6 of method ConvertFixedToManaged | local | 32 | | Local variable 6 of method ConvertToBase64Array | local | 32 | +| Local variable 6 of method ConvertToNative | local | 32 | +| Local variable 6 of method Copy | local | 32 | +| Local variable 6 of method FindItemIndex | local | 32 | | Local variable 6 of method GenerateMetadataForProperty | local | 32 | -| Local variable 6 of method GetAsciiCore | local | 32 | -| Local variable 6 of method IndexOfOrdinalCore | local | 32 | +| Local variable 6 of method IcuGetAsciiCore | local | 32 | | Local variable 6 of method InternalCopy | local | 32 | | Local variable 6 of method JoinInternal | local | 32 | | Local variable 6 of method PadRight | local | 32 | +| Local variable 6 of method PickPivotAndPartition | local | 32 | | Local variable 6 of method Remove | local | 32 | -| Local variable 6 of method Replace | local | 32 | | Local variable 6 of method Resize | local | 32 | | Local variable 6 of method SetConstantValue | local | 32 | | Local variable 6 of method ToBase64CharArray | local | 32 | | Local variable 6 of method TryDecodeFromUtf16 | local | 32 | | Local variable 6 of method TryFormat | local | 32 | -| Local variable 6 of method Write | local | 32 | | Local variable 7 of method .ctor | local | 32 | -| Local variable 7 of method Append | local | 32 | +| Local variable 7 of method AddIfNotPresent | local | 32 | +| Local variable 7 of method ConvertFixedToNative | local | 32 | | Local variable 7 of method GenerateMetadata | local | 32 | | Local variable 7 of method GetBytesWithFallback | local | 32 | | Local variable 7 of method GetCharsWithFallback | local | 32 | -| Local variable 7 of method GetHashCodeOfStringCore | local | 32 | +| Local variable 7 of method IcuGetHashCodeOfString | local | 32 | +| Local variable 7 of method IcuNormalize | local | 32 | | Local variable 7 of method Insert | local | 32 | | Local variable 7 of method JoinInternal | local | 32 | | Local variable 7 of method PadLeft | local | 32 | | Local variable 7 of method Populate | local | 32 | | Local variable 7 of method Pow10 | local | 32 | -| Local variable 7 of method Remove | local | 32 | | Local variable 7 of method Resize | local | 32 | -| Local variable 7 of method WriteEventString | local | 32 | -| Local variable 7 of method get_Item | local | 32 | +| Local variable 7 of method TryInsert | local | 32 | +| Local variable 7 of method WriteWhenEncodingIsNotUtf8 | local | 32 | | Local variable 8 of method JoinInternal | local | 32 | | Local variable 8 of method Pow10 | local | 32 | -| Local variable 8 of method Replace | local | 32 | | Local variable 8 of method SetConstantValue | local | 32 | | Local variable 8 of method ToBase64CharArray | local | 32 | | Local variable 8 of method ToString | local | 32 | -| Local variable 8 of method TryInsert | local | 32 | -| Local variable 8 of method Write | local | 32 | +| Local variable 8 of method TrimExcess | local | 32 | +| Local variable 8 of method WriteEventString | local | 32 | +| Local variable 9 of method g__GetNonRandomizedHashCodeOrdinalIgnoreCaseSlow\|52_0 | local | 32 | +| Local variable 9 of method AddIfNotPresent | local | 32 | +| Local variable 9 of method Enable | local | 32 | +| Local variable 9 of method FindItemIndex | local | 32 | | Local variable 9 of method GenerateMetadataForProperty | local | 32 | -| Local variable 9 of method GetHashCodeOfStringCore | local | 32 | +| Local variable 9 of method IcuGetHashCodeOfString | local | 32 | +| Local variable 9 of method IcuNormalize | local | 32 | | Local variable 9 of method Insert | local | 32 | +| Local variable 9 of method IntersectWithEnumerable | local | 32 | | Local variable 9 of method JoinInternal | local | 32 | | Local variable 9 of method TrimExcess | local | 32 | -| Local variable 9 of method get_Item | local | 32 | | Local variable 10 of method .ctor | local | 32 | | Local variable 10 of method FormatFixed | local | 32 | | Local variable 10 of method IntToString | local | 32 | | Local variable 10 of method JoinInternal | local | 32 | | Local variable 10 of method LongToString | local | 32 | | Local variable 10 of method ReplaceAllInChunk | local | 32 | -| Local variable 11 of method GenerateMetadata | local | 32 | -| Local variable 11 of method GetHashCodeOfStringCore | local | 32 | -| Local variable 11 of method InternalReadChars | local | 32 | +| Local variable 10 of method TrimExcess | local | 32 | +| Local variable 11 of method AddIfNotPresent | local | 32 | +| Local variable 11 of method IcuGetHashCodeOfString | local | 32 | | Local variable 11 of method Resize | local | 32 | -| Local variable 11 of method get_Item | local | 32 | +| Local variable 12 of method FindItemIndex | local | 32 | | Local variable 12 of method JoinCore | local | 32 | | Local variable 13 of method .ctor | local | 32 | +| Local variable 13 of method AddIfNotPresent | local | 32 | | Local variable 13 of method ChangeCaseCommon | local | 32 | -| Local variable 13 of method get_Item | local | 32 | -| Local variable 14 of method .ctor | local | 32 | | Local variable 14 of method Resize | local | 32 | -| Local variable 15 of method get_Item | local | 32 | | Local variable 16 of method .ctor | local | 32 | -| Local variable 17 of method get_Item | local | 32 | -| Local variable 18 of method .ctor | local | 32 | | Local variable 19 of method .ctor | local | 32 | | Local variable 19 of method NumberToStringFormat | local | 32 | -| Local variable 19 of method get_Item | local | 32 | +| Local variable 21 of method GenerateMetadata | local | 32 | | Local variable 22 of method .ctor | local | 32 | | Local variable 23 of method WriteEvent | local | 32 | | Local variable 24 of method WriteEvent | local | 32 | | Local variable 25 of method .ctor | local | 32 | | Local variable 25 of method WriteEvent | local | 32 | -| Local variable 26 of method .ctor | local | 32 | | Local variable 26 of method WriteEvent | local | 32 | | Local variable 27 of method WriteEvent | local | 32 | | Local variable 28 of method .ctor | local | 32 | | Local variable 28 of method WriteEvent | local | 32 | | Local variable 29 of method WriteEvent | local | 32 | -| Local variable 30 of method .ctor | local | 32 | +| Local variable 30 of method g__SseImpl\|59_0 | local | 32 | | Local variable 30 of method WriteEvent | local | 32 | -| Local variable 31 of method .ctor | local | 32 | | Local variable 31 of method NumberToStringFormat | local | 32 | -| Local variable 33 of method .ctor | local | 32 | -| Local variable 34 of method .ctor | local | 32 | | Local variable 34 of method WriteEvent | local | 32 | -| Local variable 35 of method .ctor | local | 32 | -| Local variable 37 of method .ctor | local | 32 | -| Local variable 38 of method .ctor | local | 32 | -| Local variable 39 of method .ctor | local | 32 | -| Local variable 41 of method .ctor | local | 32 | -| Local variable 43 of method .ctor | local | 32 | -| Local variable 45 of method .ctor | local | 32 | -| Local variable 47 of method .ctor | local | 32 | -| Local variable 49 of method .ctor | local | 32 | | Max | method | 32 | | Min | method | 32 | -| Parameter 0 of g__SoftwareFallback\|10_0 | parameter | 32 | +| NullRef | method | 32 | | Parameter 0 of g__SoftwareFallback\|12_0 | parameter | 32 | -| Parameter 0 of g__IncrementX\|115_1 | parameter | 32 | -| Parameter 0 of g__IncrementY\|115_0 | parameter | 32 | +| Parameter 0 of g__SoftwareFallback\|14_0 | parameter | 32 | +| Parameter 0 of g__IncrementX\|112_1 | parameter | 32 | +| Parameter 0 of g__IncrementY\|112_0 | parameter | 32 | | Parameter 0 of Abs | parameter | 32 | | Parameter 0 of AccumulateDecimalDigitsIntoBigInteger | parameter | 32 | | Parameter 0 of Add | parameter | 32 | @@ -378,6 +409,7 @@ | Parameter 0 of AdjustHour | parameter | 32 | | Parameter 0 of AdjustTimeZoneToLocal | parameter | 32 | | Parameter 0 of AdjustTimeZoneToUniversal | parameter | 32 | +| Parameter 0 of And | parameter | 32 | | Parameter 0 of AppendParameters | parameter | 32 | | Parameter 0 of AreSame | parameter | 32 | | Parameter 0 of As | parameter | 32 | @@ -385,8 +417,11 @@ | Parameter 0 of AsPointer | parameter | 32 | | Parameter 0 of AsRef | parameter | 32 | | Parameter 0 of AssembleFloatingPointBits | parameter | 32 | +| Parameter 0 of AwaitOnCompleted | parameter | 32 | +| Parameter 0 of AwaitUnsafeOnCompleted | parameter | 32 | | Parameter 0 of BinarySearch | parameter | 32 | | Parameter 0 of Block | parameter | 32 | +| Parameter 0 of BulkMoveWithWriteBarrier | parameter | 32 | | Parameter 0 of ByteOffset | parameter | 32 | | Parameter 0 of CheckDefaultDateTime | parameter | 32 | | Parameter 0 of CheckForAvailableMemory | parameter | 32 | @@ -396,8 +431,9 @@ | Parameter 0 of ClearWithoutReferences | parameter | 32 | | Parameter 0 of Compare | parameter | 32 | | Parameter 0 of CompareExchange | parameter | 32 | -| Parameter 0 of CompareOrdinalIgnoreCase | parameter | 32 | -| Parameter 0 of CompareStringOrdinalIgnoreCase | parameter | 32 | +| Parameter 0 of CompareIgnoreCaseInvariantMode | parameter | 32 | +| Parameter 0 of CompareStringIgnoreCase | parameter | 32 | +| Parameter 0 of CompareStringIgnoreCaseNonAscii | parameter | 32 | | Parameter 0 of ComputeHash32 | parameter | 32 | | Parameter 0 of ComputeHash32OrdinalIgnoreCase | parameter | 32 | | Parameter 0 of ComputeHash32OrdinalIgnoreCaseSlow | parameter | 32 | @@ -406,6 +442,7 @@ | Parameter 0 of Contains | parameter | 32 | | Parameter 0 of ConvertBigIntegerToFloatingPointBits | parameter | 32 | | Parameter 0 of CountSignificantBits | parameter | 32 | +| Parameter 0 of Create | parameter | 32 | | Parameter 0 of CreateReadOnlySpan | parameter | 32 | | Parameter 0 of CreateSpan | parameter | 32 | | Parameter 0 of DateTimeOffsetTimeZonePostProcessing | parameter | 32 | @@ -423,12 +460,12 @@ | Parameter 0 of Div96ByConst | parameter | 32 | | Parameter 0 of Div128By96 | parameter | 32 | | Parameter 0 of DivRem | parameter | 32 | +| Parameter 0 of Element | parameter | 32 | | Parameter 0 of EncodeObject | parameter | 32 | | Parameter 0 of EnsureInitialized | parameter | 32 | | Parameter 0 of EnsureInitializedCore | parameter | 32 | | Parameter 0 of EnsureLockInitialized | parameter | 32 | -| Parameter 0 of EqualsOrdinalIgnoreCase | parameter | 32 | -| Parameter 0 of EqualsOrdinalIgnoreCaseNonAscii | parameter | 32 | +| Parameter 0 of EqualsIgnoreCase | parameter | 32 | | Parameter 0 of Exchange | parameter | 32 | | Parameter 0 of ExchangeAdd | parameter | 32 | | Parameter 0 of FormatCurrency | parameter | 32 | @@ -436,6 +473,7 @@ | Parameter 0 of FormatExponent | parameter | 32 | | Parameter 0 of FormatFixed | parameter | 32 | | Parameter 0 of FormatGeneral | parameter | 32 | +| Parameter 0 of FormatHalf | parameter | 32 | | Parameter 0 of FormatNumber | parameter | 32 | | Parameter 0 of FormatPercent | parameter | 32 | | Parameter 0 of FormatScientific | parameter | 32 | @@ -466,18 +504,13 @@ | Parameter 0 of GetExecutingAssembly | parameter | 32 | | Parameter 0 of GetHashCode | parameter | 32 | | Parameter 0 of GetHebrewDayOfNM | parameter | 32 | +| Parameter 0 of GetIUnknownImpl | parameter | 32 | | Parameter 0 of GetMaxThreads | parameter | 32 | | Parameter 0 of GetMaxThreadsNative | parameter | 32 | -| Parameter 0 of GetMemoryInfo | parameter | 32 | | Parameter 0 of GetMinThreads | parameter | 32 | | Parameter 0 of GetMinThreadsNative | parameter | 32 | | Parameter 0 of GetNextIntroducedMethod | parameter | 32 | -| Parameter 0 of GetObjectHandleOnStack | parameter | 32 | -| Parameter 0 of GetQCallAssemblyOnStack | parameter | 32 | -| Parameter 0 of GetQCallModuleOnStack | parameter | 32 | -| Parameter 0 of GetQCallTypeHandleOnStack | parameter | 32 | -| Parameter 0 of GetStackCrawlMarkHandle | parameter | 32 | -| Parameter 0 of GetStringHandleOnStack | parameter | 32 | +| Parameter 0 of GetStateMachineBox | parameter | 32 | | Parameter 0 of GetSymbolOrDefault | parameter | 32 | | Parameter 0 of GetThreadDeserializationTracker | parameter | 32 | | Parameter 0 of GetTimeOfN | parameter | 32 | @@ -485,7 +518,10 @@ | Parameter 0 of GetTimeOfNNN | parameter | 32 | | Parameter 0 of GetTimeZoneName | parameter | 32 | | Parameter 0 of GetWindowSize | parameter | 32 | +| Parameter 0 of GreaterThan | parameter | 32 | +| Parameter 0 of GrowTable | parameter | 32 | | Parameter 0 of HandleTimeZone | parameter | 32 | +| Parameter 0 of HashShift | parameter | 32 | | Parameter 0 of HeuristicDivide | parameter | 32 | | Parameter 0 of IncreaseScale | parameter | 32 | | Parameter 0 of IncreaseScale64 | parameter | 32 | @@ -494,16 +530,21 @@ | Parameter 0 of IndexOfAny | parameter | 32 | | Parameter 0 of InitBlockUnaligned | parameter | 32 | | Parameter 0 of Initialize | parameter | 32 | -| Parameter 0 of InitializeVMTp | parameter | 32 | | Parameter 0 of Int64DivMod1E9 | parameter | 32 | | Parameter 0 of InternalGetCurrentMethod | parameter | 32 | | Parameter 0 of InternalRound | parameter | 32 | | Parameter 0 of IsAddressGreaterThan | parameter | 32 | | Parameter 0 of IsAddressLessThan | parameter | 32 | +| Parameter 0 of IsNullRef | parameter | 32 | | Parameter 0 of IsUtf8ContinuationByte | parameter | 32 | +| Parameter 0 of KeepAliveViaCleanupList | parameter | 32 | +| Parameter 0 of KeyToBucket | parameter | 32 | | Parameter 0 of LastIndexOf | parameter | 32 | | Parameter 0 of LastIndexOfAny | parameter | 32 | -| Parameter 0 of LoadUIntPtr | parameter | 32 | +| Parameter 0 of LessThan | parameter | 32 | +| Parameter 0 of LoadNUInt | parameter | 32 | +| Parameter 0 of LoadUInt | parameter | 32 | +| Parameter 0 of LoadUShort | parameter | 32 | | Parameter 0 of LoadVector | parameter | 32 | | Parameter 0 of LoadVector128 | parameter | 32 | | Parameter 0 of LoadVector256 | parameter | 32 | @@ -521,13 +562,17 @@ | Parameter 0 of Min | parameter | 32 | | Parameter 0 of Multiply | parameter | 32 | | Parameter 0 of NarrowFourUtf16CharsToAsciiAndWriteToBuffer | parameter | 32 | +| Parameter 0 of NarrowFourUtf16CharsToLatin1AndWriteToBuffer | parameter | 32 | | Parameter 0 of NarrowTwoUtf16CharsToAsciiAndWriteToBuffer | parameter | 32 | +| Parameter 0 of NarrowTwoUtf16CharsToLatin1AndWriteToBuffer | parameter | 32 | | Parameter 0 of NumberToDouble | parameter | 32 | | Parameter 0 of NumberToFloatingPointBits | parameter | 32 | | Parameter 0 of NumberToFloatingPointBitsSlow | parameter | 32 | +| Parameter 0 of NumberToHalf | parameter | 32 | | Parameter 0 of NumberToSingle | parameter | 32 | | Parameter 0 of NumberToString | parameter | 32 | | Parameter 0 of NumberToStringFormat | parameter | 32 | +| Parameter 0 of Or | parameter | 32 | | Parameter 0 of OverflowUnscale | parameter | 32 | | Parameter 0 of ParseByFormat | parameter | 32 | | Parameter 0 of ParseDigits | parameter | 32 | @@ -552,8 +597,6 @@ | Parameter 0 of RefreshColors | parameter | 32 | | Parameter 0 of RemoveFirstArgIfRelatedActivityId | parameter | 32 | | Parameter 0 of Resize | parameter | 32 | -| Parameter 0 of RhBulkMoveWithWriteBarrier | parameter | 32 | -| Parameter 0 of RhZeroMemory | parameter | 32 | | Parameter 0 of Round | parameter | 32 | | Parameter 0 of RoundNumber | parameter | 32 | | Parameter 0 of SearchScale | parameter | 32 | @@ -563,11 +606,23 @@ | Parameter 0 of SetDateMDY | parameter | 32 | | Parameter 0 of SetDateYDM | parameter | 32 | | Parameter 0 of SetDateYMD | parameter | 32 | +| Parameter 0 of SetUInt32 | parameter | 32 | +| Parameter 0 of SetUInt64 | parameter | 32 | +| Parameter 0 of SetValue | parameter | 32 | +| Parameter 0 of SetZero | parameter | 32 | | Parameter 0 of Sign | parameter | 32 | +| Parameter 0 of SkipInit | parameter | 32 | | Parameter 0 of Start | parameter | 32 | +| Parameter 0 of StartAssemblyLoad | parameter | 32 | +| Parameter 0 of StelemRef_Helper | parameter | 32 | +| Parameter 0 of StelemRef_Helper_NoCacheLookup | parameter | 32 | +| Parameter 0 of StopAssemblyLoad | parameter | 32 | | Parameter 0 of SubtractDivisor | parameter | 32 | +| Parameter 0 of Swap | parameter | 32 | +| Parameter 0 of SwapIfGreater | parameter | 32 | | Parameter 0 of TZif_GenerateAdjustmentRule | parameter | 32 | | Parameter 0 of TZif_GenerateAdjustmentRules | parameter | 32 | +| Parameter 0 of TableMask | parameter | 32 | | Parameter 0 of TrimEventDescriptors | parameter | 32 | | Parameter 0 of Truncate | parameter | 32 | | Parameter 0 of TryAdjustYear | parameter | 32 | @@ -577,6 +632,7 @@ | Parameter 0 of TryFormatDecimalF | parameter | 32 | | Parameter 0 of TryFormatDecimalG | parameter | 32 | | Parameter 0 of TryFormatThrowFormatException | parameter | 32 | +| Parameter 0 of TryGetAppLocalIcuSwitchValue | parameter | 32 | | Parameter 0 of TryGetCachedCursorPosition | parameter | 32 | | Parameter 0 of TryGetCursorPosition | parameter | 32 | | Parameter 0 of TryGetLocalTzFile | parameter | 32 | @@ -611,16 +667,23 @@ | Parameter 0 of VolatileWrite | parameter | 32 | | Parameter 0 of WidenFourAsciiBytesToUtf16AndWriteToBuffer | parameter | 32 | | Parameter 0 of Write | parameter | 32 | +| Parameter 0 of WriteBarrier | parameter | 32 | | Parameter 0 of WriteFirstUtf16CharAsUtf8ThreeByteSequence | parameter | 32 | | Parameter 0 of WriteNibble | parameter | 32 | | Parameter 0 of WriteThreeLowOrderBytes | parameter | 32 | | Parameter 0 of WriteTwoUtf16CharsAsTwoUtf8ThreeByteSequences | parameter | 32 | | Parameter 0 of WriteUnaligned | parameter | 32 | +| Parameter 0 of _BulkMoveWithWriteBarrier | parameter | 32 | | Parameter 0 of _GetCurrentMethod | parameter | 32 | | Parameter 0 of _Memmove | parameter | 32 | +| Parameter 0 of _ZeroMemory | parameter | 32 | +| Parameter 0 of __BulkMoveWithWriteBarrier | parameter | 32 | | Parameter 1 of .ctor | parameter | 32 | -| Parameter 1 of b__21_0 | parameter | 32 | +| Parameter 1 of g__SoftwareFallback\|59_1 | parameter | 32 | +| Parameter 1 of g__SseImpl\|59_0 | parameter | 32 | +| Parameter 1 of g__Write\|65_0 | parameter | 32 | | Parameter 1 of AcquirePointer | parameter | 32 | +| Parameter 1 of AcquireSpan | parameter | 32 | | Parameter 1 of Add | parameter | 32 | | Parameter 1 of AddNonLetter | parameter | 32 | | Parameter 1 of AddSpecialInterface | parameter | 32 | @@ -631,8 +694,8 @@ | Parameter 1 of AreSame | parameter | 32 | | Parameter 1 of AwaitOnCompleted | parameter | 32 | | Parameter 1 of AwaitUnsafeOnCompleted | parameter | 32 | -| Parameter 1 of BeginInvoke | parameter | 32 | | Parameter 1 of Block | parameter | 32 | +| Parameter 1 of BulkMoveWithWriteBarrier | parameter | 32 | | Parameter 1 of ByteOffset | parameter | 32 | | Parameter 1 of ChangeCaseCommon | parameter | 32 | | Parameter 1 of CheckDefaultDateTime | parameter | 32 | @@ -640,6 +703,7 @@ | Parameter 1 of CheckVMForIOPacket | parameter | 32 | | Parameter 1 of ClearManaged | parameter | 32 | | Parameter 1 of ClearNative | parameter | 32 | +| Parameter 1 of ClearNativeContents | parameter | 32 | | Parameter 1 of Clone | parameter | 32 | | Parameter 1 of Compare | parameter | 32 | | Parameter 1 of ConfigureFormatOS | parameter | 32 | @@ -649,6 +713,8 @@ | Parameter 1 of ConvertContentsToManaged | parameter | 32 | | Parameter 1 of ConvertContentsToNative | parameter | 32 | | Parameter 1 of ConvertGregorianToHijri | parameter | 32 | +| Parameter 1 of ConvertSafeHandleToNative | parameter | 32 | +| Parameter 1 of ConvertSmpToUtf16 | parameter | 32 | | Parameter 1 of ConvertSpaceToManaged | parameter | 32 | | Parameter 1 of ConvertSpaceToNative | parameter | 32 | | Parameter 1 of CopyRuntimeTypeHandles | parameter | 32 | @@ -664,15 +730,17 @@ | Parameter 1 of DecodeFromUtf16 | parameter | 32 | | Parameter 1 of DecodeLastFromUtf8 | parameter | 32 | | Parameter 1 of DecodeLastFromUtf16 | parameter | 32 | +| Parameter 1 of Decompose | parameter | 32 | | Parameter 1 of Deconstruct | parameter | 32 | | Parameter 1 of Div96ByConst | parameter | 32 | | Parameter 1 of Div128By96 | parameter | 32 | | Parameter 1 of DivRem | parameter | 32 | +| Parameter 1 of DivRem32 | parameter | 32 | | Parameter 1 of EatWhiteSpace | parameter | 32 | | Parameter 1 of Encode | parameter | 32 | +| Parameter 1 of EncodeHexString | parameter | 32 | | Parameter 1 of EncodeObject | parameter | 32 | | Parameter 1 of EncodeTags | parameter | 32 | -| Parameter 1 of EndInvoke | parameter | 32 | | Parameter 1 of EnsureInitialized | parameter | 32 | | Parameter 1 of EnsureInitializedCore | parameter | 32 | | Parameter 1 of Enter | parameter | 32 | @@ -680,8 +748,7 @@ | Parameter 1 of EnumConnections | parameter | 32 | | Parameter 1 of EnumObjectParam | parameter | 32 | | Parameter 1 of EnumRunning | parameter | 32 | -| Parameter 1 of EqualsOrdinalIgnoreCase | parameter | 32 | -| Parameter 1 of EqualsOrdinalIgnoreCaseNonAscii | parameter | 32 | +| Parameter 1 of EqualsIgnoreCase | parameter | 32 | | Parameter 1 of EtwEnableCallBack | parameter | 32 | | Parameter 1 of EvaluateInternal | parameter | 32 | | Parameter 1 of EventActivityIdControl | parameter | 32 | @@ -691,7 +758,6 @@ | Parameter 1 of FStat | parameter | 32 | | Parameter 1 of FilterCustomAttributeRecord | parameter | 32 | | Parameter 1 of FilterHelper | parameter | 32 | -| Parameter 1 of FindAndParseNextNumber | parameter | 32 | | Parameter 1 of FindConnectionPoint | parameter | 32 | | Parameter 1 of FormatCurrency | parameter | 32 | | Parameter 1 of FormatFixed | parameter | 32 | @@ -714,10 +780,10 @@ | Parameter 1 of GetContainingTypeLib | parameter | 32 | | Parameter 1 of GetCurFile | parameter | 32 | | Parameter 1 of GetCustData | parameter | 32 | +| Parameter 1 of GetDate | parameter | 32 | | Parameter 1 of GetDateOfDSN | parameter | 32 | | Parameter 1 of GetDateOfNDS | parameter | 32 | | Parameter 1 of GetDateOfNNDS | parameter | 32 | -| Parameter 1 of GetDatePart | parameter | 32 | | Parameter 1 of GetDateTimeNow | parameter | 32 | | Parameter 1 of GetDateTimeNowUtcOffsetFromUtc | parameter | 32 | | Parameter 1 of GetDayOfMN | parameter | 32 | @@ -737,10 +803,12 @@ | Parameter 1 of GetFloatingPointMaxDigitsAndPrecision | parameter | 32 | | Parameter 1 of GetGUID | parameter | 32 | | Parameter 1 of GetHebrewDayOfNM | parameter | 32 | +| Parameter 1 of GetIUnknownImpl | parameter | 32 | | Parameter 1 of GetInterface | parameter | 32 | | Parameter 1 of GetJapaneseEraStartDate | parameter | 32 | | Parameter 1 of GetJitContext | parameter | 32 | | Parameter 1 of GetLibAttr | parameter | 32 | +| Parameter 1 of GetLicInfo | parameter | 32 | | Parameter 1 of GetLocalSignature | parameter | 32 | | Parameter 1 of GetLocaleName | parameter | 32 | | Parameter 1 of GetMarshalAs | parameter | 32 | @@ -748,17 +816,19 @@ | Parameter 1 of GetMaxThreadsNative | parameter | 32 | | Parameter 1 of GetMemberCache | parameter | 32 | | Parameter 1 of GetMemberList | parameter | 32 | -| Parameter 1 of GetMemoryInfo | parameter | 32 | -| Parameter 1 of GetMetadata | parameter | 32 | +| Parameter 1 of GetMetadataLength | parameter | 32 | +| Parameter 1 of GetMetadataLengthForTypeV2 | parameter | 32 | +| Parameter 1 of GetMetadataLengthV2 | parameter | 32 | | Parameter 1 of GetMinThreads | parameter | 32 | | Parameter 1 of GetMinThreadsNative | parameter | 32 | +| Parameter 1 of GetMonthDayOrder | parameter | 32 | | Parameter 1 of GetNeutralResourcesLanguage | parameter | 32 | +| Parameter 1 of GetNextUnicodeScalarValueFromUtf16Surrogate | parameter | 32 | | Parameter 1 of GetObjectStartLength | parameter | 32 | | Parameter 1 of GetPEKind | parameter | 32 | | Parameter 1 of GetPrimaryAndSecondary | parameter | 32 | | Parameter 1 of GetPropertyOrFieldData | parameter | 32 | | Parameter 1 of GetPwUidR | parameter | 32 | -| Parameter 1 of GetRawArrayGeometry | parameter | 32 | | Parameter 1 of GetRegularToken | parameter | 32 | | Parameter 1 of GetRunningObjectTable | parameter | 32 | | Parameter 1 of GetScopeProps | parameter | 32 | @@ -766,39 +836,47 @@ | Parameter 1 of GetSortHandle | parameter | 32 | | Parameter 1 of GetStackTracesDeepCopy | parameter | 32 | | Parameter 1 of GetStateMachineBox | parameter | 32 | +| Parameter 1 of GetTime | parameter | 32 | | Parameter 1 of GetTimeOfN | parameter | 32 | | Parameter 1 of GetTimeOfNN | parameter | 32 | | Parameter 1 of GetTimeOfNNN | parameter | 32 | +| Parameter 1 of GetTimePrecise | parameter | 32 | | Parameter 1 of GetTypeAttr | parameter | 32 | | Parameter 1 of GetTypeComp | parameter | 32 | | Parameter 1 of GetTypeFlags | parameter | 32 | +| Parameter 1 of GetTypeInfoFromType | parameter | 32 | | Parameter 1 of GetTypeInfoOfGuid | parameter | 32 | | Parameter 1 of GetTypeKind | parameter | 32 | | Parameter 1 of GetUtf16SurrogatesFromSupplementaryPlaneScalar | parameter | 32 | | Parameter 1 of GetVersion | parameter | 32 | | Parameter 1 of GetWindowSize | parameter | 32 | -| Parameter 1 of GrowTable | parameter | 32 | +| Parameter 1 of GetYearMonthDayOrder | parameter | 32 | +| Parameter 1 of GetYearMonthOrder | parameter | 32 | +| Parameter 1 of GreaterThan | parameter | 32 | | Parameter 1 of HandleTimeZone | parameter | 32 | | Parameter 1 of Hash | parameter | 32 | | Parameter 1 of HeuristicDivide | parameter | 32 | +| Parameter 1 of HtmlDecode | parameter | 32 | +| Parameter 1 of HtmlEncode | parameter | 32 | | Parameter 1 of Initialize | parameter | 32 | | Parameter 1 of Insert | parameter | 32 | | Parameter 1 of Int32ToNumber | parameter | 32 | | Parameter 1 of Int64ToNumber | parameter | 32 | | Parameter 1 of InternalGetSignature | parameter | 32 | | Parameter 1 of InternalLoad | parameter | 32 | -| Parameter 1 of InternalLoadAssemblyName | parameter | 32 | | Parameter 1 of InternalTryGetRawMetadata | parameter | 32 | | Parameter 1 of Inverse | parameter | 32 | +| Parameter 1 of Invert | parameter | 32 | | Parameter 1 of Invoke | parameter | 32 | | Parameter 1 of IsAddressGreaterThan | parameter | 32 | | Parameter 1 of IsAddressLessThan | parameter | 32 | | Parameter 1 of IsSystemMoniker | parameter | 32 | | Parameter 1 of LStat | parameter | 32 | | Parameter 1 of LazyCreateEvent | parameter | 32 | +| Parameter 1 of LessThan | parameter | 32 | | Parameter 1 of Lex | parameter | 32 | -| Parameter 1 of Load | parameter | 32 | | Parameter 1 of MapBufferToConsoleKey | parameter | 32 | +| Parameter 1 of MarshalToNative | parameter | 32 | | Parameter 1 of Max | parameter | 32 | | Parameter 1 of Memmove | parameter | 32 | | Parameter 1 of Min | parameter | 32 | @@ -836,18 +914,24 @@ | Parameter 1 of ReorderArgumentArray | parameter | 32 | | Parameter 1 of ReplaceInPlaceAtChunk | parameter | 32 | | Parameter 1 of RestoreDispatchState | parameter | 32 | -| Parameter 1 of RhBulkMoveWithWriteBarrier | parameter | 32 | | Parameter 1 of SafeHandleAddRef | parameter | 32 | | Parameter 1 of SequenceEqual | parameter | 32 | +| Parameter 1 of SerializeSubstitute | parameter | 32 | +| Parameter 1 of SerializeTransitionTime | parameter | 32 | | Parameter 1 of SetBindOptions | parameter | 32 | | Parameter 1 of SetCurrentThreadActivityId | parameter | 32 | +| Parameter 1 of SetException | parameter | 32 | +| Parameter 1 of SetNotificationForWaitCompletion | parameter | 32 | | Parameter 1 of SetValue | parameter | 32 | | Parameter 1 of SkipWhitespace | parameter | 32 | | Parameter 1 of SnapForObservation | parameter | 32 | | Parameter 1 of SplitName | parameter | 32 | | Parameter 1 of Start | parameter | 32 | +| Parameter 1 of StartAssemblyLoad | parameter | 32 | | Parameter 1 of Stat | parameter | 32 | | Parameter 1 of Subtract | parameter | 32 | +| Parameter 1 of Swap | parameter | 32 | +| Parameter 1 of SwapIfGreater | parameter | 32 | | Parameter 1 of TZif_ParseJulianDay | parameter | 32 | | Parameter 1 of TZif_ParseMDateRule | parameter | 32 | | Parameter 1 of TZif_ParsePosixDate | parameter | 32 | @@ -864,6 +948,7 @@ | Parameter 1 of TryDequeueSlow | parameter | 32 | | Parameter 1 of TryDigitGenShortest | parameter | 32 | | Parameter 1 of TryEnter | parameter | 32 | +| Parameter 1 of TryFindFirstMatchedLane | parameter | 32 | | Parameter 1 of TryGetArray | parameter | 32 | | Parameter 1 of TryGetBuffer | parameter | 32 | | Parameter 1 of TryGetCachedCursorPosition | parameter | 32 | @@ -898,6 +983,7 @@ | Parameter 1 of TryParseExactP | parameter | 32 | | Parameter 1 of TryParseExactX | parameter | 32 | | Parameter 1 of TryParseGuid | parameter | 32 | +| Parameter 1 of TryParseGuidCore | parameter | 32 | | Parameter 1 of TryParseGuidN | parameter | 32 | | Parameter 1 of TryParseHebrewNumber | parameter | 32 | | Parameter 1 of TryParseHex | parameter | 32 | @@ -928,12 +1014,16 @@ | Parameter 1 of TryParseUInt64X | parameter | 32 | | Parameter 1 of TryPeek | parameter | 32 | | Parameter 1 of TryRead | parameter | 32 | +| Parameter 1 of TryReadDoubleBigEndian | parameter | 32 | +| Parameter 1 of TryReadDoubleLittleEndian | parameter | 32 | | Parameter 1 of TryReadInt16BigEndian | parameter | 32 | | Parameter 1 of TryReadInt16LittleEndian | parameter | 32 | | Parameter 1 of TryReadInt32BigEndian | parameter | 32 | | Parameter 1 of TryReadInt32LittleEndian | parameter | 32 | | Parameter 1 of TryReadInt64BigEndian | parameter | 32 | | Parameter 1 of TryReadInt64LittleEndian | parameter | 32 | +| Parameter 1 of TryReadSingleBigEndian | parameter | 32 | +| Parameter 1 of TryReadSingleLittleEndian | parameter | 32 | | Parameter 1 of TryReadUInt16BigEndian | parameter | 32 | | Parameter 1 of TryReadUInt16LittleEndian | parameter | 32 | | Parameter 1 of TryReadUInt32BigEndian | parameter | 32 | @@ -948,7 +1038,6 @@ | Parameter 1 of UInt32ToNumber | parameter | 32 | | Parameter 1 of UInt64ToNumber | parameter | 32 | | Parameter 1 of Unscale | parameter | 32 | -| Parameter 1 of ValidateEventOpcodeForTransfer | parameter | 32 | | Parameter 1 of ValidateVariableAndValue | parameter | 32 | | Parameter 1 of VarDecCmp | parameter | 32 | | Parameter 1 of VarDecCmpSub | parameter | 32 | @@ -963,13 +1052,16 @@ | Parameter 1 of WriteEvent | parameter | 32 | | Parameter 1 of WriteEventRaw | parameter | 32 | | Parameter 1 of YearMonthAdjustment | parameter | 32 | +| Parameter 1 of _BulkMoveWithWriteBarrier | parameter | 32 | | Parameter 1 of _GetScopeProps | parameter | 32 | | Parameter 1 of _Memmove | parameter | 32 | -| Parameter 1 of nCreateDynamicAssembly | parameter | 32 | +| Parameter 1 of __BulkMoveWithWriteBarrier | parameter | 32 | | Parameter 1 of nGetPrimaryAndSecondary | parameter | 32 | -| Parameter 2 of g__BufferUntil\|86_0 | parameter | 32 | +| Parameter 2 of g__SoftwareFallback\|42_0 | parameter | 32 | +| Parameter 2 of g__BufferUntil\|83_0 | parameter | 32 | | Parameter 2 of Add | parameter | 32 | | Parameter 2 of AddDivisor | parameter | 32 | +| Parameter 2 of AddIfNotPresent | parameter | 32 | | Parameter 2 of AddNum | parameter | 32 | | Parameter 2 of AddResourceSet | parameter | 32 | | Parameter 2 of AddSep | parameter | 32 | @@ -979,15 +1071,18 @@ | Parameter 2 of AttributeUsageCheck | parameter | 32 | | Parameter 2 of AwaitOnCompleted | parameter | 32 | | Parameter 2 of AwaitUnsafeOnCompleted | parameter | 32 | +| Parameter 2 of BigMul | parameter | 32 | | Parameter 2 of BiggestPowerTen | parameter | 32 | | Parameter 2 of ChangeCaseCommon | parameter | 32 | | Parameter 2 of CheckVMForIOPacket | parameter | 32 | | Parameter 2 of CommonPrefixWith | parameter | 32 | -| Parameter 2 of CompareOrdinalIgnoreCase | parameter | 32 | -| Parameter 2 of CompareStringOrdinalIgnoreCase | parameter | 32 | +| Parameter 2 of CompareIgnoreCaseInvariantMode | parameter | 32 | +| Parameter 2 of CompareStringIgnoreCase | parameter | 32 | +| Parameter 2 of CompareStringIgnoreCaseNonAscii | parameter | 32 | | Parameter 2 of ConfigureFormatR | parameter | 32 | | Parameter 2 of ContinueTryEnter | parameter | 32 | | Parameter 2 of ConvertGregorianToHijri | parameter | 32 | +| Parameter 2 of ConvertSmpToUtf16 | parameter | 32 | | Parameter 2 of ConvertUtcToTimeZone | parameter | 32 | | Parameter 2 of CopyToTempBufferWithoutWhiteSpace | parameter | 32 | | Parameter 2 of CountOccurrences | parameter | 32 | @@ -1000,6 +1095,7 @@ | Parameter 2 of DecodeFromUtf16 | parameter | 32 | | Parameter 2 of DecodeLastFromUtf8 | parameter | 32 | | Parameter 2 of DecodeLastFromUtf16 | parameter | 32 | +| Parameter 2 of Decompose | parameter | 32 | | Parameter 2 of Deconstruct | parameter | 32 | | Parameter 2 of Dequeue | parameter | 32 | | Parameter 2 of DivByConst | parameter | 32 | @@ -1008,7 +1104,6 @@ | Parameter 2 of DrainLeftoverDataForGetByteCount | parameter | 32 | | Parameter 2 of DrainLeftoverDataForGetCharCount | parameter | 32 | | Parameter 2 of EncodeObject | parameter | 32 | -| Parameter 2 of EndInvoke | parameter | 32 | | Parameter 2 of EnqueueSlow | parameter | 32 | | Parameter 2 of EnsureInitialized | parameter | 32 | | Parameter 2 of EnsureInitializedCore | parameter | 32 | @@ -1030,6 +1125,8 @@ | Parameter 2 of FromUtf16 | parameter | 32 | | Parameter 2 of GenerateMetadata | parameter | 32 | | Parameter 2 of GenerateMetadataForProperty | parameter | 32 | +| Parameter 2 of GenerateMetadataForTypeV2 | parameter | 32 | +| Parameter 2 of GenerateMetadataV2 | parameter | 32 | | Parameter 2 of GetAdjustmentRuleForAmbiguousOffsets | parameter | 32 | | Parameter 2 of GetAdjustmentRuleForTime | parameter | 32 | | Parameter 2 of GetBoundaries | parameter | 32 | @@ -1037,15 +1134,15 @@ | Parameter 2 of GetClassLayout | parameter | 32 | | Parameter 2 of GetCodeInfo | parameter | 32 | | Parameter 2 of GetContainingTypeLib | parameter | 32 | +| Parameter 2 of GetCurrentContextInfo | parameter | 32 | | Parameter 2 of GetCustData | parameter | 32 | | Parameter 2 of GetCustomAttributeProps | parameter | 32 | | Parameter 2 of GetCustomAttributes | parameter | 32 | -| Parameter 2 of GetDatePart | parameter | 32 | +| Parameter 2 of GetDate | parameter | 32 | | Parameter 2 of GetDayOfMN | parameter | 32 | | Parameter 2 of GetDayOfNM | parameter | 32 | | Parameter 2 of GetDayOfNN | parameter | 32 | | Parameter 2 of GetDefaultValue | parameter | 32 | -| Parameter 2 of GetDisplayName | parameter | 32 | | Parameter 2 of GetDocumentation | parameter | 32 | | Parameter 2 of GetDocumentation2 | parameter | 32 | | Parameter 2 of GetDynamicOrStaticVariables | parameter | 32 | @@ -1057,6 +1154,7 @@ | Parameter 2 of GetFuncCustData | parameter | 32 | | Parameter 2 of GetFuncDesc | parameter | 32 | | Parameter 2 of GetGenericParamProps | parameter | 32 | +| Parameter 2 of GetIUnknownImpl | parameter | 32 | | Parameter 2 of GetImplTypeCustData | parameter | 32 | | Parameter 2 of GetImplTypeFlags | parameter | 32 | | Parameter 2 of GetIndexOfNextTokenAfterSeconds | parameter | 32 | @@ -1067,9 +1165,7 @@ | Parameter 2 of GetLocaleInfoGroupingSizes | parameter | 32 | | Parameter 2 of GetLocaleInfoInt | parameter | 32 | | Parameter 2 of GetMarshalAs | parameter | 32 | -| Parameter 2 of GetMemoryInfo | parameter | 32 | -| Parameter 2 of GetMetadata | parameter | 32 | -| Parameter 2 of GetMonthDayOrder | parameter | 32 | +| Parameter 2 of GetMetadataLengthForNamedTypeV2 | parameter | 32 | | Parameter 2 of GetMops | parameter | 32 | | Parameter 2 of GetObject | parameter | 32 | | Parameter 2 of GetObjectParam | parameter | 32 | @@ -1080,7 +1176,6 @@ | Parameter 2 of GetPointerToFirstInvalidByte | parameter | 32 | | Parameter 2 of GetPointerToFirstInvalidChar | parameter | 32 | | Parameter 2 of GetPropertyProps | parameter | 32 | -| Parameter 2 of GetRawArrayGeometry | parameter | 32 | | Parameter 2 of GetRefTypeInfo | parameter | 32 | | Parameter 2 of GetRefTypeOfImplType | parameter | 32 | | Parameter 2 of GetRegularToken | parameter | 32 | @@ -1090,11 +1185,14 @@ | Parameter 2 of GetSessionInfo | parameter | 32 | | Parameter 2 of GetSessionInfoCallback | parameter | 32 | | Parameter 2 of GetStackTracesDeepCopy | parameter | 32 | +| Parameter 2 of GetTime | parameter | 32 | | Parameter 2 of GetTimeOfLastChange | parameter | 32 | +| Parameter 2 of GetTimePrecise | parameter | 32 | | Parameter 2 of GetTypeInfo | parameter | 32 | | Parameter 2 of GetTypeInfoOfGuid | parameter | 32 | | Parameter 2 of GetTypeInfoType | parameter | 32 | | Parameter 2 of GetUnescapeSequence | parameter | 32 | +| Parameter 2 of GetUnicodeCategoryInternal | parameter | 32 | | Parameter 2 of GetUtcOffsetFromUniversalTime | parameter | 32 | | Parameter 2 of GetUtcOffsetFromUtc | parameter | 32 | | Parameter 2 of GetUtf16SurrogatesFromSupplementaryPlaneScalar | parameter | 32 | @@ -1102,19 +1200,17 @@ | Parameter 2 of GetVarDesc | parameter | 32 | | Parameter 2 of GetVarIndexOfMemId | parameter | 32 | | Parameter 2 of GetVersion | parameter | 32 | -| Parameter 2 of GetYearMonthDayOrder | parameter | 32 | -| Parameter 2 of GetYearMonthOrder | parameter | 32 | | Parameter 2 of GrabInts | parameter | 32 | | Parameter 2 of GrabLongs | parameter | 32 | | Parameter 2 of IndexOf | parameter | 32 | | Parameter 2 of IndexOfAny | parameter | 32 | | Parameter 2 of Initialize | parameter | 32 | -| Parameter 2 of InternalConvertToUtf32 | parameter | 32 | | Parameter 2 of InternalDefineDynamicAssembly | parameter | 32 | | Parameter 2 of InternalFallback | parameter | 32 | | Parameter 2 of InternalFallbackGetByteCount | parameter | 32 | -| Parameter 2 of InternalGetUnicodeCategory | parameter | 32 | +| Parameter 2 of InternalLoad | parameter | 32 | | Parameter 2 of InternalTryGetRawMetadata | parameter | 32 | +| Parameter 2 of Invoke | parameter | 32 | | Parameter 2 of IsDigit | parameter | 32 | | Parameter 2 of IsInstanceOfInterface | parameter | 32 | | Parameter 2 of LastIndexOf | parameter | 32 | @@ -1143,7 +1239,6 @@ | Parameter 2 of ParseComponent | parameter | 32 | | Parameter 2 of ParseDigits | parameter | 32 | | Parameter 2 of ParseExactDigits | parameter | 32 | -| Parameter 2 of ParseFormatO | parameter | 32 | | Parameter 2 of ParseFormatR | parameter | 32 | | Parameter 2 of ParseFractionExact | parameter | 32 | | Parameter 2 of ParseInt | parameter | 32 | @@ -1167,11 +1262,10 @@ | Parameter 2 of Remove | parameter | 32 | | Parameter 2 of RemoveRelativeSegments | parameter | 32 | | Parameter 2 of ReplaceInPlaceAtChunk | parameter | 32 | +| Parameter 2 of RequestLicKey | parameter | 32 | | Parameter 2 of ResolveToken | parameter | 32 | | Parameter 2 of RunForThreadPoolUnsafe | parameter | 32 | -| Parameter 2 of RunInternal | parameter | 32 | | Parameter 2 of SequenceCompareTo | parameter | 32 | -| Parameter 2 of ShiftLeft | parameter | 32 | | Parameter 2 of SnapForObservation | parameter | 32 | | Parameter 2 of SplitName | parameter | 32 | | Parameter 2 of SubtractDivisor | parameter | 32 | @@ -1181,6 +1275,7 @@ | Parameter 2 of TZif_ParsePosixFormat | parameter | 32 | | Parameter 2 of TZif_ParseRaw | parameter | 32 | | Parameter 2 of TimeToLunar | parameter | 32 | +| Parameter 2 of ToUpperSurrogate | parameter | 32 | | Parameter 2 of ToUtf16 | parameter | 32 | | Parameter 2 of Tokenize | parameter | 32 | | Parameter 2 of TryAddTicks | parameter | 32 | @@ -1195,6 +1290,7 @@ | Parameter 2 of TryEncodeToUtf8 | parameter | 32 | | Parameter 2 of TryEncodeToUtf16 | parameter | 32 | | Parameter 2 of TryEnter | parameter | 32 | +| Parameter 2 of TryFindFirstMatchedLane | parameter | 32 | | Parameter 2 of TryFormat | parameter | 32 | | Parameter 2 of TryFormatDateTimeL | parameter | 32 | | Parameter 2 of TryFormatDateTimeR | parameter | 32 | @@ -1202,20 +1298,15 @@ | Parameter 2 of TryFormatDecimalF | parameter | 32 | | Parameter 2 of TryFormatDecimalG | parameter | 32 | | Parameter 2 of TryFormatFloatingPoint | parameter | 32 | -| Parameter 2 of TryFormatInt32MultipleDigits | parameter | 32 | | Parameter 2 of TryFormatInt64Default | parameter | 32 | -| Parameter 2 of TryFormatInt64LessThanNegativeBillionMaxUInt | parameter | 32 | -| Parameter 2 of TryFormatInt64MoreThanNegativeBillionMaxUInt | parameter | 32 | | Parameter 2 of TryFormatInt64MultipleDigits | parameter | 32 | -| Parameter 2 of TryFormatUInt32MultipleDigits | parameter | 32 | | Parameter 2 of TryFormatUInt32SingleDigit | parameter | 32 | | Parameter 2 of TryFormatUInt64 | parameter | 32 | | Parameter 2 of TryFormatUInt64Default | parameter | 32 | -| Parameter 2 of TryFormatUInt64LessThanBillionMaxUInt | parameter | 32 | -| Parameter 2 of TryFormatUInt64MoreThanBillionMaxUInt | parameter | 32 | | Parameter 2 of TryFormatUInt64MultipleDigits | parameter | 32 | | Parameter 2 of TryFromBase64Chars | parameter | 32 | | Parameter 2 of TryFromBase64String | parameter | 32 | +| Parameter 2 of TryGetBits | parameter | 32 | | Parameter 2 of TryGetByteCount | parameter | 32 | | Parameter 2 of TryGetEntry | parameter | 32 | | Parameter 2 of TryGetExport | parameter | 32 | @@ -1224,6 +1315,7 @@ | Parameter 2 of TryGetRawMetadata | parameter | 32 | | Parameter 2 of TryGetRuneAt | parameter | 32 | | Parameter 2 of TryGetString | parameter | 32 | +| Parameter 2 of TryGetStringValue | parameter | 32 | | Parameter 2 of TryGetTimeZone | parameter | 32 | | Parameter 2 of TryGetTimeZoneFromLocalMachine | parameter | 32 | | Parameter 2 of TryGetUserNameFromPasswd | parameter | 32 | @@ -1239,6 +1331,7 @@ | Parameter 2 of TryParseDateTimeOffsetO | parameter | 32 | | Parameter 2 of TryParseDateTimeOffsetR | parameter | 32 | | Parameter 2 of TryParseExact | parameter | 32 | +| Parameter 2 of TryParseGuidCore | parameter | 32 | | Parameter 2 of TryParseGuidN | parameter | 32 | | Parameter 2 of TryParseHebrewNumber | parameter | 32 | | Parameter 2 of TryParseHex | parameter | 32 | @@ -1252,6 +1345,7 @@ | Parameter 2 of TryParseNumber | parameter | 32 | | Parameter 2 of TryParseSByteD | parameter | 32 | | Parameter 2 of TryParseSByteN | parameter | 32 | +| Parameter 2 of TryParseThrowFormatException | parameter | 32 | | Parameter 2 of TryParseTimeSpanBigG | parameter | 32 | | Parameter 2 of TryParseTimeSpanC | parameter | 32 | | Parameter 2 of TryParseTimeSpanFraction | parameter | 32 | @@ -1268,6 +1362,7 @@ | Parameter 2 of TryParseUInt64N | parameter | 32 | | Parameter 2 of TryParseUInt64X | parameter | 32 | | Parameter 2 of TryRunDouble | parameter | 32 | +| Parameter 2 of TryRunHalf | parameter | 32 | | Parameter 2 of TryRunShortest | parameter | 32 | | Parameter 2 of TryRunSingle | parameter | 32 | | Parameter 2 of TryStringToNumber | parameter | 32 | @@ -1302,13 +1397,12 @@ | Parameter 2 of _ParseAttributeUsageAttribute | parameter | 32 | | Parameter 2 of ctor>g__TryConvertFromInvariantString\|2_0 | parameter | 32 | | Parameter 3 of .ctor | parameter | 32 | -| Parameter 3 of b__39_0 | parameter | 32 | -| Parameter 3 of g__AppendToStdInReaderUntil\|86_1 | parameter | 32 | -| Parameter 3 of g__BufferUntil\|86_0 | parameter | 32 | +| Parameter 3 of b__37_0 | parameter | 32 | +| Parameter 3 of g__AppendToStdInReaderUntil\|83_1 | parameter | 32 | +| Parameter 3 of g__BufferUntil\|83_0 | parameter | 32 | | Parameter 3 of AccumulateDecimalDigitsIntoBigInteger | parameter | 32 | | Parameter 3 of AddressOfMember | parameter | 32 | | Parameter 3 of AtomicStateUpdate | parameter | 32 | -| Parameter 3 of BeginInvoke | parameter | 32 | | Parameter 3 of BindToMethod | parameter | 32 | | Parameter 3 of BindToObject | parameter | 32 | | Parameter 3 of BindToStorage | parameter | 32 | @@ -1316,6 +1410,7 @@ | Parameter 3 of CheckNewValue | parameter | 32 | | Parameter 3 of CompareExchange | parameter | 32 | | Parameter 3 of ComposeWith | parameter | 32 | +| Parameter 3 of ComputeVtables | parameter | 32 | | Parameter 3 of ContinueTryEnterWithThreadTracking | parameter | 32 | | Parameter 3 of ConvertGregorianToHijri | parameter | 32 | | Parameter 3 of ConvertHijriToGregorian | parameter | 32 | @@ -1323,21 +1418,21 @@ | Parameter 3 of CopyToTempBufferWithoutWhiteSpace | parameter | 32 | | Parameter 3 of CreateCaObject | parameter | 32 | | Parameter 3 of CreateInstance | parameter | 32 | +| Parameter 3 of CreateInstanceLic | parameter | 32 | | Parameter 3 of CreateMutexCore | parameter | 32 | | Parameter 3 of DecodeFirstRune | parameter | 32 | | Parameter 3 of DecodeObject | parameter | 32 | +| Parameter 3 of Decompose | parameter | 32 | | Parameter 3 of Deconstruct | parameter | 32 | -| Parameter 3 of DefineDynamicModuleInternal | parameter | 32 | -| Parameter 3 of DefineDynamicModuleInternalNoLock | parameter | 32 | | Parameter 3 of DivByConst | parameter | 32 | | Parameter 3 of DivRem | parameter | 32 | | Parameter 3 of DoAnsiConversion | parameter | 32 | | Parameter 3 of Dragon4Double | parameter | 32 | +| Parameter 3 of Dragon4Half | parameter | 32 | | Parameter 3 of Dragon4Single | parameter | 32 | | Parameter 3 of DrainLeftoverDataForGetChars | parameter | 32 | | Parameter 3 of EncodeObject | parameter | 32 | | Parameter 3 of EncodeRune | parameter | 32 | -| Parameter 3 of EndInvoke | parameter | 32 | | Parameter 3 of Enum | parameter | 32 | | Parameter 3 of EnumCalendarInfo | parameter | 32 | | Parameter 3 of EnumDatePatterns | parameter | 32 | @@ -1346,16 +1441,17 @@ | Parameter 3 of ExpandPredefinedFormat | parameter | 32 | | Parameter 3 of FilterHelper | parameter | 32 | | Parameter 3 of FromUtf16 | parameter | 32 | +| Parameter 3 of GenerateMetadataForNamedTypeV2 | parameter | 32 | | Parameter 3 of GetAdjustmentRuleForTime | parameter | 32 | | Parameter 3 of GetBoundaries | parameter | 32 | | Parameter 3 of GetCalendarInfo | parameter | 32 | | Parameter 3 of GetClassLayout | parameter | 32 | | Parameter 3 of GetCodeInfo | parameter | 32 | | Parameter 3 of GetControlCharacters | parameter | 32 | -| Parameter 3 of GetCurrentTextElementLen | parameter | 32 | +| Parameter 3 of GetCurrentContextInfo | parameter | 32 | | Parameter 3 of GetCustomAttributeProps | parameter | 32 | | Parameter 3 of GetDataFromController | parameter | 32 | -| Parameter 3 of GetDatePart | parameter | 32 | +| Parameter 3 of GetDate | parameter | 32 | | Parameter 3 of GetDefaultValue | parameter | 32 | | Parameter 3 of GetDisplayName | parameter | 32 | | Parameter 3 of GetDocumentation | parameter | 32 | @@ -1371,8 +1467,6 @@ | Parameter 3 of GetKeyFromCharValue | parameter | 32 | | Parameter 3 of GetLocaleInfoGroupingSizes | parameter | 32 | | Parameter 3 of GetMarshalAs | parameter | 32 | -| Parameter 3 of GetMemoryInfo | parameter | 32 | -| Parameter 3 of GetMetadata | parameter | 32 | | Parameter 3 of GetPInvokeMap | parameter | 32 | | Parameter 3 of GetParamCustData | parameter | 32 | | Parameter 3 of GetParamDefProps | parameter | 32 | @@ -1381,10 +1475,11 @@ | Parameter 3 of GetPointerToFirstInvalidChar | parameter | 32 | | Parameter 3 of GetPropertyOrFieldData | parameter | 32 | | Parameter 3 of GetPropertyProps | parameter | 32 | -| Parameter 3 of GetRawArrayGeometry | parameter | 32 | | Parameter 3 of GetResourceData | parameter | 32 | | Parameter 3 of GetSeparatorToken | parameter | 32 | +| Parameter 3 of GetTime | parameter | 32 | | Parameter 3 of GetTimeOfLastChange | parameter | 32 | +| Parameter 3 of GetTimePrecise | parameter | 32 | | Parameter 3 of GetType | parameter | 32 | | Parameter 3 of GetTypeByName | parameter | 32 | | Parameter 3 of GetUtcOffsetFromUtc | parameter | 32 | @@ -1428,6 +1523,7 @@ | Parameter 3 of TZif_ParsePosixFormat | parameter | 32 | | Parameter 3 of TZif_ParseRaw | parameter | 32 | | Parameter 3 of TimeToLunar | parameter | 32 | +| Parameter 3 of ToUpperSurrogate | parameter | 32 | | Parameter 3 of ToUtf16 | parameter | 32 | | Parameter 3 of Tokenize | parameter | 32 | | Parameter 3 of TryDecodeFromUtf16 | parameter | 32 | @@ -1444,6 +1540,7 @@ | Parameter 3 of TryFormatR | parameter | 32 | | Parameter 3 of TryGetEntry | parameter | 32 | | Parameter 3 of TryGetMemoryManager | parameter | 32 | +| Parameter 3 of TryGetSpan | parameter | 32 | | Parameter 3 of TryGetSpecialConsoleKey | parameter | 32 | | Parameter 3 of TryGetString | parameter | 32 | | Parameter 3 of TryGetTimeZone | parameter | 32 | @@ -1460,6 +1557,7 @@ | Parameter 3 of TryParseDecimal | parameter | 32 | | Parameter 3 of TryParseDouble | parameter | 32 | | Parameter 3 of TryParseExact | parameter | 32 | +| Parameter 3 of TryParseHalf | parameter | 32 | | Parameter 3 of TryParseInt32 | parameter | 32 | | Parameter 3 of TryParseInt32IntegerStyle | parameter | 32 | | Parameter 3 of TryParseInt32Number | parameter | 32 | @@ -1484,6 +1582,7 @@ | Parameter 3 of ValidateTimeZoneInfo | parameter | 32 | | Parameter 3 of Write | parameter | 32 | | Parameter 3 of WriteFile | parameter | 32 | +| Parameter 3 of WriteToBuffer | parameter | 32 | | Parameter 3 of _Enum | parameter | 32 | | Parameter 3 of _GetClassLayout | parameter | 32 | | Parameter 3 of _GetCustomAttributeProps | parameter | 32 | @@ -1496,13 +1595,14 @@ | Parameter 3 of _GetPropertyProps | parameter | 32 | | Parameter 3 of _GetUserString | parameter | 32 | | Parameter 3 of _ParseAttributeUsageAttribute | parameter | 32 | -| Parameter 3 of nLoad | parameter | 32 | | Parameter 4 of .ctor | parameter | 32 | -| Parameter 4 of g__AppendToStdInReaderUntil\|86_1 | parameter | 32 | -| Parameter 4 of g__BufferUntil\|86_0 | parameter | 32 | -| Parameter 4 of g__ReadRowOrCol\|86_2 | parameter | 32 | +| Parameter 4 of g__TryFormatInt64Slow\|43_0 | parameter | 32 | +| Parameter 4 of g__TryFormatUInt32Slow\|41_0 | parameter | 32 | +| Parameter 4 of g__TryFormatUInt64Slow\|45_0 | parameter | 32 | +| Parameter 4 of g__AppendToStdInReaderUntil\|83_1 | parameter | 32 | +| Parameter 4 of g__BufferUntil\|83_0 | parameter | 32 | +| Parameter 4 of g__ReadRowOrCol\|83_2 | parameter | 32 | | Parameter 4 of AssignAssociates | parameter | 32 | -| Parameter 4 of BeginInvoke | parameter | 32 | | Parameter 4 of Bind | parameter | 32 | | Parameter 4 of BindToObject | parameter | 32 | | Parameter 4 of BindToStorage | parameter | 32 | @@ -1515,7 +1615,6 @@ | Parameter 4 of CreateSemaphoreCore | parameter | 32 | | Parameter 4 of Deconstruct | parameter | 32 | | Parameter 4 of DoStrictParse | parameter | 32 | -| Parameter 4 of EndInvoke | parameter | 32 | | Parameter 4 of EnumMonthNames | parameter | 32 | | Parameter 4 of EscapeString | parameter | 32 | | Parameter 4 of EvaluateInternal | parameter | 32 | @@ -1523,25 +1622,27 @@ | Parameter 4 of FilterHelper | parameter | 32 | | Parameter 4 of GetByteCountFast | parameter | 32 | | Parameter 4 of GetCharCountFast | parameter | 32 | -| Parameter 4 of GetCurrentTextElementLen | parameter | 32 | | Parameter 4 of GetDataFromController | parameter | 32 | | Parameter 4 of GetDefaultValue | parameter | 32 | | Parameter 4 of GetDocumentation | parameter | 32 | | Parameter 4 of GetDocumentation2 | parameter | 32 | | Parameter 4 of GetMarshalAs | parameter | 32 | -| Parameter 4 of GetMemoryInfo | parameter | 32 | -| Parameter 4 of GetMetadata | parameter | 32 | | Parameter 4 of GetNames | parameter | 32 | | Parameter 4 of GetPInvokeMap | parameter | 32 | | Parameter 4 of GetParamCustData | parameter | 32 | | Parameter 4 of GetPropertyOrFieldData | parameter | 32 | | Parameter 4 of GetPropertyProps | parameter | 32 | -| Parameter 4 of GetRawArrayGeometry | parameter | 32 | +| Parameter 4 of GetTime | parameter | 32 | +| Parameter 4 of GetTimePrecise | parameter | 32 | | Parameter 4 of GetValue | parameter | 32 | | Parameter 4 of GetVersion | parameter | 32 | | Parameter 4 of GregorianToLunar | parameter | 32 | +| Parameter 4 of IndexOf | parameter | 32 | | Parameter 4 of InitHash | parameter | 32 | | Parameter 4 of Invoke | parameter | 32 | +| Parameter 4 of IsPrefix | parameter | 32 | +| Parameter 4 of IsSuffix | parameter | 32 | +| Parameter 4 of LastIndexOf | parameter | 32 | | Parameter 4 of Lex | parameter | 32 | | Parameter 4 of LunarToGregorian | parameter | 32 | | Parameter 4 of MakeRoom | parameter | 32 | @@ -1554,8 +1655,7 @@ | Parameter 4 of ParseExactDigits | parameter | 32 | | Parameter 4 of ParseExactMultiple | parameter | 32 | | Parameter 4 of PopulateEvents | parameter | 32 | -| Parameter 4 of ProcessHebrewTerminalState | parameter | 32 | -| Parameter 4 of ProcessTerminalState | parameter | 32 | +| Parameter 4 of ReadFromBuffer | parameter | 32 | | Parameter 4 of Reduce | parameter | 32 | | Parameter 4 of Remove | parameter | 32 | | Parameter 4 of ResolveToken | parameter | 32 | @@ -1572,7 +1672,7 @@ | Parameter 4 of TryDrainLeftoverDataForGetBytes | parameter | 32 | | Parameter 4 of TryFormatDecimal | parameter | 32 | | Parameter 4 of TryFormatDouble | parameter | 32 | -| Parameter 4 of TryFormatInt32 | parameter | 32 | +| Parameter 4 of TryFormatHalf | parameter | 32 | | Parameter 4 of TryFormatInt64 | parameter | 32 | | Parameter 4 of TryFormatSingle | parameter | 32 | | Parameter 4 of TryFormatStandard | parameter | 32 | @@ -1595,13 +1695,9 @@ | Parameter 4 of TryParseExactMultiple | parameter | 32 | | Parameter 4 of TryParseExactMultipleTimeSpan | parameter | 32 | | Parameter 4 of TryParseExactTimeSpan | parameter | 32 | -| Parameter 4 of TryParseGuidCore | parameter | 32 | | Parameter 4 of TryParseNumber | parameter | 32 | | Parameter 4 of TryRunCounted | parameter | 32 | | Parameter 4 of TryRunShortest | parameter | 32 | -| Parameter 4 of TrySZBinarySearch | parameter | 32 | -| Parameter 4 of TrySZIndexOf | parameter | 32 | -| Parameter 4 of TrySZLastIndexOf | parameter | 32 | | Parameter 4 of UpdateDescriptor | parameter | 32 | | Parameter 4 of Write | parameter | 32 | | Parameter 4 of _GetDefaultValue | parameter | 32 | @@ -1609,14 +1705,15 @@ | Parameter 4 of _GetPropertyOrFieldData | parameter | 32 | | Parameter 4 of _GetPropertyProps | parameter | 32 | | Parameter 4 of _ParseAttributeUsageAttribute | parameter | 32 | +| Parameter 5 of g__TryFormatInt32Slow\|39_0 | parameter | 32 | | Parameter 5 of AssignAssociates | parameter | 32 | -| Parameter 5 of BeginInvoke | parameter | 32 | | Parameter 5 of Bind | parameter | 32 | | Parameter 5 of ConstructType | parameter | 32 | | Parameter 5 of Convert | parameter | 32 | | Parameter 5 of ConvertHijriToGregorian | parameter | 32 | | Parameter 5 of CreateCaObject | parameter | 32 | | Parameter 5 of CreateInstance | parameter | 32 | +| Parameter 5 of CreateInstanceLic | parameter | 32 | | Parameter 5 of Deconstruct | parameter | 32 | | Parameter 5 of EnsureDestinationSize | parameter | 32 | | Parameter 5 of EvaluateInternal | parameter | 32 | @@ -1628,7 +1725,6 @@ | Parameter 5 of GetDocumentation | parameter | 32 | | Parameter 5 of GetIsDaylightSavingsFromUtc | parameter | 32 | | Parameter 5 of GetMarshalAs | parameter | 32 | -| Parameter 5 of GetMemoryInfo | parameter | 32 | | Parameter 5 of GetPropertyOrFieldData | parameter | 32 | | Parameter 5 of GetType | parameter | 32 | | Parameter 5 of GregorianToLunar | parameter | 32 | @@ -1646,11 +1742,11 @@ | Parameter 5 of TranscodeToUtf8 | parameter | 32 | | Parameter 5 of TranscodeToUtf16 | parameter | 32 | | Parameter 5 of TryDigitGenShortest | parameter | 32 | +| Parameter 5 of TryFormatInt32 | parameter | 32 | | Parameter 5 of TryParseAsSpecialFloatingPoint | parameter | 32 | | Parameter 5 of TryParseByName | parameter | 32 | | Parameter 5 of TryParseExact | parameter | 32 | | Parameter 5 of TryParseExactMultiple | parameter | 32 | -| Parameter 5 of TryParseGuidCore | parameter | 32 | | Parameter 5 of TryParseInt64Enum | parameter | 32 | | Parameter 5 of TryParseRareEnum | parameter | 32 | | Parameter 5 of TryParseUInt64Enum | parameter | 32 | @@ -1660,7 +1756,6 @@ | Parameter 5 of _GetMarshalAs | parameter | 32 | | Parameter 5 of _GetPropertyOrFieldData | parameter | 32 | | Parameter 6 of AssignAssociates | parameter | 32 | -| Parameter 6 of BeginInvoke | parameter | 32 | | Parameter 6 of Bind | parameter | 32 | | Parameter 6 of Convert | parameter | 32 | | Parameter 6 of Deconstruct | parameter | 32 | @@ -1703,7 +1798,6 @@ | Parameter 8 of TryParseInt32Enum | parameter | 32 | | Parameter 8 of _GetMarshalAs | parameter | 32 | | Parameter 9 of AssignAssociates | parameter | 32 | -| Parameter 9 of BeginInvoke | parameter | 32 | | Parameter 9 of Convert | parameter | 32 | | Parameter 9 of Deconstruct | parameter | 32 | | Parameter 9 of FilterCustomAttributeRecord | parameter | 32 | @@ -1712,15 +1806,12 @@ | Parameter 9 of TryToDateTime | parameter | 32 | | Parameter 9 of _GetMarshalAs | parameter | 32 | | Parameter 10 of AssignAssociates | parameter | 32 | -| Parameter 10 of BeginInvoke | parameter | 32 | | Parameter 10 of Convert | parameter | 32 | | Parameter 10 of Deconstruct | parameter | 32 | -| Parameter 10 of FilterCustomAttributeRecord | parameter | 32 | | Parameter 10 of Invoke | parameter | 32 | | Parameter 10 of TryCreateDateTimeOffset | parameter | 32 | | Parameter 10 of _GetMarshalAs | parameter | 32 | | Parameter 11 of AssignAssociates | parameter | 32 | -| Parameter 11 of BeginInvoke | parameter | 32 | | Parameter 11 of Deconstruct | parameter | 32 | | Parameter 11 of Invoke | parameter | 32 | | Parameter 12 of Deconstruct | parameter | 32 | @@ -1733,6 +1824,10 @@ | Parameter 19 of Deconstruct | parameter | 32 | | Parameter 20 of Deconstruct | parameter | 32 | | Parameter 21 of Deconstruct | parameter | 32 | +| TableData | method | 32 | +| ThrowArrayMismatchException | method | 32 | +| Unbox | method | 32 | +| Unbox_Helper | method | 32 | | get_Current | method | 32 | | get_EventHandle | method | 32 | | get_Item | method | 32 | diff --git a/csharp/ql/test/library-tests/commons/TargetFramework/HasElement.ql b/csharp/ql/test/library-tests/commons/TargetFramework/HasElement.ql index 1a0194bb901..50057df4904 100644 --- a/csharp/ql/test/library-tests/commons/TargetFramework/HasElement.ql +++ b/csharp/ql/test/library-tests/commons/TargetFramework/HasElement.ql @@ -2,5 +2,5 @@ import csharp import semmle.code.csharp.commons.TargetFramework from TargetFrameworkAttribute target, Class c -where target.hasElement(c) +where target.hasElement(c) and target.fromSource() select c, target diff --git a/csharp/ql/test/library-tests/commons/TargetFramework/NetCore.ql b/csharp/ql/test/library-tests/commons/TargetFramework/NetCore.ql index 486dcf8491d..9ec6896629f 100644 --- a/csharp/ql/test/library-tests/commons/TargetFramework/NetCore.ql +++ b/csharp/ql/test/library-tests/commons/TargetFramework/NetCore.ql @@ -2,5 +2,5 @@ import csharp import semmle.code.csharp.commons.TargetFramework from TargetFrameworkAttribute target -where target.isNetCore() +where target.isNetCore() and target.fromSource() select target diff --git a/csharp/ql/test/library-tests/commons/TargetFramework/TargetFrameworks.ql b/csharp/ql/test/library-tests/commons/TargetFramework/TargetFrameworks.ql index eefc403351f..85adee6a0a0 100644 --- a/csharp/ql/test/library-tests/commons/TargetFramework/TargetFrameworks.ql +++ b/csharp/ql/test/library-tests/commons/TargetFramework/TargetFrameworks.ql @@ -2,4 +2,5 @@ import csharp import semmle.code.csharp.commons.TargetFramework from TargetFrameworkAttribute target +where target.fromSource() select target, target.getFrameworkType(), target.getFrameworkVersion() diff --git a/csharp/ql/test/library-tests/dataflow/library/FlowSummaries.expected b/csharp/ql/test/library-tests/dataflow/library/FlowSummaries.expected index fe62037b779..8ea7f7d9875 100644 --- a/csharp/ql/test/library-tests/dataflow/library/FlowSummaries.expected +++ b/csharp/ql/test/library-tests/dataflow/library/FlowSummaries.expected @@ -257,8 +257,8 @@ | System.Collections.Concurrent.ConcurrentStack<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | | System.Collections.Concurrent.IProducerConsumerCollection<>.CopyTo(T[], int) | this parameter [[]] -> parameter 0 [[]] | true | | System.Collections.Concurrent.OrderablePartitioner<>.EnumerableDropIndices.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Concurrent.Partitioner.d__6.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Collections.Concurrent.Partitioner.d__9.GetEnumerator() | this parameter [[]] -> return [Current] | true | +| System.Collections.Concurrent.Partitioner.d__7.GetEnumerator() | this parameter [[]] -> return [Current] | true | +| System.Collections.Concurrent.Partitioner.d__10.GetEnumerator() | this parameter [[]] -> return [Current] | true | | System.Collections.Concurrent.Partitioner.DynamicPartitionerForArray<>.InternalPartitionEnumerable.GetEnumerator() | this parameter [[]] -> return [Current] | true | | System.Collections.Concurrent.Partitioner.DynamicPartitionerForIEnumerable<>.InternalPartitionEnumerable.GetEnumerator() | this parameter [[]] -> return [Current] | true | | System.Collections.Concurrent.Partitioner.DynamicPartitionerForIList<>.InternalPartitionEnumerable.GetEnumerator() | this parameter [[]] -> return [Current] | true | @@ -432,7 +432,7 @@ | System.Collections.Generic.SortedList<,>.set_Item(TKey, TValue) | parameter 1 -> this parameter [[], Value] | true | | System.Collections.Generic.SortedList<,>.set_Item(object, object) | parameter 0 -> this parameter [[], Key] | true | | System.Collections.Generic.SortedList<,>.set_Item(object, object) | parameter 1 -> this parameter [[], Value] | true | -| System.Collections.Generic.SortedSet<>.d__93.GetEnumerator() | this parameter [[]] -> return [Current] | true | +| System.Collections.Generic.SortedSet<>.d__84.GetEnumerator() | this parameter [[]] -> return [Current] | true | | System.Collections.Generic.SortedSet<>.Add(T) | parameter 0 -> this parameter [[]] | true | | System.Collections.Generic.SortedSet<>.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | | System.Collections.Generic.SortedSet<>.CopyTo(T[], int) | this parameter [[]] -> parameter 0 [[]] | true | @@ -749,6 +749,8 @@ | System.Convert.ChangeType(object, TypeCode, IFormatProvider) | parameter 0 -> return | false | | System.Convert.FromBase64CharArray(Char[], int, int) | parameter 0 -> return | false | | System.Convert.FromBase64String(string) | parameter 0 -> return | false | +| System.Convert.FromHexString(ReadOnlySpan) | parameter 0 -> return | false | +| System.Convert.FromHexString(string) | parameter 0 -> return | false | | System.Convert.GetTypeCode(object) | parameter 0 -> return | false | | System.Convert.IsDBNull(object) | parameter 0 -> return | false | | System.Convert.ToBase64CharArray(Byte[], int, int, Char[], int) | parameter 0 -> return | false | @@ -867,6 +869,9 @@ | System.Convert.ToDouble(uint) | parameter 0 -> return | false | | System.Convert.ToDouble(ulong) | parameter 0 -> return | false | | System.Convert.ToDouble(ushort) | parameter 0 -> return | false | +| System.Convert.ToHexString(Byte[]) | parameter 0 -> return | false | +| System.Convert.ToHexString(Byte[], int, int) | parameter 0 -> return | false | +| System.Convert.ToHexString(ReadOnlySpan) | parameter 0 -> return | false | | System.Convert.ToInt16(DateTime) | parameter 0 -> return | false | | System.Convert.ToInt16(bool) | parameter 0 -> return | false | | System.Convert.ToInt16(byte) | parameter 0 -> return | false | @@ -1269,25 +1274,25 @@ | System.Lazy<>.Lazy(Func, bool) | deleget output from parameter 0 -> return [Value] | true | | System.Lazy<>.get_Value() | this parameter -> return | false | | System.Linq.EmptyPartition<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Enumerable.d__63<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Enumerable.d__80<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Enumerable.d__97<,,,>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Enumerable.d__100<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Enumerable.d__104<,,,>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Enumerable.d__61<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Enumerable.d__173<,>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Enumerable.d__176<,>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Enumerable.d__178<,,>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Enumerable.d__180<,,>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Enumerable.d__193<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Enumerable.d__189<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Enumerable.d__191<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Enumerable.d__220<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Enumerable.d__216<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Enumerable.d__218<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Enumerable.d__239<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Enumerable.d__242<,>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Linq.Enumerable.d__243<,,>.GetEnumerator() | this parameter [[]] -> return [Current] | true | +| System.Linq.Enumerable.d__64<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | +| System.Linq.Enumerable.d__81<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | +| System.Linq.Enumerable.d__98<,,,>.GetEnumerator() | this parameter [[]] -> return [Current] | true | +| System.Linq.Enumerable.d__101<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | +| System.Linq.Enumerable.d__105<,,,>.GetEnumerator() | this parameter [[]] -> return [Current] | true | +| System.Linq.Enumerable.d__62<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | +| System.Linq.Enumerable.d__174<,>.GetEnumerator() | this parameter [[]] -> return [Current] | true | +| System.Linq.Enumerable.d__177<,>.GetEnumerator() | this parameter [[]] -> return [Current] | true | +| System.Linq.Enumerable.d__179<,,>.GetEnumerator() | this parameter [[]] -> return [Current] | true | +| System.Linq.Enumerable.d__181<,,>.GetEnumerator() | this parameter [[]] -> return [Current] | true | +| System.Linq.Enumerable.d__194<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | +| System.Linq.Enumerable.d__190<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | +| System.Linq.Enumerable.d__192<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | +| System.Linq.Enumerable.d__221<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | +| System.Linq.Enumerable.d__217<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | +| System.Linq.Enumerable.d__219<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | +| System.Linq.Enumerable.d__240<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | +| System.Linq.Enumerable.d__243<,>.GetEnumerator() | this parameter [[]] -> return [Current] | true | +| System.Linq.Enumerable.d__244<,,>.GetEnumerator() | this parameter [[]] -> return [Current] | true | | System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func, Func) | deleget output from parameter 2 -> parameter 0 of delegate parameter 3 | true | | System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func, Func) | deleget output from parameter 3 -> return | true | | System.Linq.Enumerable.Aggregate(IEnumerable, TAccumulate, Func, Func) | parameter 0 [[]] -> parameter 1 of delegate parameter 2 | true | @@ -1986,7 +1991,9 @@ | System.Net.Security.NegotiateStream.BeginRead(Byte[], int, int, AsyncCallback, object) | this parameter -> parameter 0 | false | | System.Net.Security.NegotiateStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | parameter 0 -> this parameter | false | | System.Net.Security.NegotiateStream.Read(Byte[], int, int) | this parameter -> parameter 0 | false | +| System.Net.Security.NegotiateStream.ReadAsync(Byte[], int, int, CancellationToken) | this parameter -> parameter 0 | false | | System.Net.Security.NegotiateStream.Write(Byte[], int, int) | parameter 0 -> this parameter | false | +| System.Net.Security.NegotiateStream.WriteAsync(Byte[], int, int, CancellationToken) | parameter 0 -> this parameter | false | | System.Net.Security.SslStream.BeginRead(Byte[], int, int, AsyncCallback, object) | this parameter -> parameter 0 | false | | System.Net.Security.SslStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | parameter 0 -> this parameter | false | | System.Net.Security.SslStream.Read(Byte[], int, int) | this parameter -> parameter 0 | false | @@ -2024,9 +2031,9 @@ | System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.set_Item(int, T) | parameter 1 -> this parameter [[]] | true | | System.Runtime.CompilerServices.ReadOnlyCollectionBuilder<>.set_Item(int, object) | parameter 1 -> this parameter [[]] | true | | System.Runtime.CompilerServices.TaskAwaiter<>.GetResult() | this parameter [m_task, Result] -> return | true | -| System.Runtime.InteropServices.MemoryMarshal.d__3<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Runtime.Loader.AssemblyLoadContext.d__88.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Runtime.Loader.AssemblyLoadContext.d__58.GetEnumerator() | this parameter [[]] -> return [Current] | true | +| System.Runtime.InteropServices.MemoryMarshal.d__15<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | +| System.Runtime.Loader.AssemblyLoadContext.d__83.GetEnumerator() | this parameter [[]] -> return [Current] | true | +| System.Runtime.Loader.AssemblyLoadContext.d__53.GetEnumerator() | this parameter [[]] -> return [Current] | true | | System.Runtime.Loader.LibraryNameVariation.d__5.GetEnumerator() | this parameter [[]] -> return [Current] | true | | System.Security.Cryptography.CryptoStream.BeginRead(Byte[], int, int, AsyncCallback, object) | this parameter -> parameter 0 | false | | System.Security.Cryptography.CryptoStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | parameter 0 -> this parameter | false | @@ -2181,8 +2188,8 @@ | System.Text.RegularExpressions.CaptureCollection.get_Item(int) | this parameter [[]] -> return | true | | System.Text.RegularExpressions.CaptureCollection.set_Item(int, Capture) | parameter 1 -> this parameter [[]] | true | | System.Text.RegularExpressions.CaptureCollection.set_Item(int, object) | parameter 1 -> this parameter [[]] | true | -| System.Text.RegularExpressions.GroupCollection.d__48.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Text.RegularExpressions.GroupCollection.d__50.GetEnumerator() | this parameter [[]] -> return [Current] | true | +| System.Text.RegularExpressions.GroupCollection.d__49.GetEnumerator() | this parameter [[]] -> return [Current] | true | +| System.Text.RegularExpressions.GroupCollection.d__51.GetEnumerator() | this parameter [[]] -> return [Current] | true | | System.Text.RegularExpressions.GroupCollection.Add(Group) | parameter 0 -> this parameter [[]] | true | | System.Text.RegularExpressions.GroupCollection.Add(object) | parameter 0 -> this parameter [[]] | true | | System.Text.RegularExpressions.GroupCollection.CopyTo(Array, int) | this parameter [[]] -> parameter 0 [[]] | true | @@ -2257,6 +2264,12 @@ | System.Text.StringBuilder.StringBuilder(string, int, int, int) | parameter 0 -> return [[]] | true | | System.Text.StringBuilder.ToString() | this parameter [[]] -> return | false | | System.Text.StringBuilder.ToString(int, int) | this parameter [[]] -> return | false | +| System.Text.TranscodingStream.BeginRead(Byte[], int, int, AsyncCallback, object) | this parameter -> parameter 0 | false | +| System.Text.TranscodingStream.BeginWrite(Byte[], int, int, AsyncCallback, object) | parameter 0 -> this parameter | false | +| System.Text.TranscodingStream.Read(Byte[], int, int) | this parameter -> parameter 0 | false | +| System.Text.TranscodingStream.ReadAsync(Byte[], int, int, CancellationToken) | this parameter -> parameter 0 | false | +| System.Text.TranscodingStream.Write(Byte[], int, int) | parameter 0 -> this parameter | false | +| System.Text.TranscodingStream.WriteAsync(Byte[], int, int, CancellationToken) | parameter 0 -> this parameter | false | | System.Threading.Tasks.SingleProducerSingleConsumerQueue<>.GetEnumerator() | this parameter [[]] -> return [Current] | true | | System.Threading.Tasks.Task.ContinueWith(Action, object) | parameter 1 -> parameter 1 of delegate parameter 0 | true | | System.Threading.Tasks.Task.ContinueWith(Action, object, CancellationToken) | parameter 1 -> parameter 1 of delegate parameter 0 | true | @@ -2290,6 +2303,8 @@ | System.Threading.Tasks.Task.WhenAll(IEnumerable>) | parameter 0 [[], Result] -> return [Result, []] | true | | System.Threading.Tasks.Task.WhenAll(params Task[]) | parameter 0 [[], Result] -> return [Result, []] | true | | System.Threading.Tasks.Task.WhenAny(IEnumerable>) | parameter 0 [[], Result] -> return [Result, []] | true | +| System.Threading.Tasks.Task.WhenAny(Task, Task) | parameter 0 [[], Result] -> return [Result, []] | true | +| System.Threading.Tasks.Task.WhenAny(Task, Task) | parameter 1 [[], Result] -> return [Result, []] | true | | System.Threading.Tasks.Task.WhenAny(params Task[]) | parameter 0 [[], Result] -> return [Result, []] | true | | System.Threading.Tasks.Task<>.ConfigureAwait(bool) | this parameter -> return [m_configuredTaskAwaiter, m_task] | true | | System.Threading.Tasks.Task<>.ContinueWith(Action, Object>, object) | parameter 1 -> parameter 1 of delegate parameter 0 | true | @@ -2431,8 +2446,8 @@ | System.Threading.Tasks.TaskFactory<>.StartNew(Func, CancellationToken, TaskCreationOptions, TaskScheduler) | deleget output from parameter 0 -> return [Result] | true | | System.Threading.Tasks.TaskFactory<>.StartNew(Func, TaskCreationOptions) | deleget output from parameter 0 -> return [Result] | true | | System.Threading.Tasks.ThreadPoolTaskScheduler.d__6.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Threading.ThreadPool.d__51.GetEnumerator() | this parameter [[]] -> return [Current] | true | -| System.Threading.ThreadPool.d__50.GetEnumerator() | this parameter [[]] -> return [Current] | true | +| System.Threading.ThreadPool.d__52.GetEnumerator() | this parameter [[]] -> return [Current] | true | +| System.Threading.ThreadPool.d__51.GetEnumerator() | this parameter [[]] -> return [Current] | true | | System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 0 -> return [Item1] | true | | System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 1 -> return [Item2] | true | | System.Tuple.Create(T1, T2, T3, T4, T5, T6, T7, T8) | parameter 2 -> return [Item3] | true | diff --git a/csharp/ql/test/query-tests/Stubs/MinimalStubsFromSource.expected b/csharp/ql/test/query-tests/Stubs/MinimalStubsFromSource.expected index 2bc65fe4614..d2dd3037e3c 100644 --- a/csharp/ql/test/query-tests/Stubs/MinimalStubsFromSource.expected +++ b/csharp/ql/test/query-tests/Stubs/MinimalStubsFromSource.expected @@ -1 +1 @@ -| // This file contains auto-generated code.\n// original-extractor-options: /r:System.Text.RegularExpressions.dll /r:System.Collections.Specialized.dll /r:System.Net.dll /r:System.Web.dll /r:System.Net.HttpListener.dll /r:System.Collections.Specialized.dll /r:System.Private.Uri.dll /r:System.Runtime.Extensions.dll /r:System.Linq.Parallel.dll /r:System.Collections.Concurrent.dll /r:System.Linq.Expressions.dll /r:System.Collections.dll /r:System.Linq.Queryable.dll /r:System.Linq.dll /r:System.Collections.NonGeneric.dll /r:System.ObjectModel.dll /r:System.ComponentModel.TypeConverter.dll /r:System.IO.Compression.dll /r:System.IO.Pipes.dll /r:System.Net.Primitives.dll /r:System.Net.Security.dll /r:System.Security.Cryptography.Primitives.dll /r:System.Text.RegularExpressions.dll ${testdir}/../../resources/stubs/System.Web.cs /r:System.Runtime.Serialization.Primitives.dll\n\nnamespace System\n{\n// Generated from `System.Uri` in `System.Private.Uri, Version=4.0.6.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class Uri : System.Runtime.Serialization.ISerializable\n{\n public override bool Equals(object comparand) => throw null;\n public override int GetHashCode() => throw null;\n public override string ToString() => throw null;\n void System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo serializationInfo, System.Runtime.Serialization.StreamingContext streamingContext) => throw null;\n}\n\nnamespace Collections\n{\n// Generated from `System.Collections.Queue` in `System.Collections.NonGeneric, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class Queue : System.ICloneable, System.Collections.IEnumerable, System.Collections.ICollection\n{\n public virtual System.Collections.IEnumerator GetEnumerator() => throw null;\n public virtual bool IsSynchronized { get => throw null; }\n public virtual int Count { get => throw null; }\n public virtual object Clone() => throw null;\n public virtual object SyncRoot { get => throw null; }\n public virtual void CopyTo(System.Array array, int index) => throw null;\n}\n\n// Generated from `System.Collections.SortedList` in `System.Collections.NonGeneric, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class SortedList : System.ICloneable, System.Collections.IEnumerable, System.Collections.IDictionary, System.Collections.ICollection\n{\n System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => throw null;\n public virtual System.Collections.ICollection Keys { get => throw null; }\n public virtual System.Collections.ICollection Values { get => throw null; }\n public virtual System.Collections.IDictionaryEnumerator GetEnumerator() => throw null;\n public virtual bool Contains(object key) => throw null;\n public virtual bool IsFixedSize { get => throw null; }\n public virtual bool IsReadOnly { get => throw null; }\n public virtual bool IsSynchronized { get => throw null; }\n public virtual int Count { get => throw null; }\n public virtual object Clone() => throw null;\n public virtual object GetByIndex(int index) => throw null;\n public virtual object SyncRoot { get => throw null; }\n public virtual object this[object key] { get => throw null; set => throw null; }\n public virtual void Add(object key, object value) => throw null;\n public virtual void Clear() => throw null;\n public virtual void CopyTo(System.Array array, int arrayIndex) => throw null;\n public virtual void Remove(object key) => throw null;\n}\n\n// Generated from `System.Collections.Stack` in `System.Collections.NonGeneric, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class Stack : System.ICloneable, System.Collections.IEnumerable, System.Collections.ICollection\n{\n public virtual System.Collections.IEnumerator GetEnumerator() => throw null;\n public virtual bool IsSynchronized { get => throw null; }\n public virtual int Count { get => throw null; }\n public virtual object Clone() => throw null;\n public virtual object SyncRoot { get => throw null; }\n public virtual void CopyTo(System.Array array, int index) => throw null;\n}\n\nnamespace Concurrent\n{\n// Generated from `System.Collections.Concurrent.BlockingCollection<>` in `System.Collections.Concurrent, Version=4.0.15.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class BlockingCollection : System.IDisposable, System.Collections.IEnumerable, System.Collections.ICollection, System.Collections.Generic.IReadOnlyCollection, System.Collections.Generic.IEnumerable\n{\n System.Collections.Generic.IEnumerator System.Collections.Generic.IEnumerable.GetEnumerator() => throw null;\n System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => throw null;\n bool System.Collections.ICollection.IsSynchronized { get => throw null; }\n object System.Collections.ICollection.SyncRoot { get => throw null; }\n public int Count { get => throw null; }\n public void Dispose() => throw null;\n void System.Collections.ICollection.CopyTo(System.Array array, int index) => throw null;\n}\n\n// Generated from `System.Collections.Concurrent.BlockingCollectionDebugView<>` in `System.Collections.Concurrent, Version=4.0.15.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nclass BlockingCollectionDebugView\n{\n}\n\n// Generated from `System.Collections.Concurrent.ConcurrentDictionary<,>` in `System.Collections.Concurrent, Version=4.0.15.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class ConcurrentDictionary : System.Collections.IEnumerable, System.Collections.IDictionary, System.Collections.ICollection, System.Collections.Generic.IReadOnlyDictionary, System.Collections.Generic.IReadOnlyCollection>, System.Collections.Generic.IEnumerable>, System.Collections.Generic.IDictionary, System.Collections.Generic.ICollection>\n{\n System.Collections.Generic.IEnumerable System.Collections.Generic.IReadOnlyDictionary.Keys { get => throw null; }\n System.Collections.Generic.IEnumerable System.Collections.Generic.IReadOnlyDictionary.Values { get => throw null; }\n System.Collections.ICollection System.Collections.IDictionary.Keys { get => throw null; }\n System.Collections.ICollection System.Collections.IDictionary.Values { get => throw null; }\n System.Collections.IDictionaryEnumerator System.Collections.IDictionary.GetEnumerator() => throw null;\n System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => throw null;\n bool System.Collections.Generic.ICollection>.Contains(System.Collections.Generic.KeyValuePair keyValuePair) => throw null;\n bool System.Collections.Generic.ICollection>.IsReadOnly { get => throw null; }\n bool System.Collections.Generic.ICollection>.Remove(System.Collections.Generic.KeyValuePair keyValuePair) => throw null;\n bool System.Collections.Generic.IDictionary.Remove(TKey key) => throw null;\n bool System.Collections.ICollection.IsSynchronized { get => throw null; }\n bool System.Collections.IDictionary.Contains(object key) => throw null;\n bool System.Collections.IDictionary.IsFixedSize { get => throw null; }\n bool System.Collections.IDictionary.IsReadOnly { get => throw null; }\n object System.Collections.ICollection.SyncRoot { get => throw null; }\n object this[object key] { get => throw null; set => throw null; }\n public System.Collections.Generic.ICollection Keys { get => throw null; }\n public System.Collections.Generic.ICollection Values { get => throw null; }\n public System.Collections.Generic.IEnumerator> GetEnumerator() => throw null;\n public TValue this[TKey key] { get => throw null; set => throw null; }\n public bool ContainsKey(TKey key) => throw null;\n public bool TryGetValue(TKey key, out TValue value) => throw null;\n public int Count { get => throw null; }\n public void Clear() => throw null;\n void System.Collections.Generic.ICollection>.Add(System.Collections.Generic.KeyValuePair keyValuePair) => throw null;\n void System.Collections.Generic.ICollection>.CopyTo(System.Collections.Generic.KeyValuePair[] array, int index) => throw null;\n void System.Collections.Generic.IDictionary.Add(TKey key, TValue value) => throw null;\n void System.Collections.ICollection.CopyTo(System.Array array, int index) => throw null;\n void System.Collections.IDictionary.Add(object key, object value) => throw null;\n void System.Collections.IDictionary.Remove(object key) => throw null;\n}\n\n// Generated from `System.Collections.Concurrent.IDictionaryDebugView<,>` in `System.Collections.Concurrent, Version=4.0.15.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nclass IDictionaryDebugView\n{\n}\n\n}\nnamespace Generic\n{\n// Generated from `System.Collections.Generic.CollectionDebugView<>` in `System.ObjectModel, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nclass CollectionDebugView\n{\n}\n\n// Generated from `System.Collections.Generic.DictionaryDebugView<,>` in `System.ObjectModel, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nclass DictionaryDebugView\n{\n}\n\n// Generated from `System.Collections.Generic.QueueDebugView<>` in `System.Collections, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nclass QueueDebugView\n{\n}\n\n// Generated from `System.Collections.Generic.SortedSet<>` in `System.Collections, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class SortedSet : System.Runtime.Serialization.ISerializable, System.Runtime.Serialization.IDeserializationCallback, System.Collections.IEnumerable, System.Collections.ICollection, System.Collections.Generic.ISet, System.Collections.Generic.IReadOnlyCollection, System.Collections.Generic.IEnumerable, System.Collections.Generic.ICollection\n{\n System.Collections.Generic.IEnumerator System.Collections.Generic.IEnumerable.GetEnumerator() => throw null;\n System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => throw null;\n bool System.Collections.Generic.ICollection.IsReadOnly { get => throw null; }\n bool System.Collections.ICollection.IsSynchronized { get => throw null; }\n object System.Collections.ICollection.SyncRoot { get => throw null; }\n public bool Add(T item) => throw null;\n public bool IsProperSubsetOf(System.Collections.Generic.IEnumerable other) => throw null;\n public bool IsProperSupersetOf(System.Collections.Generic.IEnumerable other) => throw null;\n public bool IsSubsetOf(System.Collections.Generic.IEnumerable other) => throw null;\n public bool IsSupersetOf(System.Collections.Generic.IEnumerable other) => throw null;\n public bool Overlaps(System.Collections.Generic.IEnumerable other) => throw null;\n public bool Remove(T item) => throw null;\n public bool SetEquals(System.Collections.Generic.IEnumerable other) => throw null;\n public int Count { get => throw null; }\n public virtual bool Contains(T item) => throw null;\n public virtual void Clear() => throw null;\n public virtual void IntersectWith(System.Collections.Generic.IEnumerable other) => throw null;\n public void CopyTo(T[] array, int index) => throw null;\n public void ExceptWith(System.Collections.Generic.IEnumerable other) => throw null;\n public void SymmetricExceptWith(System.Collections.Generic.IEnumerable other) => throw null;\n public void UnionWith(System.Collections.Generic.IEnumerable other) => throw null;\n void System.Collections.Generic.ICollection.Add(T item) => throw null;\n void System.Collections.ICollection.CopyTo(System.Array array, int index) => throw null;\n void System.Runtime.Serialization.IDeserializationCallback.OnDeserialization(object sender) => throw null;\n void System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) => throw null;\n}\n\n// Generated from `System.Collections.Generic.Stack<>` in `System.Collections, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class Stack : System.Collections.IEnumerable, System.Collections.ICollection, System.Collections.Generic.IReadOnlyCollection, System.Collections.Generic.IEnumerable\n{\n System.Collections.Generic.IEnumerator System.Collections.Generic.IEnumerable.GetEnumerator() => throw null;\n System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => throw null;\n bool System.Collections.ICollection.IsSynchronized { get => throw null; }\n object System.Collections.ICollection.SyncRoot { get => throw null; }\n public T Peek() => throw null;\n public int Count { get => throw null; }\n void System.Collections.ICollection.CopyTo(System.Array array, int arrayIndex) => throw null;\n}\n\n// Generated from `System.Collections.Generic.StackDebugView<>` in `System.Collections, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nclass StackDebugView\n{\n}\n\n}\nnamespace Specialized\n{\n// Generated from `System.Collections.Specialized.NameObjectCollectionBase` in `System.Collections.Specialized, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nabstract public class NameObjectCollectionBase : System.Runtime.Serialization.ISerializable, System.Runtime.Serialization.IDeserializationCallback, System.Collections.IEnumerable, System.Collections.ICollection\n{\n bool System.Collections.ICollection.IsSynchronized { get => throw null; }\n object System.Collections.ICollection.SyncRoot { get => throw null; }\n public virtual System.Collections.IEnumerator GetEnumerator() => throw null;\n public virtual int Count { get => throw null; }\n public virtual void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) => throw null;\n public virtual void OnDeserialization(object sender) => throw null;\n void System.Collections.ICollection.CopyTo(System.Array array, int index) => throw null;\n}\n\n// Generated from `System.Collections.Specialized.NameValueCollection` in `System.Collections.Specialized, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class NameValueCollection : System.Collections.Specialized.NameObjectCollectionBase\n{\n public string this[string name] { get => throw null; set => throw null; }\n}\n\n}\n}\nnamespace ComponentModel\n{\n// Generated from `System.ComponentModel.ComponentConverter` in `System.ComponentModel.TypeConverter, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class ComponentConverter : System.ComponentModel.ReferenceConverter\n{\n}\n\n// Generated from `System.ComponentModel.DefaultEventAttribute` in `System.ComponentModel.TypeConverter, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class DefaultEventAttribute : System.Attribute\n{\n public DefaultEventAttribute(string name) => throw null;\n public override bool Equals(object obj) => throw null;\n public override int GetHashCode() => throw null;\n}\n\n// Generated from `System.ComponentModel.DefaultPropertyAttribute` in `System.ComponentModel.TypeConverter, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class DefaultPropertyAttribute : System.Attribute\n{\n public DefaultPropertyAttribute(string name) => throw null;\n public override bool Equals(object obj) => throw null;\n public override int GetHashCode() => throw null;\n}\n\n// Generated from `System.ComponentModel.DesignerAttribute` in `System.ComponentModel.TypeConverter, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class DesignerAttribute : System.Attribute\n{\n public DesignerAttribute(System.Type designerType) => throw null;\n public DesignerAttribute(System.Type designerType, System.Type designerBaseType) => throw null;\n public DesignerAttribute(string designerTypeName) => throw null;\n public DesignerAttribute(string designerTypeName, System.Type designerBaseType) => throw null;\n public DesignerAttribute(string designerTypeName, string designerBaseTypeName) => throw null;\n public override bool Equals(object obj) => throw null;\n public override int GetHashCode() => throw null;\n public override object TypeId { get => throw null; }\n}\n\n// Generated from `System.ComponentModel.INotifyPropertyChanged` in `System.ObjectModel, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic interface INotifyPropertyChanged\n{\n}\n\n// Generated from `System.ComponentModel.ReferenceConverter` in `System.ComponentModel.TypeConverter, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class ReferenceConverter : System.ComponentModel.TypeConverter\n{\n}\n\n// Generated from `System.ComponentModel.TypeConverterAttribute` in `System.ObjectModel, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class TypeConverterAttribute : System.Attribute\n{\n public TypeConverterAttribute() => throw null;\n public TypeConverterAttribute(System.Type type) => throw null;\n public TypeConverterAttribute(string typeName) => throw null;\n public override bool Equals(object obj) => throw null;\n public override int GetHashCode() => throw null;\n}\n\n// Generated from `System.ComponentModel.TypeConverter` in `System.ComponentModel.TypeConverter, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class TypeConverter\n{\n}\n\n// Generated from `System.ComponentModel.TypeDescriptionProviderAttribute` in `System.ObjectModel, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class TypeDescriptionProviderAttribute : System.Attribute\n{\n public TypeDescriptionProviderAttribute(System.Type type) => throw null;\n public TypeDescriptionProviderAttribute(string typeName) => throw null;\n}\n\n// Generated from `System.ComponentModel.TypeDescriptionProvider` in `System.ComponentModel.TypeConverter, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nabstract public class TypeDescriptionProvider\n{\n}\n\n// Generated from `System.ComponentModel.TypeDescriptor` in `System.ComponentModel.TypeConverter, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class TypeDescriptor\n{\n}\n\nnamespace Design\n{\n// Generated from `System.ComponentModel.Design.DesignerOptionService` in `System.ComponentModel.TypeConverter, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nabstract public class DesignerOptionService : System.ComponentModel.Design.IDesignerOptionService\n{\n}\n\n// Generated from `System.ComponentModel.Design.IDesignerOptionService` in `System.ComponentModel.TypeConverter, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic interface IDesignerOptionService\n{\n}\n\n// Generated from `System.ComponentModel.Design.IDesigner` in `System.ComponentModel.TypeConverter, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic interface IDesigner : System.IDisposable\n{\n}\n\n// Generated from `System.ComponentModel.Design.IRootDesigner` in `System.ComponentModel.TypeConverter, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic interface IRootDesigner : System.IDisposable, System.ComponentModel.Design.IDesigner\n{\n}\n\n}\n}\nnamespace Dynamic\n{\n// Generated from `System.Dynamic.BindingRestrictions` in `System.Linq.Expressions, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nabstract public class BindingRestrictions\n{\n}\n\n// Generated from `System.Dynamic.DynamicMetaObject` in `System.Linq.Expressions, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class DynamicMetaObject\n{\n}\n\n// Generated from `System.Dynamic.ExpandoObject` in `System.Linq.Expressions, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class ExpandoObject : System.Dynamic.IDynamicMetaObjectProvider, System.ComponentModel.INotifyPropertyChanged, System.Collections.IEnumerable, System.Collections.Generic.IEnumerable>, System.Collections.Generic.IDictionary, System.Collections.Generic.ICollection>\n{\n System.Collections.Generic.ICollection System.Collections.Generic.IDictionary.Values { get => throw null; }\n System.Collections.Generic.ICollection System.Collections.Generic.IDictionary.Keys { get => throw null; }\n System.Collections.Generic.IEnumerator> System.Collections.Generic.IEnumerable>.GetEnumerator() => throw null;\n System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => throw null;\n bool System.Collections.Generic.ICollection>.Contains(System.Collections.Generic.KeyValuePair item) => throw null;\n bool System.Collections.Generic.ICollection>.IsReadOnly { get => throw null; }\n bool System.Collections.Generic.ICollection>.Remove(System.Collections.Generic.KeyValuePair item) => throw null;\n bool System.Collections.Generic.IDictionary.ContainsKey(string key) => throw null;\n bool System.Collections.Generic.IDictionary.Remove(string key) => throw null;\n bool System.Collections.Generic.IDictionary.TryGetValue(string key, out object value) => throw null;\n int System.Collections.Generic.ICollection>.Count { get => throw null; }\n object this[string key] { get => throw null; set => throw null; }\n void System.Collections.Generic.ICollection>.Add(System.Collections.Generic.KeyValuePair item) => throw null;\n void System.Collections.Generic.ICollection>.Clear() => throw null;\n void System.Collections.Generic.ICollection>.CopyTo(System.Collections.Generic.KeyValuePair[] array, int arrayIndex) => throw null;\n void System.Collections.Generic.IDictionary.Add(string key, object value) => throw null;\n}\n\n// Generated from `System.Dynamic.IDynamicMetaObjectProvider` in `System.Linq.Expressions, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic interface IDynamicMetaObjectProvider\n{\n}\n\nnamespace Utils\n{\n// Generated from `System.Dynamic.Utils.ListProvider<>` in `System.Linq.Expressions, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nabstract class ListProvider : System.Collections.IEnumerable, System.Collections.Generic.IList, System.Collections.Generic.IEnumerable, System.Collections.Generic.ICollection where T: class\n{\n System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => throw null;\n public System.Collections.Generic.IEnumerator GetEnumerator() => throw null;\n public T this[int index] { get => throw null; set => throw null; }\n public bool Contains(T item) => throw null;\n public bool IsReadOnly { get => throw null; }\n public bool Remove(T item) => throw null;\n public int Count { get => throw null; }\n public int IndexOf(T item) => throw null;\n public void Add(T item) => throw null;\n public void Clear() => throw null;\n public void CopyTo(T[] array, int index) => throw null;\n public void Insert(int index, T item) => throw null;\n public void RemoveAt(int index) => throw null;\n}\n\n}\n}\nnamespace IO\n{\n// Generated from `System.IO.BufferedStream` in `System.Runtime.Extensions, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class BufferedStream : System.IO.Stream\n{\n protected override void Dispose(bool disposing) => throw null;\n public override System.IAsyncResult BeginRead(System.Byte[] buffer, int offset, int count, System.AsyncCallback callback, object state) => throw null;\n public override System.IAsyncResult BeginWrite(System.Byte[] buffer, int offset, int count, System.AsyncCallback callback, object state) => throw null;\n public override System.Int64 Length { get => throw null; }\n public override System.Int64 Position { get => throw null; set => throw null; }\n public override System.Int64 Seek(System.Int64 offset, System.IO.SeekOrigin origin) => throw null;\n public override System.Threading.Tasks.Task CopyToAsync(System.IO.Stream destination, int bufferSize, System.Threading.CancellationToken cancellationToken) => throw null;\n public override System.Threading.Tasks.Task FlushAsync(System.Threading.CancellationToken cancellationToken) => throw null;\n public override System.Threading.Tasks.Task WriteAsync(System.Byte[] buffer, int offset, int count, System.Threading.CancellationToken cancellationToken) => throw null;\n public override System.Threading.Tasks.Task ReadAsync(System.Byte[] buffer, int offset, int count, System.Threading.CancellationToken cancellationToken) => throw null;\n public override System.Threading.Tasks.ValueTask DisposeAsync() => throw null;\n public override System.Threading.Tasks.ValueTask WriteAsync(System.ReadOnlyMemory buffer, System.Threading.CancellationToken cancellationToken) => throw null;\n public override System.Threading.Tasks.ValueTask ReadAsync(System.Memory buffer, System.Threading.CancellationToken cancellationToken) => throw null;\n public override bool CanRead { get => throw null; }\n public override bool CanSeek { get => throw null; }\n public override bool CanWrite { get => throw null; }\n public override int EndRead(System.IAsyncResult asyncResult) => throw null;\n public override int Read(System.Byte[] array, int offset, int count) => throw null;\n public override int Read(System.Span destination) => throw null;\n public override int ReadByte() => throw null;\n public override void CopyTo(System.IO.Stream destination, int bufferSize) => throw null;\n public override void EndWrite(System.IAsyncResult asyncResult) => throw null;\n public override void Flush() => throw null;\n public override void SetLength(System.Int64 value) => throw null;\n public override void Write(System.Byte[] array, int offset, int count) => throw null;\n public override void Write(System.ReadOnlySpan buffer) => throw null;\n public override void WriteByte(System.Byte value) => throw null;\n}\n\n// Generated from `System.IO.StringReader` in `System.Runtime.Extensions, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class StringReader : System.IO.TextReader\n{\n protected override void Dispose(bool disposing) => throw null;\n public StringReader(string s) => throw null;\n public override System.Threading.Tasks.Task ReadAsync(System.Char[] buffer, int index, int count) => throw null;\n public override System.Threading.Tasks.Task ReadBlockAsync(System.Char[] buffer, int index, int count) => throw null;\n public override System.Threading.Tasks.Task ReadLineAsync() => throw null;\n public override System.Threading.Tasks.Task ReadToEndAsync() => throw null;\n public override System.Threading.Tasks.ValueTask ReadAsync(System.Memory buffer, System.Threading.CancellationToken cancellationToken) => throw null;\n public override System.Threading.Tasks.ValueTask ReadBlockAsync(System.Memory buffer, System.Threading.CancellationToken cancellationToken) => throw null;\n public override int Peek() => throw null;\n public override int Read() => throw null;\n public override int Read(System.Char[] buffer, int index, int count) => throw null;\n public override int Read(System.Span buffer) => throw null;\n public override int ReadBlock(System.Span buffer) => throw null;\n public override string ReadLine() => throw null;\n public override string ReadToEnd() => throw null;\n public override void Close() => throw null;\n}\n\nnamespace Compression\n{\n// Generated from `System.IO.Compression.DeflateStream` in `System.IO.Compression, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b77a5c561934e089`\npublic class DeflateStream : System.IO.Stream\n{\n protected override void Dispose(bool disposing) => throw null;\n public override System.IAsyncResult BeginRead(System.Byte[] buffer, int offset, int count, System.AsyncCallback asyncCallback, object asyncState) => throw null;\n public override System.IAsyncResult BeginWrite(System.Byte[] array, int offset, int count, System.AsyncCallback asyncCallback, object asyncState) => throw null;\n public override System.Int64 Length { get => throw null; }\n public override System.Int64 Position { get => throw null; set => throw null; }\n public override System.Int64 Seek(System.Int64 offset, System.IO.SeekOrigin origin) => throw null;\n public override System.Threading.Tasks.Task CopyToAsync(System.IO.Stream destination, int bufferSize, System.Threading.CancellationToken cancellationToken) => throw null;\n public override System.Threading.Tasks.Task FlushAsync(System.Threading.CancellationToken cancellationToken) => throw null;\n public override System.Threading.Tasks.Task WriteAsync(System.Byte[] array, int offset, int count, System.Threading.CancellationToken cancellationToken) => throw null;\n public override System.Threading.Tasks.Task ReadAsync(System.Byte[] array, int offset, int count, System.Threading.CancellationToken cancellationToken) => throw null;\n public override System.Threading.Tasks.ValueTask DisposeAsync() => throw null;\n public override System.Threading.Tasks.ValueTask WriteAsync(System.ReadOnlyMemory buffer, System.Threading.CancellationToken cancellationToken) => throw null;\n public override System.Threading.Tasks.ValueTask ReadAsync(System.Memory buffer, System.Threading.CancellationToken cancellationToken) => throw null;\n public override bool CanRead { get => throw null; }\n public override bool CanSeek { get => throw null; }\n public override bool CanWrite { get => throw null; }\n public override int EndRead(System.IAsyncResult asyncResult) => throw null;\n public override int Read(System.Byte[] array, int offset, int count) => throw null;\n public override int Read(System.Span buffer) => throw null;\n public override int ReadByte() => throw null;\n public override void CopyTo(System.IO.Stream destination, int bufferSize) => throw null;\n public override void EndWrite(System.IAsyncResult asyncResult) => throw null;\n public override void Flush() => throw null;\n public override void SetLength(System.Int64 value) => throw null;\n public override void Write(System.Byte[] array, int offset, int count) => throw null;\n public override void Write(System.ReadOnlySpan buffer) => throw null;\n}\n\n}\n}\nnamespace Linq\n{\n// Generated from `System.Linq.Enumerable` in `System.Linq, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nstatic public class Enumerable\n{\n public static System.Collections.Generic.IEnumerable Select(this System.Collections.Generic.IEnumerable source, System.Func selector) => throw null;\n}\n\n// Generated from `System.Linq.Grouping<,>` in `System.Linq, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class Grouping : System.Linq.IGrouping, System.Collections.IEnumerable, System.Collections.Generic.IList, System.Collections.Generic.IEnumerable, System.Collections.Generic.ICollection\n{\n System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => throw null;\n TElement this[int index] { get => throw null; set => throw null; }\n bool System.Collections.Generic.ICollection.Contains(TElement item) => throw null;\n bool System.Collections.Generic.ICollection.IsReadOnly { get => throw null; }\n bool System.Collections.Generic.ICollection.Remove(TElement item) => throw null;\n int System.Collections.Generic.ICollection.Count { get => throw null; }\n int System.Collections.Generic.IList.IndexOf(TElement item) => throw null;\n public System.Collections.Generic.IEnumerator GetEnumerator() => throw null;\n void System.Collections.Generic.ICollection.Add(TElement item) => throw null;\n void System.Collections.Generic.ICollection.Clear() => throw null;\n void System.Collections.Generic.ICollection.CopyTo(TElement[] array, int arrayIndex) => throw null;\n void System.Collections.Generic.IList.Insert(int index, TElement item) => throw null;\n void System.Collections.Generic.IList.RemoveAt(int index) => throw null;\n}\n\n// Generated from `System.Linq.IGrouping<,>` in `System.Linq, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic interface IGrouping : System.Collections.IEnumerable, System.Collections.Generic.IEnumerable\n{\n}\n\n// Generated from `System.Linq.IIListProvider<>` in `System.Linq, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\ninterface IIListProvider : System.Collections.IEnumerable, System.Collections.Generic.IEnumerable\n{\n}\n\n// Generated from `System.Linq.ILookup<,>` in `System.Linq, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic interface ILookup : System.Collections.IEnumerable, System.Collections.Generic.IEnumerable>\n{\n}\n\n// Generated from `System.Linq.IOrderedEnumerable<>` in `System.Linq, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic interface IOrderedEnumerable : System.Collections.IEnumerable, System.Collections.Generic.IEnumerable\n{\n}\n\n// Generated from `System.Linq.IPartition<>` in `System.Linq, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\ninterface IPartition : System.Linq.IIListProvider, System.Collections.IEnumerable, System.Collections.Generic.IEnumerable\n{\n}\n\n// Generated from `System.Linq.IQueryable` in `System.Linq.Expressions, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic interface IQueryable : System.Collections.IEnumerable\n{\n}\n\n// Generated from `System.Linq.Lookup<,>` in `System.Linq, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class Lookup : System.Linq.ILookup, System.Linq.IIListProvider>, System.Collections.IEnumerable, System.Collections.Generic.IEnumerable>\n{\n System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => throw null;\n public System.Collections.Generic.IEnumerator> GetEnumerator() => throw null;\n}\n\n// Generated from `System.Linq.OrderedEnumerable<>` in `System.Linq, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nabstract class OrderedEnumerable : System.Linq.IPartition, System.Linq.IOrderedEnumerable, System.Linq.IIListProvider, System.Collections.IEnumerable, System.Collections.Generic.IEnumerable\n{\n System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => throw null;\n public System.Collections.Generic.IEnumerator GetEnumerator() => throw null;\n}\n\n// Generated from `System.Linq.ParallelEnumerable` in `System.Linq.Parallel, Version=4.0.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nstatic public class ParallelEnumerable\n{\n public static System.Linq.ParallelQuery AsParallel(this System.Collections.IEnumerable source) => throw null;\n}\n\n// Generated from `System.Linq.ParallelQuery<>` in `System.Linq.Parallel, Version=4.0.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class ParallelQuery : System.Linq.ParallelQuery, System.Collections.IEnumerable, System.Collections.Generic.IEnumerable\n{\n public virtual System.Collections.Generic.IEnumerator GetEnumerator() => throw null;\n}\n\n// Generated from `System.Linq.ParallelQuery` in `System.Linq.Parallel, Version=4.0.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class ParallelQuery : System.Collections.IEnumerable\n{\n System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => throw null;\n}\n\n// Generated from `System.Linq.Queryable` in `System.Linq.Queryable, Version=4.0.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nstatic public class Queryable\n{\n public static System.Linq.IQueryable AsQueryable(this System.Collections.IEnumerable source) => throw null;\n}\n\n// Generated from `System.Linq.SystemLinq_GroupingDebugView<,>` in `System.Linq, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nclass SystemLinq_GroupingDebugView\n{\n}\n\n// Generated from `System.Linq.SystemLinq_LookupDebugView<,>` in `System.Linq, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nclass SystemLinq_LookupDebugView\n{\n}\n\nnamespace Expressions\n{\n// Generated from `System.Linq.Expressions.BlockExpressionList` in `System.Linq.Expressions, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nclass BlockExpressionList : System.Collections.IEnumerable, System.Collections.Generic.IList, System.Collections.Generic.IEnumerable, System.Collections.Generic.ICollection\n{\n System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => throw null;\n public System.Collections.Generic.IEnumerator GetEnumerator() => throw null;\n public System.Linq.Expressions.Expression this[int index] { get => throw null; set => throw null; }\n public bool Contains(System.Linq.Expressions.Expression item) => throw null;\n public bool IsReadOnly { get => throw null; }\n public bool Remove(System.Linq.Expressions.Expression item) => throw null;\n public int Count { get => throw null; }\n public int IndexOf(System.Linq.Expressions.Expression item) => throw null;\n public void Add(System.Linq.Expressions.Expression item) => throw null;\n public void Clear() => throw null;\n public void CopyTo(System.Linq.Expressions.Expression[] array, int index) => throw null;\n public void Insert(int index, System.Linq.Expressions.Expression item) => throw null;\n public void RemoveAt(int index) => throw null;\n}\n\n// Generated from `System.Linq.Expressions.Expression` in `System.Linq.Expressions, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nabstract public class Expression\n{\n public override string ToString() => throw null;\n}\n\n// Generated from `System.Linq.Expressions.ParameterExpression` in `System.Linq.Expressions, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class ParameterExpression : System.Linq.Expressions.Expression\n{\n}\n\nnamespace Compiler\n{\n// Generated from `System.Linq.Expressions.Compiler.ParameterList` in `System.Linq.Expressions, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nclass ParameterList : System.Collections.IEnumerable, System.Collections.Generic.IReadOnlyList, System.Collections.Generic.IReadOnlyCollection, System.Collections.Generic.IEnumerable\n{\n System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => throw null;\n public System.Collections.Generic.IEnumerator GetEnumerator() => throw null;\n public System.Linq.Expressions.ParameterExpression this[int index] { get => throw null; }\n public int Count { get => throw null; }\n}\n\n}\nnamespace Interpreter\n{\n// Generated from `System.Linq.Expressions.Interpreter.InstructionArray` in `System.Linq.Expressions, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nstruct InstructionArray\n{\n}\n\n// Generated from `System.Linq.Expressions.Interpreter.InstructionList` in `System.Linq.Expressions, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nclass InstructionList\n{\n}\n\n// Generated from `System.Linq.Expressions.Interpreter.InterpretedFrameInfo` in `System.Linq.Expressions, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nstruct InterpretedFrameInfo\n{\n public override string ToString() => throw null;\n}\n\n// Generated from `System.Linq.Expressions.Interpreter.InterpretedFrame` in `System.Linq.Expressions, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nclass InterpretedFrame\n{\n}\n\n}\n}\nnamespace Parallel\n{\n// Generated from `System.Linq.Parallel.ListChunk<>` in `System.Linq.Parallel, Version=4.0.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nclass ListChunk : System.Collections.IEnumerable, System.Collections.Generic.IEnumerable\n{\n System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => throw null;\n public System.Collections.Generic.IEnumerator GetEnumerator() => throw null;\n}\n\n// Generated from `System.Linq.Parallel.Lookup<,>` in `System.Linq.Parallel, Version=4.0.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nclass Lookup : System.Linq.ILookup, System.Collections.IEnumerable, System.Collections.Generic.IEnumerable>\n{\n System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => throw null;\n public System.Collections.Generic.IEnumerator> GetEnumerator() => throw null;\n}\n\n// Generated from `System.Linq.Parallel.PartitionerQueryOperator<>` in `System.Linq.Parallel, Version=4.0.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nclass PartitionerQueryOperator : System.Linq.Parallel.QueryOperator\n{\n}\n\n// Generated from `System.Linq.Parallel.QueryOperator<>` in `System.Linq.Parallel, Version=4.0.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nabstract class QueryOperator : System.Linq.ParallelQuery\n{\n public override System.Collections.Generic.IEnumerator GetEnumerator() => throw null;\n}\n\n// Generated from `System.Linq.Parallel.QueryResults<>` in `System.Linq.Parallel, Version=4.0.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nabstract class QueryResults : System.Collections.IEnumerable, System.Collections.Generic.IList, System.Collections.Generic.IEnumerable, System.Collections.Generic.ICollection\n{\n System.Collections.Generic.IEnumerator System.Collections.Generic.IEnumerable.GetEnumerator() => throw null;\n System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => throw null;\n bool System.Collections.Generic.ICollection.Contains(T item) => throw null;\n bool System.Collections.Generic.ICollection.IsReadOnly { get => throw null; }\n bool System.Collections.Generic.ICollection.Remove(T item) => throw null;\n int System.Collections.Generic.IList.IndexOf(T item) => throw null;\n public T this[int index] { get => throw null; set => throw null; }\n public int Count { get => throw null; }\n void System.Collections.Generic.ICollection.Add(T item) => throw null;\n void System.Collections.Generic.ICollection.Clear() => throw null;\n void System.Collections.Generic.ICollection.CopyTo(T[] array, int arrayIndex) => throw null;\n void System.Collections.Generic.IList.Insert(int index, T item) => throw null;\n void System.Collections.Generic.IList.RemoveAt(int index) => throw null;\n}\n\n// Generated from `System.Linq.Parallel.ZipQueryOperator<,,>` in `System.Linq.Parallel, Version=4.0.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nclass ZipQueryOperator : System.Linq.Parallel.QueryOperator\n{\n}\n\n}\n}\nnamespace Net\n{\n// Generated from `System.Net.CookieCollection` in `System.Net.Primitives, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class CookieCollection : System.Collections.IEnumerable, System.Collections.ICollection, System.Collections.Generic.IReadOnlyCollection, System.Collections.Generic.IEnumerable, System.Collections.Generic.ICollection\n{\n System.Collections.Generic.IEnumerator System.Collections.Generic.IEnumerable.GetEnumerator() => throw null;\n public System.Collections.IEnumerator GetEnumerator() => throw null;\n public bool Contains(System.Net.Cookie cookie) => throw null;\n public bool IsReadOnly { get => throw null; }\n public bool IsSynchronized { get => throw null; }\n public bool Remove(System.Net.Cookie cookie) => throw null;\n public int Count { get => throw null; }\n public object SyncRoot { get => throw null; }\n public void Add(System.Net.Cookie cookie) => throw null;\n public void Clear() => throw null;\n public void CopyTo(System.Array array, int index) => throw null;\n public void CopyTo(System.Net.Cookie[] array, int index) => throw null;\n}\n\n// Generated from `System.Net.Cookie` in `System.Net.Primitives, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class Cookie\n{\n public override bool Equals(object comparand) => throw null;\n public override int GetHashCode() => throw null;\n public override string ToString() => throw null;\n}\n\n// Generated from `System.Net.FixedSizeReader` in `System.Net.Security, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nstatic class FixedSizeReader\n{\n}\n\nnamespace Security\n{\n// Generated from `System.Net.Security.AuthenticatedStream` in `System.Net.Security, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nabstract public class AuthenticatedStream : System.IO.Stream\n{\n protected override void Dispose(bool disposing) => throw null;\n public override System.Threading.Tasks.ValueTask DisposeAsync() => throw null;\n}\n\n// Generated from `System.Net.Security.CipherSuitesPolicy` in `System.Net.Security, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class CipherSuitesPolicy\n{\n}\n\n// Generated from `System.Net.Security.NegotiateStream` in `System.Net.Security, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class NegotiateStream : System.Net.Security.AuthenticatedStream\n{\n protected override void Dispose(bool disposing) => throw null;\n public override System.IAsyncResult BeginRead(System.Byte[] buffer, int offset, int count, System.AsyncCallback asyncCallback, object asyncState) => throw null;\n public override System.IAsyncResult BeginWrite(System.Byte[] buffer, int offset, int count, System.AsyncCallback asyncCallback, object asyncState) => throw null;\n public override System.Int64 Length { get => throw null; }\n public override System.Int64 Position { get => throw null; set => throw null; }\n public override System.Int64 Seek(System.Int64 offset, System.IO.SeekOrigin origin) => throw null;\n public override System.Threading.Tasks.Task FlushAsync(System.Threading.CancellationToken cancellationToken) => throw null;\n public override System.Threading.Tasks.ValueTask DisposeAsync() => throw null;\n public override bool CanRead { get => throw null; }\n public override bool CanSeek { get => throw null; }\n public override bool CanTimeout { get => throw null; }\n public override bool CanWrite { get => throw null; }\n public override int EndRead(System.IAsyncResult asyncResult) => throw null;\n public override int Read(System.Byte[] buffer, int offset, int count) => throw null;\n public override int ReadTimeout { get => throw null; set => throw null; }\n public override int WriteTimeout { get => throw null; set => throw null; }\n public override void EndWrite(System.IAsyncResult asyncResult) => throw null;\n public override void Flush() => throw null;\n public override void SetLength(System.Int64 value) => throw null;\n public override void Write(System.Byte[] buffer, int offset, int count) => throw null;\n}\n\n// Generated from `System.Net.Security.SslStream` in `System.Net.Security, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class SslStream : System.Net.Security.AuthenticatedStream\n{\n protected override void Dispose(bool disposing) => throw null;\n public override System.IAsyncResult BeginRead(System.Byte[] buffer, int offset, int count, System.AsyncCallback asyncCallback, object asyncState) => throw null;\n public override System.IAsyncResult BeginWrite(System.Byte[] buffer, int offset, int count, System.AsyncCallback asyncCallback, object asyncState) => throw null;\n public override System.Int64 Length { get => throw null; }\n public override System.Int64 Position { get => throw null; set => throw null; }\n public override System.Int64 Seek(System.Int64 offset, System.IO.SeekOrigin origin) => throw null;\n public override System.Threading.Tasks.Task FlushAsync(System.Threading.CancellationToken cancellationToken) => throw null;\n public override System.Threading.Tasks.Task WriteAsync(System.Byte[] buffer, int offset, int count, System.Threading.CancellationToken cancellationToken) => throw null;\n public override System.Threading.Tasks.Task ReadAsync(System.Byte[] buffer, int offset, int count, System.Threading.CancellationToken cancellationToken) => throw null;\n public override System.Threading.Tasks.ValueTask DisposeAsync() => throw null;\n public override System.Threading.Tasks.ValueTask WriteAsync(System.ReadOnlyMemory buffer, System.Threading.CancellationToken cancellationToken) => throw null;\n public override System.Threading.Tasks.ValueTask ReadAsync(System.Memory buffer, System.Threading.CancellationToken cancellationToken) => throw null;\n public override bool CanRead { get => throw null; }\n public override bool CanSeek { get => throw null; }\n public override bool CanTimeout { get => throw null; }\n public override bool CanWrite { get => throw null; }\n public override int EndRead(System.IAsyncResult asyncResult) => throw null;\n public override int Read(System.Byte[] buffer, int offset, int count) => throw null;\n public override int ReadByte() => throw null;\n public override int ReadTimeout { get => throw null; set => throw null; }\n public override int WriteTimeout { get => throw null; set => throw null; }\n public override void EndWrite(System.IAsyncResult asyncResult) => throw null;\n public override void Flush() => throw null;\n public override void SetLength(System.Int64 value) => throw null;\n public override void Write(System.Byte[] buffer, int offset, int count) => throw null;\n}\n\n// Generated from `System.Net.Security.TlsCipherSuite` in `System.Net.Security, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic enum TlsCipherSuite\n{\n}\n\n}\n}\nnamespace Runtime\n{\nnamespace Serialization\n{\n// Generated from `System.Runtime.Serialization.DataContractAttribute` in `System.Runtime.Serialization.Primitives, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class DataContractAttribute : System.Attribute\n{\n public DataContractAttribute() => throw null;\n}\n\n// Generated from `System.Runtime.Serialization.DataMemberAttribute` in `System.Runtime.Serialization.Primitives, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class DataMemberAttribute : System.Attribute\n{\n public DataMemberAttribute() => throw null;\n}\n\n}\n}\nnamespace Text\n{\nnamespace RegularExpressions\n{\n// Generated from `System.Text.RegularExpressions.Capture` in `System.Text.RegularExpressions, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class Capture\n{\n public override string ToString() => throw null;\n}\n\n// Generated from `System.Text.RegularExpressions.CollectionDebuggerProxy<>` in `System.Text.RegularExpressions, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nclass CollectionDebuggerProxy\n{\n}\n\n// Generated from `System.Text.RegularExpressions.GroupCollection` in `System.Text.RegularExpressions, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class GroupCollection : System.Collections.IList, System.Collections.IEnumerable, System.Collections.ICollection, System.Collections.Generic.IReadOnlyList, System.Collections.Generic.IReadOnlyDictionary, System.Collections.Generic.IReadOnlyCollection, System.Collections.Generic.IReadOnlyCollection>, System.Collections.Generic.IList, System.Collections.Generic.IEnumerable, System.Collections.Generic.IEnumerable>, System.Collections.Generic.ICollection\n{\n System.Collections.Generic.IEnumerator> System.Collections.Generic.IEnumerable>.GetEnumerator() => throw null;\n System.Collections.Generic.IEnumerator System.Collections.Generic.IEnumerable.GetEnumerator() => throw null;\n System.Text.RegularExpressions.Group this[int index] { get => throw null; set => throw null; }\n bool System.Collections.Generic.ICollection.Contains(System.Text.RegularExpressions.Group item) => throw null;\n bool System.Collections.Generic.ICollection.Remove(System.Text.RegularExpressions.Group item) => throw null;\n bool System.Collections.IList.Contains(object value) => throw null;\n bool System.Collections.IList.IsFixedSize { get => throw null; }\n int System.Collections.Generic.IList.IndexOf(System.Text.RegularExpressions.Group item) => throw null;\n int System.Collections.IList.Add(object value) => throw null;\n int System.Collections.IList.IndexOf(object value) => throw null;\n object this[int index] { get => throw null; set => throw null; }\n public System.Collections.Generic.IEnumerable Values { get => throw null; }\n public System.Collections.Generic.IEnumerable Keys { get => throw null; }\n public System.Collections.IEnumerator GetEnumerator() => throw null;\n public System.Text.RegularExpressions.Group this[string groupname] { get => throw null; }\n public bool ContainsKey(string key) => throw null;\n public bool IsReadOnly { get => throw null; }\n public bool IsSynchronized { get => throw null; }\n public bool TryGetValue(string key, out System.Text.RegularExpressions.Group value) => throw null;\n public int Count { get => throw null; }\n public object SyncRoot { get => throw null; }\n public void CopyTo(System.Array array, int arrayIndex) => throw null;\n public void CopyTo(System.Text.RegularExpressions.Group[] array, int arrayIndex) => throw null;\n void System.Collections.Generic.ICollection.Add(System.Text.RegularExpressions.Group item) => throw null;\n void System.Collections.Generic.ICollection.Clear() => throw null;\n void System.Collections.Generic.IList.Insert(int index, System.Text.RegularExpressions.Group item) => throw null;\n void System.Collections.Generic.IList.RemoveAt(int index) => throw null;\n void System.Collections.IList.Clear() => throw null;\n void System.Collections.IList.Insert(int index, object value) => throw null;\n void System.Collections.IList.Remove(object value) => throw null;\n void System.Collections.IList.RemoveAt(int index) => throw null;\n}\n\n// Generated from `System.Text.RegularExpressions.Group` in `System.Text.RegularExpressions, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class Group : System.Text.RegularExpressions.Capture\n{\n}\n\n// Generated from `System.Text.RegularExpressions.Match` in `System.Text.RegularExpressions, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class Match : System.Text.RegularExpressions.Group\n{\n}\n\n// Generated from `System.Text.RegularExpressions.RegexOptions` in `System.Text.RegularExpressions, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\n[System.Flags]\npublic enum RegexOptions\n{\n IgnoreCase,\n}\n\n// Generated from `System.Text.RegularExpressions.Regex` in `System.Text.RegularExpressions, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class Regex : System.Runtime.Serialization.ISerializable\n{\n public Regex(string pattern) => throw null;\n public Regex(string pattern, System.Text.RegularExpressions.RegexOptions options, System.TimeSpan matchTimeout) => throw null;\n public System.Text.RegularExpressions.Match Match(string input) => throw null;\n public override string ToString() => throw null;\n public static System.Text.RegularExpressions.Match Match(string input, string pattern) => throw null;\n public static System.Text.RegularExpressions.Match Match(string input, string pattern, System.Text.RegularExpressions.RegexOptions options, System.TimeSpan matchTimeout) => throw null;\n public string Replace(string input, string replacement) => throw null;\n void System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo si, System.Runtime.Serialization.StreamingContext context) => throw null;\n}\n\n}\n}\nnamespace Timers\n{\n// Generated from `System.Timers.TimersDescriptionAttribute` in `System.ComponentModel.TypeConverter, Version=4.2.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class TimersDescriptionAttribute\n{\n public TimersDescriptionAttribute(string description) => throw null;\n}\n\n}\nnamespace Windows\n{\nnamespace Markup\n{\n// Generated from `System.Windows.Markup.ValueSerializerAttribute` in `System.ObjectModel, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class ValueSerializerAttribute : System.Attribute\n{\n public ValueSerializerAttribute(System.Type valueSerializerType) => throw null;\n public ValueSerializerAttribute(string valueSerializerTypeName) => throw null;\n}\n\n}\n}\n}\n | +| // This file contains auto-generated code.\n// original-extractor-options: /r:System.Text.RegularExpressions.dll /r:System.Collections.Specialized.dll /r:System.Net.dll /r:System.Web.dll /r:System.Net.HttpListener.dll /r:System.Collections.Specialized.dll /r:System.Private.Uri.dll /r:System.Runtime.Extensions.dll /r:System.Linq.Parallel.dll /r:System.Collections.Concurrent.dll /r:System.Linq.Expressions.dll /r:System.Collections.dll /r:System.Linq.Queryable.dll /r:System.Linq.dll /r:System.Collections.NonGeneric.dll /r:System.ObjectModel.dll /r:System.ComponentModel.TypeConverter.dll /r:System.IO.Compression.dll /r:System.IO.Pipes.dll /r:System.Net.Primitives.dll /r:System.Net.Security.dll /r:System.Security.Cryptography.Primitives.dll /r:System.Text.RegularExpressions.dll ${testdir}/../../resources/stubs/System.Web.cs /r:System.Runtime.Serialization.Primitives.dll\n\nnamespace System\n{\n// Generated from `System.Uri` in `System.Private.Uri, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class Uri : System.Runtime.Serialization.ISerializable\n{\n public override bool Equals(object comparand) => throw null;\n public override int GetHashCode() => throw null;\n public override string ToString() => throw null;\n void System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo serializationInfo, System.Runtime.Serialization.StreamingContext streamingContext) => throw null;\n}\n\nnamespace Collections\n{\n// Generated from `System.Collections.Queue` in `System.Collections.NonGeneric, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class Queue : System.ICloneable, System.Collections.IEnumerable, System.Collections.ICollection\n{\n public virtual System.Collections.IEnumerator GetEnumerator() => throw null;\n public virtual bool IsSynchronized { get => throw null; }\n public virtual int Count { get => throw null; }\n public virtual object Clone() => throw null;\n public virtual object SyncRoot { get => throw null; }\n public virtual void CopyTo(System.Array array, int index) => throw null;\n}\n\n// Generated from `System.Collections.SortedList` in `System.Collections.NonGeneric, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class SortedList : System.ICloneable, System.Collections.IEnumerable, System.Collections.IDictionary, System.Collections.ICollection\n{\n System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => throw null;\n public virtual System.Collections.ICollection Keys { get => throw null; }\n public virtual System.Collections.ICollection Values { get => throw null; }\n public virtual System.Collections.IDictionaryEnumerator GetEnumerator() => throw null;\n public virtual bool Contains(object key) => throw null;\n public virtual bool IsFixedSize { get => throw null; }\n public virtual bool IsReadOnly { get => throw null; }\n public virtual bool IsSynchronized { get => throw null; }\n public virtual int Count { get => throw null; }\n public virtual object Clone() => throw null;\n public virtual object GetByIndex(int index) => throw null;\n public virtual object SyncRoot { get => throw null; }\n public virtual object this[object key] { get => throw null; set => throw null; }\n public virtual void Add(object key, object value) => throw null;\n public virtual void Clear() => throw null;\n public virtual void CopyTo(System.Array array, int arrayIndex) => throw null;\n public virtual void Remove(object key) => throw null;\n}\n\n// Generated from `System.Collections.Stack` in `System.Collections.NonGeneric, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class Stack : System.ICloneable, System.Collections.IEnumerable, System.Collections.ICollection\n{\n public virtual System.Collections.IEnumerator GetEnumerator() => throw null;\n public virtual bool IsSynchronized { get => throw null; }\n public virtual int Count { get => throw null; }\n public virtual object Clone() => throw null;\n public virtual object SyncRoot { get => throw null; }\n public virtual void CopyTo(System.Array array, int index) => throw null;\n}\n\nnamespace Concurrent\n{\n// Generated from `System.Collections.Concurrent.BlockingCollection<>` in `System.Collections.Concurrent, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class BlockingCollection : System.IDisposable, System.Collections.IEnumerable, System.Collections.ICollection, System.Collections.Generic.IReadOnlyCollection, System.Collections.Generic.IEnumerable\n{\n System.Collections.Generic.IEnumerator System.Collections.Generic.IEnumerable.GetEnumerator() => throw null;\n System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => throw null;\n bool System.Collections.ICollection.IsSynchronized { get => throw null; }\n object System.Collections.ICollection.SyncRoot { get => throw null; }\n public int Count { get => throw null; }\n public void Dispose() => throw null;\n void System.Collections.ICollection.CopyTo(System.Array array, int index) => throw null;\n}\n\n// Generated from `System.Collections.Concurrent.BlockingCollectionDebugView<>` in `System.Collections.Concurrent, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nclass BlockingCollectionDebugView\n{\n}\n\n// Generated from `System.Collections.Concurrent.IDictionaryDebugView<,>` in `System.Collections.Concurrent, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nclass IDictionaryDebugView\n{\n}\n\n}\nnamespace Generic\n{\n// Generated from `System.Collections.Generic.CollectionDebugView<>` in `System.ObjectModel, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nclass CollectionDebugView\n{\n}\n\n// Generated from `System.Collections.Generic.DictionaryDebugView<,>` in `System.ObjectModel, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nclass DictionaryDebugView\n{\n}\n\n// Generated from `System.Collections.Generic.QueueDebugView<>` in `System.Collections, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nclass QueueDebugView\n{\n}\n\n// Generated from `System.Collections.Generic.SortedSet<>` in `System.Collections, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class SortedSet : System.Runtime.Serialization.ISerializable, System.Runtime.Serialization.IDeserializationCallback, System.Collections.IEnumerable, System.Collections.ICollection, System.Collections.Generic.ISet, System.Collections.Generic.IReadOnlySet, System.Collections.Generic.IReadOnlyCollection, System.Collections.Generic.IEnumerable, System.Collections.Generic.ICollection\n{\n System.Collections.Generic.IEnumerator System.Collections.Generic.IEnumerable.GetEnumerator() => throw null;\n System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => throw null;\n bool System.Collections.Generic.ICollection.IsReadOnly { get => throw null; }\n bool System.Collections.ICollection.IsSynchronized { get => throw null; }\n object System.Collections.ICollection.SyncRoot { get => throw null; }\n public bool Add(T item) => throw null;\n public bool IsProperSubsetOf(System.Collections.Generic.IEnumerable other) => throw null;\n public bool IsProperSupersetOf(System.Collections.Generic.IEnumerable other) => throw null;\n public bool IsSubsetOf(System.Collections.Generic.IEnumerable other) => throw null;\n public bool IsSupersetOf(System.Collections.Generic.IEnumerable other) => throw null;\n public bool Overlaps(System.Collections.Generic.IEnumerable other) => throw null;\n public bool Remove(T item) => throw null;\n public bool SetEquals(System.Collections.Generic.IEnumerable other) => throw null;\n public int Count { get => throw null; }\n public virtual bool Contains(T item) => throw null;\n public virtual void Clear() => throw null;\n public virtual void IntersectWith(System.Collections.Generic.IEnumerable other) => throw null;\n public void CopyTo(T[] array, int index) => throw null;\n public void ExceptWith(System.Collections.Generic.IEnumerable other) => throw null;\n public void SymmetricExceptWith(System.Collections.Generic.IEnumerable other) => throw null;\n public void UnionWith(System.Collections.Generic.IEnumerable other) => throw null;\n void System.Collections.Generic.ICollection.Add(T item) => throw null;\n void System.Collections.ICollection.CopyTo(System.Array array, int index) => throw null;\n void System.Runtime.Serialization.IDeserializationCallback.OnDeserialization(object sender) => throw null;\n void System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) => throw null;\n}\n\n// Generated from `System.Collections.Generic.Stack<>` in `System.Collections, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class Stack : System.Collections.IEnumerable, System.Collections.ICollection, System.Collections.Generic.IReadOnlyCollection, System.Collections.Generic.IEnumerable\n{\n System.Collections.Generic.IEnumerator System.Collections.Generic.IEnumerable.GetEnumerator() => throw null;\n System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => throw null;\n bool System.Collections.ICollection.IsSynchronized { get => throw null; }\n object System.Collections.ICollection.SyncRoot { get => throw null; }\n public T Peek() => throw null;\n public int Count { get => throw null; }\n void System.Collections.ICollection.CopyTo(System.Array array, int arrayIndex) => throw null;\n}\n\n// Generated from `System.Collections.Generic.StackDebugView<>` in `System.Collections, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nclass StackDebugView\n{\n}\n\n}\nnamespace Specialized\n{\n// Generated from `System.Collections.Specialized.NameObjectCollectionBase` in `System.Collections.Specialized, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nabstract public class NameObjectCollectionBase : System.Runtime.Serialization.ISerializable, System.Runtime.Serialization.IDeserializationCallback, System.Collections.IEnumerable, System.Collections.ICollection\n{\n bool System.Collections.ICollection.IsSynchronized { get => throw null; }\n object System.Collections.ICollection.SyncRoot { get => throw null; }\n public virtual System.Collections.IEnumerator GetEnumerator() => throw null;\n public virtual int Count { get => throw null; }\n public virtual void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context) => throw null;\n public virtual void OnDeserialization(object sender) => throw null;\n void System.Collections.ICollection.CopyTo(System.Array array, int index) => throw null;\n}\n\n// Generated from `System.Collections.Specialized.NameValueCollection` in `System.Collections.Specialized, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class NameValueCollection : System.Collections.Specialized.NameObjectCollectionBase\n{\n public string this[string name] { get => throw null; set => throw null; }\n}\n\n}\n}\nnamespace ComponentModel\n{\n// Generated from `System.ComponentModel.ComponentConverter` in `System.ComponentModel.TypeConverter, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class ComponentConverter : System.ComponentModel.ReferenceConverter\n{\n}\n\n// Generated from `System.ComponentModel.DefaultEventAttribute` in `System.ComponentModel.TypeConverter, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class DefaultEventAttribute : System.Attribute\n{\n public DefaultEventAttribute(string name) => throw null;\n public override bool Equals(object obj) => throw null;\n public override int GetHashCode() => throw null;\n}\n\n// Generated from `System.ComponentModel.DefaultPropertyAttribute` in `System.ComponentModel.TypeConverter, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class DefaultPropertyAttribute : System.Attribute\n{\n public DefaultPropertyAttribute(string name) => throw null;\n public override bool Equals(object obj) => throw null;\n public override int GetHashCode() => throw null;\n}\n\n// Generated from `System.ComponentModel.INotifyPropertyChanged` in `System.ObjectModel, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic interface INotifyPropertyChanged\n{\n}\n\n// Generated from `System.ComponentModel.ReferenceConverter` in `System.ComponentModel.TypeConverter, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class ReferenceConverter : System.ComponentModel.TypeConverter\n{\n}\n\n// Generated from `System.ComponentModel.TypeConverterAttribute` in `System.ObjectModel, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class TypeConverterAttribute : System.Attribute\n{\n public TypeConverterAttribute() => throw null;\n public TypeConverterAttribute(System.Type type) => throw null;\n public TypeConverterAttribute(string typeName) => throw null;\n public override bool Equals(object obj) => throw null;\n public override int GetHashCode() => throw null;\n}\n\n// Generated from `System.ComponentModel.TypeConverter` in `System.ComponentModel.TypeConverter, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class TypeConverter\n{\n}\n\n// Generated from `System.ComponentModel.TypeDescriptionProviderAttribute` in `System.ObjectModel, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class TypeDescriptionProviderAttribute : System.Attribute\n{\n public TypeDescriptionProviderAttribute(System.Type type) => throw null;\n public TypeDescriptionProviderAttribute(string typeName) => throw null;\n}\n\n// Generated from `System.ComponentModel.TypeDescriptionProvider` in `System.ComponentModel.TypeConverter, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nabstract public class TypeDescriptionProvider\n{\n}\n\n// Generated from `System.ComponentModel.TypeDescriptor` in `System.ComponentModel.TypeConverter, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class TypeDescriptor\n{\n}\n\nnamespace Design\n{\n// Generated from `System.ComponentModel.Design.DesignerOptionService` in `System.ComponentModel.TypeConverter, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nabstract public class DesignerOptionService : System.ComponentModel.Design.IDesignerOptionService\n{\n}\n\n// Generated from `System.ComponentModel.Design.IDesignerOptionService` in `System.ComponentModel.TypeConverter, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic interface IDesignerOptionService\n{\n}\n\n}\n}\nnamespace Dynamic\n{\n// Generated from `System.Dynamic.DynamicMetaObject` in `System.Linq.Expressions, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class DynamicMetaObject\n{\n}\n\n// Generated from `System.Dynamic.ExpandoObject` in `System.Linq.Expressions, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class ExpandoObject : System.Dynamic.IDynamicMetaObjectProvider, System.ComponentModel.INotifyPropertyChanged, System.Collections.IEnumerable, System.Collections.Generic.IEnumerable>, System.Collections.Generic.IDictionary, System.Collections.Generic.ICollection>\n{\n System.Collections.Generic.ICollection System.Collections.Generic.IDictionary.Values { get => throw null; }\n System.Collections.Generic.ICollection System.Collections.Generic.IDictionary.Keys { get => throw null; }\n System.Collections.Generic.IEnumerator> System.Collections.Generic.IEnumerable>.GetEnumerator() => throw null;\n System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => throw null;\n bool System.Collections.Generic.ICollection>.Contains(System.Collections.Generic.KeyValuePair item) => throw null;\n bool System.Collections.Generic.ICollection>.IsReadOnly { get => throw null; }\n bool System.Collections.Generic.ICollection>.Remove(System.Collections.Generic.KeyValuePair item) => throw null;\n bool System.Collections.Generic.IDictionary.ContainsKey(string key) => throw null;\n bool System.Collections.Generic.IDictionary.Remove(string key) => throw null;\n bool System.Collections.Generic.IDictionary.TryGetValue(string key, out object value) => throw null;\n int System.Collections.Generic.ICollection>.Count { get => throw null; }\n object this[string key] { get => throw null; set => throw null; }\n void System.Collections.Generic.ICollection>.Add(System.Collections.Generic.KeyValuePair item) => throw null;\n void System.Collections.Generic.ICollection>.Clear() => throw null;\n void System.Collections.Generic.ICollection>.CopyTo(System.Collections.Generic.KeyValuePair[] array, int arrayIndex) => throw null;\n void System.Collections.Generic.IDictionary.Add(string key, object value) => throw null;\n}\n\n// Generated from `System.Dynamic.IDynamicMetaObjectProvider` in `System.Linq.Expressions, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic interface IDynamicMetaObjectProvider\n{\n}\n\nnamespace Utils\n{\n// Generated from `System.Dynamic.Utils.ListProvider<>` in `System.Linq.Expressions, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nabstract class ListProvider : System.Collections.IEnumerable, System.Collections.Generic.IList, System.Collections.Generic.IEnumerable, System.Collections.Generic.ICollection where T: class\n{\n System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => throw null;\n public System.Collections.Generic.IEnumerator GetEnumerator() => throw null;\n public T this[int index] { get => throw null; set => throw null; }\n public bool Contains(T item) => throw null;\n public bool IsReadOnly { get => throw null; }\n public bool Remove(T item) => throw null;\n public int Count { get => throw null; }\n public int IndexOf(T item) => throw null;\n public void Add(T item) => throw null;\n public void Clear() => throw null;\n public void CopyTo(T[] array, int index) => throw null;\n public void Insert(int index, T item) => throw null;\n public void RemoveAt(int index) => throw null;\n}\n\n}\n}\nnamespace IO\n{\nnamespace Compression\n{\n// Generated from `System.IO.Compression.DeflateStream` in `System.IO.Compression, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089`\npublic class DeflateStream : System.IO.Stream\n{\n protected override void Dispose(bool disposing) => throw null;\n public override System.IAsyncResult BeginRead(System.Byte[] buffer, int offset, int count, System.AsyncCallback asyncCallback, object asyncState) => throw null;\n public override System.IAsyncResult BeginWrite(System.Byte[] array, int offset, int count, System.AsyncCallback asyncCallback, object asyncState) => throw null;\n public override System.Int64 Length { get => throw null; }\n public override System.Int64 Position { get => throw null; set => throw null; }\n public override System.Int64 Seek(System.Int64 offset, System.IO.SeekOrigin origin) => throw null;\n public override System.Threading.Tasks.Task CopyToAsync(System.IO.Stream destination, int bufferSize, System.Threading.CancellationToken cancellationToken) => throw null;\n public override System.Threading.Tasks.Task FlushAsync(System.Threading.CancellationToken cancellationToken) => throw null;\n public override System.Threading.Tasks.Task WriteAsync(System.Byte[] array, int offset, int count, System.Threading.CancellationToken cancellationToken) => throw null;\n public override System.Threading.Tasks.Task ReadAsync(System.Byte[] array, int offset, int count, System.Threading.CancellationToken cancellationToken) => throw null;\n public override System.Threading.Tasks.ValueTask DisposeAsync() => throw null;\n public override System.Threading.Tasks.ValueTask WriteAsync(System.ReadOnlyMemory buffer, System.Threading.CancellationToken cancellationToken) => throw null;\n public override System.Threading.Tasks.ValueTask ReadAsync(System.Memory buffer, System.Threading.CancellationToken cancellationToken) => throw null;\n public override bool CanRead { get => throw null; }\n public override bool CanSeek { get => throw null; }\n public override bool CanWrite { get => throw null; }\n public override int EndRead(System.IAsyncResult asyncResult) => throw null;\n public override int Read(System.Byte[] array, int offset, int count) => throw null;\n public override int Read(System.Span buffer) => throw null;\n public override int ReadByte() => throw null;\n public override void CopyTo(System.IO.Stream destination, int bufferSize) => throw null;\n public override void EndWrite(System.IAsyncResult asyncResult) => throw null;\n public override void Flush() => throw null;\n public override void SetLength(System.Int64 value) => throw null;\n public override void Write(System.Byte[] array, int offset, int count) => throw null;\n public override void Write(System.ReadOnlySpan buffer) => throw null;\n}\n\n}\n}\nnamespace Linq\n{\n// Generated from `System.Linq.Enumerable` in `System.Linq, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nstatic public class Enumerable\n{\n public static System.Collections.Generic.IEnumerable Select(this System.Collections.Generic.IEnumerable source, System.Func selector) => throw null;\n}\n\n// Generated from `System.Linq.Grouping<,>` in `System.Linq, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class Grouping : System.Linq.IGrouping, System.Collections.IEnumerable, System.Collections.Generic.IList, System.Collections.Generic.IEnumerable, System.Collections.Generic.ICollection\n{\n System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => throw null;\n TElement this[int index] { get => throw null; set => throw null; }\n bool System.Collections.Generic.ICollection.Contains(TElement item) => throw null;\n bool System.Collections.Generic.ICollection.IsReadOnly { get => throw null; }\n bool System.Collections.Generic.ICollection.Remove(TElement item) => throw null;\n int System.Collections.Generic.ICollection.Count { get => throw null; }\n int System.Collections.Generic.IList.IndexOf(TElement item) => throw null;\n public System.Collections.Generic.IEnumerator GetEnumerator() => throw null;\n void System.Collections.Generic.ICollection.Add(TElement item) => throw null;\n void System.Collections.Generic.ICollection.Clear() => throw null;\n void System.Collections.Generic.ICollection.CopyTo(TElement[] array, int arrayIndex) => throw null;\n void System.Collections.Generic.IList.Insert(int index, TElement item) => throw null;\n void System.Collections.Generic.IList.RemoveAt(int index) => throw null;\n}\n\n// Generated from `System.Linq.IGrouping<,>` in `System.Linq, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic interface IGrouping : System.Collections.IEnumerable, System.Collections.Generic.IEnumerable\n{\n}\n\n// Generated from `System.Linq.IIListProvider<>` in `System.Linq, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\ninterface IIListProvider : System.Collections.IEnumerable, System.Collections.Generic.IEnumerable\n{\n}\n\n// Generated from `System.Linq.ILookup<,>` in `System.Linq, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic interface ILookup : System.Collections.IEnumerable, System.Collections.Generic.IEnumerable>\n{\n}\n\n// Generated from `System.Linq.IOrderedEnumerable<>` in `System.Linq, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic interface IOrderedEnumerable : System.Collections.IEnumerable, System.Collections.Generic.IEnumerable\n{\n}\n\n// Generated from `System.Linq.IPartition<>` in `System.Linq, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\ninterface IPartition : System.Linq.IIListProvider, System.Collections.IEnumerable, System.Collections.Generic.IEnumerable\n{\n}\n\n// Generated from `System.Linq.IQueryable` in `System.Linq.Expressions, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic interface IQueryable : System.Collections.IEnumerable\n{\n}\n\n// Generated from `System.Linq.Lookup<,>` in `System.Linq, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class Lookup : System.Linq.ILookup, System.Linq.IIListProvider>, System.Collections.IEnumerable, System.Collections.Generic.IEnumerable>\n{\n System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => throw null;\n public System.Collections.Generic.IEnumerator> GetEnumerator() => throw null;\n}\n\n// Generated from `System.Linq.OrderedEnumerable<>` in `System.Linq, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nabstract class OrderedEnumerable : System.Linq.IPartition, System.Linq.IOrderedEnumerable, System.Linq.IIListProvider, System.Collections.IEnumerable, System.Collections.Generic.IEnumerable\n{\n System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => throw null;\n public System.Collections.Generic.IEnumerator GetEnumerator() => throw null;\n}\n\n// Generated from `System.Linq.ParallelEnumerable` in `System.Linq.Parallel, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nstatic public class ParallelEnumerable\n{\n public static System.Linq.ParallelQuery AsParallel(this System.Collections.IEnumerable source) => throw null;\n}\n\n// Generated from `System.Linq.ParallelQuery<>` in `System.Linq.Parallel, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class ParallelQuery : System.Linq.ParallelQuery, System.Collections.IEnumerable, System.Collections.Generic.IEnumerable\n{\n public virtual System.Collections.Generic.IEnumerator GetEnumerator() => throw null;\n}\n\n// Generated from `System.Linq.ParallelQuery` in `System.Linq.Parallel, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class ParallelQuery : System.Collections.IEnumerable\n{\n System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => throw null;\n}\n\n// Generated from `System.Linq.Queryable` in `System.Linq.Queryable, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nstatic public class Queryable\n{\n public static System.Linq.IQueryable AsQueryable(this System.Collections.IEnumerable source) => throw null;\n}\n\n// Generated from `System.Linq.SystemLinq_GroupingDebugView<,>` in `System.Linq, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nclass SystemLinq_GroupingDebugView\n{\n}\n\n// Generated from `System.Linq.SystemLinq_LookupDebugView<,>` in `System.Linq, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nclass SystemLinq_LookupDebugView\n{\n}\n\nnamespace Expressions\n{\n// Generated from `System.Linq.Expressions.BlockExpressionList` in `System.Linq.Expressions, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nclass BlockExpressionList : System.Collections.IEnumerable, System.Collections.Generic.IList, System.Collections.Generic.IEnumerable, System.Collections.Generic.ICollection\n{\n System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => throw null;\n public System.Collections.Generic.IEnumerator GetEnumerator() => throw null;\n public System.Linq.Expressions.Expression this[int index] { get => throw null; set => throw null; }\n public bool Contains(System.Linq.Expressions.Expression item) => throw null;\n public bool IsReadOnly { get => throw null; }\n public bool Remove(System.Linq.Expressions.Expression item) => throw null;\n public int Count { get => throw null; }\n public int IndexOf(System.Linq.Expressions.Expression item) => throw null;\n public void Add(System.Linq.Expressions.Expression item) => throw null;\n public void Clear() => throw null;\n public void CopyTo(System.Linq.Expressions.Expression[] array, int index) => throw null;\n public void Insert(int index, System.Linq.Expressions.Expression item) => throw null;\n public void RemoveAt(int index) => throw null;\n}\n\n// Generated from `System.Linq.Expressions.Expression` in `System.Linq.Expressions, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nabstract public class Expression\n{\n public override string ToString() => throw null;\n}\n\n// Generated from `System.Linq.Expressions.ParameterExpression` in `System.Linq.Expressions, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class ParameterExpression : System.Linq.Expressions.Expression\n{\n}\n\nnamespace Compiler\n{\n// Generated from `System.Linq.Expressions.Compiler.ParameterList` in `System.Linq.Expressions, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nclass ParameterList : System.Collections.IEnumerable, System.Collections.Generic.IReadOnlyList, System.Collections.Generic.IReadOnlyCollection, System.Collections.Generic.IEnumerable\n{\n System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => throw null;\n public System.Collections.Generic.IEnumerator GetEnumerator() => throw null;\n public System.Linq.Expressions.ParameterExpression this[int index] { get => throw null; }\n public int Count { get => throw null; }\n}\n\n}\nnamespace Interpreter\n{\n// Generated from `System.Linq.Expressions.Interpreter.InstructionArray` in `System.Linq.Expressions, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nstruct InstructionArray\n{\n}\n\n// Generated from `System.Linq.Expressions.Interpreter.InstructionList` in `System.Linq.Expressions, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nclass InstructionList\n{\n}\n\n// Generated from `System.Linq.Expressions.Interpreter.InterpretedFrameInfo` in `System.Linq.Expressions, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nstruct InterpretedFrameInfo\n{\n public override string ToString() => throw null;\n}\n\n// Generated from `System.Linq.Expressions.Interpreter.InterpretedFrame` in `System.Linq.Expressions, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nclass InterpretedFrame\n{\n}\n\n}\n}\nnamespace Parallel\n{\n// Generated from `System.Linq.Parallel.ListChunk<>` in `System.Linq.Parallel, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nclass ListChunk : System.Collections.IEnumerable, System.Collections.Generic.IEnumerable\n{\n System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => throw null;\n public System.Collections.Generic.IEnumerator GetEnumerator() => throw null;\n}\n\n// Generated from `System.Linq.Parallel.Lookup<,>` in `System.Linq.Parallel, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nclass Lookup : System.Linq.ILookup, System.Collections.IEnumerable, System.Collections.Generic.IEnumerable>\n{\n System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => throw null;\n public System.Collections.Generic.IEnumerator> GetEnumerator() => throw null;\n}\n\n// Generated from `System.Linq.Parallel.PartitionerQueryOperator<>` in `System.Linq.Parallel, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nclass PartitionerQueryOperator : System.Linq.Parallel.QueryOperator\n{\n}\n\n// Generated from `System.Linq.Parallel.QueryOperator<>` in `System.Linq.Parallel, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nabstract class QueryOperator : System.Linq.ParallelQuery\n{\n public override System.Collections.Generic.IEnumerator GetEnumerator() => throw null;\n}\n\n// Generated from `System.Linq.Parallel.QueryResults<>` in `System.Linq.Parallel, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nabstract class QueryResults : System.Collections.IEnumerable, System.Collections.Generic.IList, System.Collections.Generic.IEnumerable, System.Collections.Generic.ICollection\n{\n System.Collections.Generic.IEnumerator System.Collections.Generic.IEnumerable.GetEnumerator() => throw null;\n System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() => throw null;\n bool System.Collections.Generic.ICollection.Contains(T item) => throw null;\n bool System.Collections.Generic.ICollection.IsReadOnly { get => throw null; }\n bool System.Collections.Generic.ICollection.Remove(T item) => throw null;\n int System.Collections.Generic.IList.IndexOf(T item) => throw null;\n public T this[int index] { get => throw null; set => throw null; }\n public int Count { get => throw null; }\n void System.Collections.Generic.ICollection.Add(T item) => throw null;\n void System.Collections.Generic.ICollection.Clear() => throw null;\n void System.Collections.Generic.ICollection.CopyTo(T[] array, int arrayIndex) => throw null;\n void System.Collections.Generic.IList.Insert(int index, T item) => throw null;\n void System.Collections.Generic.IList.RemoveAt(int index) => throw null;\n}\n\n// Generated from `System.Linq.Parallel.ZipQueryOperator<,,>` in `System.Linq.Parallel, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nclass ZipQueryOperator : System.Linq.Parallel.QueryOperator\n{\n}\n\n}\n}\nnamespace Net\n{\n// Generated from `System.Net.CookieCollection` in `System.Net.Primitives, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class CookieCollection : System.Collections.IEnumerable, System.Collections.ICollection, System.Collections.Generic.IReadOnlyCollection, System.Collections.Generic.IEnumerable, System.Collections.Generic.ICollection\n{\n System.Collections.Generic.IEnumerator System.Collections.Generic.IEnumerable.GetEnumerator() => throw null;\n public System.Collections.IEnumerator GetEnumerator() => throw null;\n public bool Contains(System.Net.Cookie cookie) => throw null;\n public bool IsReadOnly { get => throw null; }\n public bool IsSynchronized { get => throw null; }\n public bool Remove(System.Net.Cookie cookie) => throw null;\n public int Count { get => throw null; }\n public object SyncRoot { get => throw null; }\n public void Add(System.Net.Cookie cookie) => throw null;\n public void Clear() => throw null;\n public void CopyTo(System.Array array, int index) => throw null;\n public void CopyTo(System.Net.Cookie[] array, int index) => throw null;\n}\n\n// Generated from `System.Net.Cookie` in `System.Net.Primitives, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class Cookie\n{\n public override bool Equals(object comparand) => throw null;\n public override int GetHashCode() => throw null;\n public override string ToString() => throw null;\n}\n\n// Generated from `System.Net.StreamFramer` in `System.Net.Security, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nclass StreamFramer\n{\n}\n\nnamespace Security\n{\n// Generated from `System.Net.Security.AuthenticatedStream` in `System.Net.Security, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nabstract public class AuthenticatedStream : System.IO.Stream\n{\n protected override void Dispose(bool disposing) => throw null;\n public override System.Threading.Tasks.ValueTask DisposeAsync() => throw null;\n}\n\n// Generated from `System.Net.Security.CipherSuitesPolicy` in `System.Net.Security, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class CipherSuitesPolicy\n{\n}\n\n// Generated from `System.Net.Security.NegotiateStream` in `System.Net.Security, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class NegotiateStream : System.Net.Security.AuthenticatedStream\n{\n protected override void Dispose(bool disposing) => throw null;\n public override System.IAsyncResult BeginRead(System.Byte[] buffer, int offset, int count, System.AsyncCallback asyncCallback, object asyncState) => throw null;\n public override System.IAsyncResult BeginWrite(System.Byte[] buffer, int offset, int count, System.AsyncCallback asyncCallback, object asyncState) => throw null;\n public override System.Int64 Length { get => throw null; }\n public override System.Int64 Position { get => throw null; set => throw null; }\n public override System.Int64 Seek(System.Int64 offset, System.IO.SeekOrigin origin) => throw null;\n public override System.Threading.Tasks.Task FlushAsync(System.Threading.CancellationToken cancellationToken) => throw null;\n public override System.Threading.Tasks.Task WriteAsync(System.Byte[] buffer, int offset, int count, System.Threading.CancellationToken cancellationToken) => throw null;\n public override System.Threading.Tasks.Task ReadAsync(System.Byte[] buffer, int offset, int count, System.Threading.CancellationToken cancellationToken) => throw null;\n public override System.Threading.Tasks.ValueTask DisposeAsync() => throw null;\n public override System.Threading.Tasks.ValueTask WriteAsync(System.ReadOnlyMemory buffer, System.Threading.CancellationToken cancellationToken) => throw null;\n public override System.Threading.Tasks.ValueTask ReadAsync(System.Memory buffer, System.Threading.CancellationToken cancellationToken) => throw null;\n public override bool CanRead { get => throw null; }\n public override bool CanSeek { get => throw null; }\n public override bool CanTimeout { get => throw null; }\n public override bool CanWrite { get => throw null; }\n public override int EndRead(System.IAsyncResult asyncResult) => throw null;\n public override int Read(System.Byte[] buffer, int offset, int count) => throw null;\n public override int ReadTimeout { get => throw null; set => throw null; }\n public override int WriteTimeout { get => throw null; set => throw null; }\n public override void EndWrite(System.IAsyncResult asyncResult) => throw null;\n public override void Flush() => throw null;\n public override void SetLength(System.Int64 value) => throw null;\n public override void Write(System.Byte[] buffer, int offset, int count) => throw null;\n}\n\n// Generated from `System.Net.Security.SslStream` in `System.Net.Security, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class SslStream : System.Net.Security.AuthenticatedStream\n{\n protected override void Dispose(bool disposing) => throw null;\n public override System.IAsyncResult BeginRead(System.Byte[] buffer, int offset, int count, System.AsyncCallback asyncCallback, object asyncState) => throw null;\n public override System.IAsyncResult BeginWrite(System.Byte[] buffer, int offset, int count, System.AsyncCallback asyncCallback, object asyncState) => throw null;\n public override System.Int64 Length { get => throw null; }\n public override System.Int64 Position { get => throw null; set => throw null; }\n public override System.Int64 Seek(System.Int64 offset, System.IO.SeekOrigin origin) => throw null;\n public override System.Threading.Tasks.Task FlushAsync(System.Threading.CancellationToken cancellationToken) => throw null;\n public override System.Threading.Tasks.Task WriteAsync(System.Byte[] buffer, int offset, int count, System.Threading.CancellationToken cancellationToken) => throw null;\n public override System.Threading.Tasks.Task ReadAsync(System.Byte[] buffer, int offset, int count, System.Threading.CancellationToken cancellationToken) => throw null;\n public override System.Threading.Tasks.ValueTask DisposeAsync() => throw null;\n public override System.Threading.Tasks.ValueTask WriteAsync(System.ReadOnlyMemory buffer, System.Threading.CancellationToken cancellationToken) => throw null;\n public override System.Threading.Tasks.ValueTask ReadAsync(System.Memory buffer, System.Threading.CancellationToken cancellationToken) => throw null;\n public override bool CanRead { get => throw null; }\n public override bool CanSeek { get => throw null; }\n public override bool CanTimeout { get => throw null; }\n public override bool CanWrite { get => throw null; }\n public override int EndRead(System.IAsyncResult asyncResult) => throw null;\n public override int Read(System.Byte[] buffer, int offset, int count) => throw null;\n public override int ReadByte() => throw null;\n public override int ReadTimeout { get => throw null; set => throw null; }\n public override int WriteTimeout { get => throw null; set => throw null; }\n public override void EndWrite(System.IAsyncResult asyncResult) => throw null;\n public override void Flush() => throw null;\n public override void SetLength(System.Int64 value) => throw null;\n public override void Write(System.Byte[] buffer, int offset, int count) => throw null;\n}\n\n// Generated from `System.Net.Security.TlsCipherSuite` in `System.Net.Security, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic enum TlsCipherSuite\n{\n}\n\n}\n}\nnamespace Runtime\n{\nnamespace Serialization\n{\n// Generated from `System.Runtime.Serialization.DataContractAttribute` in `System.Runtime.Serialization.Primitives, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class DataContractAttribute : System.Attribute\n{\n public DataContractAttribute() => throw null;\n}\n\n// Generated from `System.Runtime.Serialization.DataMemberAttribute` in `System.Runtime.Serialization.Primitives, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class DataMemberAttribute : System.Attribute\n{\n public DataMemberAttribute() => throw null;\n}\n\n}\n}\nnamespace Text\n{\nnamespace RegularExpressions\n{\n// Generated from `System.Text.RegularExpressions.Capture` in `System.Text.RegularExpressions, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class Capture\n{\n public override string ToString() => throw null;\n}\n\n// Generated from `System.Text.RegularExpressions.CollectionDebuggerProxy<>` in `System.Text.RegularExpressions, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\nclass CollectionDebuggerProxy\n{\n}\n\n// Generated from `System.Text.RegularExpressions.GroupCollection` in `System.Text.RegularExpressions, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class GroupCollection : System.Collections.IList, System.Collections.IEnumerable, System.Collections.ICollection, System.Collections.Generic.IReadOnlyList, System.Collections.Generic.IReadOnlyDictionary, System.Collections.Generic.IReadOnlyCollection, System.Collections.Generic.IReadOnlyCollection>, System.Collections.Generic.IList, System.Collections.Generic.IEnumerable, System.Collections.Generic.IEnumerable>, System.Collections.Generic.ICollection\n{\n System.Collections.Generic.IEnumerator> System.Collections.Generic.IEnumerable>.GetEnumerator() => throw null;\n System.Collections.Generic.IEnumerator System.Collections.Generic.IEnumerable.GetEnumerator() => throw null;\n System.Text.RegularExpressions.Group this[int index] { get => throw null; set => throw null; }\n bool System.Collections.Generic.ICollection.Contains(System.Text.RegularExpressions.Group item) => throw null;\n bool System.Collections.Generic.ICollection.Remove(System.Text.RegularExpressions.Group item) => throw null;\n bool System.Collections.IList.Contains(object value) => throw null;\n bool System.Collections.IList.IsFixedSize { get => throw null; }\n int System.Collections.Generic.IList.IndexOf(System.Text.RegularExpressions.Group item) => throw null;\n int System.Collections.IList.Add(object value) => throw null;\n int System.Collections.IList.IndexOf(object value) => throw null;\n object this[int index] { get => throw null; set => throw null; }\n public System.Collections.Generic.IEnumerable Values { get => throw null; }\n public System.Collections.Generic.IEnumerable Keys { get => throw null; }\n public System.Collections.IEnumerator GetEnumerator() => throw null;\n public System.Text.RegularExpressions.Group this[string groupname] { get => throw null; }\n public bool ContainsKey(string key) => throw null;\n public bool IsReadOnly { get => throw null; }\n public bool IsSynchronized { get => throw null; }\n public bool TryGetValue(string key, out System.Text.RegularExpressions.Group value) => throw null;\n public int Count { get => throw null; }\n public object SyncRoot { get => throw null; }\n public void CopyTo(System.Array array, int arrayIndex) => throw null;\n public void CopyTo(System.Text.RegularExpressions.Group[] array, int arrayIndex) => throw null;\n void System.Collections.Generic.ICollection.Add(System.Text.RegularExpressions.Group item) => throw null;\n void System.Collections.Generic.ICollection.Clear() => throw null;\n void System.Collections.Generic.IList.Insert(int index, System.Text.RegularExpressions.Group item) => throw null;\n void System.Collections.Generic.IList.RemoveAt(int index) => throw null;\n void System.Collections.IList.Clear() => throw null;\n void System.Collections.IList.Insert(int index, object value) => throw null;\n void System.Collections.IList.Remove(object value) => throw null;\n void System.Collections.IList.RemoveAt(int index) => throw null;\n}\n\n// Generated from `System.Text.RegularExpressions.Group` in `System.Text.RegularExpressions, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class Group : System.Text.RegularExpressions.Capture\n{\n}\n\n// Generated from `System.Text.RegularExpressions.Match` in `System.Text.RegularExpressions, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class Match : System.Text.RegularExpressions.Group\n{\n}\n\n// Generated from `System.Text.RegularExpressions.RegexOptions` in `System.Text.RegularExpressions, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\n[System.Flags]\npublic enum RegexOptions\n{\n IgnoreCase,\n}\n\n// Generated from `System.Text.RegularExpressions.Regex` in `System.Text.RegularExpressions, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class Regex : System.Runtime.Serialization.ISerializable\n{\n public Regex(string pattern) => throw null;\n public Regex(string pattern, System.Text.RegularExpressions.RegexOptions options, System.TimeSpan matchTimeout) => throw null;\n public System.Text.RegularExpressions.Match Match(string input) => throw null;\n public override string ToString() => throw null;\n public static System.Text.RegularExpressions.Match Match(string input, string pattern) => throw null;\n public static System.Text.RegularExpressions.Match Match(string input, string pattern, System.Text.RegularExpressions.RegexOptions options, System.TimeSpan matchTimeout) => throw null;\n public string Replace(string input, string replacement) => throw null;\n void System.Runtime.Serialization.ISerializable.GetObjectData(System.Runtime.Serialization.SerializationInfo si, System.Runtime.Serialization.StreamingContext context) => throw null;\n}\n\n}\n}\nnamespace Timers\n{\n// Generated from `System.Timers.TimersDescriptionAttribute` in `System.ComponentModel.TypeConverter, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class TimersDescriptionAttribute\n{\n public TimersDescriptionAttribute(string description) => throw null;\n}\n\n}\nnamespace Windows\n{\nnamespace Markup\n{\n// Generated from `System.Windows.Markup.ValueSerializerAttribute` in `System.ObjectModel, Version=5.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a`\npublic class ValueSerializerAttribute : System.Attribute\n{\n public ValueSerializerAttribute(System.Type valueSerializerType) => throw null;\n public ValueSerializerAttribute(string valueSerializerTypeName) => throw null;\n}\n\n}\n}\n}\n | From 17109a36ced2f6ede31a4aa1f7ccec186e32a47f Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Thu, 11 Feb 2021 15:24:03 +0100 Subject: [PATCH 106/142] Fix extraction error due to missing DLL --- .../experimental/Security Features/Serialization/test0.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/csharp/ql/test/experimental/Security Features/Serialization/test0.cs b/csharp/ql/test/experimental/Security Features/Serialization/test0.cs index 30d266203fa..2efcb4facf3 100644 --- a/csharp/ql/test/experimental/Security Features/Serialization/test0.cs +++ b/csharp/ql/test/experimental/Security Features/Serialization/test0.cs @@ -1,4 +1,4 @@ -// semmle-extractor-options: /r:System.Data.Common.dll /r:System.Runtime.WindowsRuntime.dll /r:System.Xml.XmlSerializer.dll /r:System.Runtime.Serialization.Xml.dll /r:System.Runtime.Serialization.Xml.dll /r:System.Collections.dll /r:System.Private.Xml.dll /r:System.Private.DataContractSerialization.dll /r:System.Runtime.Extensions.dll /r:System.ComponentModel.TypeConverter.dll /r:System.Xml.ReaderWriter.dll /r:System.IO.FileSystem.dll +// semmle-extractor-options: /r:System.Data.Common.dll /r:System.Xml.XmlSerializer.dll /r:System.Runtime.Serialization.Xml.dll /r:System.Runtime.Serialization.Xml.dll /r:System.Collections.dll /r:System.Private.Xml.dll /r:System.Private.DataContractSerialization.dll /r:System.Runtime.Extensions.dll /r:System.ComponentModel.TypeConverter.dll /r:System.Xml.ReaderWriter.dll /r:System.IO.FileSystem.dll using System; using System.Data; @@ -19,9 +19,9 @@ namespace DataSetSerializationTest } } - /* + /* * TODO: I cannot use DataContract on a QL unit test - * + * [DataContract(Name = "Customer", Namespace = "http://www.contoso.com")] public class PatternDataContractSerializer : XmlObjectSerializer { From f2e667173c2e46e7b8cd3c42906c083d75e86605 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Thu, 11 Feb 2021 18:10:43 +0100 Subject: [PATCH 107/142] C#: Add calli IL opcode extraction --- .../Context.Factories.cs | 5 ++ .../Entities/Instruction.cs | 49 ++++++++++++++----- .../src/semmle/code/cil/ConsistencyChecks.qll | 8 ++- .../ql/src/semmle/code/cil/Instructions.qll | 16 ++++++ csharp/ql/src/semmle/code/cil/Types.qll | 11 +++++ csharp/ql/src/semmle/code/csharp/Type.qll | 2 + .../cil/consistency/consistency.expected | 18 ------- 7 files changed, 78 insertions(+), 31 deletions(-) diff --git a/csharp/extractor/Semmle.Extraction.CIL/Context.Factories.cs b/csharp/extractor/Semmle.Extraction.CIL/Context.Factories.cs index 65c72487b65..7cdfa949390 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Context.Factories.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Context.Factories.cs @@ -128,6 +128,11 @@ namespace Semmle.Extraction.CIL case HandleKind.TypeDefinition: entity = new TypeDefinitionType(this, (TypeDefinitionHandle)handle); break; + case HandleKind.StandaloneSignature: + var signature = MdReader.GetStandaloneSignature((StandaloneSignatureHandle)handle); + var method = signature.DecodeMethodSignature(gc.Cx.TypeSignatureDecoder, gc); + entity = new FunctionPointerType(this, method); + break; default: throw new InternalError("Unhandled handle kind " + handle.Kind); } diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Instruction.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Instruction.cs index 9cfcf444e66..11d4287fc59 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Instruction.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Instruction.cs @@ -385,19 +385,21 @@ namespace Semmle.Extraction.CIL.Entities case Payload.Type: case Payload.Field: case Payload.ValueType: - // A generic EntityHandle. - var handle = MetadataTokens.EntityHandle(payloadValue); - var target = Cx.CreateGeneric(Method, handle); - yield return target; - if (target != null) { - yield return Tuples.cil_access(this, target); + // A generic EntityHandle. + var handle = MetadataTokens.EntityHandle(payloadValue); + var target = Cx.CreateGeneric(Method, handle); + yield return target; + if (target != null) + { + yield return Tuples.cil_access(this, target); + } + else + { + throw new InternalError($"Unable to create payload type {PayloadType} for opcode {OpCode}"); + } + break; } - else - { - throw new InternalError($"Unable to create payload type {PayloadType} for opcode {OpCode}"); - } - break; case Payload.Arg8: case Payload.Arg16: if (Method.Parameters is object) @@ -417,10 +419,33 @@ namespace Semmle.Extraction.CIL.Entities case Payload.Target32: case Payload.Switch: case Payload.Ignore8: - case Payload.CallSiteDesc: // These are not handled here. // Some of these are handled by JumpContents(). break; + case Payload.CallSiteDesc: + { + var handle = MetadataTokens.EntityHandle(payloadValue); + IExtractedEntity? target = null; + try + { + target = Cx.CreateGeneric(Method, handle); + } + catch (Exception exc) + { + Cx.Cx.Extractor.Logger.Log(Util.Logging.Severity.Warning, $"Couldn't interpret payload of payload type {PayloadType} as a function pointer type. {exc.Message} {exc.StackTrace}"); + } + + if (target != null) + { + yield return target; + yield return Tuples.cil_access(this, target); + } + else + { + throw new InternalError($"Unable to create payload type {PayloadType} for opcode {OpCode}"); + } + break; + } default: throw new InternalError($"Unhandled payload type {PayloadType}"); } diff --git a/csharp/ql/src/semmle/code/cil/ConsistencyChecks.qll b/csharp/ql/src/semmle/code/cil/ConsistencyChecks.qll index bd6a1bc8885..51b74b2463d 100644 --- a/csharp/ql/src/semmle/code/cil/ConsistencyChecks.qll +++ b/csharp/ql/src/semmle/code/cil/ConsistencyChecks.qll @@ -79,7 +79,13 @@ class MissingValue extends InstructionViolation { * A call that does not have exactly one `getTarget()`. */ class MissingCallTarget extends InstructionViolation { - MissingCallTarget() { exists(Call c | c = instruction | count(c.getTarget()) != 1) } + MissingCallTarget() { + exists(Call c | c = instruction | + count(c.getTarget()) != 1 and not c instanceof Opcodes::Calli + or + count(c.(Opcodes::Calli).getTargetType()) != 1 and c instanceof Opcodes::Calli + ) + } override string getMessage() { result = "Call has invalid target" } } diff --git a/csharp/ql/src/semmle/code/cil/Instructions.qll b/csharp/ql/src/semmle/code/cil/Instructions.qll index bc79e15d4e4..e385ceced31 100644 --- a/csharp/ql/src/semmle/code/cil/Instructions.qll +++ b/csharp/ql/src/semmle/code/cil/Instructions.qll @@ -482,6 +482,22 @@ module Opcodes { override string getOpcodeName() { result = "call" } } + /** A `calli` instruction. */ + class Calli extends Call, @cil_calli { + override string getOpcodeName() { result = "calli" } + + override Callable getTarget() { none() } + + /** Gets the function pointer type targetted by this instruction. */ + FunctionPointerType getTargetType() { cil_access(this, result) } + + // The number of items popped/pushed from the stack depends on the target of + // the call. Also, we need to pop the function pointer itself too. + override int getPopCount() { result = getTargetType().getCallPopCount() + 1 } + + override int getPushCount() { result = getTargetType().getCallPushCount() } + } + /** A `callvirt` instruction. */ class Callvirt extends Call, @cil_callvirt { override string getOpcodeName() { result = "callvirt" } diff --git a/csharp/ql/src/semmle/code/cil/Types.qll b/csharp/ql/src/semmle/code/cil/Types.qll index 1bc74767d6b..16ea219e8ac 100644 --- a/csharp/ql/src/semmle/code/cil/Types.qll +++ b/csharp/ql/src/semmle/code/cil/Types.qll @@ -310,4 +310,15 @@ class FunctionPointerType extends Type, CustomModifierReceiver, Parameterizable, int getCallingConvention() { cil_function_pointer_calling_conventions(this, result) } override string toString() { result = Type.super.toString() } + + /** Holds if the return type is `void`. */ + predicate returnsVoid() { getReturnType() instanceof VoidType } + + /** Gets the number of stack items pushed in a call to this method. */ + int getCallPushCount() { if returnsVoid() then result = 0 else result = 1 } + + /** Gets the number of stack items popped in a call to this method. */ + int getCallPopCount() { result = count(getRawParameter(_)) } + + override string getLabel() { result = getName() } } diff --git a/csharp/ql/src/semmle/code/csharp/Type.qll b/csharp/ql/src/semmle/code/csharp/Type.qll index 13b7f8275df..cf055062e33 100644 --- a/csharp/ql/src/semmle/code/csharp/Type.qll +++ b/csharp/ql/src/semmle/code/csharp/Type.qll @@ -902,6 +902,8 @@ class FunctionPointerType extends Type, Parameterizable, @function_pointer_type AnnotatedType getAnnotatedReturnType() { result.appliesTo(this) } override string getAPrimaryQlClass() { result = "FunctionPointerType" } + + override string getLabel() { result = getName() } } /** diff --git a/csharp/ql/test/library-tests/cil/consistency/consistency.expected b/csharp/ql/test/library-tests/cil/consistency/consistency.expected index ccee053d8a4..3db667efdc5 100644 --- a/csharp/ql/test/library-tests/cil/consistency/consistency.expected +++ b/csharp/ql/test/library-tests/cil/consistency/consistency.expected @@ -1,19 +1 @@ -| DispatchTailCalls | No label | -| EnumCalendarInfo | No label | | Finalize | Overridden method from System.Object is not in a base type | -| Unknown instruction in DispatchTailCalls | Call has invalid target | -| Unknown instruction in DispatchTailCalls | Cfg node has 0 pop counts | -| Unknown instruction in DispatchTailCalls | Cfg node has 0 push counts | -| Unknown instruction in DispatchTailCalls | Inconsistent stack size | -| Unknown instruction in DispatchTailCalls | Opcode 41 is missing a QL class | -| bne.un.s | Inconsistent stack size | -| conv.u | Inconsistent stack size | -| delegate* managed | No label | -| delegate* unmanaged | No label | -| ldarg.1 | Inconsistent stack size | -| ldc.i4.0 | Inconsistent stack size | -| ldfld | Inconsistent stack size | -| ldloc.3 | Inconsistent stack size | -| leave.s | Inconsistent stack size | -| ret | Inconsistent stack size | -| starg.s | Inconsistent stack size | From 7ae640ce166276ef185eaed0ec227b4207a892a6 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Thu, 11 Feb 2021 22:02:48 +0100 Subject: [PATCH 108/142] Fix OS specific tests --- .../test/library-tests/cil/attributes/attribute.expected | 3 --- csharp/ql/test/library-tests/cil/attributes/attribute.ql | 5 +++++ .../cil/typeAnnotations/typeAnnotations.expected | 3 --- .../library-tests/cil/typeAnnotations/typeAnnotations.ql | 8 +++++++- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/csharp/ql/test/library-tests/cil/attributes/attribute.expected b/csharp/ql/test/library-tests/cil/attributes/attribute.expected index b43396e796d..7ced55cab61 100644 --- a/csharp/ql/test/library-tests/cil/attributes/attribute.expected +++ b/csharp/ql/test/library-tests/cil/attributes/attribute.expected @@ -9,9 +9,6 @@ attrNoArg | Interop.Sys.<>c__DisplayClass37_0 | [CompilerGeneratedAttribute(...)] | | Interop.Sys.FileStatusFlags | [FlagsAttribute(...)] | | Interop.Sys.OpenFlags | [FlagsAttribute(...)] | -| Interop.libobjc.NSOperatingSystemVersion.majorVersion | [NativeIntegerAttribute(...)] | -| Interop.libobjc.NSOperatingSystemVersion.minorVersion | [NativeIntegerAttribute(...)] | -| Interop.libobjc.NSOperatingSystemVersion.patchVersion | [NativeIntegerAttribute(...)] | | InteropErrorExtensions | [ExtensionAttribute(...)] | | Microsoft.CodeAnalysis.EmbeddedAttribute | [CompilerGeneratedAttribute(...)] | | Microsoft.CodeAnalysis.EmbeddedAttribute | [EmbeddedAttribute(...)] | diff --git a/csharp/ql/test/library-tests/cil/attributes/attribute.ql b/csharp/ql/test/library-tests/cil/attributes/attribute.ql index a0e56a607bf..ce5ed1e1daf 100644 --- a/csharp/ql/test/library-tests/cil/attributes/attribute.ql +++ b/csharp/ql/test/library-tests/cil/attributes/attribute.ql @@ -1,8 +1,11 @@ import semmle.code.cil.Attribute import semmle.code.cil.Declaration +private predicate isOsSpecific(Declaration d) { d.getQualifiedName().matches("%libobjc%") } + query predicate attrNoArg(string dec, string attr) { exists(Declaration d, Attribute a | + not isOsSpecific(d) and a.getDeclaration() = d and not exists(a.getAnArgument()) | @@ -14,6 +17,7 @@ query predicate attrNoArg(string dec, string attr) { query predicate attrArgNamed(string dec, string attr, string name, string value) { exists(Declaration d, Attribute a | a.getDeclaration() = d and + not isOsSpecific(d) and a.getNamedArgument(name) = value | dec = d.toStringWithTypes() and @@ -24,6 +28,7 @@ query predicate attrArgNamed(string dec, string attr, string name, string value) query predicate attrArgPositional(string dec, string attr, int index, string value) { exists(Declaration d, Attribute a | a.getDeclaration() = d and + not isOsSpecific(d) and a.getArgument(index) = value | dec = d.toStringWithTypes() and diff --git a/csharp/ql/test/library-tests/cil/typeAnnotations/typeAnnotations.expected b/csharp/ql/test/library-tests/cil/typeAnnotations/typeAnnotations.expected index 24b111e695c..bc6ec867fb0 100644 --- a/csharp/ql/test/library-tests/cil/typeAnnotations/typeAnnotations.expected +++ b/csharp/ql/test/library-tests/cil/typeAnnotations/typeAnnotations.expected @@ -923,7 +923,6 @@ | Parameter 1 of SetException | parameter | 32 | | Parameter 1 of SetNotificationForWaitCompletion | parameter | 32 | | Parameter 1 of SetValue | parameter | 32 | -| Parameter 1 of SkipWhitespace | parameter | 32 | | Parameter 1 of SnapForObservation | parameter | 32 | | Parameter 1 of SplitName | parameter | 32 | | Parameter 1 of Start | parameter | 32 | @@ -1038,7 +1037,6 @@ | Parameter 1 of UInt32ToNumber | parameter | 32 | | Parameter 1 of UInt64ToNumber | parameter | 32 | | Parameter 1 of Unscale | parameter | 32 | -| Parameter 1 of ValidateVariableAndValue | parameter | 32 | | Parameter 1 of VarDecCmp | parameter | 32 | | Parameter 1 of VarDecCmpSub | parameter | 32 | | Parameter 1 of VarDecDiv | parameter | 32 | @@ -1318,7 +1316,6 @@ | Parameter 2 of TryGetStringValue | parameter | 32 | | Parameter 2 of TryGetTimeZone | parameter | 32 | | Parameter 2 of TryGetTimeZoneFromLocalMachine | parameter | 32 | -| Parameter 2 of TryGetUserNameFromPasswd | parameter | 32 | | Parameter 2 of TryGetValue | parameter | 32 | | Parameter 2 of TryGetValueWorker | parameter | 32 | | Parameter 2 of TryLoadTzFile | parameter | 32 | diff --git a/csharp/ql/test/library-tests/cil/typeAnnotations/typeAnnotations.ql b/csharp/ql/test/library-tests/cil/typeAnnotations/typeAnnotations.ql index 6544f049f7c..e35b46f673d 100644 --- a/csharp/ql/test/library-tests/cil/typeAnnotations/typeAnnotations.ql +++ b/csharp/ql/test/library-tests/cil/typeAnnotations/typeAnnotations.ql @@ -21,5 +21,11 @@ private string elementType(Element e) { } from Element e, int i -where cil_type_annotation(e, i) +where + cil_type_annotation(e, i) and + ( + not e instanceof Parameter or + e.(Parameter).getDeclaringElement().(Method).getDeclaringType().getQualifiedName() != + "System.Environment" // There are OS specific methods in this class + ) select e.toString(), elementType(e), i From 3b82abd7c711a9a6670b080735e9f84f9fb5f98e Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Tue, 2 Mar 2021 09:19:49 +0100 Subject: [PATCH 109/142] Simplify MissingCallTarget for calli --- csharp/ql/src/semmle/code/cil/ConsistencyChecks.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csharp/ql/src/semmle/code/cil/ConsistencyChecks.qll b/csharp/ql/src/semmle/code/cil/ConsistencyChecks.qll index 51b74b2463d..0c055381260 100644 --- a/csharp/ql/src/semmle/code/cil/ConsistencyChecks.qll +++ b/csharp/ql/src/semmle/code/cil/ConsistencyChecks.qll @@ -83,7 +83,7 @@ class MissingCallTarget extends InstructionViolation { exists(Call c | c = instruction | count(c.getTarget()) != 1 and not c instanceof Opcodes::Calli or - count(c.(Opcodes::Calli).getTargetType()) != 1 and c instanceof Opcodes::Calli + count(c.(Opcodes::Calli).getTargetType()) != 1 ) } From faf69d65da9e0a977cce1056fe51b12101ee915b Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Tue, 2 Mar 2021 09:23:15 +0100 Subject: [PATCH 110/142] Fix merge error --- csharp/extractor/Semmle.Extraction.CIL/Entities/Instruction.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csharp/extractor/Semmle.Extraction.CIL/Entities/Instruction.cs b/csharp/extractor/Semmle.Extraction.CIL/Entities/Instruction.cs index 11d4287fc59..3ea9332644c 100644 --- a/csharp/extractor/Semmle.Extraction.CIL/Entities/Instruction.cs +++ b/csharp/extractor/Semmle.Extraction.CIL/Entities/Instruction.cs @@ -432,7 +432,7 @@ namespace Semmle.Extraction.CIL.Entities } catch (Exception exc) { - Cx.Cx.Extractor.Logger.Log(Util.Logging.Severity.Warning, $"Couldn't interpret payload of payload type {PayloadType} as a function pointer type. {exc.Message} {exc.StackTrace}"); + Cx.Extractor.Logger.Log(Util.Logging.Severity.Warning, $"Couldn't interpret payload of payload type {PayloadType} as a function pointer type. {exc.Message} {exc.StackTrace}"); } if (target != null) From 394c82d5648123f3aed87729f4950995ec0d9ed6 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Tue, 2 Mar 2021 10:17:07 +0100 Subject: [PATCH 111/142] Apply suggestions from code review Adjust qldoc. --- .../src/semmle/code/java/frameworks/spring/SpringWeb.qll | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/java/ql/src/semmle/code/java/frameworks/spring/SpringWeb.qll b/java/ql/src/semmle/code/java/frameworks/spring/SpringWeb.qll index ad4e00959dc..dd8e660fd26 100644 --- a/java/ql/src/semmle/code/java/frameworks/spring/SpringWeb.qll +++ b/java/ql/src/semmle/code/java/frameworks/spring/SpringWeb.qll @@ -18,7 +18,11 @@ class SpringNativeWebRequest extends Class { } } -/** Models Spring `servlet` as well as `portlet` package's `ModelAndView` class. */ +/** + * A Spring `ModelAndView` class. This is either + * `org.springframework.web.servlet.ModelAndView` or + * `org.springframework.web.portlet.ModelAndView`. + */ class ModelAndView extends Class { ModelAndView() { hasQualifiedName(["org.springframework.web.servlet", "org.springframework.web.portlet"], @@ -26,7 +30,7 @@ class ModelAndView extends Class { } } -/** Models a call to the Spring `ModelAndView` class's `setViewName` method. */ +/** A call to the Spring `ModelAndView.setViewName` method. */ class SpringModelAndViewSetViewNameCall extends MethodAccess { SpringModelAndViewSetViewNameCall() { getMethod().getDeclaringType() instanceof ModelAndView and From 6460ce3f83c1da8fee7dcc08c5485d07880acc86 Mon Sep 17 00:00:00 2001 From: Owen Mansel-Chan Date: Tue, 2 Mar 2021 10:39:47 +0000 Subject: [PATCH 112/142] Add @codeql-go as code owners for the shared data-flow library files --- CODEOWNERS | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/CODEOWNERS b/CODEOWNERS index 9d0596fbc96..da670301f30 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -10,3 +10,10 @@ /java/**/experimental/**/* @github/codeql-java @xcorail /javascript/**/experimental/**/* @github/codeql-javascript @xcorail /python/**/experimental/**/* @github/codeql-python @xcorail + +# Notify members of codeql-go about PRs to the shared data-flow library files +/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl.qll @github/codeql-java @github/codeql-go +/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImpl2.qll @github/codeql-java @github/codeql-go +/java/ql/src/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll @github/codeql-java @github/codeql-go +/java/ql/src/semmle/code/java/dataflow/internal/tainttracking1/TaintTrackingImpl.qll @github/codeql-java @github/codeql-go +/java/ql/src/semmle/code/java/dataflow/internal/tainttracking2/TaintTrackingImpl.qll @github/codeql-java @github/codeql-go From fa2f3456113d62946c0572cb1b418ad106020dff Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Tue, 2 Mar 2021 12:58:42 +0100 Subject: [PATCH 113/142] Revert "Simplify MissingCallTarget for calli" This reverts commit 3b82abd7c711a9a6670b080735e9f84f9fb5f98e. --- csharp/ql/src/semmle/code/cil/ConsistencyChecks.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/csharp/ql/src/semmle/code/cil/ConsistencyChecks.qll b/csharp/ql/src/semmle/code/cil/ConsistencyChecks.qll index 0c055381260..51b74b2463d 100644 --- a/csharp/ql/src/semmle/code/cil/ConsistencyChecks.qll +++ b/csharp/ql/src/semmle/code/cil/ConsistencyChecks.qll @@ -83,7 +83,7 @@ class MissingCallTarget extends InstructionViolation { exists(Call c | c = instruction | count(c.getTarget()) != 1 and not c instanceof Opcodes::Calli or - count(c.(Opcodes::Calli).getTargetType()) != 1 + count(c.(Opcodes::Calli).getTargetType()) != 1 and c instanceof Opcodes::Calli ) } From b9783598037f93c285c259ac3b8fd829f033eef7 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 22 Feb 2021 20:28:39 +0000 Subject: [PATCH 114/142] JS: Add schema validation as TaintedObject sanitizer --- javascript/ql/src/javascript.qll | 1 + .../ql/src/semmle/javascript/JsonSchema.qll | 73 +++++++++++++++++++ .../javascript/security/TaintedObject.qll | 15 ++++ .../CWE-089/untyped/DatabaseAccesses.expected | 4 + .../CWE-089/untyped/SqlInjection.expected | 17 +++++ .../CWE-089/untyped/json-schema-validator.js | 37 ++++++++++ 6 files changed, 147 insertions(+) create mode 100644 javascript/ql/src/semmle/javascript/JsonSchema.qll create mode 100644 javascript/ql/test/query-tests/Security/CWE-089/untyped/json-schema-validator.js diff --git a/javascript/ql/src/javascript.qll b/javascript/ql/src/javascript.qll index 8b0996c740c..62d1c3f0eb0 100644 --- a/javascript/ql/src/javascript.qll +++ b/javascript/ql/src/javascript.qll @@ -36,6 +36,7 @@ import semmle.javascript.InclusionTests import semmle.javascript.JSDoc import semmle.javascript.JSON import semmle.javascript.JsonParsers +import semmle.javascript.JsonSchema import semmle.javascript.JsonStringifiers import semmle.javascript.JSX import semmle.javascript.Lines diff --git a/javascript/ql/src/semmle/javascript/JsonSchema.qll b/javascript/ql/src/semmle/javascript/JsonSchema.qll new file mode 100644 index 00000000000..1acb716b85d --- /dev/null +++ b/javascript/ql/src/semmle/javascript/JsonSchema.qll @@ -0,0 +1,73 @@ +/** + * Provides classes and predicates for working with JSON schema libraries. + */ + +import javascript + +/** + * Provides classes and predicates for working with JSON schema libraries. + */ +module JsonSchema { + /** A call that validates an input against a JSON schema. */ + abstract class ValidationCall extends DataFlow::CallNode { + /** Gets the data flow node whose value is being validated. */ + abstract DataFlow::Node getInput(); + + /** Gets the return value that indicates successful validation. */ + boolean getPolarity() { result = true } + } + + /** Provides a model of the `ajv` library. */ + module Ajv { + /** A method on `Ajv` that returns `this`. */ + private string chainedMethod() { + result = + ["addSchema", "addMetaSchema", "removeSchema", "addFormat", "addKeyword", "removeKeyword"] + } + + /** An instance of `ajv`. */ + class Instance extends API::InvokeNode { + Instance() { this = API::moduleImport("ajv").getAnInstantiation() } + + /** Gets the data flow node holding the options passed to this `Ajv` instance. */ + DataFlow::Node getOptionsArg() { result = getArgument(0) } + + /** Gets an API node that refers to this object. */ + API::Node ref() { + result = getReturn() + or + result = ref().getMember(chainedMethod()).getReturn() + } + } + + /** A call to the `validate` method of `ajv`. */ + class AjvValidationCall extends ValidationCall { + Instance instance; + int argIndex; + + AjvValidationCall() { + this = instance.ref().getMember("validate").getACall() and argIndex = 1 + or + this = instance.ref().getMember(["compile", "getSchema"]).getReturn().getACall() and + argIndex = 0 + or + this = instance.ref().getMember("compileAsync").getPromised().getACall() and argIndex = 0 + } + + override DataFlow::Node getInput() { result = getArgument(argIndex) } + + /** Gets the argument holding additional options to the call. */ + DataFlow::Node getOwnOptionsArg() { result = getArgument(argIndex + 1) } + + /** Gets a data flow passed as the extra options to this validation call or to the underlying `Ajv` instance. */ + DataFlow::Node getAnOptionsArg() { + result = getOwnOptionsArg() + or + result = instance.getOptionsArg() + } + + /** Gets the ajv instance doing the validation. */ + Instance getAjvInstance() { result = instance } + } + } +} diff --git a/javascript/ql/src/semmle/javascript/security/TaintedObject.qll b/javascript/ql/src/semmle/javascript/security/TaintedObject.qll index 7f66594254f..74ee006c37c 100644 --- a/javascript/ql/src/semmle/javascript/security/TaintedObject.qll +++ b/javascript/ql/src/semmle/javascript/security/TaintedObject.qll @@ -120,4 +120,19 @@ module TaintedObject { label = label() } } + + /** + * A sanitizer guard that validates an input against a JSON schema. + */ + private class JsonSchemaValidationGuard extends SanitizerGuard { + JsonSchema::ValidationCall call; + + JsonSchemaValidationGuard() { this = call } + + override predicate sanitizes(boolean outcome, Expr e, FlowLabel label) { + outcome = call.getPolarity() and + e = call.getInput().asExpr() and + label = label() + } + } } diff --git a/javascript/ql/test/query-tests/Security/CWE-089/untyped/DatabaseAccesses.expected b/javascript/ql/test/query-tests/Security/CWE-089/untyped/DatabaseAccesses.expected index d17ff8d1cc4..5bf367a4c18 100644 --- a/javascript/ql/test/query-tests/Security/CWE-089/untyped/DatabaseAccesses.expected +++ b/javascript/ql/test/query-tests/Security/CWE-089/untyped/DatabaseAccesses.expected @@ -1,3 +1,7 @@ +| json-schema-validator.js:27:13:27:27 | doc.find(query) | +| json-schema-validator.js:30:13:30:27 | doc.find(query) | +| json-schema-validator.js:33:13:33:27 | doc.find(query) | +| json-schema-validator.js:35:9:35:23 | doc.find(query) | | marsdb-flow-to.js:14:3:14:22 | db.myDoc.find(query) | | marsdb.js:16:3:16:17 | doc.find(query) | | minimongo.js:18:3:18:17 | doc.find(query) | diff --git a/javascript/ql/test/query-tests/Security/CWE-089/untyped/SqlInjection.expected b/javascript/ql/test/query-tests/Security/CWE-089/untyped/SqlInjection.expected index e33f30d01ba..427e2fb853c 100644 --- a/javascript/ql/test/query-tests/Security/CWE-089/untyped/SqlInjection.expected +++ b/javascript/ql/test/query-tests/Security/CWE-089/untyped/SqlInjection.expected @@ -1,4 +1,12 @@ nodes +| json-schema-validator.js:25:15:25:48 | query | +| json-schema-validator.js:25:23:25:48 | JSON.pa ... y.data) | +| json-schema-validator.js:25:34:25:47 | req.query.data | +| json-schema-validator.js:25:34:25:47 | req.query.data | +| json-schema-validator.js:33:22:33:26 | query | +| json-schema-validator.js:33:22:33:26 | query | +| json-schema-validator.js:35:18:35:22 | query | +| json-schema-validator.js:35:18:35:22 | query | | marsdb-flow-to.js:10:9:10:18 | query | | marsdb-flow-to.js:10:17:10:18 | {} | | marsdb-flow-to.js:11:17:11:24 | req.body | @@ -250,6 +258,13 @@ nodes | tst.js:10:46:10:58 | req.params.id | | tst.js:10:46:10:58 | req.params.id | edges +| json-schema-validator.js:25:15:25:48 | query | json-schema-validator.js:33:22:33:26 | query | +| json-schema-validator.js:25:15:25:48 | query | json-schema-validator.js:33:22:33:26 | query | +| json-schema-validator.js:25:15:25:48 | query | json-schema-validator.js:35:18:35:22 | query | +| json-schema-validator.js:25:15:25:48 | query | json-schema-validator.js:35:18:35:22 | query | +| json-schema-validator.js:25:23:25:48 | JSON.pa ... y.data) | json-schema-validator.js:25:15:25:48 | query | +| json-schema-validator.js:25:34:25:47 | req.query.data | json-schema-validator.js:25:23:25:48 | JSON.pa ... y.data) | +| json-schema-validator.js:25:34:25:47 | req.query.data | json-schema-validator.js:25:23:25:48 | JSON.pa ... y.data) | | marsdb-flow-to.js:10:9:10:18 | query | marsdb-flow-to.js:14:17:14:21 | query | | marsdb-flow-to.js:10:9:10:18 | query | marsdb-flow-to.js:14:17:14:21 | query | | marsdb-flow-to.js:10:17:10:18 | {} | marsdb-flow-to.js:10:9:10:18 | query | @@ -586,6 +601,8 @@ edges | tst.js:10:46:10:58 | req.params.id | tst.js:10:10:10:64 | 'SELECT ... d + '"' | | tst.js:10:46:10:58 | req.params.id | tst.js:10:10:10:64 | 'SELECT ... d + '"' | #select +| json-schema-validator.js:33:22:33:26 | query | json-schema-validator.js:25:34:25:47 | req.query.data | json-schema-validator.js:33:22:33:26 | query | This query depends on $@. | json-schema-validator.js:25:34:25:47 | req.query.data | a user-provided value | +| json-schema-validator.js:35:18:35:22 | query | json-schema-validator.js:25:34:25:47 | req.query.data | json-schema-validator.js:35:18:35:22 | query | This query depends on $@. | json-schema-validator.js:25:34:25:47 | req.query.data | a user-provided value | | marsdb-flow-to.js:14:17:14:21 | query | marsdb-flow-to.js:11:17:11:24 | req.body | marsdb-flow-to.js:14:17:14:21 | query | This query depends on $@. | marsdb-flow-to.js:11:17:11:24 | req.body | a user-provided value | | marsdb.js:16:12:16:16 | query | marsdb.js:13:17:13:24 | req.body | marsdb.js:16:12:16:16 | query | This query depends on $@. | marsdb.js:13:17:13:24 | req.body | a user-provided value | | minimongo.js:18:12:18:16 | query | minimongo.js:15:17:15:24 | req.body | minimongo.js:18:12:18:16 | query | This query depends on $@. | minimongo.js:15:17:15:24 | req.body | a user-provided value | diff --git a/javascript/ql/test/query-tests/Security/CWE-089/untyped/json-schema-validator.js b/javascript/ql/test/query-tests/Security/CWE-089/untyped/json-schema-validator.js new file mode 100644 index 00000000000..93f09a51adb --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-089/untyped/json-schema-validator.js @@ -0,0 +1,37 @@ +import Ajv from 'ajv'; +import express from 'express'; +import { MongoClient } from 'mongodb'; + +const app = express(); + +const schema = { + type: 'object', + properties: { + date: { type: 'string' }, + title: { type: 'string' }, + }, +}; +const ajv = new Ajv(); +const checkSchema = ajv.compile(schema); + +function validate(x) { + return x != null; +} + +app.post('/documents/find', (req, res) => { + MongoClient.connect('mongodb://localhost:27017/test', (err, db) => { + let doc = db.collection('doc'); + + const query = JSON.parse(req.query.data); + if (checkSchema(query)) { + doc.find(query); // OK + } + if (ajv.validate(schema, query)) { + doc.find(query); // OK + } + if (validate(query)) { + doc.find(query); // NOT OK - validate() doesn't sanitize + } + doc.find(query); // NOT OK + }); +}); From 24199a54998e7e323216090344e4e06dcdf3531b Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Wed, 24 Feb 2021 15:33:15 +0000 Subject: [PATCH 115/142] JS: Add query for resource exhaustion from deep object handling --- .../DeepObjectResourceExhaustion.qhelp | 55 +++++++++++++ .../CWE-400/DeepObjectResourceExhaustion.ql | 23 ++++++ .../examples/DeepObjectResourceExhaustion.js | 14 ++++ .../DeepObjectResourceExhaustion_fixed.js | 14 ++++ .../dataflow/DeepObjectResourceExhaustion.qll | 43 ++++++++++ ...ObjectResourceExhaustionCustomizations.qll | 78 +++++++++++++++++++ 6 files changed, 227 insertions(+) create mode 100644 javascript/ql/src/Security/CWE-400/DeepObjectResourceExhaustion.qhelp create mode 100644 javascript/ql/src/Security/CWE-400/DeepObjectResourceExhaustion.ql create mode 100644 javascript/ql/src/Security/CWE-400/examples/DeepObjectResourceExhaustion.js create mode 100644 javascript/ql/src/Security/CWE-400/examples/DeepObjectResourceExhaustion_fixed.js create mode 100644 javascript/ql/src/semmle/javascript/security/dataflow/DeepObjectResourceExhaustion.qll create mode 100644 javascript/ql/src/semmle/javascript/security/dataflow/DeepObjectResourceExhaustionCustomizations.qll diff --git a/javascript/ql/src/Security/CWE-400/DeepObjectResourceExhaustion.qhelp b/javascript/ql/src/Security/CWE-400/DeepObjectResourceExhaustion.qhelp new file mode 100644 index 00000000000..e778d9237d5 --- /dev/null +++ b/javascript/ql/src/Security/CWE-400/DeepObjectResourceExhaustion.qhelp @@ -0,0 +1,55 @@ + + + + +

    + Processing user-controlled data with a method that allocates excessive amounts + of memory can lead to denial of service. +

    + +

    + If the JSON schema validation library ajv is configured with + allErrors: true there is no limit to how many error objects + will be allocated. An attacker can exploit this by sending an object that + deliberately contains a huge number of errors, and in some cases, with + longer and longer error messages. This can cause the service to become + unresponsive due to the slow error-checking process. +

    +
    + + +

    + Do not use allErrors: true in production. +

    +
    + + +

    + In the example below, the user-submitted object req.body is + validated using ajv and allErrors: true: +

    + + + +

    + Although this ensures that req.body conforms to the schema, + the validation itself could be vulnerable to a denial-of-service attack. + An attacker could send an object containing so many errors that the server + runs out of memory. +

    + +

    + A solution is to not pass in allErrors: true, which means + ajv will only report the first error, not all of them: +

    + + +
    + + +
  • Ajv documentation: security considerations +
  • +
    +
    diff --git a/javascript/ql/src/Security/CWE-400/DeepObjectResourceExhaustion.ql b/javascript/ql/src/Security/CWE-400/DeepObjectResourceExhaustion.ql new file mode 100644 index 00000000000..69ce56fd17f --- /dev/null +++ b/javascript/ql/src/Security/CWE-400/DeepObjectResourceExhaustion.ql @@ -0,0 +1,23 @@ +/** + * @name Resources exhaustion from deep object traversal + * @description Processing user-controlled object hierarchies inefficiently can lead to denial of service. + * @kind path-problem + * @problem.severity warning + * @precision high + * @id js/resource-exhaustion-from-deep-object-traversal + * @tags security + * external/cwe/cwe-400 + */ + +import javascript +import DataFlow::PathGraph +import semmle.javascript.security.dataflow.DeepObjectResourceExhaustion::DeepObjectResourceExhaustion + +from + Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink, DataFlow::Node link, + string reason +where + cfg.hasFlowPath(source, sink) and + sink.getNode().(Sink).hasReason(link, reason) +select sink, source, sink, "Denial of service caused by processing user input from $@ with $@.", + source.getNode(), "here", link, reason diff --git a/javascript/ql/src/Security/CWE-400/examples/DeepObjectResourceExhaustion.js b/javascript/ql/src/Security/CWE-400/examples/DeepObjectResourceExhaustion.js new file mode 100644 index 00000000000..dfeac169558 --- /dev/null +++ b/javascript/ql/src/Security/CWE-400/examples/DeepObjectResourceExhaustion.js @@ -0,0 +1,14 @@ +import express from 'express'; +import Ajv from 'ajv'; + +let ajv = new Ajv({ allErrors: true }); +ajv.addSchema(require('./input-schema'), 'input'); + +var app = express(); +app.get('/user/:id', function(req, res) { + if (!ajv.validate('input', req.body)) { + res.end(ajv.errorsText()); + return; + } + // ... +}); diff --git a/javascript/ql/src/Security/CWE-400/examples/DeepObjectResourceExhaustion_fixed.js b/javascript/ql/src/Security/CWE-400/examples/DeepObjectResourceExhaustion_fixed.js new file mode 100644 index 00000000000..0c16bf565b2 --- /dev/null +++ b/javascript/ql/src/Security/CWE-400/examples/DeepObjectResourceExhaustion_fixed.js @@ -0,0 +1,14 @@ +import express from 'express'; +import Ajv from 'ajv'; + +let ajv = new Ajv({ allErrors: process.env['REST_DEBUG'] }); +ajv.addSchema(require('./input-schema'), 'input'); + +var app = express(); +app.get('/user/:id', function(req, res) { + if (!ajv.validate('input', req.body)) { + res.end(ajv.errorsText()); + return; + } + // ... +}); diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/DeepObjectResourceExhaustion.qll b/javascript/ql/src/semmle/javascript/security/dataflow/DeepObjectResourceExhaustion.qll new file mode 100644 index 00000000000..d4f8b66c699 --- /dev/null +++ b/javascript/ql/src/semmle/javascript/security/dataflow/DeepObjectResourceExhaustion.qll @@ -0,0 +1,43 @@ +/** + * Provides a taint tracking configuration for reasoning about DoS attacks + * due to inefficient handling of user-controlled objects. + */ + +import javascript +import semmle.javascript.security.TaintedObject + +module DeepObjectResourceExhaustion { + import DeepObjectResourceExhaustionCustomizations::DeepObjectResourceExhaustion + + /** + * A taint tracking configuration for reasoning about DoS attacks due to inefficient handling + * of user-controlled objects. + */ + class Configuration extends TaintTracking::Configuration { + Configuration() { this = "DeepObjectResourceExhaustion" } + + override predicate isSource(DataFlow::Node source, DataFlow::FlowLabel label) { + source instanceof Source and label = TaintedObject::label() + or + // We currently can't expose the TaintedObject label in the Customizations library + // so just add its default sources here. + source instanceof TaintedObject::Source and label = TaintedObject::label() + or + source instanceof RemoteFlowSource and label.isTaint() + } + + override predicate isSink(DataFlow::Node sink, DataFlow::FlowLabel label) { + sink instanceof Sink and label = TaintedObject::label() + } + + override predicate isSanitizerGuard(TaintTracking::SanitizerGuardNode guard) { + guard instanceof TaintedObject::SanitizerGuard + } + + override predicate isAdditionalFlowStep( + DataFlow::Node src, DataFlow::Node trg, DataFlow::FlowLabel inlbl, DataFlow::FlowLabel outlbl + ) { + TaintedObject::step(src, trg, inlbl, outlbl) + } + } +} diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/DeepObjectResourceExhaustionCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/DeepObjectResourceExhaustionCustomizations.qll new file mode 100644 index 00000000000..86d6d19634d --- /dev/null +++ b/javascript/ql/src/semmle/javascript/security/dataflow/DeepObjectResourceExhaustionCustomizations.qll @@ -0,0 +1,78 @@ +/** + * Provides sources, sinks and sanitizers for reasoning about + * DoS attacks due to inefficient handling of user-controlled objects. + */ + +import javascript + +/** + * Provides sources, sinks and sanitizers for reasoning about + * DoS attacks due to inefficient handling of user-controlled objects. + */ +module DeepObjectResourceExhaustion { + /** + * A data flow source for slow input validation. + */ + abstract class Source extends DataFlow::Node { } + + /** + * A data flow sink for slow input validation. + */ + abstract class Sink extends DataFlow::Node { + /** + * Holds if `link` and `text` should be included in the message to explain + * why the input validation is slow. + */ + abstract predicate hasReason(DataFlow::Node link, string text); + } + + /** + * A sanitizer for slow input validation. + */ + abstract class Sanitizer extends DataFlow::Node { } + + /** Gets a node that may refer to an object with `allErrors` set to `true`. */ + private DataFlow::SourceNode allErrorsObject( + DataFlow::TypeTracker t, DataFlow::PropWrite allErrors + ) { + t.start() and + exists(JsonSchema::Ajv::AjvValidationCall call) and // only compute if `ajv` is used + allErrors.getPropertyName() = "allErrors" and + allErrors.getRhs().mayHaveBooleanValue(true) and + result = allErrors.getBase().getALocalSource() + or + exists(ExtendCall call | + allErrorsObject(t.continue(), allErrors).flowsTo(call.getAnOperand()) and + (result = call or result = call.getDestinationOperand().getALocalSource()) + ) + or + exists(DataFlow::ObjectLiteralNode obj | + allErrorsObject(t.continue(), allErrors).flowsTo(obj.getASpreadProperty()) and + result = obj + ) + or + exists(DataFlow::TypeTracker t2 | result = allErrorsObject(t2, allErrors).track(t2, t)) + } + + /** Gets a node that may refer to an object with `allErrors` set to `true`. */ + private DataFlow::SourceNode allErrorsObject(DataFlow::PropWrite allErrors) { + result = allErrorsObject(DataFlow::TypeTracker::end(), allErrors) + } + + /** Argument to an `ajv` validation call configured with `allErrors: true`. */ + private class AjvValidationSink extends Sink { + DataFlow::PropWrite allErrors; + + AjvValidationSink() { + exists(JsonSchema::Ajv::AjvValidationCall call | + this = call.getInput() and + allErrorsObject(allErrors).flowsTo(call.getAnOptionsArg()) + ) + } + + override predicate hasReason(DataFlow::Node link, string text) { + link = allErrors and + text = "allErrors: true" + } + } +} From 7afa755597c2075e05c31b288ac8f8c129f810b4 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 26 Feb 2021 08:35:38 +0000 Subject: [PATCH 116/142] JS: Add ajv error as source of ExceptionXss --- .../src/Security/CWE-079/ExceptionXss.qhelp | 17 ++++++++-- .../ql/src/Security/CWE-079/ExceptionXss.ql | 12 ++++++- .../CWE-079/examples/ExceptionXssAjv.js | 13 +++++++ .../ql/src/semmle/javascript/JsonSchema.qll | 30 +++++++++++++--- .../security/dataflow/ExceptionXss.qll | 34 +++++++++++++++++++ .../ExceptionXss/ExceptionXss.expected | 5 +++ .../Security/CWE-079/ExceptionXss/ajv.js | 13 +++++++ 7 files changed, 117 insertions(+), 7 deletions(-) create mode 100644 javascript/ql/src/Security/CWE-079/examples/ExceptionXssAjv.js create mode 100644 javascript/ql/test/query-tests/Security/CWE-079/ExceptionXss/ajv.js diff --git a/javascript/ql/src/Security/CWE-079/ExceptionXss.qhelp b/javascript/ql/src/Security/CWE-079/ExceptionXss.qhelp index f815794f6b8..7ab1038b067 100644 --- a/javascript/ql/src/Security/CWE-079/ExceptionXss.qhelp +++ b/javascript/ql/src/Security/CWE-079/ExceptionXss.qhelp @@ -5,8 +5,8 @@

    -Directly writing exceptions to a webpage without sanitization allows for a cross-site scripting -vulnerability if the value of the exception can be influenced by a user. +Directly writing error messages to a webpage without sanitization allows for a cross-site scripting +vulnerability if parts of the error message can be influenced by a user.

    @@ -27,6 +27,19 @@ leaving the website vulnerable to cross-site scripting. + +

    +This second example shows an input being validated using the JSON schema validator ajv, +and in case of an error, the error message is sent directly back in the response. +

    + +

    +This is unsafe, because the error message can contain parts of the input. +For example, the input {'<img src=x onerror=alert(1)>': 'foo'} will generate the error +data/<img src=x onerror=alert(1)> should be number, causing reflected XSS. +

    +
    +
  • OWASP: diff --git a/javascript/ql/src/Security/CWE-079/ExceptionXss.ql b/javascript/ql/src/Security/CWE-079/ExceptionXss.ql index 0926894fb7e..406c9145bc7 100644 --- a/javascript/ql/src/Security/CWE-079/ExceptionXss.ql +++ b/javascript/ql/src/Security/CWE-079/ExceptionXss.ql @@ -15,8 +15,18 @@ import javascript import semmle.javascript.security.dataflow.ExceptionXss::ExceptionXss import DataFlow::PathGraph +/** + * Gets a description of the source. + */ +string getSourceDescription(DataFlow::Node source) { + result = source.(ErrorSource).getDescription() + or + not source instanceof ErrorSource and + result = "Exception text" +} + from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasFlowPath(source, sink) select sink.getNode(), source, sink, "$@ is reinterpreted as HTML without escaping meta-characters.", source.getNode(), - "Exception text" + getSourceDescription(source.getNode()) diff --git a/javascript/ql/src/Security/CWE-079/examples/ExceptionXssAjv.js b/javascript/ql/src/Security/CWE-079/examples/ExceptionXssAjv.js new file mode 100644 index 00000000000..8a3ddedb249 --- /dev/null +++ b/javascript/ql/src/Security/CWE-079/examples/ExceptionXssAjv.js @@ -0,0 +1,13 @@ +import express from 'express'; +import Ajv from 'ajv'; + +let app = express(); +let ajv = new Ajv(); + +ajv.addSchema({type: 'object', additionalProperties: {type: 'number'}}, 'pollData'); + +app.post('/polldata', (req, res) => { + if (!ajv.validate('pollData', req.body)) { + res.send(ajv.errorsText()); + } +}); diff --git a/javascript/ql/src/semmle/javascript/JsonSchema.qll b/javascript/ql/src/semmle/javascript/JsonSchema.qll index 1acb716b85d..bcb6710066c 100644 --- a/javascript/ql/src/semmle/javascript/JsonSchema.qll +++ b/javascript/ql/src/semmle/javascript/JsonSchema.qll @@ -38,6 +38,31 @@ module JsonSchema { or result = ref().getMember(chainedMethod()).getReturn() } + + /** + * Gets an API node for a function produced by `new Ajv().compile()` or similar. + * + * Note that this does not include the instance method `new Ajv().validate` as its + * signature is different. + */ + API::Node getAValidationFunction() { + result = ref().getMember(["compile", "getSchema"]).getReturn() + or + result = ref().getMember("compileAsync").getPromised() + } + + /** + * Gets an API node that refers to an error produced by this Ajv instance. + */ + API::Node getAValidationError() { + exists(API::Node base | + base = [ref(), getAValidationFunction()] + | + result = base.getMember("errors") + or + result = base.getMember("errorsText").getReturn() + ) + } } /** A call to the `validate` method of `ajv`. */ @@ -48,10 +73,7 @@ module JsonSchema { AjvValidationCall() { this = instance.ref().getMember("validate").getACall() and argIndex = 1 or - this = instance.ref().getMember(["compile", "getSchema"]).getReturn().getACall() and - argIndex = 0 - or - this = instance.ref().getMember("compileAsync").getPromised().getACall() and argIndex = 0 + this = instance.getAValidationFunction().getACall() and argIndex = 0 } override DataFlow::Node getInput() { result = getArgument(argIndex) } diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/ExceptionXss.qll b/javascript/ql/src/semmle/javascript/security/dataflow/ExceptionXss.qll index a23e9fecf4c..7eb08d5bb5f 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/ExceptionXss.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/ExceptionXss.qll @@ -130,6 +130,37 @@ module ExceptionXss { result = getCallbackErrorParam(pred) } + /** + * A source of error values that is likely to contain unencoded user input. + */ + abstract class ErrorSource extends DataFlow::Node { + /** + * Gets a human-readable description of what type of error this refers to. + * + * The result should be captialized and usable in the context of a noun. + */ + abstract string getDescription(); + } + + /** + * An error produced by validating using `ajv`. + * + * Such an error can contain property names from the input if the + * underlying schema uses `additionalProperties` or `propertyPatterns`. + * + * For example, an input of form `{"": 45}` might produce the error + * `data/ should be string`. + */ + private class JsonSchemaValidationError extends ErrorSource { + JsonSchemaValidationError() { + this = any(JsonSchema::Ajv::Instance i).getAValidationError().getAnImmediateUse() + } + + override string getDescription() { + result = "JSON schema validation error" + } + } + /** * A taint-tracking configuration for reasoning about XSS with possible exceptional flow. * Flow labels are used to ensure that we only report taint-flow that has been thrown in @@ -140,6 +171,9 @@ module ExceptionXss { override predicate isSource(DataFlow::Node source, DataFlow::FlowLabel label) { source instanceof Xss::Shared::Source and label instanceof NotYetThrown + or + source instanceof ErrorSource and + label.isTaint() } override predicate isSink(DataFlow::Node sink, DataFlow::FlowLabel label) { diff --git a/javascript/ql/test/query-tests/Security/CWE-079/ExceptionXss/ExceptionXss.expected b/javascript/ql/test/query-tests/Security/CWE-079/ExceptionXss/ExceptionXss.expected index aba89bbe379..f7312726786 100644 --- a/javascript/ql/test/query-tests/Security/CWE-079/ExceptionXss/ExceptionXss.expected +++ b/javascript/ql/test/query-tests/Security/CWE-079/ExceptionXss/ExceptionXss.expected @@ -1,4 +1,7 @@ nodes +| ajv.js:11:18:11:33 | ajv.errorsText() | +| ajv.js:11:18:11:33 | ajv.errorsText() | +| ajv.js:11:18:11:33 | ajv.errorsText() | | exception-xss.js:2:6:2:28 | foo | | exception-xss.js:2:12:2:28 | document.location | | exception-xss.js:2:12:2:28 | document.location | @@ -87,6 +90,7 @@ nodes | exception-xss.js:182:19:182:23 | error | | exception-xss.js:182:19:182:23 | error | edges +| ajv.js:11:18:11:33 | ajv.errorsText() | ajv.js:11:18:11:33 | ajv.errorsText() | | exception-xss.js:2:6:2:28 | foo | exception-xss.js:9:11:9:13 | foo | | exception-xss.js:2:6:2:28 | foo | exception-xss.js:15:9:15:11 | foo | | exception-xss.js:2:6:2:28 | foo | exception-xss.js:21:11:21:13 | foo | @@ -169,6 +173,7 @@ edges | exception-xss.js:180:26:180:30 | error | exception-xss.js:182:19:182:23 | error | | exception-xss.js:180:26:180:30 | error | exception-xss.js:182:19:182:23 | error | #select +| ajv.js:11:18:11:33 | ajv.errorsText() | ajv.js:11:18:11:33 | ajv.errorsText() | ajv.js:11:18:11:33 | ajv.errorsText() | $@ is reinterpreted as HTML without escaping meta-characters. | ajv.js:11:18:11:33 | ajv.errorsText() | JSON schema validation error | | exception-xss.js:11:18:11:18 | e | exception-xss.js:2:12:2:28 | document.location | exception-xss.js:11:18:11:18 | e | $@ is reinterpreted as HTML without escaping meta-characters. | exception-xss.js:2:12:2:28 | document.location | Exception text | | exception-xss.js:17:18:17:18 | e | exception-xss.js:2:12:2:28 | document.location | exception-xss.js:17:18:17:18 | e | $@ is reinterpreted as HTML without escaping meta-characters. | exception-xss.js:2:12:2:28 | document.location | Exception text | | exception-xss.js:23:18:23:18 | e | exception-xss.js:2:12:2:28 | document.location | exception-xss.js:23:18:23:18 | e | $@ is reinterpreted as HTML without escaping meta-characters. | exception-xss.js:2:12:2:28 | document.location | Exception text | diff --git a/javascript/ql/test/query-tests/Security/CWE-079/ExceptionXss/ajv.js b/javascript/ql/test/query-tests/Security/CWE-079/ExceptionXss/ajv.js new file mode 100644 index 00000000000..2ebbc46a4b3 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-079/ExceptionXss/ajv.js @@ -0,0 +1,13 @@ +import express from 'express'; +import Ajv from 'ajv'; + +let app = express(); +let ajv = new Ajv(); + +ajv.addSchema({type: 'object', additionalProperties: {type: 'number'}}, 'pollData'); + +app.post('/polldata', (req, res) => { + if (!ajv.validate('pollData', req.body)) { + res.send(ajv.errorsText()); // NOT OK + } +}); From 12079cd1e462d792ec0865aef3a22c3604c1641d Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Fri, 26 Feb 2021 15:25:52 +0000 Subject: [PATCH 117/142] JS: Recognize RegExps in JSON schemas --- .../ql/src/semmle/javascript/JsonSchema.qll | 34 +++++++++++++++++++ .../ql/src/semmle/javascript/Regexp.qll | 8 +++++ .../Performance/ReDoS/ReDoS.expected | 3 ++ .../Performance/ReDoS/jsonschema.js | 26 ++++++++++++++ 4 files changed, 71 insertions(+) create mode 100644 javascript/ql/test/query-tests/Performance/ReDoS/jsonschema.js diff --git a/javascript/ql/src/semmle/javascript/JsonSchema.qll b/javascript/ql/src/semmle/javascript/JsonSchema.qll index bcb6710066c..bf8cb8a6c2c 100644 --- a/javascript/ql/src/semmle/javascript/JsonSchema.qll +++ b/javascript/ql/src/semmle/javascript/JsonSchema.qll @@ -17,6 +17,34 @@ module JsonSchema { boolean getPolarity() { result = true } } + /** A data flow node that is used a JSON schema. */ + abstract class SchemaRoot extends DataFlow::Node { + } + + /** An object literal with a `$schema` property indicating it is the root of a JSON schema. */ + private class SchemaNodeByTag extends SchemaRoot, DataFlow::ObjectLiteralNode { + SchemaNodeByTag() { + getAPropertyWrite("$schema").getRhs().getStringValue().matches("%//json-schema.org%") + } + } + + /** Gets a data flow node that is part of a JSON schema. */ + private DataFlow::SourceNode getAPartOfJsonSchema(DataFlow::TypeBackTracker t) { + t.start() and + result = any(SchemaRoot n).getALocalSource() + or + result = getAPartOfJsonSchema(t.continue()).getAPropertySource() + or + exists(DataFlow::TypeBackTracker t2 | + result = getAPartOfJsonSchema(t2).backtrack(t2, t) + ) + } + + /** Gets a data flow node that is part of a JSON schema. */ + DataFlow::SourceNode getAPartOfJsonSchema() { + result = getAPartOfJsonSchema(DataFlow::TypeBackTracker::end()) + } + /** Provides a model of the `ajv` library. */ module Ajv { /** A method on `Ajv` that returns `this`. */ @@ -91,5 +119,11 @@ module JsonSchema { /** Gets the ajv instance doing the validation. */ Instance getAjvInstance() { result = instance } } + + private class AjvSchemaNode extends SchemaRoot { + AjvSchemaNode() { + this = any(Instance i).ref().getMember(["addSchema", "validate", "compile", "compileAsync"]).getParameter(0).getARhs() + } + } } } diff --git a/javascript/ql/src/semmle/javascript/Regexp.qll b/javascript/ql/src/semmle/javascript/Regexp.qll index 485848f40c4..b3cb2456ef2 100644 --- a/javascript/ql/src/semmle/javascript/Regexp.qll +++ b/javascript/ql/src/semmle/javascript/Regexp.qll @@ -865,6 +865,14 @@ predicate isInterpretedAsRegExp(DataFlow::Node source) { // because `String.prototype.search` returns a number not exists(PropAccess p | p.getBase() = mce.getEnclosingExpr()) ) + or + exists(DataFlow::SourceNode schema | + schema = JsonSchema::getAPartOfJsonSchema() + | + source = schema.getAPropertyWrite("pattern").getRhs() + or + source = schema.getAPropertySource("patternProperties").getAPropertyWrite().getPropertyNameExpr().flow() + ) ) } diff --git a/javascript/ql/test/query-tests/Performance/ReDoS/ReDoS.expected b/javascript/ql/test/query-tests/Performance/ReDoS/ReDoS.expected index a3aa59d63b1..4229d8f0c5f 100644 --- a/javascript/ql/test/query-tests/Performance/ReDoS/ReDoS.expected +++ b/javascript/ql/test/query-tests/Performance/ReDoS/ReDoS.expected @@ -12,6 +12,9 @@ | highlight.js:30:13:30:25 | (?:\\\\.\|[^`])+ | This part of the regular expression may cause exponential backtracking on strings starting with '`' and containing many repetitions of '\\\\_'. | | highlight.js:34:25:34:27 | \\w* | This part of the regular expression may cause exponential backtracking on strings starting with '?A' and containing many repetitions of 'A'. | | highlight.js:38:35:38:40 | [^()]* | This part of the regular expression may cause exponential backtracking on strings starting with 'A((' and containing many repetitions of '')('. | +| jsonschema.js:5:15:5:21 | (a?a?)* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'a'. | +| jsonschema.js:15:23:15:29 | (a?a?)* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'a'. | +| jsonschema.js:20:18:20:24 | (a?a?)* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of 'a'. | | polynomial-redos.js:17:5:17:6 | .* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of ','. | | polynomial-redos.js:41:52:41:63 | [\\x21-\\x7E]* | This part of the regular expression may cause exponential backtracking on strings containing many repetitions of '?'. | | polynomial-redos.js:46:33:46:45 | [a-zA-Z_0-9]* | This part of the regular expression may cause exponential backtracking on strings starting with 'A' and containing many repetitions of 'A'. | diff --git a/javascript/ql/test/query-tests/Performance/ReDoS/jsonschema.js b/javascript/ql/test/query-tests/Performance/ReDoS/jsonschema.js new file mode 100644 index 00000000000..542145de484 --- /dev/null +++ b/javascript/ql/test/query-tests/Performance/ReDoS/jsonschema.js @@ -0,0 +1,26 @@ +import Ajv from 'ajv'; + +let thing = { + type: 'string', + pattern: '(a?a?)*b' // NOT OK +} +new Ajv().addSchema(thing, 'thing'); + +export default { + $schema: "http://json-schema.org/draft-07/schema#", + type: "object", + properties: { + foo: { + type: "string", + pattern: "(a?a?)*b" // NOT OK + }, + bar: { + type: "object", + patternProperties: { + "(a?a?)*b": { // NOT OK + type: "number" + } + } + } + } +}; From 0bd60c1989c4e18fc6725d9f721555c222b6c9cf Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 1 Mar 2021 10:28:50 +0000 Subject: [PATCH 118/142] JS: Autoformat --- .../ql/src/semmle/javascript/JsonSchema.qll | 20 +++++++++---------- .../ql/src/semmle/javascript/Regexp.qll | 11 ++++++---- .../security/dataflow/ExceptionXss.qll | 4 +--- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/JsonSchema.qll b/javascript/ql/src/semmle/javascript/JsonSchema.qll index bf8cb8a6c2c..5c3306bf64b 100644 --- a/javascript/ql/src/semmle/javascript/JsonSchema.qll +++ b/javascript/ql/src/semmle/javascript/JsonSchema.qll @@ -18,8 +18,7 @@ module JsonSchema { } /** A data flow node that is used a JSON schema. */ - abstract class SchemaRoot extends DataFlow::Node { - } + abstract class SchemaRoot extends DataFlow::Node { } /** An object literal with a `$schema` property indicating it is the root of a JSON schema. */ private class SchemaNodeByTag extends SchemaRoot, DataFlow::ObjectLiteralNode { @@ -35,9 +34,7 @@ module JsonSchema { or result = getAPartOfJsonSchema(t.continue()).getAPropertySource() or - exists(DataFlow::TypeBackTracker t2 | - result = getAPartOfJsonSchema(t2).backtrack(t2, t) - ) + exists(DataFlow::TypeBackTracker t2 | result = getAPartOfJsonSchema(t2).backtrack(t2, t)) } /** Gets a data flow node that is part of a JSON schema. */ @@ -68,7 +65,7 @@ module JsonSchema { } /** - * Gets an API node for a function produced by `new Ajv().compile()` or similar. + * Gets an API node for a function produced by `new Ajv().compile()` or similar. * * Note that this does not include the instance method `new Ajv().validate` as its * signature is different. @@ -83,9 +80,7 @@ module JsonSchema { * Gets an API node that refers to an error produced by this Ajv instance. */ API::Node getAValidationError() { - exists(API::Node base | - base = [ref(), getAValidationFunction()] - | + exists(API::Node base | base = [ref(), getAValidationFunction()] | result = base.getMember("errors") or result = base.getMember("errorsText").getReturn() @@ -122,7 +117,12 @@ module JsonSchema { private class AjvSchemaNode extends SchemaRoot { AjvSchemaNode() { - this = any(Instance i).ref().getMember(["addSchema", "validate", "compile", "compileAsync"]).getParameter(0).getARhs() + this = + any(Instance i) + .ref() + .getMember(["addSchema", "validate", "compile", "compileAsync"]) + .getParameter(0) + .getARhs() } } } diff --git a/javascript/ql/src/semmle/javascript/Regexp.qll b/javascript/ql/src/semmle/javascript/Regexp.qll index b3cb2456ef2..a4612c3b49f 100644 --- a/javascript/ql/src/semmle/javascript/Regexp.qll +++ b/javascript/ql/src/semmle/javascript/Regexp.qll @@ -866,12 +866,15 @@ predicate isInterpretedAsRegExp(DataFlow::Node source) { not exists(PropAccess p | p.getBase() = mce.getEnclosingExpr()) ) or - exists(DataFlow::SourceNode schema | - schema = JsonSchema::getAPartOfJsonSchema() - | + exists(DataFlow::SourceNode schema | schema = JsonSchema::getAPartOfJsonSchema() | source = schema.getAPropertyWrite("pattern").getRhs() or - source = schema.getAPropertySource("patternProperties").getAPropertyWrite().getPropertyNameExpr().flow() + source = + schema + .getAPropertySource("patternProperties") + .getAPropertyWrite() + .getPropertyNameExpr() + .flow() ) ) } diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/ExceptionXss.qll b/javascript/ql/src/semmle/javascript/security/dataflow/ExceptionXss.qll index 7eb08d5bb5f..020231947e4 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/ExceptionXss.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/ExceptionXss.qll @@ -156,9 +156,7 @@ module ExceptionXss { this = any(JsonSchema::Ajv::Instance i).getAValidationError().getAnImmediateUse() } - override string getDescription() { - result = "JSON schema validation error" - } + override string getDescription() { result = "JSON schema validation error" } } /** From 05594f2936041206d9fc819acd635fa778823294 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 1 Mar 2021 10:34:18 +0000 Subject: [PATCH 119/142] JS: Change note --- javascript/change-notes/2021-03-01-ajv.md | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 javascript/change-notes/2021-03-01-ajv.md diff --git a/javascript/change-notes/2021-03-01-ajv.md b/javascript/change-notes/2021-03-01-ajv.md new file mode 100644 index 00000000000..c06bd4f5807 --- /dev/null +++ b/javascript/change-notes/2021-03-01-ajv.md @@ -0,0 +1,8 @@ +lgtm,codescanning +* The security queries now recognize the effect of JSON schema validation, and highlights + cases where this validation is susceptible to denial-of-service attacks. + Affects the package [ajv](https://npmjs.com/package/ajv). +* A new query, `js/resource-exhaustion-from-deep-object-traversal`, has been added to the query suite, + highlighting denial-of-service attacks exploiting operations that traverse deeply user-controlled objects. +* The `js/xss-through-exception` query now recognizes JSON schema validation errors as a source, as they + may contain part of the input data. From 31721b5fe3bbfed17202cb86828c709b692606a8 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 1 Mar 2021 12:56:28 +0000 Subject: [PATCH 120/142] JS: Fix missing qldoc --- .../security/dataflow/DeepObjectResourceExhaustion.qll | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/DeepObjectResourceExhaustion.qll b/javascript/ql/src/semmle/javascript/security/dataflow/DeepObjectResourceExhaustion.qll index d4f8b66c699..ca56d0e7180 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/DeepObjectResourceExhaustion.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/DeepObjectResourceExhaustion.qll @@ -6,6 +6,10 @@ import javascript import semmle.javascript.security.TaintedObject +/** + * Provides a taint tracking configuration for reasoning about DoS attacks + * due to inefficient handling of user-controlled objects. + */ module DeepObjectResourceExhaustion { import DeepObjectResourceExhaustionCustomizations::DeepObjectResourceExhaustion From fd9604c5ef701ba9eccfb09b98217ca5abe75aca Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Mon, 1 Mar 2021 13:00:34 +0000 Subject: [PATCH 121/142] JS: Update expected output for poly ReDoS --- .../Performance/ReDoS/PolynomialBackTracking.expected | 3 +++ 1 file changed, 3 insertions(+) diff --git a/javascript/ql/test/query-tests/Performance/ReDoS/PolynomialBackTracking.expected b/javascript/ql/test/query-tests/Performance/ReDoS/PolynomialBackTracking.expected index 8452d81ee07..cb7c526af5d 100644 --- a/javascript/ql/test/query-tests/Performance/ReDoS/PolynomialBackTracking.expected +++ b/javascript/ql/test/query-tests/Performance/ReDoS/PolynomialBackTracking.expected @@ -24,6 +24,9 @@ | highlight.js:38:54:38:59 | [^()]* | Strings starting with 'A((' and with many repetitions of ''' can start matching anywhere after the start of the preceeding [^()]* | | highlight.js:38:64:38:69 | [^()]* | Strings starting with 'A(' and with many repetitions of ''' can start matching anywhere after the start of the preceeding [^()]* | | highlight.js:39:22:39:24 | \\w* | Strings starting with 'A' and with many repetitions of 'A' can start matching anywhere after the start of the preceeding [a-zA-Z_]\\w*\\([^()]*(\\([^()]*(\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)\\s*\\{ | +| jsonschema.js:5:15:5:21 | (a?a?)* | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding (a?a?)*b | +| jsonschema.js:15:23:15:29 | (a?a?)* | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding (a?a?)*b | +| jsonschema.js:20:18:20:24 | (a?a?)* | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding (a?a?)*b | | lib/closure.js:4:6:4:7 | u* | Strings with many repetitions of 'u' can start matching anywhere after the start of the preceeding u*o | | lib/lib.js:1:15:1:16 | a* | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding a*b | | lib/lib.js:8:3:8:4 | f* | Strings with many repetitions of 'f' can start matching anywhere after the start of the preceeding f*g | From beb15e27eb21077d1ec915be0ec39303d1a8fe2b Mon Sep 17 00:00:00 2001 From: Porcuiney Hairs Date: Tue, 2 Mar 2021 18:13:33 +0530 Subject: [PATCH 122/142] remove tests --- .../query-tests/security/CWE-489/StrutsBad.xml | 11 ----------- .../query-tests/security/CWE-489/StrutsGood.xml | 11 ----------- .../query-tests/security/CWE-489/devMode.expected | 1 - .../query-tests/security/CWE-489/devMode.qlref | 1 - 4 files changed, 24 deletions(-) delete mode 100644 java/ql/test/experimental/query-tests/security/CWE-489/StrutsBad.xml delete mode 100644 java/ql/test/experimental/query-tests/security/CWE-489/StrutsGood.xml delete mode 100644 java/ql/test/experimental/query-tests/security/CWE-489/devMode.expected delete mode 100644 java/ql/test/experimental/query-tests/security/CWE-489/devMode.qlref diff --git a/java/ql/test/experimental/query-tests/security/CWE-489/StrutsBad.xml b/java/ql/test/experimental/query-tests/security/CWE-489/StrutsBad.xml deleted file mode 100644 index 4ee9c1647cf..00000000000 --- a/java/ql/test/experimental/query-tests/security/CWE-489/StrutsBad.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-489/StrutsGood.xml b/java/ql/test/experimental/query-tests/security/CWE-489/StrutsGood.xml deleted file mode 100644 index 369b42a7ec9..00000000000 --- a/java/ql/test/experimental/query-tests/security/CWE-489/StrutsGood.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/java/ql/test/experimental/query-tests/security/CWE-489/devMode.expected b/java/ql/test/experimental/query-tests/security/CWE-489/devMode.expected deleted file mode 100644 index fec3ff3c2c8..00000000000 --- a/java/ql/test/experimental/query-tests/security/CWE-489/devMode.expected +++ /dev/null @@ -1 +0,0 @@ -| StrutsBad.xml:8:5:8:52 | constant | Enabling development mode in production environments is dangerous | diff --git a/java/ql/test/experimental/query-tests/security/CWE-489/devMode.qlref b/java/ql/test/experimental/query-tests/security/CWE-489/devMode.qlref deleted file mode 100644 index da70fb9a6c4..00000000000 --- a/java/ql/test/experimental/query-tests/security/CWE-489/devMode.qlref +++ /dev/null @@ -1 +0,0 @@ -experimental/Security/CWE/CWE-489/devMode.ql From b20ce8bfca2cea05bfe8e8589144f6f830ad5a9f Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 2 Mar 2021 14:04:23 +0100 Subject: [PATCH 123/142] use callgraph instead of TypeInference in Testing.qll --- javascript/ql/src/semmle/javascript/frameworks/Testing.qll | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/frameworks/Testing.qll b/javascript/ql/src/semmle/javascript/frameworks/Testing.qll index 631ed3b4611..fb2d85523d4 100644 --- a/javascript/ql/src/semmle/javascript/frameworks/Testing.qll +++ b/javascript/ql/src/semmle/javascript/frameworks/Testing.qll @@ -33,7 +33,7 @@ class BDDTest extends Test, @call_expr { exists(CallExpr call | call = this | call.getCallee().(VarAccess).getName() = "it" and exists(call.getArgument(0).getStringValue()) and - call.getArgument(1).analyze().getAValue() instanceof AbstractFunction + exists(call.getArgument(1).flow().getAFunctionValue(0)) ) } } @@ -60,7 +60,7 @@ class JestTest extends Test, @call_expr { exists(CallExpr call | call = this | call.getCallee().(GlobalVarAccess).getName() = "test" and exists(call.getArgument(0).getStringValue()) and - call.getArgument(1).analyze().getAValue() instanceof AbstractFunction + exists(call.getArgument(1).flow().getAFunctionValue(0)) ) and getFile() = getTestFile(any(File f), "test") } @@ -94,7 +94,7 @@ class CucumberTest extends Test, @call_expr { exists(DataFlow::ModuleImportNode m, CallExpr call | m.getPath() = "cucumber" and call = m.getAnInvocation().asExpr() and - call.getArgument(0).analyze().getAValue() instanceof AbstractFunction and + exists(call.getArgument(0).flow().getAFunctionValue()) and this = call ) } From ae56285331ff63672bae6778f01788a610309c64 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 2 Mar 2021 14:06:09 +0100 Subject: [PATCH 124/142] use callgraph instead of type-inference for array taint-steps --- javascript/ql/src/semmle/javascript/Arrays.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/Arrays.qll b/javascript/ql/src/semmle/javascript/Arrays.qll index 47b3771560b..0114dd923a8 100644 --- a/javascript/ql/src/semmle/javascript/Arrays.qll +++ b/javascript/ql/src/semmle/javascript/Arrays.qll @@ -25,7 +25,7 @@ module ArrayTaintTracking { // `array.map(function (elt, i, ary) { ... })`: if `array` is tainted, then so are // `elt` and `ary`; similar for `forEach` exists(Function f | - call.getArgument(0).analyze().getAValue().(AbstractFunction).getFunction() = f and + call.getArgument(0).getAFunctionValue(0).getFunction() = f and call.(DataFlow::MethodCallNode).getMethodName() = ["map", "forEach"] and pred = call.getReceiver() and succ = DataFlow::parameterNode(f.getParameter([0, 2])) From 47f4faa4e27e4254bb37701eaacb4c7dc602c6c6 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 2 Mar 2021 14:06:38 +0100 Subject: [PATCH 125/142] use local dataflow instead of type-inference for `mayHaveBooleanValue` --- javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll index 3a619033e3c..fe7ba8e2e75 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll @@ -106,7 +106,11 @@ module DataFlow { /** Holds if this node may evaluate to the Boolean value `b`. */ predicate mayHaveBooleanValue(boolean b) { - b = analyze().getAValue().(AbstractBoolean).getBooleanValue() + getAPredecessor().mayHaveBooleanValue(b) // needed stage 31 + stage 26 + stage 22 (unfixable) + or + b = true and asExpr().(BooleanLiteral).getValue() = "true" + or + b = false and asExpr().(BooleanLiteral).getValue() = "false" } /** Gets the integer value of this node, if it is an integer constant. */ From d916118ea42663cb46e0ccb1afd8644bfb58136e Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Tue, 2 Mar 2021 13:16:10 +0000 Subject: [PATCH 126/142] JS: Move ExceptionXss source into Xss.qll --- .../ql/src/Security/CWE-079/ExceptionXss.ql | 12 +--- .../security/dataflow/ExceptionXss.qll | 46 ++------------- .../javascript/security/dataflow/Xss.qll | 56 +++++++++++++++++++ 3 files changed, 62 insertions(+), 52 deletions(-) diff --git a/javascript/ql/src/Security/CWE-079/ExceptionXss.ql b/javascript/ql/src/Security/CWE-079/ExceptionXss.ql index 406c9145bc7..7c9cedc1705 100644 --- a/javascript/ql/src/Security/CWE-079/ExceptionXss.ql +++ b/javascript/ql/src/Security/CWE-079/ExceptionXss.ql @@ -15,18 +15,8 @@ import javascript import semmle.javascript.security.dataflow.ExceptionXss::ExceptionXss import DataFlow::PathGraph -/** - * Gets a description of the source. - */ -string getSourceDescription(DataFlow::Node source) { - result = source.(ErrorSource).getDescription() - or - not source instanceof ErrorSource and - result = "Exception text" -} - from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink where cfg.hasFlowPath(source, sink) select sink.getNode(), source, sink, "$@ is reinterpreted as HTML without escaping meta-characters.", source.getNode(), - getSourceDescription(source.getNode()) + source.getNode().(Source).getDescription() diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/ExceptionXss.qll b/javascript/ql/src/semmle/javascript/security/dataflow/ExceptionXss.qll index 020231947e4..3340df26e72 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/ExceptionXss.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/ExceptionXss.qll @@ -10,6 +10,7 @@ module ExceptionXss { import DomBasedXssCustomizations::DomBasedXss as DomBasedXssCustom import ReflectedXssCustomizations::ReflectedXss as ReflectedXssCustom import Xss as Xss + import Xss::ExceptionXss private import semmle.javascript.dataflow.InferredTypes /** @@ -71,14 +72,9 @@ module ExceptionXss { ) } - /** - * A FlowLabel representing tainted data that has not been thrown in an exception. - * In the js/xss-through-exception query data-flow can only reach a sink after - * the data has been thrown as an exception, and data that has not been thrown - * as an exception therefore has this flow label, and only this flow label, associated with it. - */ - class NotYetThrown extends DataFlow::FlowLabel { - NotYetThrown() { this = "NotYetThrown" } + // Materialize flow labels + private class ConcreteNotYetThrown extends Xss::ExceptionXss::NotYetThrown { + ConcreteNotYetThrown() { this = this } } /** @@ -130,35 +126,6 @@ module ExceptionXss { result = getCallbackErrorParam(pred) } - /** - * A source of error values that is likely to contain unencoded user input. - */ - abstract class ErrorSource extends DataFlow::Node { - /** - * Gets a human-readable description of what type of error this refers to. - * - * The result should be captialized and usable in the context of a noun. - */ - abstract string getDescription(); - } - - /** - * An error produced by validating using `ajv`. - * - * Such an error can contain property names from the input if the - * underlying schema uses `additionalProperties` or `propertyPatterns`. - * - * For example, an input of form `{"": 45}` might produce the error - * `data/ should be string`. - */ - private class JsonSchemaValidationError extends ErrorSource { - JsonSchemaValidationError() { - this = any(JsonSchema::Ajv::Instance i).getAValidationError().getAnImmediateUse() - } - - override string getDescription() { result = "JSON schema validation error" } - } - /** * A taint-tracking configuration for reasoning about XSS with possible exceptional flow. * Flow labels are used to ensure that we only report taint-flow that has been thrown in @@ -168,10 +135,7 @@ module ExceptionXss { Configuration() { this = "ExceptionXss" } override predicate isSource(DataFlow::Node source, DataFlow::FlowLabel label) { - source instanceof Xss::Shared::Source and label instanceof NotYetThrown - or - source instanceof ErrorSource and - label.isTaint() + source.(Xss::ExceptionXss::Source).getAFlowLabel() = label } override predicate isSink(DataFlow::Node sink, DataFlow::FlowLabel label) { diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll b/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll index ea911f95300..85b31b90995 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/Xss.qll @@ -602,3 +602,59 @@ module XssThroughDom { /** A data flow source for XSS through DOM vulnerabilities. */ abstract class Source extends Shared::Source { } } + +/** Provides classes for customizing the `ExceptionXss` query. */ +module ExceptionXss { + /** A data flow source for XSS caused by interpreting exception or error text as HTML. */ + abstract class Source extends DataFlow::Node { + /** + * Gets a flow label to associate with this source. + * + * For sources that should pass through a `throw/catch` before reaching the sink, use the + * `NotYetThrown` labe. Otherwise use `taint` (the default). + */ + DataFlow::FlowLabel getAFlowLabel() { result.isTaint() } + + /** + * Gets a human-readable description of what type of error this refers to. + * + * The result should be capitalized and usable in the context of a noun. + */ + string getDescription() { result = "Error text" } + } + + /** + * A FlowLabel representing tainted data that has not been thrown in an exception. + * In the js/xss-through-exception query data-flow can only reach a sink after + * the data has been thrown as an exception, and data that has not been thrown + * as an exception therefore has this flow label, and only this flow label, associated with it. + */ + abstract class NotYetThrown extends DataFlow::FlowLabel { + NotYetThrown() { this = "NotYetThrown" } + } + + private class XssSourceAsSource extends Source { + XssSourceAsSource() { this instanceof Shared::Source } + + override DataFlow::FlowLabel getAFlowLabel() { result instanceof NotYetThrown } + + override string getDescription() { result = "Exception text" } + } + + /** + * An error produced by validating using `ajv`. + * + * Such an error can contain property names from the input if the + * underlying schema uses `additionalProperties` or `propertyPatterns`. + * + * For example, an input of form `{"": 45}` might produce the error + * `data/ should be string`. + */ + private class JsonSchemaValidationError extends Source { + JsonSchemaValidationError() { + this = any(JsonSchema::Ajv::Instance i).getAValidationError().getAnImmediateUse() + } + + override string getDescription() { result = "JSON schema validation error" } + } +} From 5d27cd934dc51ada0be96131c5729f5eb533bd09 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Tue, 2 Mar 2021 13:52:27 +0000 Subject: [PATCH 127/142] JS: Move Source def into customizations lib --- .../javascript/security/TaintedObject.qll | 21 ++++---------- .../security/TaintedObjectCustomizations.qll | 28 +++++++++++++++++++ .../dataflow/DeepObjectResourceExhaustion.qll | 8 +----- ...ObjectResourceExhaustionCustomizations.qll | 18 +++++++++++- 4 files changed, 51 insertions(+), 24 deletions(-) create mode 100644 javascript/ql/src/semmle/javascript/security/TaintedObjectCustomizations.qll diff --git a/javascript/ql/src/semmle/javascript/security/TaintedObject.qll b/javascript/ql/src/semmle/javascript/security/TaintedObject.qll index 74ee006c37c..444dec2ae71 100644 --- a/javascript/ql/src/semmle/javascript/security/TaintedObject.qll +++ b/javascript/ql/src/semmle/javascript/security/TaintedObject.qll @@ -16,22 +16,16 @@ import javascript private import semmle.javascript.dataflow.InferredTypes +/** Provides classes and predicates for reasoning about deeply tainted objects. */ module TaintedObject { private import DataFlow + import TaintedObjectCustomizations::TaintedObject - private class TaintedObjectLabel extends FlowLabel { - TaintedObjectLabel() { this = "tainted-object" } + // Materialize flow labels + private class ConcreteTaintedObjectLabel extends TaintedObjectLabel { + ConcreteTaintedObjectLabel() { this = this } } - /** - * Gets the flow label representing a deeply tainted object. - * - * A "tainted object" is an array or object whose property values are all assumed to be tainted as well. - * - * Note that the presence of the this label generally implies the presence of the `taint` label as well. - */ - FlowLabel label() { result instanceof TaintedObjectLabel } - /** * Holds for the flows steps that are relevant for tracking user-controlled JSON objects. */ @@ -79,11 +73,6 @@ module TaintedObject { */ predicate isSource(Node source, FlowLabel label) { source instanceof Source and label = label() } - /** - * A source of a user-controlled deep object. - */ - abstract class Source extends DataFlow::Node { } - /** Request input accesses as a JSON source. */ private class RequestInputAsSource extends Source { RequestInputAsSource() { this.(HTTP::RequestInputAccess).isUserControlledObject() } diff --git a/javascript/ql/src/semmle/javascript/security/TaintedObjectCustomizations.qll b/javascript/ql/src/semmle/javascript/security/TaintedObjectCustomizations.qll new file mode 100644 index 00000000000..8e0fd38f15a --- /dev/null +++ b/javascript/ql/src/semmle/javascript/security/TaintedObjectCustomizations.qll @@ -0,0 +1,28 @@ +/** + * Provides access to the "tainted object" flow label defined in `TaintedObject.qll`, without + * materializing that flow label. + */ + +import javascript + +/** Provides classes and predicates for reasoning about deeply tainted objects. */ +module TaintedObject { + /** A flow label representing a deeply tainted object. */ + abstract class TaintedObjectLabel extends DataFlow::FlowLabel { + TaintedObjectLabel() { this = "tainted-object" } + } + + /** + * Gets the flow label representing a deeply tainted object. + * + * A "tainted object" is an array or object whose property values are all assumed to be tainted as well. + * + * Note that the presence of the this label generally implies the presence of the `taint` label as well. + */ + DataFlow::FlowLabel label() { result instanceof TaintedObjectLabel } + + /** + * A source of a user-controlled deep object. + */ + abstract class Source extends DataFlow::Node { } +} diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/DeepObjectResourceExhaustion.qll b/javascript/ql/src/semmle/javascript/security/dataflow/DeepObjectResourceExhaustion.qll index ca56d0e7180..31bccc11162 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/DeepObjectResourceExhaustion.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/DeepObjectResourceExhaustion.qll @@ -21,13 +21,7 @@ module DeepObjectResourceExhaustion { Configuration() { this = "DeepObjectResourceExhaustion" } override predicate isSource(DataFlow::Node source, DataFlow::FlowLabel label) { - source instanceof Source and label = TaintedObject::label() - or - // We currently can't expose the TaintedObject label in the Customizations library - // so just add its default sources here. - source instanceof TaintedObject::Source and label = TaintedObject::label() - or - source instanceof RemoteFlowSource and label.isTaint() + source.(Source).getAFlowLabel() = label } override predicate isSink(DataFlow::Node sink, DataFlow::FlowLabel label) { diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/DeepObjectResourceExhaustionCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/DeepObjectResourceExhaustionCustomizations.qll index 86d6d19634d..39ba56ba62b 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/DeepObjectResourceExhaustionCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/DeepObjectResourceExhaustionCustomizations.qll @@ -4,6 +4,7 @@ */ import javascript +private import semmle.javascript.security.TaintedObjectCustomizations /** * Provides sources, sinks and sanitizers for reasoning about @@ -13,7 +14,22 @@ module DeepObjectResourceExhaustion { /** * A data flow source for slow input validation. */ - abstract class Source extends DataFlow::Node { } + abstract class Source extends DataFlow::Node { + /** Gets a flow label to associate with this source. */ + DataFlow::FlowLabel getAFlowLabel() { result = TaintedObject::label() } + } + + private class TaintedObjectSourceAsSource extends Source { + TaintedObjectSourceAsSource() { this instanceof TaintedObject::Source } + + override DataFlow::FlowLabel getAFlowLabel() { result = TaintedObject::label() } + } + + private class RemoteFlowSourceAsSource extends Source { + RemoteFlowSourceAsSource() { this instanceof RemoteFlowSource } + + override DataFlow::FlowLabel getAFlowLabel() { result.isTaint() } + } /** * A data flow sink for slow input validation. From 88e5348da9fa822e2693beb30b08ec306f0c5f58 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Tue, 2 Mar 2021 13:53:58 +0000 Subject: [PATCH 128/142] JS: Move RemotePropertyInjection test into subfolder --- .../RemotePropertyInjection.expected | 0 .../{ => RemovePropertyInjection}/RemotePropertyInjection.qlref | 0 .../Security/CWE-400/{ => RemovePropertyInjection}/tst.js | 0 .../Security/CWE-400/{ => RemovePropertyInjection}/tstNonExpr.js | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename javascript/ql/test/query-tests/Security/CWE-400/{ => RemovePropertyInjection}/RemotePropertyInjection.expected (100%) rename javascript/ql/test/query-tests/Security/CWE-400/{ => RemovePropertyInjection}/RemotePropertyInjection.qlref (100%) rename javascript/ql/test/query-tests/Security/CWE-400/{ => RemovePropertyInjection}/tst.js (100%) rename javascript/ql/test/query-tests/Security/CWE-400/{ => RemovePropertyInjection}/tstNonExpr.js (100%) diff --git a/javascript/ql/test/query-tests/Security/CWE-400/RemotePropertyInjection.expected b/javascript/ql/test/query-tests/Security/CWE-400/RemovePropertyInjection/RemotePropertyInjection.expected similarity index 100% rename from javascript/ql/test/query-tests/Security/CWE-400/RemotePropertyInjection.expected rename to javascript/ql/test/query-tests/Security/CWE-400/RemovePropertyInjection/RemotePropertyInjection.expected diff --git a/javascript/ql/test/query-tests/Security/CWE-400/RemotePropertyInjection.qlref b/javascript/ql/test/query-tests/Security/CWE-400/RemovePropertyInjection/RemotePropertyInjection.qlref similarity index 100% rename from javascript/ql/test/query-tests/Security/CWE-400/RemotePropertyInjection.qlref rename to javascript/ql/test/query-tests/Security/CWE-400/RemovePropertyInjection/RemotePropertyInjection.qlref diff --git a/javascript/ql/test/query-tests/Security/CWE-400/tst.js b/javascript/ql/test/query-tests/Security/CWE-400/RemovePropertyInjection/tst.js similarity index 100% rename from javascript/ql/test/query-tests/Security/CWE-400/tst.js rename to javascript/ql/test/query-tests/Security/CWE-400/RemovePropertyInjection/tst.js diff --git a/javascript/ql/test/query-tests/Security/CWE-400/tstNonExpr.js b/javascript/ql/test/query-tests/Security/CWE-400/RemovePropertyInjection/tstNonExpr.js similarity index 100% rename from javascript/ql/test/query-tests/Security/CWE-400/tstNonExpr.js rename to javascript/ql/test/query-tests/Security/CWE-400/RemovePropertyInjection/tstNonExpr.js From 6e0322dc604793a53315348139de7a8fa2177c03 Mon Sep 17 00:00:00 2001 From: Asger Feldthaus Date: Tue, 2 Mar 2021 13:56:28 +0000 Subject: [PATCH 129/142] JS: Add DeepResourceExhaustion test --- .../DeepObjectResourceExhaustion.expected | 8 ++++++++ .../DeepObjectResourceExhaustion.qlref | 1 + .../CWE-400/DeepObjectResourceExhaustion/tst.js | 12 ++++++++++++ 3 files changed, 21 insertions(+) create mode 100644 javascript/ql/test/query-tests/Security/CWE-400/DeepObjectResourceExhaustion/DeepObjectResourceExhaustion.expected create mode 100644 javascript/ql/test/query-tests/Security/CWE-400/DeepObjectResourceExhaustion/DeepObjectResourceExhaustion.qlref create mode 100644 javascript/ql/test/query-tests/Security/CWE-400/DeepObjectResourceExhaustion/tst.js diff --git a/javascript/ql/test/query-tests/Security/CWE-400/DeepObjectResourceExhaustion/DeepObjectResourceExhaustion.expected b/javascript/ql/test/query-tests/Security/CWE-400/DeepObjectResourceExhaustion/DeepObjectResourceExhaustion.expected new file mode 100644 index 00000000000..c93bc1c7111 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-400/DeepObjectResourceExhaustion/DeepObjectResourceExhaustion.expected @@ -0,0 +1,8 @@ +nodes +| tst.js:9:29:9:36 | req.body | +| tst.js:9:29:9:36 | req.body | +| tst.js:9:29:9:36 | req.body | +edges +| tst.js:9:29:9:36 | req.body | tst.js:9:29:9:36 | req.body | +#select +| tst.js:9:29:9:36 | req.body | tst.js:9:29:9:36 | req.body | tst.js:9:29:9:36 | req.body | Denial of service caused by processing user input from $@ with $@. | tst.js:9:29:9:36 | req.body | here | tst.js:4:21:4:35 | allErrors: true | allErrors: true | diff --git a/javascript/ql/test/query-tests/Security/CWE-400/DeepObjectResourceExhaustion/DeepObjectResourceExhaustion.qlref b/javascript/ql/test/query-tests/Security/CWE-400/DeepObjectResourceExhaustion/DeepObjectResourceExhaustion.qlref new file mode 100644 index 00000000000..659d91ba4b8 --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-400/DeepObjectResourceExhaustion/DeepObjectResourceExhaustion.qlref @@ -0,0 +1 @@ +Security/CWE-400/DeepObjectResourceExhaustion.ql \ No newline at end of file diff --git a/javascript/ql/test/query-tests/Security/CWE-400/DeepObjectResourceExhaustion/tst.js b/javascript/ql/test/query-tests/Security/CWE-400/DeepObjectResourceExhaustion/tst.js new file mode 100644 index 00000000000..9ecdad2dbbc --- /dev/null +++ b/javascript/ql/test/query-tests/Security/CWE-400/DeepObjectResourceExhaustion/tst.js @@ -0,0 +1,12 @@ +import express from 'express'; +import Ajv from 'ajv'; + +let ajv = new Ajv({ allErrors: true }); +ajv.addSchema(require('./input-schema'), 'input'); + +var app = express(); +app.get('/user/:id', function(req, res) { + if (!ajv.validate('input', req.body)) { // NOT OK + return; + } +}); From 6c884f86d256a43d5ed129471aa363d86284c69c Mon Sep 17 00:00:00 2001 From: Asger F Date: Tue, 2 Mar 2021 14:01:59 +0000 Subject: [PATCH 130/142] Apply suggestions from code review Co-authored-by: Erik Krogh Kristensen --- .../dataflow/DeepObjectResourceExhaustionCustomizations.qll | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/DeepObjectResourceExhaustionCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/DeepObjectResourceExhaustionCustomizations.qll index 39ba56ba62b..c33a5a03793 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/DeepObjectResourceExhaustionCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/DeepObjectResourceExhaustionCustomizations.qll @@ -32,18 +32,18 @@ module DeepObjectResourceExhaustion { } /** - * A data flow sink for slow input validation. + * A data flow sink for inefficient handling of user-controlled objects. */ abstract class Sink extends DataFlow::Node { /** * Holds if `link` and `text` should be included in the message to explain - * why the input validation is slow. + * why the handling of the object is slow. */ abstract predicate hasReason(DataFlow::Node link, string text); } /** - * A sanitizer for slow input validation. + * A sanitizer for inefficient handling of user-controlled objects. */ abstract class Sanitizer extends DataFlow::Node { } From 919ee38049179cb104b9e23ca3a16ac33bf49068 Mon Sep 17 00:00:00 2001 From: Asger F Date: Tue, 2 Mar 2021 14:02:35 +0000 Subject: [PATCH 131/142] Update javascript/ql/src/semmle/javascript/security/dataflow/DeepObjectResourceExhaustionCustomizations.qll Co-authored-by: Erik Krogh Kristensen --- .../dataflow/DeepObjectResourceExhaustionCustomizations.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/security/dataflow/DeepObjectResourceExhaustionCustomizations.qll b/javascript/ql/src/semmle/javascript/security/dataflow/DeepObjectResourceExhaustionCustomizations.qll index c33a5a03793..52b3874c8cc 100644 --- a/javascript/ql/src/semmle/javascript/security/dataflow/DeepObjectResourceExhaustionCustomizations.qll +++ b/javascript/ql/src/semmle/javascript/security/dataflow/DeepObjectResourceExhaustionCustomizations.qll @@ -12,7 +12,7 @@ private import semmle.javascript.security.TaintedObjectCustomizations */ module DeepObjectResourceExhaustion { /** - * A data flow source for slow input validation. + * A data flow source for inefficient handling of user-controlled objects. */ abstract class Source extends DataFlow::Node { /** Gets a flow label to associate with this source. */ From 714e1dc6868b831f8c887056029949632c157ec7 Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Tue, 2 Mar 2021 15:08:07 +0100 Subject: [PATCH 132/142] Add change note --- csharp/change-notes/2021-03-02-dotnet5.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 csharp/change-notes/2021-03-02-dotnet5.md diff --git a/csharp/change-notes/2021-03-02-dotnet5.md b/csharp/change-notes/2021-03-02-dotnet5.md new file mode 100644 index 00000000000..57ec8bc485d --- /dev/null +++ b/csharp/change-notes/2021-03-02-dotnet5.md @@ -0,0 +1,2 @@ +lgtm,codescanning +* The extractor has been updated to use dotnet 5 dependencies. From 4d33407f6c15c7d951cc020ac1573f1309879f73 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 2 Mar 2021 15:21:36 +0100 Subject: [PATCH 133/142] optimize getACalleeValue --- javascript/ql/src/semmle/javascript/dataflow/Nodes.qll | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll b/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll index 65e3c9854e5..bc6a4ebbab3 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll @@ -168,7 +168,13 @@ class InvokeNode extends DataFlow::SourceNode { private ObjectLiteralNode getOptionsArgument(int i) { result.flowsTo(getArgument(i)) } /** Gets an abstract value representing possible callees of this call site. */ - final AbstractValue getACalleeValue() { result = getCalleeNode().analyze().getAValue() } + final AbstractValue getACalleeValue() { + exists(DataFlow::Node callee, DataFlow::AnalyzedNode analyzed | + pragma[only_bind_into](callee) = getCalleeNode() and + pragma[only_bind_into](analyzed) = callee.analyze() and + pragma[only_bind_into](result) = analyzed.getAValue() + ) + } /** * Gets a potential callee of this call site. From 95a1edcabc13b5d6d8c94b0fdd852a9ae44c45e0 Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Tue, 2 Mar 2021 15:22:38 +0100 Subject: [PATCH 134/142] refactor FunctionStyleClass to get a better join-order --- .../ql/src/semmle/javascript/dataflow/Nodes.qll | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll b/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll index bc6a4ebbab3..741f128059c 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/Nodes.qll @@ -1172,6 +1172,16 @@ module ClassNode { result.getFile() = f } + /** + * Gets a reference to the function `func`, where there exists a read/write of the "prototype" property on that reference. + */ + pragma[noinline] + private DataFlow::SourceNode getAFunctionValueWithPrototype(AbstractValue func) { + exists(result.getAPropertyReference("prototype")) and + result.analyze().getAValue() = pragma[only_bind_into](func) and + func instanceof AbstractFunction // the join-order goes bad if `func` has type `AbstractFunction`. + } + /** * A function definition with prototype manipulation as a `ClassNode` instance. */ @@ -1182,10 +1192,7 @@ module ClassNode { FunctionStyleClass() { function.getFunction() = astNode and ( - exists(DataFlow::PropRef read | - read.getPropertyName() = "prototype" and - read.getBase().analyze().getAValue() = function - ) + exists(getAFunctionValueWithPrototype(function)) or exists(string name | this = AccessPath::getAnAssignmentTo(name) and @@ -1246,7 +1253,7 @@ module ClassNode { * Gets a reference to the prototype of this class. */ DataFlow::SourceNode getAPrototypeReference() { - exists(DataFlow::SourceNode base | base.analyze().getAValue() = function | + exists(DataFlow::SourceNode base | base = getAFunctionValueWithPrototype(function) | result = base.getAPropertyRead("prototype") or result = base.getAPropertySource("prototype") From 81ff76814f09dff819236ec17728a69ca98d5a33 Mon Sep 17 00:00:00 2001 From: Joe Farebrother Date: Tue, 2 Mar 2021 16:35:34 +0000 Subject: [PATCH 135/142] Remove incorrect expectaton --- java/ql/test/library-tests/frameworks/apache-http/B.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/ql/test/library-tests/frameworks/apache-http/B.java b/java/ql/test/library-tests/frameworks/apache-http/B.java index bfba6f5a7d0..96e5df3289e 100644 --- a/java/ql/test/library-tests/frameworks/apache-http/B.java +++ b/java/ql/test/library-tests/frameworks/apache-http/B.java @@ -52,7 +52,7 @@ class B { bbuf.append((byte[]) taint(), 0, 3); sink(bbuf.array()); //$hasTaintFlow=y sink(bbuf.toByteArray()); //$hasTaintFlow=y - sink(bbuf.toString()); //SPURIOUS: $hasTaintFlow=y + sink(bbuf.toString()); CharArrayBuffer cbuf = new CharArrayBuffer(42); cbuf.append(bbuf.toByteArray(), 0, 3); From 9982112b611f041168db8e43d434d7ae8f8e5e36 Mon Sep 17 00:00:00 2001 From: Andrew Eisenberg Date: Tue, 2 Mar 2021 08:57:17 -0800 Subject: [PATCH 136/142] Documentation: Update C/C++ Element::fromSource() docs The previous documentation was not correct. This documentation is adapted from File::fromSource(). --- cpp/ql/src/semmle/code/cpp/Element.qll | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/Element.qll b/cpp/ql/src/semmle/code/cpp/Element.qll index 66f23ea110f..daa15e0f625 100644 --- a/cpp/ql/src/semmle/code/cpp/Element.qll +++ b/cpp/ql/src/semmle/code/cpp/Element.qll @@ -80,11 +80,9 @@ class Element extends ElementBase { File getFile() { result = this.getLocation().getFile() } /** - * Holds if this element may be from source. - * - * Note: this predicate is provided for consistency with the libraries - * for other languages, such as Java and Python. In C++, all files are - * classified as source files, so this predicate is always true. + * Holds if this element may be from source. This predicate holds for all + * elements, except for those in the dummy file, whose name is the empty string. + * The dummy file contains declarations that are built directly into the compiler. */ predicate fromSource() { this.getFile().fromSource() } From dbd843288415369daf967a0ec7b1c3eec1890b02 Mon Sep 17 00:00:00 2001 From: Robert Marsh Date: Tue, 2 Mar 2021 12:11:12 -0800 Subject: [PATCH 137/142] C++: autoformat --- .../semmle/code/cpp/ir/implementation/internal/TOperand.qll | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TOperand.qll b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TOperand.qll index 0a55587e436..1e132463cdd 100644 --- a/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TOperand.qll +++ b/cpp/ql/src/semmle/code/cpp/ir/implementation/internal/TOperand.qll @@ -55,9 +55,7 @@ private module Internal { ) { defInstr = AliasedConstruction::getPhiOperandDefinition(useInstr, predecessorBlock, overlap) } or - TAliasedChiOperand(TAliasedSSAChiInstruction useInstr, ChiOperandTag tag) { - any() - } + TAliasedChiOperand(TAliasedSSAChiInstruction useInstr, ChiOperandTag tag) { any() } } /** From b9450c901ae4f6c69f8cb9a0f6f87d6b82e004ae Mon Sep 17 00:00:00 2001 From: Erik Krogh Kristensen Date: Wed, 3 Mar 2021 11:18:09 +0100 Subject: [PATCH 138/142] remove development comment --- javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll index fe7ba8e2e75..595917fa6ed 100644 --- a/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll +++ b/javascript/ql/src/semmle/javascript/dataflow/DataFlow.qll @@ -106,7 +106,7 @@ module DataFlow { /** Holds if this node may evaluate to the Boolean value `b`. */ predicate mayHaveBooleanValue(boolean b) { - getAPredecessor().mayHaveBooleanValue(b) // needed stage 31 + stage 26 + stage 22 (unfixable) + getAPredecessor().mayHaveBooleanValue(b) or b = true and asExpr().(BooleanLiteral).getValue() = "true" or From dd75ea31df601d32476acc3995a1cef0b4468609 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 3 Mar 2021 14:17:22 +0100 Subject: [PATCH 139/142] Python: Apply suggestions from code review Co-authored-by: Taus --- python/ql/src/semmle/crypto/Crypto.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/ql/src/semmle/crypto/Crypto.qll b/python/ql/src/semmle/crypto/Crypto.qll index 1e8e9ccf067..d9f25b42c9a 100644 --- a/python/ql/src/semmle/crypto/Crypto.qll +++ b/python/ql/src/semmle/crypto/Crypto.qll @@ -118,7 +118,7 @@ abstract class CryptographicAlgorithm extends TCryptographicAlgorithm { /** * Holds if the name of this algorithm matches `name` modulo case, - * white space, dashes and underscores. + * white space, dashes, and underscores. */ bindingset[name] predicate matchesName(string name) { From c3175ae7b1234c4bd020505fac40c5ecc5bb1ae4 Mon Sep 17 00:00:00 2001 From: Rasmus Wriedt Larsen Date: Wed, 3 Mar 2021 14:18:33 +0100 Subject: [PATCH 140/142] Python/JS: Sync CryptoAlgorithms.qll --- .../ql/src/semmle/javascript/security/CryptoAlgorithms.qll | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/javascript/ql/src/semmle/javascript/security/CryptoAlgorithms.qll b/javascript/ql/src/semmle/javascript/security/CryptoAlgorithms.qll index 1e8e9ccf067..d9f25b42c9a 100644 --- a/javascript/ql/src/semmle/javascript/security/CryptoAlgorithms.qll +++ b/javascript/ql/src/semmle/javascript/security/CryptoAlgorithms.qll @@ -118,7 +118,7 @@ abstract class CryptographicAlgorithm extends TCryptographicAlgorithm { /** * Holds if the name of this algorithm matches `name` modulo case, - * white space, dashes and underscores. + * white space, dashes, and underscores. */ bindingset[name] predicate matchesName(string name) { From a5a432966949ad32a3edfe75ecbace091b04633a Mon Sep 17 00:00:00 2001 From: Tamas Vajk Date: Fri, 6 Nov 2020 10:37:38 +0100 Subject: [PATCH 141/142] C#: Add tests for covariant return types --- .../test/library-tests/csharp9/CovariantReturn.cs | 9 +++++++++ .../test/library-tests/csharp9/PrintAst.expected | 15 +++++++++++++++ .../csharp9/covariantReturn.expected | 1 + .../test/library-tests/csharp9/covariantReturn.ql | 8 ++++++++ 4 files changed, 33 insertions(+) create mode 100644 csharp/ql/test/library-tests/csharp9/CovariantReturn.cs create mode 100644 csharp/ql/test/library-tests/csharp9/covariantReturn.expected create mode 100644 csharp/ql/test/library-tests/csharp9/covariantReturn.ql diff --git a/csharp/ql/test/library-tests/csharp9/CovariantReturn.cs b/csharp/ql/test/library-tests/csharp9/CovariantReturn.cs new file mode 100644 index 00000000000..ac39aae893d --- /dev/null +++ b/csharp/ql/test/library-tests/csharp9/CovariantReturn.cs @@ -0,0 +1,9 @@ +class A +{ + public virtual A M1() { throw null; } +} + +class B : A +{ + public override B M1() { throw null; } +} \ No newline at end of file diff --git a/csharp/ql/test/library-tests/csharp9/PrintAst.expected b/csharp/ql/test/library-tests/csharp9/PrintAst.expected index 56299fbdc68..6da09ceb287 100644 --- a/csharp/ql/test/library-tests/csharp9/PrintAst.expected +++ b/csharp/ql/test/library-tests/csharp9/PrintAst.expected @@ -117,6 +117,21 @@ BinaryPattern.cs: # 19| 1: [SwitchCaseExpr] ... => ... # 19| 0: [DiscardPatternExpr] _ # 19| 2: [StringLiteral] "other" +CovariantReturn.cs: +# 1| [Class] A +# 3| 5: [Method] M1 +# 3| -1: [TypeMention] A +# 3| 4: [BlockStmt] {...} +# 3| 0: [ThrowStmt] throw ...; +# 3| 0: [NullLiteral] null +# 6| [Class] B +#-----| 3: (Base types) +# 6| 0: [TypeMention] A +# 8| 5: [Method] M1 +# 8| -1: [TypeMention] B +# 8| 4: [BlockStmt] {...} +# 8| 0: [ThrowStmt] throw ...; +# 8| 0: [NullLiteral] null Discard.cs: # 3| [Class] Discard # 5| 5: [Method] M1 diff --git a/csharp/ql/test/library-tests/csharp9/covariantReturn.expected b/csharp/ql/test/library-tests/csharp9/covariantReturn.expected new file mode 100644 index 00000000000..789c8c7caaa --- /dev/null +++ b/csharp/ql/test/library-tests/csharp9/covariantReturn.expected @@ -0,0 +1 @@ +| A.M1 | A | B.M1 | B | diff --git a/csharp/ql/test/library-tests/csharp9/covariantReturn.ql b/csharp/ql/test/library-tests/csharp9/covariantReturn.ql new file mode 100644 index 00000000000..f4958cbba31 --- /dev/null +++ b/csharp/ql/test/library-tests/csharp9/covariantReturn.ql @@ -0,0 +1,8 @@ +import csharp + +from Method m, Method overrider +where + m.getAnOverrider() = overrider and + m.getFile().getStem() = "CovariantReturn" +select m.getQualifiedName(), m.getReturnType().toString(), overrider.getQualifiedName(), + overrider.getReturnType().toString() From d5d04394714bb0fe63bc43b2e63dae6a1bc2e0c8 Mon Sep 17 00:00:00 2001 From: Marcono1234 Date: Sun, 28 Feb 2021 18:58:41 +0100 Subject: [PATCH 142/142] Java: Fix wrong algorithm name matching The regex character class `[5|7]` matches `5`, `7` and `|`. --- .../semmle/code/java/security/Encryption.qll | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/java/ql/src/semmle/code/java/security/Encryption.qll b/java/ql/src/semmle/code/java/security/Encryption.qll index ddbaf9cba73..c8292a6a42c 100644 --- a/java/ql/src/semmle/code/java/security/Encryption.qll +++ b/java/ql/src/semmle/code/java/security/Encryption.qll @@ -120,13 +120,16 @@ private string algorithmRegex(string algorithmString) { * Gets the name of an algorithm that is known to be insecure. */ string getAnInsecureAlgorithmName() { - result = "DES" or - result = "RC2" or - result = "RC4" or - result = "RC5" or - result = "ARCFOUR" or // a variant of RC4 - result = "ECB" or // encryption mode ECB like AES/ECB/NoPadding is vulnerable to replay and other attacks - result = "AES/CBC/PKCS[5|7]Padding" // CBC mode of operation with PKCS#5 (or PKCS#7) padding is vulnerable to padding oracle attacks + result = + [ + "DES", "RC2", "RC4", "RC5", + // ARCFOUR is a variant of RC4 + "ARCFOUR", + // Encryption mode ECB like AES/ECB/NoPadding is vulnerable to replay and other attacks + "ECB", + // CBC mode of operation with PKCS#5 or PKCS#7 padding is vulnerable to padding oracle attacks + "AES/CBC/PKCS[57]Padding" + ] } /** @@ -163,14 +166,11 @@ string getInsecureAlgorithmRegex() { * Gets the name of an algorithm that is known to be secure. */ string getASecureAlgorithmName() { - result = "RSA" or - result = "SHA256" or - result = "SHA512" or - result = "CCM" or - result = "GCM" or - result = "AES([^a-zA-Z](?!ECB|CBC/PKCS[5|7]Padding)).*" or - result = "Blowfish" or - result = "ECIES" + result = + [ + "RSA", "SHA256", "SHA512", "CCM", "GCM", "AES([^a-zA-Z](?!ECB|CBC/PKCS[57]Padding)).*", + "Blowfish", "ECIES" + ] } private string rankedSecureAlgorithm(int i) { result = rank[i](getASecureAlgorithmName()) }