Fix UB in link_holes: iterator stored in realloc-based Array without construction - #331
Merged
Conversation
…e a realloc-based gdstk::Array without construction, which crashes under MSVC /D_ITERATOR_DEBUG_LEVEL=2 (Debug builds) because operator= reads the iterator's debug-linkage fields from uninitialized memory. Store an index instead.
Owner
|
Thanks! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Problem
link_holes()insrc/clipper_tools.cppstores aClipperLib::Path::iteratorinside
SortingPath, and instances ofSortingPathlive in agdstk::Array<SortingPath>.gdstk::Arraygrows viarealloc()/plainassignment and never invokes constructors on its slots, so the iterator ends up
copy-assigned into memory that was never constructed.
Under MSVC with
_ITERATOR_DEBUG_LEVEL=2(the default for Debug builds),std::vector<T>::iteratoris not a bare pointer: it carries_Myproxy/_Mynextiterbookkeeping used to register itself in a linked list owned by itsvector, and
operator=reads those fields on the left-hand side beforeoverwriting them. Reading them out of uninitialized memory is undefined
behavior, and in practice it reads a garbage pointer and crashes with an access
violation the moment
gdstk::boolean(...)needs to produce a polygon with ahole (e.g.
Operation::Notwhere one operand is fully contained in the other).Release builds (and any
/D_ITERATOR_DEBUG_LEVEL=0configuration) don't showthis, because there
std::vector<T>::iteratordegenerates to a thin pointerwrapper with a trivial
operator=, so the same UB happens to be harmless —which is presumably why this has gone unnoticed.