В начале этой недели Google выпустила обновление Chrome OS 91.0.4472.165. Пользователи хромбуков после его установки столкнулись с проблемой входа в систему после перезагрузки. Они не могли зайти под своей учетной записью или система вообще не давала возможности для входа и уходила в перезагрузку.

Через двое суток разработчики Google выпустили исправление для стабильной версии Chrome OS под номером 91.0.4472.167.

Пользователи, которые после установки версии .165 не делали с хромбуком никаких действий, смогли получить новое обновление автоматически и даже не особо заметили проблему.

Часть пользователей, которые ранее все же установили версию .165 и перезагрузились или выключали устройство, оказались с нерабочим хромбуком. Они делились на форумах Reddit своими проблемами и попытками обновить якобы стабильную версию Chrome OS до рабочей. Основное решение, если нет доступа к возможности обновить Chrome OS даже через гостевой вход, сброс устройства к заводским настройкам или загрузка через ранее созданный USB-диск для восстановления. Причем в этом случае все данные пользователя при откате системы до рабочего состояния удаляются.

Пользователь Reddit обнаружил, что разработчики Google по какой-то причине в стабильной версии Chrome OS 91.0.4472.165 пропустили один амперсанд в коде функции проверки типа ключей пользователя при входе.

Вместо логического оператора "&&" в коде функции VaultKeyset стоял "&", что приводило к некорректной работе алгоритма входа пользователя в систему.

Вышеописанный баг прошел три ревизии при тестировании в канале разработчиков и был оставлен в стабильной версии Chrome OS. Причина, по которой это произошло, Google не раскрыла. Причем компания после жалоб пользователей сначала удалила сборку 91.0.4472.165 из своей матрицы обновлений, оставив там предыдущую стабильную версию Chrome OS 91.0.4472.147. С 22 июля Google выпустила необходимый патч в версии 91.0.4472.167.

Комментарии (30)


  1. DenimTornado
    24.07.2021 13:47

    капец, как такое могло пройти ревью..?


    1. cyber_ua
      24.07.2021 13:55
      +11

      вопрос в другом, через какое место они покрывают код тестами, что такое прошло


      1. staticmain
        24.07.2021 14:29
        +7

        image


      1. Kopilov
        24.07.2021 15:18
        +3

        Через выкат в продакшен. Пользователи тестируют на "сломается — не сломается"


        1. da411d
          25.07.2021 01:05
          +1

          Не должны. Эта методика запатентована Microsoft...


  1. avdx
    24.07.2021 14:03

    Не вижу, как эта ошибка могла на что то влиять. Поведение в обоих случаях должно быть одинаковым, если обе функции возвращают bool (на что указывает их название). Скорее просто исправили эту описку в процессе поиска реального бага.


    1. avdx
      24.07.2021 14:16
      +1

      А, там реально ошибка в том, что вторая функция вызовется в любом случае, даже если has_value() вернет false.


      1. fougasse
        24.07.2021 16:06
        +3

        при этом еще и порядок вызова функций неопределён и остаётся на совести оптимизатора, в отличие от оператора &&


      1. MyraJKee
        24.07.2021 21:37

        Человек пишет что не видит как эта ошибка могла на что-то повлиять, а не про сам факт ошибки.

        То есть для того чтобы попасть в тело if , в случае с логическим "и" необходимо чтобы обе функции возвращали true. В случае с битовой операцией так же необходимо чтобы обе функции возвращали true.

        То есть для пользователя по идее не должно быть разницы. Поэтому не совсем понятно на что жаловались пользователи.


        1. avdx
          24.07.2021 21:45

          Так это я сам на свой комментарий и ответил :)
          Тут ситуация аналогичная такой: допустим есть указатель ptr на какой то класс, у которо есть метод foo(), возвращающий bool. Если написать

          if ((ptr != nulptr) && ptr->foo())

          то все будет нормально, даже если ptr будет nullptr, а если написать
          if ((ptr != nullptr) & ptr->foo())

          то ptr->foo() вызовется в любом случае и все упадет.


          1. MyraJKee
            24.07.2021 21:53

            Да, ступил ) но почему упадет?

            Понятно что вторая функция в данном случае будет вызываться всегда, но это не значит что вызов приведет к исключению. Хотя тут надо код смотреть


          1. MyraJKee
            24.07.2021 21:55

            Либо я просто чего-то не знаю и если has_value() возвращает false, то label() например возвращает null


            1. avdx
              24.07.2021 21:59

              Ну выглядит так, что -> там перегруженный оператор, которые возвращает nullptr, если has_value() возвращает false. Т.е. key_data_ это что то типа какого то умного указателя, типа shared_ptr.


              1. MyraJKee
                24.07.2021 22:07

                Да, тогда понятно... Просто я встречал иногда у некоторых коллег использование побитовых "и", но это хотя бы на сколько помню не влияло на логику приложения в целом. Хоть и выглядело паршиво. А тут гугль понимаешь... Уровень все таки... И такая хрень.


  1. virtyaluk
    24.07.2021 18:12
    +2

    Почему не использовать плюсовый алиас and вместо &&? Тогда такие штуки можно будет поймать даже при просмотре глазами.


    1. DirectoriX
      24.07.2021 19:50
      +1

      Потому что неявно приводить bool к int (или к какому там целочисленному типу компилятор решит привести), а потом так же неявно обратно — дурной тон, особенно в C++.
      Что меня действительно напрягает — неужели у них нет никаких статических анализаторов, через которые код должен успешно пройти перед сборкой? Или у них настолько много подобных мест, что они не заметили в простыне предупреждений именно это?


      1. virtyaluk
        24.07.2021 20:17
        +4

        Не понимаю о чем вы. Судя по заметке один из программистов случайно написал вместо && просто &. Я предположил, что использование альтернативного токена в таком случае было бы намного приемлемее для отлова ошибок. Спецификация языка прямо говорит, что между && и and нет никакой разницы:

        In all respects of the language, each alternative token behaves exactly the same as its primary token…


  1. 1234rfvb
    24.07.2021 21:20
    -6

    Единичный амперсанд был единственным знаком, внесённым руками, автор принял его за простое and меж двух слов. Уровень подготовки прогеров налицо. Да, не обижайтесь. Вы работаете с тем, чего не понимаете. Потому что понять слой на слое на слое н е в о з м о ж н о. Это реалии, в которых мы живём и которыми вынуждены пользоваться. Капустный кочан, вот во что превратилось программирование со всеми этими фремворками. Любая обезьянка может создать "программу" или "сайт".


  1. symbix
    24.07.2021 22:12
    +5

    Странно, что статическим анализатором не поймали. Даже cppcheck на такое триггерится, предлагая скобки поставить, а уж всякие coverity тем более должны.


  1. Alexsey
    25.07.2021 03:41
    +6

    Есть подозрение что ревьювер, который это пропустил просто не сильно смотрел на код так как его отревьювили до него. А программист при мердже в релиз накосячил.

    Изначальный PR. В нем все нормально.

    PR который ушел в релиз. В нем амперсанд пропущен.


    1. v1000
      25.07.2021 09:12
      +2

      Вот так и появляются бэкдоры в программах.


    1. wataru
      25.07.2021 11:27

      Ага. Косяк был добавлен во втором патч-сете, вместе с какими-то фиксами. Похоже, были ошибки компиляции.


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


      А дальше — опечатка при фиксе и ревьювер, который решил второй раз "тот же самый" коммит не ревьювить.


  1. wyfinger
    25.07.2021 13:03
    +1

    Зачем вообще два отдельных оператора в C, разве тип операции нельзя понять из типов операндов?


    1. eandr_67
      25.07.2021 13:55

      У этих операций разная семантика. Упрощённо:

      & — Оба операнда вычисляются в произвольном порядке и интерпретируются как целые числа. Результатом является целое число — побитовое логическое умножение операндов.

      && — Сначала всегда вычисляется только первый операнд. Если его значение приводится к false, второй операнд не вычисляется и в качестве результата выражения возвращается false. Если значение первого операнда приводится к true, вычисляется второй операнд и в качестве значения выражения возвращается значение второго операнда, приведённое к bool.


      1. wyfinger
        25.07.2021 14:32

        Я говорил о том, что компилятор может проверить тип опнрандов и если они оба булевы использовать логическое И с частичным вычислением и все прочим.

        Если же оба операнда числовые - применять битовое И.

        Если типы разные или тип результата не соответствует операции кидаем исключение.

        Как это сделано в Pascal.

        Всегда бесили эти && и & когда приходилось что-нибудь писать на C.


        1. edo1h
          25.07.2021 15:03

          если они оба булевы использовать логическое И

          так так и будет, если оба булевы, то результат & и && одинаков.


          Всегда бесили эти && и & когда приходилось что-нибудь писать на C.

          на момент изобретения си возможность писать a && b вместо (a != 0) && (b != 0) казалось очень классной идеей.
          всё-таки с тех пор очень много лет прошло.


        1. eandr_67
          25.07.2021 15:25

          А зачем усложнять компилятор и ухудшать читабельность кода? То, что логическая операция с частичным выполнением и числовая битовая операция с полным выполнением обозначаются разными символами — совершенно правильное решение. Другое дело — слабая типизация C/C++, нивелирующая преимущества этого решения.

          В классическом Pascal есть только логический AND. То, что в современных реализациях AND можно применять к числам — уродливая самодеятельность «улучшателей» языка.


          1. wyfinger
            25.07.2021 15:51

            Не, не согласен, никогда в Pascal не было с этим затруднений.

            Наверное дело привычки.


  1. Mike-M
    25.07.2021 18:29

    Не знаток различных языков программирования, поэтому вопрос «первоклассника»:
    Как обстоят дела с возможностью допустить такую простую ошибку/опечатку (& vs &&) в других ЯП?


    1. eandr_67
      25.07.2021 23:25

      В Java, JavaScript, PHP замена && на & не вызовет ошибки — код выполнится.
      В Go замена && на & вызовет ошибку компиляции.