簡體   English   中英

從調用 MEX 的 function 返回后 Matlab 崩潰

[英]Matlab crash after returning from function that calls MEX

我正在創建一個 MEX 以使用 A* 算法查找兩個節點之間的路徑。 代碼按預期工作,檢索到正確的結果,一切似乎都很好,但是當我從調用 MEX 的方法返回時,Matlab 只是自行關閉。

As I know sometimes Matlab creates a pointer to the same memory address when the user tries to create a copy of a variable (IE A = 3; B = A, then A and B are pointing to the same memory address, even though Matlab shows它們作為 2 個自變量)我使用了一個舊技巧,即直接對變量的副本執行操作,即使它是一個愚蠢的操作,Matlab 會認為這兩個變量不再相同,並將創建它(即 A = 3;B = A;B = B+0,現在 A 和 B 存儲為不同的獨立變量)。

因此,我發現解決此問題的唯一方法是執行 function getWP 中所示的操作:

function testAStarC()
    % load the map of the area
    load('epsp0_2_nav.mat');

    % Set the initial node
    initNode = '16x21';
    % Set the target node
    finalNode = '-15x54';

    % Select Heuristic
    heuristic = 'Manhattan';

    % Create a target location (targetX, targetY, targetAngle)
    targetCoords = [-15*110  54*110 0.15];

    % Function that hosts the call to the MEX
    wp = getWP(map, initNode, finalNode, targetCoords, heuristic);

    disp('If you remove the line cellNodes{keyID}.x = cellNodes{keyID}.x; from getWP ...
        I wont reach this line');
    disp(['Route with ',num2str(length(wp)),' wp found']);
    disp('done');


function waypointsList = getWP(map, initNode, finalNode, targetCoords, heuristic)
    % HashMap containing the nodes (this is a Java hashmap)
    nodesHash = map.navMap.nodes.nodes;
    keys = nodesHash.keys();
    numNodes = length(keys);

    cellNodes = cell(1,numNodes);

    % Parse the nodes from the HashMap to Cells as the MEX seems to be
    % unable to read directly from the Java HashMap
    for keyID=1:numNodes
        cellNodes{keyID} = nodesHash(keys{keyID});

        %---------------------------------------------------------
        % WITHOUTH THIS MATLAB CRASHES WHEN RETURNING FROM GETWP
        %---------------------------------------------------------
        % We need this to force Matlab to create a new copy of the content,
        % otherwise will send a pointer aiming to the HashMap and crash when
        % returning from getWP.
        cellNodes{keyID}.x = cellNodes{keyID}.x;
    end

    waypointsList = AStar(cellNodes, initNode, finalNode, targetCoords, heuristic, 1);
    disp('I am not crashing here if you remove cellNodes{keyID}.x = cellNodes{keyID}.x');

我的第一個想法是我對 MEX 中的“cellNodes”做錯了,這導致 Matlab 崩潰,但我沒有直接使用輸入參數執行任何操作。 這是節點 class 的構造函數:

節點.cpp

Node::Node(mxArray *cellElement)
{
    double *xIn;
    double *yIn;
    char strIn[15];
    double *posXIn;
    double *posYIn;
    double *weightIn;
    double *tempVal;

    size_t numCellElms;
    mxArray *cellElement2;
    numCellElms = mxGetNumberOfFields(cellElement);
    size_t size;

    for (int cellItem = 0; cellItem < numCellElms; cellItem++)
    {
        cellElement2 = mxGetCell(cellElement,cellItem);
        if (cellItem == 0)
        {
            xIn = mxGetPr(cellElement2);
            memcpy(tempVal,xIn,sizeof(double));
            gridX = int(*tempVal);
        }

        if (cellItem == 1)
        {
            yIn = mxGetPr(cellElement2);
            memcpy(tempVal,yIn,sizeof(double));
            gridY = int(*tempVal);
        }
    
        if (cellItem >= 2 && cellItem < 10)
        {
            mwSize buflen = mxGetN(cellElement2)*sizeof(mxChar)+1;
            if (buflen <= 1)
            {
                connections[cellItem-2][0] = '\0';
            }
            else
            {
                mxGetString(cellElement2, strIn, buflen);
                memcpy(&connections[cellItem-2][0], strIn, buflen);              
            }
        }
    
        if (cellItem == 10)
        {
            posXIn = mxGetPr(cellElement2);
            memcpy(&posX,posXIn,sizeof(double));            
        }                
        if (cellItem == 11)
        {
            posYIn = mxGetPr(cellElement2);
            memcpy(&posY,posYIn,sizeof(double));  
        }        
        if (cellItem == 12)
        {
            posXIn = mxGetPr(cellElement2);
            memcpy(&wpX,posXIn,sizeof(double));            
        }                
        if (cellItem == 13)
        {
            posYIn = mxGetPr(cellElement2);
            memcpy(&wpY,posYIn,sizeof(double));  
        }                
        if (cellItem == 14)
        {
            weightIn = mxGetPr(cellElement2);
            memcpy(&weight,weightIn,sizeof(double));              
        }                                
    }

    sprintf(xStr,"%i",gridX);
    sprintf(yStr,"%i",gridY);
    sprintf(key,"%ix%i",gridX,gridY);
}

這就是我在 AStar.cpp 中初始化節點列表的方式

// Create nodes in the nodes hash
mxArray *cellElement;
std::map<std::string, Node> nodesHash;
for (int nodeID=0; nodeID < numberOfNodes; nodeID++) 
{
    cellElement = mxGetCell(prhs[0], nodeID);
    Node n(cellElement);
    nodesHash[n.key] = n;
}

現在表單不再使用 prhs[0],因為沒有改變 prhs[0] 的內容(變量包含指向 Matlab 變量 cellNodes 的指針),這個變量在離開 MEX 后應該完全相同。

從這里我有兩個問題:

  1. 如果沒有改變第一個參數的內容,為什么從 getWP 返回時它會崩潰?
  2. 有沒有更優雅的方法來強制 Matlab 創建變量的真實副本?

謝謝!

*Edit1:在 Windows10 64 位中使用 Matlab 2015b。


由@CrisLuengo 和@JamesTursa 推薦。

1)如果沒有改變第一個參數的內容,為什么從getWP返回時它會崩潰?

[Node.cpp] 'double* tempVal' 未分配,盡管代碼有效,但這可能會破壞 prhs[0] 的完整性,從而導致 Matlab 從調用 MEX 的 function 返回時崩潰。

解決方案是將 tempVal 聲明為“double tempVal[1]”。 之后,testAStarC.m 行 'cellNodes{keyID}.x = cellNodes{keyID}.x;' 可以刪除而不會導致錯誤。

雖然與崩潰無關,但使用 memcpy 獲取標量雙精度已被 mxGetScalar() 取代。

節點構造函數:

Node::Node(mxArray *cellElement)
{
    char strIn[15];
    double tempVal[1];

    size_t numCellElms = mxGetNumberOfFields(cellElement);
    mwSize buflen;

    for (int cellItem = 0; cellItem < numCellElms; cellItem++)
    {
        mxArray *cellElement2 = mxGetCell(cellElement,cellItem);
    
        switch (cellItem)
        {
            case 0:
                gridX = (int)mxGetScalar(cellElement2);
                break;
            case 1:
                gridY = (int)mxGetScalar(cellElement2);
                break;
            case 2:
            case 3:
            case 4:
            case 5:
            case 6:
            case 7:
            case 8:
            case 9:
                buflen = mxGetN(cellElement2)*sizeof(mxChar)+1;
                if (buflen <= 1)
                    connections[cellItem-2][0] = '\0';
                else
                {
                    mxGetString(cellElement2, strIn, buflen);
                    memcpy(&connections[cellItem-2][0], strIn, buflen);              
                }
                break;
            case 10:
                posX = mxGetScalar(cellElement2);        
                break;
            case 11:
                posY = mxGetScalar(cellElement2);  
                break;
            case 12:
                wpX = mxGetScalar(cellElement2);
                break;
            case 13:
                wpY = mxGetScalar(cellElement2);    
                break;
            case 14:
                weight = mxGetScalar(cellElement2);
                break;
        }
    }
    
    sprintf(xStr,"%i",gridX);
    sprintf(yStr,"%i",gridY);
    sprintf(key,"%ix%i",gridX,gridY);
}

測試AStarC.m

function waypointsList = getWP(map, initNode, finalNode, targetCoords, heuristic)
    % HashMap containing the nodes (this is a Java hashmap)
    nodesHash = map.navMap.nodes.nodes;
    keys = nodesHash.keys();
    numNodes = length(keys);

    cellNodes = cell(1,numNodes);

    % Parse the nodes from the HashMap to Cells as the MEX seems to be
    % unable to read directly from the Java HashMap
    for keyID=1:numNodes
        cellNodes{keyID} = nodesHash(keys{keyID});
    end

    waypointsList = AStar(cellNodes, initNode, finalNode, targetCoords, heuristic, 1);

2) 有沒有更優雅的方式強制 Matlab 創建變量的真實副本? 不,你能做的最好的就是嘗試分配技巧。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM