)]}'
{
  "commit": "0bccc93d5baf62b78b4b62869c730873ad989e19",
  "tree": "8daf7dad6aeb7d1d8395ccb2350e2900f7dac7fe",
  "parents": [
    "4f0e290b10de49bc1ac3635f181762d5b6937d1e"
  ],
  "author": {
    "name": "Ding Qiuran",
    "email": "133388209+dynapx@users.noreply.github.com",
    "time": "Tue Oct 20 09:12:24 2026 -0700"
  },
  "committer": {
    "name": "Copybara-Service",
    "email": "copybara-worker@google.com",
    "time": "Tue Oct 20 09:23:42 2026 -0700"
  },
  "message": "Check Python object allocation failures in upb bindings (#30614)\n\n## Summary\n\nHandle failed Python object allocations in several upb Python binding paths.\n\nThis change addresses cases where `PyType_GenericAlloc()` could return `NULL`\nbut the result was used immediately without validation. In an allocation\nfailure scenario, the code could dereference a NULL pointer and terminate the\nPython process instead of propagating the allocation failure as a Python\nexception.\n\n## Background\n\n`PyType_GenericAlloc()` is a Python C API allocation function. It may return\n`NULL` when object allocation fails, for example when the process is under\nmemory pressure. Callers must check the returned pointer before initializing\nthe object.\n\nThe affected code paths assigned fields to the result immediately after the\nallocation call. If allocation failed, these assignments could dereference\n`NULL`, causing a native crash and preventing the original `MemoryError` from\nbeing propagated normally.\n\n## Affected paths\n\n### Extension dictionary creation\n\nPyUpb_Message_GetExtensionDict\n  -\u003e PyUpb_ExtensionDict_New\n  -\u003e PyType_GenericAlloc\n  -\u003e ext_dict-\u003emsg\n\nIf allocation failed, `ext_dict` was `NULL` before `ext_dict-\u003emsg` was accessed.\n\n### Map iterator creation\n\nPython map iteration\n  -\u003e PyUpb_MapIterator_New\n  -\u003e PyType_GenericAlloc\n  -\u003e iter-\u003emap\n\nThe iterator constructor used the allocated object before checking whether\nallocation succeeded.\n\n### Message object creation\n\nPyUpb_RepeatedCompositeContainer_AppendNew\n  -\u003e PyUpb_Message_Get\n  -\u003e PyUpb_Descriptor_GetClass\n  -\u003e PyType_GenericAlloc\n\nThe message creation path now returns immediately when class lookup or object\nallocation fails. An invalid `Py_DECREF(NULL)` in the allocation failure path\nwas also removed.\n\n## Impact\n\nThese issues are most relevant under allocation failure or severe memory\npressure rather than during ordinary input processing. Without the checks, a\nfailed allocation could result in:\n\n- NULL pointer dereference;\n- termination of the Python interpreter;\n- loss of the original allocation error;\n- failure to propagate `MemoryError` through the normal Python API.\n\nThe practical impact is primarily process stability and availability. The\npatch does not change the behavior of successful object creation.\n\n## Changes\n\n- Check the result of `PyType_GenericAlloc()` in\n  `PyUpb_ExtensionDict_New`.\n- Check the result of `PyType_GenericAlloc()` in\n  `PyUpb_MapIterator_New`.\n- Preserve the normal error return from `PyUpb_Message_Get()` when class lookup\n  or object allocation fails.\n- Remove the invalid `Py_DECREF(NULL)` from the message allocation failure\n  path.\n\nRelated allocation checks in other Python binding constructors are already\npresent in the current upstream code and are not duplicated by this change.\n\n## Significance\n\nThese checks make allocation failure paths conform to the Python C API error\nhandling convention. They ensure that object construction either returns a\nvalid initialized object or returns `NULL` so that the active Python exception\ncan be propagated to the caller.\n\nThis is a defensive stability improvement for unusual but valid interpreter\nstates, including memory pressure and allocation-failure testing.\n\nCloses #30614\n\nCOPYBARA_INTEGRATE_REVIEW\u003dhttps://github.com/protocolbuffers/protobuf/pull/30614 from dynapx:python-allocation-error-handling 0112317d1cd4ab5e9f072e807cab6e1648ad3f38\nPiperOrigin-RevId: 1003153689\n",
  "tree_diff": [
    {
      "type": "modify",
      "old_id": "838663b4ddba0bdebeb9182a9277ad18a81f40ac",
      "old_mode": 33188,
      "old_path": "python/convert.c",
      "new_id": "5c8bea8299beaf198cc9d7393eda16070645e30d",
      "new_mode": 33188,
      "new_path": "python/convert.c"
    },
    {
      "type": "modify",
      "old_id": "ed7dc362533adf22b3ecaa5d0af7bc523c834e36",
      "old_mode": 33188,
      "old_path": "python/extension_dict.c",
      "new_id": "708a89d62ed8080b7647d2942228b22deaf7529f",
      "new_mode": 33188,
      "new_path": "python/extension_dict.c"
    },
    {
      "type": "modify",
      "old_id": "2c21a179407539655bc68c8f4c682f18ac483830",
      "old_mode": 33188,
      "old_path": "python/google/protobuf/internal/message_factory_test.py",
      "new_id": "6fd6489ca987019ec4646258a8f8141e7cd75df5",
      "new_mode": 33188,
      "new_path": "python/google/protobuf/internal/message_factory_test.py"
    },
    {
      "type": "modify",
      "old_id": "21d2d438ee6015bebf692b21f9fa2ac8cca41801",
      "old_mode": 33188,
      "old_path": "python/map.c",
      "new_id": "274447b92735345fd43a803008b4492b9ef4d563",
      "new_mode": 33188,
      "new_path": "python/map.c"
    },
    {
      "type": "modify",
      "old_id": "6587d87251f888c305ef0578b3cdb6cd3f2e8728",
      "old_mode": 33188,
      "old_path": "python/message.c",
      "new_id": "317b4a6908091d2f3930fdf1f6d82f3730adc22d",
      "new_mode": 33188,
      "new_path": "python/message.c"
    }
  ]
}
