Why not login to Qiita and try out its useful features?

We'll deliver articles that match you.

You can read useful information later.

2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Pythonใ‚นใ‚ฏใƒชใƒ—ใƒˆใ‚’่ปฝ้‡ใ‚ตใƒณใƒ‰ใƒœใƒƒใ‚ฏใ‚นใงๅ‰ฒใจๅฎ‰ๅ…จใซๅฎŸ่กŒใ™ใ‚‹

Last updated at Posted at 2025-02-26

LLMใฎPythonใ‚นใ‚ฏใƒชใƒ—ใƒˆๅ‡บๅŠ›ใ‚’ๆฏ”่ผƒ็š„ๅฎ‰ๅ…จใซๅฎŸ่กŒใ—ใŸใ„ใ€ใใ†ใ„ใ†ๆ™‚ใฃใฆๅ‰ฒใจใ‚ใ‚Šใพใ™ใ‚ˆใญใ€‚ไฝฟใ†ใฎใฏ่‡ชๅˆ†ใ ใ‘ใชใฎใงๆ€–ใ„ใฎใฏๅถ็„ถๅฑ้™บใชใ‚ณใƒผใƒ‰ใŒๅ‡บใฆใใŸๆ™‚ใ ใ‘ใ€ใฟใŸใ„ใชใ‚ฑใƒผใ‚นใงใ™ใ€‚

ใงใ‚‚ไธ–้–“ใซๅ‡บๅ›žใฃใฆใ‚‹ๆƒ…ๅ ฑใฏDockerใ‚’ไฝฟใฃใŸใ‚‚ใฎ (llm-sandbox) ใจใ‹ใ€WebAssemblyใ‚’ไฝฟใฃใŸใ‚‚ใฎ (Pyodide) ใจใ‹ใ€CPythonไปฅๅค–ใฎๅฎŸ่ฃ…ใ‚’ไฝฟใฃใŸใ‚‚ใฎ (PyPyใฎใ‚ตใƒณใƒ‰ใƒœใƒƒใ‚ฏใ‚นๆฉŸ่ƒฝ) ใจใ‹ใ€Webใ‚ตใƒผใƒ“ใ‚นๅ‘ใ‘ใฎ้‡้‡็ดšใฎใ‚‚ใฎใฐใ‹ใ‚Šใ€‚่ปฝใ‹ใฃใŸใงใ‚ใ‚ใ† pysandbox ใฏใƒ‡ใ‚ถใ‚คใƒณใซๆฌ ้™ฅใŒใ‚ใ‚Šใ€ๅˆถ้™ใ‚‚ๅคšใ้–‹็™บไธญๆญขใจใชใฃใฆใ„ใพใ—ใŸใ€‚

ใใ‚“ใชไธญใงใ•ใฆใฉใ†ใ—ใ‚ˆใ†ใ€ใ‚ตใƒณใƒ‰ใƒœใƒƒใ‚ฏใ‚นใฎPython็’ฐๅขƒใงใ‚‚ใƒ›ใ‚นใƒˆใฎPython็’ฐๅขƒใจๅŒใ˜ใ‚‚ใฎใŒไฝฟใˆใ‚Œใฐ็ฎก็†ใŒๆฅฝใชใฎใซใ€ใจๆ€ใ„ใชใŒใ‚‰่ชฟในใฆใ„ใพใ—ใŸใ€‚

ใใฎ็ตๆžœใ€Pythonใƒฉใ‚คใƒ–ใƒฉใƒชใฎไธญใงใฏๆฑบๅฎšๆ‰“ใŒ่ฆ‹ใคใ‹ใ‚‰ใชใ‹ใฃใŸใ‚‚ใฎใฎใ€Linux็’ฐๅขƒใฎไธญใงใฏ systemd-nspawn ใ‚’่ชญใฟ่พผใฟๅฐ‚็”จใƒžใ‚ฆใƒณใƒˆใงไฝฟใ†ๆ–นๆณ•ใ‚’ๆ€ใ„ใคใ๏ผˆไฝ†ใ—ใƒซใƒผใƒˆๆจฉ้™ใŒๅฟ…่ฆ๏ผ‰ใ€ใใฎ systemd-nspawn ใซไผผใชใŒใ‚‰ใ‚‚ใƒซใƒผใƒˆๆจฉ้™ใŒไธ่ฆใชbubblewrap (bwrap) ใ‚’่ฆ‹ใคใ‘ใ€ใใฎ bwrap ใ‚’ไฝฟใฃใฆใ‚ตใƒณใƒ‰ใƒœใƒƒใ‚ฏใ‚นใง Python ใ‚นใ‚ฏใƒชใƒ—ใƒˆใ‚’ๅฎŸ่กŒใ™ใ‚‹ใ‚ณใƒผใƒ‰ใ‚’ๆ›ธใ„ใฆใฟใพใ—ใŸใ€‚

# License: Public Domain
import os
import subprocess

home_dir = os.path.expanduser("~")

try:
    os.makedirs("/tmp/mysandbox_root")
except FileExistsError:
    pass

def sandbox_pyexec(code):
    proc = subprocess.Popen(
        ["bwrap", "--bind", "/tmp/mysandbox_root", "/", "--ro-bind", "/bin", "/bin", # ใ‚ทใ‚นใƒ†ใƒ ใƒ•ใ‚กใ‚คใƒซใ‚’Read-Onlyใงๅ…ฑๆœ‰ใ™ใ‚‹
         "--ro-bind", "/lib", "/lib", "--ro-bind", "/lib64", "/lib64", 
         "--ro-bind", "/usr", "/usr", "--ro-bind", "/etc", "/etc", # ใ‚ใ‚“ใพใ‚Š่‰ฏใใชใ„
         "--ro-bind", home_dir + "/.local/lib", home_dir + "/.local/lib", # pip ใƒฉใ‚คใƒ–ใƒฉใƒชใ‚’Read-Onlyใงๅ…ฑๆœ‰ใ™ใ‚‹
         "--ro-bind", home_dir + "/.local/bin", home_dir + "/.local/bin",
         "--ro-bind", home_dir + "/.local/share", home_dir + "/.local/share",
         "--bind", "/proc", "/proc", "--unshare-all", "--", # ใชใ‚‹ในใใƒ›ใ‚นใƒˆใจ้žๅ…ฑๆœ‰๏ผˆsystemd-nspawnใจ้•ใฃใฆใƒ—ใƒญใ‚ปใ‚นใƒชใ‚นใƒˆใฏๅ…ฑๆœ‰ใ—ใฆใ‚‹ใ‘ใฉ๏ผ‰
         "bash", "-c", "python -"],  # Pythonใงๆจ™ๆบ–ๅ…ฅๅŠ›ใฎใ‚ณใƒผใƒ‰ใ‚’ๅฎŸ่กŒ
        stdin=subprocess.PIPE,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        text=True  # stdin / stdout ใ‚’ๆ–‡ๅญ—ๅˆ—ใจใ—ใฆๆ‰ฑใ†
    )
    result, err = proc.communicate(code)
    return (result.strip(), err.strip())
    

r, err = sandbox_pyexec( """print("ใ“ใ‚Œใฏใƒ†ใ‚นใƒˆใงใ™")""")

print("stdout:", r)
print("stderr:", err)
# stdout: ใ“ใ‚Œใฏใƒ†ใ‚นใƒˆใงใ™
# stderr: 

r, err = sandbox_pyexec( """import os
os.system("ls /")""")

print("stdout:", r)
print("stderr:", err)
# stdout: bin
# etc
# home
# lib
# lib64
# proc
# usr
# stderr: 

r, err = sandbox_pyexec( """wrong python syntax here""")

print("stdout:", r)
print("stderr:", err)
# stdout: 
# stderr: File "<stdin>", line 1
#     wrong python syntax here
#           ^^^^^^
# SyntaxError: invalid syntax

ใ‚คใƒณใƒฉใ‚ฟใ‚ฏใƒ†ใ‚ฃใƒ–ใ‚ทใ‚งใƒซ็‰ˆ

ใ‚คใƒณใ‚ฟใƒฉใ‚ฏใƒ†ใ‚ฃใƒ–ใ‚ทใ‚งใƒซใง็’ฐๅขƒใ‚’ไฟๅญ˜ใ™ใ‚‹็‰ˆใ‚‚ไฝœใ‚Šใพใ—ใŸ๏ผˆ2026ๅนด1ๆœˆ11ๆ—ฅ่ฟฝ่จ˜๏ผ‰ใ€‚

# License: Public Domain
import os
import pty
import termios
import select
import sys

home_dir = os.path.expanduser("~")
try:
    os.makedirs("/tmp/mysandbox_root")
except FileExistsError:
    pass

def disable_echo(fd):
    attrs = termios.tcgetattr(fd)
    attrs[3] = attrs[3] & ~termios.ECHO  # lflags ใ‹ใ‚‰ ECHO ใ‚’่ฝใจใ™
    termios.tcsetattr(fd, termios.TCSANOW, attrs)

def sandbox_pyenv():
    pid, fd = pty.fork()
    if pid == 0: # child
         # sys.stdout.flush()][
         disable_echo(0)
         os.execvp("bwrap", 
            ["bwrap", "--bind", "/tmp/mysandbox_root", "/", "--ro-bind", "/bin", "/bin", # ใ‚ทใ‚นใƒ†ใƒ ใƒ•ใ‚กใ‚คใƒซใ‚’Read-Onlyใงๅ…ฑๆœ‰ใ™ใ‚‹
             "--ro-bind", "/lib", "/lib", "--ro-bind", "/lib64", "/lib64", 
             "--ro-bind", "/usr", "/usr", "--ro-bind", "/etc", "/etc", # ใ‚ใ‚“ใพใ‚Š่‰ฏใใชใ„
             "--ro-bind", home_dir + "/.local/lib", home_dir + "/.local/lib", # pip ใƒฉใ‚คใƒ–ใƒฉใƒชใ‚’Read-Onlyใงๅ…ฑๆœ‰ใ™ใ‚‹
             "--ro-bind", home_dir + "/.local/bin", home_dir + "/.local/bin",
             "--ro-bind", home_dir + "/.local/share", home_dir + "/.local/share",
             "--bind", "/proc", "/proc", "--unshare-all", "--", # ใชใ‚‹ในใใƒ›ใ‚นใƒˆใจ้žๅ…ฑๆœ‰๏ผˆsystemd-nspawnใจ้•ใฃใฆใƒ—ใƒญใ‚ปใ‚นใƒชใ‚นใƒˆใฏๅ…ฑๆœ‰ใ—ใฆใ‚‹ใ‘ใฉ๏ผ‰
             "python", "-i"],  # Pythonใฎใ‚คใƒณใ‚ฟใƒฉใ‚ฏใƒ†ใ‚ฃใƒ–ใƒขใƒผใƒ‰ใงๆจ™ๆบ–ๅ…ฅๅŠ›ใฎใ‚ณใƒผใƒ‰ใ‚’ๅฎŸ่กŒ
         )
         exit()
    else:
        output = b""
        while True:
            r, _, _ = select.select([fd], [], [])
            chunk = os.read(fd, 1024)
            output += chunk

            if output.endswith(b">>> "):
                #print("debug: bunner: %s"%output)
                break

    return fd

def sandbox_pyexec(fd, code):
    output = b""
    for line in code.split("\n"):
        os.write(fd, line.encode("utf-8") + b"\n")

        while True:
            r, _, _ = select.select([fd], [], [])
            chunk = os.read(fd, 1024)
            output += chunk

            if output.endswith(b">>> ") or output.endswith(b"... "):
                output = output[:-4] # ใƒ—ใƒญใƒณใƒ—ใƒˆใ‚’้™คๅŽป
                break

    text = output.decode(errors="ignore")
    return text

def sandbox_reset(fd):
    sandbox_pyexec(fd, """globals().clear()
import gc
gc.collect()
globals().clear()
""")

fd = sandbox_pyenv()
print("[exec]%s[/exec]"%sandbox_pyexec(fd, "a = 100")) # [exec][/exec]
print("[exec]%s[/exec]"%sandbox_pyexec(fd, "print(a)")) # [exec]100\n[/exec]
print("[exec]%s[/exec]"%sandbox_pyexec(fd, "a")) # [exec]100\n[/exec]
print("[exec]%s[/exec]"%sandbox_pyexec(fd, "b")) # [exec]Traceback (most recent call last):\n  File "<stdin>", line 1, in <module>\nNameError: name 'b' is not defined\n[/exec]

print("[exec]%s[/exec]"%sandbox_pyexec(fd, """print("aaa")\nprint("bbb")""")) # [exec]aaa\nbbb\n[/exec]
print("[exec]%s[/exec]"%sandbox_pyexec(fd, """print("aaa" + \\\n "bbb")""")) # [exec]aaabbb\n[/exec]

sandbox_reset(fd)
print("[exec]%s[/exec]"%sandbox_pyexec(fd, "a"))  # [exec]Traceback (most recent call last):\n  File "<stdin>", line 1, in <module>\nNameError: name 'a' is not defined\n[/exec]
2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up

Today's trending articles

Comments

No comments

Let's comment your feelings that are more than good

Being held Article posting campaign

2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Login to continue?

Login or Sign up with social account

Login or Sign up with your email address