Pull to refresh

Comments 25

Вот хоть убей не знаю, зачем вообще кому-то может потребоваться eval, тем более — в Питоне. Только по дурости и/или лености.
Во славу сатаны, конечно же. Даже название намекает.
Насколько я успел заметить, eval часто применяется в задачах из серии кодогенерации. Тот же cog в конечном счёте eval-ит код: bitbucket.org/ned/cog/src/2fbe1f31bd50ba9ef76e3d9fb2d18165a3daeca5/cogapp/cogapp.py

P.S. я сейчас отвечаю на вопрос, а не оправдываю его применение, если что.)
да и не только в питоне, но и в PHP
Почти во всех скриптовых языках есть eval. Это миллионная статья про то почему eval опасен. Но он не так страшен как его малюют и у него есть хорошее применение.
В eval нельзя никогда исполнять то что получено из внешнего источника.

Eval хорош в единственной вещи: метапрограммирование + оптимизация. Самый быстрый mysql драйвер под node.js написан с применением eval. Eval позволяет скомпилировать один раз функцию под конкретную окружающую среду. В случае драйвера mysql генерируется функция для прямого мэппинга отдачи объектов.
function(data){
  return {id: data[0], name: data[1], date: new Date(data[2])};
}

В случае написания высоконагруженных приложений рендереры могут стать узким местом, потому почти все библиотеки форматирования даты, заточенные на скорость используют eval. coolDateFormater('Y-m-d') -> вернёт функцию, которая примет на вход дату, а внутри не будет разбирать формат, а сразу возьмёт из даты год, месяц, день и отдаст: Год +'-'+ месяц +'-'+ день. Рендереры не всегда про визуальную часть, в моделях зачастую данные перегоняются в свой формат и на 1к таких операций это уже может дать эффект, а на 10к стать заметным невооруженным глазом.
Лично у меня есть паттерн observable оптимизированный через eval. Вместо обхода списка всех подписчиков — на каждое подписывание перегенерируется функция, которая вызывает всех подписчиков в нужном скоупе с переданными параметрами. Дало ускорение ~30%. На богатых на эвенты моделях такой подход сказался положительно. (Хотя кого я обманываю, я люблю оптимизировать и эта задача была сделана just for fun. Так как скорость решения оказалась выше обычной реализации — стал использовать эту).
UFO just landed and posted this here
Там на самом деле надо было заходить к оптимизации с другой стороны, что бы когда добавляешь пачку объектов — выключать рассылку эвентов. Эта оптимизация была сделана потом. Но до этого момента было видно что ворочается чуть менее безнадёжно).
Например, в стандартной библиотеке collections.named_tuple реализован именно через eval (формалньно — через exec, но невелика разница). hg.python.org/cpython/file/ab5e2b0fba15/Lib/collections/__init__.py#l239
Наверное, более чистым способом было бы аккуратно собрать AST-дерево и скомпилировать его, благо возможности для того есть. Но это сложнее, и, возможно, даже медленнее.
UFO just landed and posted this here
UFO just landed and posted this here
UFO just landed and posted this here
Совершенно не того же. eval с блоком в Perl есть и используется вместо try/catch и абсолютно безопасен. Опасен только eval со строкой. В вашем примере, что бы не находилось в переменной $file будет вызван require с одним аргументом и больше ничего.
eval — очень удобный способ фильтрации чего угодно по сложным пользовательским выражениям (найти все ноутбуки в продаже, от 10 000 до 20 000, но не acer, либо можно acer, но если до 12 000 и выпущен в этом году и памяти больше 8G, либо любой ноут с USB 3.0 если меньше 10 000, и при этом не учитывать предложения фирм, которые в моем черном списке).

Обычный интерфейс «с галочками» как на яндекс-маркете, во-первых очень сложно реализуется (особенно, если нам его надо для многих видов товара сделать), во-вторых — гораздо менее гибкий (попробуйте-ка вышеописанное выражение выразить в виде «галочек» на форме фильтра в маркете)

ниже дал ссылку на свой пост с обсуждением этой проблемы и безопасным решением
В TCL есть замечательная штука — safe interp. Которая как раз решает подобные проблемы. Почему другие языки не возьмут на вооружение эту штуку?
Пробовали, не получается. Есть у меня подозрение, что с TCL оно работает только в силу малараспространённости TCL'я. Причём NSA, скорее всего, умеет вскрывать сервера, использующие safe interp, а остальным оно просто не нужно.
Вы неправы. В TCL оно сделано строго по принципу «запрещено всё, что не разрешено», т.е. по белым спискам (в отличие от того, что например описано в статье выше — там чёрные списки). То есть, взломать конечно можно, если разрешили неправильно (скажем, сделали алиас небезопасной функции в интерп, а проверку при вызове алиаса выполнили недостаточно тщательно), но это не проблема языка или интерпретатора, а явно ошибка в программе, некорректное использование или некорректный (слишком обширный) белый список.
Сообщений же на тему «escape safe interp» в случае с корректным белым списком не обнаруживается, несмотря на то, что в силу структуры самого языка возможностей «сбежать» там должно быть хоть отбавляй.
Да, его проблема в том, что он умеет только загрузить примитивные конструкции. Как json.loads и подобные.
Некропостну со ссылкой на свой пост по этой теме — evalidate: безопасная обработка пользовательских выражений. Тоже очень долго мучался с безопасностью eval'а (при том что от всей его мощности мне нужно всего-то полпроцента), кончилось написанием своего модуля для обработки только безопасных пользовательских выражений.

REPL как правило доверенный — а потому проблема безопасного eval в этом случае не стоит

Sign up to leave a comment.

Articles