Comments 25
Вот хоть убей не знаю, зачем вообще кому-то может потребоваться eval, тем более — в Питоне. Только по дурости и/или лености.
Во славу сатаны, конечно же. Даже название намекает.
Насколько я успел заметить, eval часто применяется в задачах из серии кодогенерации. Тот же cog в конечном счёте eval-ит код: bitbucket.org/ned/cog/src/2fbe1f31bd50ba9ef76e3d9fb2d18165a3daeca5/cogapp/cogapp.py
P.S. я сейчас отвечаю на вопрос, а не оправдываю его применение, если что.)
P.S. я сейчас отвечаю на вопрос, а не оправдываю его применение, если что.)
да и не только в питоне, но и в PHP
Почти во всех скриптовых языках есть eval. Это миллионная статья про то почему eval опасен. Но он не так страшен как его малюют и у него есть хорошее применение.
В eval нельзя никогда исполнять то что получено из внешнего источника.
Eval хорош в единственной вещи: метапрограммирование + оптимизация. Самый быстрый mysql драйвер под node.js написан с применением eval. Eval позволяет скомпилировать один раз функцию под конкретную окружающую среду. В случае драйвера mysql генерируется функция для прямого мэппинга отдачи объектов.
В случае написания высоконагруженных приложений рендереры могут стать узким местом, потому почти все библиотеки форматирования даты, заточенные на скорость используют eval. coolDateFormater('Y-m-d') -> вернёт функцию, которая примет на вход дату, а внутри не будет разбирать формат, а сразу возьмёт из даты год, месяц, день и отдаст: Год +'-'+ месяц +'-'+ день. Рендереры не всегда про визуальную часть, в моделях зачастую данные перегоняются в свой формат и на 1к таких операций это уже может дать эффект, а на 10к стать заметным невооруженным глазом.
В 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. Так как скорость решения оказалась выше обычной реализации — стал использовать эту).
Например, в стандартной библиотеке collections.named_tuple реализован именно через eval (формалньно — через exec, но невелика разница). hg.python.org/cpython/file/ab5e2b0fba15/Lib/collections/__init__.py#l239
Наверное, более чистым способом было бы аккуратно собрать AST-дерево и скомпилировать его, благо возможности для того есть. Но это сложнее, и, возможно, даже медленнее.
Наверное, более чистым способом было бы аккуратно собрать AST-дерево и скомпилировать его, благо возможности для того есть. Но это сложнее, и, возможно, даже медленнее.
UFO just landed and posted this here
На вскидку, про динамическое подключение модулей
UFO just landed and posted this here
UFO just landed and posted this here
eval — очень удобный способ фильтрации чего угодно по сложным пользовательским выражениям (найти все ноутбуки в продаже, от 10 000 до 20 000, но не acer, либо можно acer, но если до 12 000 и выпущен в этом году и памяти больше 8G, либо любой ноут с USB 3.0 если меньше 10 000, и при этом не учитывать предложения фирм, которые в моем черном списке).
Обычный интерфейс «с галочками» как на яндекс-маркете, во-первых очень сложно реализуется (особенно, если нам его надо для многих видов товара сделать), во-вторых — гораздо менее гибкий (попробуйте-ка вышеописанное выражение выразить в виде «галочек» на форме фильтра в маркете)
ниже дал ссылку на свой пост с обсуждением этой проблемы и безопасным решением
Обычный интерфейс «с галочками» как на яндекс-маркете, во-первых очень сложно реализуется (особенно, если нам его надо для многих видов товара сделать), во-вторых — гораздо менее гибкий (попробуйте-ка вышеописанное выражение выразить в виде «галочек» на форме фильтра в маркете)
ниже дал ссылку на свой пост с обсуждением этой проблемы и безопасным решением
Есть такое:
code.activestate.com/recipes/496746-restricted-safe-eval/
Проблемы с os. запросами решается через setuid setgid seteuid setegid chroot
Но конечно лучше eval не использовать в оригинале.
code.activestate.com/recipes/496746-restricted-safe-eval/
Проблемы с os. запросами решается через setuid setgid seteuid setegid chroot
Но конечно лучше eval не использовать в оригинале.
В TCL есть замечательная штука — safe interp. Которая как раз решает подобные проблемы. Почему другие языки не возьмут на вооружение эту штуку?
Пробовали, не получается. Есть у меня подозрение, что с TCL оно работает только в силу малараспространённости TCL'я. Причём NSA, скорее всего, умеет вскрывать сервера, использующие safe interp, а остальным оно просто не нужно.
Вы неправы. В TCL оно сделано строго по принципу «запрещено всё, что не разрешено», т.е. по белым спискам (в отличие от того, что например описано в статье выше — там чёрные списки). То есть, взломать конечно можно, если разрешили неправильно (скажем, сделали алиас небезопасной функции в интерп, а проверку при вызове алиаса выполнили недостаточно тщательно), но это не проблема языка или интерпретатора, а явно ошибка в программе, некорректное использование или некорректный (слишком обширный) белый список.
Сообщений же на тему «escape safe interp» в случае с корректным белым списком не обнаруживается, несмотря на то, что в силу структуры самого языка возможностей «сбежать» там должно быть хоть отбавляй.
Сообщений же на тему «escape safe interp» в случае с корректным белым списком не обнаруживается, несмотря на то, что в силу структуры самого языка возможностей «сбежать» там должно быть хоть отбавляй.
docs.python.org/dev/library/ast.html#ast.literal_eval безопасный. Правда, именно поэтому умеет совсем немного.
Интересный материал: us.pycon.org/2014/schedule/presentation/208/ — выступление на пайкон 2014 о создании питонячей песочницы.
слайды
слайды
Некропостну со ссылкой на свой пост по этой теме — evalidate: безопасная обработка пользовательских выражений. Тоже очень долго мучался с безопасностью eval'а (при том что от всей его мощности мне нужно всего-то полпроцента), кончилось написанием своего модуля для обработки только безопасных пользовательских выражений.
Как реализовать REPL без eval?
Sign up to leave a comment.
И снова про опасность eval()