Files
codeql/csharp/ql/test/library-tests/dataflow/call-sensitivity/CallSensitivityFlow.cs
2025-08-28 11:57:03 +02:00

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());
}
}