1. Си / Говнокод #23534

    −1

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    18. 18
    19. 19
    20. 20
    21. 21
    22. 22
    23. 23
    24. 24
    25. 25
    26. 26
    27. 27
    28. 28
    29. 29
    30. 30
    31. 31
    32. 32
    33. 33
    34. 34
    #include <stdio.h>
    #include <stdlib.h>
    
    int * ptr;
    
    int * getptr()
    {
      puts("getptr");
      return ptr;
    }
    
    int jump()
    {
      puts("jump");
      ptr = (int*)malloc(sizeof(int));
      return 1337;
    }
    
    int main()
    {
      ptr = (int*)malloc(sizeof(int));
      *ptr = 0;
    
      *( getptr() ) = 1;
      printf( "*ptr = %i\n\n", *ptr );
    
      *( getptr() ) = (jump(), 100);
      printf( "*ptr = %i\n\n", *ptr );
    
      *( getptr() ) = jump();
      printf( "*ptr = %i\n\n", *ptr );
    
      return 0;
    }

    ШИКАРНО:

    Start

    getptr
    *ptr = 1

    jump
    getptr
    *ptr = 100

    getptr
    jump
    *ptr = 0

    0

    Finish

    Запостил: bugspawn, 15 Ноября 2017

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

    • подсказка: сей фрагмент иллюстрирует волшебный порядок вычисления операндов в С/С++
      Ответить
      • Подсказка: нет никакого волшебного порядка, порядок вычисления зависит от компилятора, твой код содержит UB.
        Пример с 100 работает из-за наличия "точки следования" в виде оператора ,
        Ответить
        • тест №3:
          - частично вычисляется левая часть = (выполняется getptr())
          - вычисляется правая часть (выполняется jump())
          - продолжает вычисляться левая часть (выполняется *)
          не, ну это КАК ВООБЩЕ?
          т.е. есть оператор =, у него 2 операнда, и компилятор такой взял чучуть посчитал слева, потом чучуть справа, потом подумал решил снова влево посчитать

          тест №2:
          - вычисляется правая часть (выполняется jump() и ",")
          - вычисляется левая часть = (выполняется getptr() и потом *)
          каким таким боком "," внутри правого операнда влияет на то, когда в левом операнде будет посчитано значение в скобках (getptr()) - до или после вычисления правого операнда???
          Ответить
          • Ну посмотри асмовый листинг, и узнай почему копелятор так делает.
            Это же UB, он имеет право что угодно сделать. При включенной оптмизации компелятор вообще может выкинуть UB код: дескать можно вообще ничего не делать, раз UB.
            Ответить
            • > Это же UB, он имеет право что угодно сделать.

              правильнее: что бы разрешить компилерам делать что угодно (== агресивная оптимизация вызовов функций), стандарт оставляет это как UB.
              Ответить
              • Лолшто. Уб - это некорректный код, который в общем случае нельзя диагностировать при конпиляции, не более. Как висячий указатель разыменовать. Стандарт не вводит уб ради каких-то там оптимизаций. Просто конпиляторы оптимизируют в предположении, что программист не пишет некорректный код, не более.
                Ответить
                • > Уб - это некорректный код,

                  я не говорил про общий случай. я говорил про конкретный случай, проиллюстрированый в говнокоде.

                  стандарт может сделать корректным код сверху, но это преднамеренно не делается.
                  Ответить
                  • Да, почитал топик, ты все правильно сказал. Извини за выпад. Иногда хочется поумничать неразобравшись. Прости.
                    Ответить
                    • internal internet error. apology identified. undefined behavior detected. aborting.

                      WAS THIS PAGE HELPFUL? YES/NO. TELL US MORE. YOUR OPINION IS IMPORTANT TO US!
                      Ответить
                • в общем случае нет, а в частном случае иногда можно. Например, разыменовывание нулевого указателя - точно UB, к гадалке не ходи.
                  Ответить
          • Ты нуб штоли? Конпилятор переупорядочивает инструкции так, чтобы они выполнялись быстрее. Иди читать про точки следования в плюсах и конвеер в процессоре, нуб.
            Ответить
        • единственное объяснение что мне приходит в голову, это что сперва вычисляется то что в скобках с наибольшим уровнем вложенности по обе стороны от =, причем справа налево, потом от большего уровня вложенности к меньшему
          Ответить
          • Думаю, тем, кто пишет код с UB и винит компилятор в нелогичном поведении, лучше идти напитон. Там наверняка порядок вычисления присваиваний детерминирован. Специально для творческих личностей, желающих этим порядком воспользоваться.
            Ответить
            • Не только питон. Обычно в ЯПах под JVM и .NET тоже нет UB (ну, кроме race conditions). А в CPython и MRI Ruby нет и их:)

              В swift, я думаю, что тоже UB нет (во всяк случае ябловый UBSanitizer в шланге работает только для C)
              Ответить
              • В C# есть https://stackoverflow.com/a/1860953
                Но UB там возникает не на ровном месте, в отличии от плюсов и сишки
                Ответить
                • >>unsafe" block
                  ну так-то оно и в Java есть sun.misc.Unsafe

                  Даже в питоне можно взять cTypes и стригеррить черте-что

                  Мы же про "нормальное" использование языка.
                  Ответить
                  • Не, можно и без unsafe, например вот https://habrahabr.ru/company/enterra/blog/243371/ :

                    > Если кратко, то содержание поста сводится к рассмотрению следующего примера:
                    [Description(Value)]
                    class Test
                    {
                        const string Value = "X\ud800Y";
                    }


                    > Строка в C# представляет собой последовательность слов в UTF-16. А значение "X\ud800Y" не особо хорошее, т.к. включает в себя старшее слово суррогатной пары 0xD800, после которого должно бы идти младшее слово (интервал 0xDC00..0xDFFF), но вместо него идёт Y (0x0059). Проблемы начинаются из-за того, что в IL-коде для хранения аргументов конструктора атрибута используется UTF-8. Впрочем, у Джона Скита всё очень хорошо расписано, всем советую прочитать оригинальный пост.

                    > Меня заинтересовало, как же будут себя вести MS.NET и Mono в этой непростой ситуации (подробная заметка). А вести они себя будут по-разному. Первое различие можно увидеть во время компиляции. MS.NET положит значение строки в метаданные в виде 58 ED A0 80 59, а Mono — в виде 58 59 BF BD 00 (оба значения являются невалидными UTF-8 строчками). Второе различие можно пронаблюдать запустив полученные приложения. MS.NET сможет запустить обе версии и успешно достанет значение аргумента атрибута (в виде 0058 fffd fffd 0059 и 0058 0059 fffd fffd 0000 соответственно), а Mono поперхнётся настолько невалидной строкой и вернёт null в каждом из случаев. Из-за этого маленький пример Джона Скита сразу упал, когда я попытался запустить его под Mono.
                    Ответить
                    • в общем если хотите чтоб без UB - пишите на брайнфаке. Во всяких нетривиальных языках всегда можно какую-то ерунду не учесть, типа кодировок или вообще фиг пойми чего, из-за чего возникнет UB, не потому что специально хотели делать UB, просто никто о таком нестандартном сценарии не задумывался
                      Ответить
                    • Охренеть!! ТАкой литерал не должен был скомпилироваться!
                      Это дыра в стандарте
                      [quote]
                      According to the ECMA-334 document (p. 473):

                      A program that does not contain any occurrences of the unsafe modifier cannot exhibit any undefined behavior.
                      [/quote]

                      Но вообще мой cl четко видит тут три буквы: первая и последняя обычные, а средняя занимает 3 байта в UTF-8 (мне кажется это какой-то такой плейн где всякие asian languages, а нет, это невалидная хуйня (которую уникод обозначает значком [?]) )
                      class Program
                          {
                              const string Value = "X\ud800Y";
                      
                              static void Main(string[] args)
                              {            
                                  Console.WriteLine(String.Join(" ", Encoding.UTF8.GetBytes(Value).Select(b => b.ToString())));
                              }
                          }
                      // 88 239 191 189 89
                      // Тащемто попытка напечтать то и выводит: X[?]Y.
                      Ответить
              • # UB (ну, кроме race conditions)

                Это не UB
                Ответить
          • После игры "угадай что делает компелятор по эфектам от UB" вам предстоит уровень "возьми платформу с weak memory model типа ARM или PowerPC и угадай в каком порядке CPU выполнит твой код"
            Ответить
            • это поэтому на ведроидах все без исключения постоянно крэшится? :)
              Ответить
              • Откуда статистика?

                Ведроид бывает
                1) не только на arm (mips, atom)
                2) 90% софта там писано на java/kotlin под ART. А там действуют правила JMM и JLS.

                зы: ну ты понимаешь же что с weak memory model можно прекрасно жить, как и с любой другой memory model, главное не завязываться на странные спец-эффекты.
                Любой CPU всегда можно попросить не реордерить ничего (обычно с помощью интринсика или ключевого слова ЯПа, которое затем превращается в инструкцию типа fence или как-то так)
                Ответить
                • статистика по личным и очевидцев наблюдениям)
                  понятно что жить можно и любой подводный камень можно переступить
                  но должно же быть какоето объяснение феномену...
                  на вики пишут что косяки JMM с 2004 года недействительны
                  Ответить
                  • Я думаю что падения связаны с более низким уровнем review (у ябла он сильнее), а не с memory model ибо см. пункт 2.

                    У JMM нет UB кроме race conditions, но это не совсем UB так как не зависит от компилятора (а зависит от количества ядер, шедулера операционной системы, количества и тяжести других процессов, и месяца китайского календаря).

                    Объяснение очень простое: чем слабее гарантии -- тем больше свободы у инженеров в разработке проца, а значит тем лучше он у них может получиться.

                    Ты ведь наверное тоже не любишь делать свои интерфейсы и API публичными, что бы на них сразу же завязались 150 человек, и ты бы потом не мог их отрефакторить
                    Ответить
    • Автор, срочно переходи на PHP!
      Там всё, как тебе нравится: https://ideone.com/IY0KUp
      Ответить
      • Что такое $$ptr в данной программе?
        Ответить
        • Обращение к переменной с названием в переменной $ptr.
          Ответить
          • А переменные с названиями 0, 1 и 2 в "PHP" бывают?
            Ответить
            • В ПХП возможно всё, если делать это через жопу.
              Напрямую к ним обратиться нельзя - это синтаксически неверно. Но если использовать $$, то именем переменной может быть любая строка и, следовательно, что угодно, что в нее конвертится.
              https://ideone.com/svS2sO
              Ответить
              • Я догадывался... Но как объяснить непрограммистам, над чем я ржу?

                P.S. Это можно публиковать отдельным говнокодом.
                Ответить
      • Но в пыхе нет указателей, как же без них отстрелить себе ногу?
        Ответить
        • Когда я был пыховцем, у меня не было указателей чтобы отстрелить себе ногу, но мне хотелось ходить без ноги, как взрослые С++ программисты, и тогда я использовать SQL инъекции, глобальные переменные и eval()
          Ответить
    • Переходи на С++17
      Ответить

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