Пользователь
0,0
рейтинг
12 марта 2015 в 05:25

Разработка → Можно ли верить коду в редакторе? bi-directional текст

def maps():
	print "maps maps maps"

def spam():
	print "Erasing everything..."
	print "done."

Вы знаете, что если очень долго смотреть на следующую строку, то там останутся только три слова «spam»?

s = "spam‮" ,spam ,"‬spam"
s[1]()

Действительно, первая строка очень необычная. В целом, в результате этого кода будет выполнена зловредная функция spam.

Посмотреть на ideone. (Для тех кто не знает: там внизу есть вывод выполнившейся программы)

RLO


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

Направление отрисовки определяется автоматически по принадлежности символов конкретному алфавиту (ивриту, например) или, если это знак пунктуации или цифра, то по более хитрым правилам, в зависимости от контекста.

RLO — символ форматирования, расшифровывается как right-to-left override. Меняет направление письма на правостороннее для символов с дефолтно-левосторонним письмом. (В стандарте написано, что это может использоваться для записи таких вот идентификаторов, когда те состоят из смешанного иврита и английского и, видимо, английские включения естественно читаются справа-налево).

Ну так вот. Благодаря ему мы можем получить нашу прелесть:
s = "spam<RLO>" ,spam ,"<PDF>spam"
s = "spam‮" ,spam ,"‬spam"

PDF расшифровывается как pop directional formatting, сбрасывает эффект последнего RLO или его друзей.

Нетрудно догадаться, что интерпретатор окажется равнодушен к непонятным символам в строковых литералах. А вот некоторые редакторы, вроде emacs*, Xcode, Kate, развернут промежуточный текст именно так, как это делает браузер.

* в случае emacs, возможно, поведение зависит от терминала. Но в vim и nano проблемы в том же терминале нет: оба показывают только код символа RLO в соответствующей позиции.

О других вариантах использования в коде


Символ RLO не является вайтспейсовым, кроме того, python ругается на него в составе идентификаторов, что немного ограничивает возможности применения.

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

Картинки


vim


sublime text


xcode


emacs


… и еще раз ссылка на ideone.

upd: есть еще вот такой вариант с Embedding и Mark

Бонус

«rm -rf echo», которая на самом деле только печатает «rm -rf»
echo -e '\xe2\x80\x8f\xe2\x80\xaaecho \xe2\x80\xac\xe2\x80\x8f\xe2\x80\xaarm -rf \xe2\x80\xac\xe2\x80\x8f'

bash почему-то игнорирует символы форматирования в начале команды, чем открывает большой простор для злодействия.
Павел @TheRipper
карма
31,7
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

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

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

  • –13
    РЛО:)
  • 0
    PyCharm показывает правильно, но не видит символы форматирования, аналогично Sublime Text.
    • 0
      Также Notepad++ и IDLE.
  • +12
    Никому нельзя верить, особенно букве «C»
    • +3
      Ara
  • НЛО прилетело и опубликовало эту надпись здесь
    • НЛО прилетело и опубликовало эту надпись здесь
      • +22
        Темой не ошиблись?
        • +1
          Адресом он ошибся. Ему на жежешечку надо было…
      • +2
        Ольгинцы переехали и теперь их принято называть «Савушкин продукт»:)
        • НЛО прилетело и опубликовало эту надпись здесь
          • +1
            Ну так и надо было сразу же извиниться. Вот честное слово, смотря на ваш комментарий, я даже не подумал про возможную «ошибку окном». А фраза «Правильно… и карму за это слить. Неужели ольгинцы уже на Хабре?» ничуть не похожа на вежливое извинение.
            • НЛО прилетело и опубликовало эту надпись здесь
  • +3
    В некоторых редакторах можно включить отображение управляющих последовательностей. Кажется, что с распространением юникода эту опцию нужно будет включать в редакторах по умолчанию
    • 0
      … с распространением юникода… нужно будет...? Этот уже случилось :)
      Но осилить стандарт все еще дается не всем… :)
  • 0
    Вздрогнул, увидев знакомый код 0x200E. Тоже устал с ними бороться. Из-за одного 0x200F сравнение строк работает «крайне интересно».
  • +6
    В Atom эта строка вызывает некоторое визуальное безумие. То есть, в этом вопросе ему доверять (пока?) нельзя.

    Раскрывается она, как в браузере (учитывая браузерное происхождение Atom, это было предсказуемо). Toggle invisibles не выдаёт тот факт, что там что-то не то. Но. Нельзя заехать курсором в область, ограниченную RLO и PDF. Ни стрелками, ни мышью. Во всяком случае, так кажется — при проезжании мимо RDO курсор прыгает на длину, которую он огораживает. Но на самом деле, дело обстоит вот как:



    В конце строки якобы пустой хвост. Фактически он не пуст, при попытке его стереть вытирается конец строки, начиная от последних кавычек. Шириной он аккурат в 10 символов, сколько между RLO и PDF. То есть, после проезжания через RDO курсор визуально смещается вправо на длину развёрнутого фрагмента, а фактически заезжает внутрь него. Баг. Хоть понятно, откуда растёт.

    А теперь весёлая часть. Если включить грамматику Python, баг видоизменяется — смещение от реального положения уменьшается до 4 символов. Тут я перестал понимать что происходит. Пойду оформлять баг-репорт. Спасибо вам за очередное «wat» :)
  • 0
    У меня в RSS-ленте это выглядит так:
    s = "spam"", maps, "spam
    ()[1]s
    


    Поэтому до открытия статьи я минут пять ломал голову над тем, как это должно работать.
  • +2
    Eclipse ведёт себя так же как Emacs и Xcode:
  • +7
  • –1
    Старый добрый Textmate не подвел:

    image
    • +1
      Переоткройте, указав кодировку UTF-8. Он вас подвёл — открыл UTF-8 файл в какой‐то однобитовой кодировке, по‐видимости, в latin1.
      • –1


        Нас никто не подводил. И мы бы не стали писать комментарий, если бы не были уверены как оно есть на самом деле.
        • +2
          Вы решили выкопать себе или своему редактору могилу?

          Во‐первых, не знаю, как в textmate, а в Vim файлы в памяти храняться в кодировке &encoding независимо от кодировки, в которой они лежат в ФС. Вы можете открыть latin1 файл и написать там сколько угодно юникодных символов и Vim ничего вам не скажет вплоть до того, как вы попытаетесь это сохранить. Так что снимок совершенно неубедителен.

          Во‐вторых, RLO и PDF — это два символа. У вас на снимке их шесть. Если вы действительно открыли файл с правильным содержимым, не перекодированный из latin1 в UTF-8 по дороге чем‐то излишне умным и TextMate открыл его именно как UTF-8, то содержимое, видимое на экране, совершенно некорректно: вы видите U+202E и U+202C, отображённые как U+00E2, U+0080, U+00AE и U+00E2, U+0080, U+00AC соответственно. Если вы считаете, что отобразив содержимое файла именно так, TextMate вас не подвёл, то разговаривать с вами совершенно бессмысленно.
          • +1
            Относительно последнего аргумента: редактор программисту нужен для того чтобы точно, понятно и читаемо отображать текст (иногда ради последнего жертвуют первым) (редактирование и навигацию по тексту рассматривать не буду, т.к. вы не описали процесс взаимодействия с этими символами). Указанное отображение при заданных условиях (открытие в кодировке UTF-8 именно оригинального файла) нарушает все три пункта сразу:

            1. Оно не точное, т.к. отображены не те символы, что присутствуют в файле, при этом такого же отображения можно добиться с помощью другой последовательности байт (записать в файле эти самые шесть символов явно).
            2. Оно не понятно, т.к. никак не ассоциируется с PDF и не даёт подсказок относительно того, что надо искать в таблице символов (Vim отображает PDF как <202C>, что тоже не ассоциируется с PDF, но, тем не менее, может быть найдено в таблице символов).
            3. Оно не читаемо по тем же причинам, что и не понятно.
          • –1
            tl;dr;
            О нет, могила на хабре!

            Чувак, всё на самом деле проще чем ты выдумал.
            • 0
              tl;dr;
              О нет, могила на хабре!
              Чувак, всё на самом деле проще чем ты выдумал.
              Не, ну вот мне тоже интересно, поясните. Проще — это как? Ваш редактор явно же неправильно нарисовал эти символы. Вы не согласны с этим? Тем более что (судя по подчёркнутому спеллчекером слову) символ â действительно отдельным символом представлен.
              • 0
                1. Я ничего специально не перекодировал, заняться мне больше не чем. Я скопипастил код из ideone в новый файл. Естественно, по умолчанию новый файл в UTF8, я же не ебнутый.
                2. Я считал бы, что он меня подвел, только если бы было как в Atom, Xcode или Emacs. Да, идеально было бы как в vim, но все-таки в TextMate я по крайней мере увижу, что меня пытаются наебать, случись подобное (банальный копипаст кода откуда-нибудь). А перейти на vim меня ничто не заставит.
                3. Особой разницы для меня не было бы, увидь я там вместо этих символов — я бы так же стер весь код.

                А теперь срыв покровов, т.е. причина: github.com/textmate/textmate/blob/master/Frameworks/editor/src/editor.cc#L56-L60.
                • 0
                  * увидь я там вместо этих символов «202e»
                • 0
                  А теперь срыв покровов, т.е. причина: github.com/textmate/textmate/blob/master/Frameworks/editor/src/editor.cc#L56-L60.
                  Нет. Смотрите исходник: github.com/textmate/textmate/blob/master/Frameworks/text/src/utf8.h#L214. PDF и RLO — это корректные Unicode символы.

                  Причина, судя по всему, именно «Я скопипастил код из ideone в новый файл.» Скачайте файл (http://ideone.com/plain/GuSU4F) и откройте его в textmate.
                  • 0
                    PDF и RLO — это корректные Unicode символы.
                    Кроме того, данная функция занимается удалением некорректных символов. А не удалением символов и вставкой вместо них новых.

                    Кстати говоря, указанный вами код, если бы он срабатывал при открытии файла, есть отличная антиреклама для textmate. Если Vim видит некорректный символ при открытии в utf8, то он показывает на его месте <XX> (код данного символа) и позволяет найти такой символ с g8g. При сохранении без редактирования символ никуда не девается. Vim не портит текст.

                    Однако, судя по всему, он используется только для того, чтобы фильтровать ввод от других команд. Что тоже не слишком хорошо, но лучше.
  • 0
    Когда прочитал первую строчку функции, невольно возникла ассоциация с cat «test… test… test...».
    Когда дочитал до конца, оказалось, что интуиция меня не подвела.

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