Open jonpryor opened 10 months ago
IMO, this can potentially lead to false positives unless the analysis can confirm that the second last string parameter is being passed as format string to some string.Format call and the last params array parameter is passed as format arguments to that call.
@mavasani wrote:
IMO, this can potentially lead to false positives
It will absolutely lead to false positives. I would personally take that tradeoff. I have been bit by this in production more than once, which is too often.
unless the analysis can confirm that the second last string parameter is being passed as format string to some string.Format call and the last params array parameter is passed as format arguments to that call
would result in versioning brittleness: in v1 of the lib it doesn't use string.Format()
, but in v2 it does use string.Format()
. What used to be fine is now potentially problematic.
The one false positive I'm less certain about is Microsoft.Extensions.Logging
, in which there are non-overloaded extension methods which end in string, params object[]
such as LoggerExtensions.Log(ILogger, LogLevel, string, params object?[])
), but passing a message
string containing {
doesn't result in any runtime error; in fact, that's one of their examples!
logger.LogInformation("Hello World! Logging is {Description}.", "fun");
It will absolutely lead to false positives. I would personally take that tradeoff. I have been bit by this in production more than once, which is too often.
Moving to dotnet\runtime for triaging the analyzer proposal. Normally, analyzer suggestions that can lead to many false positives are recommended to be implemented in a separate third party analyzer package, but I will let the triage team make a call.
Tagging subscribers to this area: @dotnet/area-system-runtime See info in area-owners.md if you want to be subscribed.
Author: | jonpryor |
---|---|
Assignees: | - |
Labels: | `area-System.Runtime`, `untriaged`, `needs-area-label` |
Milestone: | - |
(From the "Save me from myself" department…)
Describe the problem you are trying to solve
C#
params
arrays are awesome:They're also a footgun, lying in wait:
Quick, what's wrong with the above code? It would compile (given enough extra code), and it certainly looks reasonable, and similar code constructs have passed code review innumerable times.
What Could Possibly Go Wrong?
What happens is the above sketch eventually effectively calls:
which promptly throws an exception:
There are (at least) two mitigations for this: overloading, and using the format string.
Overloading: Method overloading nicely "solves"/"avoids" the problem:
The callsite of
Utilities.LogError(info, e.ToString())
is unchanged, but now avoids callingstring.Format()
, and thus avoids theFormatException
.Explicit format strings: occasionally method overloading isn't (easily) possible, in which case the format string should be explicitly specified:
Describe suggestions on how to achieve the rule
When an analyzer rule encounters a method invocation:
string, params *whatever*[]
parameter "pair"? If it does, continue to (2).params *whatever*[]
parameter? If there are, then it's "fine". (It might not be fine; see also dotnet/roslyn-analyzers#2799! But it's not what this issue is trying to look for.). If there are no values in theparams object[]
parameter, continue to (3).Additional context