Compare commits

...

84 Commits

Author SHA1 Message Date
Mathias Vorreiter Pedersen
9ddacf55a5 C++/C#: Sync identical files. 2022-08-29 12:21:02 +01:00
Mathias Vorreiter Pedersen
ba1005f875 C#: Fix Code Scanning alert. 2022-08-29 12:21:01 +01:00
Mathias Vorreiter Pedersen
99b21b3d79 C++: Accept test changes. 2022-08-29 12:21:01 +01:00
Mathias Vorreiter Pedersen
5b51fcbd3d C++: Suppress Code Scanning warning. 2022-08-26 09:07:08 +01:00
Mathias Vorreiter Pedersen
e13ae70eeb C++: Autoformat. 2022-08-26 09:06:38 +01:00
Mathias Vorreiter Pedersen
9f17bd0d89 C++: Accept test changes. 2022-08-25 15:51:10 +01:00
Mathias Vorreiter Pedersen
86bb9c38ce C#: Sync identical files. 2022-08-25 15:47:21 +01:00
Mathias Vorreiter Pedersen
dc105b404b C++: Only GVN side-effect-free functions. This improves the performance dramatically. 2022-08-25 15:46:41 +01:00
Mathias Vorreiter Pedersen
fac28ccbe0 Merge branch 'main' into rdmarsh2/cpp/gvn-functions 2022-08-25 15:43:12 +01:00
Erik Krogh Kristensen
06afe9c0f4 Merge pull request #9816 from erik-krogh/msgConsis
Make alert messages consistent across languages
2022-08-25 15:20:01 +02:00
Ian Lynagh
2e2621adad Merge pull request #10154 from igfoo/igfoo/findSubType
Kotlin: Implement and use fun <T,reified S: T> Iterable<T>.findSubType
2022-08-25 12:57:46 +01:00
Erik Krogh Kristensen
ba1ad00d2a Merge pull request #10062 from erik-krogh/redosPrefix
JS: use the shared regular expression libraries in `js/case-sensitive-middleware-path`
2022-08-25 12:57:16 +02:00
erik-krogh
c7aa58252a change "does not seem to check" to "does not check" in unchecked-cast-in-equals queries 2022-08-25 12:31:58 +02:00
Ian Lynagh
12eab3d7f0 Kotlin: Specialise findSubType to IrDeclaration
We only use it on that type, and this makes the uses a bit quieter.
2022-08-25 10:11:19 +01:00
erik-krogh
014dcd1454 fixup a Python query, it didn't select something with a location 2022-08-24 16:23:20 +02:00
erik-krogh
5d9b25c75d Merge branch 'main' into msgConsis 2022-08-24 16:19:32 +02:00
erik-krogh
1c0f2251e2 Merge branch 'main' into msgConsis 2022-08-24 14:38:57 +02:00
Ian Lynagh
4cd90a15d0 Kotlin: Use findSubType in KotlinUsesExtractor too 2022-08-24 12:16:16 +01:00
Ian Lynagh
28d95f4d99 Kotlin: Implement and use fun <T,reified S: T> Iterable<T>.findSubType
We had a lot of uses of find which looked for a subtype, but then had to
cast (seemingly unsafely) the result to that subtype. This pulls all the
casts out into a utility function.
2022-08-24 12:10:53 +01:00
erik-krogh
f1799ae3d2 print the endpointExample in the alert-messsage, and only report one working example 2022-08-24 13:09:48 +02:00
erik-krogh
27fcc90a97 Merge branch 'main' into msgConsis 2022-08-24 09:21:43 +02:00
erik-krogh
a50234adb0 apply suggestion from review 2022-08-23 15:41:37 +02:00
erik-krogh
5e3cb08ed2 rename stateInPumpableRegexp to stateInRelevantRegexp 2022-08-23 12:40:45 +02:00
erik-krogh
1a7d3ee831 update expected output after changing queries 2022-08-23 12:35:32 +02:00
erik-krogh
afadcd9b45 use a more detailed alert message in bitwise-sign-check 2022-08-23 11:18:45 +02:00
erik-krogh
d96d6721ba change the alert message of unused-local-variable 2022-08-23 11:15:11 +02:00
erik-krogh
de8384d904 revert alert message change to java/unused-local-variable 2022-08-23 11:14:58 +02:00
erik-krogh
305a23b952 apply suggestion from review 2022-08-23 11:05:32 +02:00
erik-krogh
f7846a598e add change-notes 2022-08-23 07:54:01 +02:00
erik-krogh
7e0bd5bde4 update expected output of tests 2022-08-22 21:41:47 +02:00
erik-krogh
df9a9f4a56 update rb/stored-css to match javascript 2022-08-22 21:41:47 +02:00
erik-krogh
9b257bfa9e update rb/reflected-xss to match javascript 2022-08-22 21:41:47 +02:00
erik-krogh
ca299b9dc1 update py/unreachable-statement to match javascript/go 2022-08-22 21:41:47 +02:00
erik-krogh
31e15e27fc update py/unsafe-deserialization to match ruby/javascript/java 2022-08-22 21:41:47 +02:00
erik-krogh
778879908e update rb/code-injection to match python 2022-08-22 21:41:46 +02:00
erik-krogh
60908de089 update js/nested-loops-with-same-variable to match cpp 2022-08-22 21:41:46 +02:00
erik-krogh
20625ae60d update {js/go/py}/xpath-injection to match csharp/java 2022-08-22 21:41:46 +02:00
erik-krogh
b5458b2125 update js/insecure-randomness to match csharp 2022-08-22 21:41:46 +02:00
erik-krogh
9cdd8cc8f5 update js/tainted-format-string to match ruby/java 2022-08-22 21:41:46 +02:00
erik-krogh
9395f156de update {js/py}/command-line-injection to match csharp/java 2022-08-22 21:41:46 +02:00
erik-krogh
684a987abf update java/unused-import to match python 2022-08-22 21:41:46 +02:00
erik-krogh
54268f4424 update java/static-array to match csharp 2022-08-22 21:41:46 +02:00
erik-krogh
8899c1be04 update java/unassigned-field to match csharp 2022-08-22 21:41:46 +02:00
erik-krogh
280b101caa update java/useless-assignment-to-local to match go 2022-08-22 21:41:46 +02:00
erik-krogh
034d197e01 update {java/rb}/xxe to match python/javascript 2022-08-22 21:41:46 +02:00
erik-krogh
2d0a4c3d83 update {go/py}/stack-trace-exposure to match javascript 2022-08-22 21:41:46 +02:00
erik-krogh
5a0183f1e2 update java/password-in-configuration to match csharp 2022-08-22 21:41:46 +02:00
erik-krogh
151529d08f correct the query-id of the experimental go/pam-auth-bypass query 2022-08-22 21:41:46 +02:00
erik-krogh
b5f3cd7a55 update cs/useless-tostring-call to match java 2022-08-22 21:41:46 +02:00
erik-krogh
49a3e208d7 update cs/index-out-of-bounds to match javascript/go 2022-08-22 21:41:46 +02:00
erik-krogh
52171d6733 update cs/unchecked-cast-in-equals to match java 2022-08-22 21:41:46 +02:00
erik-krogh
ea11f744e1 update cs/confusing-override-name to match java 2022-08-22 21:41:46 +02:00
erik-krogh
064c9a6938 update {cs/java}/todo-comment to match javascript 2022-08-22 21:41:46 +02:00
erik-krogh
678e433013 update cpp/missing-case-in-switch to match java 2022-08-22 21:41:45 +02:00
erik-krogh
ea2777fa3e update {cs/cpp}/equality-on-floats to use the same alert-message/description 2022-08-22 21:41:45 +02:00
erik-krogh
55c8863e92 update java/sql-injection to match go/javascript/python/ruby 2022-08-22 21:41:45 +02:00
erik-krogh
3553f3d9b8 update {rb/py/js/go}/path-injection to match java/csharp 2022-08-22 21:41:45 +02:00
erik-krogh
39c1832995 update {cpp/js}/bitwise-sign-check to match java 2022-08-22 21:41:45 +02:00
erik-krogh
cc41a83a8d update {py/cpp}/commented-out-code to match csharp/java/javascript 2022-08-22 21:41:45 +02:00
erik-krogh
b471a401cc update {rb/js/java}/unused-parameter to match python 2022-08-22 21:41:45 +02:00
erik-krogh
698ccd8850 update {cpp/java}/unused-local to match python 2022-08-22 21:41:45 +02:00
erik-krogh
5a312cd0da update cpp/complex-block to match java/csharp 2022-08-22 21:41:45 +02:00
erik-krogh
b1c9843d15 update {cs/cpp}/empty-block so they have the same alert message 2022-08-22 21:41:45 +02:00
erik-krogh
594fbc678e update js/zip-slip to match java/go/csharp 2022-08-22 21:41:45 +02:00
erik-krogh
e52fa9a469 update {cs/java}/regex-injection to match javascript 2022-08-22 21:41:45 +02:00
erik-krogh
049af68bc2 restrict suffix-construction to relevant regexps 2022-08-21 20:35:39 +02:00
erik-krogh
0aebc90b61 don't lowercase the endpointExample, and correctly handle root states 2022-08-21 18:38:47 +02:00
erik-krogh
bcf4c57060 Merge branch 'main' into redosPrefix 2022-08-19 19:22:49 +02:00
erik-krogh
d052b1e3c9 also support regular expressions without repetitions 2022-08-19 19:21:44 +02:00
erik-krogh
26fcf6b25b apply suggestions from review 2022-08-18 15:00:57 +02:00
erik-krogh
de3e1c39e4 use the shared regular expression libraries in js/case-sensitive-middleware-path 2022-08-18 10:07:55 +02:00
erik-krogh
473bc92e2d move the PrefixConstruction module out of the ReDoSPruning module 2022-08-18 10:07:48 +02:00
Robert Marsh
af2c96f344 Merge branch 'main' into rdmarsh2/cpp/gvn-functions 2022-08-12 12:39:37 -04:00
Robert Marsh
7c4d3800b6 C++: change note for function call GVNs 2022-08-01 13:32:12 -04:00
Robert Marsh
5c11062d21 C++/C#: sync GVN files 2022-08-01 13:26:04 -04:00
Robert Marsh
83af49c72f C++: respond to PR comments 2022-08-01 12:59:23 -04:00
Robert Marsh
e0cfbb53dc C++: add missing SideEffectElimination.qll 2022-08-01 09:52:46 -04:00
Robert Marsh
844aabe3d6 C++/C#: fix join order in GVN 2022-07-29 14:51:09 -04:00
Robert Marsh
c09c38c9a8 C++/C#: sync for IR side effect removal 2022-07-29 12:08:52 -04:00
Robert Marsh
d324969d68 C++: remove some side-effect instructions
This leverages the existing alias analysis to identify functions which
have no reads or writes of the AllAliasedMemory virtual variable, and
therefore have no global side effects. A recursion over the call graph
identifies functions which have no indirect global side effects, and
calls to those functions have their global side effect instructions
removed.
2022-07-29 10:38:25 -04:00
Robert Marsh
4ae218729a C++/C#: Sync identical files 2022-07-25 15:21:39 -04:00
Robert Marsh
cc8e65f811 C++: include aliased memory in function call GVNs 2022-07-25 14:55:20 -04:00
Robert Marsh
76b292da6a C++: initial GVN for function calls 2022-07-25 14:26:54 -04:00
Robert Marsh
0b691dd46c C++: function tests for GVN 2022-07-25 14:24:41 -04:00
153 changed files with 2649 additions and 1793 deletions

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* Multiple function calls made in the same function may now receive the same global value number when the analysis can show they produce the same results.

View File

@@ -1712,6 +1712,11 @@ class SideEffectInstruction extends Instruction {
*/
class CallSideEffectInstruction extends SideEffectInstruction {
CallSideEffectInstruction() { this.getOpcode() instanceof Opcode::CallSideEffect }
/** Gets the operand for the value that will be read by this instruction */
final SideEffectOperand getSideEffectOperand() { result = this.getAnOperand() }
final Instruction getSideEffect() { result = this.getAnOperand().getDef() }
}
/**
@@ -1723,6 +1728,11 @@ class CallSideEffectInstruction extends SideEffectInstruction {
*/
class CallReadSideEffectInstruction extends SideEffectInstruction {
CallReadSideEffectInstruction() { this.getOpcode() instanceof Opcode::CallReadSideEffect }
/** Gets the operand for the value that will be read by this instruction */
final SideEffectOperand getSideEffectOperand() { result = this.getAnOperand() }
final Instruction getSideEffect() { result = this.getAnOperand().getDef() }
}
/**

View File

@@ -1,3 +1,4 @@
import semmle.code.cpp.ir.implementation.aliased_ssa.IR
import semmle.code.cpp.ir.internal.Overlap
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
import semmle.code.cpp.models.interfaces.SideEffect as SideEffect

View File

@@ -41,8 +41,92 @@ newtype TValueNumber =
) {
loadTotalOverlapValueNumber(_, irFunc, type, memOperand, operand)
} or
TCallValueNumber(TCallPartialValueNumber vn) { callValueNumber(_, _, vn) } or
TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) }
private class NumberableCallInstruction extends CallInstruction {
NumberableCallInstruction() {
not this.getResultIRType() instanceof IRVoidType and
exists(SideEffect::SideEffectFunction sideEffectFunc |
sideEffectFunc = this.getStaticCallTarget()
|
sideEffectFunc.hasOnlySpecificReadSideEffects() and
sideEffectFunc.hasOnlySpecificWriteSideEffects()
)
}
}
private newtype TCallPartialValueNumber =
TNilArgument() or
TArgument(TCallPartialValueNumber head, TValueNumber arg) {
exists(NumberableCallInstruction call, int index |
callArgValueNumber(call, index, arg) and
callPartialValueNumber(call, index, head)
)
}
private predicate callValueNumber(
NumberableCallInstruction call, int index, TCallPartialValueNumber vn
) {
index = max(int n | callArgRank(call, n, _) | n) and
exists(TCallPartialValueNumber head, TValueNumber arg |
callPartialValueNumber(call, index, pragma[only_bind_out](head)) and
callArgValueNumber(call, index, pragma[only_bind_into](arg)) and
vn = TArgument(head, arg)
)
or
not exists(int n | callArgRank(call, n, _)) and
index = -1 and
vn = TNilArgument()
}
private predicate callPartialValueNumber(
NumberableCallInstruction call, int index, TCallPartialValueNumber head
) {
exists(call) and
index = 1 and
head = TNilArgument()
or
exists(TCallPartialValueNumber prev, TValueNumber prevVN |
callPartialValueNumber(call, index - 1, pragma[only_bind_out](prev)) and
callArgValueNumber(call, index - 1, pragma[only_bind_into](prevVN)) and
head = TArgument(prev, prevVN)
)
}
/**
*/
private predicate callArgValueNumber(NumberableCallInstruction call, int index, TValueNumber arg) {
exists(Instruction instr |
callArgRank(call, index, instr) and
arg = tvalueNumber(instr)
)
}
/**
* Holds if `arg` is the `index`th element in `call`'s extended argument list, including the `this`
* argument and side-effect reads.
*/
private predicate callArgRank(NumberableCallInstruction call, int index, Instruction arg) {
arg =
rank[index](int argIndex, boolean isEffect, Instruction instr |
// There is no need to include the call's read and write side effects on
// all-aliased-memory as `NumberableCallInstruction`s do not read or write
// to all-aliased-memory.
instr = call.getArgument(argIndex) and
isEffect = false
or
exists(ReadSideEffectInstruction read |
read.getPrimaryInstruction() = call and
read.getSideEffectOperand().getAnyDef() = instr and
read.getIndex() = argIndex and
isEffect = true
)
|
instr order by argIndex, isEffect
)
}
/**
* A `CopyInstruction` whose source operand's value is congruent to the definition of that source
* operand.
@@ -93,6 +177,8 @@ private predicate numberableInstruction(Instruction instr) {
instr instanceof CongruentCopyInstruction
or
instr instanceof LoadTotalOverlapInstruction
or
instr instanceof NumberableCallInstruction
}
private predicate filteredNumberableInstruction(Instruction instr) {
@@ -309,6 +395,11 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
or
// The value number of a copy is just the value number of its source value.
result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue())
or
exists(TCallPartialValueNumber pvn |
callValueNumber(instr, _, pvn) and
result = TCallValueNumber(pvn)
)
)
)
}

View File

@@ -8,11 +8,6 @@ private import Imports::RawIR as RawIR
private import SsaInstructions
private import SsaOperands
private import NewIR
private class OldBlock = Reachability::ReachableBlock;
private class OldInstruction = Reachability::ReachableInstruction;
import Cached
cached
@@ -58,7 +53,9 @@ private module Cached {
cached
predicate hasInstruction(TStageInstruction instr) {
instr instanceof TRawInstruction and instr instanceof OldInstruction
instr instanceof TRawInstruction and
instr instanceof OldInstruction and
not removedInstruction(instr)
or
instr = phiInstruction(_, _)
or
@@ -382,7 +379,14 @@ private module Cached {
(
if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind)
then result = unreachedInstruction(instruction.getEnclosingIRFunction())
else result = getNewInstruction(oldInstruction.getSuccessor(kind))
else
if removedInstruction(oldInstruction.getSuccessor(kind))
then
// the only removed nodes are side-effect writes, but those may have Chi nodes
// skip to the following instruction in the old IR, which won't be removed
// if we start skipping specific side effects, this may no longer hold
result = getNewInstruction(oldInstruction.getSuccessor(kind).getSuccessor(kind))
else result = getNewInstruction(oldInstruction.getSuccessor(kind))
)
)
or

View File

@@ -13,3 +13,15 @@ import semmle.code.cpp.ir.implementation.internal.TOperand::AliasedSsaOperands a
/** DEPRECATED: Alias for SsaOperands */
deprecated module SSAOperands = SsaOperands;
private import SideEffectElimination as Elim
predicate removedInstruction(Reachability::ReachableInstruction instr) {
Elim::removeableSideEffect(instr)
}
class OldBlock = Reachability::ReachableBlock;
class OldInstruction extends Reachability::ReachableInstruction {
OldInstruction() { not Elim::removeableSideEffect(this) }
}

View File

@@ -0,0 +1,42 @@
import cpp as CPP
import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as Unaliased
import AliasAnalysis as Alias
import AliasConfiguration as Conf
import semmle.code.cpp.models.interfaces.SideEffect as SideEffect
private predicate noLocalSideEffectWrite(CPP::Function func) {
forall(Unaliased::AddressOperand addr | addr.getUse().getEnclosingFunction() = func |
not (
Alias::getAddressOperandAllocation(addr) instanceof Conf::VariableAllocation and
Alias::getAddressOperandAllocation(addr).(Conf::VariableAllocation).alwaysEscapes()
)
)
}
language[monotonicAggregates]
private predicate noTransitiveSideEffectWrite(CPP::Function func) {
exists(Unaliased::IRFunction irFunc | irFunc.getFunction() = func) and
noLocalSideEffectWrite(func) and
forall(Unaliased::CallInstruction call | call.getEnclosingFunction() = func |
exists(call.getStaticCallTarget())
) and
forall(Unaliased::CallInstruction call, CPP::Function callee |
call.getStaticCallTarget() = callee and
call.getEnclosingFunction() = func
|
noTransitiveSideEffectWrite(callee)
or
callee.(SideEffect::SideEffectFunction).hasOnlySpecificWriteSideEffects()
)
}
predicate removeableSideEffect(Unaliased::SideEffectInstruction instr) {
(
instr instanceof Unaliased::CallSideEffectInstruction or
instr instanceof Unaliased::CallReadSideEffectInstruction
) and
noTransitiveSideEffectWrite(instr
.getPrimaryInstruction()
.(Unaliased::CallInstruction)
.getStaticCallTarget())
}

View File

@@ -34,6 +34,7 @@ newtype TInstruction =
AliasedSsa::SSA::hasPhiInstruction(blockStartInstr, memoryLocation)
} or
TAliasedSsaChiInstruction(TRawInstruction primaryInstruction) {
not AliasedSsa::removedInstruction(primaryInstruction) and
AliasedSsa::SSA::hasChiInstruction(primaryInstruction)
} or
TAliasedSsaUnreachedInstruction(IRFunctionBase irFunc) {

View File

@@ -5,3 +5,5 @@ import semmle.code.cpp.ir.implementation.aliased_ssa.internal.SSAConstruction as
/** DEPRECATED: Alias for AliasedSsa */
deprecated module AliasedSSA = AliasedSsa;
import semmle.code.cpp.ir.implementation.aliased_ssa.internal.SideEffectElimination as Elim

View File

@@ -1712,6 +1712,11 @@ class SideEffectInstruction extends Instruction {
*/
class CallSideEffectInstruction extends SideEffectInstruction {
CallSideEffectInstruction() { this.getOpcode() instanceof Opcode::CallSideEffect }
/** Gets the operand for the value that will be read by this instruction */
final SideEffectOperand getSideEffectOperand() { result = this.getAnOperand() }
final Instruction getSideEffect() { result = this.getAnOperand().getDef() }
}
/**
@@ -1723,6 +1728,11 @@ class CallSideEffectInstruction extends SideEffectInstruction {
*/
class CallReadSideEffectInstruction extends SideEffectInstruction {
CallReadSideEffectInstruction() { this.getOpcode() instanceof Opcode::CallReadSideEffect }
/** Gets the operand for the value that will be read by this instruction */
final SideEffectOperand getSideEffectOperand() { result = this.getAnOperand() }
final Instruction getSideEffect() { result = this.getAnOperand().getDef() }
}
/**

View File

@@ -1,3 +1,4 @@
import semmle.code.cpp.ir.implementation.aliased_ssa.IR
import semmle.code.cpp.ir.internal.Overlap
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
import semmle.code.cpp.models.interfaces.SideEffect as SideEffect

View File

@@ -41,8 +41,92 @@ newtype TValueNumber =
) {
loadTotalOverlapValueNumber(_, irFunc, type, memOperand, operand)
} or
TCallValueNumber(TCallPartialValueNumber vn) { callValueNumber(_, _, vn) } or
TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) }
private class NumberableCallInstruction extends CallInstruction {
NumberableCallInstruction() {
not this.getResultIRType() instanceof IRVoidType and
exists(SideEffect::SideEffectFunction sideEffectFunc |
sideEffectFunc = this.getStaticCallTarget()
|
sideEffectFunc.hasOnlySpecificReadSideEffects() and
sideEffectFunc.hasOnlySpecificWriteSideEffects()
)
}
}
private newtype TCallPartialValueNumber =
TNilArgument() or
TArgument(TCallPartialValueNumber head, TValueNumber arg) {
exists(NumberableCallInstruction call, int index |
callArgValueNumber(call, index, arg) and
callPartialValueNumber(call, index, head)
)
}
private predicate callValueNumber(
NumberableCallInstruction call, int index, TCallPartialValueNumber vn
) {
index = max(int n | callArgRank(call, n, _) | n) and
exists(TCallPartialValueNumber head, TValueNumber arg |
callPartialValueNumber(call, index, pragma[only_bind_out](head)) and
callArgValueNumber(call, index, pragma[only_bind_into](arg)) and
vn = TArgument(head, arg)
)
or
not exists(int n | callArgRank(call, n, _)) and
index = -1 and
vn = TNilArgument()
}
private predicate callPartialValueNumber(
NumberableCallInstruction call, int index, TCallPartialValueNumber head
) {
exists(call) and
index = 1 and
head = TNilArgument()
or
exists(TCallPartialValueNumber prev, TValueNumber prevVN |
callPartialValueNumber(call, index - 1, pragma[only_bind_out](prev)) and
callArgValueNumber(call, index - 1, pragma[only_bind_into](prevVN)) and
head = TArgument(prev, prevVN)
)
}
/**
*/
private predicate callArgValueNumber(NumberableCallInstruction call, int index, TValueNumber arg) {
exists(Instruction instr |
callArgRank(call, index, instr) and
arg = tvalueNumber(instr)
)
}
/**
* Holds if `arg` is the `index`th element in `call`'s extended argument list, including the `this`
* argument and side-effect reads.
*/
private predicate callArgRank(NumberableCallInstruction call, int index, Instruction arg) {
arg =
rank[index](int argIndex, boolean isEffect, Instruction instr |
// There is no need to include the call's read and write side effects on
// all-aliased-memory as `NumberableCallInstruction`s do not read or write
// to all-aliased-memory.
instr = call.getArgument(argIndex) and
isEffect = false
or
exists(ReadSideEffectInstruction read |
read.getPrimaryInstruction() = call and
read.getSideEffectOperand().getAnyDef() = instr and
read.getIndex() = argIndex and
isEffect = true
)
|
instr order by argIndex, isEffect
)
}
/**
* A `CopyInstruction` whose source operand's value is congruent to the definition of that source
* operand.
@@ -93,6 +177,8 @@ private predicate numberableInstruction(Instruction instr) {
instr instanceof CongruentCopyInstruction
or
instr instanceof LoadTotalOverlapInstruction
or
instr instanceof NumberableCallInstruction
}
private predicate filteredNumberableInstruction(Instruction instr) {
@@ -309,6 +395,11 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
or
// The value number of a copy is just the value number of its source value.
result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue())
or
exists(TCallPartialValueNumber pvn |
callValueNumber(instr, _, pvn) and
result = TCallValueNumber(pvn)
)
)
)
}

View File

@@ -1712,6 +1712,11 @@ class SideEffectInstruction extends Instruction {
*/
class CallSideEffectInstruction extends SideEffectInstruction {
CallSideEffectInstruction() { this.getOpcode() instanceof Opcode::CallSideEffect }
/** Gets the operand for the value that will be read by this instruction */
final SideEffectOperand getSideEffectOperand() { result = this.getAnOperand() }
final Instruction getSideEffect() { result = this.getAnOperand().getDef() }
}
/**
@@ -1723,6 +1728,11 @@ class CallSideEffectInstruction extends SideEffectInstruction {
*/
class CallReadSideEffectInstruction extends SideEffectInstruction {
CallReadSideEffectInstruction() { this.getOpcode() instanceof Opcode::CallReadSideEffect }
/** Gets the operand for the value that will be read by this instruction */
final SideEffectOperand getSideEffectOperand() { result = this.getAnOperand() }
final Instruction getSideEffect() { result = this.getAnOperand().getDef() }
}
/**

View File

@@ -1,3 +1,4 @@
import semmle.code.cpp.ir.implementation.aliased_ssa.IR
import semmle.code.cpp.ir.internal.Overlap
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
import semmle.code.cpp.models.interfaces.SideEffect as SideEffect

View File

@@ -41,8 +41,92 @@ newtype TValueNumber =
) {
loadTotalOverlapValueNumber(_, irFunc, type, memOperand, operand)
} or
TCallValueNumber(TCallPartialValueNumber vn) { callValueNumber(_, _, vn) } or
TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) }
private class NumberableCallInstruction extends CallInstruction {
NumberableCallInstruction() {
not this.getResultIRType() instanceof IRVoidType and
exists(SideEffect::SideEffectFunction sideEffectFunc |
sideEffectFunc = this.getStaticCallTarget()
|
sideEffectFunc.hasOnlySpecificReadSideEffects() and
sideEffectFunc.hasOnlySpecificWriteSideEffects()
)
}
}
private newtype TCallPartialValueNumber =
TNilArgument() or
TArgument(TCallPartialValueNumber head, TValueNumber arg) {
exists(NumberableCallInstruction call, int index |
callArgValueNumber(call, index, arg) and
callPartialValueNumber(call, index, head)
)
}
private predicate callValueNumber(
NumberableCallInstruction call, int index, TCallPartialValueNumber vn
) {
index = max(int n | callArgRank(call, n, _) | n) and
exists(TCallPartialValueNumber head, TValueNumber arg |
callPartialValueNumber(call, index, pragma[only_bind_out](head)) and
callArgValueNumber(call, index, pragma[only_bind_into](arg)) and
vn = TArgument(head, arg)
)
or
not exists(int n | callArgRank(call, n, _)) and
index = -1 and
vn = TNilArgument()
}
private predicate callPartialValueNumber(
NumberableCallInstruction call, int index, TCallPartialValueNumber head
) {
exists(call) and
index = 1 and
head = TNilArgument()
or
exists(TCallPartialValueNumber prev, TValueNumber prevVN |
callPartialValueNumber(call, index - 1, pragma[only_bind_out](prev)) and
callArgValueNumber(call, index - 1, pragma[only_bind_into](prevVN)) and
head = TArgument(prev, prevVN)
)
}
/**
*/
private predicate callArgValueNumber(NumberableCallInstruction call, int index, TValueNumber arg) {
exists(Instruction instr |
callArgRank(call, index, instr) and
arg = tvalueNumber(instr)
)
}
/**
* Holds if `arg` is the `index`th element in `call`'s extended argument list, including the `this`
* argument and side-effect reads.
*/
private predicate callArgRank(NumberableCallInstruction call, int index, Instruction arg) {
arg =
rank[index](int argIndex, boolean isEffect, Instruction instr |
// There is no need to include the call's read and write side effects on
// all-aliased-memory as `NumberableCallInstruction`s do not read or write
// to all-aliased-memory.
instr = call.getArgument(argIndex) and
isEffect = false
or
exists(ReadSideEffectInstruction read |
read.getPrimaryInstruction() = call and
read.getSideEffectOperand().getAnyDef() = instr and
read.getIndex() = argIndex and
isEffect = true
)
|
instr order by argIndex, isEffect
)
}
/**
* A `CopyInstruction` whose source operand's value is congruent to the definition of that source
* operand.
@@ -93,6 +177,8 @@ private predicate numberableInstruction(Instruction instr) {
instr instanceof CongruentCopyInstruction
or
instr instanceof LoadTotalOverlapInstruction
or
instr instanceof NumberableCallInstruction
}
private predicate filteredNumberableInstruction(Instruction instr) {
@@ -309,6 +395,11 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
or
// The value number of a copy is just the value number of its source value.
result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue())
or
exists(TCallPartialValueNumber pvn |
callValueNumber(instr, _, pvn) and
result = TCallValueNumber(pvn)
)
)
)
}

View File

@@ -8,11 +8,6 @@ private import Imports::RawIR as RawIR
private import SsaInstructions
private import SsaOperands
private import NewIR
private class OldBlock = Reachability::ReachableBlock;
private class OldInstruction = Reachability::ReachableInstruction;
import Cached
cached
@@ -58,7 +53,9 @@ private module Cached {
cached
predicate hasInstruction(TStageInstruction instr) {
instr instanceof TRawInstruction and instr instanceof OldInstruction
instr instanceof TRawInstruction and
instr instanceof OldInstruction and
not removedInstruction(instr)
or
instr = phiInstruction(_, _)
or
@@ -382,7 +379,14 @@ private module Cached {
(
if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind)
then result = unreachedInstruction(instruction.getEnclosingIRFunction())
else result = getNewInstruction(oldInstruction.getSuccessor(kind))
else
if removedInstruction(oldInstruction.getSuccessor(kind))
then
// the only removed nodes are side-effect writes, but those may have Chi nodes
// skip to the following instruction in the old IR, which won't be removed
// if we start skipping specific side effects, this may no longer hold
result = getNewInstruction(oldInstruction.getSuccessor(kind).getSuccessor(kind))
else result = getNewInstruction(oldInstruction.getSuccessor(kind))
)
)
or

View File

@@ -14,3 +14,9 @@ import semmle.code.cpp.ir.implementation.internal.TOperand::UnaliasedSsaOperands
/** DEPRECATED: Alias for SsaOperands */
deprecated module SSAOperands = SsaOperands;
predicate removedInstruction(Reachability::ReachableInstruction instr) { none() }
class OldBlock = Reachability::ReachableBlock;
class OldInstruction = Reachability::ReachableInstruction;

View File

@@ -29,7 +29,4 @@ where
n = strictcount(ComplexStmt s | s = b.getAStmt()) and
n > 3 and
complexStmt = b.getAStmt()
select b,
"Block with too many statements (" + n.toString() +
" complex statements in the block). Complex statements at: $@", complexStmt,
complexStmt.toString()
select b, "Block with too many statements (" + n.toString() + " complex statements in the block)."

View File

@@ -110,4 +110,4 @@ where
emptyBlock(s, eb) and
not emptyBlockContainsNonchild(eb) and
not lineComment(eb)
select eb, "Empty block without comment"
select eb, "Empty block without comment."

View File

@@ -12,4 +12,4 @@
import CommentedOutCode
from CommentedOutCode comment
select comment, "This comment appears to contain commented-out code"
select comment, "This comment appears to contain commented-out code."

View File

@@ -1,7 +1,6 @@
/**
* @name Sign check of bitwise operation
* @description Checking the sign of a bitwise operation often has surprising
* edge cases.
* @description Checking the sign of the result of a bitwise operation may yield unexpected results.
* @kind problem
* @problem.severity warning
* @precision high
@@ -26,4 +25,4 @@ where
forall(int op | op = lhs.(BitwiseAndExpr).getAnOperand().getValue().toInt() | op < 0) and
// exception for cases involving macros
not e.isAffectedByMacro()
select e, "Potential unsafe sign check of a bitwise operation."
select e, "Potentially unsafe sign check of a bitwise operation."

View File

@@ -21,4 +21,4 @@ where
FloatingPointType and
not ro.getAnOperand().isConstant() and // comparisons to constants generate too many false positives
not left.(VariableAccess).getTarget() = right.(VariableAccess).getTarget() // skip self comparison
select ro, "Equality test on floating point values may not behave as expected."
select ro, "Equality checks on floating point values can yield unexpected results."

View File

@@ -13,10 +13,11 @@
import cpp
from EnumSwitch es, float missing, float total
from EnumSwitch es, float missing, float total, EnumConstant case
where
not es.hasDefaultCase() and
missing = count(es.getAMissingCase()) and
total = missing + count(es.getASwitchCase()) and
missing / total < 0.3
select es, "Switch statement is missing case for " + es.getAMissingCase().getName()
missing / total < 0.3 and
case = es.getAMissingCase()
select es, "Switch statement does not have a case for $@.", case, case.getName()

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* The alert message of many queries have been changed to make the message consistent with other languages.

File diff suppressed because it is too large Load Diff

View File

@@ -1050,46 +1050,36 @@ ssa.cpp:
# 240| r240_3(glval<unknown>) = FunctionAddress[Constructible] :
# 240| r240_4(int) = Constant[1] :
# 240| v240_5(void) = Call[Constructible] : func:r240_3, this:r240_1, 0:r240_4
# 240| m240_6(unknown) = ^CallSideEffect : ~m239_4
# 240| m240_7(unknown) = Chi : total:m239_4, partial:m240_6
# 240| m240_8(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r240_1
# 240| m240_9(Constructible) = Chi : total:m240_2, partial:m240_8
# 240| m240_6(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r240_1
# 240| m240_7(Constructible) = Chi : total:m240_2, partial:m240_6
# 241| r241_1(glval<Constructible>) = VariableAddress[c] :
# 241| r241_2(glval<unknown>) = FunctionAddress[g] :
# 241| v241_3(void) = Call[g] : func:r241_2, this:r241_1
# 241| m241_4(unknown) = ^CallSideEffect : ~m240_7
# 241| m241_5(unknown) = Chi : total:m240_7, partial:m241_4
# 241| v241_6(void) = ^IndirectReadSideEffect[-1] : &:r241_1, m240_9
# 241| m241_7(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r241_1
# 241| m241_8(Constructible) = Chi : total:m240_9, partial:m241_7
# 241| v241_4(void) = ^IndirectReadSideEffect[-1] : &:r241_1, m240_7
# 241| m241_5(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r241_1
# 241| m241_6(Constructible) = Chi : total:m240_7, partial:m241_5
# 242| r242_1(glval<Constructible>) = VariableAddress[c] :
# 242| r242_2(glval<unknown>) = FunctionAddress[g] :
# 242| v242_3(void) = Call[g] : func:r242_2, this:r242_1
# 242| m242_4(unknown) = ^CallSideEffect : ~m241_5
# 242| m242_5(unknown) = Chi : total:m241_5, partial:m242_4
# 242| v242_6(void) = ^IndirectReadSideEffect[-1] : &:r242_1, m241_8
# 242| m242_7(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r242_1
# 242| m242_8(Constructible) = Chi : total:m241_8, partial:m242_7
# 242| v242_4(void) = ^IndirectReadSideEffect[-1] : &:r242_1, m241_6
# 242| m242_5(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r242_1
# 242| m242_6(Constructible) = Chi : total:m241_6, partial:m242_5
# 243| r243_1(glval<Constructible>) = VariableAddress[c2] :
# 243| m243_2(Constructible) = Uninitialized[c2] : &:r243_1
# 243| r243_3(glval<unknown>) = FunctionAddress[Constructible] :
# 243| r243_4(int) = Constant[2] :
# 243| v243_5(void) = Call[Constructible] : func:r243_3, this:r243_1, 0:r243_4
# 243| m243_6(unknown) = ^CallSideEffect : ~m242_5
# 243| m243_7(unknown) = Chi : total:m242_5, partial:m243_6
# 243| m243_8(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r243_1
# 243| m243_9(Constructible) = Chi : total:m243_2, partial:m243_8
# 243| m243_6(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r243_1
# 243| m243_7(Constructible) = Chi : total:m243_2, partial:m243_6
# 244| r244_1(glval<Constructible>) = VariableAddress[c2] :
# 244| r244_2(glval<unknown>) = FunctionAddress[g] :
# 244| v244_3(void) = Call[g] : func:r244_2, this:r244_1
# 244| m244_4(unknown) = ^CallSideEffect : ~m243_7
# 244| m244_5(unknown) = Chi : total:m243_7, partial:m244_4
# 244| v244_6(void) = ^IndirectReadSideEffect[-1] : &:r244_1, m243_9
# 244| m244_7(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r244_1
# 244| m244_8(Constructible) = Chi : total:m243_9, partial:m244_7
# 244| v244_4(void) = ^IndirectReadSideEffect[-1] : &:r244_1, m243_7
# 244| m244_5(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r244_1
# 244| m244_6(Constructible) = Chi : total:m243_7, partial:m244_5
# 245| v245_1(void) = NoOp :
# 239| v239_5(void) = ReturnVoid :
# 239| v239_6(void) = AliasedUse : ~m244_5
# 239| v239_6(void) = AliasedUse : m239_3
# 239| v239_7(void) = ExitFunction :
# 247| char* VoidStarIndirectParameters(char*, int)
@@ -1391,43 +1381,37 @@ ssa.cpp:
# 294| r294_18(glval<int>) = VariableAddress[x] :
# 294| r294_19(int) = Load[x] : &:r294_18, m291_6
# 294| v294_20(void) = Call[A] : func:r294_17, this:r294_16, 0:r294_19
# 294| m294_21(unknown) = ^CallSideEffect : ~m294_14
# 294| m294_22(unknown) = Chi : total:m294_14, partial:m294_21
# 294| m294_23(A) = ^IndirectMayWriteSideEffect[-1] : &:r294_16
# 294| m294_24(unknown) = Chi : total:m294_15, partial:m294_23
# 294| v294_25(void) = Call[A] : func:r294_9, this:r294_8, 0:r294_16
# 294| m294_26(unknown) = ^CallSideEffect : ~m294_22
# 294| m294_27(unknown) = Chi : total:m294_22, partial:m294_26
# 294| v294_28(void) = ^BufferReadSideEffect[0] : &:r294_16, ~m294_24
# 294| m294_29(A) = ^IndirectMayWriteSideEffect[-1] : &:r294_8
# 294| m294_30(unknown) = Chi : total:m294_7, partial:m294_29
# 294| m294_31(unknown) = ^BufferMayWriteSideEffect[0] : &:r294_16
# 294| m294_32(unknown) = Chi : total:m294_24, partial:m294_31
# 294| r294_33(glval<int>) = FieldAddress[i] : r294_8
# 294| r294_34(int) = Load[?] : &:r294_33, ~m294_30
# 294| m294_35(int) = Store[j] : &:r294_1, r294_34
# 294| m294_21(A) = ^IndirectMayWriteSideEffect[-1] : &:r294_16
# 294| m294_22(unknown) = Chi : total:m294_15, partial:m294_21
# 294| v294_23(void) = Call[A] : func:r294_9, this:r294_8, 0:r294_16
# 294| v294_24(void) = ^BufferReadSideEffect[0] : &:r294_16, ~m294_22
# 294| m294_25(A) = ^IndirectMayWriteSideEffect[-1] : &:r294_8
# 294| m294_26(unknown) = Chi : total:m294_7, partial:m294_25
# 294| m294_27(unknown) = ^BufferMayWriteSideEffect[0] : &:r294_16
# 294| m294_28(unknown) = Chi : total:m294_22, partial:m294_27
# 294| r294_29(glval<int>) = FieldAddress[i] : r294_8
# 294| r294_30(int) = Load[?] : &:r294_29, ~m294_26
# 294| m294_31(int) = Store[j] : &:r294_1, r294_30
# 295| r295_1(glval<A *>) = VariableAddress[a] :
# 295| r295_2(glval<unknown>) = FunctionAddress[operator new] :
# 295| r295_3(unsigned long) = Constant[4] :
# 295| r295_4(void *) = Call[operator new] : func:r295_2, 0:r295_3
# 295| m295_5(unknown) = ^CallSideEffect : ~m294_27
# 295| m295_6(unknown) = Chi : total:m294_27, partial:m295_5
# 295| m295_5(unknown) = ^CallSideEffect : ~m294_14
# 295| m295_6(unknown) = Chi : total:m294_14, partial:m295_5
# 295| m295_7(unknown) = ^InitializeDynamicAllocation : &:r295_4
# 295| r295_8(A *) = Convert : r295_4
# 295| r295_9(glval<unknown>) = FunctionAddress[A] :
# 295| v295_10(void) = Call[A] : func:r295_9, this:r295_8
# 295| m295_11(unknown) = ^CallSideEffect : ~m295_6
# 295| m295_12(unknown) = Chi : total:m295_6, partial:m295_11
# 295| m295_13(A) = ^IndirectMayWriteSideEffect[-1] : &:r295_8
# 295| m295_14(unknown) = Chi : total:m295_7, partial:m295_13
# 295| m295_15(A *) = Store[a] : &:r295_1, r295_8
# 295| m295_11(A) = ^IndirectMayWriteSideEffect[-1] : &:r295_8
# 295| m295_12(unknown) = Chi : total:m295_7, partial:m295_11
# 295| m295_13(A *) = Store[a] : &:r295_1, r295_8
# 296| r296_1(glval<Point *>) = VariableAddress[#return] :
# 296| r296_2(glval<Point *>) = VariableAddress[p] :
# 296| r296_3(Point *) = Load[p] : &:r296_2, m292_9
# 296| m296_4(Point *) = Store[#return] : &:r296_1, r296_3
# 291| r291_7(glval<Point *>) = VariableAddress[#return] :
# 291| v291_8(void) = ReturnValue : &:r291_7, m296_4
# 291| v291_9(void) = AliasedUse : ~m295_12
# 291| v291_9(void) = AliasedUse : ~m295_6
# 291| v291_10(void) = ExitFunction :
# 301| int main(int, char**)

View File

@@ -1045,46 +1045,36 @@ ssa.cpp:
# 240| r240_3(glval<unknown>) = FunctionAddress[Constructible] :
# 240| r240_4(int) = Constant[1] :
# 240| v240_5(void) = Call[Constructible] : func:r240_3, this:r240_1, 0:r240_4
# 240| m240_6(unknown) = ^CallSideEffect : ~m239_4
# 240| m240_7(unknown) = Chi : total:m239_4, partial:m240_6
# 240| m240_8(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r240_1
# 240| m240_9(Constructible) = Chi : total:m240_2, partial:m240_8
# 240| m240_6(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r240_1
# 240| m240_7(Constructible) = Chi : total:m240_2, partial:m240_6
# 241| r241_1(glval<Constructible>) = VariableAddress[c] :
# 241| r241_2(glval<unknown>) = FunctionAddress[g] :
# 241| v241_3(void) = Call[g] : func:r241_2, this:r241_1
# 241| m241_4(unknown) = ^CallSideEffect : ~m240_7
# 241| m241_5(unknown) = Chi : total:m240_7, partial:m241_4
# 241| v241_6(void) = ^IndirectReadSideEffect[-1] : &:r241_1, m240_9
# 241| m241_7(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r241_1
# 241| m241_8(Constructible) = Chi : total:m240_9, partial:m241_7
# 241| v241_4(void) = ^IndirectReadSideEffect[-1] : &:r241_1, m240_7
# 241| m241_5(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r241_1
# 241| m241_6(Constructible) = Chi : total:m240_7, partial:m241_5
# 242| r242_1(glval<Constructible>) = VariableAddress[c] :
# 242| r242_2(glval<unknown>) = FunctionAddress[g] :
# 242| v242_3(void) = Call[g] : func:r242_2, this:r242_1
# 242| m242_4(unknown) = ^CallSideEffect : ~m241_5
# 242| m242_5(unknown) = Chi : total:m241_5, partial:m242_4
# 242| v242_6(void) = ^IndirectReadSideEffect[-1] : &:r242_1, m241_8
# 242| m242_7(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r242_1
# 242| m242_8(Constructible) = Chi : total:m241_8, partial:m242_7
# 242| v242_4(void) = ^IndirectReadSideEffect[-1] : &:r242_1, m241_6
# 242| m242_5(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r242_1
# 242| m242_6(Constructible) = Chi : total:m241_6, partial:m242_5
# 243| r243_1(glval<Constructible>) = VariableAddress[c2] :
# 243| m243_2(Constructible) = Uninitialized[c2] : &:r243_1
# 243| r243_3(glval<unknown>) = FunctionAddress[Constructible] :
# 243| r243_4(int) = Constant[2] :
# 243| v243_5(void) = Call[Constructible] : func:r243_3, this:r243_1, 0:r243_4
# 243| m243_6(unknown) = ^CallSideEffect : ~m242_5
# 243| m243_7(unknown) = Chi : total:m242_5, partial:m243_6
# 243| m243_8(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r243_1
# 243| m243_9(Constructible) = Chi : total:m243_2, partial:m243_8
# 243| m243_6(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r243_1
# 243| m243_7(Constructible) = Chi : total:m243_2, partial:m243_6
# 244| r244_1(glval<Constructible>) = VariableAddress[c2] :
# 244| r244_2(glval<unknown>) = FunctionAddress[g] :
# 244| v244_3(void) = Call[g] : func:r244_2, this:r244_1
# 244| m244_4(unknown) = ^CallSideEffect : ~m243_7
# 244| m244_5(unknown) = Chi : total:m243_7, partial:m244_4
# 244| v244_6(void) = ^IndirectReadSideEffect[-1] : &:r244_1, m243_9
# 244| m244_7(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r244_1
# 244| m244_8(Constructible) = Chi : total:m243_9, partial:m244_7
# 244| v244_4(void) = ^IndirectReadSideEffect[-1] : &:r244_1, m243_7
# 244| m244_5(Constructible) = ^IndirectMayWriteSideEffect[-1] : &:r244_1
# 244| m244_6(Constructible) = Chi : total:m243_7, partial:m244_5
# 245| v245_1(void) = NoOp :
# 239| v239_5(void) = ReturnVoid :
# 239| v239_6(void) = AliasedUse : ~m244_5
# 239| v239_6(void) = AliasedUse : m239_3
# 239| v239_7(void) = ExitFunction :
# 247| char* VoidStarIndirectParameters(char*, int)
@@ -1385,43 +1375,37 @@ ssa.cpp:
# 294| r294_18(glval<int>) = VariableAddress[x] :
# 294| r294_19(int) = Load[x] : &:r294_18, m291_6
# 294| v294_20(void) = Call[A] : func:r294_17, this:r294_16, 0:r294_19
# 294| m294_21(unknown) = ^CallSideEffect : ~m294_14
# 294| m294_22(unknown) = Chi : total:m294_14, partial:m294_21
# 294| m294_23(A) = ^IndirectMayWriteSideEffect[-1] : &:r294_16
# 294| m294_24(unknown) = Chi : total:m294_15, partial:m294_23
# 294| v294_25(void) = Call[A] : func:r294_9, this:r294_8, 0:r294_16
# 294| m294_26(unknown) = ^CallSideEffect : ~m294_22
# 294| m294_27(unknown) = Chi : total:m294_22, partial:m294_26
# 294| v294_28(void) = ^BufferReadSideEffect[0] : &:r294_16, ~m294_24
# 294| m294_29(A) = ^IndirectMayWriteSideEffect[-1] : &:r294_8
# 294| m294_30(unknown) = Chi : total:m294_7, partial:m294_29
# 294| m294_31(unknown) = ^BufferMayWriteSideEffect[0] : &:r294_16
# 294| m294_32(unknown) = Chi : total:m294_24, partial:m294_31
# 294| r294_33(glval<int>) = FieldAddress[i] : r294_8
# 294| r294_34(int) = Load[?] : &:r294_33, ~m294_30
# 294| m294_35(int) = Store[j] : &:r294_1, r294_34
# 294| m294_21(A) = ^IndirectMayWriteSideEffect[-1] : &:r294_16
# 294| m294_22(unknown) = Chi : total:m294_15, partial:m294_21
# 294| v294_23(void) = Call[A] : func:r294_9, this:r294_8, 0:r294_16
# 294| v294_24(void) = ^BufferReadSideEffect[0] : &:r294_16, ~m294_22
# 294| m294_25(A) = ^IndirectMayWriteSideEffect[-1] : &:r294_8
# 294| m294_26(unknown) = Chi : total:m294_7, partial:m294_25
# 294| m294_27(unknown) = ^BufferMayWriteSideEffect[0] : &:r294_16
# 294| m294_28(unknown) = Chi : total:m294_22, partial:m294_27
# 294| r294_29(glval<int>) = FieldAddress[i] : r294_8
# 294| r294_30(int) = Load[?] : &:r294_29, ~m294_26
# 294| m294_31(int) = Store[j] : &:r294_1, r294_30
# 295| r295_1(glval<A *>) = VariableAddress[a] :
# 295| r295_2(glval<unknown>) = FunctionAddress[operator new] :
# 295| r295_3(unsigned long) = Constant[4] :
# 295| r295_4(void *) = Call[operator new] : func:r295_2, 0:r295_3
# 295| m295_5(unknown) = ^CallSideEffect : ~m294_27
# 295| m295_6(unknown) = Chi : total:m294_27, partial:m295_5
# 295| m295_5(unknown) = ^CallSideEffect : ~m294_14
# 295| m295_6(unknown) = Chi : total:m294_14, partial:m295_5
# 295| m295_7(unknown) = ^InitializeDynamicAllocation : &:r295_4
# 295| r295_8(A *) = Convert : r295_4
# 295| r295_9(glval<unknown>) = FunctionAddress[A] :
# 295| v295_10(void) = Call[A] : func:r295_9, this:r295_8
# 295| m295_11(unknown) = ^CallSideEffect : ~m295_6
# 295| m295_12(unknown) = Chi : total:m295_6, partial:m295_11
# 295| m295_13(A) = ^IndirectMayWriteSideEffect[-1] : &:r295_8
# 295| m295_14(unknown) = Chi : total:m295_7, partial:m295_13
# 295| m295_15(A *) = Store[a] : &:r295_1, r295_8
# 295| m295_11(A) = ^IndirectMayWriteSideEffect[-1] : &:r295_8
# 295| m295_12(unknown) = Chi : total:m295_7, partial:m295_11
# 295| m295_13(A *) = Store[a] : &:r295_1, r295_8
# 296| r296_1(glval<Point *>) = VariableAddress[#return] :
# 296| r296_2(glval<Point *>) = VariableAddress[p] :
# 296| r296_3(Point *) = Load[p] : &:r296_2, m292_9
# 296| m296_4(Point *) = Store[#return] : &:r296_1, r296_3
# 291| r291_7(glval<Point *>) = VariableAddress[#return] :
# 291| v291_8(void) = ReturnValue : &:r291_7, m296_4
# 291| v291_9(void) = AliasedUse : ~m295_12
# 291| v291_9(void) = AliasedUse : ~m295_6
# 291| v291_10(void) = ExitFunction :
# 301| int main(int, char**)

View File

@@ -149,9 +149,6 @@ uniqueNodeLocation
| conditional_destructors.cpp:29:6:29:7 | EnterFunction | Node should have one location but has 2. |
| conditional_destructors.cpp:29:6:29:7 | ExitFunction | Node should have one location but has 2. |
| conditional_destructors.cpp:29:6:29:7 | InitializeNonLocal | Node should have one location but has 2. |
| conditional_destructors.cpp:29:6:29:7 | Phi | Node should have one location but has 2. |
| conditional_destructors.cpp:29:6:29:7 | Phi | Node should have one location but has 2. |
| conditional_destructors.cpp:29:6:29:7 | Phi | Node should have one location but has 2. |
| conditional_destructors.cpp:29:6:29:7 | ReturnVoid | Node should have one location but has 2. |
| conditional_destructors.cpp:29:6:29:7 | SideEffect | Node should have one location but has 2. |
| conditional_destructors.cpp:38:6:38:7 | AliasedDefinition | Node should have one location but has 2. |
@@ -162,9 +159,6 @@ uniqueNodeLocation
| conditional_destructors.cpp:38:6:38:7 | EnterFunction | Node should have one location but has 2. |
| conditional_destructors.cpp:38:6:38:7 | ExitFunction | Node should have one location but has 2. |
| conditional_destructors.cpp:38:6:38:7 | InitializeNonLocal | Node should have one location but has 2. |
| conditional_destructors.cpp:38:6:38:7 | Phi | Node should have one location but has 2. |
| conditional_destructors.cpp:38:6:38:7 | Phi | Node should have one location but has 2. |
| conditional_destructors.cpp:38:6:38:7 | Phi | Node should have one location but has 2. |
| conditional_destructors.cpp:38:6:38:7 | ReturnVoid | Node should have one location but has 2. |
| conditional_destructors.cpp:38:6:38:7 | SideEffect | Node should have one location but has 2. |
| conditional_destructors.cpp:38:6:38:7 | Unreached | Node should have one location but has 2. |
@@ -561,9 +555,6 @@ uniqueNodeLocation
| forstmt.cpp:1:6:1:7 | EnterFunction | Node should have one location but has 2. |
| forstmt.cpp:1:6:1:7 | ExitFunction | Node should have one location but has 2. |
| forstmt.cpp:1:6:1:7 | InitializeNonLocal | Node should have one location but has 2. |
| forstmt.cpp:1:6:1:7 | Phi | Node should have one location but has 2. |
| forstmt.cpp:1:6:1:7 | Phi | Node should have one location but has 2. |
| forstmt.cpp:1:6:1:7 | Phi | Node should have one location but has 2. |
| forstmt.cpp:1:6:1:7 | ReturnVoid | Node should have one location but has 2. |
| forstmt.cpp:1:6:1:7 | SideEffect | Node should have one location but has 2. |
| forstmt.cpp:8:6:8:7 | AliasedDefinition | Node should have one location but has 2. |
@@ -574,9 +565,6 @@ uniqueNodeLocation
| forstmt.cpp:8:6:8:7 | EnterFunction | Node should have one location but has 2. |
| forstmt.cpp:8:6:8:7 | ExitFunction | Node should have one location but has 2. |
| forstmt.cpp:8:6:8:7 | InitializeNonLocal | Node should have one location but has 2. |
| forstmt.cpp:8:6:8:7 | Phi | Node should have one location but has 2. |
| forstmt.cpp:8:6:8:7 | Phi | Node should have one location but has 2. |
| forstmt.cpp:8:6:8:7 | Phi | Node should have one location but has 2. |
| forstmt.cpp:8:6:8:7 | ReturnVoid | Node should have one location but has 2. |
| forstmt.cpp:8:6:8:7 | SideEffect | Node should have one location but has 2. |
| forstmt.cpp:8:6:8:7 | Unreached | Node should have one location but has 2. |

View File

@@ -2,6 +2,7 @@
| test.cpp:5:7:5:8 | p0 | 5:c7-c8 6:c7-c8 |
| test.cpp:5:7:5:13 | ... + ... | 5:c7-c13 6:c7-c13 7:c7-c7 |
| test.cpp:5:12:5:13 | p1 | 5:c12-c13 6:c12-c13 |
| test.cpp:10:16:10:16 | 1 | 10:c16-c16 176:c7-c7 178:c7-c7 |
| test.cpp:16:3:16:3 | x | 16:c3-c3 17:c3-c3 |
| test.cpp:16:7:16:8 | p0 | 16:c7-c8 17:c7-c8 |
| test.cpp:16:7:16:13 | ... + ... | 16:c7-c13 17:c7-c13 |
@@ -38,3 +39,9 @@
| test.cpp:145:15:145:15 | y | 145:c15-c15 147:c7-c7 |
| test.cpp:153:11:153:18 | global_a | 153:c11-c18 154:c11-c18 156:c3-c10 |
| test.cpp:153:21:153:21 | x | 153:c21-c21 154:c21-c21 |
| test.cpp:166:18:166:20 | (const char *)... | 166:c18-c20 167:c18-c20 173:c18-c20 |
| test.cpp:166:18:166:20 | dst | 166:c18-c20 167:c18-c20 171:c10-c12 173:c18-c20 |
| test.cpp:168:18:168:20 | (const char *)... | 168:c18-c20 169:c18-c20 171:c15-c17 174:c18-c20 |
| test.cpp:168:18:168:20 | src | 168:c18-c20 169:c18-c20 171:c15-c17 174:c18-c20 |
| test.cpp:176:10:176:10 | 2 | 176:c10-c10 178:c10-c10 21:c16-c16 |
| test.cpp:177:7:177:7 | 3 | 177:c7-c7 35:c16-c16 |

View File

@@ -44,3 +44,11 @@
| test.cpp:144:15:144:15 | GVN | 144:c15-c15 149:c15-c15 |
| test.cpp:153:11:153:18 | GVN | 153:c11-c18 154:c11-c18 156:c3-c10 |
| test.cpp:153:21:153:21 | GVN | 153:c21-c21 154:c21-c21 |
| test.cpp:166:11:166:16 | GVN | 166:c11-c16 167:c11-c16 |
| test.cpp:166:18:166:20 | GVN | 166:c18-c20 167:c18-c20 171:c10-c12 173:c18-c20 |
| test.cpp:166:18:166:20 | GVN | 166:c18-c20 167:c18-c20 173:c18-c20 |
| test.cpp:168:11:168:16 | GVN | 168:c11-c16 169:c11-c16 174:c11-c16 |
| test.cpp:168:18:168:20 | GVN | 168:c18-c20 169:c18-c20 171:c15-c17 174:c18-c20 |
| test.cpp:168:18:168:20 | GVN | 168:c18-c20 169:c18-c20 171:c15-c17 174:c18-c20 |
| test.cpp:176:7:176:7 | GVN | 176:c7-c7 178:c7-c7 |
| test.cpp:176:10:176:10 | GVN | 176:c10-c10 178:c10-c10 |

View File

@@ -1,15 +1,20 @@
| test.cpp:5:3:5:13 | ... = ... | test.cpp:5:3:5:13 | ... = ... | AST only |
| test.cpp:6:3:6:13 | ... = ... | test.cpp:6:3:6:13 | ... = ... | AST only |
| test.cpp:7:3:7:7 | ... = ... | test.cpp:7:3:7:7 | ... = ... | AST only |
| test.cpp:10:16:10:16 | 1 | test.cpp:176:7:176:7 | 1 | AST only |
| test.cpp:10:16:10:16 | 1 | test.cpp:178:7:178:7 | 1 | AST only |
| test.cpp:16:3:16:24 | ... = ... | test.cpp:16:3:16:24 | ... = ... | AST only |
| test.cpp:17:3:17:24 | ... = ... | test.cpp:17:3:17:24 | ... = ... | AST only |
| test.cpp:18:3:18:7 | ... = ... | test.cpp:18:3:18:7 | ... = ... | AST only |
| test.cpp:21:16:21:16 | 2 | test.cpp:176:10:176:10 | 2 | AST only |
| test.cpp:21:16:21:16 | 2 | test.cpp:178:10:178:10 | 2 | AST only |
| test.cpp:29:3:29:3 | x | test.cpp:31:3:31:3 | x | IR only |
| test.cpp:29:3:29:24 | ... = ... | test.cpp:29:3:29:24 | ... = ... | AST only |
| test.cpp:30:3:30:17 | call to change_global02 | test.cpp:30:3:30:17 | call to change_global02 | AST only |
| test.cpp:31:3:31:3 | x | test.cpp:29:3:29:3 | x | IR only |
| test.cpp:31:3:31:24 | ... = ... | test.cpp:31:3:31:24 | ... = ... | AST only |
| test.cpp:32:3:32:7 | ... = ... | test.cpp:32:3:32:7 | ... = ... | AST only |
| test.cpp:35:16:35:16 | 3 | test.cpp:177:7:177:7 | 3 | AST only |
| test.cpp:43:3:43:3 | x | test.cpp:45:3:45:3 | x | IR only |
| test.cpp:43:3:43:24 | ... = ... | test.cpp:43:3:43:24 | ... = ... | AST only |
| test.cpp:43:7:43:24 | ... + ... | test.cpp:45:7:45:24 | ... + ... | IR only |
@@ -127,3 +132,41 @@
| test.cpp:147:7:147:7 | y | test.cpp:145:15:145:15 | y | AST only |
| test.cpp:149:15:149:15 | x | test.cpp:144:15:144:15 | x | IR only |
| test.cpp:156:3:156:17 | ... = ... | test.cpp:156:3:156:17 | ... = ... | AST only |
| test.cpp:166:11:166:16 | call to strlen | test.cpp:167:11:167:16 | call to strlen | IR only |
| test.cpp:166:18:166:20 | (const char *)... | test.cpp:166:18:166:20 | (const char *)... | AST only |
| test.cpp:166:18:166:20 | (const char *)... | test.cpp:167:18:167:20 | (const char *)... | AST only |
| test.cpp:166:18:166:20 | (const char *)... | test.cpp:173:18:173:20 | (const char *)... | AST only |
| test.cpp:167:11:167:16 | call to strlen | test.cpp:166:11:166:16 | call to strlen | IR only |
| test.cpp:167:18:167:20 | (const char *)... | test.cpp:166:18:166:20 | (const char *)... | AST only |
| test.cpp:167:18:167:20 | (const char *)... | test.cpp:167:18:167:20 | (const char *)... | AST only |
| test.cpp:167:18:167:20 | (const char *)... | test.cpp:173:18:173:20 | (const char *)... | AST only |
| test.cpp:168:11:168:16 | call to strlen | test.cpp:169:11:169:16 | call to strlen | IR only |
| test.cpp:168:11:168:16 | call to strlen | test.cpp:174:11:174:16 | call to strlen | IR only |
| test.cpp:168:18:168:20 | (const char *)... | test.cpp:168:18:168:20 | (const char *)... | AST only |
| test.cpp:168:18:168:20 | (const char *)... | test.cpp:169:18:169:20 | (const char *)... | AST only |
| test.cpp:168:18:168:20 | (const char *)... | test.cpp:171:15:171:17 | (const char *)... | AST only |
| test.cpp:168:18:168:20 | (const char *)... | test.cpp:174:18:174:20 | (const char *)... | AST only |
| test.cpp:169:11:169:16 | call to strlen | test.cpp:168:11:168:16 | call to strlen | IR only |
| test.cpp:169:11:169:16 | call to strlen | test.cpp:174:11:174:16 | call to strlen | IR only |
| test.cpp:169:18:169:20 | (const char *)... | test.cpp:168:18:168:20 | (const char *)... | AST only |
| test.cpp:169:18:169:20 | (const char *)... | test.cpp:169:18:169:20 | (const char *)... | AST only |
| test.cpp:169:18:169:20 | (const char *)... | test.cpp:171:15:171:17 | (const char *)... | AST only |
| test.cpp:169:18:169:20 | (const char *)... | test.cpp:174:18:174:20 | (const char *)... | AST only |
| test.cpp:171:15:171:17 | (const char *)... | test.cpp:168:18:168:20 | (const char *)... | AST only |
| test.cpp:171:15:171:17 | (const char *)... | test.cpp:169:18:169:20 | (const char *)... | AST only |
| test.cpp:171:15:171:17 | (const char *)... | test.cpp:171:15:171:17 | (const char *)... | AST only |
| test.cpp:171:15:171:17 | (const char *)... | test.cpp:174:18:174:20 | (const char *)... | AST only |
| test.cpp:173:18:173:20 | (const char *)... | test.cpp:166:18:166:20 | (const char *)... | AST only |
| test.cpp:173:18:173:20 | (const char *)... | test.cpp:167:18:167:20 | (const char *)... | AST only |
| test.cpp:173:18:173:20 | (const char *)... | test.cpp:173:18:173:20 | (const char *)... | AST only |
| test.cpp:174:11:174:16 | call to strlen | test.cpp:168:11:168:16 | call to strlen | IR only |
| test.cpp:174:11:174:16 | call to strlen | test.cpp:169:11:169:16 | call to strlen | IR only |
| test.cpp:174:18:174:20 | (const char *)... | test.cpp:168:18:168:20 | (const char *)... | AST only |
| test.cpp:174:18:174:20 | (const char *)... | test.cpp:169:18:169:20 | (const char *)... | AST only |
| test.cpp:174:18:174:20 | (const char *)... | test.cpp:171:15:171:17 | (const char *)... | AST only |
| test.cpp:174:18:174:20 | (const char *)... | test.cpp:174:18:174:20 | (const char *)... | AST only |
| test.cpp:176:7:176:7 | 1 | test.cpp:10:16:10:16 | 1 | AST only |
| test.cpp:176:10:176:10 | 2 | test.cpp:21:16:21:16 | 2 | AST only |
| test.cpp:177:7:177:7 | 3 | test.cpp:35:16:35:16 | 3 | AST only |
| test.cpp:178:7:178:7 | 1 | test.cpp:10:16:10:16 | 1 | AST only |
| test.cpp:178:10:178:10 | 2 | test.cpp:21:16:21:16 | 2 | AST only |

View File

@@ -1145,3 +1145,206 @@ test.cpp:
# 152| v152_7(void) = ReturnVoid :
# 152| v152_8(void) = AliasedUse : ~m156_7
# 152| v152_9(void) = ExitFunction :
# 163| int add(int, int)
# 163| Block 0
# 163| v163_1(void) = EnterFunction :
# 163| m163_2(unknown) = AliasedDefinition :
# 163| valnum = unique
# 163| m163_3(unknown) = InitializeNonLocal :
# 163| valnum = unique
# 163| m163_4(unknown) = Chi : total:m163_2, partial:m163_3
# 163| valnum = unique
# 163| r163_5(glval<int>) = VariableAddress[a] :
# 163| valnum = r163_10, r163_5
# 163| m163_6(int) = InitializeParameter[a] : &:r163_5
# 163| valnum = m163_6, r163_11
# 163| r163_7(glval<int>) = VariableAddress[b] :
# 163| valnum = r163_12, r163_7
# 163| m163_8(int) = InitializeParameter[b] : &:r163_7
# 163| valnum = m163_8, r163_13
# 163| r163_9(glval<int>) = VariableAddress[#return] :
# 163| valnum = r163_16, r163_9
# 163| r163_10(glval<int>) = VariableAddress[a] :
# 163| valnum = r163_10, r163_5
# 163| r163_11(int) = Load[a] : &:r163_10, m163_6
# 163| valnum = m163_6, r163_11
# 163| r163_12(glval<int>) = VariableAddress[b] :
# 163| valnum = r163_12, r163_7
# 163| r163_13(int) = Load[b] : &:r163_12, m163_8
# 163| valnum = m163_8, r163_13
# 163| r163_14(int) = Add : r163_11, r163_13
# 163| valnum = m163_15, r163_14
# 163| m163_15(int) = Store[#return] : &:r163_9, r163_14
# 163| valnum = m163_15, r163_14
# 163| r163_16(glval<int>) = VariableAddress[#return] :
# 163| valnum = r163_16, r163_9
# 163| v163_17(void) = ReturnValue : &:r163_16, m163_15
# 163| v163_18(void) = AliasedUse : m163_3
# 163| v163_19(void) = ExitFunction :
# 165| void test_func_value_numbering(char*, char*)
# 165| Block 0
# 165| v165_1(void) = EnterFunction :
# 165| m165_2(unknown) = AliasedDefinition :
# 165| valnum = unique
# 165| m165_3(unknown) = InitializeNonLocal :
# 165| valnum = unique
# 165| m165_4(unknown) = Chi : total:m165_2, partial:m165_3
# 165| valnum = unique
# 165| r165_5(glval<char *>) = VariableAddress[dst] :
# 165| valnum = r165_5, r166_3, r167_3, r171_2, r173_3
# 165| m165_6(char *) = InitializeParameter[dst] : &:r165_5
# 165| valnum = m165_6, r165_7, r166_4, r167_4, r171_3, r173_4
# 165| r165_7(char *) = Load[dst] : &:r165_5, m165_6
# 165| valnum = m165_6, r165_7, r166_4, r167_4, r171_3, r173_4
# 165| m165_8(unknown) = InitializeIndirection[dst] : &:r165_7
# 165| valnum = unique
# 165| r165_9(glval<char *>) = VariableAddress[src] :
# 165| valnum = r165_9, r168_3, r169_3, r171_4, r174_3
# 165| m165_10(char *) = InitializeParameter[src] : &:r165_9
# 165| valnum = m165_10, r165_11, r168_4, r169_4, r171_5, r174_4
# 165| r165_11(char *) = Load[src] : &:r165_9, m165_10
# 165| valnum = m165_10, r165_11, r168_4, r169_4, r171_5, r174_4
# 165| m165_12(unknown) = InitializeIndirection[src] : &:r165_11
# 165| valnum = unique
# 166| r166_1(glval<int>) = VariableAddress[a] :
# 166| valnum = unique
# 166| r166_2(glval<unknown>) = FunctionAddress[strlen] :
# 166| valnum = unique
# 166| r166_3(glval<char *>) = VariableAddress[dst] :
# 166| valnum = r165_5, r166_3, r167_3, r171_2, r173_3
# 166| r166_4(char *) = Load[dst] : &:r166_3, m165_6
# 166| valnum = m165_6, r165_7, r166_4, r167_4, r171_3, r173_4
# 166| r166_5(char *) = Convert : r166_4
# 166| valnum = r166_5, r167_5, r173_5
# 166| r166_6(int) = Call[strlen] : func:r166_2, 0:r166_5
# 166| valnum = m166_8, m167_8, r166_6, r167_6
# 166| v166_7(void) = ^BufferReadSideEffect[0] : &:r166_5, ~m165_8
# 166| m166_8(int) = Store[a] : &:r166_1, r166_6
# 166| valnum = m166_8, m167_8, r166_6, r167_6
# 167| r167_1(glval<int>) = VariableAddress[b] :
# 167| valnum = unique
# 167| r167_2(glval<unknown>) = FunctionAddress[strlen] :
# 167| valnum = unique
# 167| r167_3(glval<char *>) = VariableAddress[dst] :
# 167| valnum = r165_5, r166_3, r167_3, r171_2, r173_3
# 167| r167_4(char *) = Load[dst] : &:r167_3, m165_6
# 167| valnum = m165_6, r165_7, r166_4, r167_4, r171_3, r173_4
# 167| r167_5(char *) = Convert : r167_4
# 167| valnum = r166_5, r167_5, r173_5
# 167| r167_6(int) = Call[strlen] : func:r167_2, 0:r167_5
# 167| valnum = m166_8, m167_8, r166_6, r167_6
# 167| v167_7(void) = ^BufferReadSideEffect[0] : &:r167_5, ~m165_8
# 167| m167_8(int) = Store[b] : &:r167_1, r167_6
# 167| valnum = m166_8, m167_8, r166_6, r167_6
# 168| r168_1(glval<int>) = VariableAddress[c] :
# 168| valnum = unique
# 168| r168_2(glval<unknown>) = FunctionAddress[strlen] :
# 168| valnum = unique
# 168| r168_3(glval<char *>) = VariableAddress[src] :
# 168| valnum = r165_9, r168_3, r169_3, r171_4, r174_3
# 168| r168_4(char *) = Load[src] : &:r168_3, m165_10
# 168| valnum = m165_10, r165_11, r168_4, r169_4, r171_5, r174_4
# 168| r168_5(char *) = Convert : r168_4
# 168| valnum = r168_5, r169_5, r171_6, r174_5
# 168| r168_6(int) = Call[strlen] : func:r168_2, 0:r168_5
# 168| valnum = m168_8, m169_8, m174_8, r168_6, r169_6, r174_6
# 168| v168_7(void) = ^BufferReadSideEffect[0] : &:r168_5, ~m165_12
# 168| m168_8(int) = Store[c] : &:r168_1, r168_6
# 168| valnum = m168_8, m169_8, m174_8, r168_6, r169_6, r174_6
# 169| r169_1(glval<int>) = VariableAddress[d] :
# 169| valnum = unique
# 169| r169_2(glval<unknown>) = FunctionAddress[strlen] :
# 169| valnum = unique
# 169| r169_3(glval<char *>) = VariableAddress[src] :
# 169| valnum = r165_9, r168_3, r169_3, r171_4, r174_3
# 169| r169_4(char *) = Load[src] : &:r169_3, m165_10
# 169| valnum = m165_10, r165_11, r168_4, r169_4, r171_5, r174_4
# 169| r169_5(char *) = Convert : r169_4
# 169| valnum = r168_5, r169_5, r171_6, r174_5
# 169| r169_6(int) = Call[strlen] : func:r169_2, 0:r169_5
# 169| valnum = m168_8, m169_8, m174_8, r168_6, r169_6, r174_6
# 169| v169_7(void) = ^BufferReadSideEffect[0] : &:r169_5, ~m165_12
# 169| m169_8(int) = Store[d] : &:r169_1, r169_6
# 169| valnum = m168_8, m169_8, m174_8, r168_6, r169_6, r174_6
# 171| r171_1(glval<unknown>) = FunctionAddress[strcat] :
# 171| valnum = unique
# 171| r171_2(glval<char *>) = VariableAddress[dst] :
# 171| valnum = r165_5, r166_3, r167_3, r171_2, r173_3
# 171| r171_3(char *) = Load[dst] : &:r171_2, m165_6
# 171| valnum = m165_6, r165_7, r166_4, r167_4, r171_3, r173_4
# 171| r171_4(glval<char *>) = VariableAddress[src] :
# 171| valnum = r165_9, r168_3, r169_3, r171_4, r174_3
# 171| r171_5(char *) = Load[src] : &:r171_4, m165_10
# 171| valnum = m165_10, r165_11, r168_4, r169_4, r171_5, r174_4
# 171| r171_6(char *) = Convert : r171_5
# 171| valnum = r168_5, r169_5, r171_6, r174_5
# 171| r171_7(char *) = Call[strcat] : func:r171_1, 0:r171_3, 1:r171_6
# 171| valnum = unique
# 171| v171_8(void) = ^BufferReadSideEffect[0] : &:r171_3, ~m165_8
# 171| v171_9(void) = ^BufferReadSideEffect[1] : &:r171_6, ~m165_12
# 171| m171_10(unknown) = ^BufferMayWriteSideEffect[0] : &:r171_3
# 171| valnum = unique
# 171| m171_11(unknown) = Chi : total:m165_8, partial:m171_10
# 171| valnum = unique
# 173| r173_1(glval<int>) = VariableAddress[e] :
# 173| valnum = unique
# 173| r173_2(glval<unknown>) = FunctionAddress[strlen] :
# 173| valnum = unique
# 173| r173_3(glval<char *>) = VariableAddress[dst] :
# 173| valnum = r165_5, r166_3, r167_3, r171_2, r173_3
# 173| r173_4(char *) = Load[dst] : &:r173_3, m165_6
# 173| valnum = m165_6, r165_7, r166_4, r167_4, r171_3, r173_4
# 173| r173_5(char *) = Convert : r173_4
# 173| valnum = r166_5, r167_5, r173_5
# 173| r173_6(int) = Call[strlen] : func:r173_2, 0:r173_5
# 173| valnum = m173_8, r173_6
# 173| v173_7(void) = ^BufferReadSideEffect[0] : &:r173_5, ~m171_11
# 173| m173_8(int) = Store[e] : &:r173_1, r173_6
# 173| valnum = m173_8, r173_6
# 174| r174_1(glval<int>) = VariableAddress[f] :
# 174| valnum = unique
# 174| r174_2(glval<unknown>) = FunctionAddress[strlen] :
# 174| valnum = unique
# 174| r174_3(glval<char *>) = VariableAddress[src] :
# 174| valnum = r165_9, r168_3, r169_3, r171_4, r174_3
# 174| r174_4(char *) = Load[src] : &:r174_3, m165_10
# 174| valnum = m165_10, r165_11, r168_4, r169_4, r171_5, r174_4
# 174| r174_5(char *) = Convert : r174_4
# 174| valnum = r168_5, r169_5, r171_6, r174_5
# 174| r174_6(int) = Call[strlen] : func:r174_2, 0:r174_5
# 174| valnum = m168_8, m169_8, m174_8, r168_6, r169_6, r174_6
# 174| v174_7(void) = ^BufferReadSideEffect[0] : &:r174_5, ~m165_12
# 174| m174_8(int) = Store[f] : &:r174_1, r174_6
# 174| valnum = m168_8, m169_8, m174_8, r168_6, r169_6, r174_6
# 176| r176_1(glval<unknown>) = FunctionAddress[add] :
# 176| valnum = unique
# 176| r176_2(int) = Constant[1] :
# 176| valnum = r176_2, r178_2
# 176| r176_3(int) = Constant[2] :
# 176| valnum = r176_3, r178_3
# 176| r176_4(int) = Call[add] : func:r176_1, 0:r176_2, 1:r176_3
# 176| valnum = unique
# 177| r177_1(glval<unknown>) = FunctionAddress[add] :
# 177| valnum = unique
# 177| r177_2(int) = Constant[3] :
# 177| valnum = unique
# 177| r177_3(int) = Constant[4] :
# 177| valnum = unique
# 177| r177_4(int) = Call[add] : func:r177_1, 0:r177_2, 1:r177_3
# 177| valnum = unique
# 178| r178_1(glval<unknown>) = FunctionAddress[add] :
# 178| valnum = unique
# 178| r178_2(int) = Constant[1] :
# 178| valnum = r176_2, r178_2
# 178| r178_3(int) = Constant[2] :
# 178| valnum = r176_3, r178_3
# 178| r178_4(int) = Call[add] : func:r178_1, 0:r178_2, 1:r178_3
# 178| valnum = unique
# 179| v179_1(void) = NoOp :
# 165| v165_13(void) = ReturnIndirection[dst] : &:r165_7, m171_11
# 165| v165_14(void) = ReturnIndirection[src] : &:r165_11, m165_12
# 165| v165_15(void) = ReturnVoid :
# 165| v165_16(void) = AliasedUse : m165_3
# 165| v165_17(void) = ExitFunction :

View File

@@ -156,4 +156,24 @@ void test_read_global_different(int n) {
global_a->y = n;
int d = global_a->x;
}
int strlen(const char *str);
char *strcat(char *dst, const char *src);
int add(int a, int b) { return a+b; }
void test_func_value_numbering(char *dst, char *src) {
int a = strlen(dst);
int b = strlen(dst); // same as previous line
int c = strlen(src);
int d = strlen(src); // same as previous line
strcat(dst, src);
int e = strlen(dst); // different from a and b
int f = strlen(src); // same as c and d
add(1, 2);
add(3, 4);
add(1, 2); // same as two lines earlier
}

View File

@@ -1,3 +1,3 @@
| empty_block.cpp:9:10:9:11 | { ... } | Empty block without comment |
| empty_block.cpp:12:10:13:3 | { ... } | Empty block without comment |
| empty_block.cpp:20:10:21:3 | { ... } | Empty block without comment |
| empty_block.cpp:9:10:9:11 | { ... } | Empty block without comment. |
| empty_block.cpp:12:10:13:3 | { ... } | Empty block without comment. |
| empty_block.cpp:20:10:21:3 | { ... } | Empty block without comment. |

View File

@@ -1,20 +1,20 @@
| test2.cpp:37:1:37:39 | // int myFunction() { return myValue; } | This comment appears to contain commented-out code |
| test2.cpp:39:1:39:45 | // int myFunction() const { return myValue; } | This comment appears to contain commented-out code |
| test2.cpp:41:1:41:54 | // int myFunction() const noexcept { return myValue; } | This comment appears to contain commented-out code |
| test2.cpp:43:1:43:18 | // #define MYMACRO | This comment appears to contain commented-out code |
| test2.cpp:45:1:45:23 | // #include "include.h" | This comment appears to contain commented-out code |
| test2.cpp:47:1:51:2 | /*\n#ifdef\nvoid myFunction();\n#endif\n*/ | This comment appears to contain commented-out code |
| test2.cpp:59:1:59:24 | // #if(defined(MYMACRO)) | This comment appears to contain commented-out code |
| test2.cpp:63:1:63:15 | // #pragma once | This comment appears to contain commented-out code |
| test2.cpp:65:1:65:17 | // # pragma once | This comment appears to contain commented-out code |
| test2.cpp:67:1:67:19 | /*#error"myerror"*/ | This comment appears to contain commented-out code |
| test2.cpp:91:1:95:2 | /*\n#ifdef MYMACRO\n\t// ...\n#endif // #ifdef MYMACRO\n*/ | This comment appears to contain commented-out code |
| test2.cpp:107:21:107:43 | // #include "config2.h" | This comment appears to contain commented-out code |
| test2.cpp:115:16:115:35 | /* #ifdef MYMACRO */ | This comment appears to contain commented-out code |
| test2.cpp:117:1:117:24 | // commented_out_code(); | This comment appears to contain commented-out code |
| test2.cpp:120:2:120:25 | // commented_out_code(); | This comment appears to contain commented-out code |
| test.c:2:1:2:22 | // commented out code; | This comment appears to contain commented-out code |
| test.c:4:1:7:8 | // some; | This comment appears to contain commented-out code |
| test.c:9:1:13:8 | // also; | This comment appears to contain commented-out code |
| test.c:21:1:26:2 | /*\n some;\n commented;\n out;\n code;\n*/ | This comment appears to contain commented-out code |
| test.c:28:1:34:2 | /*\n also;\n this\n is;\n commented-out\n code;\n*/ | This comment appears to contain commented-out code |
| test2.cpp:37:1:37:39 | // int myFunction() { return myValue; } | This comment appears to contain commented-out code. |
| test2.cpp:39:1:39:45 | // int myFunction() const { return myValue; } | This comment appears to contain commented-out code. |
| test2.cpp:41:1:41:54 | // int myFunction() const noexcept { return myValue; } | This comment appears to contain commented-out code. |
| test2.cpp:43:1:43:18 | // #define MYMACRO | This comment appears to contain commented-out code. |
| test2.cpp:45:1:45:23 | // #include "include.h" | This comment appears to contain commented-out code. |
| test2.cpp:47:1:51:2 | /*\n#ifdef\nvoid myFunction();\n#endif\n*/ | This comment appears to contain commented-out code. |
| test2.cpp:59:1:59:24 | // #if(defined(MYMACRO)) | This comment appears to contain commented-out code. |
| test2.cpp:63:1:63:15 | // #pragma once | This comment appears to contain commented-out code. |
| test2.cpp:65:1:65:17 | // # pragma once | This comment appears to contain commented-out code. |
| test2.cpp:67:1:67:19 | /*#error"myerror"*/ | This comment appears to contain commented-out code. |
| test2.cpp:91:1:95:2 | /*\n#ifdef MYMACRO\n\t// ...\n#endif // #ifdef MYMACRO\n*/ | This comment appears to contain commented-out code. |
| test2.cpp:107:21:107:43 | // #include "config2.h" | This comment appears to contain commented-out code. |
| test2.cpp:115:16:115:35 | /* #ifdef MYMACRO */ | This comment appears to contain commented-out code. |
| test2.cpp:117:1:117:24 | // commented_out_code(); | This comment appears to contain commented-out code. |
| test2.cpp:120:2:120:25 | // commented_out_code(); | This comment appears to contain commented-out code. |
| test.c:2:1:2:22 | // commented out code; | This comment appears to contain commented-out code. |
| test.c:4:1:7:8 | // some; | This comment appears to contain commented-out code. |
| test.c:9:1:13:8 | // also; | This comment appears to contain commented-out code. |
| test.c:21:1:26:2 | /*\n some;\n commented;\n out;\n code;\n*/ | This comment appears to contain commented-out code. |
| test.c:28:1:34:2 | /*\n also;\n this\n is;\n commented-out\n code;\n*/ | This comment appears to contain commented-out code. |

View File

@@ -1,4 +1,4 @@
| bsc.cpp:2:10:2:32 | ... > ... | Potential unsafe sign check of a bitwise operation. |
| bsc.cpp:6:10:6:32 | ... > ... | Potential unsafe sign check of a bitwise operation. |
| bsc.cpp:18:10:18:28 | ... > ... | Potential unsafe sign check of a bitwise operation. |
| bsc.cpp:22:10:22:28 | ... < ... | Potential unsafe sign check of a bitwise operation. |
| bsc.cpp:2:10:2:32 | ... > ... | Potentially unsafe sign check of a bitwise operation. |
| bsc.cpp:6:10:6:32 | ... > ... | Potentially unsafe sign check of a bitwise operation. |
| bsc.cpp:18:10:18:28 | ... > ... | Potentially unsafe sign check of a bitwise operation. |
| bsc.cpp:22:10:22:28 | ... < ... | Potentially unsafe sign check of a bitwise operation. |

View File

@@ -1,4 +1,4 @@
| c.c:10:5:10:10 | ... == ... | Equality test on floating point values may not behave as expected. |
| c.c:14:5:14:14 | ... == ... | Equality test on floating point values may not behave as expected. |
| c.c:16:5:16:12 | ... == ... | Equality test on floating point values may not behave as expected. |
| c.c:17:5:17:12 | ... == ... | Equality test on floating point values may not behave as expected. |
| c.c:10:5:10:10 | ... == ... | Equality checks on floating point values can yield unexpected results. |
| c.c:14:5:14:14 | ... == ... | Equality checks on floating point values can yield unexpected results. |
| c.c:16:5:16:12 | ... == ... | Equality checks on floating point values can yield unexpected results. |
| c.c:17:5:17:12 | ... == ... | Equality checks on floating point values can yield unexpected results. |

View File

@@ -14,4 +14,4 @@ import csharp
from CommentLine c
where c.getText().regexpMatch("(?s).*FIXME.*|.*TODO.*|.*(?<!=)\\s*XXX.*")
select c, "TODO comment."
select c, "TODO comments should be addressed."

View File

@@ -72,5 +72,5 @@ where
) and
m1.fromSource()
select m1,
"confusing to have methods " + m1.getName() + " in " + m1.getDeclaringType().getName() + " and " +
m2.getName() + " in " + m2.getDeclaringType().getName() + "."
"It is confusing to have methods " + m1.getName() + " in " + m1.getDeclaringType().getName() +
" and " + m2.getName() + " in " + m2.getDeclaringType().getName() + "."

View File

@@ -64,6 +64,5 @@ where
validGuard.controls(array, index) and
validGuard.guards(indexAccess, _)
)
select incorrectGuard,
"Off-by-one index comparison against length leads to possible out of bounds $@.", ea,
ea.toString()
select incorrectGuard, "Off-by-one index comparison against length may lead to out-of-bounds $@.",
ea, ea.toString()

View File

@@ -1,6 +1,8 @@
/**
* @name Equality check on floating point values
* @description Equality checks on floating point values can yield unexpected results.
* @description Comparing results of floating-point computations with '==' or
* '!=' is likely to yield surprising results since floating-point
* computation does not follow the standard rules of algebra.
* @kind problem
* @problem.severity warning
* @precision medium

View File

@@ -42,4 +42,4 @@ where
(loopStmtWithEmptyBlock(s) or conditionalWithEmptyBlock(s)) and
not exists(CommentBlock c | c.getParent() = s) and
not exists(ForStmt fs | fs.getBody() = s and exists(fs.getAnUpdate()))
select s, "Empty block."
select s, "Empty block without comment."

View File

@@ -35,4 +35,4 @@ where
access = cast.getAChild() and
access.getTarget().getDeclaringElement() = access.getEnclosingCallable() and
nodeBeforeParameterAccess(access.getAControlFlowNode())
select cast, "Missing type-check before casting parameter to 'Equals'."
select cast, "Equals() method does not check argument type."

View File

@@ -23,5 +23,5 @@ where
c.hasFlowPath(source, sink) and
// No global timeout set
not exists(RegexGlobalTimeout r)
select sink.getNode(), source, sink, "$@ flows to the construction of a regular expression.",
source.getNode(), "User-provided value"
select sink.getNode(), source, sink, "This regular expression is constructed from a $@.",
source.getNode(), "user-provided value"

View File

@@ -18,4 +18,4 @@ from MethodCall mc
where
mc instanceof ImplicitToStringExpr and
mc.getTarget() instanceof ToStringMethod
select mc, "Redundant call to 'ToString'."
select mc, "Redundant call to 'ToString' on a String object."

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* The alert message of many queries have been changed to make the message consistent with other languages.

View File

@@ -17,3 +17,5 @@ module SSA {
predicate hasUnreachedInstruction(IRFunctionBase irFunc) { none() }
}
predicate removedInstruction(TRawInstruction instr) { none() }

View File

@@ -34,6 +34,7 @@ newtype TInstruction =
AliasedSsa::SSA::hasPhiInstruction(blockStartInstr, memoryLocation)
} or
TAliasedSsaChiInstruction(TRawInstruction primaryInstruction) {
not AliasedSsa::removedInstruction(primaryInstruction) and
AliasedSsa::SSA::hasChiInstruction(primaryInstruction)
} or
TAliasedSsaUnreachedInstruction(IRFunctionBase irFunc) {

View File

@@ -1712,6 +1712,11 @@ class SideEffectInstruction extends Instruction {
*/
class CallSideEffectInstruction extends SideEffectInstruction {
CallSideEffectInstruction() { this.getOpcode() instanceof Opcode::CallSideEffect }
/** Gets the operand for the value that will be read by this instruction */
final SideEffectOperand getSideEffectOperand() { result = this.getAnOperand() }
final Instruction getSideEffect() { result = this.getAnOperand().getDef() }
}
/**
@@ -1723,6 +1728,11 @@ class CallSideEffectInstruction extends SideEffectInstruction {
*/
class CallReadSideEffectInstruction extends SideEffectInstruction {
CallReadSideEffectInstruction() { this.getOpcode() instanceof Opcode::CallReadSideEffect }
/** Gets the operand for the value that will be read by this instruction */
final SideEffectOperand getSideEffectOperand() { result = this.getAnOperand() }
final Instruction getSideEffect() { result = this.getAnOperand().getDef() }
}
/**

View File

@@ -1,3 +1,4 @@
import experimental.ir.internal.Overlap
import experimental.ir.internal.IRCSharpLanguage as Language
import experimental.ir.implementation.unaliased_ssa.IR
import experimental.ir.interfaces.SideEffect as SideEffect

View File

@@ -41,8 +41,92 @@ newtype TValueNumber =
) {
loadTotalOverlapValueNumber(_, irFunc, type, memOperand, operand)
} or
TCallValueNumber(TCallPartialValueNumber vn) { callValueNumber(_, _, vn) } or
TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) }
private class NumberableCallInstruction extends CallInstruction {
NumberableCallInstruction() {
not this.getResultIRType() instanceof IRVoidType and
exists(SideEffect::SideEffectFunction sideEffectFunc |
sideEffectFunc = this.getStaticCallTarget()
|
sideEffectFunc.hasOnlySpecificReadSideEffects() and
sideEffectFunc.hasOnlySpecificWriteSideEffects()
)
}
}
private newtype TCallPartialValueNumber =
TNilArgument() or
TArgument(TCallPartialValueNumber head, TValueNumber arg) {
exists(NumberableCallInstruction call, int index |
callArgValueNumber(call, index, arg) and
callPartialValueNumber(call, index, head)
)
}
private predicate callValueNumber(
NumberableCallInstruction call, int index, TCallPartialValueNumber vn
) {
index = max(int n | callArgRank(call, n, _) | n) and
exists(TCallPartialValueNumber head, TValueNumber arg |
callPartialValueNumber(call, index, pragma[only_bind_out](head)) and
callArgValueNumber(call, index, pragma[only_bind_into](arg)) and
vn = TArgument(head, arg)
)
or
not exists(int n | callArgRank(call, n, _)) and
index = -1 and
vn = TNilArgument()
}
private predicate callPartialValueNumber(
NumberableCallInstruction call, int index, TCallPartialValueNumber head
) {
exists(call) and
index = 1 and
head = TNilArgument()
or
exists(TCallPartialValueNumber prev, TValueNumber prevVN |
callPartialValueNumber(call, index - 1, pragma[only_bind_out](prev)) and
callArgValueNumber(call, index - 1, pragma[only_bind_into](prevVN)) and
head = TArgument(prev, prevVN)
)
}
/**
*/
private predicate callArgValueNumber(NumberableCallInstruction call, int index, TValueNumber arg) {
exists(Instruction instr |
callArgRank(call, index, instr) and
arg = tvalueNumber(instr)
)
}
/**
* Holds if `arg` is the `index`th element in `call`'s extended argument list, including the `this`
* argument and side-effect reads.
*/
private predicate callArgRank(NumberableCallInstruction call, int index, Instruction arg) {
arg =
rank[index](int argIndex, boolean isEffect, Instruction instr |
// There is no need to include the call's read and write side effects on
// all-aliased-memory as `NumberableCallInstruction`s do not read or write
// to all-aliased-memory.
instr = call.getArgument(argIndex) and
isEffect = false
or
exists(ReadSideEffectInstruction read |
read.getPrimaryInstruction() = call and
read.getSideEffectOperand().getAnyDef() = instr and
read.getIndex() = argIndex and
isEffect = true
)
|
instr order by argIndex, isEffect
)
}
/**
* A `CopyInstruction` whose source operand's value is congruent to the definition of that source
* operand.
@@ -93,6 +177,8 @@ private predicate numberableInstruction(Instruction instr) {
instr instanceof CongruentCopyInstruction
or
instr instanceof LoadTotalOverlapInstruction
or
instr instanceof NumberableCallInstruction
}
private predicate filteredNumberableInstruction(Instruction instr) {
@@ -309,6 +395,11 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
or
// The value number of a copy is just the value number of its source value.
result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue())
or
exists(TCallPartialValueNumber pvn |
callValueNumber(instr, _, pvn) and
result = TCallValueNumber(pvn)
)
)
)
}

View File

@@ -1712,6 +1712,11 @@ class SideEffectInstruction extends Instruction {
*/
class CallSideEffectInstruction extends SideEffectInstruction {
CallSideEffectInstruction() { this.getOpcode() instanceof Opcode::CallSideEffect }
/** Gets the operand for the value that will be read by this instruction */
final SideEffectOperand getSideEffectOperand() { result = this.getAnOperand() }
final Instruction getSideEffect() { result = this.getAnOperand().getDef() }
}
/**
@@ -1723,6 +1728,11 @@ class CallSideEffectInstruction extends SideEffectInstruction {
*/
class CallReadSideEffectInstruction extends SideEffectInstruction {
CallReadSideEffectInstruction() { this.getOpcode() instanceof Opcode::CallReadSideEffect }
/** Gets the operand for the value that will be read by this instruction */
final SideEffectOperand getSideEffectOperand() { result = this.getAnOperand() }
final Instruction getSideEffect() { result = this.getAnOperand().getDef() }
}
/**

View File

@@ -1,3 +1,4 @@
import experimental.ir.internal.Overlap
import experimental.ir.internal.IRCSharpLanguage as Language
import experimental.ir.implementation.unaliased_ssa.IR
import experimental.ir.interfaces.SideEffect as SideEffect

View File

@@ -41,8 +41,92 @@ newtype TValueNumber =
) {
loadTotalOverlapValueNumber(_, irFunc, type, memOperand, operand)
} or
TCallValueNumber(TCallPartialValueNumber vn) { callValueNumber(_, _, vn) } or
TUniqueValueNumber(IRFunction irFunc, Instruction instr) { uniqueValueNumber(instr, irFunc) }
private class NumberableCallInstruction extends CallInstruction {
NumberableCallInstruction() {
not this.getResultIRType() instanceof IRVoidType and
exists(SideEffect::SideEffectFunction sideEffectFunc |
sideEffectFunc = this.getStaticCallTarget()
|
sideEffectFunc.hasOnlySpecificReadSideEffects() and
sideEffectFunc.hasOnlySpecificWriteSideEffects()
)
}
}
private newtype TCallPartialValueNumber =
TNilArgument() or
TArgument(TCallPartialValueNumber head, TValueNumber arg) {
exists(NumberableCallInstruction call, int index |
callArgValueNumber(call, index, arg) and
callPartialValueNumber(call, index, head)
)
}
private predicate callValueNumber(
NumberableCallInstruction call, int index, TCallPartialValueNumber vn
) {
index = max(int n | callArgRank(call, n, _) | n) and
exists(TCallPartialValueNumber head, TValueNumber arg |
callPartialValueNumber(call, index, pragma[only_bind_out](head)) and
callArgValueNumber(call, index, pragma[only_bind_into](arg)) and
vn = TArgument(head, arg)
)
or
not exists(int n | callArgRank(call, n, _)) and
index = -1 and
vn = TNilArgument()
}
private predicate callPartialValueNumber(
NumberableCallInstruction call, int index, TCallPartialValueNumber head
) {
exists(call) and
index = 1 and
head = TNilArgument()
or
exists(TCallPartialValueNumber prev, TValueNumber prevVN |
callPartialValueNumber(call, index - 1, pragma[only_bind_out](prev)) and
callArgValueNumber(call, index - 1, pragma[only_bind_into](prevVN)) and
head = TArgument(prev, prevVN)
)
}
/**
*/
private predicate callArgValueNumber(NumberableCallInstruction call, int index, TValueNumber arg) {
exists(Instruction instr |
callArgRank(call, index, instr) and
arg = tvalueNumber(instr)
)
}
/**
* Holds if `arg` is the `index`th element in `call`'s extended argument list, including the `this`
* argument and side-effect reads.
*/
private predicate callArgRank(NumberableCallInstruction call, int index, Instruction arg) {
arg =
rank[index](int argIndex, boolean isEffect, Instruction instr |
// There is no need to include the call's read and write side effects on
// all-aliased-memory as `NumberableCallInstruction`s do not read or write
// to all-aliased-memory.
instr = call.getArgument(argIndex) and
isEffect = false
or
exists(ReadSideEffectInstruction read |
read.getPrimaryInstruction() = call and
read.getSideEffectOperand().getAnyDef() = instr and
read.getIndex() = argIndex and
isEffect = true
)
|
instr order by argIndex, isEffect
)
}
/**
* A `CopyInstruction` whose source operand's value is congruent to the definition of that source
* operand.
@@ -93,6 +177,8 @@ private predicate numberableInstruction(Instruction instr) {
instr instanceof CongruentCopyInstruction
or
instr instanceof LoadTotalOverlapInstruction
or
instr instanceof NumberableCallInstruction
}
private predicate filteredNumberableInstruction(Instruction instr) {
@@ -309,6 +395,11 @@ private TValueNumber nonUniqueValueNumber(Instruction instr) {
or
// The value number of a copy is just the value number of its source value.
result = tvalueNumber(instr.(CongruentCopyInstruction).getSourceValue())
or
exists(TCallPartialValueNumber pvn |
callValueNumber(instr, _, pvn) and
result = TCallValueNumber(pvn)
)
)
)
}

View File

@@ -8,11 +8,6 @@ private import Imports::RawIR as RawIR
private import SsaInstructions
private import SsaOperands
private import NewIR
private class OldBlock = Reachability::ReachableBlock;
private class OldInstruction = Reachability::ReachableInstruction;
import Cached
cached
@@ -58,7 +53,9 @@ private module Cached {
cached
predicate hasInstruction(TStageInstruction instr) {
instr instanceof TRawInstruction and instr instanceof OldInstruction
instr instanceof TRawInstruction and
instr instanceof OldInstruction and
not removedInstruction(instr)
or
instr = phiInstruction(_, _)
or
@@ -382,7 +379,14 @@ private module Cached {
(
if Reachability::isInfeasibleInstructionSuccessor(oldInstruction, kind)
then result = unreachedInstruction(instruction.getEnclosingIRFunction())
else result = getNewInstruction(oldInstruction.getSuccessor(kind))
else
if removedInstruction(oldInstruction.getSuccessor(kind))
then
// the only removed nodes are side-effect writes, but those may have Chi nodes
// skip to the following instruction in the old IR, which won't be removed
// if we start skipping specific side effects, this may no longer hold
result = getNewInstruction(oldInstruction.getSuccessor(kind).getSuccessor(kind))
else result = getNewInstruction(oldInstruction.getSuccessor(kind))
)
)
or

View File

@@ -14,3 +14,9 @@ import experimental.ir.implementation.internal.TOperand::UnaliasedSsaOperands as
/** DEPRECATED: Alias for SsaOperands */
deprecated module SSAOperands = SsaOperands;
predicate removedInstruction(Reachability::ReachableInstruction instr) { none() }
class OldBlock = Reachability::ReachableBlock;
class OldInstruction = Reachability::ReachableInstruction;

View File

@@ -0,0 +1,24 @@
private import csharp as CSharp
/**
* A class that models the side effects of a library function.
*/
abstract class SideEffectFunction extends CSharp::Callable {
/**
* Holds if the function never reads from memory that was defined before entry to the function.
* This memory could be from global variables, or from other memory that was reachable from a
* pointer that was passed into the function. Input side-effects, and reads from memory that
* cannot be visible to the caller (for example a buffer inside an I/O library) are not modeled
* here.
*/
abstract predicate hasOnlySpecificReadSideEffects();
/**
* Holds if the function never writes to memory that remains allocated after the function
* returns. This memory could be from global variables, or from other memory that was reachable
* from a pointer that was passed into the function. Output side-effects, and writes to memory
* that cannot be visible to the caller (for example a buffer inside an I/O library) are not
* modeled here.
*/
abstract predicate hasOnlySpecificWriteSideEffects();
}

View File

@@ -1,3 +1,3 @@
| TodoComments.cs:4:5:4:26 | // ... | TODO comment. |
| TodoComments.cs:5:5:5:27 | // ... | TODO comment. |
| TodoCommentsBad.cs:7:9:7:41 | // ... | TODO comment. |
| TodoComments.cs:4:5:4:26 | // ... | TODO comments should be addressed. |
| TodoComments.cs:5:5:5:27 | // ... | TODO comments should be addressed. |
| TodoCommentsBad.cs:7:9:7:41 | // ... | TODO comments should be addressed. |

View File

@@ -1,3 +1,3 @@
| EmptyBlock.cs:9:9:10:9 | {...} | Empty block. |
| EmptyBlock.cs:26:9:27:9 | {...} | Empty block. |
| EmptyBlock.cs:48:9:49:9 | {...} | Empty block. |
| EmptyBlock.cs:9:9:10:9 | {...} | Empty block without comment. |
| EmptyBlock.cs:26:9:27:9 | {...} | Empty block without comment. |
| EmptyBlock.cs:48:9:49:9 | {...} | Empty block without comment. |

View File

@@ -1,4 +1,4 @@
| ContainerLengthCmpOffByOne.cs:8:25:8:40 | ... <= ... | Off-by-one index comparison against length leads to possible out of bounds $@. | ContainerLengthCmpOffByOne.cs:10:31:10:37 | access to array element | access to array element |
| ContainerLengthCmpOffByOne.cs:14:25:14:40 | ... >= ... | Off-by-one index comparison against length leads to possible out of bounds $@. | ContainerLengthCmpOffByOne.cs:16:31:16:37 | access to array element | access to array element |
| ContainerLengthCmpOffByOne.cs:27:13:27:28 | ... <= ... | Off-by-one index comparison against length leads to possible out of bounds $@. | ContainerLengthCmpOffByOne.cs:29:31:29:37 | access to array element | access to array element |
| ContainerLengthCmpOffByOne.cs:33:13:33:28 | ... >= ... | Off-by-one index comparison against length leads to possible out of bounds $@. | ContainerLengthCmpOffByOne.cs:35:31:35:37 | access to array element | access to array element |
| ContainerLengthCmpOffByOne.cs:8:25:8:40 | ... <= ... | Off-by-one index comparison against length may lead to out-of-bounds $@. | ContainerLengthCmpOffByOne.cs:10:31:10:37 | access to array element | access to array element |
| ContainerLengthCmpOffByOne.cs:14:25:14:40 | ... >= ... | Off-by-one index comparison against length may lead to out-of-bounds $@. | ContainerLengthCmpOffByOne.cs:16:31:16:37 | access to array element | access to array element |
| ContainerLengthCmpOffByOne.cs:27:13:27:28 | ... <= ... | Off-by-one index comparison against length may lead to out-of-bounds $@. | ContainerLengthCmpOffByOne.cs:29:31:29:37 | access to array element | access to array element |
| ContainerLengthCmpOffByOne.cs:33:13:33:28 | ... >= ... | Off-by-one index comparison against length may lead to out-of-bounds $@. | ContainerLengthCmpOffByOne.cs:35:31:35:37 | access to array element | access to array element |

View File

@@ -1 +1 @@
| UncheckedCastInEquals.cs:7:17:7:27 | (...) ... | Missing type-check before casting parameter to 'Equals'. |
| UncheckedCastInEquals.cs:7:17:7:27 | (...) ... | Equals() method does not check argument type. |

View File

@@ -8,4 +8,4 @@ nodes
| RegexInjection.cs:14:19:14:23 | access to local variable regex | semmle.label | access to local variable regex |
subpaths
#select
| RegexInjection.cs:14:19:14:23 | access to local variable regex | RegexInjection.cs:10:24:10:46 | access to property QueryString : NameValueCollection | RegexInjection.cs:14:19:14:23 | access to local variable regex | $@ flows to the construction of a regular expression. | RegexInjection.cs:10:24:10:46 | access to property QueryString | User-provided value |
| RegexInjection.cs:14:19:14:23 | access to local variable regex | RegexInjection.cs:10:24:10:46 | access to property QueryString : NameValueCollection | RegexInjection.cs:14:19:14:23 | access to local variable regex | This regular expression is constructed from a $@. | RegexInjection.cs:10:24:10:46 | access to property QueryString | user-provided value |

View File

@@ -1,3 +1,3 @@
| RedundantToStringCall.cs:7:27:7:38 | call to method ToString | Redundant call to 'ToString'. |
| RedundantToStringCall.cs:10:37:10:48 | call to method ToString | Redundant call to 'ToString'. |
| RedundantToStringCallBad.cs:7:45:7:56 | call to method ToString | Redundant call to 'ToString'. |
| RedundantToStringCall.cs:7:27:7:38 | call to method ToString | Redundant call to 'ToString' on a String object. |
| RedundantToStringCall.cs:10:37:10:48 | call to method ToString | Redundant call to 'ToString' on a String object. |
| RedundantToStringCallBad.cs:7:45:7:56 | call to method ToString | Redundant call to 'ToString' on a String object. |

View File

@@ -21,5 +21,5 @@ import DataFlow::PathGraph
from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink
where cfg.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "This path depends on $@.", source.getNode(),
"a user-provided value"
select sink.getNode(), source, sink, "$@ flows to here and is used in a path.", source.getNode(),
"User-provided value"

View File

@@ -76,5 +76,6 @@ class StackTraceExposureConfig extends TaintTracking::Configuration {
from StackTraceExposureConfig cfg, DataFlow::PathNode source, DataFlow::PathNode sink
where cfg.hasFlowPath(source, sink)
select source.getNode(), source, sink, "This stack trace is exposed to a remote user $@.",
sink.getNode(), "here"
select sink.getNode(), source, sink,
"Stack trace information from $@ may be exposed to an external user here.", source.getNode(),
"here"

View File

@@ -24,5 +24,5 @@ predicate isStringOrByte(DataFlow::PathNode node) {
from Configuration config, DataFlow::PathNode source, DataFlow::PathNode sink
where config.hasFlowPath(source, sink) and isStringOrByte(sink)
select sink.getNode(), source, sink, "$@ flows here and is used in an XPath expression.",
source.getNode(), "A user-provided value"
select sink.getNode(), source, sink, "$@ flows to here and is used in an XPath expression.",
source.getNode(), "User-provided value"

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* The alert message of many queries have been changed to make the message consistent with other languages.

View File

@@ -3,7 +3,7 @@
* @description Not using `pam.AcctMgmt` after `pam.Authenticate` to check the validity of a login can lead to authorization bypass.
* @kind problem
* @problem.severity warning
* @id go/unreachable-statement
* @id go/pam-auth-bypass
* @tags maintainability
* correctness
* external/cwe/cwe-561

View File

@@ -9,6 +9,6 @@ nodes
| test.go:211:35:211:43 | untrusted | semmle.label | untrusted |
subpaths
#select
| test.go:209:18:209:26 | untrusted | test.go:208:15:208:26 | call to Data : map type | test.go:209:18:209:26 | untrusted | This path depends on $@. | test.go:208:15:208:26 | call to Data | a user-provided value |
| test.go:210:10:210:18 | untrusted | test.go:208:15:208:26 | call to Data : map type | test.go:210:10:210:18 | untrusted | This path depends on $@. | test.go:208:15:208:26 | call to Data | a user-provided value |
| test.go:211:35:211:43 | untrusted | test.go:208:15:208:26 | call to Data : map type | test.go:211:35:211:43 | untrusted | This path depends on $@. | test.go:208:15:208:26 | call to Data | a user-provided value |
| test.go:209:18:209:26 | untrusted | test.go:208:15:208:26 | call to Data : map type | test.go:209:18:209:26 | untrusted | $@ flows to here and is used in a path. | test.go:208:15:208:26 | call to Data | User-provided value |
| test.go:210:10:210:18 | untrusted | test.go:208:15:208:26 | call to Data : map type | test.go:210:10:210:18 | untrusted | $@ flows to here and is used in a path. | test.go:208:15:208:26 | call to Data | User-provided value |
| test.go:211:35:211:43 | untrusted | test.go:208:15:208:26 | call to Data : map type | test.go:211:35:211:43 | untrusted | $@ flows to here and is used in a path. | test.go:208:15:208:26 | call to Data | User-provided value |

View File

@@ -20,5 +20,5 @@ nodes
| EndToEnd.go:64:26:64:55 | call to Get | semmle.label | call to Get |
subpaths
#select
| EndToEnd.go:58:18:58:47 | call to Get | EndToEnd.go:58:18:58:25 | selection of Params : pointer type | EndToEnd.go:58:18:58:47 | call to Get | This path depends on $@. | EndToEnd.go:58:18:58:25 | selection of Params | a user-provided value |
| EndToEnd.go:64:26:64:55 | call to Get | EndToEnd.go:64:26:64:33 | selection of Params : pointer type | EndToEnd.go:64:26:64:55 | call to Get | This path depends on $@. | EndToEnd.go:64:26:64:33 | selection of Params | a user-provided value |
| EndToEnd.go:58:18:58:47 | call to Get | EndToEnd.go:58:18:58:25 | selection of Params : pointer type | EndToEnd.go:58:18:58:47 | call to Get | $@ flows to here and is used in a path. | EndToEnd.go:58:18:58:25 | selection of Params | User-provided value |
| EndToEnd.go:64:26:64:55 | call to Get | EndToEnd.go:64:26:64:33 | selection of Params : pointer type | EndToEnd.go:64:26:64:55 | call to Get | $@ flows to here and is used in a path. | EndToEnd.go:64:26:64:33 | selection of Params | User-provided value |

View File

@@ -14,6 +14,6 @@ nodes
| tst.go:17:41:17:56 | selection of Filename | semmle.label | selection of Filename |
subpaths
#select
| TaintedPath.go:16:29:16:40 | tainted_path | TaintedPath.go:13:18:13:22 | selection of URL : pointer type | TaintedPath.go:16:29:16:40 | tainted_path | This path depends on $@. | TaintedPath.go:13:18:13:22 | selection of URL | a user-provided value |
| TaintedPath.go:20:28:20:69 | call to Join | TaintedPath.go:13:18:13:22 | selection of URL : pointer type | TaintedPath.go:20:28:20:69 | call to Join | This path depends on $@. | TaintedPath.go:13:18:13:22 | selection of URL | a user-provided value |
| tst.go:17:41:17:56 | selection of Filename | tst.go:14:2:14:39 | ... := ...[1] : pointer type | tst.go:17:41:17:56 | selection of Filename | This path depends on $@. | tst.go:14:2:14:39 | ... := ...[1] | a user-provided value |
| TaintedPath.go:16:29:16:40 | tainted_path | TaintedPath.go:13:18:13:22 | selection of URL : pointer type | TaintedPath.go:16:29:16:40 | tainted_path | $@ flows to here and is used in a path. | TaintedPath.go:13:18:13:22 | selection of URL | User-provided value |
| TaintedPath.go:20:28:20:69 | call to Join | TaintedPath.go:13:18:13:22 | selection of URL : pointer type | TaintedPath.go:20:28:20:69 | call to Join | $@ flows to here and is used in a path. | TaintedPath.go:13:18:13:22 | selection of URL | User-provided value |
| tst.go:17:41:17:56 | selection of Filename | tst.go:14:2:14:39 | ... := ...[1] : pointer type | tst.go:17:41:17:56 | selection of Filename | $@ flows to here and is used in a path. | tst.go:14:2:14:39 | ... := ...[1] | User-provided value |

View File

@@ -5,4 +5,4 @@ nodes
| test.go:17:10:17:12 | buf | semmle.label | buf |
subpaths
#select
| test.go:14:2:14:4 | definition of buf | test.go:14:2:14:4 | definition of buf : slice type | test.go:17:10:17:12 | buf | This stack trace is exposed to a remote user $@. | test.go:17:10:17:12 | buf | here |
| test.go:17:10:17:12 | buf | test.go:14:2:14:4 | definition of buf : slice type | test.go:17:10:17:12 | buf | Stack trace information from $@ may be exposed to an external user here. | test.go:14:2:14:4 | definition of buf | here |

View File

@@ -85,43 +85,43 @@ nodes
| tst.go:180:27:180:122 | ...+... | semmle.label | ...+... |
subpaths
#select
| XPathInjection.go:16:29:16:91 | ...+... | XPathInjection.go:13:14:13:19 | selection of Form : Values | XPathInjection.go:16:29:16:91 | ...+... | $@ flows here and is used in an XPath expression. | XPathInjection.go:13:14:13:19 | selection of Form | A user-provided value |
| tst.go:35:23:35:85 | ...+... | tst.go:32:14:32:19 | selection of Form : Values | tst.go:35:23:35:85 | ...+... | $@ flows here and is used in an XPath expression. | tst.go:32:14:32:19 | selection of Form | A user-provided value |
| tst.go:38:24:38:86 | ...+... | tst.go:32:14:32:19 | selection of Form : Values | tst.go:38:24:38:86 | ...+... | $@ flows here and is used in an XPath expression. | tst.go:32:14:32:19 | selection of Form | A user-provided value |
| tst.go:41:24:41:82 | ...+... | tst.go:32:14:32:19 | selection of Form : Values | tst.go:41:24:41:82 | ...+... | $@ flows here and is used in an XPath expression. | tst.go:32:14:32:19 | selection of Form | A user-provided value |
| tst.go:49:26:49:84 | ...+... | tst.go:46:14:46:19 | selection of Form : Values | tst.go:49:26:49:84 | ...+... | $@ flows here and is used in an XPath expression. | tst.go:46:14:46:19 | selection of Form | A user-provided value |
| tst.go:52:29:52:87 | ...+... | tst.go:46:14:46:19 | selection of Form : Values | tst.go:52:29:52:87 | ...+... | $@ flows here and is used in an XPath expression. | tst.go:46:14:46:19 | selection of Form | A user-provided value |
| tst.go:55:33:55:91 | ...+... | tst.go:46:14:46:19 | selection of Form : Values | tst.go:55:33:55:91 | ...+... | $@ flows here and is used in an XPath expression. | tst.go:46:14:46:19 | selection of Form | A user-provided value |
| tst.go:58:30:58:88 | ...+... | tst.go:46:14:46:19 | selection of Form : Values | tst.go:58:30:58:88 | ...+... | $@ flows here and is used in an XPath expression. | tst.go:46:14:46:19 | selection of Form | A user-provided value |
| tst.go:66:25:66:83 | ...+... | tst.go:63:14:63:19 | selection of Form : Values | tst.go:66:25:66:83 | ...+... | $@ flows here and is used in an XPath expression. | tst.go:63:14:63:19 | selection of Form | A user-provided value |
| tst.go:69:28:69:86 | ...+... | tst.go:63:14:63:19 | selection of Form : Values | tst.go:69:28:69:86 | ...+... | $@ flows here and is used in an XPath expression. | tst.go:63:14:63:19 | selection of Form | A user-provided value |
| tst.go:72:25:72:83 | ...+... | tst.go:63:14:63:19 | selection of Form : Values | tst.go:72:25:72:83 | ...+... | $@ flows here and is used in an XPath expression. | tst.go:63:14:63:19 | selection of Form | A user-provided value |
| tst.go:75:34:75:92 | ...+... | tst.go:63:14:63:19 | selection of Form : Values | tst.go:75:34:75:92 | ...+... | $@ flows here and is used in an XPath expression. | tst.go:63:14:63:19 | selection of Form | A user-provided value |
| tst.go:78:32:78:90 | ...+... | tst.go:63:14:63:19 | selection of Form : Values | tst.go:78:32:78:90 | ...+... | $@ flows here and is used in an XPath expression. | tst.go:63:14:63:19 | selection of Form | A user-provided value |
| tst.go:81:29:81:87 | ...+... | tst.go:63:14:63:19 | selection of Form : Values | tst.go:81:29:81:87 | ...+... | $@ flows here and is used in an XPath expression. | tst.go:63:14:63:19 | selection of Form | A user-provided value |
| tst.go:84:23:84:85 | ...+... | tst.go:63:14:63:19 | selection of Form : Values | tst.go:84:23:84:85 | ...+... | $@ flows here and is used in an XPath expression. | tst.go:63:14:63:19 | selection of Form | A user-provided value |
| tst.go:87:22:87:84 | ...+... | tst.go:63:14:63:19 | selection of Form : Values | tst.go:87:22:87:84 | ...+... | $@ flows here and is used in an XPath expression. | tst.go:63:14:63:19 | selection of Form | A user-provided value |
| tst.go:95:26:95:84 | ...+... | tst.go:92:14:92:19 | selection of Form : Values | tst.go:95:26:95:84 | ...+... | $@ flows here and is used in an XPath expression. | tst.go:92:14:92:19 | selection of Form | A user-provided value |
| tst.go:98:29:98:87 | ...+... | tst.go:92:14:92:19 | selection of Form : Values | tst.go:98:29:98:87 | ...+... | $@ flows here and is used in an XPath expression. | tst.go:92:14:92:19 | selection of Form | A user-provided value |
| tst.go:101:33:101:91 | ...+... | tst.go:92:14:92:19 | selection of Form : Values | tst.go:101:33:101:91 | ...+... | $@ flows here and is used in an XPath expression. | tst.go:92:14:92:19 | selection of Form | A user-provided value |
| tst.go:104:30:104:88 | ...+... | tst.go:92:14:92:19 | selection of Form : Values | tst.go:104:30:104:88 | ...+... | $@ flows here and is used in an XPath expression. | tst.go:92:14:92:19 | selection of Form | A user-provided value |
| tst.go:112:25:112:87 | ...+... | tst.go:109:14:109:19 | selection of Form : Values | tst.go:112:25:112:87 | ...+... | $@ flows here and is used in an XPath expression. | tst.go:109:14:109:19 | selection of Form | A user-provided value |
| tst.go:115:26:115:88 | ...+... | tst.go:109:14:109:19 | selection of Form : Values | tst.go:115:26:115:88 | ...+... | $@ flows here and is used in an XPath expression. | tst.go:109:14:109:19 | selection of Form | A user-provided value |
| tst.go:124:23:124:126 | ...+... | tst.go:120:14:120:19 | selection of Form : Values | tst.go:124:23:124:126 | ...+... | $@ flows here and is used in an XPath expression. | tst.go:120:14:120:19 | selection of Form | A user-provided value |
| tst.go:124:23:124:126 | ...+... | tst.go:121:14:121:19 | selection of Form : Values | tst.go:124:23:124:126 | ...+... | $@ flows here and is used in an XPath expression. | tst.go:121:14:121:19 | selection of Form | A user-provided value |
| tst.go:127:24:127:127 | ...+... | tst.go:120:14:120:19 | selection of Form : Values | tst.go:127:24:127:127 | ...+... | $@ flows here and is used in an XPath expression. | tst.go:120:14:120:19 | selection of Form | A user-provided value |
| tst.go:127:24:127:127 | ...+... | tst.go:121:14:121:19 | selection of Form : Values | tst.go:127:24:127:127 | ...+... | $@ flows here and is used in an XPath expression. | tst.go:121:14:121:19 | selection of Form | A user-provided value |
| tst.go:130:27:130:122 | ...+... | tst.go:120:14:120:19 | selection of Form : Values | tst.go:130:27:130:122 | ...+... | $@ flows here and is used in an XPath expression. | tst.go:120:14:120:19 | selection of Form | A user-provided value |
| tst.go:130:27:130:122 | ...+... | tst.go:121:14:121:19 | selection of Form : Values | tst.go:130:27:130:122 | ...+... | $@ flows here and is used in an XPath expression. | tst.go:121:14:121:19 | selection of Form | A user-provided value |
| tst.go:141:27:141:89 | ...+... | tst.go:138:14:138:19 | selection of Form : Values | tst.go:141:27:141:89 | ...+... | $@ flows here and is used in an XPath expression. | tst.go:138:14:138:19 | selection of Form | A user-provided value |
| tst.go:144:28:144:90 | ...+... | tst.go:138:14:138:19 | selection of Form : Values | tst.go:144:28:144:90 | ...+... | $@ flows here and is used in an XPath expression. | tst.go:138:14:138:19 | selection of Form | A user-provided value |
| tst.go:153:33:153:136 | ...+... | tst.go:149:14:149:19 | selection of Form : Values | tst.go:153:33:153:136 | ...+... | $@ flows here and is used in an XPath expression. | tst.go:149:14:149:19 | selection of Form | A user-provided value |
| tst.go:153:33:153:136 | ...+... | tst.go:150:14:150:19 | selection of Form : Values | tst.go:153:33:153:136 | ...+... | $@ flows here and is used in an XPath expression. | tst.go:150:14:150:19 | selection of Form | A user-provided value |
| tst.go:156:18:156:121 | ...+... | tst.go:149:14:149:19 | selection of Form : Values | tst.go:156:18:156:121 | ...+... | $@ flows here and is used in an XPath expression. | tst.go:149:14:149:19 | selection of Form | A user-provided value |
| tst.go:156:18:156:121 | ...+... | tst.go:150:14:150:19 | selection of Form : Values | tst.go:156:18:156:121 | ...+... | $@ flows here and is used in an XPath expression. | tst.go:150:14:150:19 | selection of Form | A user-provided value |
| tst.go:162:31:162:126 | ...+... | tst.go:149:14:149:19 | selection of Form : Values | tst.go:162:31:162:126 | ...+... | $@ flows here and is used in an XPath expression. | tst.go:149:14:149:19 | selection of Form | A user-provided value |
| tst.go:162:31:162:126 | ...+... | tst.go:150:14:150:19 | selection of Form : Values | tst.go:162:31:162:126 | ...+... | $@ flows here and is used in an XPath expression. | tst.go:150:14:150:19 | selection of Form | A user-provided value |
| tst.go:171:21:171:116 | ...+... | tst.go:149:14:149:19 | selection of Form : Values | tst.go:171:21:171:116 | ...+... | $@ flows here and is used in an XPath expression. | tst.go:149:14:149:19 | selection of Form | A user-provided value |
| tst.go:171:21:171:116 | ...+... | tst.go:150:14:150:19 | selection of Form : Values | tst.go:171:21:171:116 | ...+... | $@ flows here and is used in an XPath expression. | tst.go:150:14:150:19 | selection of Form | A user-provided value |
| tst.go:180:27:180:122 | ...+... | tst.go:149:14:149:19 | selection of Form : Values | tst.go:180:27:180:122 | ...+... | $@ flows here and is used in an XPath expression. | tst.go:149:14:149:19 | selection of Form | A user-provided value |
| tst.go:180:27:180:122 | ...+... | tst.go:150:14:150:19 | selection of Form : Values | tst.go:180:27:180:122 | ...+... | $@ flows here and is used in an XPath expression. | tst.go:150:14:150:19 | selection of Form | A user-provided value |
| XPathInjection.go:16:29:16:91 | ...+... | XPathInjection.go:13:14:13:19 | selection of Form : Values | XPathInjection.go:16:29:16:91 | ...+... | $@ flows to here and is used in an XPath expression. | XPathInjection.go:13:14:13:19 | selection of Form | User-provided value |
| tst.go:35:23:35:85 | ...+... | tst.go:32:14:32:19 | selection of Form : Values | tst.go:35:23:35:85 | ...+... | $@ flows to here and is used in an XPath expression. | tst.go:32:14:32:19 | selection of Form | User-provided value |
| tst.go:38:24:38:86 | ...+... | tst.go:32:14:32:19 | selection of Form : Values | tst.go:38:24:38:86 | ...+... | $@ flows to here and is used in an XPath expression. | tst.go:32:14:32:19 | selection of Form | User-provided value |
| tst.go:41:24:41:82 | ...+... | tst.go:32:14:32:19 | selection of Form : Values | tst.go:41:24:41:82 | ...+... | $@ flows to here and is used in an XPath expression. | tst.go:32:14:32:19 | selection of Form | User-provided value |
| tst.go:49:26:49:84 | ...+... | tst.go:46:14:46:19 | selection of Form : Values | tst.go:49:26:49:84 | ...+... | $@ flows to here and is used in an XPath expression. | tst.go:46:14:46:19 | selection of Form | User-provided value |
| tst.go:52:29:52:87 | ...+... | tst.go:46:14:46:19 | selection of Form : Values | tst.go:52:29:52:87 | ...+... | $@ flows to here and is used in an XPath expression. | tst.go:46:14:46:19 | selection of Form | User-provided value |
| tst.go:55:33:55:91 | ...+... | tst.go:46:14:46:19 | selection of Form : Values | tst.go:55:33:55:91 | ...+... | $@ flows to here and is used in an XPath expression. | tst.go:46:14:46:19 | selection of Form | User-provided value |
| tst.go:58:30:58:88 | ...+... | tst.go:46:14:46:19 | selection of Form : Values | tst.go:58:30:58:88 | ...+... | $@ flows to here and is used in an XPath expression. | tst.go:46:14:46:19 | selection of Form | User-provided value |
| tst.go:66:25:66:83 | ...+... | tst.go:63:14:63:19 | selection of Form : Values | tst.go:66:25:66:83 | ...+... | $@ flows to here and is used in an XPath expression. | tst.go:63:14:63:19 | selection of Form | User-provided value |
| tst.go:69:28:69:86 | ...+... | tst.go:63:14:63:19 | selection of Form : Values | tst.go:69:28:69:86 | ...+... | $@ flows to here and is used in an XPath expression. | tst.go:63:14:63:19 | selection of Form | User-provided value |
| tst.go:72:25:72:83 | ...+... | tst.go:63:14:63:19 | selection of Form : Values | tst.go:72:25:72:83 | ...+... | $@ flows to here and is used in an XPath expression. | tst.go:63:14:63:19 | selection of Form | User-provided value |
| tst.go:75:34:75:92 | ...+... | tst.go:63:14:63:19 | selection of Form : Values | tst.go:75:34:75:92 | ...+... | $@ flows to here and is used in an XPath expression. | tst.go:63:14:63:19 | selection of Form | User-provided value |
| tst.go:78:32:78:90 | ...+... | tst.go:63:14:63:19 | selection of Form : Values | tst.go:78:32:78:90 | ...+... | $@ flows to here and is used in an XPath expression. | tst.go:63:14:63:19 | selection of Form | User-provided value |
| tst.go:81:29:81:87 | ...+... | tst.go:63:14:63:19 | selection of Form : Values | tst.go:81:29:81:87 | ...+... | $@ flows to here and is used in an XPath expression. | tst.go:63:14:63:19 | selection of Form | User-provided value |
| tst.go:84:23:84:85 | ...+... | tst.go:63:14:63:19 | selection of Form : Values | tst.go:84:23:84:85 | ...+... | $@ flows to here and is used in an XPath expression. | tst.go:63:14:63:19 | selection of Form | User-provided value |
| tst.go:87:22:87:84 | ...+... | tst.go:63:14:63:19 | selection of Form : Values | tst.go:87:22:87:84 | ...+... | $@ flows to here and is used in an XPath expression. | tst.go:63:14:63:19 | selection of Form | User-provided value |
| tst.go:95:26:95:84 | ...+... | tst.go:92:14:92:19 | selection of Form : Values | tst.go:95:26:95:84 | ...+... | $@ flows to here and is used in an XPath expression. | tst.go:92:14:92:19 | selection of Form | User-provided value |
| tst.go:98:29:98:87 | ...+... | tst.go:92:14:92:19 | selection of Form : Values | tst.go:98:29:98:87 | ...+... | $@ flows to here and is used in an XPath expression. | tst.go:92:14:92:19 | selection of Form | User-provided value |
| tst.go:101:33:101:91 | ...+... | tst.go:92:14:92:19 | selection of Form : Values | tst.go:101:33:101:91 | ...+... | $@ flows to here and is used in an XPath expression. | tst.go:92:14:92:19 | selection of Form | User-provided value |
| tst.go:104:30:104:88 | ...+... | tst.go:92:14:92:19 | selection of Form : Values | tst.go:104:30:104:88 | ...+... | $@ flows to here and is used in an XPath expression. | tst.go:92:14:92:19 | selection of Form | User-provided value |
| tst.go:112:25:112:87 | ...+... | tst.go:109:14:109:19 | selection of Form : Values | tst.go:112:25:112:87 | ...+... | $@ flows to here and is used in an XPath expression. | tst.go:109:14:109:19 | selection of Form | User-provided value |
| tst.go:115:26:115:88 | ...+... | tst.go:109:14:109:19 | selection of Form : Values | tst.go:115:26:115:88 | ...+... | $@ flows to here and is used in an XPath expression. | tst.go:109:14:109:19 | selection of Form | User-provided value |
| tst.go:124:23:124:126 | ...+... | tst.go:120:14:120:19 | selection of Form : Values | tst.go:124:23:124:126 | ...+... | $@ flows to here and is used in an XPath expression. | tst.go:120:14:120:19 | selection of Form | User-provided value |
| tst.go:124:23:124:126 | ...+... | tst.go:121:14:121:19 | selection of Form : Values | tst.go:124:23:124:126 | ...+... | $@ flows to here and is used in an XPath expression. | tst.go:121:14:121:19 | selection of Form | User-provided value |
| tst.go:127:24:127:127 | ...+... | tst.go:120:14:120:19 | selection of Form : Values | tst.go:127:24:127:127 | ...+... | $@ flows to here and is used in an XPath expression. | tst.go:120:14:120:19 | selection of Form | User-provided value |
| tst.go:127:24:127:127 | ...+... | tst.go:121:14:121:19 | selection of Form : Values | tst.go:127:24:127:127 | ...+... | $@ flows to here and is used in an XPath expression. | tst.go:121:14:121:19 | selection of Form | User-provided value |
| tst.go:130:27:130:122 | ...+... | tst.go:120:14:120:19 | selection of Form : Values | tst.go:130:27:130:122 | ...+... | $@ flows to here and is used in an XPath expression. | tst.go:120:14:120:19 | selection of Form | User-provided value |
| tst.go:130:27:130:122 | ...+... | tst.go:121:14:121:19 | selection of Form : Values | tst.go:130:27:130:122 | ...+... | $@ flows to here and is used in an XPath expression. | tst.go:121:14:121:19 | selection of Form | User-provided value |
| tst.go:141:27:141:89 | ...+... | tst.go:138:14:138:19 | selection of Form : Values | tst.go:141:27:141:89 | ...+... | $@ flows to here and is used in an XPath expression. | tst.go:138:14:138:19 | selection of Form | User-provided value |
| tst.go:144:28:144:90 | ...+... | tst.go:138:14:138:19 | selection of Form : Values | tst.go:144:28:144:90 | ...+... | $@ flows to here and is used in an XPath expression. | tst.go:138:14:138:19 | selection of Form | User-provided value |
| tst.go:153:33:153:136 | ...+... | tst.go:149:14:149:19 | selection of Form : Values | tst.go:153:33:153:136 | ...+... | $@ flows to here and is used in an XPath expression. | tst.go:149:14:149:19 | selection of Form | User-provided value |
| tst.go:153:33:153:136 | ...+... | tst.go:150:14:150:19 | selection of Form : Values | tst.go:153:33:153:136 | ...+... | $@ flows to here and is used in an XPath expression. | tst.go:150:14:150:19 | selection of Form | User-provided value |
| tst.go:156:18:156:121 | ...+... | tst.go:149:14:149:19 | selection of Form : Values | tst.go:156:18:156:121 | ...+... | $@ flows to here and is used in an XPath expression. | tst.go:149:14:149:19 | selection of Form | User-provided value |
| tst.go:156:18:156:121 | ...+... | tst.go:150:14:150:19 | selection of Form : Values | tst.go:156:18:156:121 | ...+... | $@ flows to here and is used in an XPath expression. | tst.go:150:14:150:19 | selection of Form | User-provided value |
| tst.go:162:31:162:126 | ...+... | tst.go:149:14:149:19 | selection of Form : Values | tst.go:162:31:162:126 | ...+... | $@ flows to here and is used in an XPath expression. | tst.go:149:14:149:19 | selection of Form | User-provided value |
| tst.go:162:31:162:126 | ...+... | tst.go:150:14:150:19 | selection of Form : Values | tst.go:162:31:162:126 | ...+... | $@ flows to here and is used in an XPath expression. | tst.go:150:14:150:19 | selection of Form | User-provided value |
| tst.go:171:21:171:116 | ...+... | tst.go:149:14:149:19 | selection of Form : Values | tst.go:171:21:171:116 | ...+... | $@ flows to here and is used in an XPath expression. | tst.go:149:14:149:19 | selection of Form | User-provided value |
| tst.go:171:21:171:116 | ...+... | tst.go:150:14:150:19 | selection of Form : Values | tst.go:171:21:171:116 | ...+... | $@ flows to here and is used in an XPath expression. | tst.go:150:14:150:19 | selection of Form | User-provided value |
| tst.go:180:27:180:122 | ...+... | tst.go:149:14:149:19 | selection of Form : Values | tst.go:180:27:180:122 | ...+... | $@ flows to here and is used in an XPath expression. | tst.go:149:14:149:19 | selection of Form | User-provided value |
| tst.go:180:27:180:122 | ...+... | tst.go:150:14:150:19 | selection of Form : Values | tst.go:180:27:180:122 | ...+... | $@ flows to here and is used in an XPath expression. | tst.go:150:14:150:19 | selection of Form | User-provided value |

View File

@@ -1584,7 +1584,7 @@ open class KotlinFileExtractor(
}
}
private fun findFunction(cls: IrClass, name: String): IrFunction? = cls.declarations.find { it is IrFunction && it.name.asString() == name } as IrFunction?
private fun findFunction(cls: IrClass, name: String): IrFunction? = cls.declarations.findSubType<IrFunction> { it.name.asString() == name }
val jvmIntrinsicsClass by lazy {
val result = pluginContext.referenceClass(FqName("kotlin.jvm.internal.Intrinsics"))?.owner
@@ -1641,12 +1641,11 @@ open class KotlinFileExtractor(
}
val stringValueOfObjectMethod by lazy {
val result = javaLangString?.declarations?.find {
it is IrFunction &&
val result = javaLangString?.declarations?.findSubType<IrFunction> {
it.name.asString() == "valueOf" &&
it.valueParameters.size == 1 &&
it.valueParameters[0].type == pluginContext.irBuiltIns.anyNType
} as IrFunction?
}
if (result == null) {
logger.error("Couldn't find declaration java.lang.String.valueOf(Object)")
}
@@ -1654,9 +1653,9 @@ open class KotlinFileExtractor(
}
val objectCloneMethod by lazy {
val result = javaLangObject?.declarations?.find {
it is IrFunction && it.name.asString() == "clone"
} as IrFunction?
val result = javaLangObject?.declarations?.findSubType<IrFunction> {
it.name.asString() == "clone"
}
if (result == null) {
logger.error("Couldn't find declaration java.lang.Object.clone(...)")
}
@@ -1670,10 +1669,9 @@ open class KotlinFileExtractor(
}
val kotlinNoWhenBranchMatchedConstructor by lazy {
val result = kotlinNoWhenBranchMatchedExn?.declarations?.find {
it is IrConstructor &&
val result = kotlinNoWhenBranchMatchedExn?.declarations?.findSubType<IrConstructor> {
it.valueParameters.isEmpty()
} as IrConstructor?
}
if (result == null) {
logger.error("Couldn't find no-arg constructor for kotlin.NoWhenBranchMatchedException")
}
@@ -1798,13 +1796,13 @@ open class KotlinFileExtractor(
return
}
val func = ((c.getTypeArgument(0) as? IrSimpleType)?.classifier?.owner as? IrClass)?.declarations?.find { it is IrFunction && it.name.asString() == fnName }
val func = ((c.getTypeArgument(0) as? IrSimpleType)?.classifier?.owner as? IrClass)?.declarations?.findSubType<IrFunction> { it.name.asString() == fnName }
if (func == null) {
logger.errorElement("Couldn't find function $fnName on enum type", c)
return
}
extractMethodAccess(func as IrFunction, false)
extractMethodAccess(func, false)
}
fun binopReceiver(id: Label<out DbExpr>, receiver: IrExpression?, receiverDescription: String) {
@@ -2273,10 +2271,10 @@ open class KotlinFileExtractor(
logger.errorElement("Argument to dataClassArrayMemberToString not a class", c)
return
}
val realCallee = javaUtilArrays?.declarations?.find { decl ->
decl is IrFunction && decl.name.asString() == "toString" && decl.valueParameters.size == 1 &&
val realCallee = javaUtilArrays?.declarations?.findSubType<IrFunction> { decl ->
decl.name.asString() == "toString" && decl.valueParameters.size == 1 &&
decl.valueParameters[0].type.classOrNull?.let { it == realArrayClass } == true
} as IrFunction?
}
if (realCallee == null) {
logger.errorElement("Couldn't find a java.lang.Arrays.toString method matching class ${realArrayClass.owner.name}", c)
} else {
@@ -2300,10 +2298,10 @@ open class KotlinFileExtractor(
logger.errorElement("Argument to dataClassArrayMemberHashCode not a class", c)
return
}
val realCallee = javaUtilArrays?.declarations?.find { decl ->
decl is IrFunction && decl.name.asString() == "hashCode" && decl.valueParameters.size == 1 &&
val realCallee = javaUtilArrays?.declarations?.findSubType<IrFunction> { decl ->
decl.name.asString() == "hashCode" && decl.valueParameters.size == 1 &&
decl.valueParameters[0].type.classOrNull?.let { it == realArrayClass } == true
} as IrFunction?
}
if (realCallee == null) {
logger.errorElement("Couldn't find a java.lang.Arrays.hashCode method matching class ${realArrayClass.owner.name}", c)
} else {
@@ -4452,7 +4450,7 @@ open class KotlinFileExtractor(
return
}
val invokeMethod = functionType.classOrNull?.owner?.declarations?.filterIsInstance<IrFunction>()?.find { it.name.asString() == OperatorNameConventions.INVOKE.asString()}
val invokeMethod = functionType.classOrNull?.owner?.declarations?.findSubType<IrFunction> { it.name.asString() == OperatorNameConventions.INVOKE.asString()}
if (invokeMethod == null) {
logger.errorElement("Couldn't find `invoke` method on functional interface.", e)
return
@@ -4463,7 +4461,7 @@ open class KotlinFileExtractor(
logger.errorElement("Expected to find SAM conversion to IrClass. Found '${typeOwner.javaClass}' instead. Can't implement SAM interface.", e)
return
}
val samMember = typeOwner.declarations.filterIsInstance<IrFunction>().find { it is IrOverridableMember && it.modality == Modality.ABSTRACT }
val samMember = typeOwner.declarations.findSubType<IrFunction> { it is IrOverridableMember && it.modality == Modality.ABSTRACT }
if (samMember == null) {
logger.errorElement("Couldn't find SAM member in type '${typeOwner.kotlinFqName.asString()}'. Can't implement SAM interface.", e)
return
@@ -4652,7 +4650,7 @@ open class KotlinFileExtractor(
val superCallId = tw.getFreshIdLabel<DbSuperconstructorinvocationstmt>()
tw.writeStmts_superconstructorinvocationstmt(superCallId, constructorBlockId, 0, ids.constructor)
val baseConstructor = baseClass.owner.declarations.find { it is IrFunction && it.symbol is IrConstructorSymbol }
val baseConstructor = baseClass.owner.declarations.findSubType<IrFunction> { it.symbol is IrConstructorSymbol }
val baseConstructorId = useFunction<DbConstructor>(baseConstructor as IrFunction)
tw.writeHasLocation(superCallId, locId)

View File

@@ -326,11 +326,11 @@ open class KotlinUsesExtractor(
if (replacementClass === parentClass)
return f
return globalExtensionState.syntheticToRealFunctionMap.getOrPut(f) {
val result = replacementClass.declarations.find { replacementDecl ->
val result = replacementClass.declarations.findSubType<IrSimpleFunction> { replacementDecl ->
replacementDecl is IrSimpleFunction && replacementDecl.name == f.name && replacementDecl.valueParameters.size == f.valueParameters.size && replacementDecl.valueParameters.zip(f.valueParameters).all {
erase(it.first.type) == erase(it.second.type)
}
} as IrFunction?
}
if (result == null) {
logger.warn("Failed to replace synthetic class function ${f.name}")
} else {
@@ -351,9 +351,9 @@ open class KotlinUsesExtractor(
if (replacementClass === parentClass)
return f
return globalExtensionState.syntheticToRealFieldMap.getOrPut(f) {
val result = replacementClass.declarations.find { replacementDecl ->
replacementDecl is IrField && replacementDecl.name == f.name
} as IrField?
val result = replacementClass.declarations.findSubType<IrField> { replacementDecl ->
replacementDecl.name == f.name
}
if (result == null) {
logger.warn("Failed to replace synthetic class field ${f.name}")
} else {
@@ -1097,7 +1097,7 @@ open class KotlinUsesExtractor(
return f.returnType
}
val otherKeySet = parentClass.declarations.filterIsInstance<IrFunction>().find { it.name.asString() == "keySet" && it.valueParameters.size == 1 }
val otherKeySet = parentClass.declarations.findSubType<IrFunction> { it.name.asString() == "keySet" && it.valueParameters.size == 1 }
?: return f.returnType
return otherKeySet.returnType.codeQlWithHasQuestionMark(false)
@@ -1177,8 +1177,7 @@ open class KotlinUsesExtractor(
getJavaEquivalentClass(parentClass)?.let { javaClass ->
if (javaClass != parentClass)
// Look for an exact type match...
javaClass.declarations.find { decl ->
decl is IrFunction &&
javaClass.declarations.findSubType<IrFunction> { decl ->
decl.name == f.name &&
decl.valueParameters.size == f.valueParameters.size &&
// Note matching by classifier not the whole type so that generic arguments are allowed to differ,
@@ -1194,7 +1193,7 @@ open class KotlinUsesExtractor(
} ?:
// Or check property accessors:
if (f.isAccessor) {
val prop = javaClass.declarations.filterIsInstance<IrProperty>().find { decl ->
val prop = javaClass.declarations.findSubType<IrProperty> { decl ->
decl.name == (f.propertyIfAccessor as IrProperty).name
}
if (prop?.getter?.name == f.name)

View File

@@ -0,0 +1,15 @@
package com.github.codeql
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
/**
* This behaves the same as Iterable<IrDeclaration>.find, but requires
* that the value found is of the subtype S, and it casts
* the result for you appropriately.
*/
inline fun <reified S: IrDeclaration> Iterable<IrDeclaration>.findSubType(
predicate: (S) -> Boolean
): S? {
return this.find { it is S && predicate(it) } as S?
}

View File

@@ -93,8 +93,6 @@ class RegExpRoot extends RegExpTerm {
* Holds if this root term is relevant to the ReDoS analysis.
*/
predicate isRelevant() {
// there is at least one repetition
getRoot(any(InfiniteRepetitionQuantifier q)) = this and
// is actually used as a RegExp
this.isUsedAsRegExp() and
// not excluded for library specific reasons
@@ -877,6 +875,101 @@ predicate isStartState(State state) {
*/
signature predicate isCandidateSig(State state, string pump);
/**
* Holds if `state` is a candidate for ReDoS.
*/
signature predicate isCandidateSig(State state);
/**
* Predicates for constructing a prefix string that leads to a given state.
*/
module PrefixConstruction<isCandidateSig/1 isCandidate> {
/**
* Holds if `state` is the textually last start state for the regular expression.
*/
private predicate lastStartState(State state) {
exists(RegExpRoot root |
state =
max(State s, Location l |
s = stateInRelevantRegexp() and
isStartState(s) and
getRoot(s.getRepr()) = root and
l = s.getRepr().getLocation()
|
s
order by
l.getStartLine(), l.getStartColumn(), s.getRepr().toString(), l.getEndColumn(),
l.getEndLine()
)
)
}
/**
* Holds if there exists any transition (Epsilon() or other) from `a` to `b`.
*/
private predicate existsTransition(State a, State b) { delta(a, _, b) }
/**
* Gets the minimum number of transitions it takes to reach `state` from the `start` state.
*/
int prefixLength(State start, State state) =
shortestDistances(lastStartState/1, existsTransition/2)(start, state, result)
/**
* Gets the minimum number of transitions it takes to reach `state` from the start state.
*/
private int lengthFromStart(State state) { result = prefixLength(_, state) }
/**
* Gets a string for which the regular expression will reach `state`.
*
* Has at most one result for any given `state`.
* This predicate will not always have a result even if there is a ReDoS issue in
* the regular expression.
*/
string prefix(State state) {
lastStartState(state) and
result = ""
or
// the search stops past the last redos candidate state.
lengthFromStart(state) <= max(lengthFromStart(any(State s | isCandidate(s)))) and
exists(State prev |
// select a unique predecessor (by an arbitrary measure)
prev =
min(State s, Location loc |
lengthFromStart(s) = lengthFromStart(state) - 1 and
loc = s.getRepr().getLocation() and
delta(s, _, state)
|
s
order by
loc.getStartLine(), loc.getStartColumn(), loc.getEndLine(), loc.getEndColumn(),
s.getRepr().toString()
)
|
// greedy search for the shortest prefix
result = prefix(prev) and delta(prev, Epsilon(), state)
or
not delta(prev, Epsilon(), state) and
result = prefix(prev) + getCanonicalEdgeChar(prev, state)
)
}
/**
* Gets a canonical char for which there exists a transition from `prev` to `next` in the NFA.
*/
private string getCanonicalEdgeChar(State prev, State next) {
result =
min(string c | delta(prev, any(InputSymbol symbol | c = intersect(Any(), symbol)), next))
}
/** Gets a state within a regular expression that contains a candidate state. */
pragma[noinline]
State stateInRelevantRegexp() {
exists(State s | isCandidate(s) | getRoot(s.getRepr()) = getRoot(result.getRepr()))
}
}
/**
* A module for pruning candidate ReDoS states.
* The candidates are specified by the `isCandidate` signature predicate.
@@ -910,95 +1003,9 @@ module ReDoSPruning<isCandidateSig/2 isCandidate> {
/** Gets a state that can reach the `accept-any` state using only epsilon steps. */
private State acceptsAnySuffix() { epsilonSucc*(result) = AcceptAnySuffix(_) }
/**
* Predicates for constructing a prefix string that leads to a given state.
*/
private module PrefixConstruction {
/**
* Holds if `state` is the textually last start state for the regular expression.
*/
private predicate lastStartState(State state) {
exists(RegExpRoot root |
state =
max(State s, Location l |
s = stateInPumpableRegexp() and
isStartState(s) and
getRoot(s.getRepr()) = root and
l = s.getRepr().getLocation()
|
s
order by
l.getStartLine(), l.getStartColumn(), s.getRepr().toString(), l.getEndColumn(),
l.getEndLine()
)
)
}
predicate isCandidateState(State s) { isReDoSCandidate(s, _) }
/**
* Holds if there exists any transition (Epsilon() or other) from `a` to `b`.
*/
private predicate existsTransition(State a, State b) { delta(a, _, b) }
/**
* Gets the minimum number of transitions it takes to reach `state` from the `start` state.
*/
int prefixLength(State start, State state) =
shortestDistances(lastStartState/1, existsTransition/2)(start, state, result)
/**
* Gets the minimum number of transitions it takes to reach `state` from the start state.
*/
private int lengthFromStart(State state) { result = prefixLength(_, state) }
/**
* Gets a string for which the regular expression will reach `state`.
*
* Has at most one result for any given `state`.
* This predicate will not always have a result even if there is a ReDoS issue in
* the regular expression.
*/
string prefix(State state) {
lastStartState(state) and
result = ""
or
// the search stops past the last redos candidate state.
lengthFromStart(state) <= max(lengthFromStart(any(State s | isReDoSCandidate(s, _)))) and
exists(State prev |
// select a unique predecessor (by an arbitrary measure)
prev =
min(State s, Location loc |
lengthFromStart(s) = lengthFromStart(state) - 1 and
loc = s.getRepr().getLocation() and
delta(s, _, state)
|
s
order by
loc.getStartLine(), loc.getStartColumn(), loc.getEndLine(), loc.getEndColumn(),
s.getRepr().toString()
)
|
// greedy search for the shortest prefix
result = prefix(prev) and delta(prev, Epsilon(), state)
or
not delta(prev, Epsilon(), state) and
result = prefix(prev) + getCanonicalEdgeChar(prev, state)
)
}
/**
* Gets a canonical char for which there exists a transition from `prev` to `next` in the NFA.
*/
private string getCanonicalEdgeChar(State prev, State next) {
result =
min(string c | delta(prev, any(InputSymbol symbol | c = intersect(Any(), symbol)), next))
}
/** Gets a state within a regular expression that has a pumpable state. */
pragma[noinline]
State stateInPumpableRegexp() {
exists(State s | isReDoSCandidate(s, _) | getRoot(s.getRepr()) = getRoot(result.getRepr()))
}
}
import PrefixConstruction<isCandidateState/1> as Prefix
/**
* Predicates for testing the presence of a rejecting suffix.
@@ -1018,8 +1025,6 @@ module ReDoSPruning<isCandidateSig/2 isCandidate> {
* using epsilon transitions. But any attempt at repeating `w` will end in a state that accepts all suffixes.
*/
private module SuffixConstruction {
import PrefixConstruction
/**
* Holds if all states reachable from `fork` by repeating `w`
* are likely rejectable by appending some suffix.
@@ -1036,7 +1041,7 @@ module ReDoSPruning<isCandidateSig/2 isCandidate> {
*/
pragma[noinline]
private predicate isLikelyRejectable(State s) {
s = stateInPumpableRegexp() and
s = Prefix::stateInRelevantRegexp() and
(
// exists a reject edge with some char.
hasRejectEdge(s)
@@ -1052,7 +1057,7 @@ module ReDoSPruning<isCandidateSig/2 isCandidate> {
* Holds if `s` is not an accept state, and there is no epsilon transition to an accept state.
*/
predicate isRejectState(State s) {
s = stateInPumpableRegexp() and not epsilonSucc*(s) = Accept(_)
s = Prefix::stateInRelevantRegexp() and not epsilonSucc*(s) = Accept(_)
}
/**
@@ -1060,7 +1065,7 @@ module ReDoSPruning<isCandidateSig/2 isCandidate> {
*/
pragma[noopt]
predicate hasEdgeToLikelyRejectable(State s) {
s = stateInPumpableRegexp() and
s = Prefix::stateInRelevantRegexp() and
// all edges (at least one) with some char leads to another state that is rejectable.
// the `next` states might not share a common suffix, which can cause FPs.
exists(string char | char = hasEdgeToLikelyRejectableHelper(s) |
@@ -1076,7 +1081,7 @@ module ReDoSPruning<isCandidateSig/2 isCandidate> {
*/
pragma[noinline]
private string hasEdgeToLikelyRejectableHelper(State s) {
s = stateInPumpableRegexp() and
s = Prefix::stateInRelevantRegexp() and
not hasRejectEdge(s) and
not isRejectState(s) and
deltaClosedChar(s, result, _)
@@ -1088,8 +1093,8 @@ module ReDoSPruning<isCandidateSig/2 isCandidate> {
* `prev` to `next` that the character symbol `char`.
*/
predicate deltaClosedChar(State prev, string char, State next) {
prev = stateInPumpableRegexp() and
next = stateInPumpableRegexp() and
prev = Prefix::stateInRelevantRegexp() and
next = Prefix::stateInRelevantRegexp() and
deltaClosed(prev, getAnInputSymbolMatchingRelevant(char), next)
}
@@ -1099,18 +1104,28 @@ module ReDoSPruning<isCandidateSig/2 isCandidate> {
result = getAnInputSymbolMatching(char)
}
pragma[noinline]
RegExpRoot relevantRoot() {
exists(RegExpTerm term, State s |
s.getRepr() = term and isCandidateState(s) and result = term.getRootTerm()
)
}
/**
* Gets a char used for finding possible suffixes inside `root`.
*/
pragma[noinline]
private string relevant(RegExpRoot root) {
exists(ascii(result)) and exists(root)
or
exists(InputSymbol s | belongsTo(s, root) | result = intersect(s, _))
or
// The characters from `hasSimpleRejectEdge`. Only `\n` is really needed (as `\n` is not in the `ascii` relation).
// The three chars must be kept in sync with `hasSimpleRejectEdge`.
result = ["|", "\n", "Z"] and exists(root)
root = relevantRoot() and
(
exists(ascii(result)) and exists(root)
or
exists(InputSymbol s | belongsTo(s, root) | result = intersect(s, _))
or
// The characters from `hasSimpleRejectEdge`. Only `\n` is really needed (as `\n` is not in the `ascii` relation).
// The three chars must be kept in sync with `hasSimpleRejectEdge`.
result = ["|", "\n", "Z"] and exists(root)
)
}
/**
@@ -1208,12 +1223,12 @@ module ReDoSPruning<isCandidateSig/2 isCandidate> {
predicate hasReDoSResult(RegExpTerm t, string pump, State s, string prefixMsg) {
isReDoSAttackable(t, pump, s) and
(
prefixMsg = "starting with '" + escape(PrefixConstruction::prefix(s)) + "' and " and
not PrefixConstruction::prefix(s) = ""
prefixMsg = "starting with '" + escape(Prefix::prefix(s)) + "' and " and
not Prefix::prefix(s) = ""
or
PrefixConstruction::prefix(s) = "" and prefixMsg = ""
Prefix::prefix(s) = "" and prefixMsg = ""
or
not exists(PrefixConstruction::prefix(s)) and prefixMsg = ""
not exists(Prefix::prefix(s)) and prefixMsg = ""
)
}

View File

@@ -14,4 +14,4 @@ import semmle.code.java.deadcode.DeadCode
from RootdefCallable c
where not c.whitelisted()
select c.unusedParameter() as p, "The parameter " + p + " is unused."
select c.unusedParameter() as p, "The parameter '" + p + "' is never used."

View File

@@ -16,4 +16,4 @@ where
e.isStrict() and
e.getGreaterOperand() instanceof BitwiseExpr and
e.getLesserOperand().(IntegerLiteral).getIntValue() = 0
select e, "Sign check of a bitwise operation."
select e, "Potentially unsafe sign check of a bitwise operation."

View File

@@ -77,4 +77,4 @@ where
// Exclude `equals` methods that implement reference-equality.
not m instanceof ReferenceEquals and
not m instanceof UnimplementedEquals
select m, "equals() method does not seem to check argument type."
select m, "equals() method does not check argument type."

View File

@@ -19,4 +19,5 @@ import DataFlow::PathGraph
from QueryInjectionSink query, DataFlow::PathNode source, DataFlow::PathNode sink
where queryTaintedBy(query, source, sink)
select query, source, sink, "Query might include code from $@.", source.getNode(), "this user input"
select query, source, sink, "This SQL query depends on $@.", source.getNode(),
"a user-provided value"

View File

@@ -51,5 +51,6 @@ class XxeConfig extends TaintTracking::Configuration {
from DataFlow::PathNode source, DataFlow::PathNode sink, XxeConfig conf
where conf.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "Unsafe parsing of XML file from $@.", source.getNode(),
"user input"
select sink.getNode(), source, sink,
"A $@ is parsed as XML without guarding against external entity expansion.", source.getNode(),
"user-provided value"

View File

@@ -17,4 +17,4 @@ from JavadocText c
where
c.getText().matches("%TODO%") or
c.getText().matches("%FIXME%")
select c, "TODO/FIXME comment."
select c, "TODO comments should be addressed."

View File

@@ -21,4 +21,4 @@ where
read(v) and
not def.(AssignExpr).getSource() instanceof NullLiteral and
(def instanceof Assignment or def.(UnaryAssignExpr).getParent() instanceof ExprStmt)
select def, "This assignment to " + v.getName() + " is useless: the value is never read."
select def, "This definition of " + v.getName() + " is never used."

View File

@@ -86,5 +86,6 @@ where
) and
// Exclude special VM classes.
not isVMObserver(f.getDeclaringType())
select f, "Field " + f.getName() + " never assigned non-null value, yet it is read at $@.", fr,
fr.getFile().getStem() + ".java:" + fr.getLocation().getStartLine()
select f,
"The field '" + f.getName() + "' is never explicitly assigned a value, yet it is read $@.", fr,
"here"

View File

@@ -41,4 +41,4 @@ where
f.getType() instanceof Array and
f.fromSource() and
forall(AssignExpr a | a.getDest() = f.getAnAccess() | nonEmptyArrayLiteralOrNull(a.getSource()))
select f, "The array constant " + f.getName() + " is vulnerable to mutation."
select f, "The array constant '" + f.getName() + "' is vulnerable to mutation."

View File

@@ -71,4 +71,4 @@ where
not neededImport(i) and
not i instanceof ImportStaticOnDemand and
not i instanceof ImportStaticTypeMember
select i, "The statement '" + i + "' is unnecessary."
select i, "Import of '" + i + "' is not used."

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* The alert message of many queries have been changed to make the message consistent with other languages.

View File

@@ -48,4 +48,4 @@ where
)
or
hasEmbeddedPassword(nameAttr.getValue().trim()) // Attribute value matches password pattern
select nameAttr, "Plaintext password in configuration file."
select nameAttr, "Avoid plaintext passwords in configuration files."

View File

@@ -85,5 +85,5 @@ class RegexInjectionConfiguration extends TaintTracking::Configuration {
from DataFlow::PathNode source, DataFlow::PathNode sink, RegexInjectionConfiguration c
where c.hasFlowPath(source, sink)
select sink.getNode(), source, sink, "$@ is user controlled.", source.getNode(),
"This regular expression pattern"
select sink.getNode(), source, sink, "This regular expression is constructed from a $@.",
source.getNode(), "user-provided value"

View File

@@ -1,3 +1,3 @@
| applicationContext.xml:9:3:9:48 | name=password | Plaintext password in configuration file. |
| context.xml:4:2:8:50 | password=1234 | Plaintext password in configuration file. |
| custom-config.xml:3:2:3:137 | value=server=myoracle.example.com;port=1521;database=testdb;username=root;password=test1234 | Plaintext password in configuration file. |
| applicationContext.xml:9:3:9:48 | name=password | Avoid plaintext passwords in configuration files. |
| context.xml:4:2:8:50 | password=1234 | Avoid plaintext passwords in configuration files. |
| custom-config.xml:3:2:3:137 | value=server=myoracle.example.com;port=1521;database=testdb;username=root;password=test1234 | Avoid plaintext passwords in configuration files. |

View File

@@ -56,18 +56,18 @@ nodes
subpaths
| RegexInjection.java:68:36:68:42 | pattern : String | RegexInjection.java:71:14:71:23 | str : String | RegexInjection.java:72:12:72:14 | str : String | RegexInjection.java:68:32:68:43 | foo(...) : String |
#select
| RegexInjection.java:16:26:16:47 | ... + ... | RegexInjection.java:13:22:13:52 | getParameter(...) : String | RegexInjection.java:16:26:16:47 | ... + ... | $@ is user controlled. | RegexInjection.java:13:22:13:52 | getParameter(...) | This regular expression pattern |
| RegexInjection.java:23:24:23:30 | pattern | RegexInjection.java:20:22:20:52 | getParameter(...) : String | RegexInjection.java:23:24:23:30 | pattern | $@ is user controlled. | RegexInjection.java:20:22:20:52 | getParameter(...) | This regular expression pattern |
| RegexInjection.java:30:31:30:37 | pattern | RegexInjection.java:27:22:27:52 | getParameter(...) : String | RegexInjection.java:30:31:30:37 | pattern | $@ is user controlled. | RegexInjection.java:27:22:27:52 | getParameter(...) | This regular expression pattern |
| RegexInjection.java:37:29:37:35 | pattern | RegexInjection.java:34:22:34:52 | getParameter(...) : String | RegexInjection.java:37:29:37:35 | pattern | $@ is user controlled. | RegexInjection.java:34:22:34:52 | getParameter(...) | This regular expression pattern |
| RegexInjection.java:44:34:44:40 | pattern | RegexInjection.java:41:22:41:52 | getParameter(...) : String | RegexInjection.java:44:34:44:40 | pattern | $@ is user controlled. | RegexInjection.java:41:22:41:52 | getParameter(...) | This regular expression pattern |
| RegexInjection.java:54:28:54:34 | pattern | RegexInjection.java:51:22:51:52 | getParameter(...) : String | RegexInjection.java:54:28:54:34 | pattern | $@ is user controlled. | RegexInjection.java:51:22:51:52 | getParameter(...) | This regular expression pattern |
| RegexInjection.java:61:28:61:34 | pattern | RegexInjection.java:58:22:58:52 | getParameter(...) : String | RegexInjection.java:61:28:61:34 | pattern | $@ is user controlled. | RegexInjection.java:58:22:58:52 | getParameter(...) | This regular expression pattern |
| RegexInjection.java:68:26:68:52 | ... + ... | RegexInjection.java:65:22:65:52 | getParameter(...) : String | RegexInjection.java:68:26:68:52 | ... + ... | $@ is user controlled. | RegexInjection.java:65:22:65:52 | getParameter(...) | This regular expression pattern |
| RegexInjection.java:90:26:90:47 | ... + ... | RegexInjection.java:84:22:84:52 | getParameter(...) : String | RegexInjection.java:90:26:90:47 | ... + ... | $@ is user controlled. | RegexInjection.java:84:22:84:52 | getParameter(...) | This regular expression pattern |
| RegexInjection.java:103:40:103:46 | pattern | RegexInjection.java:100:22:100:52 | getParameter(...) : String | RegexInjection.java:103:40:103:46 | pattern | $@ is user controlled. | RegexInjection.java:100:22:100:52 | getParameter(...) | This regular expression pattern |
| RegexInjection.java:110:42:110:48 | pattern | RegexInjection.java:107:22:107:52 | getParameter(...) : String | RegexInjection.java:110:42:110:48 | pattern | $@ is user controlled. | RegexInjection.java:107:22:107:52 | getParameter(...) | This regular expression pattern |
| RegexInjection.java:117:44:117:50 | pattern | RegexInjection.java:114:22:114:52 | getParameter(...) : String | RegexInjection.java:117:44:117:50 | pattern | $@ is user controlled. | RegexInjection.java:114:22:114:52 | getParameter(...) | This regular expression pattern |
| RegexInjection.java:124:41:124:47 | pattern | RegexInjection.java:121:22:121:52 | getParameter(...) : String | RegexInjection.java:124:41:124:47 | pattern | $@ is user controlled. | RegexInjection.java:121:22:121:52 | getParameter(...) | This regular expression pattern |
| RegexInjection.java:131:43:131:49 | pattern | RegexInjection.java:128:22:128:52 | getParameter(...) : String | RegexInjection.java:131:43:131:49 | pattern | $@ is user controlled. | RegexInjection.java:128:22:128:52 | getParameter(...) | This regular expression pattern |
| RegexInjection.java:146:45:146:51 | pattern | RegexInjection.java:143:22:143:52 | getParameter(...) : String | RegexInjection.java:146:45:146:51 | pattern | $@ is user controlled. | RegexInjection.java:143:22:143:52 | getParameter(...) | This regular expression pattern |
| RegexInjection.java:16:26:16:47 | ... + ... | RegexInjection.java:13:22:13:52 | getParameter(...) : String | RegexInjection.java:16:26:16:47 | ... + ... | This regular expression is constructed from a $@. | RegexInjection.java:13:22:13:52 | getParameter(...) | user-provided value |
| RegexInjection.java:23:24:23:30 | pattern | RegexInjection.java:20:22:20:52 | getParameter(...) : String | RegexInjection.java:23:24:23:30 | pattern | This regular expression is constructed from a $@. | RegexInjection.java:20:22:20:52 | getParameter(...) | user-provided value |
| RegexInjection.java:30:31:30:37 | pattern | RegexInjection.java:27:22:27:52 | getParameter(...) : String | RegexInjection.java:30:31:30:37 | pattern | This regular expression is constructed from a $@. | RegexInjection.java:27:22:27:52 | getParameter(...) | user-provided value |
| RegexInjection.java:37:29:37:35 | pattern | RegexInjection.java:34:22:34:52 | getParameter(...) : String | RegexInjection.java:37:29:37:35 | pattern | This regular expression is constructed from a $@. | RegexInjection.java:34:22:34:52 | getParameter(...) | user-provided value |
| RegexInjection.java:44:34:44:40 | pattern | RegexInjection.java:41:22:41:52 | getParameter(...) : String | RegexInjection.java:44:34:44:40 | pattern | This regular expression is constructed from a $@. | RegexInjection.java:41:22:41:52 | getParameter(...) | user-provided value |
| RegexInjection.java:54:28:54:34 | pattern | RegexInjection.java:51:22:51:52 | getParameter(...) : String | RegexInjection.java:54:28:54:34 | pattern | This regular expression is constructed from a $@. | RegexInjection.java:51:22:51:52 | getParameter(...) | user-provided value |
| RegexInjection.java:61:28:61:34 | pattern | RegexInjection.java:58:22:58:52 | getParameter(...) : String | RegexInjection.java:61:28:61:34 | pattern | This regular expression is constructed from a $@. | RegexInjection.java:58:22:58:52 | getParameter(...) | user-provided value |
| RegexInjection.java:68:26:68:52 | ... + ... | RegexInjection.java:65:22:65:52 | getParameter(...) : String | RegexInjection.java:68:26:68:52 | ... + ... | This regular expression is constructed from a $@. | RegexInjection.java:65:22:65:52 | getParameter(...) | user-provided value |
| RegexInjection.java:90:26:90:47 | ... + ... | RegexInjection.java:84:22:84:52 | getParameter(...) : String | RegexInjection.java:90:26:90:47 | ... + ... | This regular expression is constructed from a $@. | RegexInjection.java:84:22:84:52 | getParameter(...) | user-provided value |
| RegexInjection.java:103:40:103:46 | pattern | RegexInjection.java:100:22:100:52 | getParameter(...) : String | RegexInjection.java:103:40:103:46 | pattern | This regular expression is constructed from a $@. | RegexInjection.java:100:22:100:52 | getParameter(...) | user-provided value |
| RegexInjection.java:110:42:110:48 | pattern | RegexInjection.java:107:22:107:52 | getParameter(...) : String | RegexInjection.java:110:42:110:48 | pattern | This regular expression is constructed from a $@. | RegexInjection.java:107:22:107:52 | getParameter(...) | user-provided value |
| RegexInjection.java:117:44:117:50 | pattern | RegexInjection.java:114:22:114:52 | getParameter(...) : String | RegexInjection.java:117:44:117:50 | pattern | This regular expression is constructed from a $@. | RegexInjection.java:114:22:114:52 | getParameter(...) | user-provided value |
| RegexInjection.java:124:41:124:47 | pattern | RegexInjection.java:121:22:121:52 | getParameter(...) : String | RegexInjection.java:124:41:124:47 | pattern | This regular expression is constructed from a $@. | RegexInjection.java:121:22:121:52 | getParameter(...) | user-provided value |
| RegexInjection.java:131:43:131:49 | pattern | RegexInjection.java:128:22:128:52 | getParameter(...) : String | RegexInjection.java:131:43:131:49 | pattern | This regular expression is constructed from a $@. | RegexInjection.java:128:22:128:52 | getParameter(...) | user-provided value |
| RegexInjection.java:146:45:146:51 | pattern | RegexInjection.java:143:22:143:52 | getParameter(...) : String | RegexInjection.java:146:45:146:51 | pattern | This regular expression is constructed from a $@. | RegexInjection.java:143:22:143:52 | getParameter(...) | user-provided value |

View File

@@ -1 +1 @@
| Bad.java:13:17:13:22 | equals | equals() method does not seem to check argument type. |
| Bad.java:13:17:13:22 | equals | equals() method does not check argument type. |

View File

@@ -1,5 +1,5 @@
| StaticArray.java:3:31:3:33 | bad | The array constant bad is vulnerable to mutation. |
| StaticArray.java:14:35:14:54 | bad_multidimensional | The array constant bad_multidimensional is vulnerable to mutation. |
| StaticArray.java:15:35:15:67 | bad_multidimensional_partial_init | The array constant bad_multidimensional_partial_init is vulnerable to mutation. |
| StaticArray.java:17:31:17:47 | bad_separate_init | The array constant bad_separate_init is vulnerable to mutation. |
| StaticArray.java:26:33:26:44 | bad_nonempty | The array constant bad_nonempty is vulnerable to mutation. |
| StaticArray.java:3:31:3:33 | bad | The array constant 'bad' is vulnerable to mutation. |
| StaticArray.java:14:35:14:54 | bad_multidimensional | The array constant 'bad_multidimensional' is vulnerable to mutation. |
| StaticArray.java:15:35:15:67 | bad_multidimensional_partial_init | The array constant 'bad_multidimensional_partial_init' is vulnerable to mutation. |
| StaticArray.java:17:31:17:47 | bad_separate_init | The array constant 'bad_separate_init' is vulnerable to mutation. |
| StaticArray.java:26:33:26:44 | bad_nonempty | The array constant 'bad_nonempty' is vulnerable to mutation. |

View File

@@ -1,2 +1,2 @@
| A.java:29:13:29:21 | ...=... | This assignment to x is useless: the value is never read. |
| UnreadLocal/ImplicitReads.java:38:5:38:9 | ...=... | This assignment to c is useless: the value is never read. |
| A.java:29:13:29:21 | ...=... | This definition of x is never used. |
| UnreadLocal/ImplicitReads.java:38:5:38:9 | ...=... | This definition of c is never used. |

View File

@@ -1 +1 @@
| Test.java:6:11:6:15 | x | The parameter x is unused. |
| Test.java:6:11:6:15 | x | The parameter 'x' is never used. |

View File

@@ -251,101 +251,101 @@ nodes
| XmlInputFactoryTests.java:56:34:56:54 | getInputStream(...) | semmle.label | getInputStream(...) |
subpaths
#select
| DocumentBuilderTests.java:14:19:14:39 | getInputStream(...) | DocumentBuilderTests.java:14:19:14:39 | getInputStream(...) | DocumentBuilderTests.java:14:19:14:39 | getInputStream(...) | Unsafe parsing of XML file from $@. | DocumentBuilderTests.java:14:19:14:39 | getInputStream(...) | user input |
| DocumentBuilderTests.java:28:19:28:39 | getInputStream(...) | DocumentBuilderTests.java:28:19:28:39 | getInputStream(...) | DocumentBuilderTests.java:28:19:28:39 | getInputStream(...) | Unsafe parsing of XML file from $@. | DocumentBuilderTests.java:28:19:28:39 | getInputStream(...) | user input |
| DocumentBuilderTests.java:35:19:35:39 | getInputStream(...) | DocumentBuilderTests.java:35:19:35:39 | getInputStream(...) | DocumentBuilderTests.java:35:19:35:39 | getInputStream(...) | Unsafe parsing of XML file from $@. | DocumentBuilderTests.java:35:19:35:39 | getInputStream(...) | user input |
| DocumentBuilderTests.java:42:19:42:39 | getInputStream(...) | DocumentBuilderTests.java:42:19:42:39 | getInputStream(...) | DocumentBuilderTests.java:42:19:42:39 | getInputStream(...) | Unsafe parsing of XML file from $@. | DocumentBuilderTests.java:42:19:42:39 | getInputStream(...) | user input |
| DocumentBuilderTests.java:49:19:49:39 | getInputStream(...) | DocumentBuilderTests.java:49:19:49:39 | getInputStream(...) | DocumentBuilderTests.java:49:19:49:39 | getInputStream(...) | Unsafe parsing of XML file from $@. | DocumentBuilderTests.java:49:19:49:39 | getInputStream(...) | user input |
| DocumentBuilderTests.java:64:19:64:39 | getInputStream(...) | DocumentBuilderTests.java:64:19:64:39 | getInputStream(...) | DocumentBuilderTests.java:64:19:64:39 | getInputStream(...) | Unsafe parsing of XML file from $@. | DocumentBuilderTests.java:64:19:64:39 | getInputStream(...) | user input |
| DocumentBuilderTests.java:71:19:71:39 | getInputStream(...) | DocumentBuilderTests.java:71:19:71:39 | getInputStream(...) | DocumentBuilderTests.java:71:19:71:39 | getInputStream(...) | Unsafe parsing of XML file from $@. | DocumentBuilderTests.java:71:19:71:39 | getInputStream(...) | user input |
| DocumentBuilderTests.java:79:19:79:39 | getInputStream(...) | DocumentBuilderTests.java:79:19:79:39 | getInputStream(...) | DocumentBuilderTests.java:79:19:79:39 | getInputStream(...) | Unsafe parsing of XML file from $@. | DocumentBuilderTests.java:79:19:79:39 | getInputStream(...) | user input |
| DocumentBuilderTests.java:87:19:87:39 | getInputStream(...) | DocumentBuilderTests.java:87:19:87:39 | getInputStream(...) | DocumentBuilderTests.java:87:19:87:39 | getInputStream(...) | Unsafe parsing of XML file from $@. | DocumentBuilderTests.java:87:19:87:39 | getInputStream(...) | user input |
| DocumentBuilderTests.java:94:16:94:38 | getInputSource(...) | DocumentBuilderTests.java:93:51:93:71 | getInputStream(...) : InputStream | DocumentBuilderTests.java:94:16:94:38 | getInputSource(...) | Unsafe parsing of XML file from $@. | DocumentBuilderTests.java:93:51:93:71 | getInputStream(...) | user input |
| DocumentBuilderTests.java:101:16:101:52 | sourceToInputSource(...) | DocumentBuilderTests.java:100:41:100:61 | getInputStream(...) : InputStream | DocumentBuilderTests.java:101:16:101:52 | sourceToInputSource(...) | Unsafe parsing of XML file from $@. | DocumentBuilderTests.java:100:41:100:61 | getInputStream(...) | user input |
| DocumentBuilderTests.java:102:16:102:38 | getInputStream(...) | DocumentBuilderTests.java:100:41:100:61 | getInputStream(...) : InputStream | DocumentBuilderTests.java:102:16:102:38 | getInputStream(...) | Unsafe parsing of XML file from $@. | DocumentBuilderTests.java:100:41:100:61 | getInputStream(...) | user input |
| SAXBuilderTests.java:8:19:8:39 | getInputStream(...) | SAXBuilderTests.java:8:19:8:39 | getInputStream(...) | SAXBuilderTests.java:8:19:8:39 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXBuilderTests.java:8:19:8:39 | getInputStream(...) | user input |
| SAXBuilderTests.java:20:19:20:39 | getInputStream(...) | SAXBuilderTests.java:20:19:20:39 | getInputStream(...) | SAXBuilderTests.java:20:19:20:39 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXBuilderTests.java:20:19:20:39 | getInputStream(...) | user input |
| SAXParserTests.java:13:18:13:38 | getInputStream(...) | SAXParserTests.java:13:18:13:38 | getInputStream(...) | SAXParserTests.java:13:18:13:38 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXParserTests.java:13:18:13:38 | getInputStream(...) | user input |
| SAXParserTests.java:30:18:30:38 | getInputStream(...) | SAXParserTests.java:30:18:30:38 | getInputStream(...) | SAXParserTests.java:30:18:30:38 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXParserTests.java:30:18:30:38 | getInputStream(...) | user input |
| SAXParserTests.java:38:18:38:38 | getInputStream(...) | SAXParserTests.java:38:18:38:38 | getInputStream(...) | SAXParserTests.java:38:18:38:38 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXParserTests.java:38:18:38:38 | getInputStream(...) | user input |
| SAXParserTests.java:46:18:46:38 | getInputStream(...) | SAXParserTests.java:46:18:46:38 | getInputStream(...) | SAXParserTests.java:46:18:46:38 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXParserTests.java:46:18:46:38 | getInputStream(...) | user input |
| SAXParserTests.java:55:18:55:38 | getInputStream(...) | SAXParserTests.java:55:18:55:38 | getInputStream(...) | SAXParserTests.java:55:18:55:38 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXParserTests.java:55:18:55:38 | getInputStream(...) | user input |
| SAXParserTests.java:64:18:64:38 | getInputStream(...) | SAXParserTests.java:64:18:64:38 | getInputStream(...) | SAXParserTests.java:64:18:64:38 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXParserTests.java:64:18:64:38 | getInputStream(...) | user input |
| SAXParserTests.java:73:18:73:38 | getInputStream(...) | SAXParserTests.java:73:18:73:38 | getInputStream(...) | SAXParserTests.java:73:18:73:38 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXParserTests.java:73:18:73:38 | getInputStream(...) | user input |
| SAXReaderTests.java:8:17:8:37 | getInputStream(...) | SAXReaderTests.java:8:17:8:37 | getInputStream(...) | SAXReaderTests.java:8:17:8:37 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXReaderTests.java:8:17:8:37 | getInputStream(...) | user input |
| SAXReaderTests.java:23:17:23:37 | getInputStream(...) | SAXReaderTests.java:23:17:23:37 | getInputStream(...) | SAXReaderTests.java:23:17:23:37 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXReaderTests.java:23:17:23:37 | getInputStream(...) | user input |
| SAXReaderTests.java:30:17:30:37 | getInputStream(...) | SAXReaderTests.java:30:17:30:37 | getInputStream(...) | SAXReaderTests.java:30:17:30:37 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXReaderTests.java:30:17:30:37 | getInputStream(...) | user input |
| SAXReaderTests.java:37:17:37:37 | getInputStream(...) | SAXReaderTests.java:37:17:37:37 | getInputStream(...) | SAXReaderTests.java:37:17:37:37 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXReaderTests.java:37:17:37:37 | getInputStream(...) | user input |
| SAXReaderTests.java:45:17:45:37 | getInputStream(...) | SAXReaderTests.java:45:17:45:37 | getInputStream(...) | SAXReaderTests.java:45:17:45:37 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXReaderTests.java:45:17:45:37 | getInputStream(...) | user input |
| SAXReaderTests.java:53:17:53:37 | getInputStream(...) | SAXReaderTests.java:53:17:53:37 | getInputStream(...) | SAXReaderTests.java:53:17:53:37 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXReaderTests.java:53:17:53:37 | getInputStream(...) | user input |
| SAXReaderTests.java:61:17:61:37 | getInputStream(...) | SAXReaderTests.java:61:17:61:37 | getInputStream(...) | SAXReaderTests.java:61:17:61:37 | getInputStream(...) | Unsafe parsing of XML file from $@. | SAXReaderTests.java:61:17:61:37 | getInputStream(...) | user input |
| SAXSourceTests.java:20:18:20:23 | source | SAXSourceTests.java:17:62:17:82 | getInputStream(...) : InputStream | SAXSourceTests.java:20:18:20:23 | source | Unsafe parsing of XML file from $@. | SAXSourceTests.java:17:62:17:82 | getInputStream(...) | user input |
| SchemaTests.java:12:39:12:77 | new StreamSource(...) | SchemaTests.java:12:56:12:76 | getInputStream(...) : InputStream | SchemaTests.java:12:39:12:77 | new StreamSource(...) | Unsafe parsing of XML file from $@. | SchemaTests.java:12:56:12:76 | getInputStream(...) | user input |
| SchemaTests.java:25:39:25:77 | new StreamSource(...) | SchemaTests.java:25:56:25:76 | getInputStream(...) : InputStream | SchemaTests.java:25:39:25:77 | new StreamSource(...) | Unsafe parsing of XML file from $@. | SchemaTests.java:25:56:25:76 | getInputStream(...) | user input |
| SchemaTests.java:31:39:31:77 | new StreamSource(...) | SchemaTests.java:31:56:31:76 | getInputStream(...) : InputStream | SchemaTests.java:31:39:31:77 | new StreamSource(...) | Unsafe parsing of XML file from $@. | SchemaTests.java:31:56:31:76 | getInputStream(...) | user input |
| SchemaTests.java:38:39:38:77 | new StreamSource(...) | SchemaTests.java:38:56:38:76 | getInputStream(...) : InputStream | SchemaTests.java:38:39:38:77 | new StreamSource(...) | Unsafe parsing of XML file from $@. | SchemaTests.java:38:56:38:76 | getInputStream(...) | user input |
| SchemaTests.java:45:39:45:77 | new StreamSource(...) | SchemaTests.java:45:56:45:76 | getInputStream(...) : InputStream | SchemaTests.java:45:39:45:77 | new StreamSource(...) | Unsafe parsing of XML file from $@. | SchemaTests.java:45:56:45:76 | getInputStream(...) | user input |
| SimpleXMLTests.java:14:41:14:61 | getInputStream(...) | SimpleXMLTests.java:14:41:14:61 | getInputStream(...) | SimpleXMLTests.java:14:41:14:61 | getInputStream(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:14:41:14:61 | getInputStream(...) | user input |
| SimpleXMLTests.java:19:41:19:61 | getInputStream(...) | SimpleXMLTests.java:19:41:19:61 | getInputStream(...) | SimpleXMLTests.java:19:41:19:61 | getInputStream(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:19:41:19:61 | getInputStream(...) | user input |
| SimpleXMLTests.java:24:41:24:84 | new InputStreamReader(...) | SimpleXMLTests.java:24:63:24:83 | getInputStream(...) : InputStream | SimpleXMLTests.java:24:41:24:84 | new InputStreamReader(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:24:63:24:83 | getInputStream(...) | user input |
| SimpleXMLTests.java:31:41:31:53 | new String(...) | SimpleXMLTests.java:30:5:30:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:31:41:31:53 | new String(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:30:5:30:25 | getInputStream(...) | user input |
| SimpleXMLTests.java:38:41:38:53 | new String(...) | SimpleXMLTests.java:37:5:37:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:38:41:38:53 | new String(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:37:5:37:25 | getInputStream(...) | user input |
| SimpleXMLTests.java:43:41:43:84 | new InputStreamReader(...) | SimpleXMLTests.java:43:63:43:83 | getInputStream(...) : InputStream | SimpleXMLTests.java:43:41:43:84 | new InputStreamReader(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:43:63:43:83 | getInputStream(...) | user input |
| SimpleXMLTests.java:48:37:48:57 | getInputStream(...) | SimpleXMLTests.java:48:37:48:57 | getInputStream(...) | SimpleXMLTests.java:48:37:48:57 | getInputStream(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:48:37:48:57 | getInputStream(...) | user input |
| SimpleXMLTests.java:53:37:53:57 | getInputStream(...) | SimpleXMLTests.java:53:37:53:57 | getInputStream(...) | SimpleXMLTests.java:53:37:53:57 | getInputStream(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:53:37:53:57 | getInputStream(...) | user input |
| SimpleXMLTests.java:58:26:58:46 | getInputStream(...) | SimpleXMLTests.java:58:26:58:46 | getInputStream(...) | SimpleXMLTests.java:58:26:58:46 | getInputStream(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:58:26:58:46 | getInputStream(...) | user input |
| SimpleXMLTests.java:63:26:63:46 | getInputStream(...) | SimpleXMLTests.java:63:26:63:46 | getInputStream(...) | SimpleXMLTests.java:63:26:63:46 | getInputStream(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:63:26:63:46 | getInputStream(...) | user input |
| SimpleXMLTests.java:68:37:68:80 | new InputStreamReader(...) | SimpleXMLTests.java:68:59:68:79 | getInputStream(...) : InputStream | SimpleXMLTests.java:68:37:68:80 | new InputStreamReader(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:68:59:68:79 | getInputStream(...) | user input |
| SimpleXMLTests.java:73:37:73:80 | new InputStreamReader(...) | SimpleXMLTests.java:73:59:73:79 | getInputStream(...) : InputStream | SimpleXMLTests.java:73:37:73:80 | new InputStreamReader(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:73:59:73:79 | getInputStream(...) | user input |
| SimpleXMLTests.java:78:26:78:69 | new InputStreamReader(...) | SimpleXMLTests.java:78:48:78:68 | getInputStream(...) : InputStream | SimpleXMLTests.java:78:26:78:69 | new InputStreamReader(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:78:48:78:68 | getInputStream(...) | user input |
| SimpleXMLTests.java:83:26:83:69 | new InputStreamReader(...) | SimpleXMLTests.java:83:48:83:68 | getInputStream(...) : InputStream | SimpleXMLTests.java:83:26:83:69 | new InputStreamReader(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:83:48:83:68 | getInputStream(...) | user input |
| SimpleXMLTests.java:90:37:90:49 | new String(...) | SimpleXMLTests.java:89:5:89:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:90:37:90:49 | new String(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:89:5:89:25 | getInputStream(...) | user input |
| SimpleXMLTests.java:97:37:97:49 | new String(...) | SimpleXMLTests.java:96:5:96:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:97:37:97:49 | new String(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:96:5:96:25 | getInputStream(...) | user input |
| SimpleXMLTests.java:104:26:104:38 | new String(...) | SimpleXMLTests.java:103:5:103:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:104:26:104:38 | new String(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:103:5:103:25 | getInputStream(...) | user input |
| SimpleXMLTests.java:111:26:111:38 | new String(...) | SimpleXMLTests.java:110:5:110:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:111:26:111:38 | new String(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:110:5:110:25 | getInputStream(...) | user input |
| SimpleXMLTests.java:115:22:115:42 | getInputStream(...) | SimpleXMLTests.java:115:22:115:42 | getInputStream(...) | SimpleXMLTests.java:115:22:115:42 | getInputStream(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:115:22:115:42 | getInputStream(...) | user input |
| SimpleXMLTests.java:119:22:119:65 | new InputStreamReader(...) | SimpleXMLTests.java:119:44:119:64 | getInputStream(...) : InputStream | SimpleXMLTests.java:119:22:119:65 | new InputStreamReader(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:119:44:119:64 | getInputStream(...) | user input |
| SimpleXMLTests.java:124:22:124:42 | getInputStream(...) | SimpleXMLTests.java:124:22:124:42 | getInputStream(...) | SimpleXMLTests.java:124:22:124:42 | getInputStream(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:124:22:124:42 | getInputStream(...) | user input |
| SimpleXMLTests.java:129:22:129:65 | new InputStreamReader(...) | SimpleXMLTests.java:129:44:129:64 | getInputStream(...) : InputStream | SimpleXMLTests.java:129:22:129:65 | new InputStreamReader(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:129:44:129:64 | getInputStream(...) | user input |
| SimpleXMLTests.java:134:22:134:42 | getInputStream(...) | SimpleXMLTests.java:134:22:134:42 | getInputStream(...) | SimpleXMLTests.java:134:22:134:42 | getInputStream(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:134:22:134:42 | getInputStream(...) | user input |
| SimpleXMLTests.java:139:22:139:65 | new InputStreamReader(...) | SimpleXMLTests.java:139:44:139:64 | getInputStream(...) : InputStream | SimpleXMLTests.java:139:22:139:65 | new InputStreamReader(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:139:44:139:64 | getInputStream(...) | user input |
| SimpleXMLTests.java:146:22:146:34 | new String(...) | SimpleXMLTests.java:145:5:145:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:146:22:146:34 | new String(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:145:5:145:25 | getInputStream(...) | user input |
| SimpleXMLTests.java:153:22:153:34 | new String(...) | SimpleXMLTests.java:152:5:152:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:153:22:153:34 | new String(...) | Unsafe parsing of XML file from $@. | SimpleXMLTests.java:152:5:152:25 | getInputStream(...) | user input |
| TransformerTests.java:20:27:20:65 | new StreamSource(...) | TransformerTests.java:20:44:20:64 | getInputStream(...) : InputStream | TransformerTests.java:20:27:20:65 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:20:44:20:64 | getInputStream(...) | user input |
| TransformerTests.java:21:23:21:61 | new StreamSource(...) | TransformerTests.java:21:40:21:60 | getInputStream(...) : InputStream | TransformerTests.java:21:23:21:61 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:21:40:21:60 | getInputStream(...) | user input |
| TransformerTests.java:71:27:71:65 | new StreamSource(...) | TransformerTests.java:71:44:71:64 | getInputStream(...) : InputStream | TransformerTests.java:71:27:71:65 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:71:44:71:64 | getInputStream(...) | user input |
| TransformerTests.java:72:23:72:61 | new StreamSource(...) | TransformerTests.java:72:40:72:60 | getInputStream(...) : InputStream | TransformerTests.java:72:23:72:61 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:72:40:72:60 | getInputStream(...) | user input |
| TransformerTests.java:79:27:79:65 | new StreamSource(...) | TransformerTests.java:79:44:79:64 | getInputStream(...) : InputStream | TransformerTests.java:79:27:79:65 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:79:44:79:64 | getInputStream(...) | user input |
| TransformerTests.java:80:23:80:61 | new StreamSource(...) | TransformerTests.java:80:40:80:60 | getInputStream(...) : InputStream | TransformerTests.java:80:23:80:61 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:80:40:80:60 | getInputStream(...) | user input |
| TransformerTests.java:88:27:88:65 | new StreamSource(...) | TransformerTests.java:88:44:88:64 | getInputStream(...) : InputStream | TransformerTests.java:88:27:88:65 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:88:44:88:64 | getInputStream(...) | user input |
| TransformerTests.java:89:23:89:61 | new StreamSource(...) | TransformerTests.java:89:40:89:60 | getInputStream(...) : InputStream | TransformerTests.java:89:23:89:61 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:89:40:89:60 | getInputStream(...) | user input |
| TransformerTests.java:97:27:97:65 | new StreamSource(...) | TransformerTests.java:97:44:97:64 | getInputStream(...) : InputStream | TransformerTests.java:97:27:97:65 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:97:44:97:64 | getInputStream(...) | user input |
| TransformerTests.java:98:23:98:61 | new StreamSource(...) | TransformerTests.java:98:40:98:60 | getInputStream(...) : InputStream | TransformerTests.java:98:23:98:61 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:98:40:98:60 | getInputStream(...) | user input |
| TransformerTests.java:103:21:103:59 | new StreamSource(...) | TransformerTests.java:103:38:103:58 | getInputStream(...) : InputStream | TransformerTests.java:103:21:103:59 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:103:38:103:58 | getInputStream(...) | user input |
| TransformerTests.java:116:21:116:59 | new StreamSource(...) | TransformerTests.java:116:38:116:58 | getInputStream(...) : InputStream | TransformerTests.java:116:21:116:59 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:116:38:116:58 | getInputStream(...) | user input |
| TransformerTests.java:122:21:122:59 | new StreamSource(...) | TransformerTests.java:122:38:122:58 | getInputStream(...) : InputStream | TransformerTests.java:122:21:122:59 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:122:38:122:58 | getInputStream(...) | user input |
| TransformerTests.java:129:21:129:59 | new StreamSource(...) | TransformerTests.java:129:38:129:58 | getInputStream(...) : InputStream | TransformerTests.java:129:21:129:59 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:129:38:129:58 | getInputStream(...) | user input |
| TransformerTests.java:136:21:136:59 | new StreamSource(...) | TransformerTests.java:136:38:136:58 | getInputStream(...) : InputStream | TransformerTests.java:136:21:136:59 | new StreamSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:136:38:136:58 | getInputStream(...) | user input |
| TransformerTests.java:141:18:141:70 | new SAXSource(...) | TransformerTests.java:141:48:141:68 | getInputStream(...) : InputStream | TransformerTests.java:141:18:141:70 | new SAXSource(...) | Unsafe parsing of XML file from $@. | TransformerTests.java:141:48:141:68 | getInputStream(...) | user input |
| UnmarshallerTests.java:28:18:28:38 | getInputStream(...) | UnmarshallerTests.java:28:18:28:38 | getInputStream(...) | UnmarshallerTests.java:28:18:28:38 | getInputStream(...) | Unsafe parsing of XML file from $@. | UnmarshallerTests.java:28:18:28:38 | getInputStream(...) | user input |
| XMLReaderTests.java:16:18:16:55 | new InputSource(...) | XMLReaderTests.java:16:34:16:54 | getInputStream(...) : InputStream | XMLReaderTests.java:16:18:16:55 | new InputSource(...) | Unsafe parsing of XML file from $@. | XMLReaderTests.java:16:34:16:54 | getInputStream(...) | user input |
| XMLReaderTests.java:56:18:56:55 | new InputSource(...) | XMLReaderTests.java:56:34:56:54 | getInputStream(...) : InputStream | XMLReaderTests.java:56:18:56:55 | new InputSource(...) | Unsafe parsing of XML file from $@. | XMLReaderTests.java:56:34:56:54 | getInputStream(...) | user input |
| XMLReaderTests.java:63:18:63:55 | new InputSource(...) | XMLReaderTests.java:63:34:63:54 | getInputStream(...) : InputStream | XMLReaderTests.java:63:18:63:55 | new InputSource(...) | Unsafe parsing of XML file from $@. | XMLReaderTests.java:63:34:63:54 | getInputStream(...) | user input |
| XMLReaderTests.java:70:18:70:55 | new InputSource(...) | XMLReaderTests.java:70:34:70:54 | getInputStream(...) : InputStream | XMLReaderTests.java:70:18:70:55 | new InputSource(...) | Unsafe parsing of XML file from $@. | XMLReaderTests.java:70:34:70:54 | getInputStream(...) | user input |
| XMLReaderTests.java:78:18:78:55 | new InputSource(...) | XMLReaderTests.java:78:34:78:54 | getInputStream(...) : InputStream | XMLReaderTests.java:78:18:78:55 | new InputSource(...) | Unsafe parsing of XML file from $@. | XMLReaderTests.java:78:34:78:54 | getInputStream(...) | user input |
| XMLReaderTests.java:86:18:86:55 | new InputSource(...) | XMLReaderTests.java:86:34:86:54 | getInputStream(...) : InputStream | XMLReaderTests.java:86:18:86:55 | new InputSource(...) | Unsafe parsing of XML file from $@. | XMLReaderTests.java:86:34:86:54 | getInputStream(...) | user input |
| XMLReaderTests.java:94:18:94:55 | new InputSource(...) | XMLReaderTests.java:94:34:94:54 | getInputStream(...) : InputStream | XMLReaderTests.java:94:18:94:55 | new InputSource(...) | Unsafe parsing of XML file from $@. | XMLReaderTests.java:94:34:94:54 | getInputStream(...) | user input |
| XMLReaderTests.java:100:18:100:55 | new InputSource(...) | XMLReaderTests.java:100:34:100:54 | getInputStream(...) : InputStream | XMLReaderTests.java:100:18:100:55 | new InputSource(...) | Unsafe parsing of XML file from $@. | XMLReaderTests.java:100:34:100:54 | getInputStream(...) | user input |
| XPathExpressionTests.java:27:21:27:58 | new InputSource(...) | XPathExpressionTests.java:27:37:27:57 | getInputStream(...) : InputStream | XPathExpressionTests.java:27:21:27:58 | new InputSource(...) | Unsafe parsing of XML file from $@. | XPathExpressionTests.java:27:37:27:57 | getInputStream(...) | user input |
| XmlInputFactoryTests.java:9:35:9:55 | getInputStream(...) | XmlInputFactoryTests.java:9:35:9:55 | getInputStream(...) | XmlInputFactoryTests.java:9:35:9:55 | getInputStream(...) | Unsafe parsing of XML file from $@. | XmlInputFactoryTests.java:9:35:9:55 | getInputStream(...) | user input |
| XmlInputFactoryTests.java:10:34:10:54 | getInputStream(...) | XmlInputFactoryTests.java:10:34:10:54 | getInputStream(...) | XmlInputFactoryTests.java:10:34:10:54 | getInputStream(...) | Unsafe parsing of XML file from $@. | XmlInputFactoryTests.java:10:34:10:54 | getInputStream(...) | user input |
| XmlInputFactoryTests.java:24:35:24:55 | getInputStream(...) | XmlInputFactoryTests.java:24:35:24:55 | getInputStream(...) | XmlInputFactoryTests.java:24:35:24:55 | getInputStream(...) | Unsafe parsing of XML file from $@. | XmlInputFactoryTests.java:24:35:24:55 | getInputStream(...) | user input |
| XmlInputFactoryTests.java:25:34:25:54 | getInputStream(...) | XmlInputFactoryTests.java:25:34:25:54 | getInputStream(...) | XmlInputFactoryTests.java:25:34:25:54 | getInputStream(...) | Unsafe parsing of XML file from $@. | XmlInputFactoryTests.java:25:34:25:54 | getInputStream(...) | user input |
| XmlInputFactoryTests.java:31:35:31:55 | getInputStream(...) | XmlInputFactoryTests.java:31:35:31:55 | getInputStream(...) | XmlInputFactoryTests.java:31:35:31:55 | getInputStream(...) | Unsafe parsing of XML file from $@. | XmlInputFactoryTests.java:31:35:31:55 | getInputStream(...) | user input |
| XmlInputFactoryTests.java:32:34:32:54 | getInputStream(...) | XmlInputFactoryTests.java:32:34:32:54 | getInputStream(...) | XmlInputFactoryTests.java:32:34:32:54 | getInputStream(...) | Unsafe parsing of XML file from $@. | XmlInputFactoryTests.java:32:34:32:54 | getInputStream(...) | user input |
| XmlInputFactoryTests.java:39:35:39:55 | getInputStream(...) | XmlInputFactoryTests.java:39:35:39:55 | getInputStream(...) | XmlInputFactoryTests.java:39:35:39:55 | getInputStream(...) | Unsafe parsing of XML file from $@. | XmlInputFactoryTests.java:39:35:39:55 | getInputStream(...) | user input |
| XmlInputFactoryTests.java:40:34:40:54 | getInputStream(...) | XmlInputFactoryTests.java:40:34:40:54 | getInputStream(...) | XmlInputFactoryTests.java:40:34:40:54 | getInputStream(...) | Unsafe parsing of XML file from $@. | XmlInputFactoryTests.java:40:34:40:54 | getInputStream(...) | user input |
| XmlInputFactoryTests.java:47:35:47:55 | getInputStream(...) | XmlInputFactoryTests.java:47:35:47:55 | getInputStream(...) | XmlInputFactoryTests.java:47:35:47:55 | getInputStream(...) | Unsafe parsing of XML file from $@. | XmlInputFactoryTests.java:47:35:47:55 | getInputStream(...) | user input |
| XmlInputFactoryTests.java:48:34:48:54 | getInputStream(...) | XmlInputFactoryTests.java:48:34:48:54 | getInputStream(...) | XmlInputFactoryTests.java:48:34:48:54 | getInputStream(...) | Unsafe parsing of XML file from $@. | XmlInputFactoryTests.java:48:34:48:54 | getInputStream(...) | user input |
| XmlInputFactoryTests.java:55:35:55:55 | getInputStream(...) | XmlInputFactoryTests.java:55:35:55:55 | getInputStream(...) | XmlInputFactoryTests.java:55:35:55:55 | getInputStream(...) | Unsafe parsing of XML file from $@. | XmlInputFactoryTests.java:55:35:55:55 | getInputStream(...) | user input |
| XmlInputFactoryTests.java:56:34:56:54 | getInputStream(...) | XmlInputFactoryTests.java:56:34:56:54 | getInputStream(...) | XmlInputFactoryTests.java:56:34:56:54 | getInputStream(...) | Unsafe parsing of XML file from $@. | XmlInputFactoryTests.java:56:34:56:54 | getInputStream(...) | user input |
| DocumentBuilderTests.java:14:19:14:39 | getInputStream(...) | DocumentBuilderTests.java:14:19:14:39 | getInputStream(...) | DocumentBuilderTests.java:14:19:14:39 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | DocumentBuilderTests.java:14:19:14:39 | getInputStream(...) | user-provided value |
| DocumentBuilderTests.java:28:19:28:39 | getInputStream(...) | DocumentBuilderTests.java:28:19:28:39 | getInputStream(...) | DocumentBuilderTests.java:28:19:28:39 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | DocumentBuilderTests.java:28:19:28:39 | getInputStream(...) | user-provided value |
| DocumentBuilderTests.java:35:19:35:39 | getInputStream(...) | DocumentBuilderTests.java:35:19:35:39 | getInputStream(...) | DocumentBuilderTests.java:35:19:35:39 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | DocumentBuilderTests.java:35:19:35:39 | getInputStream(...) | user-provided value |
| DocumentBuilderTests.java:42:19:42:39 | getInputStream(...) | DocumentBuilderTests.java:42:19:42:39 | getInputStream(...) | DocumentBuilderTests.java:42:19:42:39 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | DocumentBuilderTests.java:42:19:42:39 | getInputStream(...) | user-provided value |
| DocumentBuilderTests.java:49:19:49:39 | getInputStream(...) | DocumentBuilderTests.java:49:19:49:39 | getInputStream(...) | DocumentBuilderTests.java:49:19:49:39 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | DocumentBuilderTests.java:49:19:49:39 | getInputStream(...) | user-provided value |
| DocumentBuilderTests.java:64:19:64:39 | getInputStream(...) | DocumentBuilderTests.java:64:19:64:39 | getInputStream(...) | DocumentBuilderTests.java:64:19:64:39 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | DocumentBuilderTests.java:64:19:64:39 | getInputStream(...) | user-provided value |
| DocumentBuilderTests.java:71:19:71:39 | getInputStream(...) | DocumentBuilderTests.java:71:19:71:39 | getInputStream(...) | DocumentBuilderTests.java:71:19:71:39 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | DocumentBuilderTests.java:71:19:71:39 | getInputStream(...) | user-provided value |
| DocumentBuilderTests.java:79:19:79:39 | getInputStream(...) | DocumentBuilderTests.java:79:19:79:39 | getInputStream(...) | DocumentBuilderTests.java:79:19:79:39 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | DocumentBuilderTests.java:79:19:79:39 | getInputStream(...) | user-provided value |
| DocumentBuilderTests.java:87:19:87:39 | getInputStream(...) | DocumentBuilderTests.java:87:19:87:39 | getInputStream(...) | DocumentBuilderTests.java:87:19:87:39 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | DocumentBuilderTests.java:87:19:87:39 | getInputStream(...) | user-provided value |
| DocumentBuilderTests.java:94:16:94:38 | getInputSource(...) | DocumentBuilderTests.java:93:51:93:71 | getInputStream(...) : InputStream | DocumentBuilderTests.java:94:16:94:38 | getInputSource(...) | A $@ is parsed as XML without guarding against external entity expansion. | DocumentBuilderTests.java:93:51:93:71 | getInputStream(...) | user-provided value |
| DocumentBuilderTests.java:101:16:101:52 | sourceToInputSource(...) | DocumentBuilderTests.java:100:41:100:61 | getInputStream(...) : InputStream | DocumentBuilderTests.java:101:16:101:52 | sourceToInputSource(...) | A $@ is parsed as XML without guarding against external entity expansion. | DocumentBuilderTests.java:100:41:100:61 | getInputStream(...) | user-provided value |
| DocumentBuilderTests.java:102:16:102:38 | getInputStream(...) | DocumentBuilderTests.java:100:41:100:61 | getInputStream(...) : InputStream | DocumentBuilderTests.java:102:16:102:38 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | DocumentBuilderTests.java:100:41:100:61 | getInputStream(...) | user-provided value |
| SAXBuilderTests.java:8:19:8:39 | getInputStream(...) | SAXBuilderTests.java:8:19:8:39 | getInputStream(...) | SAXBuilderTests.java:8:19:8:39 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | SAXBuilderTests.java:8:19:8:39 | getInputStream(...) | user-provided value |
| SAXBuilderTests.java:20:19:20:39 | getInputStream(...) | SAXBuilderTests.java:20:19:20:39 | getInputStream(...) | SAXBuilderTests.java:20:19:20:39 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | SAXBuilderTests.java:20:19:20:39 | getInputStream(...) | user-provided value |
| SAXParserTests.java:13:18:13:38 | getInputStream(...) | SAXParserTests.java:13:18:13:38 | getInputStream(...) | SAXParserTests.java:13:18:13:38 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | SAXParserTests.java:13:18:13:38 | getInputStream(...) | user-provided value |
| SAXParserTests.java:30:18:30:38 | getInputStream(...) | SAXParserTests.java:30:18:30:38 | getInputStream(...) | SAXParserTests.java:30:18:30:38 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | SAXParserTests.java:30:18:30:38 | getInputStream(...) | user-provided value |
| SAXParserTests.java:38:18:38:38 | getInputStream(...) | SAXParserTests.java:38:18:38:38 | getInputStream(...) | SAXParserTests.java:38:18:38:38 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | SAXParserTests.java:38:18:38:38 | getInputStream(...) | user-provided value |
| SAXParserTests.java:46:18:46:38 | getInputStream(...) | SAXParserTests.java:46:18:46:38 | getInputStream(...) | SAXParserTests.java:46:18:46:38 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | SAXParserTests.java:46:18:46:38 | getInputStream(...) | user-provided value |
| SAXParserTests.java:55:18:55:38 | getInputStream(...) | SAXParserTests.java:55:18:55:38 | getInputStream(...) | SAXParserTests.java:55:18:55:38 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | SAXParserTests.java:55:18:55:38 | getInputStream(...) | user-provided value |
| SAXParserTests.java:64:18:64:38 | getInputStream(...) | SAXParserTests.java:64:18:64:38 | getInputStream(...) | SAXParserTests.java:64:18:64:38 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | SAXParserTests.java:64:18:64:38 | getInputStream(...) | user-provided value |
| SAXParserTests.java:73:18:73:38 | getInputStream(...) | SAXParserTests.java:73:18:73:38 | getInputStream(...) | SAXParserTests.java:73:18:73:38 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | SAXParserTests.java:73:18:73:38 | getInputStream(...) | user-provided value |
| SAXReaderTests.java:8:17:8:37 | getInputStream(...) | SAXReaderTests.java:8:17:8:37 | getInputStream(...) | SAXReaderTests.java:8:17:8:37 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | SAXReaderTests.java:8:17:8:37 | getInputStream(...) | user-provided value |
| SAXReaderTests.java:23:17:23:37 | getInputStream(...) | SAXReaderTests.java:23:17:23:37 | getInputStream(...) | SAXReaderTests.java:23:17:23:37 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | SAXReaderTests.java:23:17:23:37 | getInputStream(...) | user-provided value |
| SAXReaderTests.java:30:17:30:37 | getInputStream(...) | SAXReaderTests.java:30:17:30:37 | getInputStream(...) | SAXReaderTests.java:30:17:30:37 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | SAXReaderTests.java:30:17:30:37 | getInputStream(...) | user-provided value |
| SAXReaderTests.java:37:17:37:37 | getInputStream(...) | SAXReaderTests.java:37:17:37:37 | getInputStream(...) | SAXReaderTests.java:37:17:37:37 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | SAXReaderTests.java:37:17:37:37 | getInputStream(...) | user-provided value |
| SAXReaderTests.java:45:17:45:37 | getInputStream(...) | SAXReaderTests.java:45:17:45:37 | getInputStream(...) | SAXReaderTests.java:45:17:45:37 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | SAXReaderTests.java:45:17:45:37 | getInputStream(...) | user-provided value |
| SAXReaderTests.java:53:17:53:37 | getInputStream(...) | SAXReaderTests.java:53:17:53:37 | getInputStream(...) | SAXReaderTests.java:53:17:53:37 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | SAXReaderTests.java:53:17:53:37 | getInputStream(...) | user-provided value |
| SAXReaderTests.java:61:17:61:37 | getInputStream(...) | SAXReaderTests.java:61:17:61:37 | getInputStream(...) | SAXReaderTests.java:61:17:61:37 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | SAXReaderTests.java:61:17:61:37 | getInputStream(...) | user-provided value |
| SAXSourceTests.java:20:18:20:23 | source | SAXSourceTests.java:17:62:17:82 | getInputStream(...) : InputStream | SAXSourceTests.java:20:18:20:23 | source | A $@ is parsed as XML without guarding against external entity expansion. | SAXSourceTests.java:17:62:17:82 | getInputStream(...) | user-provided value |
| SchemaTests.java:12:39:12:77 | new StreamSource(...) | SchemaTests.java:12:56:12:76 | getInputStream(...) : InputStream | SchemaTests.java:12:39:12:77 | new StreamSource(...) | A $@ is parsed as XML without guarding against external entity expansion. | SchemaTests.java:12:56:12:76 | getInputStream(...) | user-provided value |
| SchemaTests.java:25:39:25:77 | new StreamSource(...) | SchemaTests.java:25:56:25:76 | getInputStream(...) : InputStream | SchemaTests.java:25:39:25:77 | new StreamSource(...) | A $@ is parsed as XML without guarding against external entity expansion. | SchemaTests.java:25:56:25:76 | getInputStream(...) | user-provided value |
| SchemaTests.java:31:39:31:77 | new StreamSource(...) | SchemaTests.java:31:56:31:76 | getInputStream(...) : InputStream | SchemaTests.java:31:39:31:77 | new StreamSource(...) | A $@ is parsed as XML without guarding against external entity expansion. | SchemaTests.java:31:56:31:76 | getInputStream(...) | user-provided value |
| SchemaTests.java:38:39:38:77 | new StreamSource(...) | SchemaTests.java:38:56:38:76 | getInputStream(...) : InputStream | SchemaTests.java:38:39:38:77 | new StreamSource(...) | A $@ is parsed as XML without guarding against external entity expansion. | SchemaTests.java:38:56:38:76 | getInputStream(...) | user-provided value |
| SchemaTests.java:45:39:45:77 | new StreamSource(...) | SchemaTests.java:45:56:45:76 | getInputStream(...) : InputStream | SchemaTests.java:45:39:45:77 | new StreamSource(...) | A $@ is parsed as XML without guarding against external entity expansion. | SchemaTests.java:45:56:45:76 | getInputStream(...) | user-provided value |
| SimpleXMLTests.java:14:41:14:61 | getInputStream(...) | SimpleXMLTests.java:14:41:14:61 | getInputStream(...) | SimpleXMLTests.java:14:41:14:61 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | SimpleXMLTests.java:14:41:14:61 | getInputStream(...) | user-provided value |
| SimpleXMLTests.java:19:41:19:61 | getInputStream(...) | SimpleXMLTests.java:19:41:19:61 | getInputStream(...) | SimpleXMLTests.java:19:41:19:61 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | SimpleXMLTests.java:19:41:19:61 | getInputStream(...) | user-provided value |
| SimpleXMLTests.java:24:41:24:84 | new InputStreamReader(...) | SimpleXMLTests.java:24:63:24:83 | getInputStream(...) : InputStream | SimpleXMLTests.java:24:41:24:84 | new InputStreamReader(...) | A $@ is parsed as XML without guarding against external entity expansion. | SimpleXMLTests.java:24:63:24:83 | getInputStream(...) | user-provided value |
| SimpleXMLTests.java:31:41:31:53 | new String(...) | SimpleXMLTests.java:30:5:30:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:31:41:31:53 | new String(...) | A $@ is parsed as XML without guarding against external entity expansion. | SimpleXMLTests.java:30:5:30:25 | getInputStream(...) | user-provided value |
| SimpleXMLTests.java:38:41:38:53 | new String(...) | SimpleXMLTests.java:37:5:37:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:38:41:38:53 | new String(...) | A $@ is parsed as XML without guarding against external entity expansion. | SimpleXMLTests.java:37:5:37:25 | getInputStream(...) | user-provided value |
| SimpleXMLTests.java:43:41:43:84 | new InputStreamReader(...) | SimpleXMLTests.java:43:63:43:83 | getInputStream(...) : InputStream | SimpleXMLTests.java:43:41:43:84 | new InputStreamReader(...) | A $@ is parsed as XML without guarding against external entity expansion. | SimpleXMLTests.java:43:63:43:83 | getInputStream(...) | user-provided value |
| SimpleXMLTests.java:48:37:48:57 | getInputStream(...) | SimpleXMLTests.java:48:37:48:57 | getInputStream(...) | SimpleXMLTests.java:48:37:48:57 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | SimpleXMLTests.java:48:37:48:57 | getInputStream(...) | user-provided value |
| SimpleXMLTests.java:53:37:53:57 | getInputStream(...) | SimpleXMLTests.java:53:37:53:57 | getInputStream(...) | SimpleXMLTests.java:53:37:53:57 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | SimpleXMLTests.java:53:37:53:57 | getInputStream(...) | user-provided value |
| SimpleXMLTests.java:58:26:58:46 | getInputStream(...) | SimpleXMLTests.java:58:26:58:46 | getInputStream(...) | SimpleXMLTests.java:58:26:58:46 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | SimpleXMLTests.java:58:26:58:46 | getInputStream(...) | user-provided value |
| SimpleXMLTests.java:63:26:63:46 | getInputStream(...) | SimpleXMLTests.java:63:26:63:46 | getInputStream(...) | SimpleXMLTests.java:63:26:63:46 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | SimpleXMLTests.java:63:26:63:46 | getInputStream(...) | user-provided value |
| SimpleXMLTests.java:68:37:68:80 | new InputStreamReader(...) | SimpleXMLTests.java:68:59:68:79 | getInputStream(...) : InputStream | SimpleXMLTests.java:68:37:68:80 | new InputStreamReader(...) | A $@ is parsed as XML without guarding against external entity expansion. | SimpleXMLTests.java:68:59:68:79 | getInputStream(...) | user-provided value |
| SimpleXMLTests.java:73:37:73:80 | new InputStreamReader(...) | SimpleXMLTests.java:73:59:73:79 | getInputStream(...) : InputStream | SimpleXMLTests.java:73:37:73:80 | new InputStreamReader(...) | A $@ is parsed as XML without guarding against external entity expansion. | SimpleXMLTests.java:73:59:73:79 | getInputStream(...) | user-provided value |
| SimpleXMLTests.java:78:26:78:69 | new InputStreamReader(...) | SimpleXMLTests.java:78:48:78:68 | getInputStream(...) : InputStream | SimpleXMLTests.java:78:26:78:69 | new InputStreamReader(...) | A $@ is parsed as XML without guarding against external entity expansion. | SimpleXMLTests.java:78:48:78:68 | getInputStream(...) | user-provided value |
| SimpleXMLTests.java:83:26:83:69 | new InputStreamReader(...) | SimpleXMLTests.java:83:48:83:68 | getInputStream(...) : InputStream | SimpleXMLTests.java:83:26:83:69 | new InputStreamReader(...) | A $@ is parsed as XML without guarding against external entity expansion. | SimpleXMLTests.java:83:48:83:68 | getInputStream(...) | user-provided value |
| SimpleXMLTests.java:90:37:90:49 | new String(...) | SimpleXMLTests.java:89:5:89:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:90:37:90:49 | new String(...) | A $@ is parsed as XML without guarding against external entity expansion. | SimpleXMLTests.java:89:5:89:25 | getInputStream(...) | user-provided value |
| SimpleXMLTests.java:97:37:97:49 | new String(...) | SimpleXMLTests.java:96:5:96:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:97:37:97:49 | new String(...) | A $@ is parsed as XML without guarding against external entity expansion. | SimpleXMLTests.java:96:5:96:25 | getInputStream(...) | user-provided value |
| SimpleXMLTests.java:104:26:104:38 | new String(...) | SimpleXMLTests.java:103:5:103:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:104:26:104:38 | new String(...) | A $@ is parsed as XML without guarding against external entity expansion. | SimpleXMLTests.java:103:5:103:25 | getInputStream(...) | user-provided value |
| SimpleXMLTests.java:111:26:111:38 | new String(...) | SimpleXMLTests.java:110:5:110:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:111:26:111:38 | new String(...) | A $@ is parsed as XML without guarding against external entity expansion. | SimpleXMLTests.java:110:5:110:25 | getInputStream(...) | user-provided value |
| SimpleXMLTests.java:115:22:115:42 | getInputStream(...) | SimpleXMLTests.java:115:22:115:42 | getInputStream(...) | SimpleXMLTests.java:115:22:115:42 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | SimpleXMLTests.java:115:22:115:42 | getInputStream(...) | user-provided value |
| SimpleXMLTests.java:119:22:119:65 | new InputStreamReader(...) | SimpleXMLTests.java:119:44:119:64 | getInputStream(...) : InputStream | SimpleXMLTests.java:119:22:119:65 | new InputStreamReader(...) | A $@ is parsed as XML without guarding against external entity expansion. | SimpleXMLTests.java:119:44:119:64 | getInputStream(...) | user-provided value |
| SimpleXMLTests.java:124:22:124:42 | getInputStream(...) | SimpleXMLTests.java:124:22:124:42 | getInputStream(...) | SimpleXMLTests.java:124:22:124:42 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | SimpleXMLTests.java:124:22:124:42 | getInputStream(...) | user-provided value |
| SimpleXMLTests.java:129:22:129:65 | new InputStreamReader(...) | SimpleXMLTests.java:129:44:129:64 | getInputStream(...) : InputStream | SimpleXMLTests.java:129:22:129:65 | new InputStreamReader(...) | A $@ is parsed as XML without guarding against external entity expansion. | SimpleXMLTests.java:129:44:129:64 | getInputStream(...) | user-provided value |
| SimpleXMLTests.java:134:22:134:42 | getInputStream(...) | SimpleXMLTests.java:134:22:134:42 | getInputStream(...) | SimpleXMLTests.java:134:22:134:42 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | SimpleXMLTests.java:134:22:134:42 | getInputStream(...) | user-provided value |
| SimpleXMLTests.java:139:22:139:65 | new InputStreamReader(...) | SimpleXMLTests.java:139:44:139:64 | getInputStream(...) : InputStream | SimpleXMLTests.java:139:22:139:65 | new InputStreamReader(...) | A $@ is parsed as XML without guarding against external entity expansion. | SimpleXMLTests.java:139:44:139:64 | getInputStream(...) | user-provided value |
| SimpleXMLTests.java:146:22:146:34 | new String(...) | SimpleXMLTests.java:145:5:145:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:146:22:146:34 | new String(...) | A $@ is parsed as XML without guarding against external entity expansion. | SimpleXMLTests.java:145:5:145:25 | getInputStream(...) | user-provided value |
| SimpleXMLTests.java:153:22:153:34 | new String(...) | SimpleXMLTests.java:152:5:152:25 | getInputStream(...) : InputStream | SimpleXMLTests.java:153:22:153:34 | new String(...) | A $@ is parsed as XML without guarding against external entity expansion. | SimpleXMLTests.java:152:5:152:25 | getInputStream(...) | user-provided value |
| TransformerTests.java:20:27:20:65 | new StreamSource(...) | TransformerTests.java:20:44:20:64 | getInputStream(...) : InputStream | TransformerTests.java:20:27:20:65 | new StreamSource(...) | A $@ is parsed as XML without guarding against external entity expansion. | TransformerTests.java:20:44:20:64 | getInputStream(...) | user-provided value |
| TransformerTests.java:21:23:21:61 | new StreamSource(...) | TransformerTests.java:21:40:21:60 | getInputStream(...) : InputStream | TransformerTests.java:21:23:21:61 | new StreamSource(...) | A $@ is parsed as XML without guarding against external entity expansion. | TransformerTests.java:21:40:21:60 | getInputStream(...) | user-provided value |
| TransformerTests.java:71:27:71:65 | new StreamSource(...) | TransformerTests.java:71:44:71:64 | getInputStream(...) : InputStream | TransformerTests.java:71:27:71:65 | new StreamSource(...) | A $@ is parsed as XML without guarding against external entity expansion. | TransformerTests.java:71:44:71:64 | getInputStream(...) | user-provided value |
| TransformerTests.java:72:23:72:61 | new StreamSource(...) | TransformerTests.java:72:40:72:60 | getInputStream(...) : InputStream | TransformerTests.java:72:23:72:61 | new StreamSource(...) | A $@ is parsed as XML without guarding against external entity expansion. | TransformerTests.java:72:40:72:60 | getInputStream(...) | user-provided value |
| TransformerTests.java:79:27:79:65 | new StreamSource(...) | TransformerTests.java:79:44:79:64 | getInputStream(...) : InputStream | TransformerTests.java:79:27:79:65 | new StreamSource(...) | A $@ is parsed as XML without guarding against external entity expansion. | TransformerTests.java:79:44:79:64 | getInputStream(...) | user-provided value |
| TransformerTests.java:80:23:80:61 | new StreamSource(...) | TransformerTests.java:80:40:80:60 | getInputStream(...) : InputStream | TransformerTests.java:80:23:80:61 | new StreamSource(...) | A $@ is parsed as XML without guarding against external entity expansion. | TransformerTests.java:80:40:80:60 | getInputStream(...) | user-provided value |
| TransformerTests.java:88:27:88:65 | new StreamSource(...) | TransformerTests.java:88:44:88:64 | getInputStream(...) : InputStream | TransformerTests.java:88:27:88:65 | new StreamSource(...) | A $@ is parsed as XML without guarding against external entity expansion. | TransformerTests.java:88:44:88:64 | getInputStream(...) | user-provided value |
| TransformerTests.java:89:23:89:61 | new StreamSource(...) | TransformerTests.java:89:40:89:60 | getInputStream(...) : InputStream | TransformerTests.java:89:23:89:61 | new StreamSource(...) | A $@ is parsed as XML without guarding against external entity expansion. | TransformerTests.java:89:40:89:60 | getInputStream(...) | user-provided value |
| TransformerTests.java:97:27:97:65 | new StreamSource(...) | TransformerTests.java:97:44:97:64 | getInputStream(...) : InputStream | TransformerTests.java:97:27:97:65 | new StreamSource(...) | A $@ is parsed as XML without guarding against external entity expansion. | TransformerTests.java:97:44:97:64 | getInputStream(...) | user-provided value |
| TransformerTests.java:98:23:98:61 | new StreamSource(...) | TransformerTests.java:98:40:98:60 | getInputStream(...) : InputStream | TransformerTests.java:98:23:98:61 | new StreamSource(...) | A $@ is parsed as XML without guarding against external entity expansion. | TransformerTests.java:98:40:98:60 | getInputStream(...) | user-provided value |
| TransformerTests.java:103:21:103:59 | new StreamSource(...) | TransformerTests.java:103:38:103:58 | getInputStream(...) : InputStream | TransformerTests.java:103:21:103:59 | new StreamSource(...) | A $@ is parsed as XML without guarding against external entity expansion. | TransformerTests.java:103:38:103:58 | getInputStream(...) | user-provided value |
| TransformerTests.java:116:21:116:59 | new StreamSource(...) | TransformerTests.java:116:38:116:58 | getInputStream(...) : InputStream | TransformerTests.java:116:21:116:59 | new StreamSource(...) | A $@ is parsed as XML without guarding against external entity expansion. | TransformerTests.java:116:38:116:58 | getInputStream(...) | user-provided value |
| TransformerTests.java:122:21:122:59 | new StreamSource(...) | TransformerTests.java:122:38:122:58 | getInputStream(...) : InputStream | TransformerTests.java:122:21:122:59 | new StreamSource(...) | A $@ is parsed as XML without guarding against external entity expansion. | TransformerTests.java:122:38:122:58 | getInputStream(...) | user-provided value |
| TransformerTests.java:129:21:129:59 | new StreamSource(...) | TransformerTests.java:129:38:129:58 | getInputStream(...) : InputStream | TransformerTests.java:129:21:129:59 | new StreamSource(...) | A $@ is parsed as XML without guarding against external entity expansion. | TransformerTests.java:129:38:129:58 | getInputStream(...) | user-provided value |
| TransformerTests.java:136:21:136:59 | new StreamSource(...) | TransformerTests.java:136:38:136:58 | getInputStream(...) : InputStream | TransformerTests.java:136:21:136:59 | new StreamSource(...) | A $@ is parsed as XML without guarding against external entity expansion. | TransformerTests.java:136:38:136:58 | getInputStream(...) | user-provided value |
| TransformerTests.java:141:18:141:70 | new SAXSource(...) | TransformerTests.java:141:48:141:68 | getInputStream(...) : InputStream | TransformerTests.java:141:18:141:70 | new SAXSource(...) | A $@ is parsed as XML without guarding against external entity expansion. | TransformerTests.java:141:48:141:68 | getInputStream(...) | user-provided value |
| UnmarshallerTests.java:28:18:28:38 | getInputStream(...) | UnmarshallerTests.java:28:18:28:38 | getInputStream(...) | UnmarshallerTests.java:28:18:28:38 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | UnmarshallerTests.java:28:18:28:38 | getInputStream(...) | user-provided value |
| XMLReaderTests.java:16:18:16:55 | new InputSource(...) | XMLReaderTests.java:16:34:16:54 | getInputStream(...) : InputStream | XMLReaderTests.java:16:18:16:55 | new InputSource(...) | A $@ is parsed as XML without guarding against external entity expansion. | XMLReaderTests.java:16:34:16:54 | getInputStream(...) | user-provided value |
| XMLReaderTests.java:56:18:56:55 | new InputSource(...) | XMLReaderTests.java:56:34:56:54 | getInputStream(...) : InputStream | XMLReaderTests.java:56:18:56:55 | new InputSource(...) | A $@ is parsed as XML without guarding against external entity expansion. | XMLReaderTests.java:56:34:56:54 | getInputStream(...) | user-provided value |
| XMLReaderTests.java:63:18:63:55 | new InputSource(...) | XMLReaderTests.java:63:34:63:54 | getInputStream(...) : InputStream | XMLReaderTests.java:63:18:63:55 | new InputSource(...) | A $@ is parsed as XML without guarding against external entity expansion. | XMLReaderTests.java:63:34:63:54 | getInputStream(...) | user-provided value |
| XMLReaderTests.java:70:18:70:55 | new InputSource(...) | XMLReaderTests.java:70:34:70:54 | getInputStream(...) : InputStream | XMLReaderTests.java:70:18:70:55 | new InputSource(...) | A $@ is parsed as XML without guarding against external entity expansion. | XMLReaderTests.java:70:34:70:54 | getInputStream(...) | user-provided value |
| XMLReaderTests.java:78:18:78:55 | new InputSource(...) | XMLReaderTests.java:78:34:78:54 | getInputStream(...) : InputStream | XMLReaderTests.java:78:18:78:55 | new InputSource(...) | A $@ is parsed as XML without guarding against external entity expansion. | XMLReaderTests.java:78:34:78:54 | getInputStream(...) | user-provided value |
| XMLReaderTests.java:86:18:86:55 | new InputSource(...) | XMLReaderTests.java:86:34:86:54 | getInputStream(...) : InputStream | XMLReaderTests.java:86:18:86:55 | new InputSource(...) | A $@ is parsed as XML without guarding against external entity expansion. | XMLReaderTests.java:86:34:86:54 | getInputStream(...) | user-provided value |
| XMLReaderTests.java:94:18:94:55 | new InputSource(...) | XMLReaderTests.java:94:34:94:54 | getInputStream(...) : InputStream | XMLReaderTests.java:94:18:94:55 | new InputSource(...) | A $@ is parsed as XML without guarding against external entity expansion. | XMLReaderTests.java:94:34:94:54 | getInputStream(...) | user-provided value |
| XMLReaderTests.java:100:18:100:55 | new InputSource(...) | XMLReaderTests.java:100:34:100:54 | getInputStream(...) : InputStream | XMLReaderTests.java:100:18:100:55 | new InputSource(...) | A $@ is parsed as XML without guarding against external entity expansion. | XMLReaderTests.java:100:34:100:54 | getInputStream(...) | user-provided value |
| XPathExpressionTests.java:27:21:27:58 | new InputSource(...) | XPathExpressionTests.java:27:37:27:57 | getInputStream(...) : InputStream | XPathExpressionTests.java:27:21:27:58 | new InputSource(...) | A $@ is parsed as XML without guarding against external entity expansion. | XPathExpressionTests.java:27:37:27:57 | getInputStream(...) | user-provided value |
| XmlInputFactoryTests.java:9:35:9:55 | getInputStream(...) | XmlInputFactoryTests.java:9:35:9:55 | getInputStream(...) | XmlInputFactoryTests.java:9:35:9:55 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | XmlInputFactoryTests.java:9:35:9:55 | getInputStream(...) | user-provided value |
| XmlInputFactoryTests.java:10:34:10:54 | getInputStream(...) | XmlInputFactoryTests.java:10:34:10:54 | getInputStream(...) | XmlInputFactoryTests.java:10:34:10:54 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | XmlInputFactoryTests.java:10:34:10:54 | getInputStream(...) | user-provided value |
| XmlInputFactoryTests.java:24:35:24:55 | getInputStream(...) | XmlInputFactoryTests.java:24:35:24:55 | getInputStream(...) | XmlInputFactoryTests.java:24:35:24:55 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | XmlInputFactoryTests.java:24:35:24:55 | getInputStream(...) | user-provided value |
| XmlInputFactoryTests.java:25:34:25:54 | getInputStream(...) | XmlInputFactoryTests.java:25:34:25:54 | getInputStream(...) | XmlInputFactoryTests.java:25:34:25:54 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | XmlInputFactoryTests.java:25:34:25:54 | getInputStream(...) | user-provided value |
| XmlInputFactoryTests.java:31:35:31:55 | getInputStream(...) | XmlInputFactoryTests.java:31:35:31:55 | getInputStream(...) | XmlInputFactoryTests.java:31:35:31:55 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | XmlInputFactoryTests.java:31:35:31:55 | getInputStream(...) | user-provided value |
| XmlInputFactoryTests.java:32:34:32:54 | getInputStream(...) | XmlInputFactoryTests.java:32:34:32:54 | getInputStream(...) | XmlInputFactoryTests.java:32:34:32:54 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | XmlInputFactoryTests.java:32:34:32:54 | getInputStream(...) | user-provided value |
| XmlInputFactoryTests.java:39:35:39:55 | getInputStream(...) | XmlInputFactoryTests.java:39:35:39:55 | getInputStream(...) | XmlInputFactoryTests.java:39:35:39:55 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | XmlInputFactoryTests.java:39:35:39:55 | getInputStream(...) | user-provided value |
| XmlInputFactoryTests.java:40:34:40:54 | getInputStream(...) | XmlInputFactoryTests.java:40:34:40:54 | getInputStream(...) | XmlInputFactoryTests.java:40:34:40:54 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | XmlInputFactoryTests.java:40:34:40:54 | getInputStream(...) | user-provided value |
| XmlInputFactoryTests.java:47:35:47:55 | getInputStream(...) | XmlInputFactoryTests.java:47:35:47:55 | getInputStream(...) | XmlInputFactoryTests.java:47:35:47:55 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | XmlInputFactoryTests.java:47:35:47:55 | getInputStream(...) | user-provided value |
| XmlInputFactoryTests.java:48:34:48:54 | getInputStream(...) | XmlInputFactoryTests.java:48:34:48:54 | getInputStream(...) | XmlInputFactoryTests.java:48:34:48:54 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | XmlInputFactoryTests.java:48:34:48:54 | getInputStream(...) | user-provided value |
| XmlInputFactoryTests.java:55:35:55:55 | getInputStream(...) | XmlInputFactoryTests.java:55:35:55:55 | getInputStream(...) | XmlInputFactoryTests.java:55:35:55:55 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | XmlInputFactoryTests.java:55:35:55:55 | getInputStream(...) | user-provided value |
| XmlInputFactoryTests.java:56:34:56:54 | getInputStream(...) | XmlInputFactoryTests.java:56:34:56:54 | getInputStream(...) | XmlInputFactoryTests.java:56:34:56:54 | getInputStream(...) | A $@ is parsed as XML without guarding against external entity expansion. | XmlInputFactoryTests.java:56:34:56:54 | getInputStream(...) | user-provided value |

View File

@@ -93,8 +93,6 @@ class RegExpRoot extends RegExpTerm {
* Holds if this root term is relevant to the ReDoS analysis.
*/
predicate isRelevant() {
// there is at least one repetition
getRoot(any(InfiniteRepetitionQuantifier q)) = this and
// is actually used as a RegExp
this.isUsedAsRegExp() and
// not excluded for library specific reasons
@@ -877,6 +875,101 @@ predicate isStartState(State state) {
*/
signature predicate isCandidateSig(State state, string pump);
/**
* Holds if `state` is a candidate for ReDoS.
*/
signature predicate isCandidateSig(State state);
/**
* Predicates for constructing a prefix string that leads to a given state.
*/
module PrefixConstruction<isCandidateSig/1 isCandidate> {
/**
* Holds if `state` is the textually last start state for the regular expression.
*/
private predicate lastStartState(State state) {
exists(RegExpRoot root |
state =
max(State s, Location l |
s = stateInRelevantRegexp() and
isStartState(s) and
getRoot(s.getRepr()) = root and
l = s.getRepr().getLocation()
|
s
order by
l.getStartLine(), l.getStartColumn(), s.getRepr().toString(), l.getEndColumn(),
l.getEndLine()
)
)
}
/**
* Holds if there exists any transition (Epsilon() or other) from `a` to `b`.
*/
private predicate existsTransition(State a, State b) { delta(a, _, b) }
/**
* Gets the minimum number of transitions it takes to reach `state` from the `start` state.
*/
int prefixLength(State start, State state) =
shortestDistances(lastStartState/1, existsTransition/2)(start, state, result)
/**
* Gets the minimum number of transitions it takes to reach `state` from the start state.
*/
private int lengthFromStart(State state) { result = prefixLength(_, state) }
/**
* Gets a string for which the regular expression will reach `state`.
*
* Has at most one result for any given `state`.
* This predicate will not always have a result even if there is a ReDoS issue in
* the regular expression.
*/
string prefix(State state) {
lastStartState(state) and
result = ""
or
// the search stops past the last redos candidate state.
lengthFromStart(state) <= max(lengthFromStart(any(State s | isCandidate(s)))) and
exists(State prev |
// select a unique predecessor (by an arbitrary measure)
prev =
min(State s, Location loc |
lengthFromStart(s) = lengthFromStart(state) - 1 and
loc = s.getRepr().getLocation() and
delta(s, _, state)
|
s
order by
loc.getStartLine(), loc.getStartColumn(), loc.getEndLine(), loc.getEndColumn(),
s.getRepr().toString()
)
|
// greedy search for the shortest prefix
result = prefix(prev) and delta(prev, Epsilon(), state)
or
not delta(prev, Epsilon(), state) and
result = prefix(prev) + getCanonicalEdgeChar(prev, state)
)
}
/**
* Gets a canonical char for which there exists a transition from `prev` to `next` in the NFA.
*/
private string getCanonicalEdgeChar(State prev, State next) {
result =
min(string c | delta(prev, any(InputSymbol symbol | c = intersect(Any(), symbol)), next))
}
/** Gets a state within a regular expression that contains a candidate state. */
pragma[noinline]
State stateInRelevantRegexp() {
exists(State s | isCandidate(s) | getRoot(s.getRepr()) = getRoot(result.getRepr()))
}
}
/**
* A module for pruning candidate ReDoS states.
* The candidates are specified by the `isCandidate` signature predicate.
@@ -910,95 +1003,9 @@ module ReDoSPruning<isCandidateSig/2 isCandidate> {
/** Gets a state that can reach the `accept-any` state using only epsilon steps. */
private State acceptsAnySuffix() { epsilonSucc*(result) = AcceptAnySuffix(_) }
/**
* Predicates for constructing a prefix string that leads to a given state.
*/
private module PrefixConstruction {
/**
* Holds if `state` is the textually last start state for the regular expression.
*/
private predicate lastStartState(State state) {
exists(RegExpRoot root |
state =
max(State s, Location l |
s = stateInPumpableRegexp() and
isStartState(s) and
getRoot(s.getRepr()) = root and
l = s.getRepr().getLocation()
|
s
order by
l.getStartLine(), l.getStartColumn(), s.getRepr().toString(), l.getEndColumn(),
l.getEndLine()
)
)
}
predicate isCandidateState(State s) { isReDoSCandidate(s, _) }
/**
* Holds if there exists any transition (Epsilon() or other) from `a` to `b`.
*/
private predicate existsTransition(State a, State b) { delta(a, _, b) }
/**
* Gets the minimum number of transitions it takes to reach `state` from the `start` state.
*/
int prefixLength(State start, State state) =
shortestDistances(lastStartState/1, existsTransition/2)(start, state, result)
/**
* Gets the minimum number of transitions it takes to reach `state` from the start state.
*/
private int lengthFromStart(State state) { result = prefixLength(_, state) }
/**
* Gets a string for which the regular expression will reach `state`.
*
* Has at most one result for any given `state`.
* This predicate will not always have a result even if there is a ReDoS issue in
* the regular expression.
*/
string prefix(State state) {
lastStartState(state) and
result = ""
or
// the search stops past the last redos candidate state.
lengthFromStart(state) <= max(lengthFromStart(any(State s | isReDoSCandidate(s, _)))) and
exists(State prev |
// select a unique predecessor (by an arbitrary measure)
prev =
min(State s, Location loc |
lengthFromStart(s) = lengthFromStart(state) - 1 and
loc = s.getRepr().getLocation() and
delta(s, _, state)
|
s
order by
loc.getStartLine(), loc.getStartColumn(), loc.getEndLine(), loc.getEndColumn(),
s.getRepr().toString()
)
|
// greedy search for the shortest prefix
result = prefix(prev) and delta(prev, Epsilon(), state)
or
not delta(prev, Epsilon(), state) and
result = prefix(prev) + getCanonicalEdgeChar(prev, state)
)
}
/**
* Gets a canonical char for which there exists a transition from `prev` to `next` in the NFA.
*/
private string getCanonicalEdgeChar(State prev, State next) {
result =
min(string c | delta(prev, any(InputSymbol symbol | c = intersect(Any(), symbol)), next))
}
/** Gets a state within a regular expression that has a pumpable state. */
pragma[noinline]
State stateInPumpableRegexp() {
exists(State s | isReDoSCandidate(s, _) | getRoot(s.getRepr()) = getRoot(result.getRepr()))
}
}
import PrefixConstruction<isCandidateState/1> as Prefix
/**
* Predicates for testing the presence of a rejecting suffix.
@@ -1018,8 +1025,6 @@ module ReDoSPruning<isCandidateSig/2 isCandidate> {
* using epsilon transitions. But any attempt at repeating `w` will end in a state that accepts all suffixes.
*/
private module SuffixConstruction {
import PrefixConstruction
/**
* Holds if all states reachable from `fork` by repeating `w`
* are likely rejectable by appending some suffix.
@@ -1036,7 +1041,7 @@ module ReDoSPruning<isCandidateSig/2 isCandidate> {
*/
pragma[noinline]
private predicate isLikelyRejectable(State s) {
s = stateInPumpableRegexp() and
s = Prefix::stateInRelevantRegexp() and
(
// exists a reject edge with some char.
hasRejectEdge(s)
@@ -1052,7 +1057,7 @@ module ReDoSPruning<isCandidateSig/2 isCandidate> {
* Holds if `s` is not an accept state, and there is no epsilon transition to an accept state.
*/
predicate isRejectState(State s) {
s = stateInPumpableRegexp() and not epsilonSucc*(s) = Accept(_)
s = Prefix::stateInRelevantRegexp() and not epsilonSucc*(s) = Accept(_)
}
/**
@@ -1060,7 +1065,7 @@ module ReDoSPruning<isCandidateSig/2 isCandidate> {
*/
pragma[noopt]
predicate hasEdgeToLikelyRejectable(State s) {
s = stateInPumpableRegexp() and
s = Prefix::stateInRelevantRegexp() and
// all edges (at least one) with some char leads to another state that is rejectable.
// the `next` states might not share a common suffix, which can cause FPs.
exists(string char | char = hasEdgeToLikelyRejectableHelper(s) |
@@ -1076,7 +1081,7 @@ module ReDoSPruning<isCandidateSig/2 isCandidate> {
*/
pragma[noinline]
private string hasEdgeToLikelyRejectableHelper(State s) {
s = stateInPumpableRegexp() and
s = Prefix::stateInRelevantRegexp() and
not hasRejectEdge(s) and
not isRejectState(s) and
deltaClosedChar(s, result, _)
@@ -1088,8 +1093,8 @@ module ReDoSPruning<isCandidateSig/2 isCandidate> {
* `prev` to `next` that the character symbol `char`.
*/
predicate deltaClosedChar(State prev, string char, State next) {
prev = stateInPumpableRegexp() and
next = stateInPumpableRegexp() and
prev = Prefix::stateInRelevantRegexp() and
next = Prefix::stateInRelevantRegexp() and
deltaClosed(prev, getAnInputSymbolMatchingRelevant(char), next)
}
@@ -1099,18 +1104,28 @@ module ReDoSPruning<isCandidateSig/2 isCandidate> {
result = getAnInputSymbolMatching(char)
}
pragma[noinline]
RegExpRoot relevantRoot() {
exists(RegExpTerm term, State s |
s.getRepr() = term and isCandidateState(s) and result = term.getRootTerm()
)
}
/**
* Gets a char used for finding possible suffixes inside `root`.
*/
pragma[noinline]
private string relevant(RegExpRoot root) {
exists(ascii(result)) and exists(root)
or
exists(InputSymbol s | belongsTo(s, root) | result = intersect(s, _))
or
// The characters from `hasSimpleRejectEdge`. Only `\n` is really needed (as `\n` is not in the `ascii` relation).
// The three chars must be kept in sync with `hasSimpleRejectEdge`.
result = ["|", "\n", "Z"] and exists(root)
root = relevantRoot() and
(
exists(ascii(result)) and exists(root)
or
exists(InputSymbol s | belongsTo(s, root) | result = intersect(s, _))
or
// The characters from `hasSimpleRejectEdge`. Only `\n` is really needed (as `\n` is not in the `ascii` relation).
// The three chars must be kept in sync with `hasSimpleRejectEdge`.
result = ["|", "\n", "Z"] and exists(root)
)
}
/**
@@ -1208,12 +1223,12 @@ module ReDoSPruning<isCandidateSig/2 isCandidate> {
predicate hasReDoSResult(RegExpTerm t, string pump, State s, string prefixMsg) {
isReDoSAttackable(t, pump, s) and
(
prefixMsg = "starting with '" + escape(PrefixConstruction::prefix(s)) + "' and " and
not PrefixConstruction::prefix(s) = ""
prefixMsg = "starting with '" + escape(Prefix::prefix(s)) + "' and " and
not Prefix::prefix(s) = ""
or
PrefixConstruction::prefix(s) = "" and prefixMsg = ""
Prefix::prefix(s) = "" and prefixMsg = ""
or
not exists(PrefixConstruction::prefix(s)) and prefixMsg = ""
not exists(Prefix::prefix(s)) and prefixMsg = ""
)
}

View File

@@ -13,4 +13,4 @@ import UnusedParameter
from Parameter p
where isAnAccidentallyUnusedParameter(p)
select p, "Unused parameter " + p.getAVariable().getName() + "."
select p, "The parameter '" + p.getVariable().getName() + "' is never used."

View File

@@ -53,4 +53,4 @@ where
not e instanceof EqualityTest and
e.getRightOperand().getIntValue() = 0 and
not acceptableSignCheck(b)
select e, "Sign check of a bitwise operation"
select e, "Potentially unsafe sign check of a bitwise operation."

Some files were not shown because too many files have changed in this diff Show More