From 5eb9a535a40783a666db239553f636da96ce6fa7 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 13 Mar 2025 10:37:17 +0100 Subject: [PATCH 1/4] C#: Remove disposal test for library code as we are no longer doing CIL extraction or data flow. --- .../Class1.cs_ | 42 ------------------ .../DisposalTests.dll | Bin 4096 -> 0 bytes .../NoDisposeCallOnLocalIDisposable.cs | 3 -- .../NoDisposeCallOnLocalIDisposable.expected | 1 - 4 files changed, 46 deletions(-) delete mode 100644 csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/Class1.cs_ delete mode 100644 csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/DisposalTests.dll diff --git a/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/Class1.cs_ b/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/Class1.cs_ deleted file mode 100644 index ed948c053d05..000000000000 --- a/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/Class1.cs_ +++ /dev/null @@ -1,42 +0,0 @@ -using System; - -namespace DisposalTests -{ - public class MyType : IDisposable - { - public void Dispose() - { - } - } - - public class Class1 : IDisposable - { - public void DisposesParameter(IDisposable p1, IDisposable p2) - { - p1.Dispose(); - } - - public void CapturesDisposable(MyType p1, MyType p2) - { - field1 = p1; - field2 = p2; - } - - public void DisposesSelf() - { - Dispose(); - } - - MyType field1, field2; - - public void Dispose() - { - field1.Dispose(); - } - - public static void Dispose(IDisposable d) - { - d.Dispose(); - } - } -} diff --git a/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/DisposalTests.dll b/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/DisposalTests.dll deleted file mode 100644 index f731c5af9e1100bb3f30338cab4259f9ae8cd137..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4096 zcmeHKU2GiH75-+u-Z&01iPJ)?qAoA-~|b_4^6*wXVz=S zP1GXsf_m2X-1B$OJ?GpzbH-B-oJI$LG{@!3z?+-}Mm4@RIz@HQ&F6aX`s(wyylLz| ze@k)B3C%{}*8;n4R&3AnBeSf`py`>8XXXzS%(`Dy*4nk*TN2kZ6Tp6>1IIsE^|#h; zpJB7P#ux;;D9OaqXKv+ea*T2S>olE;;}(I$ui+Fi1{HET zwoww2Xg9|a7-bq(pj@AZ5-W~zh_4=wB`^w%FJUzqNnHsNTMC^xV*;;s0)_~`2Xtd# zb87ny0a zk>qz`*c!Bk28Xh{B*0F%#2e|h|54yc&U=I|M1kYgLa}&z6qTaJg~hMqsrt|1^ehLtKxwWaWxbuaApm(zL`RMkZxiS60r99 zKeWrPLe6eP%|L}qM1_SgQg!QK(~F$C!qh@>p`j2Pa8~7JttM;7BHrF|Gg24}Lsc)k z3q>bdDlXbVO+|b8npG$L;5RGn_d2dRtb)+-y_L#IZ`Kd$c0{G^Uezk+d$Ufh8ECt< zlbl~~IIb2RRIWX*sj#hYMLZL*DwSxZLLAuMLR*oPL(3zl?6^*}M4MD6EGTyt%L`~F zvGYMsifFq<6-J>|b=|~vafzCBRYg*6)jOQArGAkLU{xYNXj$eRyXN^}z_{=5Rh#-|?#fdl2^+%djD={qib{M6HD?)~$(|M>bdd;W8zO~dHw zFky6(SifG_p03yKKKj`D3*EarGQC}^%#_hP(mSH(uHLRr805R+hYQ#wZ-8Rzh9iO9 znD)Ji`HE^tcE!2CKN%XdTcz*u?FRa+>4{HMDN-Q z(<};l4XjUhTgM$3G>HSALW{9Ju1(<@!*#*re@?l+2lCG-g!p)TLKc- z1`cUGeMEiwMVlx&>2}>_aj=jt3?F~_rVSTPPoJBAcH^b~iFd_EZg=TW$U9!D*lx34 z3jJnKQKdlf0W9STb9T_!Sz4Au$uA!-=@d$yio&EKtiy6Mt5GeZuy1U~$n8k>{d#w@ zujKaPD{t+&^zxI>*Uo?Q(Ol9$CEO>3HicRVtv(xTj^_Lz@48dACjlmk!TVrrPwVH9wbcmfAWP4Y`? zn*1d3-uSBvZ>7KaSNs;16BUT(yJJT8?ImutG_S1=!$v?q4*S2NPY<*3wSJ3URixIY zG^E}}L_42c46mj4(J8wj0dA+t3bzW;KI)=uw7_a4Hkp0zIjQ22o1oYj`FUu}BxHx3b zUfN5AB5mvGsM---_4n(&4kU7^tW=aF=$}lGoMiJgC2Rmao0CQtdi{-w;yMG1f6;j&+{2%j`_v e-R0G7uaO%62*8a0XZXV}e+0SwKZXCf0{;eT1xqLZ diff --git a/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.cs b/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.cs index 457c1ae4b40d..c70ad75df153 100644 --- a/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.cs +++ b/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.cs @@ -76,9 +76,6 @@ public IDisposable Method() var xmlDoc = new XmlDocument(); xmlDoc.Load(xmlReader); - // GOOD: Passed to a library (False positive as this is disposed in library code). - DisposalTests.Class1.Dispose(new StreamWriter("output.txt")); - // GOOD: Disposed automatically. using var c2 = new Timer(TimerProc); diff --git a/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.expected b/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.expected index 1a72517edb8b..9aa7baa2d504 100644 --- a/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.expected +++ b/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.expected @@ -3,5 +3,4 @@ | NoDisposeCallOnLocalIDisposable.cs:53:9:53:64 | object creation of type FileStream | Disposable 'FileStream' is created but not disposed. | | NoDisposeCallOnLocalIDisposable.cs:75:25:75:71 | call to method Create | Disposable 'XmlReader' is created but not disposed. | | NoDisposeCallOnLocalIDisposable.cs:75:42:75:64 | object creation of type StringReader | Disposable 'StringReader' is created but not disposed. | -| NoDisposeCallOnLocalIDisposable.cs:80:38:80:67 | object creation of type StreamWriter | Disposable 'StreamWriter' is created but not disposed. | | NoDisposeCallOnLocalIDisposableBad.cs:8:22:8:56 | object creation of type FileStream | Disposable 'FileStream' is created but not disposed. | From 40375a038709ec7aa5b27985e1f9ccc9693c76f7 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 13 Mar 2025 10:47:45 +0100 Subject: [PATCH 2/4] C#: Use stubs for the cs/local-not-disposed tests. --- .../API Abuse/NoDisposeCallOnLocalIDisposable/options | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/options b/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/options index f12c8c66331e..ef338c0b1c12 100644 --- a/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/options +++ b/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/options @@ -1 +1,2 @@ -semmle-extractor-options: /r:System.Private.Xml.dll /r:System.IO.Compression.dll +semmle-extractor-options: /nostdlib /noconfig +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../resources/stubs/_frameworks/Microsoft.AspNetCore.App/Microsoft.AspNetCore.App.csproj From 209b9c6114e7030407b82a1c7252a5ff50895fca Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 13 Mar 2025 11:07:07 +0100 Subject: [PATCH 3/4] C#: Re-factor to use inline expectation tests instead. --- .../NoDisposeCallOnLocalIDisposable.cs | 17 +++++++++++++---- .../NoDisposeCallOnLocalIDisposable.expected | 2 +- .../NoDisposeCallOnLocalIDisposable.qlref | 3 ++- .../NoDisposeCallOnLocalIDisposableBad.cs | 11 ----------- 4 files changed, 16 insertions(+), 17 deletions(-) delete mode 100644 csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposableBad.cs diff --git a/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.cs b/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.cs index c70ad75df153..eef0371ca9b6 100644 --- a/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.cs +++ b/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.cs @@ -48,9 +48,9 @@ public IDisposable Method() } // BAD: No Dispose call - var c1d = new Timer(TimerProc); - var fs = new FileStream("", FileMode.CreateNew, FileAccess.Write); - new FileStream("", FileMode.CreateNew, FileAccess.Write).Fluent(); + var c1d = new Timer(TimerProc); // $ Alert + var fs = new FileStream("", FileMode.CreateNew, FileAccess.Write); // $ Alert + new FileStream("", FileMode.CreateNew, FileAccess.Write).Fluent(); // $ Alert // GOOD: Disposed via wrapper fs = new FileStream("", FileMode.CreateNew, FileAccess.Write); @@ -72,7 +72,7 @@ public IDisposable Method() ; // GOOD: XmlDocument.Load disposes incoming XmlReader (False positive as this is disposed in library code) - var xmlReader = XmlReader.Create(new StringReader("xml"), null); + var xmlReader = XmlReader.Create(new StringReader("xml"), null); // $ Alert var xmlDoc = new XmlDocument(); xmlDoc.Load(xmlReader); @@ -104,6 +104,15 @@ void TimerProc(object obj) public void Dispose() { } } +class Bad +{ + long GetLength(string file) + { + var stream = new FileStream(file, FileMode.Open); // $ Alert + return stream.Length; + } +} + static class Extensions { public static FileStream Fluent(this FileStream fs) => fs; diff --git a/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.expected b/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.expected index 9aa7baa2d504..8c79d11d473e 100644 --- a/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.expected +++ b/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.expected @@ -3,4 +3,4 @@ | NoDisposeCallOnLocalIDisposable.cs:53:9:53:64 | object creation of type FileStream | Disposable 'FileStream' is created but not disposed. | | NoDisposeCallOnLocalIDisposable.cs:75:25:75:71 | call to method Create | Disposable 'XmlReader' is created but not disposed. | | NoDisposeCallOnLocalIDisposable.cs:75:42:75:64 | object creation of type StringReader | Disposable 'StringReader' is created but not disposed. | -| NoDisposeCallOnLocalIDisposableBad.cs:8:22:8:56 | object creation of type FileStream | Disposable 'FileStream' is created but not disposed. | +| NoDisposeCallOnLocalIDisposable.cs:111:22:111:56 | object creation of type FileStream | Disposable 'FileStream' is created but not disposed. | diff --git a/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.qlref b/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.qlref index 3f71b594f228..67155fa1e447 100644 --- a/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.qlref +++ b/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.qlref @@ -1 +1,2 @@ -API Abuse/NoDisposeCallOnLocalIDisposable.ql \ No newline at end of file +query: API Abuse/NoDisposeCallOnLocalIDisposable.ql +postprocess: utils/test/InlineExpectationsTestQuery.ql diff --git a/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposableBad.cs b/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposableBad.cs deleted file mode 100644 index 9f8bb3e8e002..000000000000 --- a/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposableBad.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System; -using System.IO; - -class Bad -{ - long GetLength(string file) - { - var stream = new FileStream(file, FileMode.Open); - return stream.Length; - } -} From b1edd9294b1194585cda377d519226dfc678df01 Mon Sep 17 00:00:00 2001 From: Michael Nebel Date: Thu, 13 Mar 2025 11:19:37 +0100 Subject: [PATCH 4/4] C#: Add some more test cases to cs/local-not-disposed. --- .../NoDisposeCallOnLocalIDisposable.cs | 14 ++++++++++++-- .../NoDisposeCallOnLocalIDisposable.expected | 13 +++++++------ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.cs b/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.cs index eef0371ca9b6..aa11be14f67b 100644 --- a/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.cs +++ b/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.cs @@ -1,10 +1,11 @@ using System; -using System.Text; using System.IO; using System.IO.Compression; -using System.Xml; +using System.Net.Http; +using System.Text; using System.Threading; using System.Threading.Tasks; +using System.Xml; class Test { @@ -94,6 +95,15 @@ public IDisposable Method() return null; } + public void M(IHttpClientFactory factory) + { + // GOOD: Factory tracks and disposes. + HttpClient client1 = factory.CreateClient(); + + // BAD: No Dispose call + var client2 = new HttpClient(); // $ Alert + } + // GOOD: Escapes IDisposable Create() => new Timer(TimerProc); diff --git a/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.expected b/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.expected index 8c79d11d473e..f08cf6837c5f 100644 --- a/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.expected +++ b/csharp/ql/test/query-tests/API Abuse/NoDisposeCallOnLocalIDisposable/NoDisposeCallOnLocalIDisposable.expected @@ -1,6 +1,7 @@ -| NoDisposeCallOnLocalIDisposable.cs:51:19:51:38 | object creation of type Timer | Disposable 'Timer' is created but not disposed. | -| NoDisposeCallOnLocalIDisposable.cs:52:18:52:73 | object creation of type FileStream | Disposable 'FileStream' is created but not disposed. | -| NoDisposeCallOnLocalIDisposable.cs:53:9:53:64 | object creation of type FileStream | Disposable 'FileStream' is created but not disposed. | -| NoDisposeCallOnLocalIDisposable.cs:75:25:75:71 | call to method Create | Disposable 'XmlReader' is created but not disposed. | -| NoDisposeCallOnLocalIDisposable.cs:75:42:75:64 | object creation of type StringReader | Disposable 'StringReader' is created but not disposed. | -| NoDisposeCallOnLocalIDisposable.cs:111:22:111:56 | object creation of type FileStream | Disposable 'FileStream' is created but not disposed. | +| NoDisposeCallOnLocalIDisposable.cs:52:19:52:38 | object creation of type Timer | Disposable 'Timer' is created but not disposed. | +| NoDisposeCallOnLocalIDisposable.cs:53:18:53:73 | object creation of type FileStream | Disposable 'FileStream' is created but not disposed. | +| NoDisposeCallOnLocalIDisposable.cs:54:9:54:64 | object creation of type FileStream | Disposable 'FileStream' is created but not disposed. | +| NoDisposeCallOnLocalIDisposable.cs:76:25:76:71 | call to method Create | Disposable 'XmlReader' is created but not disposed. | +| NoDisposeCallOnLocalIDisposable.cs:76:42:76:64 | object creation of type StringReader | Disposable 'StringReader' is created but not disposed. | +| NoDisposeCallOnLocalIDisposable.cs:104:23:104:38 | object creation of type HttpClient | Disposable 'HttpClient' is created but not disposed. | +| NoDisposeCallOnLocalIDisposable.cs:121:22:121:56 | object creation of type FileStream | Disposable 'FileStream' is created but not disposed. |