-
Notifications
You must be signed in to change notification settings - Fork 8.1k
Fix null reference when markdown content is empty #7463
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 null reference when markdown content is empty #7463
Conversation
iSazonov
left a comment
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 wonder that we have to check so many null references. Seems we need review all the code (not in the PR).
| protected override void Write(VT100Renderer renderer, FencedCodeBlock obj) | ||
| { | ||
| foreach (var codeLine in obj.Lines.Lines) | ||
| if (obj?.Lines != null && obj.Lines.Lines != 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.
If we use "?" we could do
if (obj?.Lines?.Lines != 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.
Updated to obj?.Lines.Lines != null
obj.Lines is of type StringLineGroup which cannot be null.
| if (obj?.Lines != null && obj.Lines.Lines != null) | ||
| { | ||
| if (!string.IsNullOrWhiteSpace(codeLine.ToString())) | ||
| foreach (var codeLine in obj?.Lines.Lines) |
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.
We have checked obj != null in previous line and could remove "?"
foreach (var codeLine in obj.Lines.Lines) 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.
Fixed
| { | ||
| // Format header and then add blank line to improve readability. | ||
| switch (obj.Level) | ||
| string headerText = obj.Inline?.FirstChild?.ToString(); |
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.
Should we check obj != null too?
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.
Fixed.
| else | ||
| { | ||
| renderer.Write(renderer.EscapeSequences.FormatLink(obj.FirstChild.ToString(), obj.Url)); | ||
| renderer.Write(renderer.EscapeSequences.FormatLink(obj.FirstChild?.ToString(), obj.Url)); |
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.
We check obj.FirstChild != null in both code path in the "if-else" - seems we should move the check to new "if":
if (obj.FirstChild != null)
{
if (obj.IsImage)
{
renderer.Write(renderer.EscapeSequences.FormatImage(obj.FirstChild.ToString()));
}
else
{
renderer.Write(renderer.EscapeSequences.FormatLink(obj.FirstChild.ToString(), obj.Url));
}
}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.
The question marks here would have different semantics of course, but I imagine FormatLink will thrown an NRE if its first argument is null.
So I would do similar to @iSazonov (just a style change):
if (obj.FirstChild == null)
{
return;
}
if (obj.IsImage)
{
renderer.Write(renderer.EscapeSequences.FormatImage(obj.FirstChild.ToString()));
}
else
{
renderer.Write(renderer.EscapeSequences.FormatLink(obj.FirstChild.ToString(), obj.Url));
}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.
We support having empty alt-text for images and empty link text. So updated accordingly.
| if (obj?.Lines.Lines != null) | ||
| { | ||
| if (!string.IsNullOrWhiteSpace(codeLine.ToString())) | ||
| foreach (var codeLine in obj.Lines.Lines) |
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.
string instead of var would be more obvious here
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.
Fixed
| string text = obj?.FirstChild?.ToString(); | ||
|
|
||
| // Format link as image or link. | ||
| if (obj.IsImage) |
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 obj is null, this will cause an NRE. Would the logic be preserved like this:
string text = obj?.FirstChild?.ToString();
if (text == null)
{
return;
}
// Golden path code...?
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.
obj can never be null, hence removed ? after obj.
We allow text to be null hence the above logic holds.
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 (obj.IsImage) - can cause an NRE.
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.
@iSazonov obj is guaranteed to be not null. If it is null the renderer is not called.
|
@rjmholt Updated. |
rjmholt
left a comment
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.
LGTM!
| // This specifically helps for parameters help content. | ||
| if (string.Equals(obj.Info, "yaml", StringComparison.OrdinalIgnoreCase)) | ||
| { | ||
| renderer.Write("\t").WriteLine(codeLine.ToString()); |
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.
We call codeLine.ToString()) twice above - should we use a variable?
And in line 34 too.
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.
One is in if and other is in else, so only one of them is called. And this change is out of scope for this PR.
|
@daxian-dbw @SteveL-MSFT The PR is ready to merge if you haven't comments. |
Fix #7453
PR Summary
Fix cases where markdown content can be empty and we get a null reference exception.
PR Checklist
.h,.cpp,.cs,.ps1and.psm1files have the correct copyright headerWIP:to the beginning of the title and remove the prefix when the PR is ready.[feature]if the change is significant or affects feature tests