Skip to content

Commit 31b6d2d

Browse files
committed
[SharedCache] Fix the triage symbol table data races
Any update to the model should only happen on the UI thread now. This also fixes the other issue here: #6300
1 parent 470f350 commit 31b6d2d

File tree

2 files changed

+42
-33
lines changed

2 files changed

+42
-33
lines changed

view/sharedcache/ui/symboltable.cpp

Lines changed: 38 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ SymbolTableModel::SymbolTableModel(SymbolTableView* parent)
1414

1515
int SymbolTableModel::rowCount(const QModelIndex& parent) const {
1616
Q_UNUSED(parent);
17-
return static_cast<int>(m_symbols.size());
17+
return static_cast<int>(m_modelSymbols.size());
1818
}
1919

2020
int SymbolTableModel::columnCount(const QModelIndex& parent) const {
@@ -28,7 +28,7 @@ QVariant SymbolTableModel::data(const QModelIndex& index, int role) const {
2828
return QVariant();
2929
}
3030

31-
const CacheSymbol& symbol = m_symbols.at(index.row());
31+
auto symbol = symbolAt(index.row());
3232
auto symbolType = GetSymbolTypeAsString(symbol.type);
3333

3434
switch (index.column()) {
@@ -60,13 +60,15 @@ QVariant SymbolTableModel::headerData(int section, Qt::Orientation orientation,
6060
}
6161
}
6262

63-
void SymbolTableModel::updateSymbols() {
64-
m_symbols = m_parent->m_symbols;
63+
void SymbolTableModel::updateSymbols(std::vector<CacheSymbol>&& symbols)
64+
{
65+
m_preparedSymbols = symbols;
6566
setFilter(m_filter);
6667
}
6768

68-
const CacheSymbol& SymbolTableModel::symbolAt(int row) const {
69-
return m_symbols.at(row);
69+
const CacheSymbol& SymbolTableModel::symbolAt(int row) const
70+
{
71+
return m_modelSymbols.at(row);
7072
}
7173

7274

@@ -75,23 +77,19 @@ void SymbolTableModel::setFilter(std::string text)
7577
beginResetModel();
7678

7779
m_filter = text;
78-
m_symbols.clear();
80+
m_modelSymbols = {};
7981

80-
if (m_filter.empty())
82+
// Skip filtering if no filter applied.
83+
if (!m_filter.empty())
8184
{
82-
m_symbols = m_parent->m_symbols;
83-
}
84-
else
85-
{
86-
m_symbols.reserve(m_parent->m_symbols.size());
87-
for (const auto& symbol : m_parent->m_symbols)
88-
{
85+
m_modelSymbols.reserve(m_preparedSymbols.size());
86+
for (const auto& symbol : m_preparedSymbols)
8987
if (((std::string_view)symbol.name).find(m_filter) != std::string::npos)
90-
{
91-
m_symbols.push_back(symbol);
92-
}
93-
}
94-
m_symbols.shrink_to_fit();
88+
m_modelSymbols.push_back(symbol);
89+
m_modelSymbols.shrink_to_fit();
90+
} else
91+
{
92+
m_modelSymbols = m_preparedSymbols;
9593
}
9694

9795
endResetModel();
@@ -121,14 +119,26 @@ SymbolTableView::~SymbolTableView() {
121119
void SymbolTableView::populateSymbols(BinaryView &view)
122120
{
123121
if (auto controller = SharedCacheController::GetController(view)) {
124-
BackgroundThread::create(this)
125-
->thenBackground([this, controller]() {
126-
// TODO: There is a crash related to `this` being destructed. https://github.com/Vector35/binaryninja-api/issues/6300
127-
std::vector<CacheSymbol> newSymbols = controller->GetSymbols();
128-
m_symbols.swap(newSymbols);
129-
})
130-
->thenMainThread([this](){ m_model->updateSymbols(); })
131-
->start();
122+
typedef std::vector<CacheSymbol> SymbolList;
123+
// Retrieve the symbols from the controller in a future than pass that to the model.
124+
QPointer<QFutureWatcher<SymbolList>> watcher = new QFutureWatcher<SymbolList>(this);
125+
connect(watcher, &QFutureWatcher<SymbolList>::finished, this, [watcher, this]() {
126+
if (watcher)
127+
{
128+
auto symbols = watcher->result();
129+
m_model->updateSymbols(std::move(symbols));
130+
}
131+
});
132+
QFuture<SymbolList> future = QtConcurrent::run([controller]() {
133+
return controller->GetSymbols();
134+
});
135+
watcher->setFuture(future);
136+
connect(this, &QObject::destroyed, this, [watcher]() {
137+
if (watcher && watcher->isRunning()) {
138+
watcher->cancel();
139+
watcher->waitForFinished();
140+
}
141+
});
132142
}
133143
}
134144

view/sharedcache/ui/symboltable.h

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ class SymbolTableModel : public QAbstractTableModel {
1515

1616
SymbolTableView* m_parent;
1717
std::string m_filter;
18-
std::vector<SharedCacheAPI::CacheSymbol> m_symbols;
18+
std::vector<SharedCacheAPI::CacheSymbol> m_preparedSymbols {};
19+
// the symbols we actually use.
20+
std::vector<SharedCacheAPI::CacheSymbol> m_modelSymbols {};
1921

2022
public:
2123
explicit SymbolTableModel(SymbolTableView* parent);
@@ -25,7 +27,7 @@ class SymbolTableModel : public QAbstractTableModel {
2527
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
2628
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
2729

28-
void updateSymbols();
30+
void updateSymbols(std::vector<SharedCacheAPI::CacheSymbol>&& symbols);
2931

3032
void setFilter(std::string text);
3133

@@ -38,9 +40,6 @@ class SymbolTableView : public QTableView, public FilterTarget
3840
Q_OBJECT
3941
friend class SymbolTableModel;
4042

41-
// TODO: Both the model and the view store the symbols?
42-
std::vector<SharedCacheAPI::CacheSymbol> m_symbols;
43-
4443
SymbolTableModel* m_model;
4544

4645
public:

0 commit comments

Comments
 (0)