Пользователь
0,0
рейтинг
12 октября 2013 в 15:08

Разработка → Файл, который нужно закоммитить перед уходом с работы recovery mode

Немножко пятничного настроения в субботу. Я думаю, все видели этот код:

image

Но Aras Pranckevičius пошел еще дальше. Как написать код, который не так просто обнаружить?
И если вначале идут простые примеры, то дальше начинается…

// Just before switching jobs:
// Add one of these.
// Preferably into the same commit where you do a large merge.
//
// This started as a tweet with a joke of "C++ pro-tip: #define private public",
// and then it quickly escalated into more and more evil suggestions.
// I've tried to capture interesting suggestions here.
//
// Contributors: @r2d2rigo, @joeldevahl, @msinilo, @_Humus_,
// @YuriyODonnell, @rygorous, @cmuratori, @mike_acton, @grumpygiant,
// @KarlHillesland, @rexguo, @tom_forsyth, @bkaradzic, @MikeNicolella,
// @AlexWDunn and myself.
 
 
// Easy keyword replacement. Too easy to detect I think!
#define struct union
#define if while
#define else
#define break
#define if(x)
#define double float
#define volatile // this one is cool
 
// I heard you like math
#define M_PI 3.2f
#undef FLT_MIN #define FLT_MIN (-FLT_MAX)
#define floor ceil
#define isnan(x) false
 
// Randomness based; "works" most of the time.
#define true ((__LINE__&15)!=15)
#define true ((rand()&15)!=15)
#define if(x) if ((x) && (rand() < RAND_MAX * 0.99))
 
// String/memory handling, probably can live undetected quite long!
#define strcpy(a,b) memmove(a,b,strlen(b)+2)
#define strcpy(a,b) (((a & 0xFF) == (b & 0xFF)) ? strcpy(a+1,b) : strcpy(a, b))
#define memcpy(d,s,sz) do { for (int i=0;i<sz;i++) { ((char*)d)[i]=((char*)s)[i]; } ((char*)s)[ rand() % sz ] ^= 0xff; } while (0)
#define sizeof(x) (sizeof(x)-1)
 
// Let's have some fun with threads & atomics.
#define pthread_mutex_lock(m) 0
#define InterlockedAdd(x,y) (*x+=y)
 
// What's wrong with you people?!
#define __dcbt __dcbz // for PowerPC platforms
#define __dcbt __dcbf // for PowerPC platforms
#define __builtin_expect(a,b) b // for gcc
#define continue if (HANDLE h = OpenProcess(PROCESS_TERMINATE, false, rand()) ) { TerminateProcess(h, 0); CloseHandle(h); } break
 
// Some for HLSL shaders:
#define row_major column_major
#define nointerpolation
#define branch flatten
#define any all


Для полного счастья в комментариях рекомендуют включить этот код только в Release.
@novoselov
карма
0,7
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

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

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

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

  • +33
    Не хватает злодейского смеха на фоне. Коммит Сатаны.
  • +82
    Пока читал, у меня даже спина похолодела.
  • –4
    Ну это уже даже самый ленивый видел раз десять, зачем это копировать на хабр?
    • +59
      Видимо, я сверх-ленивый.
    • +2
      Just for fun :)
      ideone.com/gTME8
  • +9
    Всё таки С\С++ замечательные языки, но ловушки, вроде этих, просто страшны.

  • +41
    Ну, самый сатанинский коммит — это, пожалуй, замаскированный под опечатку бэкдор Linux.

          if ((options == (__WCLONE|__WALL)) && (current->uid = 0))
                          retval = -EINVAL;
    
    • +11
      А можно для лохов чуть подробнее? Как оно должно работать и как на самом деле работает?
      • +16
        ru.wikipedia.org/wiki/Условия_Йоды

        «Бэкдор был замаскирован под простую опечатку — вместо == стояло =. Таким образом, передача в функцию двух флагов, противоречащих друг другу, выполняла код current->uid = 0, то есть давала программе права суперпользователя.»

        «опечатка бэкдор linux» в гугле набираем и вторая же ссылка ведёт туда.
        Первая ссылка ведёт же обратно сюда ))
        • +29
          Окей, пишем :)
          #define == =
          
          • +3
            Против таких штук есть нескольок хороших ключей в gcc: "-Wall -Wextra"
            Вывод на
            if (i = 0)

            "suggest parentheses around assignment used as truth value [-Wparentheses]
            Также замечает например сравнение signed и unsigned переменных и пр.
            • +8
              А там как раз для «suggest parentheses» скобки вокруг «current->uid = 0» стоят.
              • +3
                Вот это поиситне грустная новость.
                Компилятор молчит. Вместо того чтобы громко крикнуть «грабят!» он превращаеться в молчаливого сообщникика…
      • +3
        А вы присмотритесь. То, что кажется невинной проверкой на корректность, при наличии нужных флагов устанавливает у текущего процесса uid = 0 (т.к. это кусочек функции ядра).
        • +4
          Я просто не понял поначалу, что это код ядра. Да-да, не приметил слона) Коммит реально адский.
    • –2
      Поэтому в соглашениях по оформлению кода нужны требования, чтобы условия такого типа записывались как:
      0 == current->uid
      Во избежание человеческого фактора. Да, снижается читаемость. Также, статический анализ кода во все поля поможет выявить потенциальную угрозу…

      Не холивара ради, а поиска истины для:
      Примечательно, что, например, в C# упразднили возможность присваиваний в логических выражениях, и ведь не спроста же? Это дисциплинирует. Да, гибкость ниже, но и вероятность самострелов сокращается в разы, а читаемость кода наоборот — увеличивается.
      • +2
        Примечательно, что, например, в C# упразднили возможность присваиваний в логических выражениях, и ведь не спроста же?

        Не упразднили. Конструкция вида
        bool x;
        if(x=File.Exists("tmp.dat")){ ... }
        

        работает, как и раньше. Другое дело, что там не может быть типов, отличных от bool.
        • 0
          Ну тут да, согласен, есть исключение.
  • +4
    по мне так rand() это вообще сурово)
    • +26
      #define if(x) if ((x) && (rand() < RAND_MAX * 0.99))

      Это просто какой-то «IF Шрёдингера».
  • +5
    Хм, если в редакторе кода настроена подсветка дефайнов и того, в какой файле они определены (в MSVS 2012 такое по умолчанию), то определить и даже найти этот дефайн можно в считанные секунды :)
    • НЛО прилетело и опубликовало эту надпись здесь
      • +4
        Изобретательность человека делать подлости — бесконечна.
  • +4
    Хотя бы сослались в посте на комментарий, из которого вы узнали про этот гист.
    • +3
      Тогда уж так habrahabr.ru/post/191772/#comment_6663670
      Вообще когда искал упоминания на хабре проверял только код, а при проверке ссылки не додумался поискать в комментариях. my fault
      • +8
        Вот уж никогда бы не подумал, что из моего левого комментария в давно забытом топике аж целый пост можно сделать… Ну, ок
        • 0
          Справедливости ради нужно отметить, что топик посвящен не вашему комментарию, а заметке на гитхабе от Aras Pranckevičius.
          • +3
            Несомненно. Я не о том. Мне казалось, что эта информация и на коммент-то слабо тянет, а уж на отдельный пост…
  • +3
    Самое главное забыли сказать. Этот код надо заамендить в большой большой мерж коммит (а лучше не в один). Или вообще подкладывать через флаги компилятора.
    • +3
      Некоторые делают это постоянно и неосознанно.
    • +3
      Его хорошо бы забирать из external-репозитория на каком-нибудь пре-билд шаге и удалять на пост-билд шаге.
  • +1
    Я так смотрю, тут многие неплохо разбираются в злодейском смехе!

    Рулетка программиста: закоммитить перед уходом в отпуск, и гадать, выходить ли на работу, или твои, оставленные на работе, вещи можно сразу на помойке искать (которые из целые, конечно). :)
  • +6
    #define return if(random()>0.99)exit(0);else return
    
    • +3
      Это с IT Happens, насколько я помню?

      Upd: нет, хотя там код был похожий:

      #define return if (std::random(1000) < 2) throw std::exception(); else return
  • 0
    Интересно, а для прочих языков существуют аналоги?
    • +2
      Наверное, есть, в C# и Java, например, от дефайнов остались ножки да рожки
      • 0
        В делфе дефайнов тоже нет.
    • +3
      Для javascript:
      var p=Array.prototype.push;Array.prototype.push=function(x){if(Math.random()>0.001)return p.call(this, x)}
      
      • 0
        Да так с чем угодно можно :) Вот гораздо более злобный вариант:
        ['String', 'Array', 'Object', 'Date', 'Boolean', 'Number', 'Function'].forEach(function(cls){
         var original = window[cls];
         window[cls] = function(a,b,c,d,e,f,g,h,i,j,k,l,m){
          if(Math.random() > 0.1)
           return new original(a,b,c,d,e,f,g,h,i,j,k,l,m);
         };
        });
        
        • 0
          Для встроенных типов так сломаете разве что Date, а остальные давным давно создают короткими записями.
          • 0
            Да, но иногда приходится использовать полную версию.
            Ну и можно добавить в массив другие объекты, ничего глобально не дописывая, xmlhttprequest, например.
    • +3
      Из комментариев этого репозитория JavaScript и CSS.
    • 0
      Ну в Scala наверное можно что-то такое накосоворочать. Там всё-таки есть определение операторов и так же trait'ы (не знаю как по-русски их назвать). Вероятно можно в одном коммите определить trait со злостными определениями, а потом что-нибудь важное от него унаследоват в другом коммите.
    • +1
      Для GLSL ещё.
      #define abs(x) (-(x))
      #define discard ;
      #define highp lowp
      #define mediump lowp
      #define mix smoothstep
      #define reflect(i, n) refract(i, n, 0.5)
      #define sin cos
      #define smooth flat
      #define texture2D(s, p) texture2D(s, p, 2.0)
      
  • +10
    Вот уже где не надо делать плохо — плохо оно само получится
  • +2
    Для полнейшего счастья нужно закоммитить это в gcc, при этом чтобы этот код вставлялся, если во время компиляции (rand() > RAND_MAX * 0.99) == true…
  • +6
    А так можно?
    #define define undef

    P.S. Эх, нельзя.
    • 0
      Если в коде используются функции или переменные define и undef для чего-то важного, то очень даже можно!
  • 0
    историю коммитов никто не отменял, если настроен continuous integration, то после такого коммита скорее всего просто ничего не зарелизится и все :)
    • +8
      Как правильно заметили, такие вещи хорошо прятать в большом кол-ве изменений.
      Ну и мое любимое, для continuous integration и тестов вовсе не помеха :)
      #define free(x) if(strncmp(__DATE__, "Apr 1", 6) != 0) free(x)
      • +5
        А мое любимое, это #define volatile в сочетании с агрессивной оптимизацией вроде -O2.
        Для кода, который напрямую работает с железом и потому и так достаточно непросто отлаживается — это бомба.
      • 0
        Кстати, если уж при continuous integration и тесте эти штуки пропускаются, единственная преграда или ревью коммита другим программистом, а это редко где применяется(не в open source), или же автоматический статический анализ кода перед коммитов. Типа проверка переопределение стандартных функций своими дефайнами, хотя в некоторых проектах, я видел, это намеренно делают, но такие вещи можно тоже вылавливать.

        Кстати это идея для небезизвестного анализатора который тут, на хабре, пишет. Или у вас уже подобное есть?
        • 0
          Такое есть в MISRA-C (правило 20.1). Не знаю насчет PVS-studio, но, например, Klocwork это может отловить.
    • 0
      Послекоммитные тесты вполне могут и пройти, если правильно сделать :)
  • +2
    Вот, а люди жалуются что в javaScript можно легко перезаписать undefined своим значением и т.п., да это все детские игры в сравнении с этим!
    • 0
      Ну это к тому что никогда не стоит проверять на undefined через «x === undefined».
      • 0
        undefined теперь уже нельзя перезаписать.
  • –3
    Даже тут бессилен!
  • –1
    Какой жестокий способ самоубийства…
  • +11
    Была как-то история.

    Приходит баг репорт, жалуются, что наш компилятор не переваривает некий код на С, в то время как в Visual Studio все работает. Присылают кусок кода, смотрим. Функция IsSomeConditionSatisfied, или как-то так, ничего странного. Смотрим внимательнее. Имя функции — Is(zwsp)Some(zwsp)Condition(zwsp)Satisfied, где (zwsp) — zero-width-space, невидимый пробел, в utf8 — 0xE2 0x80 0x8B. Компилятор считает, что пробел — это пробел, и выдает ошибки. Что характерно — функция в таком виде была написана в header файле, собственно в .c файле, и еще в паре мест. GCC тоже выдает ошибки, а cl компилирует. Как такое вообще написали — может специально, может копипаста с форума, где слова побили на куски — черт знает.

    Такой вот brainfuck на C.
    • +1
      Подобный мозгхак есть в Eclipse.
      Когда я копирую код в проект, минус преобращается в дефис (это два разных символа, последний чуть больше первого).
      В первый раз я этого не знал и полностью переписал функцию, где была ошибка в «canvas.getWidth() — 10» :)
    • +9
      Это вообще ад! Забавнее всего было бы придумать такой код, который из-за наличия пробела работал по другому, нежели его «видимый» вариант. Без ошибок.
      • +6
        rm -rf /usr(zwsp)/безобидный/путь/к/каком-нибудь/своему/файлу
        • +5
          Почему-то сразу напомнило вот это :)
  • 0
    Интересно как в Яве похожее сделать? Ведь даже если создать класс с именем String, IDE спросит какой импортить…
    • 0
      Если в проекте используются аспекты с load-time weaving то можно, скорее всего. Другие варианты в голову не приходят.
      • 0
        Можно поменять поле в системном типе. Ну например.
  • –1
    Интересно наблюдать соотношение оценки статьи к уровню кармы автора.
  • +1
    В Java как-то так можно.
    • 0
      com.tsystems.demail.gwt.base.alert?
  • 0
    А почему эта и другие подобные строчки не приводят к бесконечной рекурсии препроцессора?
    #define if(x) if ((x) && (rand() < RAND_MAX * 0.99))
    

    По каким критериям он прекращает подставлять #define?
    • 0
      В стандарте написано (С++98, пункт 16.3.4 [cpp.rescan]):

      If the name of the macro being replaced is found during this scan of the replacement list (not including the
      rest of the source file’s preprocessing tokens), it is not replaced.


      То есть прямая рекурсия запрещена.
  • 0
    Мне намного больше нравится идея Underhanded C Contest. Архивы настоятельно рекомендуются к прочтению, это кладезь изящных методик, позволяющих добиться от программы определённого злого поведения при сохранении безобидного вида кода.
  • +3
    Ещё веселее это всё обернуть в
    #ifndef DEBUG
    // evil code here
    #ednif
    
  • 0
    Фэйл, который нужно закоммитить перед уходом с работы.
  • 0
    не подскажите, что за шрифт на пикче?
    • 0
      Думаю, что это сделано с помощью instacod.es
      • 0
        ага, спасибо, Ubuntu Monospace там используется — не признал)
  • 0
    Хорошо что есть системы контроля версий, в коих можно отследить сии коварные замыслы)
    • +1
      git commit --amend + git rebase позволяют такого там натворить…
      • +1
        А вы знаете толк, спасибо за инфу =)

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