Skip to content

Commit 46c1c4c

Browse files
committed
dbSta: move stale-Path regression from rsz and switch to verilog+IntegratedFixture
Signed-off-by: Minju Kim <mkim@precisioninno.com>
1 parent 94e9212 commit 46c1c4c

6 files changed

Lines changed: 107 additions & 258 deletions

File tree

src/dbSta/test/BUILD

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,6 +292,7 @@ cc_test(
292292
"Nangate45/Nangate45.lef",
293293
"Nangate45/Nangate45_typ.lib",
294294
"cpp/TestDbSta_0.v",
295+
"cpp/TestDbSta_StalePath.v",
295296
],
296297
deps = [
297298
"//src/dbSta",

src/dbSta/test/cpp/TestDbSta.cc

Lines changed: 88 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,87 @@ 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_StalePath.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.
113+
// 2. Delete upstream b1 + updateTiming -> free b1/inv1 Path[] slots.
114+
// 3. Add a fresh BUF + clock + updateTiming -> recycle freed slots.
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. When the drvr slot itself is preserved, also assert
118+
// the strict stale-pointer signature (same raw address, different
119+
// content).
120+
TEST_F(TestDbSta, StalePrevPathAfterUpdateTiming)
121+
{
122+
readVerilogAndSetup("TestDbSta_StalePath.v");
123+
sta_->updateTiming(true);
124+
125+
Network* network = sta_->network();
126+
127+
Instance* nd1 = db_network_->dbToSta(block_->findInst("nd1"));
128+
Path* drvr_path = sta_->vertexWorstArrivalPath(
129+
sta_->ensureGraph()->pinDrvrVertex(network->findPin(nd1, "ZN")),
130+
MinMax::max());
131+
ASSERT_NE(drvr_path, nullptr);
132+
ASSERT_EQ(network->pathName(drvr_path->pin(sta_.get())), "nd1/ZN");
133+
const Path* prev_before = drvr_path->prevPath();
134+
ASSERT_NE(prev_before, nullptr);
135+
const std::string prev_pin_before
136+
= network->pathName(prev_before->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. Allocator behaviour decides which slot lands
160+
// on the recycled memory:
161+
// (a) drvr slot preserved + prev slot recycled (glibc in our CI) --
162+
// strict stale-pointer signature: same raw prev address, but
163+
// pin() decodes to content from an unrelated instance.
164+
// (b) drvr slot itself recycled (other allocators) -- drvr pin decodes
165+
// to something other than nd1/ZN.
166+
// Either case proves the captured raw Path* outlived the slot.
167+
const std::string drvr_pin_after
168+
= network->pathName(drvr_path->pin(sta_.get()));
169+
const Path* prev_after = drvr_path->prevPath();
170+
const std::string prev_pin_after
171+
= prev_after ? network->pathName(prev_after->pin(sta_.get()))
172+
: std::string("<null>");
173+
const bool drvr_recycled = drvr_pin_after != "nd1/ZN";
174+
const bool prev_recycled = prev_after != nullptr && prev_pin_after != "nd1/A1"
175+
&& prev_pin_after != "nd1/A2";
176+
EXPECT_TRUE(drvr_recycled || prev_recycled)
177+
<< "expected slot reuse to be demonstrable; drvr=" << drvr_pin_after
178+
<< " prev=" << prev_pin_after;
179+
if (!drvr_recycled && prev_after != nullptr) {
180+
EXPECT_EQ(prev_after, prev_before)
181+
<< "stale-pointer signature: prev_path_ address unchanged";
182+
EXPECT_NE(prev_pin_after, prev_pin_before)
183+
<< "but slot content should differ after free+reuse. before="
184+
<< prev_pin_before << " after=" << prev_pin_after;
185+
}
186+
}
187+
100188
} // 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/test/BUILD

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -262,34 +262,6 @@ BIG_TESTS = [
262262
for test_name in ALL_TESTS
263263
]
264264

265-
cc_test(
266-
name = "TestBufInvNand2",
267-
srcs = [
268-
"cpp/TestBufInvNand2.cc",
269-
],
270-
data = [
271-
"Nangate45/Nangate45.lef",
272-
"Nangate45/Nangate45_typ.lib",
273-
],
274-
deps = [
275-
"//src/ant",
276-
"//src/dbSta",
277-
"//src/dbSta:dbNetwork",
278-
"//src/dpl",
279-
"//src/est",
280-
"//src/grt",
281-
"//src/odb",
282-
"//src/rsz",
283-
"//src/sta:opensta_lib",
284-
"//src/stt",
285-
"//src/tst",
286-
"//src/tst:nangate45_fixture",
287-
"//src/utl",
288-
"@googletest//:gtest",
289-
"@googletest//:gtest_main",
290-
],
291-
)
292-
293265
cc_test(
294266
name = "rsz_buffer_removal",
295267
srcs = [

src/rsz/test/cpp/CMakeLists.txt

Lines changed: 0 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -28,30 +28,6 @@ gtest_discover_tests(TestBufRem1
2828
add_dependencies(build_and_test TestBufRem1
2929
)
3030

31-
add_executable(TestBufInvNand2 TestBufInvNand2.cc)
32-
target_link_libraries(TestBufInvNand2
33-
OpenSTA
34-
GTest::gtest
35-
GTest::gtest_main
36-
GTest::gmock
37-
dbSta_lib
38-
utl_lib
39-
rsz_lib
40-
grt_lib
41-
dpl_lib
42-
stt_lib
43-
odb
44-
tst
45-
${TCL_LIBRARY}
46-
)
47-
48-
gtest_discover_tests(TestBufInvNand2
49-
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/..
50-
)
51-
52-
add_dependencies(build_and_test TestBufInvNand2
53-
)
54-
5531
add_executable(TestBufferRemoval2 TestBufferRemoval2.cc)
5632
target_link_libraries(TestBufferRemoval2
5733
OpenSTA

0 commit comments

Comments
 (0)