Skip to content

PyArmored code crashes stochastically on hash calculation for frame.f_code #2300

@himkt

Description

@himkt

I prepared the simple Python script to get a frame object and try to calculate a hash of f_core.

import sys
from pathlib import Path

# note; pyarmor_segv is simple python module only with pathlib to raise exception.
# https://github.com/himkt/pyarmor-hash-segv/blob/main/src/pyarmor_segv/__init__.py
from pyarmor_segv import func  # pyright: ignore[reportMissingImports]

try:
    func(Path('empty'))
except ValueError:
    # Get the obfuscated function's frame
    tb = sys.exc_info()[2].tb_next  # type: ignore
    frame = tb.tb_frame  # type: ignore
    code = frame.f_code
    print(f"frame.f_code: {code}")
    print(f"co_name: {code.co_name}")
    print(f"Computing hash(frame.f_code)...: {hash(code)}")
    print("Success")

I repeatedly generated the obfuscated module and ran the script (replicate.sh, you can see the script in https://github.com/himkt/pyarmor-hash-segv) to get segmentation faults stochastically.

> ./replicate.sh 
Trial  1: frame.f_code: <code object func at 0x7776cf78c370, file "<frozen pyarmor_segv>", line 5>
co_name: func
Computing hash(frame.f_code)...: -3915728441605713561
Success
Normal ✓
Trial  2: frame.f_code: <code object func at 0x7251b5ec8370, file "<frozen pyarmor_segv>", line 5>
co_name: func
SEGFAULT ✗
Trial  3: frame.f_code: <code object func at 0x764dbfd10370, file "<frozen pyarmor_segv>", line 5>
co_name: func
SEGFAULT ✗
Trial  4: frame.f_code: <code object func at 0x733c5db98370, file "<frozen pyarmor_segv>", line 5>
co_name: func
Computing hash(frame.f_code)...: -1940020248159428493
Success
Normal ✓
Trial  5: frame.f_code: <code object func at 0x7b56701c8370, file "<frozen pyarmor_segv>", line 5>
co_name: func
SEGFAULT ✗
Trial  6: frame.f_code: <code object func at 0x7b871eb74370, file "<frozen pyarmor_segv>", line 5>
co_name: func
Computing hash(frame.f_code)...: -5207489521542538451
Success
Normal ✓
Trial  7: frame.f_code: <code object func at 0x7f8314848370, file "<frozen pyarmor_segv>", line 5>
co_name: func
SEGFAULT ✗
Trial  8: frame.f_code: <code object func at 0x735fb1d6c370, file "<frozen pyarmor_segv>", line 5>
co_name: func
SEGFAULT ✗
Trial  9: frame.f_code: <code object func at 0x74676b578370, file "<frozen pyarmor_segv>", line 5>
co_name: func
SEGFAULT ✗
Trial 10: frame.f_code: <code object func at 0x72a01b358370, file "<frozen pyarmor_segv>", line 5>
co_name: func
SEGFAULT ✗

In IPython scenario (I think it is related to #2293):

  1. IPython exception handler calls get_records() in ultratb.py
  2. Calls stack_data.FrameInfo.stack_data(etb, ...) in ultratb.py
  3. stack_data/core.py calls Source.executing(frame_or_tb)
  4. executing/executing.py creates dict key: key = (frame.f_code, id(code), lasti)
  5. executing_cache.get(key) triggers hash(key)hash(frame.f_code)
  6. PyArmor-corrupted frame.f_code causes SEGFAULT when hashed

Metadata

Metadata

Assignees

No one assigned

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions