1. Java / Говнокод #24217

    +3

    1. 1
    http://www.ssw.uni-linz.ac.at/Research/Papers/Wuerthinger07/Wuerthinger07.pdf

    Как известно, в языках C и C++ есть проблема с buffer overflow, в то время как в языке Java такой проблемы нет (баги в реализации самой JVM не рассматриваем). В языке Java, как и в многих других подобных языках для анскиллябр заедушных, не могущих в сырые указатели, сделали проверки границ массива. В говноязыке C++ впрочем тоже есть какая-то такая питушня, например std::vector::at выполняет роверку выхода индекса за границы диапазона вектора. Только вот в язык JVM давно уже внедряют такую хреноту, как array bounds check elimination, т.е. убирание проверок, когда на этапе компиляции можно доказать, что такие проверки не нужны.

    В какой версии C++ сделают чтоб std::vector::at тоже вот так могло автозаменяться на небезопасный аналог если компилятор доказал что там эти проверки не нужны?

    Запостил: j123123, 03 Мая 2018

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

    • > В какой версии C++ сделают чтоб std::vector::at тоже вот так могло автозаменяться на небезопасный аналог если компилятор доказал что там эти проверки не нужны?
      думаю, это примерно начиная с версии "говно бронтозавра" https://godbolt.org/g/Kq4mJJ
      Ответить
      • https://godbolt.org/g/1vygk4 - не впечатлен
        Ответить
        • int bar(const std::vector<int> &in) {
              int sum = 0;
              sum += in.at(0);
              sum += in.at(1);
              sum += in.at(2);
              return sum;
          }


          bar(std::vector<int, std::allocator<int> > const&):
            sub rsp, 8
            mov rcx, QWORD PTR [rdi]
            mov rax, QWORD PTR [rdi+8]
            sub rax, rcx
            sar rax, 2
            je .L20
            mov edx, DWORD PTR [rcx]
            cmp rax, 1
            jbe .L21
            add edx, DWORD PTR [rcx+4]
            cmp rax, 2
            je .L22
            mov eax, DWORD PTR [rcx+8]
            add rsp, 8
            add eax, edx
            ret
          .L20:
            xor edx, edx
            xor esi, esi
            mov edi, OFFSET FLAT:.LC2
            xor eax, eax
            call std::__throw_out_of_range_fmt(char const*, ...)
          .L22:
            mov edx, 2
            mov esi, 2
            mov edi, OFFSET FLAT:.LC2
            xor eax, eax
            call std::__throw_out_of_range_fmt(char const*, ...)
          .L21:
            mov edx, 1
            mov esi, 1
            mov edi, OFFSET FLAT:.LC2
            xor eax, eax
            call std::__throw_out_of_range_fmt(char const*, ...)

          .L20, .L21, .L22 - метки, куда прыгаем если возникает эксепшен, и для каждого std::vector::at по проверке, хотя тут бы хватило одной проверки интервала
          Ответить
          • > __throw_out_of_range_fmt
            Ну здесь нельзя винить конпелятор — исключения то разные. Откуда ему знать, что "a[1] не найден" и "a[2] не найден" для тебя однохуйственны?
            Ответить
          • а ты что хотел? Компилятор же не знает размер входного вектора. https://godbolt.org/g/tnxiR1 - очень простой пример.
            Ответить
    • > доказал, что проверки там не нужны
      Дык давно выбрасывают. И даже простую арифметику над диапазонами умеют в этом доказательстве проделывать.

      Вот только работает эта хрень обычно только на знаковых интах (т.к. их переполнение не определено). А на беззнаковых конпелятор часто ссыт испортить логику и оставляет всё как есть.
      Ответить
      • З.Ы. Хотя код, который он ссыт оптимизировать, часто вообще под вопросом:

        sizeof(T)*i < buf_size

        Вдруг программист тут и правда хотел получить и обработать переполнение?
        Ответить
        • @Вдруг программист тут и правда хотел получить и обработать переполнение?

          Метод от противного?
          Ответить
      • > Дык давно выбрасывают. И даже простую арифметику над диапазонами умеют в этом доказательстве проделывать.

        А этот механизм реализован непосредственно в компиляторе, или это решается каким-то шаблонным и/или constexpr говном?

        http://www.ciselant.de/projects/gcc_printf/gcc_printf.html например оптимизации, связанные с использованием printf (всякие там замены printf на puts и putchar для частных случаев) реализованы в самом компиляторе, а не какой-то шаблоноеблей (которой в сишке просто нет)
        Ответить
        • В конпеляторе.

          Где-то мы же уже обсуждали наивную функцию вывода числа, где gcc выбросил все проверки (включая проверку на (digit < '0' || digit > '9') и вывел %&^#@^!* для числа Тараса.
          Ответить
          • Зуйню Герман ЦаЦаев выдал.
            ЗЫ. Где это?
            Ответить
          • Т.е. если я напишу какое-то свое говно, в котором можно проверять что-то на предмет выхода за границы, никакими C++ными костылями я подобное убирание проверок сделать не смогу, кроме как запатчить сам компилятор? Хуита
            Ответить
            • Конкретно проверка диапазонов в std'шном говне в конпелятор не зашита. Если конпелятор докажет, что твоё говно для проверки выхода за границу всегда true — он его тоже выбросит. Просто крестоконпеляторам далеко до полноценных доказательств. Пока у них получаются только простые вещи в духе x ∈ [0, 9] ⇒ x + '0' ∈ ['0', '9'] или x ≤ 5 ⇒ x * 2 ≤ 10.
              Ответить
            • З.Ы. Вон в соседнем треде даже простое доказательство по индукции провернуть не смог:
              if (x < 0)
                  x = -x;
              // теперь конпелятор знает, что x ≥ 0 (и вполне успешно юзает это в вычислении условий и выражений)
              
              while (x) {
                  if (x < 0)
                      return;
                  // тут можно было бы воспользоваться индукцией и убрать проверку:
                  // - мы знаем, что до входа в первую итерацию цикла x ≥ 0
                  // - мы знаем, что на выходе из каждой итерации цикла x ≥ 0 ⇒ x / 10 ≥ 0
                  // но gcc почему-то не может в такие рассуждения и оставляет её
                  x /= 10;
              }
              Ответить
    • Вы все лалки. Какого хрена вы считаете, что конпелятор должен за вас что-то оптимизировать? Конпеляторы нужны, чтобы с меньшими (чем на асме) усилиями получать рабочий код, пускай раздутый и медленный (по сравнению с асмом), но правильно работающий код, и более-менее переносимый. А если вам нужен супер-пупер быстрый, или муси-пуси маленький кот, то для этого нужно юзать ассемблер.

      ХУЙНЯЯ
      Ответить
      • Я называю вас питухами только потому, что вы: а) нихрена не понимание, не умеете и несёте херню. И это даже не самое страшное - вы нихрена не делаете выводов - вы думаете, что слиться и попитросянить - схавитить плюсов и свести разговор к ха-ха делает вам чести - но только по этому вы питухи. б) Вы слишком анскильны и не доросли ещё до уровня своей наглости. (с)
        Ответить

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