grt: fix cugr memory crash on out-of-bounds grid access#9739
grt: fix cugr memory crash on out-of-bounds grid access#9739Divinesoumyadip wants to merge 2 commits intoThe-OpenROAD-Project:masterfrom
Conversation
Signed-off-by: Divinesoumyadip <soumyacode7@gmail.com>
|
clang-tidy review says "All clean, LGTM! 👍" |
8dfc154 to
03bdb03
Compare
There was a problem hiding this comment.
Code Review
This pull request addresses a critical crash caused by out-of-bounds memory access in the routing grid logic. The approach of clamping indices to valid boundaries is correct. However, I've identified a critical scenario where the new code can still crash if the gridlines_ vector is empty. Additionally, there's a high-severity issue where the logic for the upper bound of the returned interval can produce a negative index, which is inconsistent with the lower bound calculation. I've provided specific comments and code suggestions to address both of these issues to make the fix more robust.
| const IntervalT& loc_interval) const | ||
| { | ||
| if (dimension < 0 || dimension > 1) { | ||
| return {0, 0}; | ||
| } | ||
| const auto& lineRange = rangeSearchGridlines(dimension, loc_interval); | ||
| return {gridlines_[dimension][lineRange.low()] == loc_interval.low() | ||
| ? lineRange.low() | ||
| : std::max(lineRange.low() - 1, 0), | ||
| gridlines_[dimension][lineRange.high()] == loc_interval.high() | ||
| ? lineRange.high() - 1 | ||
| : std::min(lineRange.high(), getSize(dimension) - 1)}; | ||
|
|
There was a problem hiding this comment.
While the clamping logic prevents out-of-bounds access for non-empty gridlines_, it doesn't handle the case where gridlines_[dimension] is empty. In this scenario, rangeSearchGridlines returns {0, 0}, max_idx becomes 0, and l and h are set to 0. The subsequent access gridlines_[dimension][l] will then cause a crash, which this pull request aims to prevent.
An early exit for an empty gridline vector is needed. With this check, the std::max in the max_idx calculation also becomes redundant and can be simplified.
if (dimension < 0 || dimension > 1) return {0, 0};
if (gridlines_[dimension].empty()) {
return {0, 0};
}
const auto& lineRange = rangeSearchGridlines(dimension, loc_interval);
// BOUNDARY SHIELD: Safely clamp to array boundaries
const int max_idx = (int)gridlines_[dimension].size() - 1;
const int l = std::min(lineRange.low(), max_idx);
const int h = std::min(lineRange.high(), max_idx);| const int l = std::min(lineRange.low(), max_idx); | ||
| const int h = std::min(lineRange.high(), max_idx); | ||
|
|
||
| return { |
There was a problem hiding this comment.
The calculation for the upper bound of the returned interval can result in a negative index. If h is 0 and gridlines_[dimension][h] == loc_interval.high(), the expression evaluates to h - 1, which is -1. This is inconsistent with the lower bound calculation, which uses std::max(..., 0) to prevent negative indices. A similar protection should be applied here to ensure a non-negative index is always returned.
? std::max(0, h - 1)|
clang-tidy review says "All clean, LGTM! 👍" |
1 similar comment
|
clang-tidy review says "All clean, LGTM! 👍" |
03bdb03 to
207a5a1
Compare
|
clang-tidy review says "All clean, LGTM! 👍" |
Signed-off-by: Divinesoumyadip <soumyacode7@gmail.com>
207a5a1 to
d086195
Compare
|
clang-tidy review says "All clean, LGTM! 👍" |
|
Hi @eder-matheus ,I have addressed the edge cases mentioned by the code assist bot (added empty-vector checks and non-negative index clamping). This fix is ready for review and will prevent the SIGABRT crash in the CUGR engine for inconsistent designs. Thanks |
This change resolves a critical
Signal 6 (SIGABRT)crash in the CUGR global routing engine caused by a mismatch between physical design coordinates and the internally constructed virtual routing grid. In certain inconsistent designs, coordinates of pins, ports, or obstacles could fall outside the precomputed grid boundaries, leading to an out-of-bounds access in the routing grid data structures. The update introduces geometric boundary clamping to ensure safe projection of coordinates onto the grid and prevent memory access violations.During initialization, the CUGR router constructs a discrete 3D routing structure called
GridGraph, derived from the routing layers and track definitions specified in LEF files. Throughout routing, physical coordinates are projected onto this grid using theGridGraph::rangeSearchRowsfunction.In inconsistent configurations for example, when a design using a 13-layer metal stack is routed on a 6-layer grid, or when IO pins are located outside the defined core region,the coordinate-to-grid index calculation may generate indices larger than the size of the internal
gridlines_vector.Because the implementation previously accessed the vector directly (
gridlines_[dimension][index]) without validating the computed index, the C++ standard library detected the invalid access and triggered the assertion__n < this->size(). This resulted in an immediateSIGABRTand core dump, preventing the router from reporting which design element caused the failure.Solution
This approach ensures that coordinate projections are always mapped to a valid grid boundary, eliminating the possibility of out-of-range memory access while allowing the router to continue execution and report the underlying design inconsistency.
Implementation
By enforcing this boundary clamping, invalid coordinate projections are safely mapped to the nearest valid grid cell. Instead of causing a memory crash, the router can now continue execution and emit a handled diagnostic such as
GRT-0286 (Failed to determine parent layer), which identifies the specific net responsible for the geometry mismatch.The fix was validated using a stress-test design containing a 13-layer metal stack routed using a 6-layer routing grid.
The added
std::minandstd::maxchecks are constant-time (O(1)) operations and introduce no measurable overhead to the routing runtime.This update hardens the
GridGraphcoordinate projection logic against out-of-range memory access. By replacing a fatal crash with safe boundary handling and actionable diagnostics, the change improves the robustness and reliability of the OpenROAD routing pipeline and ensures predictable behavior even when encountering inconsistent design data.