1. PHP / Говнокод #27104

    0

    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
    https://habr.com/ru/company/vk/blog/527420/
    
    ВКонтакте снова выкладывает KPHP 
    
    ....
    
    Сгенерировать С++ из PHP — этого мало. Собственно говоря, это самое простое.
    
    Во-первых, в PHP мы используем кучу функций стандартной библиотеки: header(),
     mb_strlen(), curl_init(), array_merge(). Их тысячи — и все должны быть
    реализованы внутри KPHP с учётом типизации и работать так же, как в PHP.
    Реализация всего PHP stdlib (а также KPHP-дополнений), всех PHP-типов с
    операциями и допущениями — это называется runtime, вон там квадратик сверху.
    
    Во-вторых, PHP-сайт — это веб-сервер. Следовательно, и в KPHP должна быть вся
    серверная часть, чтобы можно было в том же nginx подменить PHP-шный upstream
    на KPHP-шный — и всё продолжало работать так же. KPHP поднимает свой веб-сервер,
    оркестрирует процессы, заполняет суперглобалы и переинициализирует состояние,
    как и PHP… Это тоже хардкорная часть — называется server, квадратик снизу.
    
    И только имея результирующий код C++, написанные runtime и server, всё это можно
    объединить и отдать на откуп плюсовым компиляторам. Мы используем g++ — там в
    диаграмме есть квадратик g++. Но не совсем так: у vk.com настолько огромная
    кодовая база, что этот компилятор не справляется, и поэтому мы применяем патченный
    distcc для параллельной компиляции на множестве агентов. В итоге всё линкуется в
    один огромный бинарник (это весь vk.com), он раскидывается на кучу бэкендов и
    синхронно перезапускается. Каждая копия запускает мастер-процесс, который порождает
    группу однопоточных воркеров. Вот они на самом деле и исполняют исходный PHP-код.
    
    Многие технические проблемы остаются за кадром — их не опишешь в статье на Хабре.
    Чего стоит один только сбор трейсов при ошибках: ведь в С++ не получить
    человекочитаемый стек, а хочется разработчику вообще его на PHP-код намаппить.
    Гигантское количество внутренних нюансов, множество подпорок и легаси — но в итоге
    продукт хорошо работает и развивается.

    PHP и C++... два говна нашли друг друга

    Запостил: j123123, 11 Ноября 2020

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

    • https://github.com/VKCOM/kphp/blob/master/runtime/datetime.cpp#L42

      static inline int32_t is_leap(int32_t year) {
        return ((year % 4 == 0) ^ (year % 100 == 0) ^ (year % 400 == 0));
      }


      Надеюсь, это говно не понадобится человечеству в 2100 году. Тут еще операция xor, какая оптимизация )))
      Ответить
    • https://github.com/VKCOM/kphp/blob/master/runtime/datetime.cpp#L682

      if (s[0] == '-' || (s[0] == '+' || ('0' <= s[0] && s[0] <= '9'))) {
            int cnt;
            pos = -1;
            if (sscanf(s.c_str(), "%d%20s %n", &cnt, str, &pos) == 2 && pos != -1) {
              bool error = false;
              switch (str[0]) {
                case 'd':
                  if (str[1] == 'a' && str[2] == 'y' && ((str[3] == 's' && str[4] == 0) || str[3] == 0)) {
                    t.tm_mday += cnt;
                    break;
                  }
                  error = true;
                  break;
                case 'h':
                  if (str[1] == 'o' && str[2] == 'u' && str[3] == 'r' && ((str[4] == 's' && str[5] == 0) || str[4] == 0)) {
                    t.tm_hour += cnt;
                    break;
                  }
                  error = true;
                  break;
                case 'm':
                  if (str[1] == 'o' && str[2] == 'n' && str[3] == 't' && str[4] == 'h' && ((str[5] == 's' && str[6] == 0) || str[5] == 0)) {
                    t.tm_mon += cnt;
                    break;
                  }
                  if (str[1] == 'i' && str[2] == 'n' && str[3] == 'u' && str[4] == 't' && str[5] == 'e' && ((str[6] == 's' && str[7] == 0) || str[6] == 0)) {
                    t.tm_min += cnt;
                    break;
                  }
                  error = true;
                  break;
                case 'w':
                  if (str[1] == 'e' && str[2] == 'e' && str[3] == 'k' && ((str[4] == 's' && str[5] == 0) || str[4] == 0)) {
                    t.tm_mday += cnt * 7;
                    if (!strncmp(s.c_str() + pos, "1 day", 5)) {
                      t.tm_mday += (s[0] == '+' ? 1 : -1);
                      pos += 5;
                      while (s[pos] == ' ') {
                        pos++;
                      }
                    }
                    break;
                  }
                  error = true;
                  break;


      ухх бля, вот сразу видно, чувствуется рука вконтактовского олимпиадника
      Ответить
      • Ну напиши сам эту функцию и выложи её сюда. Посмотрим, потечём.
        Ответить
    • > if (str[1] == 'o' && str[2] == 'n' && str[3] == 't' && str[4] == 'h' && ((str[5] == 's' && str[6] == 0) || str[5] == 0))

      никогда не берите на работу олимпиадников и пыхеров

      Кстати, надо бы Ротоёбу присоветовать ВК в качестве работы: он примерно в таком же стиле пишет, правда на пхп, но там и пхп такой же ведь
      Ответить
      • эт че получается, вконтакшле не на пхп написан?
        Ответить
        • там бекенд с алгоритмами на сишке, веб морда на пыхе, а потом они стали пых в сишку компилировать (по аналогии с фейсбуком)
          Ответить
        • Сам вконтакт написан-таки не совсем на пхп, а на особом подмножестве пхп, который через вот эту ебаную срань как-то компилируется в C++ и запускается. Подробности см. на хабре.
          Ответить
    • https://github.com/VKCOM/kphp/blob/04819c075f5599582f4f8780775f26a6377ca05d/runtime/string_functions.cpp#L375


      string f$html_entity_decode(const string &str, int64_t flags, const string &encoding) {
        if (flags >= 3) {
          php_critical_error ("unsupported parameter flags = %ld in function html_entity_decode", flags);
        }
      
        bool utf8 = memchr(encoding.c_str(), '8', encoding.size()) != nullptr;
        if (!utf8 && strstr(encoding.c_str(), "1251") == nullptr) {
          php_critical_error ("unsupported encoding \"%s\" in function html_entity_decode", encoding.c_str());
          return str;
        }
      
        int len = str.size();
        string res(len * 7 / 4 + 4, false);
        char *p = &res[0];
        for (int i = 0; i < len; i++) {
          if (str[i] == '&') {
            int j = i + 1;
            while (j < len && str[j] != ';') {
              j++;
            }
            if (j < len) {
              if ((flags & ENT_QUOTES) && j == i + 5) {
                if (str[i + 1] == '#' && str[i + 2] == '0' && str[i + 3] == '3' && str[i + 4] == '9') {
                  i += 5;
                  *p++ = '\'';
                  continue;
                }
              }
              if (!(flags & ENT_NOQUOTES) && j == i + 5) {
                if (str[i + 1] == 'q' && str[i + 2] == 'u' && str[i + 3] == 'o' && str[i + 4] == 't') {
                  i += 5;
                  *p++ = '\"';
                  continue;
                }
              }
      
              int l = 0, r = entities_size;
              while (l + 1 < r) {
                int m = (l + r) >> 1;
                if (strncmp(str.c_str() + i + 1, ent_to_num_s[m], j - i - 1) < 0) {
                  r = m;
                } else {
                  l = m;
                }
              }
              if (strncmp(str.c_str() + i + 1, ent_to_num_s[l], j - i - 1) == 0) {
                int num = ent_to_num_i[l];
                i = j;
                if (utf8) {
                  if (num < 128) {
                    *p++ = (char)num;
                  } else if (num < 0x800) {
                    *p++ = (char)(0xc0 + (num >> 6));
                    *p++ = (char)(0x80 + (num & 63));
      ...

      Не, ну что это за пиздец?
      Ответить
      • почти что число кармака по крутости, лол

        Причм мне нравится, как ловко смешана весьма "высокоуровневая" крестушня типа std::string и
        *p++ = (char)(0xc0 + (num >> 6));
        *p++ = (char)(0x80 + (num & 63));
        Ответить
        • > utf8

          Настоящий олимпиадник инлайнит функции сам, не доверяя это конпелятору.
          Ответить
      • Блядь, они серьёзно детектят utf8 по наличию цифры 8 в названии кодировки?

        За каким хуем это вообще строка, если там джва допустимых значения. А ещё этот код вызывается на каждую энтитю, заебись для пирфоманса.
        Ответить
        • З.Ы. А нет, не на каждую. Ну про 8 всё равно пиздец.
          Ответить
          • Ну там заебешься все кобенации перебирать:
            UTF8
            utf8
            UTF-8
            utf-8
            Utf-8
            и так далее

            Проще на восьмерку проверить.
            Ответить
            • Ну тогда так: int is_utf8 = enc[enc.size() - 1] == '8'. И быстрее и точнее чем их говно.
              Ответить
              • Это уже на сениора тянет.
                Ответить
                • Оно на пустой строке правда крашится, ну да ладно.
                  Ответить
                  • Не крашнется. Передавать пустую строку ведь никто не будет...
                    Ответить
              • Можно даже так: int is_utf8 = enc[4] == '8'

                Если судить из документации соотв. функции в "PHP", для UTF-8 кодировки корректно только "UTF-8" в качестве параметра
                А вот у "cp1251" есть псевдонимы "Windows-1251", "win-1251", "1251". Т.е. достаточно просто проверять четвертый символ на восьмерку
                Ответить
                • Длину ещё нужно проверить.
                  Ответить
                  • Тогда можно и на основе длины решить. Если длина равна 5 то тогда это "UTF-8", иначе это "cp1251". Ни один из синонимов "cp1251" не имеет длину 5
                    Ответить
                • Ну да, у koi8-r и cp866 восьмёрки в другой позиции. А остальные кодировки в русском проекте маловероятны.
                  Ответить
                • switch (strchr(s, '8') - s) {
                  case 2: // cp866
                  case 3: // koi8-r
                  case 4: // utf-8
                  default: // cp1251
                  }
                  Ответить
        • > Блядь, они серьёзно детектят utf8 по наличию цифры 8 в названии кодировки?

          Ну видимо их аналог пхп-шной функции html_entity_decode https://www.php.net/manual/ru/function.html-entity-decode.php поддерживает только "UTF-8" и "CP1251". Большего им не надо.
          Ответить
          • Ну и нахуй тогда проверять на 1251 в следующей строке? И так же понятно, что раз восьмёрки нет - то 1251. А на koi8-r и cp866 всё равно глючит и не возвращает ошибку.
            Ответить
            • Отличная оптимизация. Ждем вас в команду вконтакта!
              Ответить
              • Я там выше оптимизнул лучше. Последний символ на 8 проверить. Такое вроде только в утф.
                Ответить
      • Ого, даже бинарный поиск есть встроенный.
        Ответить
    • > ВКонтакте снова выкладывает KPHP

      обиделись что в прошлый раз никто не заметил?

      > KPHP берёт PHP-код и превращает его в С++

      ребят, тайпскрипт не так работает
      Ответить
      • > обиделись что в прошлый раз никто не заметил?

        Почему никто? Я заметил. На говнокод даже отправлял куски кода оттуда
        Ответить
        • Обиделись что заметили
          Ответить
          • Да оно просто нинужно за пределами ВК.

            Судя по статье, 99% существующего кода там тупо не взлетит т.к. все динамические фишки не поддерживаются. Не заюзать привычные экстеншены для СУБД, не запустить привычные фреймворки и ORM'ы.

            Т.е. нельзя взять и портировать свои PHP'шные наработки на K-PHP. Код нужно снуля разрабатывать специально под эту платформу.

            З.Ы. Хотя код Ротоёба, наверное, взлетит. Если поддержку mysql самостоятельно привернуть.
            Ответить
            • > привычные экстеншены для СУБД

              mysql_real_escape_string()
              Ответить
    • > мы тестируем на PHP а KPHP - для продакшена

      Заебись наверное отлаживать ситуации, когда в обычном пхп всё работает а на кпхп крашится.
      Ответить
      • Это уже забота отдела разработки кпхп.
        Ответить
      • это ж какой багор, когда твой код даже пхп нормально выполняет, а твоя поделка не может )))
        Ответить
    • vanished
      Ответить

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