Snusmumriken
Так что для калькулятора — ок, для полноценного интерпретатора надо думать.
Александр
точнее не так, если поставить return, то ошибка будет не в синтаксисе, а на рантайме
Snusmumriken
так без return аналогично вызовется, не вижу разницы
Ну кароч оно вызовется дважды, если дважды лоадстрингать — с ретурном и без.
Александр
я буду пробовать без return только в случае, если сфейлился не loadstring("..")(), а именно loadstring("..")
Snusmumriken
Попробуй кстати. Но тут таки тоже можно закосякать на рантайм-ошибках с двойным вызовом чего-то сайд-эффектного.
Александр
так двойного вызова ж не будет, он всегда один - либо с return, либо без
Snusmumriken
Ну вот ты будешь пробовать без ретурна и вызывать повторно.
Snusmumriken
Тэкс
Snusmumriken
Да, кажется всё ок, я затупил
Александр
=)
Alexander
подскажите плиз, возможно ли установить значение глобальной переменной по её имени?
Alexander
То есть?
я пытаюсь отключить все глобальные библиотеки. for k in pairs(_ENV) do _ENV[k] = nil end
Alexander
Хорошо, а вопрос в чем? :)
оно так не работает, ошибку бьёт. например в k находится "os" вот как мне код такой написать, чтобы глобальный "os" приравнять к nil ?
Highly Likely
_ENV = nil или _ENV = { }
Highly Likely
Уже не работает? :)
Alexander
_ENV = nil или _ENV = { }
не, не прокатило, библиотеки не отлючились ( вот если пишу построчно типа os = nil, тогда работает
Highly Likely
Ну и да, в вашем случае, кажется, нужен _G, ане _ENV
Snusmumriken
Глобальное окружение действительно сидит в _G: local list = { "os", "table", "loadstring", } for i, key in ipairs(list) do _G[key] = nil end
Alexander
1. Какая версия lua? 2. Чего ты хочешь?
1) 5.2.4 2) Я хочу получить песочницу, отключив глобальные библиотеки. Если пишу os = nil, тогда работает. Но я хочу это сделать в цикле, чтобы все-все собрать библиотеки
Snusmumriken
Ну вот я дал пример. Это то же самое что os = nil.
Snusmumriken
Да, как ты изолировал песочницу?
Snusmumriken
Ты ей окружение задавал через этот _ENV?
Highly Likely
Ну так ты же затер os :)
Snusmumriken
Хотя даже если os затёрт, оно всё равно может сделать _G["os"] = nil, ошибки быть не должно.
Highly Likely
Покажи весь код, карочи :)
Alexander
Ты ей окружение задавал через этот _ENV?
Нет, ничего не задавал. Мне просто всё что нужно, это отключить глобальные библиотеки, и этого достаточно. Там просто пользовательский код будет выполняться на моём сервере.
Snusmumriken
+
Snusmumriken
Ну, то есть одна луа-вм на один пользовательский скрипт? Параллелить и запускать кучу инстансов разных скриптов в одной вм не планируется?
Snusmumriken
Понял, тогда см пример.
Snusmumriken
И код свой скинь
Snusmumriken
Не забудь отключить require, load и loadstring.
Alexander
всё всё работает, разобрался 👍 спасибо А в чём отличие _ENV от _G ? Может их оба затирать на всякий случай?
Highly Likely
_ENV емнип появился с 5.2
Highly Likely
И что конкретн делает, я не помню. В дефолтном виде, вроде, переадресует обращение к глобальным переменным к _G
Highly Likely
Если не находит поля у себя
Snusmumriken
_G — глобальное окружение. Без всяких upvalue и локальных контекстов. Там расположена стандартная либа, и туда пишутся переменные.
Highly Likely
По-моему _ENV че-то другое
Snusmumriken
Я ща чекну.
Snusmumriken
По-моему _ENV че-то другое
Да, ты прав, _ENV это таки текущая таблица _G. По умолчанию как раз _G и есть. Её можно переключить на другую таблицу (setenv?)
Highly Likely
Карочи, тема, которой я тоже ни разу не пользовался, спасибо Luajit’у за это
Alexander
их обе затирать лучше?
Snusmumriken
Нет
Snusmumriken
Если не менял _ENV — это одна и та же таблица что и _G.
Snusmumriken
Вот щас гуглю
Snusmumriken
Да, мы такие: print(_ENV == _G) -- prints true, since the default _ENV is set to the global table a = 1 local function f(t) local print = print -- since we will change the environment, standard functions will not be visible local _ENV = t -- change the environment. without the local, this would change the environment for the entire chunk print(getmetatable) -- prints nil, since global variables (including the standard functions) are not in the new env a = 2 -- create a new entry in t, doesn't touch the original "a" global b = 3 -- create a new entry in t end local t = {} f(t) print(a, b) --> 1 nil print(t.a, t.b) --> 2 3 http://lua-users.org/wiki/EnvironmentsTutorial
Alexander
внутри _ENV у меня _G сидит, это норма? 🤔
Snusmumriken
Да, потому что это _G и есть. Внутри _G есть _G, иначе бы ты не получил доступ к _G ))
Alexander
аааа
Alexander
а, ну понятно теперь, почему при затирании _G оно бьёт ошибку, т.к. он _G затирает и не может больше его затирать 😅 ок всем спасибо
Snusmumriken
Карочи, что ты такой делаешь. 1. Создаёшь табличку и пихаешь туда всё разрешённое: local userenv = { print = print, table = { concat = table.concat, insert = table.insert, ... }, string = string os = { -- допустим, разрешаем часть os-либы time = os.time, }, ... } -- делаем похожим на _G userenv._G = userenv 2. Потом делаешь особое пространство, в котором будет пользовательский код: do -- скоуп для юзерспейса local _ENV = userenv -- переключаешь _ENV для этого скоупа loadstring(usercode)() -- исполняем код end -- на этой точке _G уже обратно то _G которое было ранее. Все пользовательские объявления глобалов и переопределения не играют роли, ибо остались в userenv.
Alexander
кстати, _G = {} и _ENV = {} не работает
Highly Likely
(я пошел спать, короче, я совсем ересь писать начинаю)
Snusmumriken
кстати, _G = {} и _ENV = {} не работает
Я тебе только что дал такой рецепт, который ещё и не сломает тебе ничего если юзер попробует что-то грязное мутить, и его изменения не отразятся ни на чём после исполнения его куска.
Alexander
Я тебе только что дал такой рецепт, который ещё и не сломает тебе ничего если юзер попробует что-то грязное мутить, и его изменения не отразятся ни на чём после исполнения его куска.
Спасибо, сохраню сейчас покурю, пока что в луа плохо разбираюсь. Мне как раз нужно оставить юзеру возможность print всяких. Правда, в do-end не смогу код поместить, т.к. у меня вызов кода идёт через php, последовательно выполняется сначала код песочницы, затем уже пользовательский код
Snusmumriken
Не забудь добавить к пользовательскому коду что-то типа такого: usercode = replace(usercode, "\r?\nEOD", "\r\n EOD"), чтобы не допустить инъекций. Простого пробела достаточно, пых уже не сломается и даст по жопе нехорошему человеку.
Snusmumriken
Если он сгенерит строку sandboxcode где внутри $usercode будет текст "EOD; db("DROP TABLE Students;");" что оно скажет?
Alexander
Если он сгенерит строку sandboxcode где внутри $usercode будет текст "EOD; db("DROP TABLE Students;");" что оно скажет?
пых сначала читает блок EOD полностью, а затем уже заполняет его переменными
Snusmumriken
Тогда ок, я видел где-то похожую уязвимость
Snusmumriken
local _ENV = {} Она локальная. Уже никуда не нагадить.
Snusmumriken
Испортить userenv — пускай портит, ему же хуже ))
Alexander
local _ENV = {} Она локальная. Уже никуда не нагадить.
но там local _ENV = userenv -- переключаешь _ENV для этого скоупа
Snusmumriken
А, ну да, создаёшь таблицу userenv для каждого пользовательского скрипта отдельно, можно в функцию завернуть, возвращающую копию таблички.
Alexander
А что это за конструкция такая странная? не получается нагуглить loadstring[====[$usercode]====] почему не loadstring($usercode)