@@ -505,6 +505,9 @@ int32_t asyncExecDdlQuery(SRequestObj* pRequest, SQuery* pQuery) {
505505 }
506506
507507 SCmdMsgInfo * pMsgInfo = pQuery -> pCmdMsg ;
508+ // Clear pQuery->pCmdMsg before the async call so that nodesDestroyNode (which may be
509+ // triggered by the async response callback on another thread) will not double-free pCmdMsg.
510+ pQuery -> pCmdMsg = NULL ;
508511 pRequest -> type = pMsgInfo -> msgType ;
509512 pRequest -> body .requestMsg = (SDataBuf ){.pData = pMsgInfo -> pMsg , .len = pMsgInfo -> msgLen , .handle = NULL };
510513 pMsgInfo -> pMsg = NULL ; // pMsg transferred to SMsgSendInfo management
@@ -515,9 +518,9 @@ int32_t asyncExecDdlQuery(SRequestObj* pRequest, SQuery* pQuery) {
515518 int32_t code = asyncSendMsgToServer (pAppInfo -> pTransporter , & pMsgInfo -> epSet , NULL , pSendMsg );
516519 // pMsgInfo->pMsg has been transferred to pRequest->body.requestMsg and pMsgInfo->epSet has
517520 // been consumed by asyncSendMsgToServer; the SCmdMsgInfo struct itself is no longer needed.
518- // Free it now so that nodesDestroyAllocatorSet() during atexit does not orphan it when the
519- // chunk containing pQuery is released before doDestroyRequest() can be called .
520- taosMemoryFreeClear ( pQuery -> pCmdMsg );
521+ // Use the local pMsgInfo variable (not pQuery->pCmdMsg) to avoid a use-after-free: the async
522+ // response callback may have run on another thread and destroyed pQuery by this point .
523+ taosMemoryFree ( pMsgInfo );
521524 if (code ) {
522525 doRequestCallback (pRequest , code );
523526 }
0 commit comments