Нарушение прав доступа к массиву символов

Я получаю нарушение прав доступа к массиву символов, который только что создал с помощью new.

DispatchCommand(char* cmdStr)
        {
            // Dispatch
            for(int i = 0; i < sizeof(_lpCommands); i++)
            {
                const int len = strlen(_lpCommands[i].szCommand);
                char* cmdblip = new char[len + 1];
                memcpy(&cmdblip, cmdStr, len);
                cmdblip[len] = '\0';  // Access Violation

                if(strcmp(cmdblip, _lpCommands[i].szCommand) == 0)
                {
                    if(strlen(cmdStr) > strlen(_lpCommands[i].szCommand))
                        (*_lpCommands[i].cbCallback)(&cmdStr[strlen(_lpCommands[i].szCommand)]);
                    else
                        (*_lpCommands[i].cbCallback)("");

                    delete cmdblip;
                    return;
                }

                delete cmdblip;
            }

            // Error and return
            *Out::ServerInfo<<"Command not found!"<<ENDL;
        }

_lpCommands — это массив из Command структур:

struct Command
{
    char* szCommand;
    CommandCallback cbCallback;
};

Произведенное сообщение об ошибке:

Необработанное исключение по адресу 0x012219cf в Program.exe: 0xC0000005: место записи нарушения прав доступа 0x66647366.

Это был переписанный аналогичный код, в котором использовалось memcmp, что в конечном итоге привело к нарушению прав доступа без выполнения memcpy.

Что дает?


person Qix - MONICA WAS MISTREATED    schedule 27.06.2012    source источник
comment
Почему не std::string? И у вас есть неопределенное поведение в delete cmdblip;. Должно быть delete [] cmdblip;.   -  person Fred Larson    schedule 27.06.2012
comment
@FredLarson - Попытка уйти от std::string для этой конкретной части программы. И спасибо за подсказку!   -  person Qix - MONICA WAS MISTREATED    schedule 27.06.2012
comment
Не пытайтесь держаться подальше от std::string, старайтесь держаться подальше от char*!   -  person Fred Larson    schedule 27.06.2012
comment
Неиспользование std::string слишком локализовано. Этот код — фугли, и тот факт, что он содержит ошибки, является прямым следствием того факта, что ваш код ужасно отстойный, а не какой-то конкретный экземпляр отстойного.   -  person Puppy    schedule 27.06.2012
comment
Как указано в отмеченном ответе, у меня была опечатка, и я передавал указатель на указатель. Мой код отлично работает после его изменения. Мне нужно было держаться подальше от std::string для этой конкретной части кода. Охладите свои самолеты, детишки.   -  person Qix - MONICA WAS MISTREATED    schedule 29.06.2012


Ответы (2)


Не передавать &cmdblip в memcpy. Вы должны передать указатель на буфер назначения, а не указатель на этот указатель. Вместо этого передайте cmdblip.

Изменить: я согласен с тем, что в C++ следует использовать std::string. Тем не менее, техническая причина сбоя этого кода заключается в том, что memcpy повреждает указатель cmdblip, заставляя его указывать на область памяти, которая фактически состоит из первых 4 байтов скопированной строки. Затем cmdblip[len] приводит к тому, что ячейка памяти находится за пределами выделенного буфера (или любого другого законно выделенного буфера), что приводит к сбою. Итак, если вы хотите писать лучший код, используйте классы C++. И если вы хотите понять, почему данный код дал сбой, рассмотрите вышеизложенное.

person eran    schedule 27.06.2012
comment
Ах, глупая опечатка. Это была долгая ночь. Казалось, это сработало! Спасибо! - person Qix - MONICA WAS MISTREATED; 27.06.2012
comment
@ Di-0xide Вам все равно нужно изменить delete на delete[], даже если это работает. - person jrok; 27.06.2012
comment
Да, и заодно измените тип аргумента cmdStr на const char*. Вы не изменяете эту строку в своем коде, поэтому защитите себя от случайных изменений в будущем. - person eran; 27.06.2012
comment
@eran: Да. Единственный возможный ответ на этот вопрос — использовать std::string. С таким же успехом вы можете решить проблемы безработных, предоставив им койку на одну ночь — на самом деле это не решение совсем. - person Puppy; 27.06.2012
comment
@DeadMG, пожалуйста, наведите указатель мыши на маленькую стрелку, указывающую вниз, на которую вы нажали. Должно появиться сообщение о том, что этот ответ бесполезен. Мой ответ определенно полезен - он решил рассматриваемую проблему. Если вы хотите быть пуристом, вы можете высказать свое мнение о своем собственном ответе, как вы это сделали. Не злоупотребляйте отрицательным голосованием - этот ответ совершенно правильный, даже если он не меняет общий подход ОП к программированию на С++. - person eran; 27.06.2012
comment
@eran: Ваш ответ бесполезен. Все, что вы сделали, это отложили проблему ОП на время, необходимое ему для поддержания этой функции или написания новой. Вы ничего не решили. Настоящая проблема здесь в том, что код OP отстой, и это лишь одна из многих ошибок, с которыми он будет часто сталкиваться, пока она не будет исправлена. Конкретная ошибка в вопросе — это просто симптом, и его исправление ничего не решает. - person Puppy; 27.06.2012
comment
@DeadMG - единственный возможный ответ на этот вопрос - использовать std::string - вряд ли? Мой код работает нормально. Ответ Эрана был ответом на мой вопрос. Как я уже дважды заявлял, мне нужно было уйти от std::string для этого конкретного участка кода. - person Qix - MONICA WAS MISTREATED; 29.06.2012

Единственный возможный полезный ответ на этот вопрос — «Использовать std::string». Конкретная проблема, с которой вы сталкиваетесь сейчас, будет просто возникать снова или идентично каждый раз, когда вы изменяете эту функцию или пишете другую подобную ей. Единственный способ решить проблему в общем случае — это перейти на классовое решение, которое любезно предоставляется вам в качестве Стандарта. Например, ваш текущий код небезопасен в отношении исключений, вдобавок к тому, что дает вам нарушение доступа, не говоря уже о том, что он нечитаем и требует ряда других ошибок, таких как off-by-one, неправильное завершение NULL, двойное удаления и утечки памяти. О, и UB, потому что вы delete то, что вы new[].

person Puppy    schedule 27.06.2012
comment
@DomagojPandža - char* являются «настоящим C++». Я даже заявил, что хочу уйти от строк в этой конкретной части кода. Я не говорил, что больше нигде не использую строку. - person Qix - MONICA WAS MISTREATED; 29.06.2012
comment
Остается вопрос: почему? - person Etienne de Martel; 29.06.2012
comment
@Di-0xide: char* определенно не C++. - person Puppy; 29.06.2012
comment
С каких это пор char и pointers не C++? C Strings может быть не 'C++', но в последний раз, когда я проверял, у вас не может быть C++ без скалярного типа char. - person Qix - MONICA WAS MISTREATED; 29.06.2012
comment
Вы говорите, что использовали std::strings везде, но не здесь. И у вас получилось получить нарушение прав доступа именно в этой части, гы, я могу только догадываться, как это произошло. Вот почему мы возражаем против таких подходов. Вам нужно обладать знаниями и опытом, чтобы справляться с такими ситуациями, но когда они у вас уже есть, вы выбираете разработку более безопасных решений или используете стандартную библиотеку. Тот беспорядок, который вы написали наверху, является сигнатурой C. C++ был создан для гораздо большего, чем просто классы. - person ; 29.06.2012
comment
@DomagojPandža - Это здорово, но я здесь не для того, чтобы получить одобрение выбора использования массивов символов вместо std::string. Меня проинструктировали, что нам нужно оставить эту часть кода не-std::string по чертовски веской причине. Нетрудно просто ответить на вопрос и сделать любезное предложение вместо того, чтобы делать вид, будто я знаю, что лично я ужасный программист. - person Qix - MONICA WAS MISTREATED; 01.07.2012