Пользователь
250,2
рейтинг
22 февраля 2014 в 18:48

Разработка → Адам Лэнгли объяснил причины бага в iOS: лишняя строчка кода поломала всю безопасность

Вчера компания Apple выпустила обновление безопасности iOS 7.0.6 для iPhone 4 и более поздних моделей, iPod touch 5-го поколения и iPad 2+. Одновременно выпущен аналогичный патч 6.1.6 для iPhone 3GS и iPod touch 4-го поколения.

Обновление закрывает уязвимость CVE-2014-1266, которая позволяет злоумышленнику из «привилегированной позиции в сети» перехватывать и модифицировать пакеты в сессиях, защищённых SSL/TLS. Речь идёт о MiTM-атаке с подменой трафика.

В лаконичном пояснении Apple говорит, что при установке защищённого соединения по SSL/TLS система не способна определить аутентичность соединения. Проблему решили путём «добавления недостающих этапов валидации».

Хотя по лаконичному описанию не совсем понятно, каких конкретно «этапов» не хватало, но можно говорить об отсутствии полноценной защиты соединений. Так или иначе, но отсутствие необходимых этапов аутентификации означает, что раньше на все устройства Apple третьи лица, вероятно, могли устанавливать поддельные/модифицированные апдейты ОС на смартфоны и планшеты пользователей.

Сегодня известный криптограф Адам Лэнгли опубликовал статью с анализом бага в iOS. Он обращает внимание на разницу в коде OS X 10.8.5 (Security-55179.13) и 10.9 (Security-55471), где, вероятно, исправлен тот же самый баг.

Собственно, вот он.

static OSStatus
SSLVerifySignedServerKeyExchange(SSLContext *ctx, bool isRsa, SSLBuffer signedParams,
                                 uint8_t *signature, UInt16 signatureLen)
{
	OSStatus        err;
	...

	if ((err = SSLHashSHA1.update(&hashCtx, &serverRandom)) != 0)
		goto fail;
	if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
		goto fail;
		goto fail;
	if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0)
		goto fail;
	... 

fail:
	SSLFreeBuffer(&signedHashes);
	SSLFreeBuffer(&hashCtx);
	return err;
}

Процитировано с опубликованных исходников Apple.

Обратите внимание на две строки goto fail подряд. Первая из них корректно связывается с оператором if, а вторая вообще не имеет никакого отношения к делу. В результате, выполнение программы всегда завершается на этом этапе, со второго goto fail. Значение err содержит правильное значение, потому что операция обновления SHA1 была успешной и верификация подписи всегда даёт «добро».

Речь идёт о проверке подписи в сообщении ServerKeyExchange, что используется в шифрах DHE и ECDHE для передачи одноразового ключа соединения. Сервер говорит: «Вот одноразовый ключ, а вот подпись от моего сертификата, так что ты знаешь, что ключ от меня». В случае с Apple, если связь между одноразовым ключом и сертификатом сломана, то вся система разваливается. Теперь вообще ничего не работает: можно отправить клиенту правильный сертификат, но подписать рукопожатие произвольным секретным ключом, или вообще его не подписывать! Отсутствуют любые доказательства, что сервер, который присылает сертификат, вообще владеет секретным ключом для этого сертификата.

Уязвимость, вероятно, присутствует во всех версиях iOS до 7.0.5 и в OS X до 10.9.1 включительно.
Анатолий Ализар @alizar
карма
739,5
рейтинг 250,2
Пользователь
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

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

  • +141
    Классический пример. Называется, ставьте фигурные скобки и не увлекайтесь goto.

    Кроме того, слово fail в коде переводить не стоило, это метка.


    Оригинал:
    • +53
      > Кроме того, слово fail в коде переводить не стоило, это метка.
      Да уж, облом так облом :)
    • +13
      Нет, называется бекдор :)
      Фигурные скобки и goto тут ни при чём. Во-первых, всё это вообще надо было писать по-другому, во-вторых, достаточно было бы просто взглянуть на код и увидеть, что два goto — это какая-то хрень. Установление фигурных скобочек бы не помогло, потому что очевидно, что в код просто не смотрели (специально).

      Бекдоры и должны быть похожи на опечатки. Вспомните про баг в ядре линукса.
      • +4
        Не обязательно объяснять злым умыслом то, что может быть сделано по глупости. Например, в этой же функции есть signedHashes, который освобождается в конце, но нигде не используется (signedHashes.data = 0 не считаем).
        • +11
          Я не сторонник теорий заговоров, однако сходу не могу придумать сценарий, при котором в диффе в середине давно написанного кода появляется одинокая неверная строчка:

          Большая часть изменений — банальный однообразный рефакторинг, а эта строка явно выделяется и бросается в глаза.

          А с signedHashes ситуация вполне типичная: структура данных когда-то использовалась, но однажды логику переписали без неё, а инициализацию и освобождение убрать забыли. Это относительно часто встречается.
          • 0
            Результат операции rebase?..
            • +3
              Вы меня прям заинтриговали. Я про опасности rebase аж 2 статьи писал, однако в этом случае не могу придумать, каким образом он может быть виноват. Всё равно ведь в каком-то коммите эту строку надо было написать поверх древнего кода.
              • 0
                Сначала строчку ошибочно стерли, потом дописали обратно. Первый коммит при интерактивном rebase был пропущен…
                • +3
                  Будет конфликт. Т.к. в коммите будет «вставить goto между двумя строчками if», а там уже один goto находится.
                  • +2
                    Конфликта не будет, если строки идентичные, как в данном случае, просто смержится автоматически.
                    • 0
                      Попробуйте воспроизвести. Уверен, что не получится.
                    • +1
                      Я попробовал сам. Оказалось, что гит ведёт себя несколько умнее. Он определяет, что данная строка уже была добавлена, и удаляет её из накладываемого патча, применяя остальные изменения из коммита.

                      git clone https://gist.github.com/9168347.git
                      cd 9168347
                      git checkout -b rebase
                      git rebase -i 9d4ebb
                      

                      pick 4e8b496 Some commit
                      #pick 142d7bf Removed goto
                      pick f2871e8 Returned goto
                      

                      Successfully rebased and updated refs/heads/rebase.
                      

                      В результате оригинальный коммит
                      @@ -1,6 +1,8 @@
                       if ((err = SSLHashSHA1.update(&hashCtx, &serverRandom)) != 0)
                           goto fail;
                       if ((err = SSLHashSHA1.update(&hashCtx, &signedParams)) != 0)
                      +    goto fail;
                       if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0)
                           goto fail;
                       
                      +
                      

                      гит переделал в:
                      @@ -5,3 +5,4 @@
                       if ((err = SSLHashSHA1.final(&hashCtx, &hashOut)) != 0)
                           goto fail;
                       
                      +
                      


                      Судя по всему, Вы именно это и имели в виду. :)
                      • +1
                        Агу, именно это имел ввиду :)
              • +1
                Появление дублирующихся строк при автоматическом merge в git'е я наблюдал на практике несколько раз. Конкретную причину не знаю, сильно не разбирался — просто исправлял. Возможно, связано с одним и тем же коммитом в нескольких ветках (исправление ошибки в разных версиях), которые потом залили в master.
                • 0
                  Рискну предположить, что строки отличались символами окончания строки (\r\n против \n). Бывает, если не прописать настройки в вин-клиенте. В результате строки вроде бы идентичные, но не совсем, и поэтому не мержатся в одну.
          • 0
            А Сноуден знал… )
          • 0
            У меня был забавный случай с CVS. Я добавил в структуру новых полей, а коллкга в это же время переименовал старые. CVS это смержил так, что в структуре появились и переименованные, и сохранились старые поля. Компилятор это прекрасно съел, и я несколько часов разбирался, почему все перестало работать.
      • +14
        Теория заговора тем и хороша, что ею можно объяснить, пожалуй, что угодно.
        У вас, поди, и шапочка из фольги есть ;)
        • +5
          Не помогает!!! Кастрюлька лучше и роднее :)
      • +11
        О, да я теперь начальству за все свои косяки в программировании могу отмазаться — это не баг, это секретный бекдор.
      • 0
        Умерьте фантазию, бэкдор пускает не любого, а только того, кого надо.
        • +15
          «Кто надо» — это не секретный элитный клуб, а всего лишь тот, кто знает об этом бекдоре.
    • +1
      Когда участвовал в разработке кода для ядра FreeBSD приходилось соответствовать coding style, который запрещал фигурные скобки в однострочных if и for. И это вызывало ошибки даже у опытных программистов. Я так и не смог убедить руководство изменить coding style.
      В родном коде ядра встречались перлы — if, потом 5 строк комментариев, котом один оператор. Читать сложновато, но весело.
  • +78
    Оставлю для истории. Ну как можно взять — и перевести часть исходника?

    • +2
      Ага, я выше уже выложил =)
      • –2
        И? Что значит сей минус?

        Комментарий редактируется, как максимум, в течении трех минут после опубликования. Т. е. я и mayorovp выложили картинки почти одновременно (я лишь на минуту раньше). До редактирования в моем комментарии не было только картинок, но я решил добавить, т. к. после изменения поста многим будет неясно про что речь.
        • +3
          Возможно, человек, поставивший вам минус (это был не я), намекнул, что я и сам должен был увидеть ваш комментарий. Хотя бы потому что в момент публикации комментарии обновляются. А уж сторонний читатель никоим образом не сможет увидеть мой комментарий перед вашим. Таким образом, фраза «я выше уже выложил» не несет никакой информации и лишь сообщает всем очевидную вещь.
          • 0
            Вероятно. Как ни делай, параметр-который-нельзя-называть сливают в таких холиварных темах.
            • –1
              Да ладно вам, чего вы переживаете из-за одного минуса? Во многих случаях это не более, чем стат. погрешность. Возьмите недавний топик «Как айтишник по магазинам ходил» — к 769(!) плюсам нашлось 45 минусов. Не переживать же из-за каждого из них, так можно и все нервы пропереживать ;)
              • 0
                Из-за минусов обычно не переживают, а недоумевают.
                Иногда просто очень непонятна реакция. Есть пара сливов, приблизится к пониманию причин которых мне так и не удалось.
    • +26
      Однозначно угадывается автор поста.
      • –1
        if (author.equals(Alizar)) {
        идина расходимся;
        }
        • +2
          > The name `Alizar' does not exist in the current context
          • –2
            does not exist, но минусует коммент. Воин тьмы :)
    • +28
      Надо было тогда переводить полностью:
      goto облом;
      • +22
        идина облом ;)
      • –5
        иди в <...>;
        
      • +8
        Из goto облом; выйдет отличный новый мем :-)
    • +1
      Я на минуту где-то завис, пытаясь понять, что это еще за облом :)
  • +19
    <parainod>Похоже на бэкдор, замаскированный под опечатку.</paranoid>
  • –7
    Вот поэтому напрягает стремление к излишне «лаконичным» синтаксисам в новомодных ЯП (всяких Ruby, Scala и т.п.). Хотя некоторые отличились в этом плане и раньше (тот же TCL в котором и условие и «тело» берутся в одинаковые фигурные скобки, например).
    • +5
      А какое отношение новомодные ЯП имеют к 40летнему Си? Проблема-то именно в его синтаксисе.
      • 0
        На мой субъективный взгля там кол-во подобных «неувязок» синтаксических гораздо больше, ибо от всяких скобок и разделителей стараются максимально отказаться. Мне это стремление кажется ошибочным, ибо скобки и разделители помогают читать и бегло взглянув в общем понимать логику кода.
        • +8
          Надо просто правильно форматировать код и не страдать копипастой. Куда более вероятно, что человек дважды нажал ctrl+v, чем дважды напечатал goto fail;. При использовании автоформатирования такая проблема сразу себя проявляет визуально.
          • +1
            И как можно страдать копипастой при чтении?
            Я вам пример хуже приведу
            if(что-то);
               Действие
            • 0
              Вполне классика. Тот же eclipse отформатирует так:
              if(cond)
                  ;
              op();
              
            • +1
              Отчасти поэтому лично я предпочитаю форматирование вида:

              if (condition) operator;
              


              здесь сразу все ясно и ошибиться практически невозможно.
          • 0
            Как будто вы никогда не писали код в 3 часа ночи.
            • 0
              Production код стараюсь не писать в такое время =)
        • +2
          Поддержу. Расстояние Левенштейна для синтаксически верных конструкций в лаконичных языках невелико. Опечатка в «старомодном» языке скорее всего приведет к ошибке компиляции/интерпретации, а в излишне лаконичном — к неверному поведению. Но свои плюсы у компактных языков тоже, конечно, есть.
          • 0
            Для меня визуально + и — различаются больше, чем plus и minus. Возможно, тут расстояние Левенштейна не работает.
            • +2
              Не «не работает», а следует дополнить особенносятями визуального восприятия, по-хорошему, ещё и учитывать расположение клавиш для популярных раскладок.

              CoffeeScript:
              ([0..5]) # [0;5]
              ([0...5]) # [0;4]
              
              a b c d  # a(b(c(d)));
              a b, c d # a(b, c(d));
              a b; c d # a(b); c(d);
              
              if 1
                if 0
                  a()
                else 
                  b()
              c() # b(); c();
              
              if 1
                if 0
                  a()
              else 
                  b()
              c() # c();
              

              Изменение всего 1 символа приводит к совсем другому синтаксически корректному коду. На мой взгляд очевидно, что возможен более «помехоустойчивый» синтаксис.
          • +1
            Мне кажется, излишняя лаконичность — это когда часть логики вешают на whitespace (пробелы и табы). Получается, что визуально пустое место (которое легко пропускается глазами) имеет такое же значение, как и сам код.
            • +4
              Если бы отступы были незаметны их бы люди не делали. Из делают именно потому, что они заметны даже в тех языках, где они ничего не значат
    • –2
      Я думаю тут причина в отсутствии лаконичности. Вместо исключений или Maybe monad надо тупо повторять if(x) goto fail после каждой операции. Интересно, они не вычищают dead code и не пользуются статической верификацией хоть какой-то?
      • +1
        Хорошо, давайте вместо goto fail всюду писать throw exeption(). Что-то изменилось?)
        Вот Maybe monad — вещь более интересная. Но чтобы не пришлось всюду писать одно и то же — тут так же надо постараться.
        А конкретно в данном случае было бы достаточно операции &&.
        • –1
          Для того, чтобы переправить эксепшн наверх не надо писать throw exception — достаточно ничего не писать
    • 0
      А что не так с условиями в Tcl?
      • 0
        «условие и «тело» берутся в одинаковые фигурные скобки»
        Т.е. вместо if(условие) { тело } пишешь if { условие } { тело }
        • –1
          Ну, и что с этим не так?
          • 0
            Визуально сложнее отличить условие от тела, особенно когда много вложенных if-ов и прочих фигурных скобок.
            • 0
              Неправда, если Вы так говорите, значит, Вы мало писали на тикле.
              • +1
                Какая разница сколько писал когда речь о визуальном восприятии.
                Нормальная строчка TCL кода:
                foreach el $b {if {[info exists arr($el)]} {lappend res $el}}

                При первом взгяде не ясно где тело цикла — точнее почему их как-бы два.

                А вот так:
                foreach el $b { if(info exists are($el)) {lappend res $el}}

                лично мне читается гораздо легче.
                • –2
                  Во-первых, Tcl, а не TCL.
                  Во-вторых, отступы и переводы строк — раз уж Вы радеете за визуальное восприятие.
                  В-третьих, нет, фигурные скобки здесь полностью оправданы и визуальному восприятию не мешают.
                  • +1
                    Ох и придирчивы на Хабре сегодня.

                    > Tcl, а не TCL
                    en.wikipedia.org/wiki/Tcl
                    Tcl (originally from Tool Command Language, but conventionally spelled «Tcl» rather than «TCL»; pronounced as «tickle» or «tee-see-ell»[3])

                    Так что, как видите, TCL более правильное написание — раз уж для вас это важно.

                    > фигурные скобки здесь полностью оправданы
                    И чем же они лучше чем круглые скобки в данном случае? В всех языках C-подобного синтаксиса используются круглые скобки, и все довольны.
                    • –1
                      Нет, TCL не более правильное. Официальное (и правильное) написание — Tcl.

                      А Tcl — не C-подобный.
                      • +1
                        > Нет, TCL не более правильное. Официальное (и правильное) написание — Tcl.
                        Написано же черным по белому — оригинальное название Tool Command Language, используются оба способа написания (TCL и Tcl) и произношения («tee-cee-el» и «tickle») равноценно.
                        С чего вдруг «Официальное (и правильное) написание — Tcl»? Где написано что TCL — неправильно? Не выдумывайте ерунды.
                        • 0
                          Ну сходите наконец на tcl.tk
                          Tool Command Language, Tcl.
                          • 0
                            > Tool Command Language
                            А я о чем?
                            Повторяю вопрос: где написано что TCL — не правильно?
                            • 0
                              Вам недостаточно
                              > conventionally spelled «Tcl»
                              ?

                              Tcl — больше не аббревиатура, если хотите.
                              Tcl (а не Xyz, Abc, Nom или другие три буквы) — да, потому что это первые буквы в «Tool Command Language». Так совпало ;)
                            • 0
                              Вы, Sauron, процитировали "conventionally spelled «Tcl» rather than «TCL»", что в переводе означает: "принято записывать «Tcl», а не «TCL»".

                              Можно ли считать в данном случае, что «не правильно» записывать так, как не принято?

                              Если да, то вот и ответ на Ваш вопрос.

                              Если нет, то это скорее Вы «придирчивы на Хабре сегодня».
                              • 0
                                > Можно ли считать в данном случае, что «не правильно» записывать так, как не принято?
                                Нет.

                                > Если нет, то это скорее Вы «придирчивы на Хабре сегодня».
                                Почему-же? Мне все равно TCL или Tcl, я совершенно не понимаю почему от сути разговора собеседник вдруг перешел на вопросы «правильности» написания TCL. Я к такой ненужной подробности не придирался.
                    • 0
                      К сведению, фигурные скобки можно и опустить, правда, смысл будет несколько иной.
                • 0
                  А зачем тут смотреть на скобки? Вот у вас идет if и за ним два expression-а. По-моему, все очевидно.

                  Я не пишу ни на тикле, ни на лиспе, если что.
                  • +1
                    Нет, разница есть: первый параметр if — выражение на языке expr, а второй и опциональный третий — команды тикля. Так что нельзя сказать, что два выражения. Потому, кстати, и квадратные скобки нужны.
                    • 0
                      Да, согласен, глупость написал. Но общая идея, надеюсь, осталась ясна.
              • +1
                Неправда, если Вы так говорите, значит, Вы мало писали на тикле.

                Для непредвзятой оценки как раз и нужен свежий взгляд. Привыкнуть можно к чему угодно.
                • 0
                  В тикле для фигурных скобок есть причина, причём довольно серьёзная, точно так же, как в C есть причина для круглых скобок. В C в скобки круглые заключаются выражения, а в фигурные — блоки кода. В тикле нету выражений и блоков кода как таковых, есть текст, который интерпретируется в зависимости от контекста, причём решает это вызываемый код, а не вызывающий (что довольно логично). Скобки в первом параметре команды if означают лишь то, что в теле этого параметра не надо выполнять подстановки в процессе вызова этой команды. Если подстановки выполнять не нужно, то фигурные скобки не нужны.
                  • 0
                    Скобки в первом параметре команды if означают лишь то, что в теле этого параметра не надо выполнять подстановки в процессе вызова этой команды. Если подстановки выполнять не нужно, то фигурные скобки не нужны.
                    Вы сломали мой парсер логических выражений.
                    • 0
                      Вроде логично: если подстановки могут быть, их надо выключить. Если их быть не может — можно не выключать.
                      • +2
                        У вас было написано две импликации в разные стороны:
                        1. Если есть скобки, то подстановки выполнять не нужно [интерпретатору, видимо].
                        2. Если подстановки выполнять не нужно [разработчику, так понимаю], то скобки не нужны.

                        Это, в общем, и путает. Можно было просто написать, что при отсутствии фигурных скобок (например, в квадратных) интерпретатор выполняет код, при наличии фигурных — не выполняет и передает в макрос как есть.
                  • 0
                    По сути вопроса я спорить не буду, ибо в Tcl некомпетентен. Просто замечу, что выходит хотели как лучше, сделали логично и унифицированно, а неподготовленному человеку в итоге нечитабельно и неудобно. Чтобы такого не было, надо языки писать как хорошее ПО, с фокус-группами, научными исследованиями со снятием метрик читабельности синтаксиса и прочим.

                    Между делом говоря, для C есть GCC Statement Expressions, позволяющие в выражениях использовать блоки кода.
                    if (({int x = 2; (4 == x*x);})) {
                        // true
                    }
                    

                    • –1
                      Не согласен. Вон в PHP чего понагородили — всем хотели угодить же ж!
  • +11
    Вот поэтому я считаю, что тело if всегда стоит оборачивать в фигурные скобки.
    К сожалению, на текущей работе принято, что в случае когда тело if состоит из одной строки, фигурные строки ставить не стоит.
    • +14
      А я считаю, что хороший редактор кода во первых сам исправил бы некорректное форматирование, а во-вторых предупредил бы о наличии недостижимого кода.
      Ну и если вдруг редактор не помог, то хороший ревьюер оторвал бы за такой код руки автору.

      И мне, честно говоря, кажется, что это несколько более рабочие механизмы, чем обязательность скобочек у if-а.
      • 0
        Скобки в таком случае обычно вопрос договоренности внутри команды. И настройки IDE и системы сборки после этого.
    • 0
      Когда у меня тело if-а состоит из одной строки, то стараюсь разместить тело в той же строке. А иногда перфекционизм начинает доминировать и я ставлю фигурные скобки даже в таком случае =))
      • 0
        В embedded разработке есть паттерн ожидания флага
        while(SOME_HARDWARE_FLAG == 0);
        

        который тот же eclipse переписывает в виде
        while(SOME_HARDWARE_FLAG == 0)
            ;
        

        считая, что это поможет уменьшить вероятность ошибки вида
        while(SOME_HARDWARE_FLAG == 0);
            some_operator();
        


        Естественно, часть людей считают первый вариант (в одну строку) нормальным паттерном, часть — антипаттерном.
        • +8
          может быть, лучше явно показать пустой цикл?
          while(SOME_HARDWARE_FLAG == 0) {}
          
        • 0
          Не знаком с предметной областью, но очень хочется в такой цикл добавить delay на 1мс или что-то вроде. Так делают, или это ересь? Не приведет к throttling?
          • 0
            Это глупость. delay имеет смысл, когда надо освободить процессор для других потоков. Но зачем он нужен, ежели поток всего один?
            • 0
              Странно, а я думал вот так:
              Let's say we have an embedded system which has an average loop time of 1ms, and needs only to check a certain input once per second. It seems a waste to continue looping the program, especially when we don't need to do anything most of the time. In this situation, the program will loop 1000 times before it needs to read the input, and the other 999 loops of the program will just be a countdown to the next read. In this case, it is sorely inefficient to have the processor chugging away at 100% capacity all the time. We will now implement an expanded superloop to build in a delay:


              Одно ведь дело, если флаг изменится через 1-2мс, но это же может быть и флаг «юзер нажал на кнопку» и чип дергает цикл и считывает volatile переменную тысячи раз в секунду (или сотни тысяч?). Или таки я ошибаюсь и там есть защита от такого?
              • 0
                Ну, эти рассуждения годятся только в том случае, когда delay действительно уменьшает энергопотребление. Зачастую, сам delay через цикл и реализован…
                • 0
                  жесть какая =)
                  окей, спасибо за консультацию!
                  • 0
                    Добавлю кругозора ради. Инструкция HLT существовала в процессорах Intel начиная еще с 8086, если не раньше (не помню, была ли эта команда в 8008). Но, тем не менее, эта команда практически не использовалась в программах под DOS (и правда, зачем она была нужна?)

                    Как результат — мой компьютер спокойно держит 6 виртуальных машин с линуксом (я тогда курсовую по сетям делал) — и тормозит всего на двух виртуалках с ДОСом (я пытался делать курсовую по системному программированию).

                    Для того, чтобы вызов delay уменьшат энергопотребление, требуются три вещи:
                    1. в системе команд микроконтроллера должна быть команда останова,
                    2. у микроконтроллера должен присутствовать встроенный или внешний программируемый таймер,
                    3. реализация функции delay должна уметь пользоваться первым и вторым пунктами.
              • 0
                Задержка и ожидание события — две большие разницы. Если необходимо среагировать на событие чип может уходить в какой-нибудь режим энергосбережения, отключать тактирование части периферии и т. п. Стоит учитывать, что пробуждение занимает время, включения тактирования — тоже. Чем глубже режим энергосбережения — тем больше время пробуждения и больше его дисперсия, что может быть критично в системах реального времени.
          • 0
            Всё сильно зависит от среды исполнения. Когда это голое железо (т. е. совсем без ОС), то задержка — такой же цикл. В зависимости от величины задержки он может выполнять либо просто заданное число итераций, либо считать ожидать некоего значения на внешнем счетчике. Если у вас шедулер/ОС, то иногда имеет смысл сделать yield (переключить задачу и уснуть), иногда — подождать циклом.
  • +1
    Простите что не совсем по теме, но evasi0n jailbreak по прежнему работает, или эту «дырку» данным обновлением тоже прикрыли?
    • +3
      работает
  • +3
    Этот код не должен был дать закоммитить линтер.
    • +5
      Ещё скажите, что CI нужен
      • 0
        Да уж! Очень интересно как у них это получилось.
  • –17
    Надо же, Goto! Как в детстве 20 лет назад, когда на бейсике писали… Не запретили ещё!
    Хотя, вру, конечно. На ассемблере потом ещё приходилось.
    • +12
      А почему goto нужно запрещать?
      Это вполне себе паттерн программирования, наравне с некоторыми другими.
      Вот, например, официальная документация, error handling in COM:
      msdn.microsoft.com/en-us/library/windows/desktop/ff485842.aspx#jump_on_fail
      • –6
        Ну а теперь смотрим на суть статьи, к чему привело использование goto. И заодно читаем статью msdn, где паттерн вроде бы ровно тот, но за маленьким вроде бы ничего не значащим отличием — отсутствующими здесь скобками.
        Вот так использование двух вроде бы не жестко запрещенных паттернов и привело к косяку.
        Реальному, живому косяку, а не лайкам-дизлайкам в обсуждении.

        Можно вообще писать в машинных кодах супер-программы. Проблема в том, что программисты не всегда глубоко понимают суть тех или иных рекомендаций. И пропускают детали.
        • +3
          Такую ошибку можно допустить независимо ни от каких goto. Замените, к примеру, все goto fail на throw exception(). Что-то изменилось?
          • +3
            или на do{if()break;}while(0); если уж такая сильная готофобия.
          • +1
            Если бы в этом коде использовались исключения, а не поле с кодом ошибки, то такое копирование строки сделало бы код неработоспособным — он бы всегда выбрасывал исключение.
            • +1
              Точно так же, как и сейчас он всегда переходит на fail…
              • 0
                В том-то и дело, что нет.
                В блоке fail идёт лишь очистка ресурсов и возвращается полученный код ошибки. Если ошибок не было, этот код будет 0 — нет ошибки.
                Код можно посмотреть здесь
                • +1
                  Точно так же лишнее выбрасывание исключения с нулевым кодом ошибки могло бы быть обработано как отсутствие ошибки. Представьте на минутку, что мы переписываем только одну функцию, а не перерабатываем весь код программы и связанных библиотек.
                  • 0
                    Точно так же лишнее выбрасывание исключения с нулевым кодом ошибки могло бы быть обработано как отсутствие ошибки.

                    А вот за такое надо пересадку рук делать.
          • –2
            Да, зачем вообще какие-то дураки эксепшены придумали? Какие-то там throw, catch — а тут goto fail, гораздо более надежно!
            • +1
              Давно ли в стандарте C появились exceptions? Киньте ссылку на стандарт, пожалуйста.
              • 0
                В С++ — давно, ссылку на стандарт кидать лень, может поверите наслово?

                Не, ну я понимаю, что есть люди, считающие что все кроме С — говно (типа Линуса :)), только не надо позиционировать конструкции, которым более полувека, как что-то современное, ок? Программирование, как и другие инженерные области, развивается, если что.
                • +1
                  Какое отношение C++ (где очевидно есть исключения) имеет к коду на C, который обсуждается в топике и содержит презренные goto? Или все операционки срочно надо переписать на плюсах только за то, что там есть exceptions, а C безумно устарел даже в стандарте C11? Может они и в ядре будут хорошо работать? Может сразу на Java, то там модель exceptions мне нравится, да и JMM приятна.

                  У вас, кстати, libstdc++ хорошо влезает, скажем, в 8к ROM + 512 RAM? Плюсы не являются развитием C, но другим языком. C развивается самостоятельно, выходят новые стандарты, улучшаются компиляторы…

                  Во избежание таких ошибок в высокоуровневом коде на С вполне можно использовать функции-обертки, занимающиеся выделением и освобождением ресурсов, когда лишнее углубление в стек не критично. В языках с механизмом exceptions часто используют try-catch, когда такие накладные расходы допустимы.
        • 0
          А ещё нужно жестко запретить копипаст!
          Уж к скольким реальным, живым косякам привёл копипаст — и не сосчитать.
        • 0
          >Вот так использование двух вроде бы не жестко запрещенных паттернов и привело к косяку.

          По вашей логике если кто-то допустит баг при использовании паттерна «фабрика» или «синглтон», то нужно запретить фабрики и синглтоны?
      • 0
        Лично я для себя прошел такую цепочку:
        1. Goto
        2. Нет, Goto ж нельзя, запрещают
        3. Goto-то можно, оказывается! Есть даже особые случаи.
        4. Нельзя обычным программистам, один из десяти обзательно накосячит. а мне можно — я же постиг и свободен.
        5. Мне нельзя
        И не потому что накосячил. А потому что не нужно.
      • 0
        Вот, например, официальная документация, error handling in COM:

        Без обид, но если для вас COM — образец современной технологии, то, наверное, спорить бесполезно.
        • –1
          Без обид, но COM до сих пор живее всех живых. Технология WinRT (куда уж современнее-то?) — и та основана на COM.
    • 0
      Какое goto на ассемблере? Только jmp/rjmp/b/bx/bl/blx/..., только хардкор.
      • +6
        ну goto по сути и есть jmp, просто метка проще записывается :) так что goto и есть хардкор.
        • –3
          Лексема goto обычно встречается в более высокоуровневых языках. Что она транслируется в какой-то вариант оператора безусловного перехода — тоже очевидно.
          • +2
            Ассемблер бывает разные. На в микроконтроллерах PIC есть два оператора безусловного перехода bra и goto.
            • 0
              С ассемблером от microchip я не знаком. Посыпаю голову пеплом. Не понравились они мне в своё время.

              Но, предполагая, что в каком-нибудь ассемблере оно может встретиться написал «goto обычно встречается».
      • 0
        Естественно, имелось в виду jmp, jne, jle и т.п.
  • +8
    Им надо PVS-Studio прикупить: )
    • +19
      Кстати, анализатор PVS-Studio вполне себе замечает аномалию в этом коде и сообщает:

      V640: The code's operational logic does not correspond with its formatting. The statement is indented to the right, but it is always executed. It is possible that curly brackets are missing. Level: 2

      А вообще надо будет правило и касательно именно двух goto сделать.
      • +2
        А на недостижимый код после goto он не жалуется? В Java, например, здесь была бы ошибка компиляции «unreachable code».
        • +3
          Смысла большого нет. Мы стараемся не дублировать предупреждения компилятора, если не можем сделать диагностику чем-то лучше. Поясню на примере. В Visual C++ есть предупреждение, что в классе деструктор объявлен не виртуальным. Диагностика сделана «в лоб». Как результат, пользоваться ей нельзя и она по умолчанию даже выключена. То есть она даёт слишком много бестолковых предупреждений. Ведь далеко не всегда виртуальный деструктор нужен.

          У нас сделано умней. Диагностика V599 срабатывает только тогда, когда другие есть виртуальные функции. Это значит, что от класса планируют наследоваться. Следовательно, нужен виртуальный конструктор. Диагностика вполне по делу. И находятся ошибки.

          Так вот. Сейчас все нормальные компиляторы предупреждают про недостижимый код. И как они просмотрели это предупреждение — не понятно. Если оно отключено, то тоже не понятно почему.
          • +1
            А тогда зачем правило касательно двух goto? По идее, в этом случае как раз компилятор должен ругаться, как вы и говорите.
            • 0
              Я так просто это написал. В начале, конечно, надо будет изучить вопрос подробнее. Стоит ли делать и как, какая будет польза и т.д.
          • +1
            то есть, проверка на недостижимый код в у вас не делается, так как она есть в компиляторе?
            • +1
              Да. Но есть некоторые разновидности диагностик на эту тему (пример).
        • +1
          gcc имеет такую опцию -Wunreachable-code
  • +5
    Очень хороший пример, что опечатку может сделать кто угодно и где угодно. Можно как мантру повторять, что уж мы то профессионалы не делаем таких ошибок, но…

    Устал пытаться донести мысль, что никогда не стоит пренебрегать средствами дополнительного контроля над собой (статический анализ кода и т.п.). Надо такие примеры начать собирать, чтобы было что на «я пишу без глупы ошибок» ответить аргументированно.
  • –4
    Напоминает случай с уязвимостью MacOS, где программист оставил отладочную печать.
    story

    Видео с курса CS259: Software Debugging от Udacity
    • +12
      Целая минута видео, по-сути без видео, а процесс рисования картинки, вся суть которого передается тремя словами: пароль пишется в лог.
      • 0
        Извиняюсь. Действительно, вырванное из контекста смотрится не очень. В соседнем видео упоминается ещё пара неудачных способов отладки и говорится, что так делать не стоит.
        Andreas Zeller знает много интересных историй. К примеру, отладка с помощью плюшевого медведя: прежде чем обратиться к кому-либо за помощью, стоит попытаться сформулировать проблему и рассказать её вслух (плюшевому медведю). Есть большая вероятность, что при формулировке проблема всплывёт перед глазами.
        • 0
          • 0
            Такого названия не встречал, но по ссылке написано и о медведе. При этом книги вышли в одном году и истории разнятся. Видимо, идея витала в воздухе.
        • +4
          Надо ж так кардинально исказить метод резиновой уточки!

          blog.centresource.com/2005/07/05/rubber-ducky-method/
  • 0
    Реквестирую от уважаемых гуру С рефакторинг этой функции, интересно посмотреть как это сделать максимально правильно, спасибо
    • 0
      Просто уберите лишний goto fail; ;)
      Всё остальное субъективно и зависит от принятого в вашей компании coding style, ну и от ваших личных предпочтений.
  • +1
    ++ Из текста: Чтобы узнать уязвимо ли Ваше Apple устройство/приложение, нужно попытаться загрузить следующий сайт https://www.imperialviolet.org:1266 . Если у Вас это получилось, то у Вас проблема… Вот пример:
    image
    • 0
      Уже вышло обновление.
    • +2
      Safari 7.0.1 (9537.73.11) на OS X 10.9.1 открывает.
      Обновлений система не предлагает.
      • 0
        Всё верно. iOS исправлен в iOS 7.0.6 и iOS 6.1.6. В OS X 10.9.1 все работает. Хорошие новости в том, что, видимо, под удар попала только OS X 10.9, так как у меня на стареньком Mac Air'e (OS X 10.6.8) и Мас Pro (OS X 10.8.4) ни чего не работает.
        image
        • 0
          Safari вывела сообщение это.

          curl в консоли ответил
          curl: (35) error:04091077:rsa routines:INT_RSA_VERIFY:wrong signature length
  • 0
    Там в самом конце исходников:
      if ((err = SSLAllocBuffer(&key, keyDataLen)))
            return err;
    	assert(ctx->sslTslCalls != NULL);
        if ((err = ctx->sslTslCalls->generateKeyMaterial(key, ctx)) != 0)
            goto fail;
    

    Вот я думаю, строка assert(ctx->sslTslCalls != NULL); это такая же ошибка, или просто ошибка в редактировании?
    • 0
      Хотя чего это я? Это же после return. Явно просто лишний tab поставили…
      • +1
        К слову, в исходниках всё плохо касательно форматирования кода. В смысле, очень-очень плохо.
        И скобки вразнобой (одних только if — три варианта написания), и табы вперемешку с пробелами, где-то операторы отбиты пробелами, где-то нет…
        • +6
          Такое бывает, когда код писало много поколений
  • 0
    А разве простейший статический сканер кода не находит дублирующие строчки? Дубли всегда что то значат же
    • 0
      Сами по себе дубли ещё ничего не значат. Вполне корректный код:

      *p++ = 0;
      *p++ = 0;

      A[i++] = GetNext();
      A[i++] = GetNext();

      Особенно много такого может быть из-за макросов или автосгенерированного кода.
      А так да, инструменты вполне помогают найти такое. См. мой комментарий выше.

      • +3
        код то корректный, но смысл его? Ооочень редко он оправдан
  • 0
    Дублирующиеся строки и лишние табуляции/пробелы то и дело появляются при работе автоматического merge, даже в git'е. Как вариант, неправильное исправление конфликта (которые тоже не всегда показываются правильно). Само по себе это не проблема, сама проблема в том, что diff'ы после таких операций нужно просматривать всегда.
  • –1
    Во первых, пользуйте фигурные скобки
    Во вторых, автоматический реформат кода на коммите должен быть, чтобы репозитории всегда лежал правильно отформатированный код
    В третих, при компиляции такого, должна быть ошибка про unreachable code
    В четвертых, goto — зло
  • 0
    во всех версиях OS X до 10.9.1 включительно
    Поправлю, что появилось только в OS X 10.9 и присутствует в 10.9.1:
    Update: it looks like the bug was introduced in 10.9 for OS X
  • 0
    В Лэнгли что угодно объяснят… :)
  • +1
    JetBrains стебанули над этим куском кода: twitter.com/appcode/status/437896886649757696/photo/1
    Tip of the day: Detecting unreachable code is easy with AppCode. Can your IDE do the same?

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.