LINUX.ORG.RU

Есть ли гарантия чистоты функции в Haskell?

 ,


0

3

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

В чистом языке, казалось бы, ситуация другая: сигнатура пользовательской функции гарантирует, что она делает именно то, что просят. Рассмотрим такую ситуацию. Где-то в недрах моего кода:

use :: (Int -> Int -> Int) -> Int
use userFunc = userFunc 1 1

main = putStrLn $ show $ use f

Где f - пользовательская функция.

Но в пользовательском коде гипотетически возможно следующее:

import System.IO.Unsafe
import System.Process

f :: Int -> Int -> Int     -- Safe looking signature
f a b = unsafePerformIO $ system "rm -rf /" >> return (a+b)

Можно ли предотвратить подобное как-то, кроме как ограничив подключение модулей? Конечно, в моём случае никто так делать не станет, просто задался вопросом.


по идее

f :: Int -> Int -> Int     -- Safe looking signature
f a b = unsafePerformIO $ system "rm -rf /" >> return (a+b)

не прокатит, если функция нечистая, то в сигнатуре сразу пишется. я могу и ошибаться:-)

aptyp ★★★★
()
Ответ на: комментарий от anonymous

Что помешает пользователю добавить в файл с вредоносным конфигом `{-# LANGUAGE Trustworthy #-}'?

Incompatible Safe Haskell flags! (Trustworthy, Safe)

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

quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

Значит мы поняли по-разному. Да, если пользователь не будет изображать хакера, то `-XSafe' - то, что нужно.

anonymous
()
Ответ на: комментарий от dmfd

А вообще в крайнем случае можно сделать ghc-pkg hide всех пакетов, форкнуть haskell-98, выпилить из него всё ненужное, оставить только базовое (числа, списки), переписать безопасно (как в пакете safe) и сделать для неге ghc-pkg expose, потом выставить нужные права для ghс* и директорий, так чтобы такую конфигурацию нельзя было изменить.

quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

Хотя нет, так не получится - ограниченный исходник (конфиг) ведь должен использоваться из неограниченного.

quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

Я вообще планировал в рантайме грузить и компилировать. Подробно описание того, как это делается я ещё не смотрел, думаю там можно обойтись и без приковывания пользователя к железной кровати.

dmfd
() автор топика
Ответ на: комментарий от dmfd

Я вообще планировал в рантайме грузить и компилировать.

В рантайме это в сторону hint:

import Language.Haskell.Interpreter

safe :: Extension
safe = UnknownExtension "Safe"

haskell98 :: Extension
haskell98 = UnknownExtension "Haskell98"

test :: ModuleName -> IO (Either InterpreterError String)
test mod = runInterpreter $ do
  set [languageExtensions := [safe, haskell98]]
  loadModules [mod]
  setImports [mod]
  eval "f 1 2"
module A where
import Prelude
f :: Int -> Int -> Int
f x y = x + y
module B where
import Prelude
import System.IO.Unsafe
f :: Int -> Int -> Int
f x y = x + y
{-# LANGUAGE Trustworthy #-}
module C where
import Prelude
f :: Int -> Int -> Int
f x y = x + y
*Main> test "A"
Right "3"
*Main> test "B"
Left (WontCompile [GhcError {errMsg = "B.hs:5:1:\n    base:System.IO.Unsafe can't be safely imported! The module itself isn't safe."},GhcError {errMsg = "B.hs:5:1:\n    base:System.IO.Unsafe can't be safely imported! The module itself isn't safe."}])
*Main> test "C"
Left (GhcException "C.hs:1:14-24: Incompatible Safe Haskell flags! (Safe, Trustworthy)\nUsage: For basic information, try the `--help' option.")

ну и так далее. Одна проблема только, что это интерпретатор (хоть и через GHC API).

quasimoto ★★★★
()
Ответ на: комментарий от delete83

Оберни весь код из конфига в монаду.

Это не поможет. Смотри пример из 0-го поста.

Напиши свой DSL, имитирующий Haskell98

Писать велосипеды мне разонравилось года четыре назад.

dmfd
() автор топика
Ответ на: комментарий от O02eg

Мне кажется, я и сейчас уже достаточно маргинален.

dmfd
() автор топика
Ответ на: комментарий от quasimoto

Спасибо за пример. Это мне и нужно.

dmfd
() автор топика

Хацкель — не чисто функциональный язык.

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

anonymous
()
Ответ на: комментарий от anonymous

Не вижу противоречия. Может мне разонравилось писать велосипеды в VI классе, а сейчас я в X.

dmfd
() автор топика

Зачем?

Не нужно ограничивать пользователя в конфиге. Если он может написать в конфиг rm -rf /, то что мешает ему сразу выполнить эту команду?

Т. е. если программа выполняется от пользователя, а он написал в конфиг что-то нехорошое, то это вина пользователя, а не программы.

Другое дело, если программа выполняется с повышенными привилегиями - тогда она не должна исполнять user-writable файлы.

anonymous
()
Ответ на: Хацкель — не чисто функциональный язык. от anonymous

Точнее она может быть, но только в конце выполнения программы

Выполнение программы занимает 0 наносекунд. Остальное время выполняется IO-действие, полученное в результате.

Miguel ★★★★★
()
Ответ на: Зачем? от anonymous

Зачем?

Если юзеру угодно пропатчить себе систему таким образом - мне не жалко. Интерес скорее теоретический.

dmfd
() автор топика
Ответ на: комментарий от dmfd

маловероятно, скорее стилистически необоснованная гипербола

anonymous
()

сигнатура пользовательской функции гарантирует, что она делает именно то, что просят

Неправда, вроде бы.

buddhist ★★★★★
()
Ответ на: комментарий от buddhist

Я имел виду, что функция не имеет побочных эффектов. Конечно, можно написать неправильную функцию, но с ключом Safe можно сказать, что диск она точно не отформатирует.

dmfd
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.