Description
In a 3DBlox design loaded with read_3dbx, the web viewer's Timing Report widget
lists paths correctly, but clicking any path row (or any pin row in the detail
table) crashes OpenROAD with SIGSEGV and the process exits.
The crash is a null-pointer dereference, so the try/catch (const std::exception&)
around the handler does not contain it — the whole tool dies and the session is lost.
Steps to reproduce
-
From the attached directory https://drive.google.com/file/d/1w-GIUGuUxtFouo8apsCRPhktUZuMuknT/view?usp=drive_link , run openroad web.tcl (latest openroad master should work)
-
Open http://localhost:8080, open the Timing Report widget, click Update.
The 100 worst paths are listed as expected.
-
Click any path row.
Actual
[INFO WEB-0001] Server started on http://localhost:8080.
Signal 11 received
Stack trace:
...
Segmentation fault (core dumped)
(The symbolized trace from a stripped binary is misleading — addr2line snaps the
frames onto unrelated nearest symbols such as abc::CaDiCaL::... and
sta::Sdc::clear. Ignore those names; the fault location is below.)
Expected
Either the path is highlighted in the layout at its true (per-chiplet, transformed)
location, or nothing is highlighted — but no crash.
Root cause (by Claude)
TimingHandler::handleTimingHighlight takes the design's single top block and passes
it straight into the shape collector:
- src/web/src/request_handler.cpp:2546 — odb::dbBlock* block = gen_->getBlock();
- src/web/src/tile_generator.cpp:1882 — TileGenerator::getBlock() returns
db_->getChip()->getBlock()
- src/web/src/request_handler.cpp:2547 — collectTimingPathShapes(block, ...)
- src/web/src/tile_generator.cpp:5529 — resolvePin() does
block->findITerm(pin_name.c_str()) with no null check
For a 3DBlox stack the db top chip is the HIER chip, which owns no block. Verified
on the failing design:
set top [[ord::get_db] getChip]
puts "[$top getName] type=[$top getChipType] block=[$top getBlock]"
=> logic_memory_f2f type=HIER block=NULL
So block is nullptr and resolvePin faults. The pin-row click path
(src/web/src/request_handler.cpp:2553) calls resolvePin(block, pin_name)
directly and faults the same way.
The path list works because TimingReport::getReport() only touches STA and never
an odb block — which is why the crash needs the click.
Two further defects on the same code path
- Pin names are not chiplet-qualified. TimingReport::expandPath stores
dbITerm::getName() / dbBTerm::getName()
(src/web/src/timing_report.cpp:106-112), which is block-local. In a stack, the
two chiplet blocks share one name namespace, so even against a non-null block a
single findITerm lookup is ambiguous or misses. The name shown in the widget
also drops the chiplet prefix that report_checks prints
(logic_die_0/..., memory_die_0/...).
- Shapes are not lifted into root coordinates. collectNetShapes
(src/web/src/tile_generator.cpp:5567) returns wire/pin geometry in the owning
block's coordinates. Chiplet geometry needs the accumulated local-to-root
transform (ChipletNode::world_xfm, src/web/src/tile_generator.h:139, produced
by collectChiplets()). Without it a highlight for a flipped die — e.g. one placed
MZ_MX — would paint mirrored. A die at R0/(0,0) would be right only by accident.
Same unguarded call exists in the static-report writer,
src/web/src/web.cpp:1158; that function bails earlier at
src/web/src/web.cpp:1053-1056 with [ERROR WEB-0035] No design loaded., which is a
misleading message for a 3DBlox design that is loaded.
Environment
- OpenROAD master @ f552262, build features: -GPU +GUI -Python
- Linux x86-64
- Design: two ASAP7 chiplets bonded face-to-face (MZ_MX flip), dies read from DEF
via .3dbv/.3dbx; ~290k insts per die. No SPEF annotated.
Description
In a 3DBlox design loaded with
read_3dbx, the web viewer's Timing Report widgetlists paths correctly, but clicking any path row (or any pin row in the detail
table) crashes OpenROAD with SIGSEGV and the process exits.
The crash is a null-pointer dereference, so the
try/catch (const std::exception&)around the handler does not contain it — the whole tool dies and the session is lost.
Steps to reproduce
From the attached directory https://drive.google.com/file/d/1w-GIUGuUxtFouo8apsCRPhktUZuMuknT/view?usp=drive_link , run
openroad web.tcl(latest openroad master should work)Open http://localhost:8080, open the Timing Report widget, click Update.
The 100 worst paths are listed as expected.
Click any path row.
Actual
[INFO WEB-0001] Server started on http://localhost:8080.
Signal 11 received
Stack trace:
...
Segmentation fault (core dumped)
(The symbolized trace from a stripped binary is misleading — addr2line snaps the
frames onto unrelated nearest symbols such as abc::CaDiCaL::... and
sta::Sdc::clear. Ignore those names; the fault location is below.)
Expected
Either the path is highlighted in the layout at its true (per-chiplet, transformed)
location, or nothing is highlighted — but no crash.
Root cause (by Claude)
TimingHandler::handleTimingHighlight takes the design's single top block and passes
it straight into the shape collector:
db_->getChip()->getBlock()
block->findITerm(pin_name.c_str()) with no null check
For a 3DBlox stack the db top chip is the HIER chip, which owns no block. Verified
on the failing design:
set top [[ord::get_db] getChip]
puts "[$top getName] type=[$top getChipType] block=[$top getBlock]"
=> logic_memory_f2f type=HIER block=NULL
So block is nullptr and resolvePin faults. The pin-row click path
(src/web/src/request_handler.cpp:2553) calls resolvePin(block, pin_name)
directly and faults the same way.
The path list works because TimingReport::getReport() only touches STA and never
an odb block — which is why the crash needs the click.
Two further defects on the same code path
dbITerm::getName() / dbBTerm::getName()
(src/web/src/timing_report.cpp:106-112), which is block-local. In a stack, the
two chiplet blocks share one name namespace, so even against a non-null block a
single findITerm lookup is ambiguous or misses. The name shown in the widget
also drops the chiplet prefix that report_checks prints
(logic_die_0/..., memory_die_0/...).
(src/web/src/tile_generator.cpp:5567) returns wire/pin geometry in the owning
block's coordinates. Chiplet geometry needs the accumulated local-to-root
transform (ChipletNode::world_xfm, src/web/src/tile_generator.h:139, produced
by collectChiplets()). Without it a highlight for a flipped die — e.g. one placed
MZ_MX — would paint mirrored. A die at R0/(0,0) would be right only by accident.
Same unguarded call exists in the static-report writer,
src/web/src/web.cpp:1158; that function bails earlier at
src/web/src/web.cpp:1053-1056 with [ERROR WEB-0035] No design loaded., which is a
misleading message for a 3DBlox design that is loaded.
Environment
via .3dbv/.3dbx; ~290k insts per die. No SPEF annotated.