Skip to content

Fix crash on Verilog escaped-identifier ports containing /#10275

Merged
maliberty merged 4 commits intoThe-OpenROAD-Project:masterfrom
The-OpenROAD-Project-staging:fix_sdc_hang_lef_crash
Apr 28, 2026
Merged

Fix crash on Verilog escaped-identifier ports containing /#10275
maliberty merged 4 commits intoThe-OpenROAD-Project:masterfrom
The-OpenROAD-Project-staging:fix_sdc_hang_lef_crash

Conversation

@openroad-ci
Copy link
Copy Markdown
Collaborator

@openroad-ci openroad-ci commented Apr 27, 2026

Summary

Problem

check_setup -verbose (and any path through dbNetwork::direction → dbModBTerm::getIoType) crashes with SIGSEGV on netlists where a module port name is a SystemVerilog escaped identifier containing /.
Concretely, Fusion Compiler emits port declarations like:

module Mname (
    ...
     \path/with/slash,
    ...);
  output \path/with/slash ;

This is a legal SV escaped identifier and OpenSTA's Verilog reader correctly preserves it. The resulting dbModBTerm is stored in dbModule::modbterm_hash_ keyed by the literal name (with / characters intact).
However, dbModule::findModBTerm unconditionally truncated the lookup key at the last / before hashing, so the lookup missed → caller dereferenced a null dbModBTerm → crash.

Backtrace:

  dbModBTerm::getIoType
    dbNetwork::direction(Pin*)
      Network::isLoad(Pin*)
        FindNetDrvrLoads::operator()
          dbNetwork::visitConnectedPins
            ...
              Sta::ensureGraph
                Sta::checkTiming

Fix

Single change in src/odb/src/db/dbModule.cpp:545 (dbModule::findModBTerm): try a full-name hash lookup first, and fall back to the trailing-segment lookup only when the full name misses. This handles modbterms whose stored names legitimately contain the hierarchy delimiter (escaped-identifier ports), without altering behavior for any caller that was already passing a hierarchical path to a non-hierarchical port name.

Files changed

  • src/odb/src/db/dbModule.cpp — two-step lookup in findModBTerm.
  • src/dbSta/test/hier_weird_port.{v,tcl,ok} — new regression. Reads a netlist with an escaped-identifier port containing /, runs check_setup -verbose (the path that previously crashed), and verifies pin-direction resolution succeeds.
  • src/dbSta/test/CMakeLists.txt, src/dbSta/test/BUILD — register the new test.

Type of Change

  • Bug fix

Impact

Fixes a crash in a SiliconCompiler testcase and is reproducible in the small TCL added in this PR

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 signed my commits (DCO).

Related Issues

@github-actions
Copy link
Copy Markdown
Contributor

clang-tidy review says "All clean, LGTM! 👍"

Copy link
Copy Markdown
Contributor

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

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 modifies dbModule::findModBTerm to correctly handle port names containing hierarchy delimiters, such as escaped identifiers, by attempting a full-name lookup before falling back to the trailing segment. A new regression test, hier_weird_port, has been added to verify the fix. Feedback recommends optimizing the lookup logic to minimize std::string allocations by using strrchr to identify the hierarchy delimiter directly on the input character pointer.

Comment thread src/odb/src/db/dbModule.cpp Outdated
Comment on lines +555 to +564
auto it = obj->modbterm_hash_.find(std::string(name));
if (it == obj->modbterm_hash_.end()) {
std::string leaf(name);
const char hier_delimiter = getOwner()->getHierarchyDelimiter();
size_t last_idx = leaf.find_last_of(hier_delimiter);
if (last_idx != std::string::npos) {
leaf = leaf.substr(last_idx + 1);
it = obj->modbterm_hash_.find(leaf);
}
}
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.

medium

The current implementation performs multiple std::string allocations and copies (one for the initial lookup, one for the leaf copy, and one for the substr). This can be optimized by using strrchr to find the hierarchy delimiter directly on the input const char* and only performing a second lookup if necessary. This avoids redundant string constructions and improves both performance and readability.

  auto it = obj->modbterm_hash_.find(name);
  if (it == obj->modbterm_hash_.end()) {
    const char hier_delimiter = getOwner()->getHierarchyDelimiter();
    const char* last_delim = strrchr(name, hier_delimiter);
    if (last_delim != nullptr) {
      it = obj->modbterm_hash_.find(last_delim + 1);
    }
  }

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.

Good catch on the leaf-path string ops — the strrchr + last_delim + 1 form is cleaner and skips one allocation when the fallback fires. Note though that the first lookup isn't a savings: find(name) on
unordered_map<string, …> still implicitly constructs a std::string for the key compare, identical to the prior explicit std::string(name) — applied for the readability, not as a hot-path perf fix.

@dsengupta0628
Copy link
Copy Markdown
Contributor

@codex review

@dsengupta0628
Copy link
Copy Markdown
Contributor

@chatgpt-codex-connector
Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 👍

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Signed-off-by: dsengupta0628 <dsengupta@precisioninno.com>
@github-actions
Copy link
Copy Markdown
Contributor

clang-tidy review says "All clean, LGTM! 👍"

@dsengupta0628
Copy link
Copy Markdown
Contributor

Secure-ci http://secure-ci:8080/job/SB/job/secure-fix_crash_odb/

All clean here

Comment thread src/odb/src/db/dbModule.cpp Outdated

// Try the full name first. modbterm names may legitimately contain the
// hierarchy delimiter (e.g. escaped-identifier ports emitted by Fusion
// Compiler), so unconditionally truncating at the last '/' would miss
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.

How about removing the specific commercial tool name in the comment?

Signed-off-by: dsengupta0628 <dsengupta@precisioninno.com>
@github-actions
Copy link
Copy Markdown
Contributor

clang-tidy review says "All clean, LGTM! 👍"

@maliberty maliberty merged commit 512e44c into The-OpenROAD-Project:master Apr 28, 2026
14 of 16 checks passed
@maliberty maliberty deleted the fix_sdc_hang_lef_crash branch April 28, 2026 21:17
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.

4 participants