Skip to content

Commit e077b67

Browse files
authored
Merge pull request #10225 from The-OpenROAD-Project-staging/secure-fix-10210-sizeup-stale-prev-pin
rsz: use prev_arc input port to fix repair_timing SIGSEGV (#10210)
2 parents 27e6ac2 + 5a31bf9 commit e077b67

7 files changed

Lines changed: 116 additions & 14 deletions

File tree

src/dbSta/test/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,7 @@ cc_test(
295295
"Nangate45/Nangate45.lef",
296296
"Nangate45/Nangate45_typ.lib",
297297
"cpp/TestDbSta_0.v",
298+
"cpp/TestDbSta_StalePrevPath.v",
298299
],
299300
deps = [
300301
"//src/dbSta",

src/dbSta/test/cpp/TestDbSta.cc

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,12 @@
88
#include "db_sta/dbNetwork.hh"
99
#include "gtest/gtest.h"
1010
#include "odb/db.h"
11+
#include "odb/dbTypes.h"
12+
#include "sta/Graph.hh"
1113
#include "sta/NetworkClass.hh"
14+
#include "sta/Path.hh"
15+
#include "sta/SdcClass.hh"
16+
#include "sta/Sta.hh"
1217
#include "tst/IntegratedFixture.h"
1318

1419
namespace sta {
@@ -97,4 +102,71 @@ TEST_F(TestDbSta, TestHierarchyConnectivity)
97102
ASSERT_EQ(bterm_clk->getITerm(), nullptr);
98103
}
99104

105+
// Regression for #10210 (stale Path* dereference in rsz).
106+
//
107+
// Topology (TestDbSta_StalePrevPath.v):
108+
// clk -> b1(BUF) -> inv1(INV) -> nd1(NAND2) -> out1
109+
// nd1/A2 <- in2
110+
//
111+
// Flow:
112+
// 1. Capture drvr_path at nd1/ZN and snapshot prevPath() pointer + pin name
113+
// 2. Delete upstream b1 + updateTiming -> free
114+
// 3. Add a fresh BUF + clock + updateTiming -> recycle
115+
// 4. Assert the captured Path's prev slot has been recycled: pin()
116+
// decodes to data that belongs to a different instance than nd1's
117+
// real input.
118+
TEST_F(TestDbSta, StalePrevPath)
119+
{
120+
const auto* test_info = testing::UnitTest::GetInstance()->current_test_info();
121+
const std::string test_name
122+
= std::string(test_info->test_suite_name()) + "_" + test_info->name();
123+
readVerilogAndSetup(test_name + ".v");
124+
sta_->updateTiming(true);
125+
126+
Network* network = sta_->network();
127+
128+
Instance* nd1 = db_network_->dbToSta(block_->findInst("nd1"));
129+
Path* drvr_path = sta_->vertexWorstArrivalPath(
130+
sta_->ensureGraph()->pinDrvrVertex(network->findPin(nd1, "ZN")),
131+
MinMax::max());
132+
ASSERT_NE(drvr_path, nullptr);
133+
ASSERT_EQ(network->pathName(drvr_path->pin(sta_.get())), "nd1/ZN");
134+
const Path* pre_addr = drvr_path->prevPath();
135+
ASSERT_NE(pre_addr, nullptr);
136+
const std::string pre_pin_name = network->pathName(pre_addr->pin(sta_.get()));
137+
138+
// 2. Free upstream Path[] slots.
139+
sta_->deleteInstance(db_network_->dbToSta(block_->findInst("b1")));
140+
sta_->updateTiming(true);
141+
142+
// 3. Recycle freed slots via a single fresh BUF driven by a new clock.
143+
odb::dbNet* in3_net = odb::dbNet::create(block_, "in3");
144+
odb::dbBTerm* new_bt = odb::dbBTerm::create(in3_net, "in3");
145+
new_bt->setIoType(odb::dbIoType::INPUT);
146+
odb::dbNet* nfan_net = odb::dbNet::create(block_, "nfan");
147+
odb::dbInst* bnew
148+
= odb::dbInst::create(block_, db_->findMaster("BUF_X1"), "bnew");
149+
bnew->findITerm("A")->connect(in3_net);
150+
bnew->findITerm("Z")->connect(nfan_net);
151+
152+
PinSet clk2_pins(db_network_);
153+
clk2_pins.insert(db_network_->dbToSta(new_bt));
154+
FloatSeq clk2_waveform = {0.0f, 0.1f};
155+
sta_->makeClock(
156+
"clk2", clk2_pins, false, 0.2f, clk2_waveform, "", sta_->cmdMode());
157+
sta_->updateTiming(true);
158+
159+
// 4. Staleness evidence. Pointer address is same but pin name has changed.
160+
const Path* post_addr = drvr_path->prevPath();
161+
const std::string post_pin_name
162+
= post_addr ? network->pathName(post_addr->pin(sta_.get()))
163+
: std::string("<null>");
164+
165+
EXPECT_EQ(pre_addr, post_addr)
166+
<< "stale-pointer signature: prev_path_ address unchanged";
167+
EXPECT_NE(pre_pin_name, post_pin_name)
168+
<< "but slot content should differ after free+reuse. before="
169+
<< pre_pin_name << " after=" << post_pin_name;
170+
}
171+
100172
} // namespace sta
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
module top (clk,
2+
in2,
3+
out1);
4+
input clk;
5+
input in2;
6+
output out1;
7+
8+
wire n0;
9+
wire n1;
10+
11+
BUF_X1 b1 (.A(clk),
12+
.Z(n0));
13+
INV_X1 inv1 (.A(n0),
14+
.ZN(n1));
15+
NAND2_X1 nd1 (.A1(n1),
16+
.A2(in2),
17+
.ZN(out1));
18+
endmodule

src/rsz/src/RecoverPower.cc

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -327,10 +327,11 @@ bool RecoverPower::downsizeDrvr(const sta::Path* drvr_path,
327327
sta::Instance* drvr = network_->instance(drvr_pin);
328328
const float load_cap = graph_delay_calc_->loadCap(
329329
drvr_pin, drvr_path->scene(sta_), drvr_path->minMax(sta_));
330-
const int in_index = drvr_index - 1;
331-
const sta::Path* in_path = expanded->path(in_index);
332-
const sta::Pin* in_pin = in_path->pin(sta_);
333-
const sta::LibertyPort* in_port = network_->libertyPort(in_pin);
330+
const sta::TimingArc* in_arc = drvr_path->prevArc(sta_);
331+
const sta::LibertyPort* in_port = in_arc ? in_arc->from() : nullptr;
332+
if (in_port == nullptr) {
333+
return false;
334+
}
334335
if (!resizer_->dontTouch(drvr)) {
335336
float prev_drive = 0.0;
336337
if (drvr_index >= 2) {

src/rsz/src/SizeUpMove.cc

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include "sta/Liberty.hh"
1414
#include "sta/NetworkClass.hh"
1515
#include "sta/Path.hh"
16+
#include "sta/TimingArc.hh"
1617
#include "utl/Logger.h"
1718

1819
namespace rsz {
@@ -48,26 +49,27 @@ bool SizeUpMove::doMove(const sta::Path* drvr_path, float setup_slack_margin)
4849
return false;
4950
}
5051

51-
sta::Pin* drvr_input_pin = drvr_path->prevPath()->pin(sta_);
52+
const sta::TimingArc* in_arc = drvr_path->prevArc(sta_);
53+
sta::LibertyPort* in_port = in_arc ? in_arc->from() : nullptr;
54+
if (in_port == nullptr) {
55+
return false;
56+
}
57+
5258
sta::Path* prev_drvr_path = drvr_path->prevPath()->prevPath();
5359
sta::Pin* prev_drvr_pin
5460
= prev_drvr_path ? prev_drvr_path->pin(sta_) : nullptr;
5561

56-
float prev_drive;
62+
float prev_drive = 0.0;
5763
if (prev_drvr_pin) {
58-
prev_drive = 0.0;
5964
sta::LibertyPort* prev_drvr_port = network_->libertyPort(prev_drvr_pin);
6065
if (prev_drvr_port) {
6166
prev_drive = prev_drvr_port->driveResistance();
6267
}
63-
} else {
64-
prev_drive = 0.0;
6568
}
6669

6770
sta::Scene* scene = drvr_path->scene(sta_);
6871
const sta::MinMax* min_max = drvr_path->minMax(sta_);
6972
const float load_cap = graph_delay_calc_->loadCap(drvr_pin, scene, min_max);
70-
sta::LibertyPort* in_port = network_->libertyPort(drvr_input_pin);
7173
sta::LibertyPort* drvr_port = network_->libertyPort(drvr_pin);
7274
sta::LibertyCell* upsize
7375
= upsizeCell(in_port, drvr_port, load_cap, prev_drive, scene, min_max);

src/rsz/src/SwapPinsMove.cc

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -95,10 +95,12 @@ bool SwapPinsMove::doMove(const sta::Path* drvr_path, float setup_slack_margin)
9595
sta::Scene* scene = drvr_path->scene(sta_);
9696
const sta::MinMax* min_max = drvr_path->minMax(sta_);
9797
const float load_cap = graph_delay_calc_->loadCap(drvr_pin, scene, min_max);
98-
sta::Pin* drvr_input_pin = drvr_path->prevPath()->pin(sta_);
9998

100-
// We get the driver port and the cell for that port.
101-
sta::LibertyPort* input_port = network_->libertyPort(drvr_input_pin);
99+
const sta::TimingArc* in_arc = drvr_path->prevArc(sta_);
100+
sta::LibertyPort* input_port = in_arc ? in_arc->from() : nullptr;
101+
if (input_port == nullptr) {
102+
return false;
103+
}
102104
sta::LibertyPort* swap_port = input_port;
103105
LibertyPortVec ports;
104106

src/rsz/src/UnbufferMove.cc

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
#include "sta/Mode.hh"
2525
#include "sta/NetworkClass.hh"
2626
#include "sta/Path.hh"
27+
#include "sta/TimingArc.hh"
2728
#include "sta/Transition.hh"
2829
#include "utl/Logger.h"
2930

@@ -99,7 +100,12 @@ bool UnbufferMove::doMove(const sta::Path* drvr_path, float setup_slack_margin)
99100

100101
// Don't remove buffer if new max fanout violations are created
101102
sta::Vertex* drvr_vertex = graph_->pinDrvrVertex(drvr_pin);
102-
sta::Pin* drvr_input_pin = drvr_path->prevPath()->pin(sta_);
103+
const sta::TimingArc* in_arc = drvr_path->prevArc(sta_);
104+
const sta::LibertyPort* in_lib_port = in_arc ? in_arc->from() : nullptr;
105+
if (in_lib_port == nullptr) {
106+
return false;
107+
}
108+
sta::Pin* drvr_input_pin = network_->findPin(drvr, in_lib_port);
103109
sta::Path* prev_drvr_path = drvr_path->prevPath()->prevPath();
104110
sta::Pin* prev_drvr_pin
105111
= prev_drvr_path ? prev_drvr_path->pin(sta_) : nullptr;

0 commit comments

Comments
 (0)