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

    +2

    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
    35. 35
    36. 36
    37. 37
    38. 38
    39. 39
    40. 40
    union bitdata {
        struct {
          unsigned int bit1 : 1;
          unsigned int bit2 : 1;
          unsigned int bit3 : 1;
          unsigned int bit4 : 1;
          unsigned int bit5 : 1;
          unsigned int bit6 : 1;
          unsigned int bit7 : 1;
          unsigned int bit8 : 1;
        };
        unsigned char byte;
      } first_byte, second_byte;
    
    <...>
    
    for ( j = 0; j < bytes_count; j++ ) {
          unsigned char t;
    
          ret = gzread( gz_fd, &t, sizeof( t ) );
          if ( ret != sizeof( t ) ) {
        printf( "Failed to read file %s: %s\n", argv[i], strerror( errno ) );
        gzclose( gz_fd );
        return EXIT_FAILURE;
          }
    
          first_byte.byte  = t;
          second_byte.byte = ready_bytes[j];
    
          first_byte.bit1 = first_byte.bit1 == 0 && second_byte.bit1 == 0 ? 0 : 1;
          first_byte.bit2 = first_byte.bit2 == 0 && second_byte.bit2 == 0 ? 0 : 1;
          first_byte.bit3 = first_byte.bit3 == 0 && second_byte.bit3 == 0 ? 0 : 1;
          first_byte.bit4 = first_byte.bit4 == 0 && second_byte.bit4 == 0 ? 0 : 1;
          first_byte.bit5 = first_byte.bit5 == 0 && second_byte.bit5 == 0 ? 0 : 1;
          first_byte.bit6 = first_byte.bit6 == 0 && second_byte.bit6 == 0 ? 0 : 1;
          first_byte.bit7 = first_byte.bit7 == 0 && second_byte.bit7 == 0 ? 0 : 1;
          first_byte.bit8 = first_byte.bit8 == 0 && second_byte.bit8 == 0 ? 0 : 1;
    
          ready_bytes[j] = first_byte.byte;
        }

    Всё еще не можем понять, зачем в конце тернарник. Всё остальное уже не смущает.

    Запостил: codemeow, 21 Января 2022

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

    • Для читаемости!

      Кто-то прогуливал мат логику.
      Ответить
    • Для инверсии. Де-Моргана не осилили.

      З.Ы. Тут же просто first_byte.byte |= second_byte.byte?
      Ответить
      • По моему тут еще проще можно, через "или равняеца"
        Ответить
        • Да тут вообще можно максимально просто: читать не по одному байту, выкинуть union, ИЛИ-шить сразу по 128-512 бит.
          Ответить
          • Судя по всему, тут или вообще нинужно. Можно сразу читать весь стрим в ready_bytes (если там изначально были нули).
            Ответить
            • Там выше цикл по разным файлам, который я опустил (
              Ответить
      • Почему? Тут же first_byte.byte = ~(first_byte.byte | second_byte.byte)
        Ответить
    • Интересно откуда такой код.

      С одной стороны на лабу не похоже.

      >return EXIT_FAILURE;
      > strerror( errno )
      И всё довольно вменяемо.

      С другой, нумерация bit1 с единицы и реализация побитовой илишни руками.
      Ответить
      • железячник писал может?
        Ответить
        • Нормальный железячник хорошо разбирается в битовой хуйне, и такой поебени писать не будет.
          Ответить
          • > хорошо разбирается в битовой хуйне

            А я вот битовые структуры вообще не умею юзать... Мне проще через & и | побитоёбить.
            Ответить
            • Я вот сходу не скажу, в каком порядке идут биты в битовых полях. Я не помню, что об этом говорит стандарт и может ли порядок различаться в разных компиляторах и на разных платформах.
              Ответить
              • Implementation defined, само собой... И направление раскладки и разрыв поля между единицами аллокации.

                Но в пределах одного ABI работать будет, конечно.
                Ответить
              • Пиздец там тонкий лёд, конечно... Стандарт возлагает ответственность на конпелятор, конпелятор на ABI, а в x86_64 ABI написана какая-то мутная хуйня, которая ничего не объясняет:

                - bit fields are allocated from right to left
                - bit-fields must be contained in a storage unit appropriate for its declared type
                - bit-fields may share a storage unit with other struct / union members
                Ответить
                • Что такое "appropriate"? Самый маленький storage unit, который вмещает тип? Или можно и больше?
                  Что такое "may share"? Т.е. при каких-то условиях могут и в разные юниты попасть?

                  Блядь, и это формальная спецификация?
                  struct foo1 { uint8_t a : 3; uint8_t b : 3; uint8_t c : 3; } // 00bbbaaa 00000ccc
                  struct foo2 { uint8_t a : 3; uint8_t b : 3; uint16_t c : 3; } // ccbbbaaa 0000000c
                  Т.е. 16-битный storage unit вполне так appropriate для 8-битного поля. Но только если рядом есть другие 16-битные поля, иначе он уже не особо appropriate (по крайней мере для gcc). Где блядь об этом написано?
                  Ответить
                • А вот ещё интереснее кейс:
                  struct foo1 {
                      uint8_t a : 3;
                      uint8_t b : 3;
                      uint8_t c : 3;
                      uint8_t d : 3;
                      uint16_t e : 3;
                  };
                  
                  // 00bbbaaa 00dddccc 00000eee 00000000
                  Т.е. теперь нет повода шарить storage unit между 8 и 16 битными полями и 16-битный storage unit уже не appropriate для 8-битного поля.
                  Ответить
                  • З.Ы. А вот с pragma pack(1) таки упаковывает до ccbbbaaa 0eeedddc...
                    Ответить
                    • То есть без pack(1) вообще не угадаешь, как компилятор разложит биты?

                      Значит, неупакованный вариант можно использовать только для временного хранения.
                      Ответить
                      • > вообще не угадаешь, как компилятор разложит биты

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

                        И получается что вменяемого, документированного ABI у сишки для x86_64 нет. Всё работает только за счёт того, что конпеляторы подстраиваются под своих старших собратьев.
                        Ответить
              • >Я вот сходу не скажу, в каком порядке идут биты в битовых полях.

                Помоему это заивисит от проца
                Ответить
                • если это big/little endianness, то это про порядок байт в более длинных словах
                  Ответить
                  • Нумерация битов тоже бывает, например, на процессорах x86 у инструкций BT/BTR/BTS/BTC/BSR/BSF, но о них редко вспоминают.
                    Ответить
                    • BTS вообще-то никто не забыл, вот они, слева направо:
                      Ответить
            • Кстати, тут ещё union используется в качестве reinterpret_cast. Так до сих пор делают, хотя стандарт то ли на сишку, то ли на кресты не рекомендует так делать. По стандарту union используется для экономии памяти, а нее для отображения типа на тип.

              Видимо, производители компиляторов поддерживают этот хак, иначе куча программ сломается.
              Ответить
              • Можно получать доступ к соответствующим полям структур в юнионах, если они имеют compatible types. Только я не могу найти что является цомпатибле тупес.
                Ответить
              • Вроде как в с99 это уже разрешили.

                Finally, one of the changes from C90 to C99 was to remove any restriction on accessing one member of a union when the last store was to a different one. The rationale was that the behaviour would then depend on the representations of the values. Since this point is often misunderstood, it might well be worth making it clear in the Standard.

                [...]

                To address the issue about "type punning", attach a new footnote 78a to the words "named member" in 6.5.2.3#3: 78a If the member used to access the contents of a union object is not the same as the member last used to store a value in the object, the appropriate part of the object representation of the value is reinterpreted as an object representation in the new type as described in 6.2.6 (a process sometimes called "type punning"). This might be a trap representation.
                Ответить
              • Нормально, выбора-то особо нет, так или через каст указателя.
                Ответить
                • Мемсру. Хотя это тоже каст в указатель на байты.
                  Ответить
                  • Есть нюанс: при вызове мемсру указываем, сколько байтов копировать, а при касте это решает компилятор.
                    Ответить
            • Вспомнил грязный хак в «Паскале»: там множества реализовали битовыми масками. Если тип объявлен как set of 0..7, то [0] представлено единицей, [1] представлено двойкой, [0, 1] представлено тройкой. Дизъюнкцию и конъюнкцию можно вычислять как объединение и пересечение множеств соответственно.
              Ответить
              • Почему грязный? Для небольших множеств это очень годная реализация, которая выебет и деревья и хешмапы. На больших уже от плотности зависит.
                Ответить
                • Реализация-то хорошая, сверхбыстрая. Только в ТП мощность множеств ограничили 256 элементами (в этом случае представление занимает 256 бит = 32 байта).

                  Я про возможный хак для использования таких множеств вместо битовых полей. Типа:
                  type T = set of 0..7;
                  var S: T; I: Integer;
                  begin
                  Move(I, S, 1);
                  S := S * [0, 1]; // экв. I := I and 3;
                  S := S - [1]; // экв. I := I and not 1;
                  S := S + [2]; // экв. I := I or 4;
                  Move(S, I, 1);
                  end;


                  Во Фрипаскаль добавили симметричную разность (><, экв. xor) и проверку на подмножество и надмножество (<= и >=).
                  Ответить
        • zlib в контроллерах как-то маловероятен.
          Ответить
          • Контроллер контроллеру рознь. Может быть, это роутер какой-нибудь.
            Ответить
            • Ну хер знает... SoC'и роутеров обычно не считают за микроконтроллеры.
              Ответить
              • SoC — это то, что раньше у нас называли «однокристальная ЭВМ». А микроконтроллерами обычно называют что-то попроще, типа контроллера флоппика, заточенного под определённую задачу.

                Так?
                Ответить
          • Почему нет? Злиб нетребовательный к пирфомансу и памяти.
            Ответить
            • Да нечего и некуда там особо декомпрессить... Памяти мало, флешки по сравнению с ней дофига.

              Хотя при желании можно запихать, конечно. Только это будет просто inflate без gzopen/gzread и прочего нинужного обвеса.
              Ответить
          • Писал железячник, но для системного сервиса на ПК.
            Ответить
    • поясните джависту

      каким образом в битах оказываются правильные значения?
      я вижу юнион, но внутри же у него int, почему каждый из них занимает ровно один бит, а не 32 или сколько там предусмотрено платформой?

      upd:

      unsigned int bit1 : 1;


      это указание длины что ли?
      так можно было?
      в пизду, будут джаваскриптером
      Ответить
      • Это не инт, а 1 бит. Сижка такая сижка...

        32 бита инт небось для выравнивания выбран.
        Ответить
      • Двоеточие используется для описания битовых полей. После двоеточия длина в битах, которую займёт это поле вместо длины, определённой типом.

        https://en.cppreference.com/w/c/language/bit_field
        Ответить
        • спасибо. мне и так последнее время хотелось кому-то взять и уебать, а теперь я кажется и вовсе вышел на апоапсис.
          Ответить
          • Битовые поля довольно редко встречаются в сишке. Чаще всего можно увидеть кустарный код со сдвигами и со страшными константами.
            Ответить
            • Потому что они похоже считались депрекейтед еще в свободные от бюрокрадов девяностые, вероятно изза вуте ордер
              Ответить
              • Потому что, как выше выяснил Борманд, проще набитоёбить, чем выяснять, во что конпилится эта хрень.
                Ответить
      • g: bit_field
        Ответить
      • > каким образом в битах оказываются правильные значения?
        Считай это сахарок над побитовыми оперециями, нопремер first_byte.bit2 = 1 скомпилица в first_byte.byte |= 0x02
        Ответить
        • я про элайнмент
          Ответить
          • > элайнмент

            Выравнивание storage unit'а для битовых полей соответствует тому типу, который попросили. В данном случае unsigned int. Т.е. эта структура, судя по всему, будет состоять из одного юнита на 4 байта из которых только 8 бит юзаются под битовые поля.
            Ответить
          • Хаотично-Нейтральный?
            Ответить
            • У крестоконпеляторов обычно Lawful-Evil, так и ждут когда оступишься и нарушишь Стандарт.
              Ответить
              • >т когда оступишься и нарушишь Стандарт.
                Чтобы первые пол года работать правильно, а потом выкинуть половину твоей программы в самый неожиданный момент
                Ответить
    • New Linux SUDO flaw lets local users gain root privileges
      Ответить
      • Никогда такого не было, и вот опять!
        У меня в контроллерах нет никакого понятия "root privileges", поэтому я за контроллеры.
        Ответить
      • Общее правило гласит: если хакер попал к тебе в шел (в смысле зашел под обычным юзером по ссш на юникс или по рдп на винду), то можешь сразу дать ему админские права на машину, потому что получение их лишь вопрос времени
        Ответить
        • Именно поэтому я рекомендую вписывать пароль от рута прямо в motd. Так хотя бы сам не забудешь.
          Ответить
      • И вообще это прошлогодняя новость
        https://www.bleepingcomputer.com/news/security/new-linux-sudo-flaw-lets-local-users-gain-root-privileges/

        хотя подобные дыры наверняка еще будут.
        Ответить

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