-
-
Notifications
You must be signed in to change notification settings - Fork 716
BUG: Avoid copying uninitialized pixels in CastImageFilter #5680
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
|
|
@@ -21,6 +21,7 @@ | |||
| #include "itkProgressReporter.h" | ||||
| #include "itkImageAlgorithm.h" | ||||
| #include "itkImageRegionRange.h" | ||||
| #include "itkVariableLengthVector.h" | ||||
|
|
||||
| namespace itk | ||||
| { | ||||
|
|
@@ -156,12 +157,19 @@ CastImageFilter<TInputImage, TOutputImage>::DynamicThreadedGenerateDataDispatche | |||
| while (inputIt != inputEnd) | ||||
| { | ||||
| const InputPixelType & inputPixel = *inputIt; | ||||
| OutputPixelType outputPixel{ *outputIt }; | ||||
|
|
||||
| using OutputPixelValueType = typename OutputPixelType::ValueType; | ||||
|
|
||||
| constexpr bool isVariableLengthVector = std::is_same_v<OutputPixelType, VariableLengthVector<OutputPixelValueType>>; | ||||
|
|
||||
| // If the output pixel type is a VariableLengthVector, it behaves as a "reference" to the internal data. Otherwise | ||||
| // declare outputPixel as a reference, `OutputPixelType &`, to allow it to access the internal buffer directly. | ||||
| std::conditional_t<isVariableLengthVector, OutputPixelType, OutputPixelType &> outputPixel{ *outputIt }; | ||||
|
Comment on lines
+163
to
+167
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please check if this is the best criterion for choosing between:
Another possibility might be: check if
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I assume that CastImageFilter supports
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not to mention
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Given that point, it's certainly safer to check for VectorImage than the pixel type. The case for the Vector pixel type having "undefined" behavior for this situation, I have been struggling with. I suppose if the output pixel type was something like a std::vector ( or a variable length vector), there would be a major problem with the pixel being a non-trivial object. However, for these trivial object I am not sure/convinced that assigning ( and not observing) the indeterminate value is really undefined behavior.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thanks for the link, @blowekamp Looks like "If an evaluation produces an indeterminate value, the behavior is undefined." 🤷
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry, I prefer the currently proposed: std::conditional_t<isVariableLengthVector, OutputPixelType, OutputPixelType &> outputPixel{ *outputIt };Rather than: if constexpr (IsOutputVectorImage)
{
OutputPixelType outputPixel{ *outputIt };
}
else
{
OutputPixelType & outputPixel{ *outputIt };
}I don't like too much code duplication. So I just stick with the current PR 🤷
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Here at line 103 you proposed two differ loops: A similar things can be done with the Ranged iterator. The needs for the two loops and setting them are different, by as well just make two. We are conviently using the range for loop so it's rather small the duplication. Each loop can do it's one thing well.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
(*outputIt)[k] = static_cast<OutputPixelValueType>(inputPixel[k]);For VectorImage,
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
You know I felt very bad 😞 when I did so! You see, the "if" in InsightSoftwareConsortium/ITKPerformanceBenchmarking#109 has a if constexpr (isVariableLengthVector<OutputPixelType>)
{
OutputPixelType value(outputIt.Get());
for (unsigned int k = 0; k < componentsPerPixel; ++k)
{
value[k] = static_cast<typename OutputPixelType::ValueType>(inputPixel[k]);
}
}
else
{
OutputPixelType value;
for (unsigned int k = 0; k < componentsPerPixel; ++k)
{
value[k] = static_cast<typename OutputPixelType::ValueType>(inputPixel[k]);
}
outputIt.Set(value);
}I did not know how to replace this
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This does not contain this discussed ( and I thought agreed upon ) change to detect VectorImage instead of VariableLengthVector. This theoretical case of Image of VariableLengthVetor would not work. The optimization where the VariableLengthVector reference the vector image buffers is done here:
This would not apply with other Image types, and the check should be based on the image type not the pixel type. |
||||
|
|
||||
| for (unsigned int k = 0; k < componentsPerPixel; ++k) | ||||
| { | ||||
| outputPixel[k] = static_cast<typename OutputPixelType::ValueType>(inputPixel[k]); | ||||
| outputPixel[k] = static_cast<OutputPixelValueType>(inputPixel[k]); | ||||
| } | ||||
| *outputIt = outputPixel; | ||||
| ++inputIt; | ||||
| ++outputIt; | ||||
| } | ||||
|
|
||||
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 type
VariableLengthVectoris referenced in the template code but is not included or forward declared in this header file. While it may work when VectorImage is used (which transitively includes VariableLengthVector), it would be more robust to add a forward declaration at the top of the file or include the header directly. Consider addingtemplate <typename TValue> class VariableLengthVector;in the itk namespace before the CastImageFilter class, or add#include "itkVariableLengthVector.h"to the includes.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.
OK, thanks, that makes sense!