Комментарии 216
Лучший дядька на планете!!
Возможно, вырвано из контекста, а он не хочет скатываться в бесконечную переписку и с десяток групп в мессенджерах - столь любимый способ ведения дел менеджерами крупных компаний ("солдат спит, а обсуждение служба идёт"). И сразу рубит это на корню.
И смузи не пьёт ещё наверное. Фи.
Предложите свою версию общения с идиотами, которые не понимают, что if(a + b) < a - это дичь. Если вы незнакомы с программированием - перефразирую:
Если (2 + 3) меньше 2, то что-то сделать.
Вообще-то, например, на процессорах MIPS это единственный способ проверить беззнаковое переполнение. Прерывания нет. Флагов нет.
Как следствие, переносимый код на Си пишется именно так.
Если вы незнакомы с программированием - перефразирую
Это Вы, челодой моловек, с программированием явно не знакомы (да и с русским языком, вижу, тоже как-то не задалось).
> cat > example.c
#include <stdio.h>
main() {
unsigned short int m;
unsigned short int n;
m = 65530;
n = m + 100;
printf("65530 + 100 = %u\n", n);
}
> gcc example.c
> ./a.out
65530 + 100 = 94
>
Так наоборот же вроде, Торвальдс доказывает что if (a + b) < a
это нормально. Точнее, что это нормально, согласены они оба, но в чуть более сложных случаях Кук хочет чтобы разработчик явно описывал свои намерения, а Торвальдс говорит что нормально практически любое использование операций с переполнением.
Записал несколько фраз на память. Надо будет на работе использовать тоже...
Перевод омерзительный.
Поясните проблематику для крестьян, не шарящих в системном программировании и C?
Это что то на low level... И как я понял в сорсах линукса такого кода много и он кому-то мешает.
Попросил claude объяснить...
Вот пример с переполнением:
unsigned int a = UINT_MAX; // Максимальное значение для беззнакового целого числа
unsigned int b = 1;
if (a + b < a) {
// Произошло переполнение целого числа
// Обработать переполнение соответствующим образом
printf("Произошло переполнение!\n");
// ...
} else {
// Переполнения нет, продолжить нормальное выполнение
printf("Переполнения нет.\n");
// ...
}
В этом примере a
присваивается максимальное значение для беззнакового целого числа (UINT_MAX
), а b
присваивается значение 1. При сложении a
и b
результат превышает максимальное значение, вызывая переполнение. Условие if (a + b < a)
оценивается как истинное, указывая на то, что произошло переполнение, и выполняется код внутри блока if для соответствующей обработки переполнения.
Тут нужно отметить важный момент (для невнимательных): и a, и b
— не могут быть отрицательными (ибо объявлены какunsigned
), а следовательно, a + b
в нормальной ситуации никогда не может быть меньше a
; а если компьютер считает, что ((a + b) < a) == true
, то, это потому, что произошло переполнение.
Но мне кажется, что в этой ситуации было бы лучше написать обёртку вроде
#define DID_OVERFLOW_HAPPEN(a, b) ((a + b) < a)
и использовать только её. (Да, я в курсе, что #define
есть свои подземные камни).
подземные камни
#define DID_OVERFLOW_HAPPEN(a, b) (((a) + (b)) < (a))
a + b
в нормальной ситуации никогда не может быть меньшеa
Тут нужно отметить, что "a+b<a" вполне может быть в нормальной ситуации. Собственно, об этом и говорит Торвальдс, кяп. Что, де, не нужно вставлять такую проверку по умолчанию, ибо чревато многими ложными варнингами.
Кто линуксоидных мэтров учил писать такой код? Почему не написать
if (UINT_MAX - a < b) {
// Произошло переполнение
} else {
// Переполнения нет
}
Ваш способ имеет более строгое ограничение - не позволяет ничему переполниться даже во время проверки на переполнение. Но зачем усложнять, если в отличии от ситуации знакового переполнения, процессор даже не имеет флага целочисленного переполнения?
Уравнения в компьютерной архитектуре - нетривиальная вещь, сложно привыкнуть что если a + b = c
то в некоторых случаях a != c - b
из-за переполнений.
Не вижу усложнения, те же самые операции. Зачем: чтобы не возникало вопроса как в обсуждаемой теме.
Но зачем усложнять, если в отличии от ситуации знакового переполнения, процессор даже не имеет флага целочисленного переполнения?
Какой процессор?
Почему не написать
В этом варианте есть неявное предложение, что a и b типа unsigned int. Такая запись может сама по себе стать источником ошибок, если тип переменных окажется иным (после рефакторингов, например).
Именно так, решение именно для типа UINT. Именно это и обсуждается в этой теме. Если вдруг понадобиться менять типы переменной, в любом случае весь код рефакторить. Потому что исходное сравнение ни для знаковых целых, ни для вещественных чисел также не будет работать.
Знаковые целые и вещественные числа вряд ли понадобятся, а вот разрядность целого в ядре линукса запросто может поменяться.
Главное, непонятно, ради чего весь кипеш. По сути тут написано то же самое, но менее ясно. Просто чтобы роботу было проще?
Пусть поменяется, тогда поменяется и разрядность UINT_MAX. Зачем: чтобы не возникало тем подобных обсуждаемому, чтобы код ядра не зависел от реализации целочисленных операций в конкретном процессоре. Флаги, исключения есть/нет, что получается в результате переполнения - не важно, поскольку не будет переполнения.
Обсуждаемый код не зависит от реализации, это гарантировано стандартом Си.
В том-то и состоит предмет дискуссии, что тулза ругается на совершенно корректный код.
Если бы я увидел в программе Ваш вариант, я бы очень надолго задумался, почему автор решил проверить какое-то неочевидное условие вместо непосредственно результата сложения, и в чём тут подвох.
Так и сыр-бор в том, что исходный код сильно похож на описку, и совсем не очевиден на первый взгляд. А у меня всё понятно: если до максимального числа осталось меньше b - ожидаем переполнение.
Если бы я увидел в программе Ваш вариант, я бы очень надолго задумался, почему автор решил проверить какое-то неочевидное условие вместо непосредственно результата сложения, и в чём тут подвох.
Завернуть код @kryvichh в макрос с понятным именем, как предложено выше. Именно его код, потому что он правильный. Макрос стандартизировать.
На переполнения вообще — не ругаться, т.к. есть другие сценарии, кроме проверок, один из которых Линус приводит в пример.
Ваш вариант содержит столько же операций, но перестанет работать при смене типов a и b, а также не учитывает возможность, что тип b может отличаться от типа a.
Имхо, дело в том, что каждый из них это художник со своим видением. Линусу в этом патче что-то не нравится, и он отписывает автору "суди, дружок, не выше сапога".
Целочисленное переполнение - до сих пор одна из основных проблем безопасности ядра Линукс, в среднем 6 крупных уязвимостей а год, и не уменьшается. Гугл предлагает решение, анализировать код, местами добавлять аннотации, если переполнение в данном месте ожидается. Но проблема сложная, решение не идеальное, будут ложные срабатывания. Торвальдс говорит, пока решение не будет идеальным, то он против. По сути именно он не предлагает решение проблемы, а ругается что предложенное решение мешает ему писать код.
интересно, что было бы, если бы ЗП Линусу платил Гугл
Возможно, что в этом случае, Линукс бы уже похоронили усилиями Гугла, а Линус бы работал над какой нибудь Глинус
Уволили бы due to failure to comply with the Code of Conduct.
Хорошо, что это не так ☝️
Торвальдс и не должен предлагать решение. Представьте, что в вашу работу постоянно лезут с идиотскими "оптимизациями", не зная, как это всё работает. А на ваши аргументы предлагают вам самим решить проблему.
Вообще-то Торвальдс прав и вполне внятно обосновал свою точку зрения. Если делаете инструмент, то от него должно быть больше пользы, чем вреда. Он даже расписал, в каких конкретных случаях переполнение используется осмысленно.
Существуют всяческие анализаторы кода, которые становятся умнее и умнее. Я не вижу какой-то принципиальной проблемы, чтобы научить анализатор правильно обрабатывать намеренные переполнения, имея перед собой паттерны их применения.
В таких разработках, как разработка компилятора, в первую очередь заботятся об обратной совместимости, потому что никому не надо переписывать то, на что потрачены тысячи человеко-лет. Я так понял, что Кис предлагает сломать совместимость. Вот только за это я бы его подальше ещё послал.
Может быть действительно, не стоит трогать компилятор и добавить статический анализатор в воркфлоу.
Рекомендую сначала почитать, что там предлагается.
Что в каких-то случаях переполнение используется осмысленно, все понимают, и Кук это сам описал, как и привел примеры где анализатор это может понять сам. if (var + offset < var) первым привел как раз Кук.
Во многих случаях анализатор понять намерения программиста, увы, не может, и не сможет.
Менять компилятор и ломать совместимость Кук не предлагает.
Он предлагает использовать и расширять sanitizers - динамические анализаторы.
А вот как менять они расходятся,
Торвальдс говорит пока анализатор не будет бесконечно умным, и понимать, что думал программист - и число ложных срабатываний будет близко к нулю - то есть никогда - инструмент вреден.
Кук говорит, что несколько простых аннотаций типа могут помочь анализатору понять намерение программиста, и предлагает их добавить
Сама идея добавлять аннотации выглядит как костыль для непродуманной технологии. Сами анализаторы могут поменяться, в них могут внедрить AI или что там модно будет. А аннотации останутся в исходниках. И в привычках мейнтейнеров (которые ещё поменять надо будет).
Моё мнение - тут надо искать zero cost решение. Всё по той же причине, про которую говорил Торвальдс - не надо дополнительной когнитивной нагрузки на мейнтейнеров. Им и так тяжело.
Плюс психологический такой фактор. Ты профи, работаешь двадцать лет с кодом, а тебя какой-то санитайзер заставляет расписаться, что ты точно знаешь, что тут может быть переполнение. Серьёзно?
А точно отсутствие аннотации -- это меньшая когнитивная нагрузка, а не большая? Без нее нужно в голове иметь маппинг "(файл, строка) -> необходимость переполнения", а с ней это в коде записано. Да, в переходной период может быть тяжело, так как отсутствие аннотации еще не означает, что ее там нет осмысленно, но тут уж извините, ничего не поделать.
Плюс психологический такой фактор. Ты профи, работаешь двадцать лет с кодом, а тебя какой-то санитайзер заставляет расписаться, что ты точно знаешь, что тут может быть переполнение. Серьёзно?
А это уже выглядит, как какой-то детский симптом. Ты точно профи?
То что аннотации останутся - это не баг, а фича. Анализаторы могут и будут меняться, существующие аннотации будут помогать им понять намерения программиста. Так же как полдюжины аналогичных аннотаций, уже добавленных в стандарт языка С, вроде restrict, [[nodiscard]], [[ fallthrough ]] - все они помогают компилятору понять намерения программиста и сгенерить производительный и безопасный код.
Ну ввели же в С++ аннотации noexcept, аля "клянусь что эта функция точно-точно не кидает исключений". И ничего, все живы и пользуются.
Моё мнение - тут надо искать zero cost решение.
Комментарий как раз и является таковым.
Тем более, что подобное решение уже реализовано.
Если в следующем коде:
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char **argv) {
switch (argc) {
case 4:
printf("%s", argv[3]);
/* fallthrough */
case 3:
printf("%s", argv[2]);
// fallthrough
case 2:
printf("%s", argv[1]);
}
return EXIT_SUCCESS;
}
убрать комментарии, то gcc начнёт выдавать предупреждения this statement may fall through.
А с этими комментариями — не выдаёт.
Совершенно очевидно, что он их читает и понимает.
С заглавной буквы — тоже понимает.
Вообще, в С++ есть атрибут [[fallthrough]]
...
Вообще, в С++ есть атрибут
[[fallthrough]]
...
Но в ядре нет C++.
И на С23 в ядре перейдут не скоро.
Однако, речь совсем не о fallthrough.
А о чём же тогда речь? О том, что компилятор читает комментарии? Я просто в погромизме не очень, так что не знаю, воспринимать комментарий, совпадающий с названием атрибута, но не имеющий его синтиксиса, как этот самый атрибут - это особенность конкретно этого компилятора или общепризнанная практика... Но в данном случае комментарии были написаны именно для компилятора, чтобы он не подозревал лишнего.
А о чём же тогда речь? О том, что компилятор читает комментарии?
Да, и о том, что эта идея не только пришла кому-то в голову, но и была реализована для fallthrough, и что эта же идея хорошо подходит в обсуждаемом случае, поскольку комментарии как раз и предназначены для описания напрямую не очевидных из кода вещей, а намеренное использование переполнения — вещь, напрямую из кода не очевидная.
Есть множество паттернов, определяемых анализаторами как Code Smells с выдачей предупреждений, включая упомянутый тут fallthrough. Нормальной практикой является аннотация с объяснением, почему это здесь так надо. Причем, подобные предупреждения могут быть подавлены на уровне конкретной строки, файла или проекта в целом.
Существуют всяческие анализаторы кода, которые становятся умнее и умнее. Я не вижу какой-то принципиальной проблемы, чтобы научить анализатор правильно обрабатывать намеренные переполнения, имея перед собой паттерны их применения.
А я вижу. Принципиальную проблему. Чтобы понять, что в данном конкретном случае происходит, нужно понять. Иногда — посоветоваться с другими в процессе, или спросить автора. Никакой статанализатор («стат» — в обоих смыслах, статический и статистический) на это не способен.
Именно поэтому в дискуссии и появились аннотации как способ сообщить о намерениях и классифицировать код автором, после чего тулзы могли бы работать с предопределённым классом ситуаций.
Он ругается, что предложенное решение создаёт проблем и когнитивной нагрузки больше, чем решает. (ну или так ему кажется).
Вообще-то он говорит: давайте не будем вносить изменение которое все сломает, а начнем постепенно добавлять мелкие улучшения которые помогут определять потенциальные ошибки. Я так понял, что решение предложенной Кисой сразу же объявит кучу кода сломанным, и придется руками проверять и добавлять аннотации везде где детектор увидел переполнение.
Ну, грубо говоря, вы не правы.
Гугл не предлагает решение, он предлагает затчку.
Линус указывает на то, что это не решение а затычка и что надо искать решение, а не хреначить костыли. Плюс поясняет, почему это костыль.
Да, это разные идеалогии. Для специалистов гугла нормально накидать "решений" (а потом похоронить продукт).
Линус не собирается хоронить ядро и потому говорит о системе правил. Просто затычки плохо затыкая одну проблему, пораждают новые, а поезд едет и ждать ему некогда. Следовательно через несколько итераций это всё аукнется, в том числе проблемами с совместимостью. Линус за 30 лет это понял.
Потому он прямым текстом говорит "будьте решением, а не проблемой".
Кук считает, что когда при сложении двух беззнаковых целых возникает переполнение, то это ошибка или особый случай, а Торвальдс считает, что это нормальная ситуация, потому что целочисленное сложение так и задумано, по модулю 2**N.
Вообще-то Торвальдс прав, стандарты языков C и C++ прямо говорят, что переполнение беззнаковых целых допустимо и так и задумано. Пусть Кук придумывает свой язык без переполнений и на нём пишет, если хочет.
А если бы было неопределенно мы могли бы иметь дополнительные оптимизации как в случае со знаковыми типами.
Кому нужно было бы определённое поведение, мог бы использовать явно переполнение add_wraparound.
кстати, в ядре Линкуса эти оптимизации отключены и для знаковых типов - Кук там упоминает флаг -fno-strict-overflow, который делает знаковое переполнение определенным
Логично, это трудноуловимые ошибки.
Просто нужно просто добавить явные функции и пусть кому нужны оптимизации пользуются одним, а кому не нужно другим.
Примерно то, что предлагает Кук - использовать явные функции или аннотации, когда вы ожидаете переполнения.
В C++ уже предложение ввести такие функции появилось.
Рано или поздно примерно такое же предложение придёт и в С , и тогда будет не о чем спорить.
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2024/p3161r0.html
в C23 уже добавили
ckd_add()
, ckd_sub()
, ckd_mul()
Ну обсуждается же в данном случае не вопрос, правильно ли сделано в языке Си или нет.
Кому нужно было бы определённое поведение, мог бы использовать явно переполнение add_wraparound.
Вот Линус как раз и сказал, что если заведомо хороший код, такой как хэш-функции, станет вдруг требовать вместо привычных u64 какие-то u64_wrap из-за того что одну случайную ошибку (ошибку переполнения unsigned ов) решили решить таким способом - то это *HORRIBLE* потому что добавляет когнитивную нагрузку на кернел девелоперов. У нас и так их мало.
Причем в ядре Линукса даже знаковое переполнение определено - Кук там упоминает флаг -fno-strict-overflow
, который делает знаковое переполнение определенным, несмотря на стандарт С/С++ где оно не определено. Можно сказать, это Торвальдс уже придумал свой язык и на нём пишет :).
Но то что поведение определенное с точки зрения языка, никак не помогает бороться с уязвимостями, и их число в ядре не уменьшается. Кук обсуждает и предлагает решение именно этой проблемы, а не стандарта языка.
Довольно странное решение проблемы: из-за того, что какие-то люди пишут программы с ошибками, давайте запретим использовать операцию сложения. А можно вообще тогда машинную арифметику запретить.
Кто предлагает запретить операцию сложения?
У Кука предложение продолжать использовать сложение и умножение, но (двумя разными способами, для обсуждения) объявлять, ожидаете ли вы при вычислениях с данным typedef переполнения.
Да, запретить. Как запретили goto. Если кому-то зачем-то раз в сто лет понадобится делать сложение по модулю 2^32, то пусть дописывает &0xFFFFFFFF
Как раз хотел написать про goto. Вообще-то в ядре и драйверах goto полно.
Вот да, @vadimr абсолютно прав. В ядре goto
используется в большинстве функций длиннее 10 строк. В конце каждой такой функции есть код с метками для освобождения ресурсов, типа такого:
exit_N: free(buf_n);
...
exit_2: fclose(file1);
exit_1: free(pBuf);
return result;
Соответственно, если не удалось открыть файл file1 fopen(file1)
, в ветке обработки этой ошибки делается goto exit_1;
ну давайте ничего не делать, наслаждаться уязвимостями и kernel panic и мечтать о славных временах, когда все программисты начнут писать код без ошибок.
Ну, как бы, вы считаете, что делать что-то, лишь бы делать и плодить новые проблемы, это вариант лучший, чем ничего не делать и оставить маленький шанс на кернел паник и уязвимости?
Делать что-то, как правило самый хреновый вариант. Надо как-то для начала обдумать, что и зачем ты делаешь и к чему это приведёт.
А я вот не понимаю, почему нельзя уже убрать эти заботливо разложенные в семидесятых годах грабли? Почему нельзя просто сделать стандартом по умолчанию выбрасывать эксепшн всякий раз когда происходит переполнение? Причём ладно бы это было в C++, ну нравится там людям обо всё спотыкаться, но в Java-то зачем переполение буфера починили, а вот это - оставили?
потому-что это дополнительное энное количество циклов CPU на КАЖДУЮ математическую операцию
В семидесятые это был бы аргумент, а сейчас... слышали ли Вы про Python и Java? Ну и потом, если это такая проблема, то можно добавить пару сотен транзисторов в современные процессоры, чтобы контроль флага переполнения был аппаратный.
Ну кто-то программирует на питоне и джаве, а кто-то лишний процент эффективности выжимает.
Мне лично даром не нужен процессор с такими транзисторами.
Ну, тогда получите уязвимости на основе арифметических переполнений.
Это наименьшее зло в данной ситуации.
Вы серьёзно?
Абсолютно. Чтобы закрыть уязвимости, есть другие средства, а производительность никакими примочками не повысить.
Это не говоря о том, что вообще-то никто не доказал, что предлагаемые дисциплинарные меры по избиению палками ведущих разработчиков за неподобающее поведение уменьшат число уязвимостей.
Ну отлично. Давайте тогда выход за пределы буфера тоже перестанем контролировать, ибо вредит производительности. Вот веселуха-то начнётся ))
Вообще-то он и не контролируется.
Поэтому-то сишные программисты сталкиваются с забавными багами, которые стоят многих часов отладки. Суть такого бага в том, что программа падает с Access Voilation в месте, где она казалось бы в принципе не может упасть. Программист просматривает эту строчку кода и её ближайшие окрестности - и сильно удивляется, ибо распилить память там попросту нечему. Самое интересное, что стоит только чуток перетасовать код (скажем, поменять местами два несвязанных блока кода) - и ошибка таинственным образом исчезает... до следующего раза, когда очередное изменение кода не заставит её вновь всплыть.
Столкнувшись с такими чудесами, новички вообще впадают в ступор. А разгадка проста: где-то совсем в другом месте произошёл выход за пределы массива/буфера. Скажем, цикл должен быть до (n-1), а его ошибочно сделали до n. В итоге вместо записи очередной ячейки портятся случайные данные, итог - падение программы в совершенно случайном и не связанном месте.
Ну что поделать, так устроен процессор на большинстве машинных архитектур, и эффективная по скорости выполнения реализация кода наследует эту проблему. А так-то можно включить контроль выхода за границы массива опцией компилятора.
Правда, я встречал на работе как минимум одну функцию, которая корректно работает уже десятки лет (ещё с Фортрана для VAX была в своё время переписана на Паскале и Си для Intel), и при этом падает при включении контроля границ массива. Исследование показало, что там в одном месте читается лишнее значение, которое потом не используется. Переписать этот крайне запутанный код никто не взялся.
у стандартного вектора в C++ оператор[] ничего не проверяет. Если нужны проверки - .at()
Это и сейчас аргумент для софта, ради которого, собственно, используют С++, а не питончик и джаву.
Вот поэтому на С++ только и пишут, что ядро. А везде, где можно, переползли как минимум, на джаву, ибо задолбались спотыкаться об "особенности реализации"
А на чем написана сама джава машина?
Хоть на иврите. Какая разница?
Разница в том, что язык Си, на котором написано именно ядро линукс, и многие другие низкоуровневые вещи, обычно пишут не быстро тяп ляп и в продакшен, а учитывая что эти вещи в основном являются платформой для основной массы прикладных приложений, выдавливают максимум из железа и архитектуры.
Поэтому компилятор должен штатно обрабатывать все возможные варианты, которые могут прийти в голову разработчику, если он видит возможность что-то ускорить или оптимизировать и не выдавать ложных ошибок.
А в прикладном программировании тормоза зачастую не критичны.
Ну вообще уже давно пытаются переписать на Java, с переменным успехом.
на С и C++ написано абсолютно всё, при помощи чего вы оставили этот комментарий. Кроме самого кода этого сайта, интерпретатор которого тоже написан на С или С++.
Потому что add rax, rbx
(для остальных архитектур найдёте сами) не выбрасывает исключений. Максимум, устанавливает флаг переноса.
Вот ведь проблема... Как думаете, современные компиляторы с задачей проверять флаг переноса и выбрасывать исключение справятся, если захотеть?
Справятся, конечно, только программы будут в 10 раз медленнее работать.
Да? Я не знал, что JO работает в 9 раз дольше чем ADD ))
Условные переходы сбрасывают конвейер.
Только когда переход нужен. В нашем случае это будет только при переполнении.
В любом случае.
Это почему же?
Потому что в этом смысл конвейера. Нет отдельных операций.
Вам читать про предсказание ветвлений. Или вот видео.
Со времен появления спекулятивного исполнения влияет очень мало. Причем, в часто выполняемом коде, предсказание будет 100% точным, пока реальное переполнение не случится, влияние будет близко к нулю,
"Но не ноль же! А значит на буй безопасность!" -- говорит Торвальдс.
Да причём здесь спекулятивное исполнение? Ради ветвлений надо конвейер заменять отдельными скалярными операциями.
Возможно вы когда говорите "конвейер" имеете в виду параллелизм SIMD?
Когда я говорю "конвейер", то действительно имею в данном случае в виду SIMD. "Параллелизмом" я бы это называть не стал, это векторно-конвейерные операции.
Если ещё рассматривать параллелизм, тогда всё ещё хуже, так как обработка исключительных ситуаций должна быть синхронной. Но я не думаю, что ядро особо много параллелится.
Тогда непонимание вызвано этой нестандартной терминологией - обычно конвейер (pipelining) обозначает возможность процессором выполнять цепочку разных операций, не дожидаясь результатов предыдущих. И спекулятивное исполнение тут очень помогает, потому что позволяет продолжать эту цепочку даже после условного перехода.
SIMD это способность выполнять одну операцию над многими данными, но в данной дискуссии это вообще не релевантно - в ядре Linux, насколько я знаю, оно не используется, по крайней мере на x86, из-за высокой стоимости сохранения расширенных регистров.
Терминология самая что ни на есть стандартная. Конвейеризация бывает у команд (instruction pipelining) и у данных (data pipelining). Спекулятивное исполнение относится к конвейеризации команд и, конечно, ускоряет условные переходы, но даже близко не до такой степени, как если бы этих переходов не было, именно из-за конвейеризации данных.
Что касается SIMD, то в ядре Linux для x86 оно используется именно там, по поводу чего ругался Торвальдс – в вычислении хешей, шифровании и тому подобной работе с большими массивами, из-за которой и ведётся весь скандал. В ядре для этого предусмотрены макросы kernel_fpu_begin() и kernel_fpu_end().
В любом случае, как генеральное решение проверка статуса каждой арифметической операции не подходит, и чем дальше развивается архитектура процессоров, тем меньше подходит.
Совершенно не стандартная, смотрим даже вики https://en.wikipedia.org/wiki/Pipeline_(computing)
Там есть data pipeline - но под этим подразумевается именно последовательное выполнение, data processing elements connected in series. SIMD это другое, там расширенные регистры и параллельное выполнение, а не конвейер.
kernel_fpu_begin()/end() это замечательно, но именно потому и существуют - что надо вызывать перед тем как пользоваться, автоматически как в user mode регистры не сохраняются. Соответственно автоматическое использование SIMD инструкций компилятором отключено, чтобы он не сгенерировал их вне этого блока. Можно было бы конечно pragma писать на конкретную функцию, но они это обычно не используют, пишут ручками. То есть опять в дискуссии про производительность всё это не релевантно, никакого замедления в 10 раз не будет.
Ну что я вам могу сказать? Не надо изучать программирование по википедии.
SIMD – это тип системы команд, а конвейер – устройство исполнительных блоков процессора. Первое в реальной жизни подразумевает второе. Одна инструкция оперирует множеством данных именно затем, чтобы загрузить их в конвейер. Ещё это называется “потоковая обработка”, и к параллелизму имеет весьма косвенное отношение.
То есть опять в дискуссии про производительность всё это не релевантно, никакого замедления в 10 раз не будет.
Производительность, как правило, определяется обработкой наиболее тяжёлых инструкций, то есть в данном случае именно работой с массивами.
Вы таки совсем не понимаете разницу SIMD и pipelining, поэтому и ссылка на википедию (она про общую терминологию, а не изучение программирования). Конвейер - это по определению цепочка действий над одним объектом, пока один станок прикручивает шины к одной машине, другой вешает двери на вторую, третий красит третью. Конвейер используется для обычных команд. SIMD это не подразумевает и практически никогда не использует, в современных CPU достаточно арифметических устройств чтобы выполнять все SIMD вычисления одновременно, благодаря чему и получается что SIMD операция над 4 операндами может выполняться столько же, сколько обычная над одним.
Производительность, как правило, определяется обработкой наиболее тяжёлых инструкций, то есть в данном случае именно работой с массивами.
Да, солнце теплое, а вода мокрая, но что вы хотите этим общим утверждением досказать? Из-за kernel_fpu_begin()/end() автоматическое использование SIMD инструкций компилятором отключено, чтобы он не сгенерировал их вне этого блока. Эти тяжелые инструкции в ядре 100% будут написаны на ассемблере, а не компилятором - поэтому в дискуссии о замедлении кода из-за проверок компилятора - совершенно не релевантны.
Вы таки совсем не понимаете разницу SIMD и pipelining
Чтобы вы не продолжали сравнивать тёплое с мягким, почитайте теорию, например, здесь (это статья специалистов Intel). Там на 9 странице даётся объяснение SIMD execution model.
A SIMD loop conceptually has logical iterations numbered 0,1,...,N-1, where N is the number of loop iterations. The logical numbering denotes the sequence in which the iterations would be executed if the associated loop(s) were executed with no SIMD instructions. A SIMD function has a logical number of invocations numbered 0,1,...,VL-1, where VL is the number of SIMD lanes [...]
SIMD заключается не столько в том, что 4 числа в регистре процессора Intel обрабатываются одной инструкцией AVX одновременно (т.е. имеются 4 линии SIMD), а главным образом в загрузке инструкциями AVX конвейера данных. Что могло бы теоретически выполняться и на одной линии.
Вас даже не смутило что во всей статье ни разу не встречается слово pipeline / pipelining? Повторяю, к pipelining / конвейеру это не имеет никакого отношения. Концептуально конечно это можно объяснять через цикл, реально ничего такого нет. И если вас интересует производительность, то вас интересует микроархитектура, а не концептуальная модель.
А главное, как я сто раз объяснил, всё это не имеет отношения к обсуждаемому вопросу про С и компилятор, потому что в ядре это пишется на ассемблере, а не компилятором.
Буфер предсказания переходов не бесконечен, и существуют ситуации, когда производительность значительно деградирует из-за его переполнения.
Не всегда и не везде. К тому-же бывает такая штука, как условное выполнение опкода, которое конвеер не сбрасывает. Хотя всё эти фичи зависят от архитектуры. Вся прелесть C в том, что он хоть и близок к железу, но всё таки от конкретной архитектуры не зависит.
На практике в повторяющемся коде, в котором могло бы произойти переполнение, скорее всего не будет команды ADD, а будет какая-нибудь VPADDD, которая вообще никаких флагов по поводу переполнения не формирует по понятной причине.
Я про конвейер данных.
Так от архитектуры зависит, не вижу причин для спора. BTW я еще ни разу не встревал архитектуры, в которой есть команда add, которая не аффектит флаги и одновременно нет команды add, которая аффектит флаги.
Я припоминаю, что есть архитектуры вообще без флагов.
Но в данном случае, конечно, можно заменить векторную инструкцию на скалярный цикл с флагами и блекджеком, но это и будет в 10 раз медленнее.
Это мы ещё не обсудили асинхронную обработку исключительных ситуаций и т.д. и т.п. Это всё очень дорогое удовольствие с точки зрения эффективности, не зря в вещественных числах придумали в конце концов всякие инфы и наны вместо исключительных ситуаций.
P.S. В архитектуре MIPS беззнаковое сложение не формирует никаких признаков переполнения.
программы будут в 10 раз медленнее работать.
Может, это наконец научит современных, прости господи, программистов, оптимизировать код? (вспоминает с содроганием драйвер одного устройства, напсанный на чём-то электроноподобном, занимавший полтора гига памяти).
"Нет, сынок, это ты будешь меньше кушать"
Так Линус же умеет оптимизировать. И защищает принятые у знатоков оптимизации приёмы от нападок знатоков чистого кода.
Может, это наконец научит современных, прости господи, программистов, оптимизировать код?
Путём вставки бойлерплейт кода научит оптимизировать? Да, ровно наоборот же - зная, что каждая простая операция сложения/умножения, так-то мапяшаяся на одну инструкцию, будет обёрнута килограммом проверок, кто в своём уме станет заморачиваться с оптимизацией чего бы то ни было?
драйвер одного устройства, напсанный на чём-то электроноподобном
Ну, вот откуда это стремление и ядро линукса превратить во что-то электроноподобное?
Конечно справятся. Вы готовы к тому, чтобы любимые многими Python и Java работали раза этак в 3 медленнее? Ну камон, целочисленная арифметика в кольце - это основа компьютерных вычислений. Если для кого-то это новость, то это говорит только о серьёзных пробелах в фундаментальных знаниях, не более.
Вы уж определитесь, в 10 или только в три раза ))
И где же реально нужна эта целочисленная арифметика в кольце? И там где она реально нужна почему не сделать что-то вроде AND RAX, 0FFFFFFFFH ?
Причем тут "нужна" и "не нужна"? Она есть, и это реальность. Хотите другую - делайте своё ядро и компилятор к нему. Получите, возможно, прекрасную вещь, но нафиг никому не нужную.
PS. BTW, на кольцах построено довольно много быстрых хэш-функций. Вот это то, что первым пришло в голову.
А вычисление хэш-функций и сейчас пишется на ассемблере, так что не критично. Ну и прагму можно добавить, что вот здесь идёт вычисление по модулю, то ли 2^32, то ли 2^64, хе-хе )
Я не заметил в той дискуссии никого, кто бы предлагал отменить операции которые могут молча вызывать переполнение, или менять хеш-функции. Предлагают если вы пишете хеш-функцию, где переполнение ожидается - использовать соответствующую аннотацию (пару вариантов Кук предложил), которая скажет - тут это норм, не проверяй. То же можно сделать для операций где важна производительность, и кто-то очень внимательно проверил и доказал корректность или невозможность переполнения. А вот по умолчанию - начинать с ошибок в тестах под санитайзером, потом можно и при выполнении падать.
В целом, я не говорю, что сама идея дурацкая. В целом, здравая, но непонятно как реализуемая. Проводить проверку на переполнение после каждой операции - затратно и сломает много кода. Вводить дополнительные операторы, какие, как? Вот операторов циклических сдвигов до сих пор не завезли, а уж сколько лет прошло. Прагмами? Ада и багов будет еще больше. Функциями? Ну вот так и поступают, если надо.
Там собственно и есть предложение, как. Атрибутами, и в большинстве случаев не на уровне функции, а на уровне типа. Один раз typedef unsigned int __wraps u32_hash;
- и операции с этим typedef могут использовать переполнение сколько хотят. Читаемость только возрастает, хотя вначале придется поработать.
Вот ведь проблема... Как думаете, современные компиляторы с задачей проверять флаг переноса и выбрасывать исключение справятся, если захотеть?
Просто замечу, что инструкцию процессора INTO
, которая делала именно то, что вы описали, выкинули при переходе с 32 на 64 бита. Потому что ей никто никогда не пользовался.
Потому что это не грабли, а особенности машинной арифметики по сравнению с математической, которых и без того полно.
Вообще надо учитывать, что ядро линукса пишут весьма сведущие в программировании на Си люди. И это выглядит примерно как то, когда к опытным лётчикам-испытателям приходит какой-то мужик и говорит: а давайте запретим трогать вон те ручки на пульте, как-то они, мне кажется, мутно работают.
Запретительными мерами такого рода надёжность программного обеспечения увеличить невозможно.
Ну, может уже пора убрать эти особенности? В чём их преимущество? "Мы крутые парни, мы приучились не спотыкаться об эту колдобину" - так себе аргумент.
А в чём их недостаток? Компьютерные числа ограничены, в отличие от математических, и это уже сама по себе особенность, которую убрать не представляется возможным. А переполнение – просто следствие.
И в итоге предлагаемых мер – ну поменяете вы 6 уязвимостей линукса на 6 кернел паников, что это даст?
Если бы эти "весьма сведущие в программировании на Си люди" не создали бы в ядре сотни багов, и по полдюжины обнаруживаемых крупных уязвимостей из-за целочисленного переполнения в год, к ним бы никто не приходил. А так они напоминают не крутых летчиков-испыталей, а врачей которых Земмельвейс пытался заставить мыть руки (врачи принимали роды после морга, и убивали на порядок больше рожениц, чем рождение дома). Земмельвейс сократил смертность в 10-20 раз, но "опытные" летчики врачи оскорбились, не могут же они быть источником заразы, и Земмельвейса затравили.
А по другой версии, хоть он и был прав, но его не стали терпеть из-за ужасного характера, создавал проблемы, невыносимые условия для работы.
Ну да, совершенно невыносимые условия для работы - минут 15 мыть руки после разделывания трупа, перед тем как роды принимать. Целых 15 минут потратить, чтобы снизить смертность в 20 раз, это же перебор, пусть лучше дохнут. Или аннотации на typedef поставить, чтобы указать, ожидать ли с этим типом переполнения - это же сколько лишней работы, пусть лучше находят каждый месяц новую уязвимость в ядре. /s
Rust умеет паниковать при внезапном переполнении в отладочной сборке, а также предоставляет функции типа overflowing_add и saturating_add для случаев когда точно нужно вполне конкретное поведение сложения
И как раз на Rust уже можно кодить драйвера для линукса)
В Rust компромисс сдвинут в другую сторону, но это все равно не решает проблемы. Кто будет всю жизнь гонять ядро в отладочной сборке?
Кук мечтает переделать компиляторы. Тогда нужно начинать со стандарта С. Если новинка окажется полезной, то лет через 10 эти изменения может быть докатятся и до ядра.
Прогресс. Но если это только в отладочной сборке, то это новые грабли, более изощрённые. Ибо сборка для прода потом встретится с невиданными ранее данными, вызывающими не переполнение, а неожиданные эффекты. А на тестовой сборке это будет воспроизводиться по-другому, счастливой отладки!
Переполнение для беззнаковых типов это не UB. Мне казалось что в Java нет unsigned типов. Что вы собрались чинить?
Кук предложил чисто корпоративный подход - давайте сделаем переполнение отдельным инструментом и будем использовать только там, где это действительно нужно, обернем в правила и аннотации. А Торвальдс воспринял подобное как покушение на его творческие свободы и видение. Это принципиально нерешаемые разногласия проистекающие из разных целей.
Торвальдс посоветовал Кису Куку
Он что-то знал...
Наверное, Торвальдс тут все же "более прав", но вот с софт-скиллами у него все так же плохо.
А я вот иногда думаю – в каком году ядро начнут переписывать на rust? Я в курсе про драйвера, я именно про основной функционал. А в том, что это лишь вопрос времени – у меня и сомнений нет.
у меня тоже такое впечатление, стоит взглянуть само обсуждение -
см. https://lore.kernel.org/lkml/202404291502.612E0A10@keescook/t/#u
Линус лучше знает все слабые места, и приоритеты у него отличаются, все вокруг парадигмы "лучшее - враг хорошего"
в каком году ядро начнут переписывать на rust?
Вроде как безопасные фичи руста работают на древовидных структурах данных, а в ядре есть много списков, иногда даже циклических. Если писать ядро раньше чем язык решит эту проблему то какая-то часть ядра будет в unsafe.
rust - руст.
bus - бус.
suck - сук.
fuck - фук.
Язык не решит эту проблему, она как бы это сказать... Математическая и в общем виде не решаемая. Так что какое то количество unsafe останется, именно как частные решения.
Я не вижу тут правых и неправых, я вижу здесь спектр решений на линейке от "всё как есть" <-> до "полная безопасность". Можно по Торвальдсу оставить всё как есть, можно небольшими шагами, как предлагает Кук, попытаться сделать С чуть безопаснее, можно плюнуть на Торвальдса и переписать всё на Rust, сделав шаг заметно дальше. Небольшие ядра на Rust уже есть, вопрос вложится ли кто-то, чтобы довести одно из них до нужного состояния. И тут много зависит от Торвальдса - если он будет продолжать упираться, и мешать попыткам двигать С чуть-чуть в сторону большей безопасности, то кто-то может совершить таки прыжок на Rust.
Я все ещё совершенно не убеждён.
...
Но я на 100% убеждён,
Когда Linus уже повзрослеет и поймёт, что авторитетов не существует?
Среди первоначальных идей — лучше использовать санитайзеры на основе компилятора или возможности языка C для перегрузки операторов без искажения имён.
Комментарии, читаемые компилятором, решают проблему.
Торвальдс абсолютно прав. Кольцевое поведение арифметики нужно везде (начиная от временных меток и кольцевых буферов и т.д., заканчивая фильтрами и цос). Вообще, кольцевая арифметика реализует важную парадигму (полезные данные в младших разрядах хранятся, бесполезные в старших автоматически отбрасываются). Нормальные программисты это всё понимают подсознанием и справедливо считают что языки/тулзы без кольцевого поведения целого по умолчанию - бесоплезный мусор, которому место на помойке. Проблема в толпах тупых быдлокодеров, которые лезут со своим "это никому не нужно". Очень хорошо понимаю усталость Торвальдса, который десятилетиями от всего этого отбивается.
Ну если основатели и корифеи так между собой общаются, то я понимаю, откуда берётся доброжелательность, тактичность и отзывчивость в мир Линукс )
Никто "не общается" в привычном смысле этого слова, там не друзья сидят.
Есть Линус, который уже сколько там, 30+ лет занимается разработкой? Вот он сидит и занимается разработкой ядра. К нему приходит некто из Гугла или откуда-то там, и предлагает кое-что переписать в ядре - заодно нагрузив проверками часть мейнтейнеров (все ради безопасности, разумеется, как и уже де-факто невозможность нормально зайти без кучи предупреждений на статичные сайты через HTTP)
Линусу это не сдалось (факт: кто поддерживает ядро все это время? кто будет поддерживать дальше, т.к. с этим связана его репутация? Кук?), и он просит не лезть.
Линукс дафига свободный, если человек сильно хочет сделать все БЕЗОПАСНО, он может взять, форкнуть, и доработать сколько-то там миллионов строк кода, ему никто не запрещает.
Любопытно, что Ваш ответ тоже выдержан строго в духе линукс-комьюнити. )
"Тебе надо - ты и форкай" ))
линукс-комьюнити
Free and Open-Source Software комьюнити тогда уж.
Да и если вам лично ваш сосед будет говорить сделать с вашей собственностью (допустим, публичной) что-то что вы не планируете делать то я бы посмотрел на ваш стиль коммуикации. Например, у вас есть магазин, а вам упрекают что пандус смотрит в неудобную сторону, сделайте второй пандус пожалуйста.
Вот только не надо аналогий с физическим миром, потому что там как раз и существует duty of care -- во многих юрисдикциях вы именно что обязаны заботиться о всех людях, попадающих на вашу собственность (даже против вашей воли), а в мире софта такой обязанности нет, всё AS IS.
Вы обязаны заботиться, если вы ведете бизнес в этой юрисдикции, или тем или иным образом являетесь гражданином с правами и обязанностями. (У меня есть свое мнение относительно навязываемых требований владельцу, но обсуждать его я не хочу)
А в мире софта - да, пожалуйста, вот OpenSource лицензия, на этом мои обязанности исчерпываются. Попытки ввести обязанность владельцев что-то делать, на мой взгляд, приведет к уменьшение желающих это самое делать. Это как-то работает с бизнесом (тот деньги зарабатывает) или с гражданами (потому что тем деваться некуда), а вот со свободным программистом...
Нет, если вы купите, например, участок земли в далёком захолустье в США, то у вас возникнет обязанность заботиться о безопасности тех, кто там будет ходить. Поэтому если вы например разложите там капканы, не огородив территорию и не поставив предупреждающие знаки, что тут ходить нельзя, потому что опасно и на свой страх и риск, будете нести ответственность за тех, кто в эти капканы может попасть. Независимо от того, чей вы гражданин и ведёте там бизнес или нет.
В софте иначе и я эту разницу приветствую. Но делая проект, затрагивающий миллиарды людей, то ответственность, как минимум моральная, всё равно появляется. И решение игнорировать заботы и интересы пользователей несёт за собой последствия. Это не тоже самое, что отправлять в пешее путешествие пользователей пет-проекта на три калеки.
Если от уязвимостей вызванных сочетанием факторов в С/подходе Линуса/исторического пути развития, страдают многие люди, то подход "жрите что дают, бесплатно ведь" не подходит, надо искать компромиссы. Потому что альтернативные варианты тоже не идеальны -- если гугл уйдёт делать свой линукс, ещё кто-то уйдёт делать свой, то фрагментация (и так ужасная) будет ещё больше и кто от этого выиграет?
Потому что альтернативные варианты тоже не идеальны -- если гугл уйдёт делать свой линукс, ещё кто-то уйдёт делать свой, то фрагментация (и так ужасная) будет ещё больше и кто от этого выиграет?
Тут такой классический вопрос - кто будет ОПЛАЧИВАТЬ решение этой проблемы?
На мой взгляд, нечестно, если разработчик сделал хорошее решение, миллиарды пользователей им пользуются И ничего не платят ему (потому что по лицензии), но при этом с него что-то требуют.
В таком случае (имхо) надо перезаключать общественный договор в рамках конкретной системы. И главный вопрос - почему этим должен заниматься главный разработчик в своё свободное время? Не стоит ли обществу дать что-то в ответ - то, что разработчик посчитает ценным?
Ну, так гугл и оплачивает и в разработку вкладывается, тут же весь сыр-бор о том, что разные разработчики имеют разное видение и нельзя сказать, что это просто какие-то левые люди пришли и начали требовать им бесплатно что-то разработать. Вот гугл хочет двигать в сторону повышения безопасности ядра, Линус не видит этот как приоритет (у него на компе всё нормально, все проблемы с утечками случаются у кого-то ещё)
Ну, так гугл и оплачивает и в разработку вкладывается
Тогда это конфликт "кто в команде разработки определяет дальнейшее развитие". Гугл может сказать "делайте так или обрежу финансирование" - это тоже рычаг, со своими преимуществами и недостатками. Пусть решают сами. Не хочет Гугл - может еще кто будет финансировать проект, на Линукс желающих может быть много.
Я поддержу изначального разработчика (Линуса), потому что у него есть репутация - человека, который создал и держит Линукс. У Гугла сейчас в основном репутация "мы закрыли еще один проект потому что".
А тут в общем-то и не обязательно выбирать сторону и стойко за неё стоять, сами разберутся. Но я, например, был бы за тех, кто предлагает безопасностью заниматься, потому что мне безопасность важнее, чем удобство разработчиков. Но с другой стороны, интересы разработчиков тоже нельзя игнорировать, потому что без них проекта вообще не будет.
Поэтому такие статьи, вырывающие внутреннюю кухню из контекста во внешний мир -- вообще не несут никакой пользы, а чисто служат для хайпожорства ("линус послал гугл! Всем читать!")
В целом согласен - но прикольно иногда почитать комментарии и поучаствовать в дискуссии :)
Тем более что мне лично все-таки достаточно важно озвучивать важность "личности разработчика с репутацией", в то время как большинство предлагают заниматься чем-то ради общественного блага. Приходится объяснять, как функционирует опенсорс и почему так.
Я поддержу изначального разработчика (Линуса), потому что у него есть репутация - человека, который создал и держит Линукс.
Если касаться только технической стороны дела, то Linus давно похоронил свою репутацию.
Достаточно взглянуть на это:
Standards and reality
Standards are paper. I use paper to wipe my butt every day. That's how much that paper is worth. Reality is what matters.
и на это:
About testing
"Regression testing"? What's that? If it compiles, it is good; if it boots up, it is perfect.
Ну, а касательно других аспектов, он сам откровенно признался:
Linus Torvalds - "bastard"
I'm a bastard. I have absolutely no clue why people can ever think otherwise. Yet they do. People think I'm a nice guy, and the fact is that I'm a scheming, conniving bastard who doesn't care for any hurt feelings or lost hours of work, if it just results in what I consider to be a better system. And I'm not just saying that. I'm really not a very nice person. I can say "I don't care" with a straight face, and really mean it.
Вот ещё цитата, которая закрывает любую возможность серьёзно относиться к Linus'у:
I'm always right
I'm always right. This time I'm just even more right than usual.
Здесь собрано множество подобных цитат.
Так что, я бы не был столь категоричен относительно репутации.
Если касаться только технической стороны дела, то Linus давно похоронил свою репутацию.
Если касаться ТЕХНИЧЕСКОЙ стороны, то у Линуса работает, а у других нет.
А вот если смотреть, кто когда что сказал и как это можно интерпретировать...
Если касаться ТЕХНИЧЕСКОЙ стороны, то у Линуса работает, а у других нет.
К сожалению, не работает у Linus'а.
Лет 7 назад хотел проверить поведение множества вложенных tag'ированных VLAN'ов. На каждый вложенный VLAN тратится 4 байта, стандартный MTU сетевого интерфейса составляет 1500, поэтому я написал скрипт, который создаёт 350 вложенных enslave-интерфейсов, чтобы получить 350 вложенных tag'ированных VLAN'ов, чтобы, в результате, 1400 байт ушло на tag'и, и 100 байт осталось на другие заголовки и на payload пакета.
Скрипт логировал свои действия, чтобы я мог оценить скорость и динамику создания вложенных интерфейсов, поэтому я увидел, как после создания 301-го ил 302-го вложенного интерфейса ядро зависло. Курсор мыши намертво "прилип" к экрану, и даже SysRq не работал, пришлось перезагружаться. Ядро было версии 3.16.
Кстати, поведение ядра здесь замечательно сочетается с подходом Linus'а к вопросу тестирования:
About testing
"Regression testing"? What's that? If it compiles, it is good; if it boots up, it is perfect.
Не так давно решил проверить, что изменилось с тех времён.
Сначала было удивительно, потом было очень смешно.
После 8-ой вложенности выдаёт ошибку, что слишком много вложенностей, не могу добавить ещё одну вложенность.
Замечательное решение.
А вот если смотреть, кто когда что сказал и как это можно интерпретировать...
Не думаю, что там что-то, специально меняющее смысл без контекста. В частности, по поводу Standards and reality однозначно можно интерпретировать.
Когда в Shockwave Flash неправомерно использовали memcpy
вместо memmove
для копирования перекрывающихся областей памяти (чтобы побыстрее копировалось), а затем эти заботливо разложенные грабли сработали, когда для одной из архитектур реализация memcpy
изменилась, но в пределах стандарта, звук Shockwave Flash стал искажённым, потому что копирование теперь происходило неверно.
Linus требовал вернуть предыдущую реализацию memcpy
вместо того, чтобы требовать исправить код, неправомерно использующий memcpy
вместо memmove
. Когда же его ткнули носом в стандарт и прямо и недвусмысленно сказали, что ошибка — в коде Shockwave Flash, и поэтому исправлять следует именно там, а не где-то ещё, Linus выдал свой позорный опус про стандарты:
Standards and reality
Standards are paper. I use paper to wipe my butt every day. That's how much that paper is worth. Reality is what matters.
Можете сами почитать здесь.
С этого момента я понял, что, с технической точки зрения, по крайней мере, для меня, Linus — 0, хотя в тот момент мне поверить в это было трудно, но я смог, с фактами не поспоришь.
А как вы предлагаете? Мне надо, но работать будете вы причем бесплатно?
Да я собственно веду проект русского опенсорс голосового помощника Ирины - в этой нише, он, вероятно, один из самых крупных.
Так что, увы, Линуса очень хорошо понимаю. Опенсорс разработчик - это не компания, где захотел - пришел, захотел - бросил проект через полгода, ушел на другой. Хороший девелопер отвечает за свой проект перед собой и концепцией; здесь его репутация.
Люди, "дающие советы, как лучше сделать другим", как правило ЗАСЛУЖЕННО репутацией не обладают - потому что они "дали совет здесь, дали совет там" - а если все развалилось, так "они ж только совет дали, это исполнители виноваты".
Поэтому правило, да такое - готов нести ответственность? Делай форк и поддерживай сам, или делай пулл-реквест и договаривайся с командой. А вот давить на "общепринятые практики" не стоит - проект обычно выживает не потому что он "как все" - обычные проекты долго не живут - а потому что он "другой".
(Еще вариант - "профинансируй изменения", но я тут его не рассматриваю)
Линуса очень хорошо понимаю
Я понимаю его отрицательную реакцию на идею и поддерживаю, т.к. похоже, что предложено реально плохое решение существующий проблемы.
Но чего не принимаю и не понимаю - так это такой тон в деловой/комьюнити переписке. Если посмотреть на английский текст, то как мне кажется, так могут писать только очень хорошим друзьям, но никак не в паблик общении. Не отсюда ли вытекают и остальные реальные проблемы роста сообщества Linux/Opensource? Cнобизм, неправильно понятая элитарность, порой явное хамство, демонстративное отрицание стандартов, выдаваемое за оригинальность, либо показное унижение участников - откуда это взялось, и почему мало кого это беспокоит?
предложено реально плохое решение существующий проблемы.
Оно не то, чтобы плохое. Оно не соответствует команде и истории проекта - это то, за что Линус отвечает. Разница имхо очень важна - люди часто не понимают, что решение не плохое, а неподходящее для конкретной ситуации.
Но чего не принимаю и не понимаю - так это такой тон в деловой/комьюнити переписке.
Тут такое дело - хороший Опенсорс крутится вокруг решения проблем, не вокруг их обсуждения (что, сорри, часто в деловых компаниях есть).
Официально бы это звучало так: "Ваше предложение очень интересно, мы его рассмотрим" (задвигается в дальнюю часть беклога и не поднимается совсем, но никто это не видит, потому что это непублично)
В опенсорсе +- принято честно давать обратную связь, чтобы человек мог поправить свои ошибки. Иногда это слишком сильно, да - потому что специальных "менеджеров по работе с комьюнити" тут на зарплате обычно нет, да и для взаимодействия с разработчиками-инженерами (а не мимокрокодилами "я поставил, у меня не работает") они не очень подходят.
Собственно, фразу Линуса можно перевести так: "Смотрите, я считаю, что архитектурно это ок как есть, потому что это специфицировано и коре команда об этом знает. Пожалуйста, прекратите спамить везде этим вопросом (я так понял, чувак постоянно поднимал этот вопрос в разных частях системы и пытался вызвать обсуждение, которое съедает ресурсы) и попытайтесь сделать хорошее решение проблемы".
Не отсюда ли вытекают и остальные реальные проблемы роста сообщества Linux/Opensource?
Смысл в том, что нет "сообщества Linux/Opensource", вы не поверите. Так же как нет "русского сообщества" как единой массы. Есть ряд людей, которые занимаются своим делом - вы можете встретить среди них как профессоров, так и бомжей - и культура общения и потенциал роста у них у всех будет очень разный.
Попытка менеджить "рост опенсорс сообщества" - ну, имхо, плохая. Все равно что "рост культуры русского сообщества" - звучит скорее как политически красивая возможность получить ресурсы на развитие чего-то.
Основа сообщества простая: "У тебя есть возможность поправить и улучшить код так, как ты считаешь нужным". Всё. Тебе никто не обязан помогать, решать твои проблемы, и так далее. Если ты считаешь, что ценен для сообщества - в принципе, есть возможность доказать это. Я засылал в меру кривые пулл-реквесты в смежные проекты (китайский и английский) - и авторы их правили и принимали, спасибо им большое. Потому что мейнтейнеры знают - на 10 говорящих есть 1 делающий что-то толковое - и его нужно поддерживать.
Смысл в том, что нет "сообщества Linux/Opensource", вы не поверите.
Примерно так? )
я так понял, чувак постоянно поднимал этот вопрос в разных частях системы и пытался вызвать обсуждение, которое съедает ресурсы
Если это действительно так, то может тут проблема в том, что человек один раз спросил, его проигнорировали, второй раз, третий... Сколько же раз нужно спрашивать, чтобы боги соизволили ответить? И это... люди как бы смертны, это точно разумно -- держать все в голове кучки плотно работающих с кодом, а остальным типа рыпаться в их вотчину не нужно?
Мне кажется, достаточно простым решением было бы ввести в язык Си что-то вроде оператора checked. Старое поведение осталось бы старым, но если нужно перехватить установку флага переполнения и по этому условию что-то сделать - было бы в самый раз.
Вариантов-то много с точки зрения языка. Но это вопрос к комитету ISO/IEC JTC1/SC22/WG14, который занимается языком Си, а не к разработчикам ядра Линукса.
У Гугла есть же масса своих проектов. Пусть сделают для себя, обкатают и покажут всему миру success stories. Зачем с такими новаторскими идеями лезть сразу в ядро, перекладывая все проблемы с своей больной головы на здоровую?
У Гугла есть же масса своих проектов.
...закрытых? :)
Так они и так уже лазят в ядро, есть же ядро для Андроид со своими гугловскими наработками.
Там голова-то не очень здоровая, стабильные 6 крупных уязвимостей в год только в ядре. Решать-то надо как-то?
Пусть сделают для себя, обкатают и покажут всему миру success stories.
Вроде Кук это и собирается делать - сделать и обкатать, он же не просит Торвальдса это делать. Он просит коммьюнити обсудить предложение.
Ну вот, ответили. Теперь ему больше ни чего не мешает наконец идти и работать?
Полагаю, проблема ещё в том, что в некоторых компаниях сотрудникам дают бонусы за разные инновации. Вот некоторые и лезут с зачастую сырыми идеями, в надежде получить приз. До этого была история с контрибьюторами, которые тоже бросались "улучшать" какие-то рандомные куски кода.
Линус как всегда)
Торвальдс посоветовал Кису Куку из Google быть решением, а не проблемой в работе с кодом и мейнтейнерами ядра Linux