Skip to content

Refactor QZydis instance in Bridge class #3641

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

mrexodia
Copy link
Member

Make QZydis a member of the Bridge class to optimize GuiGetDisassembly performance and ensure configuration synchronization.

Co-authored-by: mr.exodia.tpodt <mr.exodia.tpodt@gmail.com>
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Race Condition in Shared Disassembly Instance

A race condition was introduced by changing GUI_GET_DISASSEMBLY to use a shared mDisasm QZydis instance instead of a local one. This allows mDisasm->DisassembleAt() to be called concurrently with mDisasm->UpdateConfig() and mDisasm->UpdateArchitecture() (from configUpdatedSlot). Without synchronization, this can lead to undefined behavior or inconsistent disassembly results.

src/gui/Src/Bridge/Bridge.cpp#L284-L543

void Bridge::configUpdatedSlot()
{
if(mDisasm)
{
mDisasm->UpdateConfig();
mDisasm->UpdateArchitecture();
}
}
/************************************************************************************
Message processing
************************************************************************************/
void* Bridge::processMessage(GUIMSG type, void* param1, void* param2)
{
if(mDbgStopped) //there can be no more messages if the debugger stopped = IGNORE
return nullptr;
switch(type)
{
case GUI_DISASSEMBLE_AT:
mLastCip = (duint)param2;
emit disassembleAt((duint)param1, (duint)param2);
break;
case GUI_SET_DEBUG_STATE:
mIsRunning = DBGSTATE(duint(param1)) == running;
if(!param2)
emit dbgStateChanged((DBGSTATE)(dsint)param1);
break;
case GUI_ADD_MSG_TO_LOG:
{
auto msg = (const char*)param1;
emit addMsgToLog(QByteArray(msg, int(strlen(msg)) + 1)); //Speed up performance: don't convert to UCS-2 QString
}
break;
case GUI_ADD_MSG_TO_LOG_HTML:
{
auto msg = (const char*)param1;
emit addMsgToLogHtml(QByteArray(msg, int(strlen(msg)) + 1)); //Speed up performance: don't convert to UCS-2 QString
}
break;
case GUI_CLEAR_LOG:
emit clearLog();
break;
case GUI_SAVE_LOG:
if(!param1)
emit saveLog();
else
emit saveLogToFile(QString((const char*)param1));
break;
case GUI_REDIRECT_LOG:
emit redirectLogToFile(QString((const char*)param1));
break;
case GUI_STOP_REDIRECT_LOG:
emit redirectLogStop();
break;
case GUI_UPDATE_WINDOW_TITLE:
emit updateWindowTitle(QString((const char*)param1));
break;
case GUI_GET_WINDOW_HANDLE:
return mWinId;
case GUI_DUMP_AT:
emit dumpAt((dsint)param1);
break;
case GUI_SCRIPT_ADD:
{
BridgeResult result(BridgeResult::ScriptAdd);
emit scriptAdd((int)(duint)param1, (const char**)param2);
result.Wait();
}
break;
case GUI_SCRIPT_CLEAR:
emit scriptClear();
break;
case GUI_SCRIPT_SETIP:
emit scriptSetIp((int)(duint)param1);
break;
case GUI_SCRIPT_ERROR:
{
BridgeResult result(BridgeResult::ScriptMessage);
emit scriptError((int)(duint)param1, QString((const char*)param2));
result.Wait();
}
break;
case GUI_SCRIPT_SETTITLE:
emit scriptSetTitle(QString((const char*)param1));
break;
case GUI_SCRIPT_SETINFOLINE:
emit scriptSetInfoLine((int)(duint)param1, QString((const char*)param2));
break;
case GUI_SCRIPT_MESSAGE:
{
BridgeResult result(BridgeResult::ScriptMessage);
emit scriptMessage(QString((const char*)param1));
result.Wait();
}
break;
case GUI_SCRIPT_MSGYN:
{
BridgeResult result(BridgeResult::ScriptMessage);
emit scriptQuestion(QString((const char*)param1));
return (void*)result.Wait();
}
break;
case GUI_SCRIPT_ENABLEHIGHLIGHTING:
emit scriptEnableHighlighting((bool)param1);
break;
case GUI_SYMBOL_UPDATE_MODULE_LIST:
emit updateSymbolList((int)(duint)param1, (SYMBOLMODULEINFO*)param2);
break;
case GUI_SYMBOL_LOG_ADD:
emit addMsgToSymbolLog(QString((const char*)param1));
break;
case GUI_SYMBOL_LOG_CLEAR:
emit clearSymbolLog();
break;
case GUI_SYMBOL_SET_PROGRESS:
emit setSymbolProgress((int)(duint)param1);
break;
case GUI_REF_ADDCOLUMN:
if(mReferenceManager->currentReferenceView())
mReferenceManager->currentReferenceView()->addColumnAtRef((int)(duint)param1, QString((const char*)param2));
break;
case GUI_REF_SETROWCOUNT:
{
if(mReferenceManager->currentReferenceView())
mReferenceManager->currentReferenceView()->setRowCount((dsint)param1);
}
break;
case GUI_REF_GETROWCOUNT:
if(mReferenceManager->currentReferenceView())
return (void*)mReferenceManager->currentReferenceView()->stdList()->getRowCount();
return 0;
case GUI_REF_SEARCH_GETROWCOUNT:
if(mReferenceManager->currentReferenceView())
return (void*)mReferenceManager->currentReferenceView()->mCurList->getRowCount();
return 0;
case GUI_REF_DELETEALLCOLUMNS:
GuiReferenceInitialize(tr("References").toUtf8().constData());
break;
case GUI_REF_SETCELLCONTENT:
{
CELLINFO* info = (CELLINFO*)param1;
if(mReferenceManager->currentReferenceView())
mReferenceManager->currentReferenceView()->setCellContent(info->row, info->col, QString(info->str));
}
break;
case GUI_REF_GETCELLCONTENT:
{
QString content;
if(mReferenceManager->currentReferenceView())
content = mReferenceManager->currentReferenceView()->stdList()->getCellContent((int)(duint)param1, (int)(duint)param2);
auto bytes = content.toUtf8();
auto data = BridgeAlloc(bytes.size() + 1);
memcpy(data, bytes.constData(), bytes.size());
return data;
}
case GUI_REF_SEARCH_GETCELLCONTENT:
{
QString content;
if(mReferenceManager->currentReferenceView())
content = mReferenceManager->currentReferenceView()->mCurList->getCellContent((int)(duint)param1, (int)(duint)param2);
auto bytes = content.toUtf8();
auto data = BridgeAlloc(bytes.size() + 1);
memcpy(data, bytes.constData(), bytes.size());
return data;
}
case GUI_REF_RELOADDATA:
emit referenceReloadData();
break;
case GUI_REF_SETSINGLESELECTION:
emit referenceSetSingleSelection((int)(duint)param1, (bool)param2);
break;
case GUI_REF_SETPROGRESS:
if(mReferenceManager->currentReferenceView())
{
auto newProgress = (int)(duint)param1;
if(mReferenceManager->currentReferenceView()->progress() != newProgress)
emit referenceSetProgress(newProgress);
}
break;
case GUI_REF_SETCURRENTTASKPROGRESS:
if(mReferenceManager->currentReferenceView())
{
auto newProgress = (int)(duint)param1;
if(mReferenceManager->currentReferenceView()->currentTaskProgress() != newProgress)
emit referenceSetCurrentTaskProgress((int)(duint)param1, QString((const char*)param2));
}
break;
case GUI_REF_SETSEARCHSTARTCOL:
if(mReferenceManager->currentReferenceView())
mReferenceManager->currentReferenceView()->setSearchStartCol((duint)param1);
break;
case GUI_REF_INITIALIZE:
{
BridgeResult result(BridgeResult::RefInitialize);
emit referenceInitialize(QString((const char*)param1));
result.Wait();
}
break;
case GUI_STACK_DUMP_AT:
emit stackDumpAt((duint)param1, (duint)param2);
break;
case GUI_ADD_RECENT_FILE:
emit addRecentFile(QString((const char*)param1));
break;
case GUI_SET_LAST_EXCEPTION:
emit setLastException((unsigned int)(duint)param1);
break;
case GUI_GET_DISASSEMBLY:
{
duint parVA = (duint)param1;
char* text = (char*)param2;
if(!text || !parVA || !DbgIsDebugging() || !mDisasm)
return 0;
byte_t buffer[16];
if(!DbgMemRead(parVA, buffer, 16))
return 0;
Instruction_t instr = mDisasm->DisassembleAt(buffer, 16, 0, parVA);

Fix in CursorFix in Web


BugBot free trial expires on July 22, 2025
You have used $0.00 of your $10.00 spend limit so far. Manage your spend limit in the Cursor dashboard.

Was this report helpful? Give feedback by reacting with 👍 or 👎

@mrexodia mrexodia merged commit 7ebb9c7 into development Jul 21, 2025
6 checks passed
@mrexodia mrexodia deleted the cursor/refactor-qzydis-instance-in-bridge-class-806d branch July 21, 2025 11:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants