mirror of
https://github.com/github/codeql.git
synced 2025-12-17 01:03:14 +01:00
266 lines
5.6 KiB
C#
266 lines
5.6 KiB
C#
public class A
|
|
{
|
|
public static void Sink(object o)
|
|
{
|
|
}
|
|
|
|
public object FlowThrough(object o, bool cond)
|
|
{
|
|
if (cond)
|
|
{
|
|
return o;
|
|
}
|
|
else
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public void CallSinkIfTrue(object o, bool cond)
|
|
{
|
|
if (cond)
|
|
{
|
|
Sink(o);
|
|
}
|
|
}
|
|
|
|
public void CallSinkIfFalse(object o, bool cond)
|
|
{
|
|
if (!cond)
|
|
{
|
|
Sink(o);
|
|
}
|
|
}
|
|
|
|
public void CallSinkFromLoop(object o, bool cond)
|
|
{
|
|
while (cond)
|
|
{
|
|
Sink(o);
|
|
}
|
|
}
|
|
|
|
public void LocalCallSensitivity(object o, bool c)
|
|
{
|
|
object o1 = o;
|
|
object o2 = null;
|
|
if (c)
|
|
{
|
|
object tmp = o1;
|
|
o2 = 1 == 1 ? (tmp) : (tmp);
|
|
}
|
|
object o3 = o2;
|
|
Sink(o3);
|
|
}
|
|
|
|
public void LocalCallSensitivity2(object o, bool b, bool c)
|
|
{
|
|
object o1 = o;
|
|
object o2 = null;
|
|
if (b || c)
|
|
{
|
|
object tmp = o1;
|
|
o2 = 1 == 1 ? (tmp) : (tmp);
|
|
}
|
|
object o3 = o2;
|
|
Sink(o3);
|
|
}
|
|
|
|
public void M1()
|
|
{
|
|
// should not exhibit flow
|
|
CallSinkIfTrue(new object(), false);
|
|
CallSinkIfFalse(new object(), true);
|
|
CallSinkFromLoop(new object(), false);
|
|
LocalCallSensitivity(new object(), false);
|
|
Sink(FlowThrough(new object(), false));
|
|
// should exhibit flow
|
|
CallSinkIfTrue(new object(), true);
|
|
CallSinkIfFalse(new object(), false);
|
|
CallSinkFromLoop(new object(), true);
|
|
LocalCallSensitivity(new object(), true);
|
|
LocalCallSensitivity2(new object(), true, true);
|
|
LocalCallSensitivity2(new object(), false, true);
|
|
LocalCallSensitivity2(new object(), true, false);
|
|
Sink(FlowThrough(new object(), true));
|
|
// expected false positive
|
|
LocalCallSensitivity2(new object(), false, false);
|
|
}
|
|
|
|
public void M2()
|
|
{
|
|
bool t = true;
|
|
bool f = false;
|
|
// should not exhibit flow
|
|
CallSinkIfTrue(new object(), f);
|
|
CallSinkIfFalse(new object(), t);
|
|
CallSinkFromLoop(new object(), f);
|
|
LocalCallSensitivity(new object(), f);
|
|
Sink(FlowThrough(new object(), f));
|
|
// should exhibit flow
|
|
CallSinkIfTrue(new object(), t);
|
|
CallSinkIfFalse(new object(), f);
|
|
CallSinkFromLoop(new object(), t);
|
|
LocalCallSensitivity(new object(), t);
|
|
Sink(FlowThrough(new object(), t));
|
|
}
|
|
|
|
public void M3(InterfaceA b)
|
|
{
|
|
bool t = true;
|
|
bool f = false;
|
|
// should not exhibit flow
|
|
b.CallSinkIfTrue(new object(), f);
|
|
b.CallSinkIfFalse(new object(), t);
|
|
b.LocalCallSensitivity(new object(), f);
|
|
// should exhibit flow
|
|
b.CallSinkIfTrue(new object(), t);
|
|
b.CallSinkIfFalse(new object(), f);
|
|
b.LocalCallSensitivity(new object(), t);
|
|
}
|
|
|
|
class B : InterfaceA
|
|
{
|
|
public void CallSinkIfTrue(object o, bool cond)
|
|
{
|
|
if (cond)
|
|
{
|
|
Sink(o);
|
|
}
|
|
}
|
|
|
|
public void CallSinkIfFalse(object o, bool cond)
|
|
{
|
|
if (!cond)
|
|
{
|
|
Sink(o);
|
|
}
|
|
}
|
|
|
|
public void LocalCallSensitivity(object o, bool c)
|
|
{
|
|
object o1 = o;
|
|
object o2 = null;
|
|
if (c)
|
|
{
|
|
object tmp = o1;
|
|
o2 = 1 == 1 ? (tmp) : (tmp);
|
|
}
|
|
object o3 = o2;
|
|
Sink(o3);
|
|
}
|
|
}
|
|
}
|
|
|
|
public class A2
|
|
{
|
|
|
|
public static void Sink(object o)
|
|
{
|
|
}
|
|
|
|
public virtual void M(object o)
|
|
{
|
|
Sink(o);
|
|
}
|
|
|
|
public static void CallM(A2 a2, object o)
|
|
{
|
|
a2.M(o);
|
|
}
|
|
|
|
public virtual object MOut() => new object();
|
|
|
|
public static object CallMOut(A2 a2) => a2.MOut();
|
|
|
|
public void Callsite(InterfaceB intF)
|
|
{
|
|
B b = new B();
|
|
// in both possible implementations of foo, this callsite is relevant
|
|
// in IntA, it improves virtual dispatch,
|
|
// and in IntB, it improves the dataflow analysis.
|
|
intF.Foo(b, new object(), false); // no flow to `Sink()` via `A2.M()`, but flow via `IntA.Foo()`
|
|
|
|
CallM(b, new object()); // no flow to `Sink()`
|
|
CallM(this, new object()); // flow to `Sink()`
|
|
|
|
var o = CallMOut(this);
|
|
Sink(o); // flow
|
|
o = CallMOut(b);
|
|
Sink(o); // no flow
|
|
}
|
|
|
|
public class B : A2
|
|
{
|
|
public override void M(object o)
|
|
{
|
|
|
|
}
|
|
|
|
public override object MOut() => throw null;
|
|
}
|
|
|
|
public class IntA : InterfaceB
|
|
{
|
|
public void Foo(A2 obj, object o, bool cond)
|
|
{
|
|
obj.M(o);
|
|
Sink(o);
|
|
}
|
|
}
|
|
|
|
public class IntB : InterfaceB
|
|
{
|
|
|
|
public void Foo(A2 obj, object o, bool cond)
|
|
{
|
|
if (cond)
|
|
{
|
|
Sink(o);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
public interface InterfaceA
|
|
{
|
|
void CallSinkIfTrue(object o, bool cond);
|
|
void CallSinkIfFalse(object o, bool cond);
|
|
void LocalCallSensitivity(object o, bool c);
|
|
}
|
|
|
|
public interface InterfaceB
|
|
{
|
|
void Foo(A2 a, object o, bool cond);
|
|
}
|
|
|
|
public class A3
|
|
{
|
|
public virtual void M1(object o)
|
|
{
|
|
this.M2(o);
|
|
}
|
|
|
|
public virtual void M2(object o)
|
|
{
|
|
Sink(o); // should not have flow
|
|
}
|
|
|
|
public static void Sink(object o)
|
|
{
|
|
}
|
|
}
|
|
|
|
public class A4 : A3
|
|
{
|
|
public override void M2(object o)
|
|
{
|
|
Sink(o); // should have flow
|
|
}
|
|
|
|
private void CallM1()
|
|
{
|
|
base.M1(new object());
|
|
}
|
|
}
|