Skip to content

Commit 16ac05c

Browse files
authored
Merge pull request #301 from The-OpenROAD-Project-staging/sta_nondet_crash_debug
Handle MT issues in setVertexArrivals, fix non-determ crash
2 parents adb933f + 16c2678 commit 16ac05c

4 files changed

Lines changed: 65 additions & 5 deletions

File tree

graph/Graph.cc

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1126,6 +1126,12 @@ Vertex::deletePaths()
11261126
tag_group_index_ = tag_group_index_max;
11271127
}
11281128

1129+
void
1130+
Vertex::setPathsDeferred(Path *paths)
1131+
{
1132+
paths_ = paths;
1133+
}
1134+
11291135
bool
11301136
Vertex::hasFanin() const
11311137
{

include/sta/Graph.hh

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,9 @@ public:
264264
Path *makePaths(uint32_t count);
265265
void setPaths(Path *paths);
266266
void deletePaths();
267+
// Set paths_ without deleting the old array.
268+
// Caller is responsible for deferred deletion of the old array.
269+
void setPathsDeferred(Path *paths);
267270
TagGroupIndex tagGroupIndex() const;
268271
void setTagGroupIndex(TagGroupIndex tag_index);
269272
// Slew is annotated by sdc set_annotated_transition cmd.

include/sta/Search.hh

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,7 @@ protected:
414414
void initVars();
415415
void deleteTags();
416416
void deleteTagsPrev();
417+
void deletePendingPaths();
417418
void deleteUnusedTagGroups();
418419
void seedInvalidArrivals();
419420
void seedArrivals();
@@ -600,6 +601,10 @@ protected:
600601
std::mutex invalid_arrivals_lock_;
601602
BfsFwdIterator *arrival_iter_;
602603
ArrivalVisitor *arrival_visitor_;
604+
// Old vertex path arrays deferred for deletion until after the parallel
605+
// BFS level completes, preventing use-after-free in concurrent CRPR readers.
606+
std::vector<Path*> paths_pending_delete_;
607+
std::mutex paths_pending_delete_lock_;
603608

604609
// Some requireds exist.
605610
bool requireds_exist_;

search/Search.cc

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -708,6 +708,20 @@ Search::deleteTagsPrev()
708708
for (TagGroup** tag_groups: tag_groups_prev_)
709709
delete [] tag_groups;
710710
tag_groups_prev_.clear();
711+
712+
deletePendingPaths();
713+
}
714+
715+
// Free old vertex path arrays that were deferred during parallel BFS visits.
716+
// Called after visitParallel completes so no thread can still hold a pointer
717+
// into any of these arrays.
718+
void
719+
Search::deletePendingPaths()
720+
{
721+
LockGuard lock(paths_pending_delete_lock_);
722+
for (Path *paths : paths_pending_delete_)
723+
delete [] paths;
724+
paths_pending_delete_.clear();
711725
}
712726

713727
void
@@ -2815,8 +2829,28 @@ void
28152829
Search::setVertexArrivals(Vertex *vertex,
28162830
TagGroupBldr *tag_bldr)
28172831
{
2818-
if (tag_bldr->empty())
2819-
deletePathsIncr(vertex);
2832+
if (tag_bldr->empty()) {
2833+
// Inline the deletePathsIncr logic using deferred deletion so that
2834+
// concurrent CRPR/latch readers that hold a pointer into the old path
2835+
// array are not left with a dangling pointer.
2836+
tnsNotifyBefore(vertex);
2837+
if (worst_slacks_)
2838+
worst_slacks_->worstSlackNotifyBefore(vertex);
2839+
TagGroup *tag_group = tagGroup(vertex);
2840+
if (tag_group) {
2841+
Path *old_paths = vertex->paths();
2842+
// Clear the tag group index first so concurrent readers observe a
2843+
// null tag group (and return early from Path::vertexPath) before
2844+
// we touch paths_.
2845+
vertex->setTagGroupIndex(tag_group_index_max);
2846+
vertex->setPathsDeferred(nullptr);
2847+
tag_group->decrRefCount();
2848+
if (old_paths) {
2849+
LockGuard lock(paths_pending_delete_lock_);
2850+
paths_pending_delete_.push_back(old_paths);
2851+
}
2852+
}
2853+
}
28202854
else {
28212855
TagGroup *prev_tag_group = tagGroup(vertex);
28222856
Path *prev_paths = vertex->paths();
@@ -2827,13 +2861,25 @@ Search::setVertexArrivals(Vertex *vertex,
28272861
}
28282862
else {
28292863
if (prev_tag_group) {
2830-
vertex->deletePaths();
2864+
// Clear the tag group index before replacing paths so concurrent
2865+
// readers see a consistent null-tag-group state during the
2866+
// transition and do not mix the old tag group with the new array.
2867+
vertex->setTagGroupIndex(tag_group_index_max);
28312868
prev_tag_group->decrRefCount();
28322869
requiredInvalid(vertex);
28332870
}
28342871
size_t path_count = tag_group->pathCount();
2835-
Path *paths = vertex->makePaths(path_count);
2836-
tag_bldr->copyPaths(tag_group, paths);
2872+
// Allocate the new array and switch paths_ directly from old to new
2873+
// without creating a null window or freeing the old array immediately.
2874+
// This prevents concurrent CRPR/latch readers from observing either a
2875+
// null pointer or a freed (dangling) pointer.
2876+
Path *new_paths = new Path[path_count];
2877+
vertex->setPathsDeferred(new_paths);
2878+
if (prev_paths) {
2879+
LockGuard lock(paths_pending_delete_lock_);
2880+
paths_pending_delete_.push_back(prev_paths);
2881+
}
2882+
tag_bldr->copyPaths(tag_group, new_paths);
28372883
vertex->setTagGroupIndex(tag_group->index());
28382884
tag_group->incrRefCount();
28392885
}

0 commit comments

Comments
 (0)