LINUXTALKS.CO

valgrind

 

L


0

1

Я пока не могу – мне тут valgrind какую-то дичь верещит.

Есть такой вот код:

struct entry_s {

    void (*handler) (void);

    struct entry_s *next;

};

typedef entry_s entry_t;


typedef struct {

    entry_t *first;
    entry_t *last;

} entries_t;


// сюда они добавляются в начале рантайма
static entries_t entries = { NULL, NULL };


// где-то ниже по коду дела

entry_t *entry = entries.first;

while (entry) {

    entry->handler();

    entry = entry->next; // valgrind: Invalid read of size 8
}

Вот скажи мне, как неойтишник, какого хуя ему не нравится?

★★★★★★★★★★

Кто ж знает, какие там поинтеры у тебя лежат в first и last в реальном коде.. Если бы было NULL как ты вписал, он бы в while вообще не зашёл

P.S. А нафига тут поле last вообще, если с него нельзя пойти в обратном направлении? Список то односвязный

ThePlayerZero    
★★
Android / Chrome

Вынеси лучше эту ветку в отдельный тред-вопрос, оно к развитию LT отношения не имеет.. В Tech-Dev-Game раздел, там как раз тем не хватает.. Звёзд я у тебя насчитал аж 10, прав должно хватить

ThePlayerZero    
★★
Последнее исправление: ThePlayerZero (всего исправлений: 1)

Android / Chrome
Ответ на: комментарий от ThePlayerZero

Он двусвязный, у энтри есть указатель на prev. Функции вставки и вынимания я тут не запостил. Запостить?

Там и лежат поинтеры на энтри’с. Если там один, то он, конечно, и фёрст и ласт одновременно.

deep-purple    
★★★★★★★★★★
Android / Firefox
Ответ на: комментарий от deep-purple

Он двусвязный, у энтри есть указатель на prev

В том коде что ты запостил никакого prev нет. Но я тебе верю

Функции вставки и вынимания я тут не запостил. Запостить?

Бумага всё стерпит, а сервер LT тем более. Пости

А, ну и last нужен и для односвязного, если в него подразумевается аппенд без цикла до последнего элемента.

Не знаю, мне всё равно не нравится.. Ну ладно, если у тебя на самом деле двусвязный, то этот вопрос исчерпан

ThePlayerZero    
★★
Последнее исправление: ThePlayerZero (всего исправлений: 1)

Android / Chrome
Ответ на: комментарий от ThePlayerZero

Чот отдельным минимальным примером не воспроизводится… Ну что ж, будем дебажить дальше. Память то может портить кто-то другой. А валгринд лишь указывает на то, что увидел.

deep-purple    
★★★★★★★★★★
Linux / Firefox
Ответ на: комментарий от ThePlayerZero

Ну, раз уж вынес в минимал:



#include <stdlib.h>
#include <string.h>
#include <stdio.h>


////////////////////////////////////////////////////////
////////////////////////////////////////////////////////


struct entry_s {

    int id;

    void (*handler) (struct entry_s *entry);

    struct entry_s *prev;
    struct entry_s *next;

};


typedef struct entry_s entry_t;


void
entry_handler(entry_t *entry)
{
    char *ptr;


    printf("handle entry: %p -> %d\n", entry, entry->id);


    ptr = malloc(1000);

    if (NULL == ptr) {

        printf("failed to allocate entry handler tmp data\n");

        return;
    }


    memset(ptr, 0, 1000);


    free(ptr);
}


entry_t *
entry_create(int id)
{
    entry_t *entry;


    entry = malloc(sizeof(entry_t));

    if (NULL == entry) {

        return NULL;
    }


    entry->id = id;

    entry->handler = entry_handler;

    entry->prev = NULL;
    entry->next = NULL;


    return entry;
}


////////////////////////////////////////////////////////
////////////////////////////////////////////////////////


typedef struct {

    entry_t *first;
    entry_t *last;

} entries_t;


void
entries_add_entry(entries_t *entries, entry_t *entry)
{
    entry_t *last;


    last = entries->last;

    if (last) {

        last->next  = entry;
        entry->prev = last;

    } else {
        entries->first = entry;
    }


    entries->last = entry;
}


void
entries_remove_entry(entries_t *entries, entry_t  *entry)
{
    entry_t *prev;
    entry_t *next;


    prev = entry->prev;
    next = entry->next;


    if (prev && next) {

        prev->next = next;
        next->prev = prev;

    } else if (prev) {

        prev->next    = NULL;
        entries->last = prev;

    } else if (next) {

        next->prev     = NULL;
        entries->first = next;

    } else {

        entries->first = NULL;
        entries->last  = NULL;
    }


    entry->prev = NULL;
    entry->next = NULL;
}


void
entries_clear(entries_t *entries)
{
    entry_t *curr;
    entry_t *next;


    curr = entries->first;

    while (curr) {

        next = curr->next;

        free(curr);

        curr = next;
    }


    entries->first = NULL;
    entries->last  = NULL;
}


////////////////////////////////////////////////////////
////////////////////////////////////////////////////////


static entries_t my_entries = { NULL, NULL };


////////////////////////////////////////////////////////
////////////////////////////////////////////////////////


#define ENTRIES_NUM  8


int
main(void)
{
    entry_t *entry;

    int i;


    // create and add
    for (i = 0; i < ENTRIES_NUM; i++) {


        entry = entry_create(i);

        if (NULL == entry) {

            printf("failed to create entry: %d\n", i);

            return 1;
        }


        entries_add_entry(&my_entries, entry);
    }


    // remove third
    entry = my_entries.first->next->next;

    entries_remove_entry(&my_entries, entry);

    free(entry);


    // each
    entry = my_entries.first;

    while (entry) {

        entry->handler(entry);

        entry = entry->next;
    }


    // clear
    entries_clear(&my_entries);


    return 0;
}


deep-purple    
★★★★★★★★★★
Linux / Firefox
Ответ на: комментарий от deep-purple

так какие у тебя проблемы с этим «минималом»?

я его скомпилил со всякими санитайзерам и ворнингами, работает вроде всё

$ gcc -Wall -Wextra -fsanitize=address -fsanitize=pointer-compare -fsanitize=pointer-subtract -fsanitize=leak -fsanitize=undefined deep-purple.c

$ ./a.out 
handle entry: 0x603000000010 -> 0
handle entry: 0x603000000040 -> 1
handle entry: 0x6030000000a0 -> 3
handle entry: 0x6030000000d0 -> 4
handle entry: 0x603000000100 -> 5
handle entry: 0x603000000130 -> 6
handle entry: 0x603000000160 -> 7

Чот отдельным минимальным примером не воспроизводится…

🗿

ThePlayerZero    
★★
Linux / Chrome
Ответ на: комментарий от deep-purple

А, ну и last нужен и для односвязного, если в него подразумевается аппенд без цикла до последнего элемента.

Не знаю, мне всё равно не нравится.. Ну ладно, если у тебя на самом деле двусвязный, то этот вопрос исчерпан

Ты бы мысль то развернул. Вдруг дельные аргументы какие есть.

  1. (Теоретико-эстетствующий) Односвязный список – это каноничная структура данных. Да, в C он реализуется на указателях и позволяет хак в виде быстрого аппенда в конец. В том же Haskell ты так принципиально не сделаешь, поскольку там нет ни указателей, ни ссылок.

Тут нарушается некая «регулярность» между имплементациями, я не могу точный термин подобрать, но что-то здесь не то :)

  1. (Консистентность API) Забыли про другие языки. Что такое односвязный список? Это стек, стопка. Ты можешь положить только наверх стопки, или взять сверху – всё.

Потом ты приходишь и говоришь – а мой односвязный список лучше, там можно ещё подложить «горшок» (Вы не скажете, где здесь туалет? Нашел время! Спасибо) под самый низ. Юзеры довольны, больше функционала – ведь лучше.. Или нет?

Но при этом вытащить нижний «горшок» уже нельзя, всё загрохочет и испортится! Потому что ты не можешь обратиться к предпоследнему элементу.

Итак, получился односвязный список с тремя методами: push, pop, (сверху), append (под низ), но без pop_back. И по-прежнему с доступом за O(N) ко всем элементами, кроме верхних и самого последнего. Ну хз. Если и существует практический кейс, где нужно именно такое API, то мне он в голову не пришёл. Вот.

ThePlayerZero    
★★
Linux / Chrome
Ответ на: комментарий от deep-purple

Чот отдельным минимальным примером не воспроизводится… Ну что ж, будем дебажить дальше. Память то может портить кто-то другой.

Чёт вспомнил один эпичный тред с лора со схожей завязкой

https://www.linux.org.ru/forum/development/11744063

приятного чтения

ThePlayerZero    
★★
Linux / Chrome
Ответ на: комментарий от ThePlayerZero

Посмотрел знакомых мне пятизвёздочников в той теме.. кого-то даже знаю лично в реале, с другими просто были хорошие обсуждения, узнавал что-то новое или наоборот..

monk ★★★★★

AIv ★★★★★

Iron_Bug ★★★★★

eao197 ★★★★★

AlexVR ★★★★★

tailgunner ★★★★★

(...)

Позову ли я их на LT? Сейчас точно нет, банально стыдно звать в пустой (перекати-поле.jpg) /Dev или в свино-гомосячий /Клуб ..

Такие дела 😔

ThePlayerZero    
★★
Последнее исправление: ThePlayerZero (всего исправлений: 1)

Linux / Chrome
Ответ на: комментарий от ThePlayerZero

Что такое односвязный список? Это стек, стопка. Ты можешь положить только наверх стопки, или взять сверху – всё.

Если и существует практический кейс, где нужно именно такое API, то мне он в голову не пришёл

То, о чём говоришь ты – FILO/LIFO.

То, что нужно мне (не XOYO):

  1. Быстрая вставка в конец, поэтому в «холдере» entries есть поле last.

  2. Быстрое вынимание из любого места, поэтому в entry есть поля prev и next.

  3. Пробежка в цикле по тем элементам, которые там есть на момент пробежки.

Тщем – это подписчики на событие.

deep-purple    
★★★★★★★★★★
Последнее исправление: deep-purple (всего исправлений: 1)

Android / Firefox
Ответ на: комментарий от TheAnonymous

Итак, получился односвязный список с тремя методами: push, pop, (сверху), append (под низ), но без pop_back. И по-прежнему с доступом за O(N) ко всем элементами, кроме верхних и самого последнего. Ну хз. Если и существует практический кейс, где нужно именно такое API, то мне он в голову не пришёл.

Очередь (FIFO)

Для фифо push не нужен, достаточно append и pop в этой терминологии

ThePlayerZero    
★★
Windows / Chrome
Ответ на: комментарий от deep-purple

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

Что с багом то? Минимал так и не удалось построить? Ты с санитайзерами пробовал собирать и запускать свой (весь) код?

ThePlayerZero    
★★
Windows / Chrome

мне тут valgrind какую-то дичь верещит.

Вывод валгринда можешь тоже запостить, емнип он там куда больше пишет чем просто

// valgrind: Invalid read of size 8

Хотя я с ним давно не сидел в обнимку, т.к. (более современные) санитайзеры лучше в большинстве случаев

у нас аж три используется на выбор

ThePlayerZero    
★★
Windows / Chrome
Ответ на: комментарий от ThePlayerZero

А причем здесь функции, в ОП вообще нет функций
Это к

А нафига тут поле last вообще, если с него нельзя пойти в обратном направлении? Список то односвязный

На односвязном списке с поддержкой вставки в конец можно сделать очередь

TheAnonymous    
★★★★★★★★★★
Linux / Firefox
Ответ на: комментарий от ThePlayerZero

Баг дал понять, что внутри entry-хендлера какой-то гандон портит указатель на сам entry. Ну и по классике, оказалось, что этот гандон – я. Исправлено.

deep-purple    
★★★★★★★★★★
Android / Firefox