diff --git a/csharp/ql/src/Bad Practices/PathCombine.qhelp b/csharp/ql/src/Bad Practices/PathCombine.qhelp new file mode 100644 index 000000000000..2562a615c87d --- /dev/null +++ b/csharp/ql/src/Bad Practices/PathCombine.qhelp @@ -0,0 +1,18 @@ + + + +

Path.Combine may silently drop its earlier arguments if its later arguments are absolute paths. E.g. Path.Combine("C:\\Users\\Me\\Documents", "C:\\Program Files\\") == "C:\\Program Files".

+ +
+ +

Use Path.Join instead.

+
+ + +
  • Microsoft Learn, .NET API browser, Path.Combine.
  • +
  • Microsoft Learn, .NET API browser, Path.Join.
  • + +
    +
    diff --git a/csharp/ql/src/Bad Practices/PathCombine.ql b/csharp/ql/src/Bad Practices/PathCombine.ql new file mode 100644 index 000000000000..aa841486bdff --- /dev/null +++ b/csharp/ql/src/Bad Practices/PathCombine.ql @@ -0,0 +1,16 @@ +/** + * @name Call to System.IO.Path.Combine + * @description Finds calls to System.IO.Path's Combine method + * @kind problem + * @problem.severity recommendation + * @precision very-high + * @id cs/path-combine + * @tags reliability + */ + +import csharp +import semmle.code.csharp.frameworks.System + +from MethodCall call +where call.getTarget().hasFullyQualifiedName("System.IO", "Path", "Combine") +select call, "Call to 'System.IO.Path.Combine'." diff --git a/csharp/ql/src/change-notes/2025-02-26-path-combine.md b/csharp/ql/src/change-notes/2025-02-26-path-combine.md new file mode 100644 index 000000000000..81610502b229 --- /dev/null +++ b/csharp/ql/src/change-notes/2025-02-26-path-combine.md @@ -0,0 +1,4 @@ +--- +category: newQuery +--- +* Added a new query, `csharp/path-combine`, to recommend against the `Path.Combine` method due to it silently discarding its earlier parameters if later parameters are rooted. \ No newline at end of file diff --git a/csharp/ql/test/query-tests/Bad Practices/Path Combine/PathCombine.cs b/csharp/ql/test/query-tests/Bad Practices/Path Combine/PathCombine.cs new file mode 100644 index 000000000000..bf9b19c4a5c7 --- /dev/null +++ b/csharp/ql/test/query-tests/Bad Practices/Path Combine/PathCombine.cs @@ -0,0 +1,14 @@ +using System.IO; + +class PathCombine +{ + void bad() + { + Path.Combine(@"C:\Users", @"C:\Program Files"); + } + + void good() + { + Path.Join(@"C:\Users", @"C:\Program Files"); + } +} diff --git a/csharp/ql/test/query-tests/Bad Practices/Path Combine/PathCombine.expected b/csharp/ql/test/query-tests/Bad Practices/Path Combine/PathCombine.expected new file mode 100644 index 000000000000..c0f9e405516b --- /dev/null +++ b/csharp/ql/test/query-tests/Bad Practices/Path Combine/PathCombine.expected @@ -0,0 +1 @@ +| PathCombine.cs:7:9:7:54 | call to method Combine | Call to 'System.IO.Path.Combine'. | diff --git a/csharp/ql/test/query-tests/Bad Practices/Path Combine/PathCombine.qlref b/csharp/ql/test/query-tests/Bad Practices/Path Combine/PathCombine.qlref new file mode 100644 index 000000000000..eaf41d047402 --- /dev/null +++ b/csharp/ql/test/query-tests/Bad Practices/Path Combine/PathCombine.qlref @@ -0,0 +1 @@ +Bad Practices/PathCombine.ql \ No newline at end of file diff --git a/csharp/ql/test/query-tests/Bad Practices/Path Combine/options b/csharp/ql/test/query-tests/Bad Practices/Path Combine/options new file mode 100644 index 000000000000..75c39b4541ba --- /dev/null +++ b/csharp/ql/test/query-tests/Bad Practices/Path Combine/options @@ -0,0 +1,2 @@ +semmle-extractor-options: /nostdlib /noconfig +semmle-extractor-options: --load-sources-from-project:${testdir}/../../../resources/stubs/_frameworks/Microsoft.NETCore.App/Microsoft.NETCore.App.csproj