Я пока не могу – мне тут 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
}

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

  • deep-purpleOP
    link
    fedilink
    arrow-up
    0
    ·
    3 years ago

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

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

    • ThePlayerZero
      link
      fedilink
      arrow-up
      0
      ·
      3 years ago

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

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

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

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

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

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

      • deep-purpleOP
        link
        fedilink
        arrow-up
        0
        ·
        3 years ago

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

        • ThePlayerZero
          link
          fedilink
          arrow-up
          0
          ·
          3 years ago

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

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

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

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

          • ThePlayerZero
            link
            fedilink
            arrow-up
            0
            ·
            3 years ago

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

            monk ★★★★★
            
            AIv ★★★★★
            
            Iron_Bug ★★★★★
            
            eao197 ★★★★★
            
            AlexVR ★★★★★
            
            tailgunner ★★★★★
            
            (...)
            

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

            Такие дела 😔

      • deep-purpleOP
        link
        fedilink
        arrow-up
        0
        ·
        3 years ago

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

        
        
        #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;
        }
        
        
        
        • ThePlayerZero
          link
          fedilink
          arrow-up
          0
          ·
          3 years ago

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

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

          $ 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
          

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

          🗿

      • deep-purpleOP
        link
        fedilink
        arrow-up
        0
        ·
        3 years ago

        мне всё равно не нравится

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

        • ThePlayerZero
          link
          fedilink
          arrow-up
          0
          ·
          3 years ago

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

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

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

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

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

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

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

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

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

          • deep-purpleOP
            link
            fedilink
            arrow-up
            0
            ·
            edit-2
            3 years ago

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

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

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

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

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

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

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

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

            • ThePlayerZero
              link
              fedilink
              arrow-up
              0
              ·
              3 years ago

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

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

              • deep-purpleOP
                link
                fedilink
                arrow-up
                0
                ·
                3 years ago

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

          • TheAnonymous
            link
            fedilink
            arrow-up
            0
            ·
            3 years ago

            «где нужно именно такое API» Очередь (FIFO)

            • ThePlayerZero
              link
              fedilink
              arrow-up
              0
              ·
              3 years ago

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

              Очередь (FIFO)

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

              • TheAnonymous
                link
                fedilink
                arrow-up
                0
                ·
                3 years ago

                push не нужен, но голова и хвост нужны

                • ThePlayerZero
                  link
                  fedilink
                  arrow-up
                  0
                  ·
                  3 years ago

                  Ну так добавление в хвост и удаление с головы это и есть два метода (функции), а не три

                  • TheAnonymous
                    link
                    fedilink
                    arrow-up
                    0
                    ·
                    3 years ago

                    А причем здесь функции, в ОП вообще нет функций Это к «А нафига тут поле last вообще, если с него нельзя пойти в обратном направлении? Список то односвязный» На односвязном списке с поддержкой вставки в конец можно сделать очередь