From 16c4b135f7591d4616d7e6f7584555da76c2f4addeb848398fd8ddb0eee25d0f Mon Sep 17 00:00:00 2001 From: Matej Cepl Date: Wed, 1 Jan 2025 23:41:54 +0000 Subject: [PATCH] - Add 313-compatibility.patch (gh#PiotrDabkowski/Js2Py#334) OBS-URL: https://build.opensuse.org/package/show/devel:languages:python/python-Js2Py?expand=0&rev=24 --- 313-compatibility.patch | 159 ++++++++++++++++++++++++++++++++++++++++ python-Js2Py.changes | 5 ++ python-Js2Py.spec | 5 +- 3 files changed, 168 insertions(+), 1 deletion(-) create mode 100644 313-compatibility.patch diff --git a/313-compatibility.patch b/313-compatibility.patch new file mode 100644 index 0000000..09f9ed5 --- /dev/null +++ b/313-compatibility.patch @@ -0,0 +1,159 @@ +From 0da30c83f149b15539ca3d246d5ebfb0afd7f140 Mon Sep 17 00:00:00 2001 +From: a-j-albert +Date: Sun, 15 Dec 2024 22:03:31 -0800 +Subject: [PATCH 1/2] My changes for 3.13 + +--- + js2py/utils/injector.py | 78 +++++++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 71 insertions(+), 7 deletions(-) + +--- a/js2py/utils/injector.py ++++ b/js2py/utils/injector.py +@@ -15,6 +15,10 @@ LOAD_FAST = opcode.opmap['LOAD_FAST'] + LOAD_GLOBAL = opcode.opmap['LOAD_GLOBAL'] + LOAD_ATTR = opcode.opmap['LOAD_ATTR'] + STORE_FAST = opcode.opmap['STORE_FAST'] ++LOAD_FAST_LOAD_FAST = opcode.opmap.get('LOAD_FAST_LOAD_FAST') ++STORE_FAST_LOAD_FAST = opcode.opmap.get('STORE_FAST_LOAD_FAST') ++STORE_FAST_STORE_FAST = opcode.opmap.get('STORE_FAST_STORE_FAST') ++EXTENDED_ARG = opcode.opmap.get('EXTENDED_ARG') + + + _func_closure = "__closure__" +@@ -43,6 +47,40 @@ def fix_js_args(func): + closure=get_function_closure(func)) + return result + ++def get_list_of_var_indices_in_compound_opcodes(code_obj, non_arg_varnames, arg_count): #E.g. STORE_FAST_LOAD_FAST ++ indices = set() ++ for inst in instructions(code_obj): ++ extended = False ++ if inst.opcode == EXTENDED_ARG: ++ extended = True ++ continue ++ if not extended and inst.opcode in (LOAD_FAST_LOAD_FAST, STORE_FAST_LOAD_FAST, STORE_FAST_STORE_FAST): ++ first_index = (inst.arg >> 4 & 0xF) - arg_count ++ second_index = (inst.arg & 0xF) - arg_count ++ if first_index >= 0: ++ indices.add(first_index) ++ if second_index >= 0: ++ indices.add(second_index) ++ extended = False ++ return indices ++ ++def rearrange_by_indices(strings, indices): ++ """ ++ Rearranges the strings in the list so that the elements corresponding ++ to the indices are at the beginning of the list. ++ ++ Args: ++ strings (list): The list of strings. ++ indices (list): A list of indices into the strings list. ++ ++ Returns: ++ list: A new list with rearranged elements. ++ """ ++ # Extract elements based on indices ++ prioritized = [strings[i] for i in indices if 0 <= i < len(strings)] ++ # Include elements not in indices ++ remaining = [strings[i] for i in range(len(strings)) if i not in indices] ++ return prioritized + remaining + + def append_arguments(code_obj, new_locals): + co_varnames = code_obj.co_varnames # Old locals +@@ -56,9 +94,9 @@ def append_arguments(code_obj, new_local + # left in code_obj.co_names. + not_removed = set(opcode.hasname) - set([LOAD_GLOBAL]) + saved_names = set() +- for inst in instructions(code_obj): +- if inst[0] in not_removed: +- saved_names.add(co_names[inst[1]]) ++ # for inst in instructions(code_obj): ++ # if inst.opcode in not_removed: ++ # saved_names.add(co_names[inst.oparg]) + + # Build co_names for the new code object. This should consist of + # globals that were only accessed via LOAD_GLOBAL +@@ -70,18 +108,21 @@ def append_arguments(code_obj, new_local + name_translations = dict( + (co_names.index(name), i) for i, name in enumerate(names)) + ++ non_arg_varnames = co_varnames[co_argcount:] # All varibles after the arguments ++ early_indices = get_list_of_var_indices_in_compound_opcodes(code_obj, non_arg_varnames, co_argcount) ++ rearranged_non_arg_varnames = rearrange_by_indices(non_arg_varnames, early_indices) + # Build co_varnames for the new code object. This should consist of + # the entirety of co_varnames with new_locals spliced in after the + # arguments + new_locals_len = len(new_locals) + varnames = ( +- co_varnames[:co_argcount] + new_locals + co_varnames[co_argcount:]) ++ co_varnames[:co_argcount] + new_locals + tuple(rearranged_non_arg_varnames)) + + # Build the dictionary that maps indices of entries in the old co_varnames + # to their indices in the new co_varnames + range1, range2 = xrange(co_argcount), xrange(co_argcount, len(co_varnames)) + varname_translations = dict((i, i) for i in range1) +- varname_translations.update((i, i + new_locals_len) for i in range2) ++ varname_translations.update((i, varnames.index(co_varnames[i])) for i in range2) + + # Build the dictionary that maps indices of deleted entries of co_names + # to their indices in the new co_varnames +@@ -94,6 +135,7 @@ def append_arguments(code_obj, new_local + modified = [] + drop_future_cache = False + for inst in instructions(code_obj): ++ # print(inst.opname + ' - ' + str(inst.line_number)) + if is_new_bytecode and inst.opname == "CACHE": + assert inst.arg == 0 + if not drop_future_cache: +@@ -124,9 +166,18 @@ def append_arguments(code_obj, new_local + arg = tgt + else: + raise(ValueError("a name was lost in translation last instruction %s" % str(inst))) ++ elif inst.opcode in (LOAD_FAST_LOAD_FAST, STORE_FAST_LOAD_FAST, STORE_FAST_STORE_FAST): ++ old_first_arg = inst.arg >> 4 & 0xF ++ old_second_arg = inst.arg & 0xF ++ new_first_arg = varname_translations[old_first_arg] ++ new_second_arg = varname_translations[old_second_arg] ++ arg = new_first_arg << 4 | new_second_arg + # If it accesses co_varnames or co_names then update its argument. + elif inst.opcode in opcode.haslocal: +- arg = varname_translations[inst.arg] ++ if arg < len(varname_translations): # Otherwise cellvar whose arg gets incremented by new_locals_len ++ arg = varname_translations[inst.arg] ++ else: ++ arg += new_locals_len + elif inst.opcode in opcode.hasname: + # for example STORE_GLOBAL + arg = name_translations[inst.arg] +@@ -135,6 +186,12 @@ def append_arguments(code_obj, new_local + if inst.argval not in code_obj.co_varnames[:code_obj.co_argcount]: # we do not need to remap existing arguments, they are not shifted by new ones. + arg = inst.arg + len(new_locals) + modified.extend(write_instruction(op, arg)) ++ if hasattr(inst, 'end_offset'): # Assume otherwise instructions will have explicit CACHE entries ++ for inline_cache in range(int((inst.end_offset - inst.cache_offset) / 2)): ++ if not drop_future_cache: ++ modified.extend(write_instruction(0, 0)) ++ else: ++ modified.extend(write_instruction(dis.opmap["NOP"], 0)) + code = bytes(modified) + args = (co_argcount + new_locals_len, 0, + code_obj.co_nlocals + new_locals_len, code_obj.co_stacksize, +@@ -229,9 +286,16 @@ def check(code_obj): + pos_to_inst = {} + bytelist = [] + ++ offset = 0 ++ instruction_bytes = None + for inst in insts: + pos_to_inst[len(bytelist)] = inst +- bytelist.extend(write_instruction(inst.opcode, inst.arg)) ++ if instruction_bytes: ++ for gap_byte in range(inst.offset - offset - len(instruction_bytes)): ++ bytelist.append(0) ++ offset = inst.offset ++ instruction_bytes = write_instruction(inst.opcode, inst.arg) ++ bytelist.extend(instruction_bytes) + new_bytecode = bytes(bytelist) + if new_bytecode != old_bytecode: + print(new_bytecode) diff --git a/python-Js2Py.changes b/python-Js2Py.changes index f3d19d1..a5bf92f 100644 --- a/python-Js2Py.changes +++ b/python-Js2Py.changes @@ -1,3 +1,8 @@ +------------------------------------------------------------------- +Wed Jan 1 23:38:45 UTC 2025 - Matej Cepl + +- Add 313-compatibility.patch (gh#PiotrDabkowski/Js2Py#334) + ------------------------------------------------------------------- Mon Jul 1 08:39:07 UTC 2024 - Daniel Garcia diff --git a/python-Js2Py.spec b/python-Js2Py.spec index ef16007..92c02b2 100644 --- a/python-Js2Py.spec +++ b/python-Js2Py.spec @@ -1,7 +1,7 @@ # # spec file for package python-Js2Py # -# Copyright (c) 2024 SUSE LLC +# Copyright (c) 2025 SUSE LLC # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -32,6 +32,9 @@ Patch0: remove-python-six.patch Patch1: python312.patch # PATCH-FIX-UPSTREAM CVE-2024-28397.patch gh#PiotrDabkowski/Js2Py#323 Patch2: CVE-2024-28397.patch +# PATCH-FIX-UPSTREAM 313-compatibility.patch gh#PiotrDabkowski/Js2Py#334 mcepl@suse.com +# Compatibility with Python 3.13 +Patch3: 313-compatibility.patch BuildRequires: %{python_module pyjsparser} BuildRequires: %{python_module setuptools} BuildRequires: fdupes