Skip to content

odb: guard null-pointer deref in getGCellTileSize()'s layer lookup - #11264

Merged
osamahammad21 merged 2 commits into
The-OpenROAD-Project:masterfrom
dhgaddy:gcell-backside-ordinal-null-guard
Aug 30, 2026
Merged

odb: guard null-pointer deref in getGCellTileSize()'s layer lookup#11264
osamahammad21 merged 2 commits into
The-OpenROAD-Project:masterfrom
dhgaddy:gcell-backside-ordinal-null-guard

Conversation

@dhgaddy

@dhgaddy dhgaddy commented Aug 29, 2026

Copy link
Copy Markdown
Contributor

Summary

Symptom

dbBlock::getGCellTileSize() segfaults instead of raising the intended ODB-0358 error, on a technology whose leading routing layers are backside metals (e.g. a BSPDN stack):

Program received signal SIGSEGV, Segmentation fault.
0x0000000000dddfd3 in odb::dbTechLayer::getName (this=0x0) at ./src/odb/src/db/dbTechLayer.cpp:1313
1313      return layer->name_;
#0  odb::dbTechLayer::getName (this=0x0) at ./src/odb/src/db/dbTechLayer.cpp:1313
#1  odb::dbBlock::getGCellTileSize()::$_0::operator()(int) const (layer_idx=2) at ./src/odb/src/db/dbBlock.cpp:2545
#2  odb::dbBlock::getGCellTileSize (this=0x7ffff779c6f8) at ./src/odb/src/db/dbBlock.cpp:2564

Root cause

getAverageTrackSpacing(), a lambda inside getGCellTileSize(), finds the Nth frontside (non-backside) ROUTING layer by counting layers while skipping any with dbTechLayer::isBackside() set. The baseline call site always requests the 2nd, 3rd, and 4th frontside layer once the block's max routing layer (raw, backside-inclusive numbering) is >= 4, regardless of how many frontside layers actually exist below it. When a technology has fewer than N frontside layers before that point, the search loop never assigns tech_layer, leaving it null.

The existing null check on the resulting track_grid then built its error message by unconditionally calling tech_layer->getName() -- dereferencing the same pointer the check just proved could be null, crashing on the error-reporting path itself instead of raising ODB-0358.

Fix

Guard the error message against a null tech_layer, reporting which frontside layer ordinal was requested and how many actually exist instead of dereferencing it.

Testing

New regression src/odb/test/cpp/TestGCellTileSize.cpp, registered in both CMake and Bazel. It constructs a tech with 4 backside ROUTING layers ahead of a single frontside layer (M1) and a max routing layer past the early-return threshold, then asserts getGCellTileSize() throws std::runtime_error (the documented behavior of Logger::error()) instead of crashing. Confirmed by reverting just the fix hunk: the test segfaults against master, passes with this change.

bazel test //src/odb/test/cpp:TestGCellTileSize and bazel test //:dup_id_test both pass. clang-format --dry-run -Werror is clean on both changed files.

Type of Change

  • Bug fix

Impact

No crash (ODB-0358 error instead) when dbBlock::getGCellTileSize() is called on a technology with fewer frontside routing layers than the lookup expects.

Verification

  • I have verified that the local build succeeds (./etc/Build.sh).
  • I have run the relevant tests and they pass.
  • My code follows the repository's formatting guidelines.
  • I have included tests to prevent regressions.
  • I have signed my commits (DCO).

Related Issues

#11263

getAverageTrackSpacing() (a lambda inside dbBlock::getGCellTileSize())
counts frontside (non-backside) ROUTING layers to find the Nth one for
a given layer_idx, but the baseline call site unconditionally asks for
the 2nd/3rd/4th frontside layer once the raw (backside-inclusive) max
routing layer is at least 4. On a technology whose leading routing
layers are backside (e.g. a BSPDN stack), that lookup can fail to find
a layer at all, leaving the local tech_layer pointer null.

The existing null check on the resulting track_grid then logged an
error message that unconditionally dereferenced tech_layer to build
it (tech_layer->getName()), crashing on the error-reporting path
itself instead of raising the intended error.

Guard the error message against a null tech_layer, reporting which
frontside layer ordinal was requested and how many actually exist
instead of dereferencing a null pointer.

Related to The-OpenROAD-Project#10547 (adds is_backside tracking and a similar null-guard
pattern for backside layers elsewhere in DRT's track assignment) but a
distinct bug, in ODB's GCell tile sizing rather than DRT.

Added a regression test (src/odb/test/cpp/TestGCellTileSize.cpp) that
reproduces the crash directly: a tech with 4 backside layers ahead of
a single frontside layer, with max routing layer set past the
early-return threshold. Confirmed this segfaults without the fix and
passes (raising the intended ODB-0358 error) with it.

Signed-off-by: dgaddy <dgaddy@ucsc.edu>
@dhgaddy
dhgaddy requested a review from a team as a code owner August 29, 2026 07:05
@dhgaddy
dhgaddy requested a review from osamahammad21 August 29, 2026 07:05

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request fixes a potential null-pointer dereference in dbBlock::getGCellTileSize() when a technology contains fewer frontside routing layers than expected (for example, when backside routing layers precede frontside layers). It safely handles a null tech_layer by formatting an informative error message instead of crashing. Additionally, a new unit test TestGCellTileSize has been added to verify this behavior and prevent regressions. I have no further feedback to provide on these changes.

tech_layer = layer;
break;
}
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the tech layer isn't found we should error out before we call findTrackGrid. Please break up the error message into two separate errors

Per review feedback (The-OpenROAD-Project#11264): the null-tech_layer and null-track_grid
cases were folded into one error message via a ternary, calling
findTrackGrid() even when tech_layer was still null. Split into two
distinct errors instead: error immediately if the requested frontside
routing layer doesn't exist at all (ODB-1219, before ever calling
findTrackGrid()), then check for a missing track grid only once
tech_layer is guaranteed non-null (ODB-0358, now unconditional on
tech_layer since it can no longer be null at that point).

Tightened the existing regression test to assert on the specific
error code raised (ODB-1219) rather than just std::runtime_error, and
added a second test covering the other split path (layer found, no
track grid yet -> ODB-0358).

Signed-off-by: dgaddy <dgaddy@ucsc.edu>

@osamahammad21 osamahammad21 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @dhgaddy

@osamahammad21
osamahammad21 merged commit 3ca581e into The-OpenROAD-Project:master Aug 30, 2026
16 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants