MexFile, вызывающий ошибку «Обнаружено утверждение» - проблема с memcpy в mexfiles? - PullRequest
2 голосов
/ 29 июня 2011

Эта проблема, к сожалению, узкая, но я в растерянности.

У меня есть собственный mex-файл, который принимает два списка uint32, каждый из которых отсортирован и не содержит общих записей, и возвращает один отсортированный список.содержащий все записи из обоих списков.Код:

#include "mex.h"
#include "matrix.h"
#include "string.h"

#define MIN(x, y) (((x) < (y)) ? (x) : (y))

void CalculationRoutine(uint32_T* CombinedList, const mwIndex FirstNumels, uint32_T* FirstList, const mwIndex SecondNumels, uint32_T* SecondList) {
mwIndex OutCounter = 0, FirstCounter = 0, SecondCounter = 0;
unsigned int i;

// Short-circuit if there is no ovelap.
if (*FirstList > *(SecondList+SecondNumels-1)) {
    memcpy(CombinedList,SecondList,SecondNumels*sizeof(uint32_T));
    memcpy(CombinedList+SecondNumels,FirstList,FirstNumels*sizeof(uint32_T));
    return;
} else if (*SecondList > *(FirstList+FirstNumels-1)) {
    memcpy(CombinedList,FirstList,FirstNumels*sizeof(uint32_T));
    memcpy(CombinedList+FirstNumels,SecondList,SecondNumels*sizeof(uint32_T));
    return;
}

// These can be done with no exhaustion checking. Leave one item because we
// are doing post-checking in the second loop.
for (i=MIN(FirstNumels, SecondNumels)-1; i--;) {
    if (*(FirstList+FirstCounter) < *(SecondList + SecondCounter)) {
        *(CombinedList+OutCounter) = *(FirstList+FirstCounter);        
        FirstCounter++;
    } else {
        *(CombinedList+OutCounter) = *(SecondList+SecondCounter);        
        SecondCounter++;
    }
    OutCounter++;
}

// These ones need exhaustion checking.
while (1){
    if (*(FirstList+FirstCounter) < *(SecondList + SecondCounter)) {
        *(CombinedList+OutCounter) = *(FirstList+FirstCounter);        
        FirstCounter++;
        if (FirstCounter == FirstNumels) {
            // Just copy the rest of the second list.
            memcpy(CombinedList+OutCounter+1,SecondList+SecondCounter,(SecondNumels-SecondCounter+1)*sizeof(uint32_T));
            return;
        }
    } else {
        *(CombinedList+OutCounter) = *(SecondList+SecondCounter);        
        SecondCounter++;
        if (SecondCounter == SecondNumels) {
            // Just copy the rest of the first list.
            memcpy(CombinedList+OutCounter+1,FirstList+FirstCounter,(FirstNumels-FirstCounter+1)*sizeof(uint32_T));
            return;
        }
    }
    OutCounter++;
}
}

void mexFunction( int nlhs, mxArray *plhs[],
                  int nrhs, const mxArray *prhs[] ) {

mxArray *CombinedList = NULL;
uint32_T *FirstList, *SecondList;    
mwIndex FirstNumels = mxGetNumberOfElements(prhs[0]), SecondNumels  = mxGetNumberOfElements(prhs[1]);   

//Input Checking
if (!mxIsUint32(prhs[0])) {
        mexErrMsgTxt("FirstList must be matrix of uint32.");
}
if (!mxIsUint32(prhs[1])) {
        mexErrMsgTxt("SecondList must be a matrix of uint32.");
}

CombinedList = mxCreateNumericMatrix(FirstNumels+SecondNumels, 1, mxUINT32_CLASS, mxREAL);
if (CombinedList == NULL) {
    mexErrMsgTxt("SecondList must be a matrix of uint32.");
}

//Short circuit when we have one or the other inputs empty.
if (mxIsEmpty(prhs[0])){
    if (!mxIsEmpty(prhs[1])) {
        // Return the SecondList verbatim.
        //CopyOneInput(mxGetData(CombinedList),SecondNumels, mxGetData(prhs[1]));
        memcpy(mxGetData(CombinedList), mxGetData(prhs[1]),SecondNumels*sizeof(uint32_T));
    }
    plhs[0] = CombinedList;
    return;
} else if (mxIsEmpty(prhs[1])) {
    // Return the FirstList verbatim.
    //CopyOneInput(mxGetData(CombinedList),FirstNumels, mxGetData(prhs[0]));
    memcpy(mxGetData(CombinedList), mxGetData(prhs[0]),FirstNumels*sizeof(uint32_T));
    plhs[0] = CombinedList;
    return;
}

CalculationRoutine(mxGetData(CombinedList),FirstNumels,
    mxGetData(prhs[0]),SecondNumels,mxGetData(prhs[1]));

plhs[0] = CombinedList;
}

Когда я запускаю код, который вызывает mex-файл, я получаю сообщения об обнаруженных утверждениях (с такими вещами, как найдено поврежденный блок 381 в таблице 5. (неверный индекс таблицы).).Утверждения всегда возникают, но не обязательно в одном и том же месте.

Если я вернусь к старой версии кода, проблем не будет.Так что что-то портит память, но я не вижу этого.Одно из внесенных мною изменений - использование memcpy, но я не вижу в этом ничего плохого.

Опять же, я извиняюсь, что это такой узкий вопрос, но любая помощь приветствуется.

ОБНОВЛЕНИЕ: Это определенно memcpy, который вызывает утверждение.Если я вернусь к присвоению значений в цикле, утверждения прекращаются.Существуют ли ограничения на использование memcpy в mex-файлах?

Ответы [ 2 ]

1 голос
/ 29 июня 2011

Я переписал функцию CalculationRoutine следующим образом:

// merge two sorted lists
void CalculationRoutine(uint32_T* C, const mwIndex nA, uint32_T* A, 
           const mwIndex nB, uint32_T* B)
{
    mwIndex indC = 0, indA = 0, indB = 0;

    // Short-circuit if there is no ovelap.
    if ( A[0] > B[nB-1] ) {
        memcpy(C, B, nB*sizeof(uint32_T));      // copy B
        memcpy(C+nB, A, nA*sizeof(uint32_T));   // copy A
        return;
    } else if ( B[0] > A[nA-1] ) {
        memcpy(C, A, nA*sizeof(uint32_T));      // copy A
        memcpy(C+nA, B, nB*sizeof(uint32_T));   // copy B
        return;
    }

    // loop until one of the two lists is exhausted
    while( indA < nA && indB < nB ) {
        if( A[indA] < B[indB] ) {
            C[indC++] = A[indA++];
        } else {
            C[indC++] = B[indB++];
        }
    }
    // process remaining items in the smaller list
    //if( indA < nA ) memcpy(C+indC, A+indA, (nA-indA)*sizeof(uint32_T));
    //if( indB < nB ) memcpy(C+indC, B+indB, (nB-indB)*sizeof(uint32_T));
    while( indA < nA ) C[indC++] = A[indA++];
    while( indB < nB ) C[indC++] = B[indB++];
}

И вот как я проверил ее правильность / производительность:

numIter = 1000; numX = 250; numY = 1000;
x = sort(randi(intmax('uint32'), [250 numIter],'uint32'));
y = sort(randi(intmax('uint32'), [1000 numIter],'uint32'));
M1 = zeros(size(x,1)+size(y,1),numIter,'uint32');
M2 = zeros(size(x,1)+size(y,1),numIter,'uint32');

tic
for i=1:numIter
    M1(:,i) = mySort(x(:,i),y(:,i));
end
toc

tic
for i=1:numIter
    M2(:,i) = sort([x(:,i);y(:,i)]);
end
toc

assert( isequal(M1,M2) )

Время было:

Elapsed time is 0.029080 seconds.        # mySort
Elapsed time is 0.074132 seconds.        # sort
0 голосов
/ 30 июня 2011

Это ошибка в третьем аргументе memcpy. Цикл while должен быть:

while (1){
    if (*(FirstList+FirstCounter) < *(SecondList + SecondCounter)) {
        *(CombinedList+OutCounter++) = *(FirstList+FirstCounter++);
        if (FirstCounter == FirstNumels) {
            // Just copy the rest of the second list.
            memcpy(CombinedList+OutCounter,SecondList+SecondCounter,(SecondNumels-SecondCounter)*sizeof(uint32_T));
            return;
        }
    } else {
        *(CombinedList+OutCounter++) = *(SecondList+SecondCounter++); 
        if (SecondCounter == SecondNumels) {
            // Just copy the rest of the first list.
            memcpy(CombinedList+OutCounter,FirstList+FirstCounter,(FirstNumels-FirstCounter)*sizeof(uint32_T));
            return;
        }
    }
}
...