Replace the PyImport_ImportModule("mcrfpy") + PyObject_GetAttrString +
full type-call ceremony with direct &mcrfpydef::PyXType references
(safe since all PyTypeObjects are inline C++17 definitions) in every
non-init call site:
- UIDrawable: get_pos/get_origin/get_global_pos now allocate via
PyVector(...).pyObject(); set_pos/set_origin check the Vector type
directly.
- GridLayers: ColorLayer at/subscript wrap via PyColor(...).pyObject()
(also fixes a module refcount leak per read); set/fill/fill_rect,
draw_fov/apply_perspective color parsing, Entity/Texture/HeightMap
instance checks, and TileLayer texture get/set use direct type refs.
- UIGrid init layers=, add_layer/remove_layer/layer(), Grid.layers
getter: direct ColorLayer/TileLayer type refs.
- PyTileSetFile.to_texture, PyLdtkProject.tileset: direct type refs.
Benchmark (tests/benchmarks/issue_331_property_read_bench.py, 200k
reads, release build):
frame.pos 559 ns -> 65 ns/read (8.6x)
frame.origin 571 ns -> 64 ns/read (8.9x)
frame.global_position 589 ns -> 66 ns/read (8.9x)
ColorLayer.at 608 ns -> 262 ns/read (2.3x)
Test suite: 304/304 pass.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DK5DHgRDNGmpN54vnEHAot
WangSet.terrain_enum (and the parallel AutoRuleSet.terrain_enum) built a
Python IntEnum from parsed terrain/color names but ignored the return codes
of PyLong_FromLong, PyUnicode_FromString, and PyDict_SetItemString. A name
carrying invalid UTF-8 -- trivially reachable from an untrusted .tsx/.ldtk
import -- makes those calls fail and leave an exception pending. The code
then called PyObject_Call with that error already set, tripping CPython's
_PyErr_Occurred assertion and aborting (libFuzzer: deadly signal).
Both functions now check every C-API return, clean up their references, and
return NULL so the real exception (e.g. UnicodeDecodeError) propagates.
Verified by A/B replay of the #312 fuzz_import_parsers crash corpus under
clang-18 ASan/UBSan: the saved crash input aborts pre-fix inside
PyWangSet::terrain_enum -> PyObject_Call and runs clean post-fix. New
regression test crafts a .tsx with invalid-UTF-8 wangset/wangcolor names.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TvvE6TB2cScBVbeap2btHw