«Free (): неверный следующий размер (быстрый)» в C ++ - PullRequest
1 голос
/ 28 ноября 2011

Я только что столкнулся с проблемой free(): invalid next size (fast) при написании программы на C ++. И я не смог понять, почему это может произойти, к сожалению. Код приведен ниже.

bool not_corrupt(struct packet *pkt, int size)
{
    if (!size) return false;
    bool result = true;
    char *exp_checksum = (char*)malloc(size * sizeof(char));
    char *rec_checksum = (char*)malloc(size * sizeof(char));
    char *rec_data = (char*)malloc(size * sizeof(char));
    //memcpy(rec_checksum, pkt->data+HEADER_SIZE+SEQ_SIZE+DATA_SIZE, size);
    //memcpy(rec_data, pkt->data+HEADER_SIZE+SEQ_SIZE, size);
    for (int i = 0; i < size; i++) {
        rec_checksum[i] = pkt->data[HEADER_SIZE+SEQ_SIZE+DATA_SIZE+i];
        rec_data[i] = pkt->data[HEADER_SIZE+SEQ_SIZE+i];
    }
    do_checksum(exp_checksum, rec_data, DATA_SIZE);
    for (int i = 0; i < size; i++) {
        if (exp_checksum[i] != rec_checksum[i]) {
            result = false;
            break;
        }
    }
    free(exp_checksum);
    free(rec_checksum);
    free(rec_data);
    return result;
}

Используются макросы:

#define RDT_PKTSIZE 128
#define SEQ_SIZE 4
#define HEADER_SIZE 1
#define DATA_SIZE ((RDT_PKTSIZE - HEADER_SIZE - SEQ_SIZE) / 2)

Используемая структура:

struct packet {
    char data[RDT_PKTSIZE];
};

Этот кусок кода не ошибается каждый раз. Это может произойти сбой с free(): invalid next size (fast) иногда в free(exp_checksum); части.

Что еще хуже, иногда то, что в rec_checksum, просто не совпадает с тем, что в pkt->data[HEADER_SIZE+SEQ_SIZE+DATA_SIZE], что должно быть одинаковым в соответствии с выражениями часов из моих инструментов отладки. Используются оба метода: memcpy и for, но эта проблема остается.

Я не совсем понимаю, почему это произошло. Я был бы очень благодарен, если бы кто-нибудь мог мне это объяснить.

Изменить:

Вот метод do_checksum (), который очень прост:

void do_checksum(char* checksum, char* data, int size)
{
    for (int i = 0; i < size; i++)
    {
        checksum[i] = ~data[i];
    }
}

Редактировать 2:

Спасибо за все.

Я переключил другую часть своего кода с использования очереди STL на вектор STL, тогда результаты получаются крутыми.

Но все же я не понял, почему. Я уверен, что я никогда не вытолкну пустую очередь.

Ответы [ 5 ]

4 голосов
/ 28 ноября 2011

Сообщение об ошибке указывает на повреждение кучи. Это может быть трудно отследить, и такие инструменты, как valgrind, могут быть чрезвычайно полезны. Повреждения кучи часто трудно отладить с помощью простого отладчика, потому что ошибка во время выполнения часто возникает задолго после фактического повреждения.

Тем не менее, наиболее очевидная потенциальная причина вашего повреждения кучи, учитывая код, размещенный до сих пор, это если DATA_SIZE больше size. Если это произойдет, то do_checksum запишет после конца exp_checksum.

1 голос
/ 28 ноября 2011

Три немедленных предложения:

  1. Проверьте размер <= 0 (вместо "! Size") </p>

  2. Проверить размер> = DATA_SIZE

  3. Проверка возврата malloc NULL

0 голосов
/ 01 декабря 2011

DATA_SIZE - это макрос, определяющий максимальную длину в моей программе, поэтому его размер должен быть меньше, чем DATA_SIZE

, даже если это так, ваша логика только создает достаточно памяти для хранения size персонажи.поэтому вы должны позвонить

do_checksum(exp_checksum, rec_data, size);

и, если вы не хотите использовать std::string (что нормально), вы должны переключиться с malloc/free на new/delete при разговоре C ++

0 голосов
/ 28 ноября 2011

Valgrind хорош ... но проверка всех ваших входных данных и проверка всех условий ошибки еще лучше.

Выполнение кода в отладчике тоже неплохая идея.

Я бы также назвал do_checksum (размер) (ваш фактический размер) вместо DATA_SIZE (предположительно, «максимальный размер»).

0 голосов
/ 28 ноября 2011

Вы пробовали Valgrind ?

Кроме того, убедитесь, что никогда не отправляете больше, чем RDT_PKTSIZE как size на not_corrupt()

bool not_corrupt(struct packet *pkt, int size)
{
    if (!size) return false;
    if (size > RDT_PKTSIZE) return false;
    /* ... */
...