diff --git a/fickling/fickle.py b/fickling/fickle.py index 723eed6..ee51ed4 100644 --- a/fickling/fickle.py +++ b/fickling/fickle.py @@ -1126,6 +1126,26 @@ def run(self, interpreter: Interpreter): return objs +class Obj(Opcode): + name = "OBJ" + + def run(self, interpreter: Interpreter): + args = [] + while interpreter.stack: + arg = interpreter.stack.pop() + if isinstance(arg, MarkObject): + break + args.insert(0, arg) + else: + raise ValueError("Exhausted the stack while searching for a MarkObject!") + kls = args.pop(0) + # TODO Verify paths for correctness + if args or hasattr(kls, "__getinitargs__") or not isinstance(kls, type): + interpreter.stack.append(ast.Call(kls, args, [])) + else: + interpreter.stack.append(ast.Call(kls, kls, [])) + + class ShortBinUnicode(DynamicLength, ConstantOpcode): name = "SHORT_BINUNICODE" priority = 5000 @@ -1475,6 +1495,22 @@ def validate(cls, obj): return obj +class BinString(DynamicLength, ConstantOpcode): + name = "BINSTRING" + priority = ShortBinBytes.priority + 1 + length_bytes = 4 + signed = True + + def encode_body(self) -> bytes: + return repr(self.arg).encode("utf-8") + + @classmethod + def validate(cls, obj): + if not isinstance(obj, str): + raise ValueError(f"String must be instantiated from a str, not {obj!r}") + return super().validate(obj) + + class BinBytes(ShortBinBytes): name = "BINBYTES" priority = ShortBinBytes.priority + 1 diff --git a/test/test_crashes.py b/test/test_crashes.py index d69f1c9..43c3c73 100644 --- a/test/test_crashes.py +++ b/test/test_crashes.py @@ -62,3 +62,8 @@ def test_pop_mark(self): """Tests the correctness of the POP_MARK opcode by using the bytecode from https://github.com/mindspore-ai/mindspore/issues/183 This can be simplified to allow for the correctness of additional opcodes to be tested""" pass + + @unparse_test(io.BytesIO(b'(cos\nsystem\nS"whoami"\no.')) + def test_obj(self): + """Tests the correctness of the OBJ opcode""" + pass