Check Python C-API returns in terrain_enum builders; closes #322
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
This commit is contained in:
parent
79df32317b
commit
a2c76c3643
3 changed files with 138 additions and 4 deletions
|
|
@ -129,7 +129,12 @@ PyObject* PyAutoRuleSet::terrain_enum(PyAutoRuleSetObject* self, PyObject*) {
|
|||
|
||||
// NONE = 0 (empty terrain)
|
||||
PyObject* zero = PyLong_FromLong(0);
|
||||
PyDict_SetItemString(members, "NONE", zero);
|
||||
if (!zero || PyDict_SetItemString(members, "NONE", zero) < 0) {
|
||||
Py_XDECREF(zero);
|
||||
Py_DECREF(members);
|
||||
Py_DECREF(int_enum);
|
||||
return NULL;
|
||||
}
|
||||
Py_DECREF(zero);
|
||||
|
||||
for (const auto& v : rs.intgrid_values) {
|
||||
|
|
@ -139,15 +144,33 @@ PyObject* PyAutoRuleSet::terrain_enum(PyAutoRuleSetObject* self, PyObject*) {
|
|||
key = "VALUE_" + std::to_string(v.value);
|
||||
}
|
||||
PyObject* val = PyLong_FromLong(v.value);
|
||||
PyDict_SetItemString(members, key.c_str(), val);
|
||||
// An intgrid value name carrying invalid UTF-8 (untrusted import data)
|
||||
// makes PyDict_SetItemString fail and leaves an exception pending; bail
|
||||
// now rather than calling more Python API with that error set, which
|
||||
// trips a _PyErr_Occurred assertion / abort. #322
|
||||
if (!val || PyDict_SetItemString(members, key.c_str(), val) < 0) {
|
||||
Py_XDECREF(val);
|
||||
Py_DECREF(members);
|
||||
Py_DECREF(int_enum);
|
||||
return NULL;
|
||||
}
|
||||
Py_DECREF(val);
|
||||
}
|
||||
|
||||
// Create enum class: IntEnum(rs.name, members)
|
||||
PyObject* name = PyUnicode_FromString(rs.name.c_str());
|
||||
if (!name) {
|
||||
Py_DECREF(members);
|
||||
Py_DECREF(int_enum);
|
||||
return NULL;
|
||||
}
|
||||
PyObject* args = PyTuple_Pack(2, name, members);
|
||||
Py_DECREF(name);
|
||||
Py_DECREF(members);
|
||||
if (!args) {
|
||||
Py_DECREF(int_enum);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyObject* enum_class = PyObject_Call(int_enum, args, NULL);
|
||||
Py_DECREF(args);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue