From b9656c9b32776f59032c44b4e3120d29683a01e1 Mon Sep 17 00:00:00 2001 From: AN Long Date: Wed, 25 Feb 2026 23:17:48 +0900 Subject: [PATCH 1/4] py: harden __import__ argument handling --- py/import.go | 36 ++++++++++++++++++++++++++++++--- stdlib/builtin/tests/builtin.py | 20 ++++++++++++++++++ 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/py/import.go b/py/import.go index 5ca6598a..8d60f55d 100644 --- a/py/import.go +++ b/py/import.go @@ -108,7 +108,9 @@ func ImportModuleLevelObject(ctx Context, name string, globals, locals StringDic } if fromFile, ok := globals["__file__"]; ok { - opts.CurDir = filepath.Dir(string(fromFile.(String))) + if fromFileStr, ok := fromFile.(String); ok { + opts.CurDir = filepath.Dir(string(fromFileStr)) + } } module, err := RunFile(ctx, srcPathname, opts, name) @@ -344,14 +346,42 @@ func BuiltinImport(ctx Context, self Object, args Tuple, kwargs StringDict, curr var globals Object = currentGlobal var locals Object = NewStringDict() var fromlist Object = Tuple{} + var fromlistTuple Tuple var level Object = Int(0) err := ParseTupleAndKeywords(args, kwargs, "U|OOOi:__import__", kwlist, &name, &globals, &locals, &fromlist, &level) if err != nil { return nil, err } + levelObj, ok := level.(Int) + if !ok { + return nil, ExceptionNewf(TypeError, "__import__() argument 5 must be int, not %s", level.Type().Name) + } + levelInt := int(levelObj) + + var globalsDict StringDict + if globalsTyped, ok := globals.(StringDict); ok { + globalsDict = globalsTyped + } else { + if levelInt > 0 { + return nil, ExceptionNewf(TypeError, "globals must be a dict") + } + globalsDict = StringDict{} + } + + localsDict, ok := locals.(StringDict) + if !ok { + localsDict = StringDict{} + } + if fromlist == None { - fromlist = Tuple{} + fromlistTuple = Tuple{} + } else { + fromlistTuple, err = SequenceTuple(fromlist) + if err != nil { + return nil, err + } } - return ImportModuleLevelObject(ctx, string(name.(String)), globals.(StringDict), locals.(StringDict), fromlist.(Tuple), int(level.(Int))) + + return ImportModuleLevelObject(ctx, string(name.(String)), globalsDict, localsDict, fromlistTuple, levelInt) } diff --git a/stdlib/builtin/tests/builtin.py b/stdlib/builtin/tests/builtin.py index 77a831a2..36cb8ff2 100644 --- a/stdlib/builtin/tests/builtin.py +++ b/stdlib/builtin/tests/builtin.py @@ -501,6 +501,26 @@ class C: pass assert lib.libfn() == 42 assert lib.libvar == 43 assert lib.libclass().method() == 44 +lib = __import__("lib", {}, {}, [""]) +assert lib.libfn() == 42 +ok = False +try: + __import__("lib", {}, {}, 1) +except TypeError: + ok = True +assert ok, "TypeError not raised" +lib = __import__("lib", 1, {}, [""]) +assert lib.libfn() == 42 +ok = False +try: + __import__("lib", 1, {}, [""], 1) +except TypeError as e: + if e.args[0] != "globals must be a dict": + raise + ok = True +assert ok, "TypeError not raised" +lib = __import__("lib", {"__file__": 1}, {}, [""]) +assert lib.libfn() == 42 doc="input" import sys From 0e801608e83045ba41eeeb22ead00c3586243b48 Mon Sep 17 00:00:00 2001 From: AN Long Date: Thu, 26 Feb 2026 01:29:22 +0900 Subject: [PATCH 2/4] Update py/import.go Co-authored-by: Sebastien Binet --- py/import.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/py/import.go b/py/import.go index 8d60f55d..56a72da3 100644 --- a/py/import.go +++ b/py/import.go @@ -357,7 +357,10 @@ func BuiltinImport(ctx Context, self Object, args Tuple, kwargs StringDict, curr if !ok { return nil, ExceptionNewf(TypeError, "__import__() argument 5 must be int, not %s", level.Type().Name) } - levelInt := int(levelObj) + levelInt, err := levelObj.GoInt() + if err != nil { + return nil, err + } var globalsDict StringDict if globalsTyped, ok := globals.(StringDict); ok { From 2719465279229599e4387b2a9cc19076c0821fa3 Mon Sep 17 00:00:00 2001 From: AN Long Date: Thu, 26 Feb 2026 01:29:30 +0900 Subject: [PATCH 3/4] Update py/import.go Co-authored-by: Sebastien Binet --- py/import.go | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/py/import.go b/py/import.go index 56a72da3..2cbcfe0d 100644 --- a/py/import.go +++ b/py/import.go @@ -362,10 +362,8 @@ func BuiltinImport(ctx Context, self Object, args Tuple, kwargs StringDict, curr return nil, err } - var globalsDict StringDict - if globalsTyped, ok := globals.(StringDict); ok { - globalsDict = globalsTyped - } else { + globalsDict, ok := globals.(StringDict) + if !ok { if levelInt > 0 { return nil, ExceptionNewf(TypeError, "globals must be a dict") } From f8a9604f9886adee4c6b5909f70fdd27acad3854 Mon Sep 17 00:00:00 2001 From: AN Long Date: Thu, 26 Feb 2026 01:31:34 +0900 Subject: [PATCH 4/4] Apply the review comment --- py/import.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/py/import.go b/py/import.go index 2cbcfe0d..8adc8568 100644 --- a/py/import.go +++ b/py/import.go @@ -375,9 +375,8 @@ func BuiltinImport(ctx Context, self Object, args Tuple, kwargs StringDict, curr localsDict = StringDict{} } - if fromlist == None { - fromlistTuple = Tuple{} - } else { + fromlistTuple = Tuple{} + if fromlist != None { fromlistTuple, err = SequenceTuple(fromlist) if err != nil { return nil, err