1. C++ / Говнокод #25564

    +4

    1. 1
    2. 2
    3. 3
    4. 4
    5. 5
    6. 6
    7. 7
    8. 8
    9. 9
    #include <iostream>
    #include <string>
    #include <string_view>
    
    int main() {
      std::string s = "Hellooooooooooooooo ";
      std::string_view sv = s + "World\n";
      std::cout << sv;
    }

    https://alexgaynor.net/2019/apr/21/modern-c++-wont-save-us/
    What's happening here is that s + "World\n" allocates a new std::string, and then is converted to a std::string_view. At this point the temporary std::string is freed, but sv still points at the memory that used to be owned by it. Any future use of sv is a use-after-free vulnerability. Oops! C++ lacks the facilities for the compiler to be aware that sv captures a reference to something where the reference lives longer than the referent. The same issue impacts std::span, also an extremely modern C++ type.

    Запостил: j123123, 24 Апреля 2019

    Комментарии (90) RSS

    • показать все, что скрытоvanished
      Ответить
    • показать все, что скрытоvanished
      Ответить
    • Для фикса добавят ещё десяток типов ссылок...
      Ответить
      • А вообще - это не какая-то новая проблема. Она всегда была для указателей, ссылок и итераторов. Если объект менялся или дох - они превращались в тыкву.

        Странно было бы, если бы string_view, который создан как быстрая обёртка над куском существующей строки, работал иначе.
        Ответить
        • > А вообще - это не какая-то новая проблема. Она всегда была для указателей, ссылок и итераторов. Если объект менялся или дох - они превращались в тыкву.

          Вот именно поэтому я за Си. Там ничего просто так не дохнет.
          #include <string.h>
          #include <stdio.h>
          #include <stdlib.h>
          
          int main()
          {
            const char a[] = "Hellooooooooooooooo ";
            const char b[] = "World\n";
            char *c = malloc(strlen(a)+strlen(b)+1);
            if(c == NULL) return EXIT_FAILURE;
            strcat(strcat(c,a), b);
            puts(c);
            free(c);
            return EXIT_SUCCESS;
          }
          Ответить
          • Вот только use-after-free у сишников почему-то встречается не реже.
            Ответить
            • Это у анскильных питухов встречается, а Цари помнят, когда они что освобождали.
              Ответить
            • показать все, что скрытоvanished
              Ответить
              • Вполне достаточно.

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

                Или я просто отупел после крестов, где я по каждой внешней функции читаю доку ровно один раз - чтобы сделать над ней RAII обёртку?
                Ответить
                • показать все, что скрытоvanished
                  Ответить
                  • > мемори футпринт под контролем
                    В крестах его держать под контролем ничуть не сложнее, имхо.

                    > пример треша
                    Да банально - в одной либе тебе возвращают хуйню, на которой ты должен LocalFree, во второй - просто free, в третьей - HuiPizdaFree. Где-то надо самому буфер подготовить (и позвать перед этим с нулём для оценки размера). Где-то тебе вернут указатель на кишки структуры который вообще удалять нельзя. Каждая либа вроде и консистентна, но в целом по проекту выходит каша.

                    Вот в том же openssl даже в пределах одной либы не всегда понятно надо ли освобождать поинтер. Благо в последних версиях они эту инфу в сигнатуру функций стали включать...

                    Вот здесь и спасают крестообёртки и крестосмартпоинтеры.
                    Ответить
                    • > Вот здесь и спасают крестообёртки и крестосмартпоинтеры.

                      Так и запишем - C++ это язык для подкостыливания сишечки.
                      Ответить
                      • Он же изначально с этой целью и создавался ;)
                        Ответить
                        • Ну то понятно, только вот его зачем-то пытаются сделать чем-то бОльшим, чем набор костылей к сишечке. Но из говна конфетку не сделаешь.
                          Ответить
                          • В общем кресты можно рассматривать даже не как самостоятельный язык, а как набор стандартизированных кривых сишных экстеншнов(которые к тому же в разных компиляторах реализованы часто не до конца, слегка по-разному и с кучей всяких багов, которые обходят всякими кривыми костылями во всяких там бустах), названный по ошибке новым языком. Впрочем, название "C++" на это явно намекает
                            Ответить
                      • Страуструп словно ортопед, который пытается выправить пациента.
                        Только аппарат Илизарова он не снимает уже очень долго, всё подкручивает к нему шурушки.
                        Ответить
                    • показать все, что скрытоvanished
                      Ответить
                    • показать все, что скрытоvanished
                      Ответить
                  • Особая боль - чтение асинхронного сишного кода. Сишник, который его писал, само собой учёл все 100500 ивентов по которым надо фришить структуры или их куски.

                    Блядь, как у вас хватает на это памяти и внимания!? И ещё остаётся на суть задачи...
                    Ответить
          • #include <string.h>
            #include <stdio.h>
            #include <stdlib.h>
            
            int main()
            {
              const char a[] = "Hellooooooooooooooo ";
              const char b[] = "World\n";
              char *c = malloc(strlen(a)+strlen(b)+1);
              if(c == NULL) return EXIT_FAILURE;
              c[0] = 0; // пофиксил
              strcat(strcat(c,a), b);
              puts(c);
              free(c);
              return EXIT_SUCCESS;
            }
            Ответить
            • @char *c = malloc(strlen(a)+strlen(b)+1);
              @if(c == NULL) return EXIT_FAILURE;

              А разве аллокатор молча не швыряет исключение?
              Хм. Погуглил. Инфы по CRT крайне мало, но я полагаю, что это обёртка над VirtualAlloc. Тогда тем более нужен обработчик, швыряющий исключение при неудачном вызове.
              Ответить
              • «new» — швыряет.
                «new (std::nothrow)» — не швыряет, возвращает «nullptr».
                «malloc»/«calloc» — не швыряют, возвращают «NULL».

                Ну и j123123 привёл пример на «C», в нём нет никаких «исключений», и именно поэтому я за.
                Ответить
                • показать все, что скрытоvanished
                  Ответить
                • То есть, как это нет? А try.. catch..throw?


                  procedure malloc(var P:Pointer; Size:DWORD);
                  begin
                  P:=Pointer(GlobalAlloc(GPTR, Size));
                  if P=nil then
                  raise ENotEnoughMemException.Create('Вы соснули с заглотом');
                  end;
                  Ответить
                  • показать все, что скрытоvanished
                    Ответить
                    • Спасибо, кэп, я знаю, что не си. Код только для примера.
                      Речь вообще-то идёт о try.. catch..throw
                      Ответить
                      • показать все, что скрытоvanished
                        Ответить
                        • Есть нестандартные расширения: в «MSVC» и в «Watcom C» есть __try...__except и __try...__finally. Работает только в «Windows», потому что гвоздями прибито к «SEH».
                          Ответить
                          • показать все, что скрытоvanished
                            Ответить
                            • setjmp/longjmp тут могут оказаться ни при чём.
                              Ответить
                              • Я настроил контрастность. см.

                                * * u n s k i l l * * u n s k i l l * * u n s k i l l * *
                                u                                                       u
                                n                   ▄▄▄▄██████▄▄  ▄█████▄▄▄             n
                                s                ████████████████▄███████████           s
                                k              █████████████████▌▐█████████████         k
                                i            ████████████████▀      ▀████████████       i
                                l           █████████████▀▀            ▀█████████▌      l
                                l          ████████▀▀                     ▀███████▌     l
                                *         ▐██████▌   -,___          ___,-  ▐█████▌      *
                                u        ▐██████▌    _____`-,    ,-'____    ▐█████▌     u
                                n        ▐█████▌    /     \        /    \   ▐█████▌     n
                                s        ▐█████▌   |    O  |   \  |   O  |  ▐█████▌     s
                                k       ▐██████▌    \_____/     \  \____/   ▐█████▌     k
                                i       ▐██████▌                 \          ▐█████▌     i
                                l      ▐███████▌                  \         ▐█████▌     l
                                l     ██████████▌              ---`         ▐██████▌    l
                                *    ▐████████████     `:---______---:`     ▐██████▌    *
                                u    ▐█████████████     `,| |  |  | |'     ▐███████▌    u
                                n   ▐███████████████      ``''''''''      ██████████▌   n
                                s   ▐██████████████████                █████████████▌   s
                                k  ▐█████████████████████------------████████████████▌  k
                                i  ▐█████████████████████▌          ▐████████████████▌  i
                                l ▐██████████████████████▌          ▐█████████████████▌ l
                                l ▐█████████████████████▌            ▐████████████████▌ l
                                * * u n s k i l l * * u n s k i l l * * u n s k i l l * *
                                Ответить
                                • * * u n s k i l l * * u n s k i l l * * u n s k i l l * *
                                  u                                                       u
                                  n                   ▄▄▄▄██████▄▄  ▄█████▄▄▄             n
                                  s                ████████████████▄███████████           s
                                  k              █████████████████▌▐█████████████         k
                                  i            ████████████████▀      ▀████████████       i
                                  l           █████████████▀▀            ▀█████████▌      l
                                  l          ████████▀▀                     ▀███████▌     l
                                  *         ▐██████▌   -,___          ___,-  ▐█████▌      *
                                  u        ▐██████▌    _____`-,    ,-'____    ▐█████▌     u
                                  n        ▐█████▌    /     \        /    \   ▐█████▌     n
                                  s        ▐█████▌   |    O  |   \  |   O  |  ▐█████▌     s
                                  k       ▐██████▌    \_____/     \  \____/   ▐█████▌     k
                                  i       ▐██████▌                 \          ▐█████▌     i
                                  l      ▐███████▌                  \         ▐█████▌     l
                                  l     ██████████▌              ---`         ▐██████▌    l
                                  *    ▐████████████     `:---______---:`     ▐██████▌    *
                                  u    ▐█████████████     `,| |  |  | |'     ▐███████▌    u
                                  n   ▐███████████████      ``''''''''      ██████████▌   n
                                  s   ▐██████████████████                █████████████▌   s
                                  k  ▐█████████████████████------------████████████████▌  k
                                  i  ▐█████████████████████▌          ▐████████████████▌  i
                                  l ▐██████████████████████▌          ▐█████████████████▌ l
                                  l ▐█████████████████████▌            ▐████████████████▌ l
                                  * * u n s k i l l * * u n s k i l l * * u n s k i l l * *
                                  Ответить
                                  • * * u n s k i l l * * u n s k i l l * * u n s k i l l * *
                                    u                                                       u
                                    n                   ▄▄▄▄██████▄▄  ▄█████▄▄▄             n
                                    s                ████████████████▄███████████           s
                                    k              █████████████████▌▐█████████████         k
                                    i            ████████████████▀      ▀████████████       i
                                    l           █████████████▀▀            ▀█████████▌      l
                                    l          ████████▀▀                     ▀███████▌     l
                                    *         ▐██████▌   -,___          ___,-  ▐█████▌      *
                                    u        ▐██████▌    _____`-,    ,-'____    ▐█████▌     u
                                    n        ▐█████▌    /     \        /    \   ▐█████▌     n
                                    s        ▐█████▌   |    O  |   \  |   O  |  ▐█████▌     s
                                    k       ▐██████▌    \_____/     \  \____/   ▐█████▌     k
                                    i       ▐██████▌                 \          ▐█████▌     i
                                    l      ▐███████▌                  \         ▐█████▌     l
                                    l     ██████████▌              ---`         ▐██████▌    l
                                    *    ▐████████████     `:---______---:`     ▐██████▌    *
                                    u    ▐█████████████     `,| |  |  | |'     ▐███████▌    u
                                    n   ▐███████████████      ``''''''''      ██████████▌   n
                                    s   ▐██████████████████                █████████████▌   s
                                    k  ▐█████████████████████------------████████████████▌  k
                                    i  ▐█████████████████████▌          ▐████████████████▌  i
                                    l ▐██████████████████████▌          ▐█████████████████▌ l
                                    l ▐█████████████████████▌            ▐████████████████▌ l
                                    * * u n s k i l l * * u n s k i l l * * u n s k i l l * *
                                    Ответить
                                    • * * u n s k i l l * * u n s k i l l * * u n s k i l l * *
                                      u                                                       u
                                      n                   ▄▄▄▄██████▄▄  ▄█████▄▄▄             n
                                      s                ████████████████▄███████████           s
                                      k              █████████████████▌▐█████████████         k
                                      i            ████████████████▀      ▀████████████       i
                                      l           █████████████▀▀            ▀█████████▌      l
                                      l          ████████▀▀                     ▀███████▌     l
                                      *         ▐██████▌   -,___          ___,-  ▐█████▌      *
                                      u        ▐██████▌    _____`-,    ,-'____    ▐█████▌     u
                                      n        ▐█████▌    /     \        /    \   ▐█████▌     n
                                      s        ▐█████▌   |    O  |   \  |   O  |  ▐█████▌     s
                                      k       ▐██████▌    \_____/     \  \____/   ▐█████▌     k
                                      i       ▐██████▌                 \          ▐█████▌     i
                                      l      ▐███████▌                  \         ▐█████▌     l
                                      l     ██████████▌              ---`         ▐██████▌    l
                                      *    ▐████████████     `:---______---:`     ▐██████▌    *
                                      u    ▐█████████████     `,| |  |  | |'     ▐███████▌    u
                                      n   ▐███████████████      ``''''''''      ██████████▌   n
                                      s   ▐██████████████████                █████████████▌   s
                                      k  ▐█████████████████████------------████████████████▌  k
                                      i  ▐█████████████████████▌          ▐████████████████▌  i
                                      l ▐██████████████████████▌          ▐█████████████████▌ l
                                      l ▐█████████████████████▌            ▐████████████████▌ l
                                      * * u n s k i l l * * u n s k i l l * * u n s k i l l * *
                                      Ответить
              • показать все, что скрытоvanished
                Ответить
              • malloc –— это не просто обёртка. Это может быть собственная куча CRT.

                CRT может при старте вызвать VirtualAlloc (или ещё какой-нибудь ...Alloc) с запасом, а потом вызывать не на каждый malloc, а по необходимости. Внутри куска, выделенного VirtualAlloc, CRT может вводить свою разметку.
                Ответить
                • P.S. Есть альтернативные реализации malloc: jemalloc, dmalloc, hoard, tcmalloc:
                  https://en.wikipedia.org/wiki/C_dynamic_memory_allocation#Implementati ons

                  Если бы функция malloc была тупой обёрткой, столько реализаций не появилось бы.
                  Ответить
                • Угу. В релизной конфигурации, к примеру, оно вызывает «HeapAlloc»:
                  // This function implements the logic of malloc().  It is called directly by the
                  // malloc() function in the Release CRT and is called by the debug heap in the
                  // Debug CRT.
                  //
                  // This function must be marked noinline, otherwise malloc and
                  // _malloc_base will have identical COMDATs, and the linker will fold
                  // them when calling one from the CRT. This is necessary because malloc
                  // needs to support users patching in custom implementations.
                  extern "C" __declspec(noinline) _CRTRESTRICT void* __cdecl _malloc_base(size_t const size)
                  {
                      // Ensure that the requested size is not too large:
                      _VALIDATE_RETURN_NOEXC(_HEAP_MAXREQ >= size, ENOMEM, nullptr);
                  
                      // Ensure we request an allocation of at least one byte:
                      size_t const actual_size = size == 0 ? 1 : size;
                  
                      for (;;)
                      {
                          void* const block = HeapAlloc(__acrt_heap, 0, actual_size);
                          if (block)
                              return block;
                  
                          // Otherwise, see if we need to call the new handler, and if so call it.
                          // If the new handler fails, just return nullptr:
                          if (_query_new_mode() == 0 || !_callnewh(actual_size))
                          {
                              errno = ENOMEM;
                              return nullptr;
                          }
                  
                          // The new handler was successful; try to allocate again...
                      }
                  }
                  Ответить
                  • А в дебаге через пару обёрток вызывается «heap_alloc_dbg»:
                    // Allocates a block of size bytes from the debug heap, using the new handler if
                    // it is configured for use with malloc.
                    static void* __cdecl heap_alloc_dbg(
                        size_t      const size,
                        int         const block_use,
                        char const* const file_name,
                        int         const line_number
                        ) throw()
                    {
                        bool const should_call_new_handler{_query_new_mode() != 0};
                        for (;;)
                        {
                            void* const block{heap_alloc_dbg_internal(size, block_use, file_name, line_number)};
                            if (block)
                                return block;
                    
                            if (!should_call_new_handler || !_callnewh(size))
                            {
                                errno_t* const global_errno{_errno()};
                                if (global_errno)
                                    *global_errno = ENOMEM;
                    
                                return nullptr;
                            }
                    
                            // The new handler was successful -- try to allocate again
                        }
                    }


                    А «heap_alloc_dbg_internal» оперирует двусвязным списком вот таких штруктур:
                    //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                    //
                    // Types
                    //
                    //-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
                    // For diagnostic purpose, blocks are allocated in the debug heap with extra
                    // information and stored in a doubly-linked list.  This makes all blocks
                    // registered with how big they are, when they were allocated, and what they are
                    // used for.
                    struct _CrtMemBlockHeader
                    {
                        _CrtMemBlockHeader* _block_header_next;
                        _CrtMemBlockHeader* _block_header_prev;
                        char const*         _file_name;
                        int                 _line_number;
                    
                        int                 _block_use;
                        size_t              _data_size;
                    
                        long                _request_number;
                        unsigned char       _gap[no_mans_land_size];
                    
                        // Followed by:
                        // unsigned char    _data[_data_size];
                        // unsigned char    _another_gap[no_mans_land_size];
                    };
                    Ответить
    • нашли до чего доклепаться
      Ответить
    • https://habr.com/ru/post/449368/ Нужно ли чистить строки в JavaScript?
      > Суть проблемы

      > В общем, оказывается, что строки содержат ссылки на родительские строки! Что??

      > Это вроде бы не сильно на что-то влияет, но только до тех пор, пока вы не захотите из огромной строки вырезать маленький кусочек и оставить себе, а большую строку удалить. Ведь она не удалится. Она останется в памяти, потому что на неё ссылается новая строка, которую вы где-то сохранили, поэтому сборщик мусора не хочет может освободить память.

      > Получается такая цепочка указателей:
      > какой-то массив или объект -> ваша новая маленькая строка -> старая большая строка
      > На самом деле всё ещё сложнее, у строки может быть несколько «родителей», но не будем усугублять.
      Ответить
      • Поэтому я за Си - там нет никакой неявной хуйни со строками, все четко и дерзко
        Ответить
      • О, очередные абсракции потекли.
        Ответить
        • Именно поэтому я против всяких говноязычков с GC и текущими абасракциями
          Ответить
        • Известная проблема. Рукожопы уже больше 8 лет не могут починить.

          > Issue 2869: Substring of huge string retains huge string in memory
          > Tue, Sep 3, 2013, 6:47 PM GMT+3

          > Status: Assigned (Open)
          Ответить
      • Можно научить сборщик мусора оценивать КПД ссылок на старые строки. Типа если строка весит метр, а нарезанные из неё куски весят джва - всё ок. А если выжила всего пара мелких фрагментов - можно их скопировать и ёбнуть оригинал.
        Ответить
        • На оценку нужны ресурсы процессора. GC же вроде и придумали для того, чтобы реже чистить.
          Ответить
          • GC придумали чтобы программистам не надо было думать об освобождении памяти.
            Ответить
            • Теперь программистам надо думать о том, чтобы GC начал думать об освобождением памяти
              Ответить
              • показать все, что скрытоvanished
                Ответить
                • Поэтому я за Brainfuck на бесконечной ленте. Там память бесконечна, и о ней можно не думать
                  Ответить
                  • Несколько лет назад была мода тупо выпиливать GC из этих ваших рантаймов. Типа, память ожидаемо кончается, и ваша stateless питушня периодически рестартуется. To же самое говорил и фельдмаршал Конрад фон Гетцендорф: "Die AWS Instanzen mussen so wie so krepieren"
                    Ответить
                • Боже! Кисонька, за что столько минусiв?
                  Ответить
              • Мне рассказывали, что в одной программе на «Йаже» пришлось в UI добавить кнопку «Вызвать System.gc()», иначе мусоросборщик сам не приходил.
                Ответить
                • > Мне рассказывали, что в одной программе на «Йаже» пришлось в UI добавить кнопку «Вызвать System.gc()»
                  Какой IntelliJ )))

                  https://intellij-support.jetbrains.com/hc/en-us/community/posts/206964525-why-does-idea-have-a-run-gc-button-
                  Ответить
          • Кадастровый протух
            Ответить
        • > Типа если строка весит метр, а нарезанные из неё куски весят джва - всё ок.
          > А если выжила всего пара мелких фрагментов - можно их скопировать и ёбнуть оригинал.

          Я кстати предлагал похожий вореант.

          Когда сборщик сталкивается с high memory pressure он должен начинать компактизировать строки, а не вываливаться с OOM.

          https://govnokod.ru/27616#comment664929
          Ответить

    Добавить комментарий