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

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

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

    Восьмой размер ему не нравится, он же так и пишет. Для меня, если честно, тоже великоват.

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

      Шрехт мелковат? Ctrl++ должон бы помочь, но этот пидр всёравно про “размер 8” треплет. Ещё варианты есть?

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

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

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

    • 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

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

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

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

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

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

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

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

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

    // valgrind: Invalid read of size 8

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

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

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

      Не, он только говорил про инвалид реад.