valgrind | Неверное чтение размера 8 | Адрес 0x7a41270 - это 0 байтов внутри блока размером 4, выделенного

вот уже несколько дней я пытаюсь найти ошибку памяти в своем программном обеспечении.
Это довольно сложно, но хорошо структурировано и отформатировано (на мой взгляд).
Ошибка появляется на 64-битной машине под управлением Debian GNU / Linux.
(... не на моей 32-битной машине - void * / int mixup?)
Я был бы очень рад, если бы вы могли мне помочь.

Фрагменты исходного кода следуют в конце этого сообщения.
Если этого недостаточно, вы можете проверить весь исходный код по адресу:
http://savannah.nongnu.org/svn/?group=cybop

Следуйте инструкциям файла INSTALL для компиляции и запуска.

Следующее программное обеспечение работает нормально:

enter code herechristian @ deneb: / home / project / cybop / examples $ ../src/controller/cyboi.

Запуск его с опцией приводит к ошибкам проверки памяти в valgrind:
christian @ deneb: / home / project / cybop / examples $ ../src/controller/cyboi --help

Я запустил memcheck, используя эту командную строку:
christian @ deneb: / home / project / cybop / examples $ valgrind --log-file = memcheck.log --tool = memcheck --read-var-info = да --track-origins = да ../src/controller/cyboi --help

Вот результат memcheck:

==20072== Memcheck, a memory error detector
==20072== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==20072== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==20072== Command: ../src/controller/cyboi --help
==20072== Parent PID: 18978
==20072== 
==20072== Invalid read of size 8
==20072==    at 0x40AF0E: decode_utf_8 (utf_8_decoder.c:298)
==20072==    by 0x42A53D: optionalise_argument (argument_optionaliser.c:110)
==20072==    by 0x42A786: optionalise (optionaliser.c:107)
==20072==    by 0x401507: main (cyboi.c:168)
==20072==  Address 0x7a41270 is 0 bytes inside a block of size 4 alloc'd
==20072==    at 0x402894D: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==20072==    by 0x404C52: allocate_array (array_allocator.c:66)
==20072==    by 0x40A0FC: allocate_item (item_allocator.c:62)
==20072==    by 0x42A4D2: optionalise_argument (argument_optionaliser.c:85)
==20072==    by 0x42A786: optionalise (optionaliser.c:107)
==20072==    by 0x401507: main (cyboi.c:168)
==20072== 
==20072== Invalid read of size 8
==20072==    at 0x40AF31: decode_utf_8 (utf_8_decoder.c:300)
==20072==    by 0x42A53D: optionalise_argument (argument_optionaliser.c:110)
==20072==    by 0x42A786: optionalise (optionaliser.c:107)
==20072==    by 0x401507: main (cyboi.c:168)
==20072==  Address 0x7a41270 is 0 bytes inside a block of size 4 alloc'd
==20072==    at 0x402894D: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==20072==    by 0x404C52: allocate_array (array_allocator.c:66)
==20072==    by 0x40A0FC: allocate_item (item_allocator.c:62)
==20072==    by 0x42A4D2: optionalise_argument (argument_optionaliser.c:85)
==20072==    by 0x42A786: optionalise (optionaliser.c:107)
==20072==    by 0x401507: main (cyboi.c:168)
==20072== 
==20072== 
==20072== HEAP SUMMARY:
==20072==     in use at exit: 0 bytes in 0 blocks
==20072==   total heap usage: 34 allocs, 34 frees, 8,232 bytes allocated
==20072== 
==20072== All heap blocks were freed -- no leaks are possible
==20072== 
==20072== For counts of detected and suppressed errors, rerun with: -v
==20072== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 4 from 4)

Запускаем программное обеспечение следующим образом:
christian @ deneb: / home / project / cybop / examples $ ../src/controller/cyboi --knowledge ui_control / run.cybol

... выдает эти ошибки:

cyboi: malloc.c: 3096: sYSMALLOc: Assertion `(old_top == (((mbinptr) (((char *) & ((av) -> bins [((1) - 1) * 2])) - __builtin_offsetof (struct malloc_chunk, fd)))) && old_size == 0) || ((длинное беззнаковое) (old_size)

= (длинное без знака) ((((__ builtin_offsetof (struct malloc_chunk, fd_nextsize)) + ((2 * (sizeof (size_t))) - 1)) & ~ ((2 * (sizeof (size_t))) - 1)) ) && ((old_top) -> size & 0x1) && ((unsigned long) old_end & pagemask) == 0) 'не удалось. Прервано

Любая помощь могла бы быть полезна. Я действительно больше не знаю, в каком месте отлаживать.

Исходный код:

//
// cyboi.c
//

// The cybol knowledge file path item.
void* k = *NULL_POINTER_STATE_CYBOI_MODEL;

// Allocate cybol knowledge file path item.
allocate_item((void*) &k, (void*) NUMBER_0_INTEGER_STATE_CYBOI_MODEL, (void*) WIDE_CHARACTER_TEXT_STATE_CYBOI_TYPE);

// Optionalise command line argument options.
optionalise((void*) &m, k, (void*) LOG_LEVEL, (void*) LOG_OUTPUT, (void*) p1, (void*) &p0);

//
// optionaliser.c
//

while (*TRUE_BOOLEAN_STATE_CYBOI_MODEL) {

    compare_integer_greater_or_equal((void*) &b, (void*) &j, p5);

    if (b != *FALSE_BOOLEAN_STATE_CYBOI_MODEL) {

        break;
    }

    optionalise_argument(p0, p1, p2, p3, p4, p5, (void*) &j);

    // Increment loop variable.
    j++;
}

//
// argument_optionaliser.c
//

// The command line argument option as multibyte character array.
void* od = *NULL_POINTER_STATE_CYBOI_MODEL;
int oc = *NUMBER_0_INTEGER_STATE_CYBOI_MODEL;
// The option, value as wide character item.
void* ow = *NULL_POINTER_STATE_CYBOI_MODEL;
// The option, value as wide character item data, count.
void* owd = *NULL_POINTER_STATE_CYBOI_MODEL;
void* owc = *NULL_POINTER_STATE_CYBOI_MODEL;

// Allocate option, value wide character item.
allocate_item((void*) &ow, (void*) NUMBER_0_INTEGER_STATE_CYBOI_MODEL, (void*) WIDE_CHARACTER_TEXT_STATE_CYBOI_TYPE);

// Get command line argument option.
// Example: "--loglevel"
copy_array_forward((void*) &od, p4, (void*) POINTER_STATE_CYBOI_TYPE, (void*) PRIMITIVE_STATE_CYBOI_MODEL_COUNT, (void*) VALUE_PRIMITIVE_STATE_CYBOI_NAME, p6);

if (od != *NULL_POINTER_STATE_CYBOI_MODEL) {

    // Get command line argument option count (number of characters).
    oc = strlen((char*) od);

    // Decode multibyte character option into wide character.
    decode_utf_8(ow, od, (void*) &oc);

} else {

    log_write((void*) stdout, L"Error: Could not optionalise command line argument. The command line argument option is null.\n");
}

//
// utf_8_decoder.c
//

// The destination item data, count, size.
void* dd = *NULL_POINTER_STATE_CYBOI_MODEL;
void* dc = *NULL_POINTER_STATE_CYBOI_MODEL;
void* ds = *NULL_POINTER_STATE_CYBOI_MODEL;
// The new destination size.
int nds = *NUMBER_0_INTEGER_STATE_CYBOI_MODEL;

// Get destination item count, size.
copy_array_forward((void*) &dc, p0, (void*) POINTER_STATE_CYBOI_TYPE, (void*) PRIMITIVE_STATE_CYBOI_MODEL_COUNT, (void*) VALUE_PRIMITIVE_STATE_CYBOI_NAME, (void*) COUNT_ITEM_STATE_CYBOI_NAME);
copy_array_forward((void*) &ds, p0, (void*) POINTER_STATE_CYBOI_TYPE, (void*) PRIMITIVE_STATE_CYBOI_MODEL_COUNT, (void*) VALUE_PRIMITIVE_STATE_CYBOI_NAME, (void*) SIZE_ITEM_STATE_CYBOI_NAME);

// Initialise new destination size.
calculate_integer_add((void*) &nds, p2);

// Reallocate destination item.
reallocate_item(p0, (void*) &nds, (void*) WIDE_CHARACTER_TEXT_STATE_CYBOI_TYPE);

// Set locale.
// CAUTION! This setting IS NECESSARY for UTF-8 character conversion
// with restartable multibyte conversion functions like "mbsnrtowcs"
// and "wcsnrtombs" to work correctly.
// The return value is not used; this is a global setting.
char* loc = setlocale(LC_CTYPE, "");

// Get destination item data.
copy_array_forward((void*) &dd, p0, (void*) POINTER_STATE_CYBOI_TYPE, (void*) PRIMITIVE_STATE_CYBOI_MODEL_COUNT, (void*) VALUE_PRIMITIVE_STATE_CYBOI_NAME, (void*) DATA_ITEM_STATE_CYBOI_NAME);

// Initialise error number.
// It is a global variable/ function and other operations
// may have set some value that is not wanted here.
//
// CAUTION! Initialise the error number BEFORE calling the function
// that might cause an error.
errno = *NUMBER_0_INTEGER_STATE_CYBOI_MODEL;

// Converts the multibyte character string into a wide character string.
// Returns the number of wide characters
// successfully converted, except in the case of an encoding error.
//
// CAUTION! The multibyte source character string does NOT need to be
// null-terminated, since the third parametre already indicates its count.
//
// CAUTION! Hand over the NEW destination size as fourth parametre,
// since it indicates the maximum number of characters to be converted
// and conversion would break too early if that parametre was too small.
//
// CAUTION! The fifth parametre may be NULL. In this case, a static
// anonymous state only known to the function internally is used instead.
// It just indicates where conversion is started.
int n = mbsnrtowcs((wchar_t*) dd, (const char**) &sd, *((size_t*) sc), *((size_t*) ds), (mbstate_t*) *NULL_POINTER_STATE_CYBOI_MODEL);

if (n >= *NUMBER_0_INTEGER_STATE_CYBOI_MODEL) {

    // Set destination count to the number of WIDE characters converted.
    copy_integer(dc, (void*) &n);

} else {

    if (errno == EILSEQ) {

        fwprintf(stdout, L"TEST ERROR EILSEQ errno: %i\n", errno);
        log_message_terminated((void*) ERROR_LEVEL_LOG_CYBOI_MODEL, (void*) L"Could not decode utf-8. The input string contains an invalid multibyte sequence.");

    } else {

        fwprintf(stdout, L"TEST ERROR UNKNOWN errno: %i\n", errno);
        log_message_terminated((void*) ERROR_LEVEL_LOG_CYBOI_MODEL, (void*) L"Could not decode utf-8. An unknown error occured.");
    }
}

//
// item_allocator.c
//

/**
 * Allocates the item.
 *
 * @param p0 the item (pointer reference)
 * @param p1 the size
 * @param p2 the type
 */
void allocate_item(void* p0, void* p1, void* p2) {

    if (p0 != *NULL_POINTER_STATE_CYBOI_MODEL) {

        void** i = (void**) p0;

        log_message_terminated((void*) DEBUG_LEVEL_LOG_CYBOI_MODEL, (void*) L"Allocate item.");

        // Allocate item.
        allocate_array(p0, (void*) ITEM_STATE_CYBOI_MODEL_COUNT, (void*) POINTER_STATE_CYBOI_TYPE);

        // The data, count, size.
        void* d = *NULL_POINTER_STATE_CYBOI_MODEL;
        void* c = *NULL_POINTER_STATE_CYBOI_MODEL;
        void* s = *NULL_POINTER_STATE_CYBOI_MODEL;

        // Allocate data, count, size.
        allocate_array((void*) &d, p1, p2);
        allocate_array((void*) &c, (void*) PRIMITIVE_STATE_CYBOI_MODEL_COUNT, (void*) INTEGER_NUMBER_STATE_CYBOI_TYPE);
        allocate_array((void*) &s, (void*) PRIMITIVE_STATE_CYBOI_MODEL_COUNT, (void*) INTEGER_NUMBER_STATE_CYBOI_TYPE);

        // Initialise count, size.
        // The data does NOT have to be initialised and remains empty.
        // The count is set to zero, since the model does not contain any elements yet.
        // The size is set to the value that was handed over as argument.
        copy_integer(c, (void*) NUMBER_0_INTEGER_STATE_CYBOI_MODEL);
        copy_integer(s, p1);

        // Set data, count, size.
        copy_array_forward(*i, (void*) &d, (void*) POINTER_STATE_CYBOI_TYPE, (void*) PRIMITIVE_STATE_CYBOI_MODEL_COUNT, (void*) DATA_ITEM_STATE_CYBOI_NAME, (void*) VALUE_PRIMITIVE_STATE_CYBOI_NAME);
        copy_array_forward(*i, (void*) &c, (void*) POINTER_STATE_CYBOI_TYPE, (void*) PRIMITIVE_STATE_CYBOI_MODEL_COUNT, (void*) COUNT_ITEM_STATE_CYBOI_NAME, (void*) VALUE_PRIMITIVE_STATE_CYBOI_NAME);
        copy_array_forward(*i, (void*) &s, (void*) POINTER_STATE_CYBOI_TYPE, (void*) PRIMITIVE_STATE_CYBOI_MODEL_COUNT, (void*) SIZE_ITEM_STATE_CYBOI_NAME, (void*) VALUE_PRIMITIVE_STATE_CYBOI_NAME);

    } else {

        log_message_terminated((void*) ERROR_LEVEL_LOG_CYBOI_MODEL, (void*) L"Could not allocate item. The item is null.");
    }
}

//
// array_allocator.c
//

/**
 * Allocates the array.
 *
 * @param p0 the array (pointer reference)
 * @param p1 the size
 * @param p2 the type
 */
void allocate_array(void* p0, void* p1, void* p2) {

    if (p0 != *NULL_POINTER_STATE_CYBOI_MODEL) {

        void** a = (void**) p0;

        log_message_terminated((void*) DEBUG_LEVEL_LOG_CYBOI_MODEL, (void*) L"Allocate array.");

        // The memory area.
        size_t ma = *NUMBER_0_INTEGER_STATE_CYBOI_MODEL;

        // Determine type (type) size.
        determine_size((void*) &ma, p2);

        // Calculate memory area.
        calculate_integer_multiply((void*) &ma, p1);

        // A minimal space in memory is always allocated,
        // even if the requested size is zero.
        // In other words, a handle to the new instance is always returned.
        *a = malloc(ma);

        // Initialise array elements with null pointer.
        //
        // CAUTION! Initialising with zero is essential, since cyboi
        // frequently tests variables for null pointer values.
        memset(*a, *NUMBER_0_INTEGER_STATE_CYBOI_MODEL, ma);

    } else {

        log_message_terminated((void*) ERROR_LEVEL_LOG_CYBOI_MODEL, (void*) L"Could not allocate array. The array is null.");
    }
}

//
// size_determiner.c
//

/**
 * Determines the size of the given type.
 *
 * @param p0 the size
 * @param p1 the type
 */
void determine_size(void* p0, void* p1) {

    if (p1 != *NULL_POINTER_STATE_CYBOI_MODEL) {

        int* t = (int*) p1;

        // CAUTION! Do NOT call the logger here.
        // It uses functions causing circular references.
        // log_message_terminated((void*) DEBUG_LEVEL_LOG_CYBOI_MODEL, (void*) L"Determine size.");

        //
        // datetime
        //

        if (*t == *DATETIME_STATE_CYBOI_TYPE) {

            // CAUTION! This type IS NEEDED, e.g. when DEEP copying a part.
            // It is actually a pointer array, of which each
            // pointer references a structure element.
            copy_integer(p0, (void*) POINTER_TYPE_SIZE);

        //
        // element
        //

        } else if (*t == *PART_ELEMENT_STATE_CYBOI_TYPE) {

            // CAUTION! This type IS NEEDED, e.g. when DEEP copying a part
            // or when setting the references of a part
            // for rubbish (garbage) collection.
            // It is actually a pointer array, of which each
            // pointer references a structure element.
            copy_integer(p0, (void*) POINTER_TYPE_SIZE);

        //
        // logicvalue
        //

        } else if (*t == *BOOLEAN_LOGICVALUE_STATE_CYBOI_TYPE) {

            copy_integer(p0, (void*) SIGNED_INTEGER_INTEGRAL_TYPE_SIZE);

        //
        // number
        //

        } else if (*t == *COMPLEX_NUMBER_STATE_CYBOI_TYPE) {

            // CAUTION! This type IS NEEDED, e.g. when DEEP copying a part.
            // It is actually a pointer array, of which each
            // pointer references a structure element.
            copy_integer(p0, (void*) POINTER_TYPE_SIZE);

        } else if (*t == *DOUBLE_NUMBER_STATE_CYBOI_TYPE) {

            copy_integer(p0, (void*) DOUBLE_REAL_TYPE_SIZE);

        } else if (*t == *FRACTION_NUMBER_STATE_CYBOI_TYPE) {

            // CAUTION! This type IS NEEDED, e.g. when DEEP copying a part.
            // It is actually a pointer array, of which each
            // pointer references a structure element.
            copy_integer(p0, (void*) POINTER_TYPE_SIZE);

        } else if (*t == *INTEGER_NUMBER_STATE_CYBOI_TYPE) {

            copy_integer(p0, (void*) SIGNED_INTEGER_INTEGRAL_TYPE_SIZE);

        } else if (*t == *UNSIGNED_LONG_NUMBER_STATE_CYBOI_TYPE) {

            copy_integer(p0, (void*) UNSIGNED_LONG_INTEGER_INTEGRAL_TYPE_SIZE);

        //
        // pointer
        //

        } else if (*t == *POINTER_STATE_CYBOI_TYPE) {

            copy_integer(p0, (void*) POINTER_TYPE_SIZE);

        //
        // text
        //

        } else if (*t == *CHARACTER_TEXT_STATE_CYBOI_TYPE) {

            copy_integer(p0, (void*) SIGNED_CHARACTER_INTEGRAL_TYPE_SIZE);

        } else if (*t == *WIDE_CHARACTER_TEXT_STATE_CYBOI_TYPE) {

            copy_integer(p0, (void*) WIDE_CHARACTER_INTEGRAL_TYPE_SIZE);

        } else {

            // CAUTION! Do NOT call the logger here.
            // It uses functions causing circular references.
            // log_message_terminated((void*) WARNING_LEVEL_LOG_CYBOI_MODEL, (void*) L"Could not determine size. The type is unknown.");
        }

    } else {

        // CAUTION! Do NOT call the logger here.
        // It uses functions causing circular references.
        // log_message_terminated((void*) ERROR_LEVEL_LOG_CYBOI_MODEL, (void*) L"Could not determine size. The type is null.");
    }
}

person Christian Heller    schedule 02.06.2012    source источник


Ответы (2)


В строке 201 в utfsize_tdecoder.c у вас есть

fwprintf(stdout, L"TEST decoder *ds: %i\n", *((int*) ds));

так что вы относитесь к ds как к int*, и это прекрасно работает. Но в строках 298 и 300, которые были обозначены valgrind,

fwprintf(stdout, L"TEST decoder *ds pre mbsnrtowcs as size_t: %i\n", *((size_t*) ds));

int n = mbsnrtowcs((wchar_t*) dd, (const char**) &sd, *((size_t*) sc), *((size_t*) ds), (mbstate_t*) *NULL_POINTER_STATE_CYBOI_MODEL);

вы относитесь к ds как к size_t*. int обычно имеет четыре байта, но size_t имеет восемь байтов в любой уважающей себя 64-битной системе.

person Daniel Fischer    schedule 02.06.2012
comment
Замечание size_t имеет восемь байтов на любой уважающей себя 64-битной системе - действительно полезный намек. Я этого не знал. CYBOI использует int для представления размера типа, а при вызове функции glibc я просто приводил к size_t. Думаю, мне нужно поменять больше мест в коде. Завтра проверю это на моем 64-битном ящике на работе. Спасибо, Кристиан - person Christian Heller; 03.06.2012
comment
Да, вот и все. Спасибо еще раз! Поскольку я работаю со стандартными переменными int во всем своем коде, я просто ввожу новую локальную переменную типа size_t непосредственно перед вызовом функции glibc и присваиваю ей значение переменной int. Затем переменная типа size_t передается как параметр функции glibc. - person Christian Heller; 04.06.2012

Подпрограмма decode_utf_8 пытается прочитать 8 байтов в том месте, где вы выделили только 4. Поскольку вы также говорите, что это происходит только на 64-битной машине, а на 32-битной это работает нормально, это указывает на то, что у вас есть ложное предположение о размер целого числа или типа указателя где-то. Вы не показываете нам decode_utf_8, поэтому сказать что-либо еще будет чистой спекуляцией.

person Jens Gustedt    schedule 02.06.2012
comment
Я скопировал функцию decode_utf_8 в свой фрагмент исходного кода. Просто прокрутите вниз. - person Christian Heller; 03.06.2012