-
Notifications
You must be signed in to change notification settings - Fork 94
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix NullReferenceException
in WorkItemFiler when all results baseline state are unchange/absent/updated
#2412
Conversation
This pull request introduces 1 alert when merging d1928a1 into 678e283 - view on LGTM.com new alerts:
In reply to: 983119894 |
update comments Update comments
fdf350f
to
e2ce908
Compare
the issue has been resolved in commits after this. In reply to: 983119894 |
public void SarifWorkItemExtensions_CreateWorkItemDescription_ResultsShouldNotBeFiled() | ||
{ | ||
string toolName = "TestToolName"; | ||
string firstLocation = @"C:\Test\Data\File{0}sarif"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -152,7 +152,7 @@ public static string CreateWorkItemDescription(this SarifLog log, SarifWorkItemC | |||
Uri runRepositoryUri = log?.Runs.FirstOrDefault()?.VersionControlProvenance?.FirstOrDefault().RepositoryUri; | |||
Uri detectionLocationUri = !string.IsNullOrEmpty(runRepositoryUri?.OriginalString) ? | |||
runRepositoryUri : | |||
results?.FirstOrDefault().Locations?[0].PhysicalLocation?.ArtifactLocation?.Uri; | |||
results?.FirstOrDefault()?.Locations?[0].PhysicalLocation?.ArtifactLocation?.Uri; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -290,6 +290,12 @@ public SarifWorkItemModel FileWorkItemInternal(SarifLog sarifLog, SarifWorkItemC | |||
{ | |||
string logId = sarifLog.GetProperty<Guid>(LOGID_PROPERTY_NAME).ToString(); | |||
|
|||
if (sarifLog.Runs?.Any(run => run.Results?.Any(result => result.ShouldBeFiled()) == true) != true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (sarifLog.Runs?.Any(run => run.Results?.Any(result => result.ShouldBeFiled()) == true) != true)
was thinking about the case of one run have work item and the other have empty array if this condiftion works.
do we think better to expand the nested condition, easiler to read and maintenance :) #Closed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
removed in latest change
@@ -290,6 +290,12 @@ public SarifWorkItemModel FileWorkItemInternal(SarifLog sarifLog, SarifWorkItemC | |||
{ | |||
string logId = sarifLog.GetProperty<Guid>(LOGID_PROPERTY_NAME).ToString(); | |||
|
|||
if (sarifLog.Runs?.Any(run => run.Results?.Any(result => result.ShouldBeFiled()) == true) != true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we think also add a safety check in this method as well
public static bool ShouldBeFiled(this Result result)
{
if(result ==null) return false;
......
} #Closed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added the check to ShouldBeFiled() and added test cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NullReferenceException
in WorkItemFiler when all results baseline state are unchange/absent/updated
context.SetProperty(ExpectedWorkItemsCount, numberOfResults); | ||
context.SetProperty(ExpectedFilingResult, FilingResult.None); | ||
|
||
TestWorkItemFiler(sarifLog, context, true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
context.SetProperty(ExpectedWorkItemsCount, numberOfResults); | ||
context.SetProperty(ExpectedFilingResult, FilingResult.None); | ||
|
||
TestWorkItemFiler(sarifLog, context, true); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Parameter adoClient controls which FilingClient mock object it generates, adoClient or githubClient. Added/updated test cases also covers githubClient.
@@ -17,6 +18,8 @@ | |||
{ | |||
public class SarifWorkItemExtensionsTests | |||
{ | |||
private readonly string testSarifFilePath = Path.Combine(Directory.GetCurrentDirectory(), "Test", "Data", "File{0}.sarif"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -290,6 +290,12 @@ public SarifWorkItemModel FileWorkItemInternal(SarifLog sarifLog, SarifWorkItemC | |||
{ | |||
string logId = sarifLog.GetProperty<Guid>(LOGID_PROPERTY_NAME).ToString(); | |||
|
|||
if (sarifLog.Runs?.Any(run => run.Results?.Any(result => result.ShouldBeFiled()) == true) != true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should add logging to this code path, don't you think? @rtaket, does someone from your team need to review this change as well?
@@ -290,6 +290,12 @@ public SarifWorkItemModel FileWorkItemInternal(SarifLog sarifLog, SarifWorkItemC | |||
{ | |||
string logId = sarifLog.GetProperty<Guid>(LOGID_PROPERTY_NAME).ToString(); | |||
|
|||
if (sarifLog.Runs?.Any(run => run.Results?.Any(result => result.ShouldBeFiled()) == true) != true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the SARIF log doesn't have any eligible result to file as a work item and it doesn't return null, the following code will create a SarifWorkItemModel:
var sarifWorkItemModel = new SarifWorkItemModel(sarifLog, filingContext);
In SarifWorkItemModel code, it iterates all results and get first result which should be filed, to construct work item title. If none of result is eligible, the SairfWorkItemModel's title will be set to null, which causes NullReferenceException when calling filingClient.FileWorkItems() to file work item.
Another solution I can think is before calling FileWorkItemInternal(), in SplitLogFile method, make sure there is only eligible results in split logs. But seems traverse of the results is still needed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved the check to SplitLogFile method, this way the sarifLog only includes eligible results to file work item, no need to traverse results. Pls let me know what do you think?
@@ -12,6 +12,11 @@ public static class SarifWorkItemsExtensions | |||
{ | |||
public static bool ShouldBeFiled(this Result result) | |||
{ | |||
if (result == null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why did we add this? Why wouldn't a null dereference be the expected condition?
i.e., why do we require
myObject?.ThisIsAnActualMethod()
to protect against a null variable but
myObject.ThisIsAnExtensionMethod()
should work when myObject is null?
I am asking a sincere question. But I'm not sure this change is a good design pattern, Shaopeng, what's your argument for it? :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it depends on which one should be responsible for the null check, the caller or the extension method.
If the caller should handle null value then we don't need this check inside extension method.
myObject?.ThisIsAnExtensionMethod()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am not sure, my thought was similar to the IDictionary cast that we were looking at last PR, either a helper already did that for you or need to cast to IDictionary everywhere it is used,
in this case if the extension method did the check for you,
or where you call the extension method.
only differ when user forgot to check null before call this extension seeing an unhandled exception because we call result.BaselineState at the first line, the other case is no exception returns false.
A quick find reference I see about 10 usages of this method.
In .net source code they also do null check at the first line of the
extension methods, like below, our logic doe not need to throw:
public static partial class StringNormalizationExtensions
{
public static bool IsNormalized(this string strInput, NormalizationForm normalizationForm)
{
if (strInput == null)
{
throw new ArgumentNullException(nameof(strInput));
}
return strInput.IsNormalized(normalizationForm);
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Like the way how .net handles in the extension method. The extension method will have similar behavior to instance method and can be protected by ? operation:
myObject?.ThisIsAnExtensionMethod()
…/microsoft/sarif-sdk into users/yongyan-gh/fileWorkItemFix
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PartitionFunction<string> partitionFunction = null; | ||
|
||
Stopwatch splittingStopwatch = Stopwatch.StartNew(); | ||
|
||
switch (splittingStrategy) | ||
{ | ||
case SplittingStrategy.None: | ||
{ | ||
// get ride of results should not be filed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove this comment. First, it does not follow convention, starting with a capital letter, ending with a period. It doesn't read very well grammatically. Not sure it provides useful additional information. Finally, this line of code is identical to other lines in this file, why are they commented? If they don't need to be, why is this line commented?
{ | ||
throw new ArgumentNullException(nameof(result)); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest removing this, because it is additional work and suggests a general pattern we should adhere that doesn't seem to have good ROI.
? 0 | ||
: results.Where(r => r.Locations != null) | ||
.SelectMany(r => r.Locations) | ||
.Count(l => l.PhysicalLocation?.ArtifactLocation?.Uri != null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
my personal opinion is this code isn't super readable and i avoid linq statements that potentially entail multiple iterations over a collection (in a pathological case).
@@ -17,6 +18,9 @@ | |||
{ | |||
public class SarifWorkItemExtensionsTests | |||
{ | |||
// Use portable file path so the tests can run on windows and other platforms. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@ -17,6 +18,9 @@ | |||
{ | |||
public class SarifWorkItemExtensionsTests | |||
{ | |||
// Use portable file path so the tests can run on windows and other platforms. | |||
private readonly string testSarifFilePath = Path.Combine(Directory.GetCurrentDirectory(), "Test", "Data", "File{0}.sarif"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Description:
BUG: Got
NullReferenceException
when WorkItemFiler tries to file a work item for the result that has baseline state should be ignored.Fixes:
result.ShouldBeFiled() == false
WorkItemFiler.FileWorkItems()
, do not create work item if all the results of target Sarif Log are not eligible for filing a work item.Currently the result is treated as it should not be file as work item if