Tests for safety of string format calls #4194
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Motivation
My first code fix for CKAN was to remove a superfluous
String.Format
call that was causing exceptions to be thrown because externally-generated strings were being used as part of a format string (see #2111).This problem generalizes; any call to
IUser.RaiseMessage
orIUser.RaiseError
can throw an exception if the first parameter isn't a valid format string. We can ensure that a string literal is safe by looking at it, and we can ensure that an i18n resource is safe by inspecting our resx files, but anytime a value is externally sourced, it isn't safe to use it as a format string because curly braces could turn up any time and ruin our day.In principle, the C# compiler could check this and emit warnings similar to what it does for nullable references, but currently it doesn't. The closest thing is the
StringSyntax
attribute, which can be used to mark a parameter as a format string, but which doesn't have any built-in functionality associated with it.Changes
MonoCecilAnalysisTestsBase
base class is factored out of the test from Add test to check GUI thread safety #3914StringFormatSafetyTests
class inherits fromMonoCecilAnalysisTestsBase
and scans all code in all of our assemblies for calls to functions with theStringSyntax
attribute. These calls are deemed safe if the argument list is non-empty, if the format string is a string literal, or if the format string is fromProperties.Resources
; otherwise a test failure is logged.StringSyntax
attribute"{0}"
, or to remove a superfluous call tostring.Format
, or other such solutionsThis guard rail will help us to write safer code.