Skip to content

Commit 035a74d

Browse files
committed
rsz: Delay buffer removal to prevent use-after-free
Signed-off-by: Krzysztof Bieganski <kbieganski@antmicro.com>
1 parent fa1888e commit 035a74d

File tree

4 files changed

+122
-3
lines changed

4 files changed

+122
-3
lines changed

src/rsz/include/rsz/Resizer.hh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,8 @@ class Resizer : public dbStaState
622622
bool removeBuffer(Instance* buffer,
623623
bool honorDontTouchFixed = true,
624624
bool recordJournal = false);
625+
bool canRemoveBuffer(Instance* buffer, bool honorDontTouchFixed = true);
626+
void removeBuffer2(Instance* buffer, bool recordJournal = false);
625627
Instance* makeInstance(LibertyCell* cell,
626628
const char* name,
627629
Instance* parent,

src/rsz/src/RepairSetup.cc

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -561,6 +561,9 @@ bool RepairSetup::repairPath(PathRef& path,
561561
drvr_index,
562562
&expanded,
563563
setup_slack_margin)) {
564+
Pin* drvr_pin = drvr_path->pin(this);
565+
Instance* drvr = network_->instance(drvr_pin);
566+
buf_to_remove_.push_back(drvr);
564567
changed = true;
565568
break;
566569
}
@@ -625,6 +628,10 @@ bool RepairSetup::repairPath(PathRef& path,
625628
}
626629
}
627630
}
631+
for (auto inst : buf_to_remove_) {
632+
resizer_->removeBuffer2(inst, /* recordJournal */ true);
633+
}
634+
buf_to_remove_.clear();
628635
}
629636
return changed;
630637
}
@@ -858,8 +865,7 @@ bool RepairSetup::removeDrvr(const PathRef* drvr_path,
858865
return false;
859866
}
860867

861-
if (resizer_->removeBuffer(
862-
drvr, /* honorDontTouch */ true, /* recordJournal */ true)) {
868+
if (resizer_->canRemoveBuffer(drvr, /* honorDontTouch */ true)) {
863869
removed_buffer_count_++;
864870
return true;
865871
}
@@ -977,7 +983,7 @@ bool RepairSetup::estimatedSlackOK(const SlackEstimatorParams& params)
977983
"because side input pin {} will have a violating slack of {}:"
978984
" old slack={}, slack margin={}, delay_degrad={}",
979985
db_network_->name(params.driver),
980-
db_network_->name(side_input_pin), new_slack, old_slack,
986+
db_network_->name(side_input_pin), new_slack, old_slack,
981987
params.setup_slack_margin, delay_degrad);
982988
// clang-format on
983989
return false;

src/rsz/src/RepairSetup.hh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ class RepairSetup : public sta::dbStaState
235235
int num_endpts);
236236
void repairSetupLastGasp(const OptoParams& params, int& num_viols);
237237

238+
std::vector<Instance*> buf_to_remove_;
238239
Logger* logger_ = nullptr;
239240
dbNetwork* db_network_ = nullptr;
240241
Resizer* resizer_;

src/rsz/src/Resizer.cc

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,116 @@ bool Resizer::removeBuffer(Instance* buffer,
399399
return buffer_removed;
400400
}
401401

402+
bool Resizer::canRemoveBuffer(Instance* buffer, bool honorDontTouchFixed)
403+
{
404+
LibertyCell* lib_cell = network_->libertyCell(buffer);
405+
if (!lib_cell || !lib_cell->isBuffer()) {
406+
return false;
407+
}
408+
// Do not remove buffers connected to input/output ports
409+
// because verilog netlists use the net name for the port.
410+
if (bufferBetweenPorts(buffer)) {
411+
return false;
412+
}
413+
dbInst* db_inst = db_network_->staToDb(buffer);
414+
if (honorDontTouchFixed) {
415+
if (db_inst->isDoNotTouch() || db_inst->isFixed()) {
416+
return false;
417+
}
418+
}
419+
LibertyPort *in_port, *out_port;
420+
lib_cell->bufferPorts(in_port, out_port);
421+
Pin* in_pin = db_network_->findPin(buffer, in_port);
422+
Pin* out_pin = db_network_->findPin(buffer, out_port);
423+
Net* in_net = db_network_->net(in_pin);
424+
Net* out_net = db_network_->net(out_pin);
425+
dbNet* in_db_net = db_network_->staToDb(in_net);
426+
dbNet* out_db_net = db_network_->staToDb(out_net);
427+
// honor net dont-touch on input net or output net
428+
if (honorDontTouchFixed) {
429+
if (in_db_net->isDoNotTouch() || out_db_net->isDoNotTouch()) {
430+
return false;
431+
}
432+
}
433+
bool out_net_ports = hasPort(out_net);
434+
Net *removed;
435+
if (out_net_ports) {
436+
if (hasPort(in_net)) {
437+
return false;
438+
}
439+
removed = in_net;
440+
} else {
441+
// default or out_net_ports
442+
// Default to in_net surviving so drivers (cached in dbNetwork)
443+
// do not change.
444+
removed = out_net;
445+
}
446+
return (!sdc_->isConstrained(in_pin) && !sdc_->isConstrained(out_pin)
447+
&& !sdc_->isConstrained(removed) && !sdc_->isConstrained(buffer));
448+
}
449+
450+
void Resizer::removeBuffer2(Instance* buffer, bool recordJournal)
451+
{
452+
LibertyCell* lib_cell = network_->libertyCell(buffer);
453+
// Do not remove buffers connected to input/output ports
454+
// because verilog netlists use the net name for the port.
455+
dbInst* db_inst = db_network_->staToDb(buffer);
456+
if (db_inst->isDoNotTouch()) {
457+
// remove instance dont touch
458+
db_inst->setDoNotTouch(false);
459+
}
460+
if (db_inst->isFixed()) {
461+
// change FIXED to PLACED just in case
462+
db_inst->setPlacementStatus(odb::dbPlacementStatus::PLACED);
463+
}
464+
LibertyPort *in_port, *out_port;
465+
lib_cell->bufferPorts(in_port, out_port);
466+
Pin* in_pin = db_network_->findPin(buffer, in_port);
467+
Pin* out_pin = db_network_->findPin(buffer, out_port);
468+
Net* in_net = db_network_->net(in_pin);
469+
Net* out_net = db_network_->net(out_pin);
470+
dbNet* in_db_net = db_network_->staToDb(in_net);
471+
dbNet* out_db_net = db_network_->staToDb(out_net);
472+
if (in_db_net->isDoNotTouch() || out_db_net->isDoNotTouch()) {
473+
// remove net dont touch for manual ECO
474+
in_db_net->setDoNotTouch(false);
475+
out_db_net->setDoNotTouch(false);
476+
}
477+
bool out_net_ports = hasPort(out_net);
478+
Net *survivor, *removed;
479+
if (out_net_ports) {
480+
survivor = out_net;
481+
removed = in_net;
482+
} else {
483+
// default or out_net_ports
484+
// Default to in_net surviving so drivers (cached in dbNetwork)
485+
// do not change.
486+
survivor = in_net;
487+
removed = out_net;
488+
}
489+
490+
if (recordJournal) {
491+
journalRemoveBuffer(buffer);
492+
}
493+
debugPrint(
494+
logger_, RSZ, "remove_buffer", 1, "remove {}", db_network_->name(buffer));
495+
496+
if (removed) {
497+
odb::dbNet* db_survivor = db_network_->staToDb(survivor);
498+
odb::dbNet* db_removed = db_network_->staToDb(removed);
499+
db_survivor->mergeNet(db_removed);
500+
501+
sta_->disconnectPin(in_pin);
502+
sta_->disconnectPin(out_pin);
503+
sta_->deleteInstance(buffer);
504+
505+
sta_->deleteNet(removed);
506+
parasitics_invalid_.erase(removed);
507+
}
508+
parasiticsInvalid(survivor);
509+
updateParasitics();
510+
}
511+
402512
void Resizer::ensureLevelDrvrVertices()
403513
{
404514
if (!level_drvr_vertices_valid_) {

0 commit comments

Comments
 (0)