Merge remote-tracking branch 'upstream/master' into ir-crement-load

Conflicts:
	cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected
	cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir_unsound.expected
	cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected
	cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir_unsound.expected
This commit is contained in:
Jonas Jensen
2020-02-06 08:37:09 +01:00
63 changed files with 5026 additions and 3679 deletions

View File

@@ -2041,12 +2041,12 @@ private class PathNodeMid extends PathNode, TPathNodeMid {
result = getSuccMid()
or
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid |
exists(PathNodeMid mid, PathNodeSink sink |
mid = getSuccMid() and
mid.getNode() = result.getNode() and
mid.getNode() = sink.getNode() and
mid.getAp() instanceof AccessPathNil and
result instanceof PathNodeSink and
result.getConfiguration() = unbind(mid.getConfiguration())
sink.getConfiguration() = unbind(mid.getConfiguration()) and
result = sink
)
}

View File

@@ -2041,12 +2041,12 @@ private class PathNodeMid extends PathNode, TPathNodeMid {
result = getSuccMid()
or
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid |
exists(PathNodeMid mid, PathNodeSink sink |
mid = getSuccMid() and
mid.getNode() = result.getNode() and
mid.getNode() = sink.getNode() and
mid.getAp() instanceof AccessPathNil and
result instanceof PathNodeSink and
result.getConfiguration() = unbind(mid.getConfiguration())
sink.getConfiguration() = unbind(mid.getConfiguration()) and
result = sink
)
}

View File

@@ -2041,12 +2041,12 @@ private class PathNodeMid extends PathNode, TPathNodeMid {
result = getSuccMid()
or
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid |
exists(PathNodeMid mid, PathNodeSink sink |
mid = getSuccMid() and
mid.getNode() = result.getNode() and
mid.getNode() = sink.getNode() and
mid.getAp() instanceof AccessPathNil and
result instanceof PathNodeSink and
result.getConfiguration() = unbind(mid.getConfiguration())
sink.getConfiguration() = unbind(mid.getConfiguration()) and
result = sink
)
}

View File

@@ -2041,12 +2041,12 @@ private class PathNodeMid extends PathNode, TPathNodeMid {
result = getSuccMid()
or
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid |
exists(PathNodeMid mid, PathNodeSink sink |
mid = getSuccMid() and
mid.getNode() = result.getNode() and
mid.getNode() = sink.getNode() and
mid.getAp() instanceof AccessPathNil and
result instanceof PathNodeSink and
result.getConfiguration() = unbind(mid.getConfiguration())
sink.getConfiguration() = unbind(mid.getConfiguration()) and
result = sink
)
}

View File

@@ -2041,12 +2041,12 @@ private class PathNodeMid extends PathNode, TPathNodeMid {
result = getSuccMid()
or
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid |
exists(PathNodeMid mid, PathNodeSink sink |
mid = getSuccMid() and
mid.getNode() = result.getNode() and
mid.getNode() = sink.getNode() and
mid.getAp() instanceof AccessPathNil and
result instanceof PathNodeSink and
result.getConfiguration() = unbind(mid.getConfiguration())
sink.getConfiguration() = unbind(mid.getConfiguration()) and
result = sink
)
}

View File

@@ -2041,12 +2041,12 @@ private class PathNodeMid extends PathNode, TPathNodeMid {
result = getSuccMid()
or
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid |
exists(PathNodeMid mid, PathNodeSink sink |
mid = getSuccMid() and
mid.getNode() = result.getNode() and
mid.getNode() = sink.getNode() and
mid.getAp() instanceof AccessPathNil and
result instanceof PathNodeSink and
result.getConfiguration() = unbind(mid.getConfiguration())
sink.getConfiguration() = unbind(mid.getConfiguration()) and
result = sink
)
}

View File

@@ -2041,12 +2041,12 @@ private class PathNodeMid extends PathNode, TPathNodeMid {
result = getSuccMid()
or
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid |
exists(PathNodeMid mid, PathNodeSink sink |
mid = getSuccMid() and
mid.getNode() = result.getNode() and
mid.getNode() = sink.getNode() and
mid.getAp() instanceof AccessPathNil and
result instanceof PathNodeSink and
result.getConfiguration() = unbind(mid.getConfiguration())
sink.getConfiguration() = unbind(mid.getConfiguration()) and
result = sink
)
}

View File

@@ -2041,12 +2041,12 @@ private class PathNodeMid extends PathNode, TPathNodeMid {
result = getSuccMid()
or
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid |
exists(PathNodeMid mid, PathNodeSink sink |
mid = getSuccMid() and
mid.getNode() = result.getNode() and
mid.getNode() = sink.getNode() and
mid.getAp() instanceof AccessPathNil and
result instanceof PathNodeSink and
result.getConfiguration() = unbind(mid.getConfiguration())
sink.getConfiguration() = unbind(mid.getConfiguration()) and
result = sink
)
}

View File

@@ -2041,12 +2041,12 @@ private class PathNodeMid extends PathNode, TPathNodeMid {
result = getSuccMid()
or
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid |
exists(PathNodeMid mid, PathNodeSink sink |
mid = getSuccMid() and
mid.getNode() = result.getNode() and
mid.getNode() = sink.getNode() and
mid.getAp() instanceof AccessPathNil and
result instanceof PathNodeSink and
result.getConfiguration() = unbind(mid.getConfiguration())
sink.getConfiguration() = unbind(mid.getConfiguration()) and
result = sink
)
}

View File

@@ -63,6 +63,7 @@ private newtype TOpcode =
TUnmodeledDefinition() or
TUnmodeledUse() or
TAliasedDefinition() or
TInitializeNonLocal() or
TAliasedUse() or
TPhi() or
TBuiltIn() or
@@ -596,6 +597,14 @@ module Opcode {
final override MemoryAccessKind getWriteMemoryAccess() { result instanceof EscapedMemoryAccess }
}
class InitializeNonLocal extends Opcode, TInitializeNonLocal {
final override string toString() { result = "InitializeNonLocal" }
final override MemoryAccessKind getWriteMemoryAccess() {
result instanceof NonLocalMemoryAccess
}
}
class AliasedUse extends Opcode, TAliasedUse {
final override string toString() { result = "AliasedUse" }

View File

@@ -298,7 +298,7 @@ class AllNonLocalMemory extends TAllNonLocalMemory, MemoryLocation {
final override string toStringInternal() { result = "{AllNonLocal}" }
final override VirtualVariable getVirtualVariable() { result = TAllAliasedMemory(irFunc, false) }
final override AliasedVirtualVariable getVirtualVariable() { result.getIRFunction() = irFunc }
final override Language::LanguageType getType() {
result = any(IRUnknownType type).getCanonicalLanguageType()
@@ -311,6 +311,14 @@ class AllNonLocalMemory extends TAllNonLocalMemory, MemoryLocation {
final override string getUniqueId() { result = "{AllNonLocal}" }
final override predicate isMayAccess() { isMayAccess = true }
override predicate canDefineReadOnly() {
// A "must" access that defines all non-local memory appears only on the `InitializeNonLocal`
// instruction, which provides the initial definition for all memory outside of the current
// function's stack frame. This memory includes string literals and other read-only globals, so
// we allow such an access to be the definition for a use of a read-only location.
not isMayAccess()
}
}
/**
@@ -341,16 +349,6 @@ class AllAliasedMemory extends TAllAliasedMemory, MemoryLocation {
class AliasedVirtualVariable extends AllAliasedMemory, VirtualVariable {
AliasedVirtualVariable() { not isMayAccess() }
override predicate canDefineReadOnly() {
// A must-def of all aliased memory is only used in two places:
// 1. In the prologue of the function, to provide a definition for all memory defined before the
// function was called. In this case, it needs to provide a definition even for read-only
// non-local variables.
// 2. As the result of a `Chi` instruction. These don't participate in overlap analysis, so it's
// OK if we let this predicate hold in that case.
any()
}
}
/**
@@ -405,10 +403,16 @@ private Overlap getExtentOverlap(MemoryLocation def, MemoryLocation use) {
use instanceof AllNonLocalMemory and
result instanceof MustExactlyOverlap
or
// AllNonLocalMemory may partially overlap any location within the same virtual variable,
// except a local variable.
result instanceof MayPartiallyOverlap and
not use.isAlwaysAllocatedOnStack()
not use instanceof AllNonLocalMemory and
not use.isAlwaysAllocatedOnStack() and
if use instanceof VariableMemoryLocation
then
// AllNonLocalMemory totally overlaps any non-local variable.
result instanceof MustTotallyOverlap
else
// AllNonLocalMemory may partially overlap any other location within the same virtual
// variable, except a stack variable.
result instanceof MayPartiallyOverlap
)
or
def.getVirtualVariable() = use.getVirtualVariable() and

View File

@@ -759,7 +759,21 @@ module DefUse {
then defLocation = useLocation
else (
definitionHasPhiNode(defLocation, block) and
defLocation = useLocation.getVirtualVariable()
defLocation = useLocation.getVirtualVariable() and
// Handle the unusual case where a virtual variable does not overlap one of its member
// locations. For example, a definition of the virtual variable representing all aliased
// memory does not overlap a use of a string literal, because the contents of a string
// literal can never be redefined. The string literal's location could still be a member of
// the `AliasedVirtualVariable` due to something like:
// ```
// char s[10];
// strcpy(s, p);
// const char* p = b ? "SomeLiteral" : s;
// return p[3];
// ```
// In the above example, `p[3]` may access either the string literal or the local variable
// `s`, so both of those locations must be members of the `AliasedVirtualVariable`.
exists(Alias::getOverlap(defLocation, useLocation))
)
)
or

View File

@@ -26,6 +26,7 @@ newtype TInstructionTag =
UnmodeledDefinitionTag() or
UnmodeledUseTag() or
AliasedDefinitionTag() or
InitializeNonLocalTag() or
AliasedUseTag() or
SwitchBranchTag() or
CallTargetTag() or
@@ -120,6 +121,8 @@ string getInstructionTagId(TInstructionTag tag) {
or
tag = AliasedDefinitionTag() and result = "AliasedDef"
or
tag = InitializeNonLocalTag() and result = "InitNonLocal"
or
tag = AliasedUseTag() and result = "AliasedUse"
or
tag = SwitchBranchTag() and result = "SwitchBranch"

View File

@@ -71,6 +71,9 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction {
result = getInstruction(AliasedDefinitionTag())
or
tag = AliasedDefinitionTag() and
result = getInstruction(InitializeNonLocalTag())
or
tag = InitializeNonLocalTag() and
result = getInstruction(UnmodeledDefinitionTag())
or
(
@@ -144,6 +147,10 @@ class TranslatedFunction extends TranslatedElement, TTranslatedFunction {
opcode instanceof Opcode::AliasedDefinition and
resultType = getUnknownType()
or
tag = InitializeNonLocalTag() and
opcode instanceof Opcode::InitializeNonLocal and
resultType = getUnknownType()
or
tag = InitializeThisTag() and
opcode instanceof Opcode::InitializeThis and
resultType = getTypeForGLValue(getThisType())

View File

@@ -759,7 +759,21 @@ module DefUse {
then defLocation = useLocation
else (
definitionHasPhiNode(defLocation, block) and
defLocation = useLocation.getVirtualVariable()
defLocation = useLocation.getVirtualVariable() and
// Handle the unusual case where a virtual variable does not overlap one of its member
// locations. For example, a definition of the virtual variable representing all aliased
// memory does not overlap a use of a string literal, because the contents of a string
// literal can never be redefined. The string literal's location could still be a member of
// the `AliasedVirtualVariable` due to something like:
// ```
// char s[10];
// strcpy(s, p);
// const char* p = b ? "SomeLiteral" : s;
// return p[3];
// ```
// In the above example, `p[3]` may access either the string literal or the local variable
// `s`, so both of those locations must be members of the `AliasedVirtualVariable`.
exists(Alias::getOverlap(defLocation, useLocation))
)
)
or

View File

@@ -187,6 +187,13 @@ private predicate boundFlowStepSsa(
guard.controls(op2.getUse().getBlock(), testIsTrue) and
reason = TCondReason(guard)
)
or
exists(IRGuardCondition guard, boolean testIsTrue, SafeCastInstruction cast |
valueNumberOfOperand(op2) = valueNumber(cast.getUnary()) and
guard = boundFlowCond(valueNumber(cast), op1, delta, upper, testIsTrue) and
guard.controls(op2.getUse().getBlock(), testIsTrue) and
reason = TCondReason(guard)
)
}
/**
@@ -259,7 +266,7 @@ private predicate safeCast(IntegralType fromtyp, IntegralType totyp) {
private class SafeCastInstruction extends ConvertInstruction {
SafeCastInstruction() {
safeCast(getResultType(), getUnary().getResultType())
safeCast(getUnary().getResultType(), getResultType())
or
getResultType() instanceof PointerType and
getUnary().getResultType() instanceof PointerType

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -249,4 +249,16 @@ char *VoidStarIndirectParameters(char *src, int size) {
*src = 'a';
memcpy(dst, src, size);
return dst;
}
}
char StringLiteralAliasing2(bool b) {
if (b) {
ExternalFunc();
}
else {
ExternalFunc();
}
const char* s = "Literal";
return s[2];
}

File diff suppressed because it is too large Load Diff

View File

@@ -59,3 +59,6 @@
| test.cpp:183:10:183:10 | Load: i | test.cpp:175:23:175:23 | InitializeParameter: x | -1 | true | CompareLT: ... < ... | test.cpp:182:9:182:13 | test.cpp:182:9:182:13 |
| test.cpp:185:10:185:10 | Load: i | test.cpp:175:23:175:23 | InitializeParameter: x | 0 | true | CompareLT: ... < ... | test.cpp:176:7:176:11 | test.cpp:176:7:176:11 |
| test.cpp:187:10:187:10 | Store: i | test.cpp:175:23:175:23 | InitializeParameter: x | 0 | false | CompareLT: ... < ... | test.cpp:182:9:182:13 | test.cpp:182:9:182:13 |
| test.cpp:199:10:199:10 | Load: i | test.cpp:197:25:197:25 | InitializeParameter: l | -1 | true | CompareLT: ... < ... | test.cpp:198:7:198:11 | test.cpp:198:7:198:11 |
| test.cpp:202:11:202:11 | Load: i | test.cpp:197:25:197:25 | InitializeParameter: l | -3 | true | CompareLT: ... < ... | test.cpp:201:7:201:15 | test.cpp:201:7:201:15 |
| test.cpp:208:10:208:10 | Load: x | test.cpp:206:24:206:24 | InitializeParameter: y | -3 | true | CompareLT: ... < ... | test.cpp:207:7:207:15 | test.cpp:207:7:207:15 |

View File

@@ -186,3 +186,25 @@ int test15(int i, int x) {
}
return i;
}
// safe integer type conversion
int test16(int i) {
long l;
l = i;
}
// implicit integer casts
void test17(int i, long l) {
if (i < l) {
sink(i);
}
if (i < l - 2) {
sink (i);
}
}
void test18(int x, int y) {
if (x < y - 2) {
sink(x);
}
}

View File

@@ -4,16 +4,20 @@ test.cpp:
# 1| v1_1(void) = EnterFunction :
# 1| m1_2(unknown) = AliasedDefinition :
# 1| valnum = unique
# 1| mu1_3(unknown) = UnmodeledDefinition :
# 1| m1_3(unknown) = InitializeNonLocal :
# 1| valnum = unique
# 1| r1_4(glval<int>) = VariableAddress[p0] :
# 1| valnum = r1_4
# 1| m1_5(int) = InitializeParameter[p0] : &:r1_4
# 1| valnum = m1_5
# 1| r1_6(glval<int>) = VariableAddress[p1] :
# 1| m1_4(unknown) = Chi : total:m1_2, partial:m1_3
# 1| valnum = unique
# 1| mu1_5(unknown) = UnmodeledDefinition :
# 1| valnum = unique
# 1| r1_6(glval<int>) = VariableAddress[p0] :
# 1| valnum = r1_6
# 1| m1_7(int) = InitializeParameter[p1] : &:r1_6
# 1| m1_7(int) = InitializeParameter[p0] : &:r1_6
# 1| valnum = m1_7
# 1| r1_8(glval<int>) = VariableAddress[p1] :
# 1| valnum = r1_8
# 1| m1_9(int) = InitializeParameter[p1] : &:r1_8
# 1| valnum = m1_9
# 2| r2_1(glval<int>) = VariableAddress[x] :
# 2| valnum = r2_1
# 2| m2_2(int) = Uninitialized[x] : &:r2_1
@@ -27,13 +31,13 @@ test.cpp:
# 3| m3_2(unsigned char) = Uninitialized[b] : &:r3_1
# 3| valnum = unique
# 5| r5_1(glval<int>) = VariableAddress[p0] :
# 5| valnum = r1_4
# 5| r5_2(int) = Load : &:r5_1, m1_5
# 5| valnum = m1_5
# 5| r5_3(glval<int>) = VariableAddress[p1] :
# 5| valnum = r1_6
# 5| r5_4(int) = Load : &:r5_3, m1_7
# 5| r5_2(int) = Load : &:r5_1, m1_7
# 5| valnum = m1_7
# 5| r5_3(glval<int>) = VariableAddress[p1] :
# 5| valnum = r1_8
# 5| r5_4(int) = Load : &:r5_3, m1_9
# 5| valnum = m1_9
# 5| r5_5(int) = Add : r5_2, r5_4
# 5| valnum = r5_5
# 5| r5_6(glval<int>) = VariableAddress[x] :
@@ -41,13 +45,13 @@ test.cpp:
# 5| m5_7(int) = Store : &:r5_6, r5_5
# 5| valnum = r5_5
# 6| r6_1(glval<int>) = VariableAddress[p0] :
# 6| valnum = r1_4
# 6| r6_2(int) = Load : &:r6_1, m1_5
# 6| valnum = m1_5
# 6| r6_3(glval<int>) = VariableAddress[p1] :
# 6| valnum = r1_6
# 6| r6_4(int) = Load : &:r6_3, m1_7
# 6| r6_2(int) = Load : &:r6_1, m1_7
# 6| valnum = m1_7
# 6| r6_3(glval<int>) = VariableAddress[p1] :
# 6| valnum = r1_8
# 6| r6_4(int) = Load : &:r6_3, m1_9
# 6| valnum = m1_9
# 6| r6_5(int) = Add : r6_2, r6_4
# 6| valnum = r5_5
# 6| r6_6(glval<int>) = VariableAddress[x] :
@@ -63,28 +67,32 @@ test.cpp:
# 7| m7_4(int) = Store : &:r7_3, r7_2
# 7| valnum = r5_5
# 8| v8_1(void) = NoOp :
# 1| r1_8(glval<int>) = VariableAddress[#return] :
# 1| r1_10(glval<int>) = VariableAddress[#return] :
# 1| valnum = unique
# 1| v1_9(void) = ReturnValue : &:r1_8
# 1| v1_10(void) = UnmodeledUse : mu*
# 1| v1_11(void) = AliasedUse : ~m1_2
# 1| v1_12(void) = ExitFunction :
# 1| v1_11(void) = ReturnValue : &:r1_10
# 1| v1_12(void) = UnmodeledUse : mu*
# 1| v1_13(void) = AliasedUse : m1_3
# 1| v1_14(void) = ExitFunction :
# 12| int test01(int, int)
# 12| Block 0
# 12| v12_1(void) = EnterFunction :
# 12| m12_2(unknown) = AliasedDefinition :
# 12| valnum = unique
# 12| mu12_3(unknown) = UnmodeledDefinition :
# 12| m12_3(unknown) = InitializeNonLocal :
# 12| valnum = unique
# 12| r12_4(glval<int>) = VariableAddress[p0] :
# 12| valnum = r12_4
# 12| m12_5(int) = InitializeParameter[p0] : &:r12_4
# 12| valnum = m12_5
# 12| r12_6(glval<int>) = VariableAddress[p1] :
# 12| m12_4(unknown) = Chi : total:m12_2, partial:m12_3
# 12| valnum = unique
# 12| mu12_5(unknown) = UnmodeledDefinition :
# 12| valnum = unique
# 12| r12_6(glval<int>) = VariableAddress[p0] :
# 12| valnum = r12_6
# 12| m12_7(int) = InitializeParameter[p1] : &:r12_6
# 12| m12_7(int) = InitializeParameter[p0] : &:r12_6
# 12| valnum = m12_7
# 12| r12_8(glval<int>) = VariableAddress[p1] :
# 12| valnum = r12_8
# 12| m12_9(int) = InitializeParameter[p1] : &:r12_8
# 12| valnum = m12_9
# 13| r13_1(glval<int>) = VariableAddress[x] :
# 13| valnum = r13_1
# 13| m13_2(int) = Uninitialized[x] : &:r13_1
@@ -98,18 +106,18 @@ test.cpp:
# 14| m14_2(unsigned char) = Uninitialized[b] : &:r14_1
# 14| valnum = unique
# 16| r16_1(glval<int>) = VariableAddress[p0] :
# 16| valnum = r12_4
# 16| r16_2(int) = Load : &:r16_1, m12_5
# 16| valnum = m12_5
# 16| r16_3(glval<int>) = VariableAddress[p1] :
# 16| valnum = r12_6
# 16| r16_4(int) = Load : &:r16_3, m12_7
# 16| r16_2(int) = Load : &:r16_1, m12_7
# 16| valnum = m12_7
# 16| r16_3(glval<int>) = VariableAddress[p1] :
# 16| valnum = r12_8
# 16| r16_4(int) = Load : &:r16_3, m12_9
# 16| valnum = m12_9
# 16| r16_5(int) = Add : r16_2, r16_4
# 16| valnum = r16_5
# 16| r16_6(glval<int>) = VariableAddress[global01] :
# 16| valnum = r16_6
# 16| r16_7(int) = Load : &:r16_6, ~m12_2
# 16| r16_7(int) = Load : &:r16_6, ~m12_3
# 16| valnum = unique
# 16| r16_8(int) = Add : r16_5, r16_7
# 16| valnum = r16_8
@@ -118,18 +126,18 @@ test.cpp:
# 16| m16_10(int) = Store : &:r16_9, r16_8
# 16| valnum = r16_8
# 17| r17_1(glval<int>) = VariableAddress[p0] :
# 17| valnum = r12_4
# 17| r17_2(int) = Load : &:r17_1, m12_5
# 17| valnum = m12_5
# 17| r17_3(glval<int>) = VariableAddress[p1] :
# 17| valnum = r12_6
# 17| r17_4(int) = Load : &:r17_3, m12_7
# 17| r17_2(int) = Load : &:r17_1, m12_7
# 17| valnum = m12_7
# 17| r17_3(glval<int>) = VariableAddress[p1] :
# 17| valnum = r12_8
# 17| r17_4(int) = Load : &:r17_3, m12_9
# 17| valnum = m12_9
# 17| r17_5(int) = Add : r17_2, r17_4
# 17| valnum = r16_5
# 17| r17_6(glval<int>) = VariableAddress[global01] :
# 17| valnum = r16_6
# 17| r17_7(int) = Load : &:r17_6, ~m12_2
# 17| r17_7(int) = Load : &:r17_6, ~m12_3
# 17| valnum = unique
# 17| r17_8(int) = Add : r17_5, r17_7
# 17| valnum = r17_8
@@ -146,28 +154,32 @@ test.cpp:
# 18| m18_4(int) = Store : &:r18_3, r18_2
# 18| valnum = r17_8
# 19| v19_1(void) = NoOp :
# 12| r12_8(glval<int>) = VariableAddress[#return] :
# 12| r12_10(glval<int>) = VariableAddress[#return] :
# 12| valnum = unique
# 12| v12_9(void) = ReturnValue : &:r12_8
# 12| v12_10(void) = UnmodeledUse : mu*
# 12| v12_11(void) = AliasedUse : ~m12_2
# 12| v12_12(void) = ExitFunction :
# 12| v12_11(void) = ReturnValue : &:r12_10
# 12| v12_12(void) = UnmodeledUse : mu*
# 12| v12_13(void) = AliasedUse : m12_3
# 12| v12_14(void) = ExitFunction :
# 25| int test02(int, int)
# 25| Block 0
# 25| v25_1(void) = EnterFunction :
# 25| m25_2(unknown) = AliasedDefinition :
# 25| valnum = unique
# 25| mu25_3(unknown) = UnmodeledDefinition :
# 25| m25_3(unknown) = InitializeNonLocal :
# 25| valnum = unique
# 25| r25_4(glval<int>) = VariableAddress[p0] :
# 25| valnum = r25_4
# 25| m25_5(int) = InitializeParameter[p0] : &:r25_4
# 25| valnum = m25_5
# 25| r25_6(glval<int>) = VariableAddress[p1] :
# 25| m25_4(unknown) = Chi : total:m25_2, partial:m25_3
# 25| valnum = unique
# 25| mu25_5(unknown) = UnmodeledDefinition :
# 25| valnum = unique
# 25| r25_6(glval<int>) = VariableAddress[p0] :
# 25| valnum = r25_6
# 25| m25_7(int) = InitializeParameter[p1] : &:r25_6
# 25| m25_7(int) = InitializeParameter[p0] : &:r25_6
# 25| valnum = m25_7
# 25| r25_8(glval<int>) = VariableAddress[p1] :
# 25| valnum = r25_8
# 25| m25_9(int) = InitializeParameter[p1] : &:r25_8
# 25| valnum = m25_9
# 26| r26_1(glval<int>) = VariableAddress[x] :
# 26| valnum = r26_1
# 26| m26_2(int) = Uninitialized[x] : &:r26_1
@@ -181,18 +193,18 @@ test.cpp:
# 27| m27_2(unsigned char) = Uninitialized[b] : &:r27_1
# 27| valnum = unique
# 29| r29_1(glval<int>) = VariableAddress[p0] :
# 29| valnum = r25_4
# 29| r29_2(int) = Load : &:r29_1, m25_5
# 29| valnum = m25_5
# 29| r29_3(glval<int>) = VariableAddress[p1] :
# 29| valnum = r25_6
# 29| r29_4(int) = Load : &:r29_3, m25_7
# 29| r29_2(int) = Load : &:r29_1, m25_7
# 29| valnum = m25_7
# 29| r29_3(glval<int>) = VariableAddress[p1] :
# 29| valnum = r25_8
# 29| r29_4(int) = Load : &:r29_3, m25_9
# 29| valnum = m25_9
# 29| r29_5(int) = Add : r29_2, r29_4
# 29| valnum = r29_5
# 29| r29_6(glval<int>) = VariableAddress[global02] :
# 29| valnum = r29_6
# 29| r29_7(int) = Load : &:r29_6, ~m25_2
# 29| r29_7(int) = Load : &:r29_6, ~m25_3
# 29| valnum = unique
# 29| r29_8(int) = Add : r29_5, r29_7
# 29| valnum = r29_8
@@ -203,18 +215,18 @@ test.cpp:
# 30| r30_1(glval<unknown>) = FunctionAddress[change_global02] :
# 30| valnum = unique
# 30| v30_2(void) = Call : func:r30_1
# 30| m30_3(unknown) = ^CallSideEffect : ~m25_2
# 30| m30_3(unknown) = ^CallSideEffect : ~m25_4
# 30| valnum = unique
# 30| m30_4(unknown) = Chi : total:m25_2, partial:m30_3
# 30| m30_4(unknown) = Chi : total:m25_4, partial:m30_3
# 30| valnum = unique
# 31| r31_1(glval<int>) = VariableAddress[p0] :
# 31| valnum = r25_4
# 31| r31_2(int) = Load : &:r31_1, m25_5
# 31| valnum = m25_5
# 31| r31_3(glval<int>) = VariableAddress[p1] :
# 31| valnum = r25_6
# 31| r31_4(int) = Load : &:r31_3, m25_7
# 31| r31_2(int) = Load : &:r31_1, m25_7
# 31| valnum = m25_7
# 31| r31_3(glval<int>) = VariableAddress[p1] :
# 31| valnum = r25_8
# 31| r31_4(int) = Load : &:r31_3, m25_9
# 31| valnum = m25_9
# 31| r31_5(int) = Add : r31_2, r31_4
# 31| valnum = r29_5
# 31| r31_6(glval<int>) = VariableAddress[global02] :
@@ -236,35 +248,39 @@ test.cpp:
# 32| m32_4(int) = Store : &:r32_3, r32_2
# 32| valnum = r31_8
# 33| v33_1(void) = NoOp :
# 25| r25_8(glval<int>) = VariableAddress[#return] :
# 25| r25_10(glval<int>) = VariableAddress[#return] :
# 25| valnum = unique
# 25| v25_9(void) = ReturnValue : &:r25_8
# 25| v25_10(void) = UnmodeledUse : mu*
# 25| v25_11(void) = AliasedUse : ~m30_4
# 25| v25_12(void) = ExitFunction :
# 25| v25_11(void) = ReturnValue : &:r25_10
# 25| v25_12(void) = UnmodeledUse : mu*
# 25| v25_13(void) = AliasedUse : ~m30_4
# 25| v25_14(void) = ExitFunction :
# 39| int test03(int, int, int*)
# 39| Block 0
# 39| v39_1(void) = EnterFunction :
# 39| m39_2(unknown) = AliasedDefinition :
# 39| valnum = unique
# 39| mu39_3(unknown) = UnmodeledDefinition :
# 39| m39_3(unknown) = InitializeNonLocal :
# 39| valnum = unique
# 39| r39_4(glval<int>) = VariableAddress[p0] :
# 39| valnum = r39_4
# 39| m39_5(int) = InitializeParameter[p0] : &:r39_4
# 39| valnum = m39_5
# 39| r39_6(glval<int>) = VariableAddress[p1] :
# 39| m39_4(unknown) = Chi : total:m39_2, partial:m39_3
# 39| valnum = unique
# 39| mu39_5(unknown) = UnmodeledDefinition :
# 39| valnum = unique
# 39| r39_6(glval<int>) = VariableAddress[p0] :
# 39| valnum = r39_6
# 39| m39_7(int) = InitializeParameter[p1] : &:r39_6
# 39| m39_7(int) = InitializeParameter[p0] : &:r39_6
# 39| valnum = m39_7
# 39| r39_8(glval<int *>) = VariableAddress[p2] :
# 39| r39_8(glval<int>) = VariableAddress[p1] :
# 39| valnum = r39_8
# 39| m39_9(int *) = InitializeParameter[p2] : &:r39_8
# 39| m39_9(int) = InitializeParameter[p1] : &:r39_8
# 39| valnum = m39_9
# 39| r39_10(int *) = Load : &:r39_8, m39_9
# 39| valnum = m39_9
# 39| m39_11(unknown) = InitializeIndirection[p2] : &:r39_10
# 39| r39_10(glval<int *>) = VariableAddress[p2] :
# 39| valnum = r39_10
# 39| m39_11(int *) = InitializeParameter[p2] : &:r39_10
# 39| valnum = m39_11
# 39| r39_12(int *) = Load : &:r39_10, m39_11
# 39| valnum = m39_11
# 39| m39_13(unknown) = InitializeIndirection[p2] : &:r39_12
# 39| valnum = unique
# 40| r40_1(glval<int>) = VariableAddress[x] :
# 40| valnum = r40_1
@@ -279,18 +295,18 @@ test.cpp:
# 41| m41_2(unsigned char) = Uninitialized[b] : &:r41_1
# 41| valnum = unique
# 43| r43_1(glval<int>) = VariableAddress[p0] :
# 43| valnum = r39_4
# 43| r43_2(int) = Load : &:r43_1, m39_5
# 43| valnum = m39_5
# 43| r43_3(glval<int>) = VariableAddress[p1] :
# 43| valnum = r39_6
# 43| r43_4(int) = Load : &:r43_3, m39_7
# 43| r43_2(int) = Load : &:r43_1, m39_7
# 43| valnum = m39_7
# 43| r43_3(glval<int>) = VariableAddress[p1] :
# 43| valnum = r39_8
# 43| r43_4(int) = Load : &:r43_3, m39_9
# 43| valnum = m39_9
# 43| r43_5(int) = Add : r43_2, r43_4
# 43| valnum = r43_5
# 43| r43_6(glval<int>) = VariableAddress[global03] :
# 43| valnum = r43_6
# 43| r43_7(int) = Load : &:r43_6, ~m39_2
# 43| r43_7(int) = Load : &:r43_6, ~m39_3
# 43| valnum = unique
# 43| r43_8(int) = Add : r43_5, r43_7
# 43| valnum = r43_8
@@ -301,28 +317,28 @@ test.cpp:
# 44| r44_1(int) = Constant[0] :
# 44| valnum = r44_1
# 44| r44_2(glval<int *>) = VariableAddress[p2] :
# 44| valnum = r39_8
# 44| r44_3(int *) = Load : &:r44_2, m39_9
# 44| valnum = m39_9
# 44| valnum = r39_10
# 44| r44_3(int *) = Load : &:r44_2, m39_11
# 44| valnum = m39_11
# 44| r44_4(glval<int>) = CopyValue : r44_3
# 44| valnum = m39_9
# 44| valnum = m39_11
# 44| m44_5(int) = Store : &:r44_4, r44_1
# 44| valnum = r44_1
# 44| m44_6(unknown) = Chi : total:m39_11, partial:m44_5
# 44| m44_6(unknown) = Chi : total:m39_13, partial:m44_5
# 44| valnum = unique
# 45| r45_1(glval<int>) = VariableAddress[p0] :
# 45| valnum = r39_4
# 45| r45_2(int) = Load : &:r45_1, m39_5
# 45| valnum = m39_5
# 45| r45_3(glval<int>) = VariableAddress[p1] :
# 45| valnum = r39_6
# 45| r45_4(int) = Load : &:r45_3, m39_7
# 45| r45_2(int) = Load : &:r45_1, m39_7
# 45| valnum = m39_7
# 45| r45_3(glval<int>) = VariableAddress[p1] :
# 45| valnum = r39_8
# 45| r45_4(int) = Load : &:r45_3, m39_9
# 45| valnum = m39_9
# 45| r45_5(int) = Add : r45_2, r45_4
# 45| valnum = r43_5
# 45| r45_6(glval<int>) = VariableAddress[global03] :
# 45| valnum = r43_6
# 45| r45_7(int) = Load : &:r45_6, ~m39_2
# 45| r45_7(int) = Load : &:r45_6, ~m39_3
# 45| valnum = unique
# 45| r45_8(int) = Add : r45_5, r45_7
# 45| valnum = r45_8
@@ -339,36 +355,40 @@ test.cpp:
# 46| m46_4(int) = Store : &:r46_3, r46_2
# 46| valnum = r45_8
# 47| v47_1(void) = NoOp :
# 39| v39_12(void) = ReturnIndirection : &:r39_10, ~m44_6
# 39| r39_13(glval<int>) = VariableAddress[#return] :
# 39| v39_14(void) = ReturnIndirection : &:r39_12, ~m44_6
# 39| r39_15(glval<int>) = VariableAddress[#return] :
# 39| valnum = unique
# 39| v39_14(void) = ReturnValue : &:r39_13
# 39| v39_15(void) = UnmodeledUse : mu*
# 39| v39_16(void) = AliasedUse : ~m39_2
# 39| v39_17(void) = ExitFunction :
# 39| v39_16(void) = ReturnValue : &:r39_15
# 39| v39_17(void) = UnmodeledUse : mu*
# 39| v39_18(void) = AliasedUse : m39_3
# 39| v39_19(void) = ExitFunction :
# 49| unsigned int my_strspn(char const*, char const*)
# 49| Block 0
# 49| v49_1(void) = EnterFunction :
# 49| m49_2(unknown) = AliasedDefinition :
# 49| valnum = unique
# 49| mu49_3(unknown) = UnmodeledDefinition :
# 49| m49_3(unknown) = InitializeNonLocal :
# 49| valnum = unique
# 49| r49_4(glval<char *>) = VariableAddress[str] :
# 49| valnum = r49_4
# 49| m49_5(char *) = InitializeParameter[str] : &:r49_4
# 49| valnum = m49_5
# 49| r49_6(char *) = Load : &:r49_4, m49_5
# 49| valnum = m49_5
# 49| m49_7(unknown) = InitializeIndirection[str] : &:r49_6
# 49| m49_4(unknown) = Chi : total:m49_2, partial:m49_3
# 49| valnum = unique
# 49| r49_8(glval<char *>) = VariableAddress[chars] :
# 49| valnum = r49_8
# 49| m49_9(char *) = InitializeParameter[chars] : &:r49_8
# 49| valnum = m49_9
# 49| r49_10(char *) = Load : &:r49_8, m49_9
# 49| valnum = m49_9
# 49| m49_11(unknown) = InitializeIndirection[chars] : &:r49_10
# 49| mu49_5(unknown) = UnmodeledDefinition :
# 49| valnum = unique
# 49| r49_6(glval<char *>) = VariableAddress[str] :
# 49| valnum = r49_6
# 49| m49_7(char *) = InitializeParameter[str] : &:r49_6
# 49| valnum = m49_7
# 49| r49_8(char *) = Load : &:r49_6, m49_7
# 49| valnum = m49_7
# 49| m49_9(unknown) = InitializeIndirection[str] : &:r49_8
# 49| valnum = unique
# 49| r49_10(glval<char *>) = VariableAddress[chars] :
# 49| valnum = r49_10
# 49| m49_11(char *) = InitializeParameter[chars] : &:r49_10
# 49| valnum = m49_11
# 49| r49_12(char *) = Load : &:r49_10, m49_11
# 49| valnum = m49_11
# 49| m49_13(unknown) = InitializeIndirection[chars] : &:r49_12
# 49| valnum = unique
# 50| r50_1(glval<char *>) = VariableAddress[ptr] :
# 50| valnum = r50_1
@@ -386,10 +406,10 @@ test.cpp:
# 53| m53_1(unsigned int) = Phi : from 0:m51_3, from 8:m62_5
# 53| valnum = m53_1
# 53| r53_2(glval<char *>) = VariableAddress[str] :
# 53| valnum = r49_4
# 53| r53_3(char *) = Load : &:r53_2, m49_5
# 53| valnum = m49_5
# 53| r53_4(char) = Load : &:r53_3, ~m49_7
# 53| valnum = r49_6
# 53| r53_3(char *) = Load : &:r53_2, m49_7
# 53| valnum = m49_7
# 53| r53_4(char) = Load : &:r53_3, ~m49_9
# 53| valnum = unique
# 53| r53_5(int) = Convert : r53_4
# 53| valnum = unique
@@ -403,13 +423,13 @@ test.cpp:
# 55| Block 2
# 55| r55_1(glval<char *>) = VariableAddress[chars] :
# 55| valnum = r49_8
# 55| r55_2(char *) = Load : &:r55_1, m49_9
# 55| valnum = m49_9
# 55| valnum = r49_10
# 55| r55_2(char *) = Load : &:r55_1, m49_11
# 55| valnum = m49_11
# 55| r55_3(glval<char *>) = VariableAddress[ptr] :
# 55| valnum = r50_1
# 55| m55_4(char *) = Store : &:r55_3, r55_2
# 55| valnum = m49_9
# 55| valnum = m49_11
#-----| Goto -> Block 3
# 56| Block 3
@@ -419,15 +439,15 @@ test.cpp:
# 56| valnum = r50_1
# 56| r56_3(char *) = Load : &:r56_2, m56_1
# 56| valnum = m56_1
# 56| r56_4(char) = Load : &:r56_3, ~m49_2
# 56| r56_4(char) = Load : &:r56_3, ~m49_4
# 56| valnum = unique
# 56| r56_5(int) = Convert : r56_4
# 56| valnum = unique
# 56| r56_6(glval<char *>) = VariableAddress[str] :
# 56| valnum = r49_4
# 56| r56_7(char *) = Load : &:r56_6, m49_5
# 56| valnum = m49_5
# 56| r56_8(char) = Load : &:r56_7, ~m49_7
# 56| valnum = r49_6
# 56| r56_7(char *) = Load : &:r56_6, m49_7
# 56| valnum = m49_7
# 56| r56_8(char) = Load : &:r56_7, ~m49_9
# 56| valnum = unique
# 56| r56_9(int) = Convert : r56_8
# 56| valnum = unique
@@ -442,7 +462,7 @@ test.cpp:
# 56| valnum = r50_1
# 56| r56_13(char *) = Load : &:r56_12, m56_1
# 56| valnum = m56_1
# 56| r56_14(char) = Load : &:r56_13, ~m49_2
# 56| r56_14(char) = Load : &:r56_13, ~m49_4
# 56| valnum = unique
# 56| r56_15(int) = Convert : r56_14
# 56| valnum = unique
@@ -472,7 +492,7 @@ test.cpp:
# 59| valnum = r50_1
# 59| r59_2(char *) = Load : &:r59_1, m56_1
# 59| valnum = m56_1
# 59| r59_3(char) = Load : &:r59_2, ~m49_2
# 59| r59_3(char) = Load : &:r59_2, ~m49_4
# 59| valnum = unique
# 59| r59_4(int) = Convert : r59_3
# 59| valnum = unique
@@ -511,29 +531,33 @@ test.cpp:
# 65| valnum = m53_1
# 65| m65_4(unsigned int) = Store : &:r65_1, r65_3
# 65| valnum = m53_1
# 49| v49_12(void) = ReturnIndirection : &:r49_6, m49_7
# 49| v49_13(void) = ReturnIndirection : &:r49_10, m49_11
# 49| r49_14(glval<unsigned int>) = VariableAddress[#return] :
# 49| v49_14(void) = ReturnIndirection : &:r49_8, m49_9
# 49| v49_15(void) = ReturnIndirection : &:r49_12, m49_13
# 49| r49_16(glval<unsigned int>) = VariableAddress[#return] :
# 49| valnum = r65_1
# 49| v49_15(void) = ReturnValue : &:r49_14, m65_4
# 49| v49_16(void) = UnmodeledUse : mu*
# 49| v49_17(void) = AliasedUse : ~m49_2
# 49| v49_18(void) = ExitFunction :
# 49| v49_17(void) = ReturnValue : &:r49_16, m65_4
# 49| v49_18(void) = UnmodeledUse : mu*
# 49| v49_19(void) = AliasedUse : m49_3
# 49| v49_20(void) = ExitFunction :
# 75| void test04(two_values*)
# 75| Block 0
# 75| v75_1(void) = EnterFunction :
# 75| m75_2(unknown) = AliasedDefinition :
# 75| valnum = unique
# 75| mu75_3(unknown) = UnmodeledDefinition :
# 75| m75_3(unknown) = InitializeNonLocal :
# 75| valnum = unique
# 75| r75_4(glval<two_values *>) = VariableAddress[vals] :
# 75| valnum = r75_4
# 75| m75_5(two_values *) = InitializeParameter[vals] : &:r75_4
# 75| valnum = m75_5
# 75| r75_6(two_values *) = Load : &:r75_4, m75_5
# 75| valnum = m75_5
# 75| m75_7(unknown) = InitializeIndirection[vals] : &:r75_6
# 75| m75_4(unknown) = Chi : total:m75_2, partial:m75_3
# 75| valnum = unique
# 75| mu75_5(unknown) = UnmodeledDefinition :
# 75| valnum = unique
# 75| r75_6(glval<two_values *>) = VariableAddress[vals] :
# 75| valnum = r75_6
# 75| m75_7(two_values *) = InitializeParameter[vals] : &:r75_6
# 75| valnum = m75_7
# 75| r75_8(two_values *) = Load : &:r75_6, m75_7
# 75| valnum = m75_7
# 75| m75_9(unknown) = InitializeIndirection[vals] : &:r75_8
# 75| valnum = unique
# 77| r77_1(glval<signed short>) = VariableAddress[v] :
# 77| valnum = r77_1
@@ -541,9 +565,9 @@ test.cpp:
# 77| valnum = unique
# 77| r77_3(int) = Call : func:r77_2
# 77| valnum = unique
# 77| m77_4(unknown) = ^CallSideEffect : ~m75_2
# 77| m77_4(unknown) = ^CallSideEffect : ~m75_4
# 77| valnum = unique
# 77| m77_5(unknown) = Chi : total:m75_2, partial:m77_4
# 77| m77_5(unknown) = Chi : total:m75_4, partial:m77_4
# 77| valnum = unique
# 77| r77_6(signed short) = Convert : r77_3
# 77| valnum = r77_6
@@ -556,22 +580,22 @@ test.cpp:
# 79| r79_3(int) = Convert : r79_2
# 79| valnum = unique
# 79| r79_4(glval<two_values *>) = VariableAddress[vals] :
# 79| valnum = r75_4
# 79| r79_5(two_values *) = Load : &:r79_4, m75_5
# 79| valnum = m75_5
# 79| valnum = r75_6
# 79| r79_5(two_values *) = Load : &:r79_4, m75_7
# 79| valnum = m75_7
# 79| r79_6(glval<signed short>) = FieldAddress[val1] : r79_5
# 79| valnum = unique
# 79| r79_7(signed short) = Load : &:r79_6, ~m75_7
# 79| r79_7(signed short) = Load : &:r79_6, ~m75_9
# 79| valnum = unique
# 79| r79_8(int) = Convert : r79_7
# 79| valnum = unique
# 79| r79_9(glval<two_values *>) = VariableAddress[vals] :
# 79| valnum = r75_4
# 79| r79_10(two_values *) = Load : &:r79_9, m75_5
# 79| valnum = m75_5
# 79| valnum = r75_6
# 79| r79_10(two_values *) = Load : &:r79_9, m75_7
# 79| valnum = m75_7
# 79| r79_11(glval<signed short>) = FieldAddress[val2] : r79_10
# 79| valnum = unique
# 79| r79_12(signed short) = Load : &:r79_11, ~m75_7
# 79| r79_12(signed short) = Load : &:r79_11, ~m75_9
# 79| valnum = unique
# 79| r79_13(int) = Convert : r79_12
# 79| valnum = unique
@@ -604,48 +628,52 @@ test.cpp:
# 82| m82_1(unknown) = Phi : from 0:~m77_5, from 1:~m80_4
# 82| valnum = unique
# 82| v82_2(void) = NoOp :
# 75| v75_8(void) = ReturnIndirection : &:r75_6, m75_7
# 75| v75_9(void) = ReturnVoid :
# 75| v75_10(void) = UnmodeledUse : mu*
# 75| v75_11(void) = AliasedUse : ~m82_1
# 75| v75_12(void) = ExitFunction :
# 75| v75_10(void) = ReturnIndirection : &:r75_8, m75_9
# 75| v75_11(void) = ReturnVoid :
# 75| v75_12(void) = UnmodeledUse : mu*
# 75| v75_13(void) = AliasedUse : ~m82_1
# 75| v75_14(void) = ExitFunction :
# 84| void test05(int, int, void*)
# 84| Block 0
# 84| v84_1(void) = EnterFunction :
# 84| m84_2(unknown) = AliasedDefinition :
# 84| v84_1(void) = EnterFunction :
# 84| m84_2(unknown) = AliasedDefinition :
# 84| valnum = unique
# 84| mu84_3(unknown) = UnmodeledDefinition :
# 84| m84_3(unknown) = InitializeNonLocal :
# 84| valnum = unique
# 84| r84_4(glval<int>) = VariableAddress[x] :
# 84| valnum = r84_4
# 84| m84_5(int) = InitializeParameter[x] : &:r84_4
# 84| valnum = m84_5
# 84| r84_6(glval<int>) = VariableAddress[y] :
# 84| m84_4(unknown) = Chi : total:m84_2, partial:m84_3
# 84| valnum = unique
# 84| mu84_5(unknown) = UnmodeledDefinition :
# 84| valnum = unique
# 84| r84_6(glval<int>) = VariableAddress[x] :
# 84| valnum = r84_6
# 84| m84_7(int) = InitializeParameter[y] : &:r84_6
# 84| m84_7(int) = InitializeParameter[x] : &:r84_6
# 84| valnum = m84_7
# 84| r84_8(glval<void *>) = VariableAddress[p] :
# 84| r84_8(glval<int>) = VariableAddress[y] :
# 84| valnum = r84_8
# 84| m84_9(void *) = InitializeParameter[p] : &:r84_8
# 84| m84_9(int) = InitializeParameter[y] : &:r84_8
# 84| valnum = m84_9
# 84| r84_10(void *) = Load : &:r84_8, m84_9
# 84| valnum = m84_9
# 84| m84_11(unknown) = InitializeIndirection[p] : &:r84_10
# 84| r84_10(glval<void *>) = VariableAddress[p] :
# 84| valnum = r84_10
# 84| m84_11(void *) = InitializeParameter[p] : &:r84_10
# 84| valnum = m84_11
# 84| r84_12(void *) = Load : &:r84_10, m84_11
# 84| valnum = m84_11
# 84| m84_13(unknown) = InitializeIndirection[p] : &:r84_12
# 84| valnum = unique
# 86| r86_1(glval<int>) = VariableAddress[v] :
# 86| r86_1(glval<int>) = VariableAddress[v] :
# 86| valnum = r86_1
# 86| m86_2(int) = Uninitialized[v] : &:r86_1
# 86| m86_2(int) = Uninitialized[v] : &:r86_1
# 86| valnum = unique
# 88| r88_1(glval<void *>) = VariableAddress[p] :
# 88| valnum = r84_8
# 88| r88_2(void *) = Load : &:r88_1, m84_9
# 88| valnum = m84_9
# 88| r88_3(void *) = Constant[0] :
# 88| r88_1(glval<void *>) = VariableAddress[p] :
# 88| valnum = r84_10
# 88| r88_2(void *) = Load : &:r88_1, m84_11
# 88| valnum = m84_11
# 88| r88_3(void *) = Constant[0] :
# 88| valnum = unique
# 88| r88_4(bool) = CompareNE : r88_2, r88_3
# 88| r88_4(bool) = CompareNE : r88_2, r88_3
# 88| valnum = unique
# 88| v88_5(void) = ConditionalBranch : r88_4
# 88| v88_5(void) = ConditionalBranch : r88_4
#-----| False -> Block 3
#-----| True -> Block 2
@@ -661,32 +689,32 @@ test.cpp:
# 88| m88_10(int) = Store : &:r88_9, r88_8
# 88| valnum = m88_6
# 89| v89_1(void) = NoOp :
# 84| v84_12(void) = ReturnIndirection : &:r84_10, m84_11
# 84| v84_13(void) = ReturnVoid :
# 84| v84_14(void) = UnmodeledUse : mu*
# 84| v84_15(void) = AliasedUse : ~m84_2
# 84| v84_16(void) = ExitFunction :
# 84| v84_14(void) = ReturnIndirection : &:r84_12, m84_13
# 84| v84_15(void) = ReturnVoid :
# 84| v84_16(void) = UnmodeledUse : mu*
# 84| v84_17(void) = AliasedUse : m84_3
# 84| v84_18(void) = ExitFunction :
# 88| Block 2
# 88| r88_11(glval<int>) = VariableAddress[x] :
# 88| valnum = r84_4
# 88| r88_12(int) = Load : &:r88_11, m84_5
# 88| valnum = m84_5
# 88| valnum = r84_6
# 88| r88_12(int) = Load : &:r88_11, m84_7
# 88| valnum = m84_7
# 88| r88_13(glval<int>) = VariableAddress[#temp88:7] :
# 88| valnum = r88_7
# 88| m88_14(int) = Store : &:r88_13, r88_12
# 88| valnum = m84_5
# 88| valnum = m84_7
#-----| Goto -> Block 1
# 88| Block 3
# 88| r88_15(glval<int>) = VariableAddress[y] :
# 88| valnum = r84_6
# 88| r88_16(int) = Load : &:r88_15, m84_7
# 88| valnum = m84_7
# 88| valnum = r84_8
# 88| r88_16(int) = Load : &:r88_15, m84_9
# 88| valnum = m84_9
# 88| r88_17(glval<int>) = VariableAddress[#temp88:7] :
# 88| valnum = r88_7
# 88| m88_18(int) = Store : &:r88_17, r88_16
# 88| valnum = m84_7
# 88| valnum = m84_9
#-----| Goto -> Block 1
# 91| int regression_test00()
@@ -694,7 +722,11 @@ test.cpp:
# 91| v91_1(void) = EnterFunction :
# 91| m91_2(unknown) = AliasedDefinition :
# 91| valnum = unique
# 91| mu91_3(unknown) = UnmodeledDefinition :
# 91| m91_3(unknown) = InitializeNonLocal :
# 91| valnum = unique
# 91| m91_4(unknown) = Chi : total:m91_2, partial:m91_3
# 91| valnum = unique
# 91| mu91_5(unknown) = UnmodeledDefinition :
# 91| valnum = unique
# 92| r92_1(glval<int>) = VariableAddress[x] :
# 92| valnum = r92_1
@@ -716,48 +748,52 @@ test.cpp:
# 93| valnum = r92_2
# 93| m93_4(int) = Store : &:r93_1, r93_3
# 93| valnum = r92_2
# 91| r91_4(glval<int>) = VariableAddress[#return] :
# 91| r91_6(glval<int>) = VariableAddress[#return] :
# 91| valnum = r93_1
# 91| v91_5(void) = ReturnValue : &:r91_4, m93_4
# 91| v91_6(void) = UnmodeledUse : mu*
# 91| v91_7(void) = AliasedUse : ~m91_2
# 91| v91_8(void) = ExitFunction :
# 91| v91_7(void) = ReturnValue : &:r91_6, m93_4
# 91| v91_8(void) = UnmodeledUse : mu*
# 91| v91_9(void) = AliasedUse : m91_3
# 91| v91_10(void) = ExitFunction :
# 104| int inheritanceConversions(Derived*)
# 104| Block 0
# 104| v104_1(void) = EnterFunction :
# 104| m104_2(unknown) = AliasedDefinition :
# 104| valnum = unique
# 104| mu104_3(unknown) = UnmodeledDefinition :
# 104| m104_3(unknown) = InitializeNonLocal :
# 104| valnum = unique
# 104| r104_4(glval<Derived *>) = VariableAddress[pd] :
# 104| valnum = r104_4
# 104| m104_5(Derived *) = InitializeParameter[pd] : &:r104_4
# 104| valnum = m104_5
# 104| r104_6(Derived *) = Load : &:r104_4, m104_5
# 104| valnum = m104_5
# 104| m104_7(unknown) = InitializeIndirection[pd] : &:r104_6
# 104| m104_4(unknown) = Chi : total:m104_2, partial:m104_3
# 104| valnum = unique
# 104| mu104_5(unknown) = UnmodeledDefinition :
# 104| valnum = unique
# 104| r104_6(glval<Derived *>) = VariableAddress[pd] :
# 104| valnum = r104_6
# 104| m104_7(Derived *) = InitializeParameter[pd] : &:r104_6
# 104| valnum = m104_7
# 104| r104_8(Derived *) = Load : &:r104_6, m104_7
# 104| valnum = m104_7
# 104| m104_9(unknown) = InitializeIndirection[pd] : &:r104_8
# 104| valnum = unique
# 105| r105_1(glval<int>) = VariableAddress[x] :
# 105| valnum = unique
# 105| r105_2(glval<Derived *>) = VariableAddress[pd] :
# 105| valnum = r104_4
# 105| r105_3(Derived *) = Load : &:r105_2, m104_5
# 105| valnum = m104_5
# 105| valnum = r104_6
# 105| r105_3(Derived *) = Load : &:r105_2, m104_7
# 105| valnum = m104_7
# 105| r105_4(Base *) = ConvertToNonVirtualBase[Derived : Base] : r105_3
# 105| valnum = r105_4
# 105| r105_5(glval<int>) = FieldAddress[b] : r105_4
# 105| valnum = r105_5
# 105| r105_6(int) = Load : &:r105_5, ~m104_7
# 105| r105_6(int) = Load : &:r105_5, ~m104_9
# 105| valnum = r105_6
# 105| m105_7(int) = Store : &:r105_1, r105_6
# 105| valnum = r105_6
# 106| r106_1(glval<Base *>) = VariableAddress[pb] :
# 106| valnum = r106_1
# 106| r106_2(glval<Derived *>) = VariableAddress[pd] :
# 106| valnum = r104_4
# 106| r106_3(Derived *) = Load : &:r106_2, m104_5
# 106| valnum = m104_5
# 106| valnum = r104_6
# 106| r106_3(Derived *) = Load : &:r106_2, m104_7
# 106| valnum = m104_7
# 106| r106_4(Base *) = ConvertToNonVirtualBase[Derived : Base] : r106_3
# 106| valnum = r105_4
# 106| m106_5(Base *) = Store : &:r106_1, r106_4
@@ -770,7 +806,7 @@ test.cpp:
# 107| valnum = r105_4
# 107| r107_4(glval<int>) = FieldAddress[b] : r107_3
# 107| valnum = r105_5
# 107| r107_5(int) = Load : &:r107_4, ~m104_7
# 107| r107_5(int) = Load : &:r107_4, ~m104_9
# 107| valnum = r107_5
# 107| m107_6(int) = Store : &:r107_1, r107_5
# 107| valnum = r107_5
@@ -782,20 +818,24 @@ test.cpp:
# 109| valnum = r107_5
# 109| m109_4(int) = Store : &:r109_1, r109_3
# 109| valnum = r107_5
# 104| v104_8(void) = ReturnIndirection : &:r104_6, m104_7
# 104| r104_9(glval<int>) = VariableAddress[#return] :
# 104| v104_10(void) = ReturnIndirection : &:r104_8, m104_9
# 104| r104_11(glval<int>) = VariableAddress[#return] :
# 104| valnum = r109_1
# 104| v104_10(void) = ReturnValue : &:r104_9, m109_4
# 104| v104_11(void) = UnmodeledUse : mu*
# 104| v104_12(void) = AliasedUse : ~m104_2
# 104| v104_13(void) = ExitFunction :
# 104| v104_12(void) = ReturnValue : &:r104_11, m109_4
# 104| v104_13(void) = UnmodeledUse : mu*
# 104| v104_14(void) = AliasedUse : m104_3
# 104| v104_15(void) = ExitFunction :
# 112| void test06()
# 112| Block 0
# 112| v112_1(void) = EnterFunction :
# 112| m112_2(unknown) = AliasedDefinition :
# 112| valnum = unique
# 112| mu112_3(unknown) = UnmodeledDefinition :
# 112| m112_3(unknown) = InitializeNonLocal :
# 112| valnum = unique
# 112| m112_4(unknown) = Chi : total:m112_2, partial:m112_3
# 112| valnum = unique
# 112| mu112_5(unknown) = UnmodeledDefinition :
# 112| valnum = unique
# 113| r113_1(glval<char[2]>) = StringConstant["a"] :
# 113| valnum = r113_1
@@ -806,7 +846,7 @@ test.cpp:
# 116| r116_1(glval<char[2]>) = StringConstant["c"] :
# 116| valnum = unique
# 117| v117_1(void) = NoOp :
# 112| v112_4(void) = ReturnVoid :
# 112| v112_5(void) = UnmodeledUse : mu*
# 112| v112_6(void) = AliasedUse : ~m112_2
# 112| v112_7(void) = ExitFunction :
# 112| v112_6(void) = ReturnVoid :
# 112| v112_7(void) = UnmodeledUse : mu*
# 112| v112_8(void) = AliasedUse : m112_3
# 112| v112_9(void) = ExitFunction :

View File

@@ -2041,12 +2041,12 @@ private class PathNodeMid extends PathNode, TPathNodeMid {
result = getSuccMid()
or
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid |
exists(PathNodeMid mid, PathNodeSink sink |
mid = getSuccMid() and
mid.getNode() = result.getNode() and
mid.getNode() = sink.getNode() and
mid.getAp() instanceof AccessPathNil and
result instanceof PathNodeSink and
result.getConfiguration() = unbind(mid.getConfiguration())
sink.getConfiguration() = unbind(mid.getConfiguration()) and
result = sink
)
}

View File

@@ -2041,12 +2041,12 @@ private class PathNodeMid extends PathNode, TPathNodeMid {
result = getSuccMid()
or
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid |
exists(PathNodeMid mid, PathNodeSink sink |
mid = getSuccMid() and
mid.getNode() = result.getNode() and
mid.getNode() = sink.getNode() and
mid.getAp() instanceof AccessPathNil and
result instanceof PathNodeSink and
result.getConfiguration() = unbind(mid.getConfiguration())
sink.getConfiguration() = unbind(mid.getConfiguration()) and
result = sink
)
}

View File

@@ -2041,12 +2041,12 @@ private class PathNodeMid extends PathNode, TPathNodeMid {
result = getSuccMid()
or
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid |
exists(PathNodeMid mid, PathNodeSink sink |
mid = getSuccMid() and
mid.getNode() = result.getNode() and
mid.getNode() = sink.getNode() and
mid.getAp() instanceof AccessPathNil and
result instanceof PathNodeSink and
result.getConfiguration() = unbind(mid.getConfiguration())
sink.getConfiguration() = unbind(mid.getConfiguration()) and
result = sink
)
}

View File

@@ -2041,12 +2041,12 @@ private class PathNodeMid extends PathNode, TPathNodeMid {
result = getSuccMid()
or
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid |
exists(PathNodeMid mid, PathNodeSink sink |
mid = getSuccMid() and
mid.getNode() = result.getNode() and
mid.getNode() = sink.getNode() and
mid.getAp() instanceof AccessPathNil and
result instanceof PathNodeSink and
result.getConfiguration() = unbind(mid.getConfiguration())
sink.getConfiguration() = unbind(mid.getConfiguration()) and
result = sink
)
}

View File

@@ -2041,12 +2041,12 @@ private class PathNodeMid extends PathNode, TPathNodeMid {
result = getSuccMid()
or
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid |
exists(PathNodeMid mid, PathNodeSink sink |
mid = getSuccMid() and
mid.getNode() = result.getNode() and
mid.getNode() = sink.getNode() and
mid.getAp() instanceof AccessPathNil and
result instanceof PathNodeSink and
result.getConfiguration() = unbind(mid.getConfiguration())
sink.getConfiguration() = unbind(mid.getConfiguration()) and
result = sink
)
}

View File

@@ -63,6 +63,7 @@ private newtype TOpcode =
TUnmodeledDefinition() or
TUnmodeledUse() or
TAliasedDefinition() or
TInitializeNonLocal() or
TAliasedUse() or
TPhi() or
TBuiltIn() or
@@ -596,6 +597,14 @@ module Opcode {
final override MemoryAccessKind getWriteMemoryAccess() { result instanceof EscapedMemoryAccess }
}
class InitializeNonLocal extends Opcode, TInitializeNonLocal {
final override string toString() { result = "InitializeNonLocal" }
final override MemoryAccessKind getWriteMemoryAccess() {
result instanceof NonLocalMemoryAccess
}
}
class AliasedUse extends Opcode, TAliasedUse {
final override string toString() { result = "AliasedUse" }

View File

@@ -759,7 +759,21 @@ module DefUse {
then defLocation = useLocation
else (
definitionHasPhiNode(defLocation, block) and
defLocation = useLocation.getVirtualVariable()
defLocation = useLocation.getVirtualVariable() and
// Handle the unusual case where a virtual variable does not overlap one of its member
// locations. For example, a definition of the virtual variable representing all aliased
// memory does not overlap a use of a string literal, because the contents of a string
// literal can never be redefined. The string literal's location could still be a member of
// the `AliasedVirtualVariable` due to something like:
// ```
// char s[10];
// strcpy(s, p);
// const char* p = b ? "SomeLiteral" : s;
// return p[3];
// ```
// In the above example, `p[3]` may access either the string literal or the local variable
// `s`, so both of those locations must be members of the `AliasedVirtualVariable`.
exists(Alias::getOverlap(defLocation, useLocation))
)
)
or

View File

@@ -167,6 +167,7 @@ class CompileTimeConstantExpr extends Expr {
/**
* Gets the string value of this expression, where possible.
*/
pragma[nomagic]
string getStringValue() {
result = this.(StringLiteral).getRepresentedString()
or

View File

@@ -2041,12 +2041,12 @@ private class PathNodeMid extends PathNode, TPathNodeMid {
result = getSuccMid()
or
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid |
exists(PathNodeMid mid, PathNodeSink sink |
mid = getSuccMid() and
mid.getNode() = result.getNode() and
mid.getNode() = sink.getNode() and
mid.getAp() instanceof AccessPathNil and
result instanceof PathNodeSink and
result.getConfiguration() = unbind(mid.getConfiguration())
sink.getConfiguration() = unbind(mid.getConfiguration()) and
result = sink
)
}

View File

@@ -2041,12 +2041,12 @@ private class PathNodeMid extends PathNode, TPathNodeMid {
result = getSuccMid()
or
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid |
exists(PathNodeMid mid, PathNodeSink sink |
mid = getSuccMid() and
mid.getNode() = result.getNode() and
mid.getNode() = sink.getNode() and
mid.getAp() instanceof AccessPathNil and
result instanceof PathNodeSink and
result.getConfiguration() = unbind(mid.getConfiguration())
sink.getConfiguration() = unbind(mid.getConfiguration()) and
result = sink
)
}

View File

@@ -2041,12 +2041,12 @@ private class PathNodeMid extends PathNode, TPathNodeMid {
result = getSuccMid()
or
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid |
exists(PathNodeMid mid, PathNodeSink sink |
mid = getSuccMid() and
mid.getNode() = result.getNode() and
mid.getNode() = sink.getNode() and
mid.getAp() instanceof AccessPathNil and
result instanceof PathNodeSink and
result.getConfiguration() = unbind(mid.getConfiguration())
sink.getConfiguration() = unbind(mid.getConfiguration()) and
result = sink
)
}

View File

@@ -2041,12 +2041,12 @@ private class PathNodeMid extends PathNode, TPathNodeMid {
result = getSuccMid()
or
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid |
exists(PathNodeMid mid, PathNodeSink sink |
mid = getSuccMid() and
mid.getNode() = result.getNode() and
mid.getNode() = sink.getNode() and
mid.getAp() instanceof AccessPathNil and
result instanceof PathNodeSink and
result.getConfiguration() = unbind(mid.getConfiguration())
sink.getConfiguration() = unbind(mid.getConfiguration()) and
result = sink
)
}

View File

@@ -2041,12 +2041,12 @@ private class PathNodeMid extends PathNode, TPathNodeMid {
result = getSuccMid()
or
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid |
exists(PathNodeMid mid, PathNodeSink sink |
mid = getSuccMid() and
mid.getNode() = result.getNode() and
mid.getNode() = sink.getNode() and
mid.getAp() instanceof AccessPathNil and
result instanceof PathNodeSink and
result.getConfiguration() = unbind(mid.getConfiguration())
sink.getConfiguration() = unbind(mid.getConfiguration()) and
result = sink
)
}

View File

@@ -0,0 +1,65 @@
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.io.IOUtils;
class Test {
public static void ioutils() {
InputStream inp = new FileInputStream("test"); // user input
InputStream buf = IOUtils.buffer(inp);
List<String> lines = IOUtils.readLines(inp, "UTF-8");
byte[] bytes = IOUtils.readFully(inp, 1000);
InputStream buf2 = IOUtils.toBufferedInputStream(inp);
Reader bufread = IOUtils.toBufferedReader(new InputStreamReader(inp));
byte[] bytes2 = IOUtils.toByteArray(inp, 1000);
char[] chars = IOUtils.toCharArray(inp, "UTF-8");
String s = IOUtils.toString(inp, "UTF-8");
InputStream is = IOUtils.toInputStream(s, "UTF-8");
StringWriter writer = new StringWriter();
writer.toString(); // not tainted
IOUtils.copy(inp, writer, "UTF-8");
writer.toString(); // tainted
writer = new StringWriter();
writer.toString(); // not tainted
IOUtils.copyLarge(bufread, writer);
writer.toString(); // tainted
byte x;
byte[] tgt = new byte[100];
x = tgt[0]; // not tainted
IOUtils.read(inp, tgt);
x = tgt[0]; // tainted
tgt = new byte[100];
x = tgt[0]; // not tainted
IOUtils.readFully(inp, tgt);
x = tgt[0]; // tainted
writer = new StringWriter();
writer.toString(); // not tainted
IOUtils.write(chars, writer);
writer.toString(); // tainted
writer = new StringWriter();
writer.toString(); // not tainted
IOUtils.writeChunked(chars, writer);
writer.toString(); // tainted
writer = new StringWriter();
writer.toString(); // not tainted
IOUtils.writeLines(lines, "\n", writer);
writer.toString(); // tainted
writer = new StringWriter();
writer.toString(); // not tainted
IOUtils.writeLines(new ArrayList<String>(), s, writer);
writer.toString(); // tainted
}
}

View File

@@ -0,0 +1,54 @@
| Test.java:12:21:12:47 | new FileInputStream(...) |
| Test.java:14:21:14:39 | buffer(...) |
| Test.java:14:36:14:38 | inp |
| Test.java:15:24:15:54 | readLines(...) |
| Test.java:15:42:15:44 | inp |
| Test.java:16:18:16:45 | readFully(...) |
| Test.java:16:36:16:38 | inp |
| Test.java:17:22:17:55 | toBufferedInputStream(...) |
| Test.java:17:52:17:54 | inp |
| Test.java:18:20:18:71 | toBufferedReader(...) |
| Test.java:18:45:18:70 | new InputStreamReader(...) |
| Test.java:18:67:18:69 | inp |
| Test.java:19:19:19:48 | toByteArray(...) |
| Test.java:19:39:19:41 | inp |
| Test.java:20:18:20:50 | toCharArray(...) |
| Test.java:20:38:20:40 | inp |
| Test.java:21:14:21:43 | toString(...) |
| Test.java:21:31:21:33 | inp |
| Test.java:22:20:22:52 | toInputStream(...) |
| Test.java:22:42:22:42 | s |
| Test.java:26:16:26:18 | inp |
| Test.java:26:21:26:26 | writer |
| Test.java:27:3:27:8 | writer |
| Test.java:27:3:27:19 | toString(...) |
| Test.java:31:21:31:27 | bufread |
| Test.java:31:30:31:35 | writer |
| Test.java:32:3:32:8 | writer |
| Test.java:32:3:32:19 | toString(...) |
| Test.java:37:16:37:18 | inp |
| Test.java:37:21:37:23 | tgt |
| Test.java:38:3:38:12 | ...=... |
| Test.java:38:7:38:9 | tgt |
| Test.java:38:7:38:12 | ...[...] |
| Test.java:42:21:42:23 | inp |
| Test.java:42:26:42:28 | tgt |
| Test.java:43:3:43:12 | ...=... |
| Test.java:43:7:43:9 | tgt |
| Test.java:43:7:43:12 | ...[...] |
| Test.java:47:17:47:21 | chars |
| Test.java:47:24:47:29 | writer |
| Test.java:48:3:48:8 | writer |
| Test.java:48:3:48:19 | toString(...) |
| Test.java:52:24:52:28 | chars |
| Test.java:52:31:52:36 | writer |
| Test.java:53:3:53:8 | writer |
| Test.java:53:3:53:19 | toString(...) |
| Test.java:57:22:57:26 | lines |
| Test.java:57:35:57:40 | writer |
| Test.java:58:3:58:8 | writer |
| Test.java:58:3:58:19 | toString(...) |
| Test.java:62:47:62:47 | s |
| Test.java:62:50:62:55 | writer |
| Test.java:63:3:63:8 | writer |
| Test.java:63:3:63:19 | toString(...) |

View File

@@ -0,0 +1,15 @@
import semmle.code.java.dataflow.DataFlow
import semmle.code.java.dataflow.TaintTracking
import semmle.code.java.dataflow.FlowSources
class Conf extends TaintTracking::Configuration {
Conf() { this = "qltest:dataflow:ioutils" }
override predicate isSource(DataFlow::Node source) { source instanceof UserInput }
override predicate isSink(DataFlow::Node sink) { any() }
}
from UserInput u, DataFlow::Node e, Conf config
where config.hasFlow(u, e) and e.getEnclosingCallable().hasName("ioutils")
select e

View File

@@ -0,0 +1 @@
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/apache-commons-io-2.6

View File

@@ -0,0 +1,159 @@
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.util.StringTokenizer;
public class B {
public static String[] taint() { return new String[] { "tainted" }; }
public static void sink(Object o) { }
public static void maintest() {
String[] args = taint();
// tainted - access to main args
String[] aaaargs = args;
sink(aaaargs);
// tainted - access to tainted array
String s = args[0];
sink(s);
// tainted - concatenation of tainted string
String concat = "Look at me " + s + ", I'm tainted!";
sink(concat);
// tainted - parenthesised
String pars = (concat);
sink(pars);
// tainted method argument, implies tainted return value
String method = tainty(pars);
sink(method);
// tainted - complex
String complex = ("Look at me " + args[0]) + ", I'm tainted!";
sink(complex);
// tainted - data preserving constructors
String constructed = new String(complex);
sink(constructed);
// tainted - unsafe escape
String badEscape = constructed.replaceAll("(<script>)", "");
sink(badEscape);
// tainted - tokenized string
String token = new StringTokenizer(badEscape).nextToken();
sink(token);
// not tainted
String safe = notTainty(complex);
sink(safe);
String shouldBeFine = taintyOtherArg(safe, complex);
sink(shouldBeFine);
// non-whitelisted constructors don't pass taint
StringWrapper herring = new StringWrapper(complex);
sink(herring);
// tainted equality check with constant
boolean cond = "foo" == s;
sink(cond);
// tainted logic with tainted operand
boolean logic = cond && safe();
sink(logic);
// tainted condition
sink(concat.endsWith("I'm tainted"));
// tainted
logic = safe() || cond;
sink(logic);
// tainted, use of equals
logic = badEscape.equals("constant");
sink(logic);
// not tainted
boolean okay = s == shouldBeFine;
sink(okay);
// methods on string that pass on taint
String trimmed = s.trim();
sink(trimmed);
String[] split = s.split(" ");
sink(split);
String lower = s.toLowerCase();
sink(lower);
String upper = s.toUpperCase();
sink(upper);
byte[] bytes = s.getBytes("UTF-8");
sink(bytes);
String toString = s.toString();
sink(toString);
String subs = s.substring(1, 10);
sink(subs);
String repl = "some constant".replace(" ", s);
sink(repl);
String replAll = "some constant".replaceAll(" ", s);
sink(replAll);
String replFirst = "some constant".replaceFirst(" ", s);
sink(replFirst);
ByteArrayOutputStream baos = null;
ObjectOutput oos = null;
ByteArrayInputStream bais = null;
ObjectInputStream ois = null;
try
{
// serialization of tainted string
baos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(baos);
oos.writeObject(s);
byte[] serializedData = baos.toByteArray(); // tainted
sink(serializedData);
// serialization of fixed string
baos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(baos);
oos.writeObject("not tainted");
byte[] serializedData2 = baos.toByteArray(); // *not* tainted
sink(serializedData2);
// de-serialization of tainted string
bais = new ByteArrayInputStream(serializedData);
ois = new ObjectInputStream(bais);
String deserializedData = (String)ois.readObject(); // tainted
sink(deserializedData);
} catch (IOException e) {
// ignored in test code
} catch (ClassNotFoundException e) {
// ignored in test code
}
// tainted array initializers
String[] taintedArray = new String[] { s };
sink(taintedArray);
String[][] taintedArray2 = new String[][] { { s } };
sink(taintedArray2);
String[][][] taintedArray3 = new String[][][] { { { s } } };
sink(taintedArray3);
return;
}
public static String tainty(String arg) {
// tainted return value
return arg;
}
public static String taintyOtherArg(String safe, String tainted) {
return safe;
}
public static String notTainty(String arg) {
return "foo";
}
public static class StringWrapper {
public String wrapped;
public StringWrapper(String s) {
this.wrapped = s;
}
}
public static boolean safe() {
return true;
}
}

View File

@@ -0,0 +1,38 @@
public class MethodFlow {
public static String taint() { return "tainted"; }
public static void sink(String s) { }
public void test() {
String tainted = taint();
sink(tainted);
String tainted2 = notNull(taint());
sink(tainted2);
String tainted3 = wrapNotNull(taint());
sink(tainted3);
String safe = notNull("a constant");
sink(safe);
String diffString = returnDiffString(taint());
sink(diffString);
}
public <T> T notNull(T x) {
if (x == null) {
throw new NullPointerException();
}
return x;
}
public <T> T wrapNotNull(T x) {
T res = notNull(x);
sink("Logged: " + res);
return res;
}
public String returnDiffString(String x) {
sink("Received: " + x);
return "OK";
}
}

View File

@@ -0,0 +1,66 @@
public class StringBuilderTests {
public static String taint() { return "tainted"; }
public static void sink(String s) { }
static void stringBuilderBad() {
StringBuilder sb = new StringBuilder();
sb.append("from preferences select locale where user='");
sb.append(taint());
sb.append("'");
sink(sb.toString());
}
static void stringBuilderOkay() {
StringBuilder sb = new StringBuilder();
sb.append("from preferences select locale where user='");
sb.append("fred");
sb.append("'");
sink(sb.toString());
}
static void stringBufferBad() {
StringBuffer sb = new StringBuffer();
sb.append("from preferences select locale where user='");
sb.append(taint());
sb.append("'");
sink(sb.toString());
}
static void stringBuilderNoVarBad() {
sink(new StringBuilder()
.append("from preferences select locale where user='")
.append(taint())
.append("'").toString()
);
}
static void stringBuilderConstructorBad() {
StringBuilder sb = new StringBuilder(taint());
sb.append("from preferences select locale where user='");
sb.append("fred");
sb.append("'");
sink(sb.toString());
}
static void stringBuilderMultipleAppendsBad() {
StringBuilder sb = new StringBuilder();
sb.append("from preferences select locale where user='").append(taint());
sb.append("'");
sink(sb.toString());
}
static void stringBuilderReplaceBad() {
StringBuilder sb = new StringBuilder();
sb.append("from preferences select locale where user='placeholder'");
sb.replace(45, 57, taint());
sink(sb.toString());
}
static void stringBuilderInsertBad() {
StringBuilder sb = new StringBuilder();
sb.append("from preferences select locale where user=''");
sb.insert(45, taint());
sink(sb.toString());
}
}

View File

@@ -0,0 +1,26 @@
public class Varargs {
public String taint() { return "tainted"; }
public void sink(String s) { }
public void sources() {
f1(taint());
f2(taint(), taint());
f3(new String[] { taint(), "" });
}
public void f1(String... ss) {
String s = ss[0];
sink(s);
}
public void f2(String... ss) {
String s = ss[0];
sink(s);
}
public void f3(String... ss) {
String s = ss[0];
sink(s);
}
}

View File

@@ -1,2 +1,47 @@
| A.java:10:19:10:25 | taint(...) | A.java:15:10:15:11 | b2 |
| A.java:20:19:20:25 | taint(...) | A.java:25:10:25:11 | b2 |
| B.java:15:21:15:27 | taint(...) | B.java:18:10:18:16 | aaaargs |
| B.java:15:21:15:27 | taint(...) | B.java:21:10:21:10 | s |
| B.java:15:21:15:27 | taint(...) | B.java:24:10:24:15 | concat |
| B.java:15:21:15:27 | taint(...) | B.java:27:10:27:13 | pars |
| B.java:15:21:15:27 | taint(...) | B.java:30:10:30:15 | method |
| B.java:15:21:15:27 | taint(...) | B.java:33:10:33:16 | complex |
| B.java:15:21:15:27 | taint(...) | B.java:36:10:36:20 | constructed |
| B.java:15:21:15:27 | taint(...) | B.java:39:10:39:18 | badEscape |
| B.java:15:21:15:27 | taint(...) | B.java:42:10:42:14 | token |
| B.java:15:21:15:27 | taint(...) | B.java:55:10:55:13 | cond |
| B.java:15:21:15:27 | taint(...) | B.java:58:10:58:14 | logic |
| B.java:15:21:15:27 | taint(...) | B.java:60:10:60:39 | endsWith(...) |
| B.java:15:21:15:27 | taint(...) | B.java:63:10:63:14 | logic |
| B.java:15:21:15:27 | taint(...) | B.java:66:10:66:14 | logic |
| B.java:15:21:15:27 | taint(...) | B.java:74:10:74:16 | trimmed |
| B.java:15:21:15:27 | taint(...) | B.java:76:10:76:14 | split |
| B.java:15:21:15:27 | taint(...) | B.java:78:10:78:14 | lower |
| B.java:15:21:15:27 | taint(...) | B.java:80:10:80:14 | upper |
| B.java:15:21:15:27 | taint(...) | B.java:82:10:82:14 | bytes |
| B.java:15:21:15:27 | taint(...) | B.java:84:10:84:17 | toString |
| B.java:15:21:15:27 | taint(...) | B.java:86:10:86:13 | subs |
| B.java:15:21:15:27 | taint(...) | B.java:88:10:88:13 | repl |
| B.java:15:21:15:27 | taint(...) | B.java:90:10:90:16 | replAll |
| B.java:15:21:15:27 | taint(...) | B.java:92:10:92:18 | replFirst |
| B.java:15:21:15:27 | taint(...) | B.java:105:12:105:25 | serializedData |
| B.java:15:21:15:27 | taint(...) | B.java:117:12:117:27 | deserializedData |
| B.java:15:21:15:27 | taint(...) | B.java:126:10:126:21 | taintedArray |
| B.java:15:21:15:27 | taint(...) | B.java:128:10:128:22 | taintedArray2 |
| B.java:15:21:15:27 | taint(...) | B.java:130:10:130:22 | taintedArray3 |
| MethodFlow.java:7:22:7:28 | taint(...) | MethodFlow.java:8:10:8:16 | tainted |
| MethodFlow.java:9:31:9:37 | taint(...) | MethodFlow.java:10:10:10:17 | tainted2 |
| MethodFlow.java:11:35:11:41 | taint(...) | MethodFlow.java:12:10:12:17 | tainted3 |
| MethodFlow.java:11:35:11:41 | taint(...) | MethodFlow.java:30:10:30:25 | ... + ... |
| MethodFlow.java:17:42:17:48 | taint(...) | MethodFlow.java:35:10:35:25 | ... + ... |
| StringBuilderTests.java:9:15:9:21 | taint(...) | StringBuilderTests.java:11:10:11:22 | toString(...) |
| StringBuilderTests.java:25:15:25:21 | taint(...) | StringBuilderTests.java:27:10:27:22 | toString(...) |
| StringBuilderTests.java:33:15:33:21 | taint(...) | StringBuilderTests.java:31:10:34:29 | toString(...) |
| StringBuilderTests.java:39:42:39:48 | taint(...) | StringBuilderTests.java:43:10:43:22 | toString(...) |
| StringBuilderTests.java:48:69:48:75 | taint(...) | StringBuilderTests.java:50:10:50:22 | toString(...) |
| StringBuilderTests.java:56:24:56:30 | taint(...) | StringBuilderTests.java:57:10:57:22 | toString(...) |
| StringBuilderTests.java:63:19:63:25 | taint(...) | StringBuilderTests.java:64:10:64:22 | toString(...) |
| Varargs.java:7:8:7:14 | taint(...) | Varargs.java:14:10:14:10 | s |
| Varargs.java:8:8:8:14 | taint(...) | Varargs.java:19:10:19:10 | s |
| Varargs.java:8:17:8:23 | taint(...) | Varargs.java:19:10:19:10 | s |
| Varargs.java:9:23:9:29 | taint(...) | Varargs.java:24:10:24:10 | s |

View File

@@ -0,0 +1,49 @@
import java.io.FileInputStream;
import java.io.IOException;
import java.net.InetAddress;
import java.net.MalformedURLException;
import java.net.Socket;
import java.net.URL;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class A {
public static void main(String[] args) {
String[] a = args; // user input
String s = args[0]; // user input
}
public static void userInput() throws SQLException, IOException, MalformedURLException {
System.getenv("test"); // user input
class TestServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
req.getParameter("test"); // remote user input
req.getHeader("test"); // remote user input
req.getQueryString(); // remote user input
req.getCookies()[0].getValue(); // remote user input
}
}
new Properties().getProperty("test"); // user input
System.getProperty("test"); // user input
new Object() {
public void test(ResultSet rs) throws SQLException {
rs.getString(0); // user input
}
};
new URL("test").openConnection().getInputStream(); // remote user input
new Socket("test", 1234).getInputStream(); // remote user input
InetAddress.getByName("test").getHostName(); // remote user input
System.in.read(); // user input
new FileInputStream("test").read(); // user input
}
}

View File

@@ -0,0 +1,8 @@
package security.library.dataflow;
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface RmiFlow extends Remote {
String listDirectory(String path);
}

View File

@@ -0,0 +1,15 @@
package security.library.dataflow;
public class RmiFlowImpl implements RmiFlow {
public String listDirectory(String path) {
String command = "ls " + path;
Runtime.getRuntime().exec(command);
return "pretend there are some results here";
}
public String notRemotable(String path) {
String command = "ls " + path;
Runtime.getRuntime().exec(command);
return "pretend there are some results here";
}
}

View File

@@ -0,0 +1,10 @@
| A.java:17:27:17:39 | args | A.java:17:27:17:39 | args |
| A.java:17:27:17:39 | args | A.java:18:18:18:21 | args |
| A.java:17:27:17:39 | args | A.java:19:16:19:19 | args |
| A.java:17:27:17:39 | args | A.java:19:16:19:22 | ...[...] |
| A.java:23:5:23:25 | getenv(...) | A.java:23:5:23:25 | getenv(...) |
| A.java:34:5:34:40 | getProperty(...) | A.java:34:5:34:40 | getProperty(...) |
| A.java:35:5:35:30 | getProperty(...) | A.java:35:5:35:30 | getProperty(...) |
| A.java:38:9:38:23 | getString(...) | A.java:38:9:38:23 | getString(...) |
| A.java:45:5:45:13 | System.in | A.java:45:5:45:13 | System.in |
| A.java:46:5:46:31 | new FileInputStream(...) | A.java:46:5:46:31 | new FileInputStream(...) |

View File

@@ -0,0 +1,18 @@
import java
import semmle.code.java.dataflow.TaintTracking
import semmle.code.java.dataflow.FlowSources
class Conf extends TaintTracking::Configuration {
Conf() { this = "remote taint conf" }
override predicate isSource(DataFlow::Node n) {
n instanceof UserInput and
not n instanceof RemoteFlowSource
}
override predicate isSink(DataFlow::Node n) { any() }
}
from DataFlow::Node src, DataFlow::Node sink, Conf conf
where conf.hasFlow(src, sink)
select src, sink

View File

@@ -0,0 +1 @@
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/servlet-api-2.4

View File

@@ -0,0 +1,11 @@
| A.java:28:9:28:32 | getParameter(...) | A.java:28:9:28:32 | getParameter(...) |
| A.java:29:9:29:29 | getHeader(...) | A.java:29:9:29:29 | getHeader(...) |
| A.java:30:9:30:28 | getQueryString(...) | A.java:30:9:30:28 | getQueryString(...) |
| A.java:31:9:31:38 | getValue(...) | A.java:31:9:31:38 | getValue(...) |
| A.java:41:5:41:53 | getInputStream(...) | A.java:41:5:41:53 | getInputStream(...) |
| A.java:42:5:42:45 | getInputStream(...) | A.java:42:5:42:45 | getInputStream(...) |
| A.java:43:5:43:47 | getHostName(...) | A.java:43:5:43:47 | getHostName(...) |
| RmiFlowImpl.java:4:30:4:40 | path | RmiFlowImpl.java:4:30:4:40 | path |
| RmiFlowImpl.java:4:30:4:40 | path | RmiFlowImpl.java:5:20:5:31 | ... + ... |
| RmiFlowImpl.java:4:30:4:40 | path | RmiFlowImpl.java:5:28:5:31 | path |
| RmiFlowImpl.java:4:30:4:40 | path | RmiFlowImpl.java:6:29:6:35 | command |

View File

@@ -0,0 +1,15 @@
import java
import semmle.code.java.dataflow.TaintTracking
import semmle.code.java.dataflow.FlowSources
class Conf extends TaintTracking::Configuration {
Conf() { this = "remote taint conf" }
override predicate isSource(DataFlow::Node n) { n instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node n) { any() }
}
from DataFlow::Node src, DataFlow::Node sink, Conf conf
where conf.hasFlow(src, sink)
select src, sink

View File

@@ -0,0 +1,14 @@
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@@ -0,0 +1,22 @@
package org.apache.commons.io;
import java.io.*;
import java.util.*;
public class IOUtils {
public static BufferedInputStream buffer(InputStream inputStream) { return null; }
public static void copy(InputStream input, Writer output, String inputEncoding) throws IOException { }
public static long copyLarge(Reader input, Writer output) throws IOException { return 42; }
public static int read(InputStream input, byte[] buffer) throws IOException { return 42; }
public static void readFully(InputStream input, byte[] buffer) throws IOException { }
public static byte[] readFully(InputStream input, int length) throws IOException { return null; }
public static List<String> readLines(InputStream input, String encoding) throws IOException { return null; }
public static InputStream toBufferedInputStream(InputStream input) throws IOException { return null; }
public static BufferedReader toBufferedReader(Reader reader) { return null; }
public static byte[] toByteArray(InputStream input, int size) throws IOException { return null; }
public static char[] toCharArray(InputStream is, String encoding) throws IOException { return null; }
public static InputStream toInputStream(String input, String encoding) throws IOException { return null; }
public static String toString(InputStream input, String encoding) throws IOException { return null; }
public static void write(char[] data, Writer output) throws IOException { }
public static void writeChunked(char[] data, Writer output) throws IOException { }
public static void writeLines(Collection<?> lines, String lineEnding, Writer writer) throws IOException { }
}

View File

@@ -1045,4 +1045,25 @@ module NodeJSLib {
i = 0 and result = this.getArgument(i)
}
}
/**
* Provides predicates for working with the "path" module and its platform-specific instances as a single module.
*/
module Path {
/**
* Gets a node that imports the "path" module, or one of its platform-specific instances.
*/
DataFlow::SourceNode moduleImport() {
result = DataFlow::moduleImport("path") or
result = DataFlow::moduleMember("path", "posix") or
result = DataFlow::moduleMember("path", "win32")
}
/**
* Gets an access to member `member` of the "path" module, or one of its platform-specific instances.
*/
DataFlow::SourceNode moduleMember(string member) {
result = moduleImport().getAPropertyRead(member)
}
}
}

View File

@@ -401,4 +401,33 @@ private module ClosureLibraryUri {
succ = uri
}
}
/**
* Provides classes for working with [path](https://nodejs.org/api/path.html) code.
*/
module path {
/**
* A taint step in the path module.
*/
private class Step extends UriLibraryStep, DataFlow::CallNode {
DataFlow::Node src;
Step() {
exists(DataFlow::SourceNode ref |
ref = NodeJSLib::Path::moduleMember("parse") or
// a ponyfill: https://www.npmjs.com/package/path-parse
ref = DataFlow::moduleImport("path-parse") or
ref = DataFlow::moduleMember("path-parse", "posix") or
ref = DataFlow::moduleMember("path-parse", "win32")
|
this = ref.getACall() and
src = getAnArgument()
)
}
override predicate step(DataFlow::Node pred, DataFlow::Node succ) {
pred = src and succ = this
}
}
}
}

View File

@@ -142,7 +142,7 @@ module TaintedPath {
or
// path.join()
exists(DataFlow::CallNode join, int n |
join = DataFlow::moduleMember("path", "join").getACall()
join = NodeJSLib::Path::moduleMember("join").getACall()
|
src = join.getArgument(n) and
dst = join and

View File

@@ -124,7 +124,7 @@ module TaintedPath {
DataFlow::Node output;
NormalizingPathCall() {
this = DataFlow::moduleMember("path", "normalize").getACall() and
this = NodeJSLib::Path::moduleMember("normalize").getACall() and
input = getArgument(0) and
output = this
}
@@ -148,7 +148,7 @@ module TaintedPath {
DataFlow::Node output;
ResolvingPathCall() {
this = DataFlow::moduleMember("path", "resolve").getACall() and
this = NodeJSLib::Path::moduleMember("resolve").getACall() and
input = getAnArgument() and
output = this
or
@@ -180,7 +180,7 @@ module TaintedPath {
DataFlow::Node output;
NormalizingRelativePathCall() {
this = DataFlow::moduleMember("path", "relative").getACall() and
this = NodeJSLib::Path::moduleMember("relative").getACall() and
input = getAnArgument() and
output = this
}
@@ -205,7 +205,7 @@ module TaintedPath {
PreservingPathCall() {
exists(string name | name = "dirname" or name = "toNamespacedPath" |
this = DataFlow::moduleMember("path", name).getACall() and
this = NodeJSLib::Path::moduleMember(name).getACall() and
input = getAnArgument() and
output = this
)
@@ -244,7 +244,7 @@ module TaintedPath {
// ".." + path.sep
exists(StringOps::Concatenation conc | node = conc |
conc.getOperand(0).getStringValue() = ".." and
conc.getOperand(1).getALocalSource() = DataFlow::moduleMember("path", "sep") and
conc.getOperand(1).getALocalSource() = NodeJSLib::Path::moduleMember("sep") and
conc.getNumOperand() = 2
)
}
@@ -311,7 +311,7 @@ module TaintedPath {
IsAbsoluteSanitizer() {
exists(DataFlow::CallNode call | this = call |
call = DataFlow::moduleMember("path", "isAbsolute").getACall() and
call = NodeJSLib::Path::moduleMember("isAbsolute").getACall() and
operand = call.getArgument(0) and
polarity = true and
negatable = true

View File

@@ -24,6 +24,12 @@
| closureUri.js:23:1:23:18 | utils.getPath(uri) | closureUri.js:23:15:23:17 | uri | closureUri.js:23:1:23:18 | utils.getPath(uri) |
| closureUri.js:27:1:27:23 | stringU ... code(x) | closureUri.js:27:22:27:22 | x | closureUri.js:27:1:27:23 | stringU ... code(x) |
| closureUri.js:28:1:28:23 | stringU ... code(x) | closureUri.js:28:22:28:22 | x | closureUri.js:28:1:28:23 | stringU ... code(x) |
| path-parse.js:4:1:4:13 | path.parse(x) | path-parse.js:4:12:4:12 | x | path-parse.js:4:1:4:13 | path.parse(x) |
| path-parse.js:5:1:5:13 | path_parse(x) | path-parse.js:5:12:5:12 | x | path-parse.js:5:1:5:13 | path_parse(x) |
| path-parse.js:6:1:6:19 | path.posix.parse(x) | path-parse.js:6:18:6:18 | x | path-parse.js:6:1:6:19 | path.posix.parse(x) |
| path-parse.js:7:1:7:19 | path_parse.posix(x) | path-parse.js:7:18:7:18 | x | path-parse.js:7:1:7:19 | path_parse.posix(x) |
| path-parse.js:8:1:8:19 | path.win32.parse(x) | path-parse.js:8:18:8:18 | x | path-parse.js:8:1:8:19 | path.win32.parse(x) |
| path-parse.js:9:1:9:19 | path_parse.win32(x) | path-parse.js:9:18:9:18 | x | path-parse.js:9:1:9:19 | path_parse.win32(x) |
| punycode.js:3:9:3:26 | punycode.decode(x) | punycode.js:3:25:3:25 | x | punycode.js:3:9:3:26 | punycode.decode(x) |
| punycode.js:5:5:5:22 | punycode.encode(x) | punycode.js:5:21:5:21 | x | punycode.js:5:5:5:22 | punycode.encode(x) |
| punycode.js:7:5:7:25 | punycod ... code(x) | punycode.js:7:24:7:24 | x | punycode.js:7:5:7:25 | punycod ... code(x) |

View File

@@ -0,0 +1,9 @@
const path = require('path');
const path_parse = require('path-parse');
path.parse(x);
path_parse(x);
path.posix.parse(x);
path_parse.posix(x);
path.win32.parse(x);
path_parse.win32(x);