Как стать автором
Обновить
13
0
Константин Белкин @cbelkin

Человек, который пишет какие-то программы.

Отправить сообщение

Потому что в подвале статьи об этом написано.

Перевод статьи подготовлен в преддверии старта специализации "iOS Developer".

Зашёл почитать про уязвимости - прочёл о том, что в любом ПО возможны ошибки. Спасибо за информацию. До этого, конечно, никто об этом не догадывался. Можно тогда ещё упомянуть, что у домашней микроволновки тоже есть баги в коде (что по меркам автора является ещё более защищённой ОС).

Статья и так небольшая, но примерно её половина это описание примитивных вещей, не требующих разъяснения для аудитории хабра.

Прошивка не верифицируется на этапе загрузки, так как является самой первой программой запускающейся при включении устройства. Верифицируются только последующие этапы: загрузчик iBoot и ядро XNU.

Да, уязвимость на DFU не исправляется с обновлением iOS, так как код прошивки имеет особый статус и не может быть обновлён после записи на устройство. Но уязвимость уже несколько лет как исправлена. Начиная с прошивки на A12 этот способ атаки не работает. Об этом не сказано.

Ещё и сама статья не помечена как перевод в заголовке. Можно было просто так и написать в заголовке «Реклама курсов iOS разработки» без всякой ерунды на целую статью.

Вы походу дебаг билдите, вот оптимизации и не выкидывают неиспользуемый код,

По-умолчанию отладочные символы не включаются компилятором в сборку (что в Java, что в C++). Для этого используется отдельный флаг -g. Автор его явно не использовал (было бы странно). Ассертов тут нет. А для того, чтобы применить оптимизацию в C++, необходимо передать соответствующие флаги (можно использовать специальные флаги, которые включают в себя группы оптимизаций: O1, O2, O3), в противном случае компилятор не производит существенных изменений в исходный код.
Для того, чтобы выкинуть неиспользуемый код необходимо задать флаг O2 и выше. Автор это сделал в части тестов, однако не учёл каким образом оптимизировался код.

Выведите результат, переключитесь в релиз и увидите совсем другие цифры

Если судить по написанному, то автор явно не использовал сборщики, а передавал флаги напрямую. Понятие дебаг/релиз применимо только к сборщикам (Make, Gradle, CMake и т.д.). Так что переключаться никуда не получится.
Немного ошибся в том, что для стандарта C++14 в clang этот функционал ещё не доделан, но тем не менее доступен как совместимость с C99.
Ссылки:
isocpp.org/files/papers/N3690.pdf — страница 185
clang.llvm.org/docs/LanguageExtensions.html#c-14-runtime-sized-arrays
clang.llvm.org/compatibility.html#vla
В C++ при применении флагов оптимизации O2 и O3 этот код ничего не делает (смотрел бинарь). Байт-код Java я не смотрел, но уверен, что компилятор Java также производит соответствующие оптимизации и полностью обнуляет ваш тест. Так что от части, вы сравнили два таймера из Java.
Может я ошибаюсь, но, насколько я помню, new[] в Java гарантирует корректное зануление массива, а вот в плюсах там может быть что угодно. Так что плюсовый вариант будет с неинициализированным массивом, По факту UB. Это раз.

В контексте статьи не имеет значения. В C++ там просто будет какой-то мусор размерностью int. Поэтому UB тут вполне defined.

Два — итоговый sum нигде не используется, и достаточно ушлые компиляторы технически могли бы вырезать весь бенчмарк с концами.

Так и будет. Clang при применении оптимизации O2 и O3 даже не вызовет эту функцию. Это полностью компрометирует предложенные результаты и всю статью целиком.
Примените к коду из статьи флаг оптимизации любой глубины (O1, O2, O3) — память под массив вообще не будет аллоцирована. Это не значит, что можно из кучи волшебным образом сделать стек, но спецификацией допускается анализ оператора new и его последующие оптимизации.
2. Компилятор может как угодно оптимизировать код, тут никто не знает.

Не как угодно. Это определяется стандартами и спецификацией компилятора. Люди, программирующие на C знают, что будет делать компилятор при применении определенных флагов.
«Сделайте правильно» int array[size] когда size не константа?

В C это возможно начиная с C99, а в C++ начиная с C++14. Последние версии clang имплементируют стандарт C++14 в полном виде (так заявлено в документации).
Грубая ошибка для C++. Много где встречал, что это является плохим тоном. Для базовых числовых типов не желательно использовать массив из указателей и использовать new, если переменная локальная!

Самое обычное выделение памяти под динамический массив в C++. Объявляется указатель на участок памяти, где будет располагаться массив не указателей, а целочисленных значений. В данном случае, конечно, new использовать было совсем не обязательно, т.к. размер необходимого массива нам заранее известен (в данном случае ваш пример с кодом приведен корректно). Но это никак не зависит от того глобальная переменная или локальная. Зависит от того, известна нам размерность или нет.

Основная проблема, что при указателях C++ может разместит массив в куче, а не в кэше(на стеке)

new говорит о выделении динамической памяти, а это всегда только куча, если не применены оптимизации компилятора. Указатели тут не при чем.
Кэш != стек. Помещение данных в стек не гарантирует его кэширование процессором.

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

В данном случае векторизовывать нечего, т.к. представленный в тесте цикл не параллелится.
Пример далеко не показательный, чтобы делать такие выводы.
Современные компиляторы уже достаточно развиты, чтобы оптимизировать такие простые циклы. Корректнее было бы сравнить полноценную программу на Java (чтобы хотя бы несколько сот классов было) и аналогичный нативный. Я уверен, что картина была бы совсем другая.

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

Вполне очевидно, что полноценный код с кучей Java классов будет медленнее аналогичного нативного. И тут не нужно никаких сравнений. Это аксиома. Просто потому что у нативный код не зависит от рантайма JVM.
Все зависит от компании, в которой растёт или рос младший разработчик и от интереса самого разработчика к предмету его работы.
Если в компании поощряется креативность (к работнику прислушиваются) и выделяют время на самостоятельные исследования вопроса (не спрашивают каждые 5 минут «Скоро уже?») — тогда у человека со временем появляется ощущение, что он может самостоятельно принимать решения, за которые не будет стыдно и его не выгонят (растёт).
Если человек прошёл собеседование, значит он уже не откровенный бездельник и какая-то база и желание развиваться у него есть (либо проблема в собеседованиях).

У вас в компании одни переводчики работают?

Пятая публикация автора за сегодняшний вечер. Все статьи на разные темы. Невероятная многогранность и разносторонняя развитость автора вызывает зависть.

К сожалению нет. Введение фантомного типа не допускает динамического изменения свойств родительского типа. В этом и весь смысл. У нас есть два структурно одинаковых объекта, но нам нужно разделить их семантически. Тогда мы декларируем обобщение, которое никак не используется и получаем уже два несовместимых типа.
Важно помнить, что подобные решения — это злоупотребление системой типов. Своего рода хак. Любой такой хак представляет собой неочевидный подход для решения критически важных проблем, жертвуя самодокументированием кода.
Возможно в каких-то ситуациях такой подход и может выполнить роль предохранителя, но главным образом фантомные типы используют для разгрузки рантайма от лишних проверок, делегируя эту задачу компилятору.

Кроме этого, в статье приведены неудачные примеры, демонстрирующие отсутствие понимания культуры программирования на Swift.
1) Пример с User и Product. Для сравнения двух бизнес объектов не требуется в явном виде сравнивать их идентификаторы. Достаточно лишь унаследовать протокол Equatable и сравнивать объекты напрямую. При желании можно переопределять дефолтный алгоритм сравнения (если не требуется сравнение по всем полям структуры).
struct User {
  let id: UUID
}

struct Product {
  let id: UUID
}

extension User: Equatable {
    static func == (lhs: User, rhs: User) -> Bool {
        return lhs.id == rhs.id
    }
}

extension Product: Equatable {
    static func == (lhs: Product, rhs: Product) -> Bool {
        return lhs.id == rhs.id
    }
}

let product = Product(id: UUID())
let user = User(id: UUID())

user == product

Проверка произойдет также на уровне компилятора и не даст собрать неверный код.

2) Пример с fetch. Для методов получения бизнес объектов из хранилища, также вместо идентификатора обычно передаётся объект целиком, либо используется специальный класс для задания параметров поиска NSPredicate.
func fetch(_ product: Product) -> Product? {
    // return product
}

fetch(user)

Проверка тоже на уровне компилятора — никаких проблем.

3) Пример с HealthKit. Тут всё просто. Проблема из ничего. Для проверки возможности скастить единицу измерения у этого же класса есть специальный метод is(compatibleWith:) developer.apple.com/documentation/healthkit/hkquantity/1615508-is
let average = statistics?.averageQuantity()
var mass = 0.0
if let qty = average,
   qty.is(compatibleWith: .meter())
{
  mass = qty.doubleValue(for: .meter())
}

Это конечно райнтайм, но зато без замусоривания кода лишними абстракциями.

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

И кстати Generics во всем цивилизованном мире зовутся обобщениями (обобщенными типами), а не универсальными типами.
Мне кажется вариации толкований слова «трюк» не является темой обсуждения этой статьи.
Насколько я могу судить, на хабре присутствует аудитория с разным уровнем технических знаний в разных областях. Кто-то знает спецификацию наизусть (и для него это кажется обычным дело), а кто-то представляет себе HTML лишь в общих чертах. И для последних, предлагаемые в этой статье тэги и атрибуты, не являются обычными, поскольку редко встречаются. На школьных курсах по информатике об этом не все говорят. На университетских курсах по веб-программированию тоже (даже на ФКН). Просто времени нет на то, чтобы обозревать всю спецификацию.

Поэтому я бы не стал приобщать представленные примеры к «Обычным знаниям тэгов и свойств».
Не вижу ничего плохо в том, что пишут статьи или книги, которые аккумулируют информацию по какой-то теме и представляют её в кратком и удобном виде. Например у меня на книжной полке стоит книга «Руководство системного администратора». Аж на 1000 страниц. 90% этой книги в том или ином виде присутствует в спецификациях. В силу того, что системное администрирование не является моей повседневной задачей, многие вещи забываются. Поэтому иногда я беру и листаю эту книгу, чтобы освежить знания. Бывает даже нахожу что-то новое для себя, чего не замечал раньше. И это удобнее, чем бессистемно рыться в мануалах. На это уйдёт гораздо больше времени. Меня заинтересует какая-то команда — вот я и пойду читать о ней подробнее в мануале.

Такой же смысл я вижу и в этой статье. У меня нет особой потребности часто заходить на спецификацию по HTML. А тем более читать её вдоль и поперёк — всё равно забудется. Когда мне доводится смотреть исходники чужих HTML страниц, то я редко вижу подобные решения. Поэтому скорее всего забывается даже у фронтенд разработчиков. Но я пишу в первую очередь о своих ощущениях. Что-то я видел раньше, что-то нет. Но вот наткнулся на статью, освежил информацию и взял на заметку. И вот как раз зашёл и почитал в спецификации по интересующим меня пунктам.
Не вижу ничего криминального в заголовке. Мне статья показалась интересной и полезной. Хорошее напоминание о тэгах и атрибутах, которые на практике используют очень редко. На мой взгляд незаслуженно. Кроме того, ещё очень много элементов, не упомянутых в этом посте, имеют такую же участь.
Проблемы с совместимостью, из представленных примеров, я увидел только у первого пункта. Атрибут loading не поддерживается браузерами Safari и Firefox. В остальном всё должно работать. Конечно, при условии, что вы не ориентируетесь на версии браузеров десятилетней давности. Но, как по мне, это уже неприлично.
1

Информация

В рейтинге
Не участвует
Откуда
Москва, Москва и Московская обл., Россия
Работает в
Дата рождения
Зарегистрирован
Активность

Специализация

Mobile Application Developer
Middle
SWIFT
iOS development