)]}'
{
  "commit": "bf6e3afaae50ae85fd1069db3c0d8b6eaf9c04fa",
  "tree": "f61edded5dba145fbaf816f20bf80dcea56d48e3",
  "parents": [
    "fdec8c350aa0c7fbb552ec70d8176f8a13eb0561"
  ],
  "author": {
    "name": "Junhyung Lee",
    "email": "70549809+espressolee@users.noreply.github.com",
    "time": "Sat Oct 24 01:30:25 2026 +0800"
  },
  "committer": {
    "name": "GitHub",
    "email": "noreply@github.com",
    "time": "Fri Oct 23 10:30:25 2026 -0700"
  },
  "message": "fix(free-threading): cast `self` directly in `cpp_function::dispatcher` (#6177)\n\n* fix(free-threading): cast `self` directly in `cpp_function::dispatcher`\n\nPart of #6159 (item 59).\n\nUnder Py_GIL_DISABLED, cpp_function::dispatcher() took the internals lock\non every bound call: it reached its function_record through\nfunction_record_ptr_from_PyObject(), which calls\nget_function_record_PyTypeObject() (PYBIND11_LOCK_INTERNALS on\ninternals.mutex).\n\ndispatcher is installed in exactly one place (initialize_generic), and the\nPyCFunction there is created with m_self set to the function_record_PyObject\nallocated a few lines above, so self is always that object. The new\nfunction_record_ptr_from_dispatcher_self() states that invariant once and\ncasts directly; its assert compares the versioned tp_name instead of calling\nis_function_record_PyObject(), which would reacquire the lock in non-NDEBUG\nbuilds. is_function_record_PyObject() and function_record_ptr_from_PyObject()\nare unchanged, so the call sites that can see a foreign object keep the\nchecked conversion.\n\nAdds test_dispatch_does_not_need_internals_lock (free-threaded builds only):\na native thread holds internals.mutex through raw PyCFunction helpers and the\ntest checks that a bound call returns before the holder\u0027s watchdog releases\nthe mutex, with a positive control proving the held mutex is the one internals\nusers take. Fails without the fix, passes with it.\n\nAssisted-by: Claude Code:claude-opus-5\n\n* test: put the source tests dir on the subprocess path\n\npybind11_tests imports custom_exceptions from the source tests directory at\ninit, so the subprocess must see that directory as well as the build\ndirectory, as test_custom_type_setup.py does.\n\nAssisted-by: Claude Code:claude-opus-5\n\n* style: qualify function-record name comparisons with std::strcmp\n\nApply the review suggestion to both sibling comparisons; retain the existing cstring include.\n\nAssisted-by: Codex:GPT-6",
  "tree_diff": [
    {
      "type": "modify",
      "old_id": "42b0e96be74e22afbbf81e57c4416f9e443c86d2",
      "old_mode": 33188,
      "old_path": "include/pybind11/detail/function_record_pyobject.h",
      "new_id": "2e66944b9cc51d1f0192a8862cb80f32192b9607",
      "new_mode": 33188,
      "new_path": "include/pybind11/detail/function_record_pyobject.h"
    },
    {
      "type": "modify",
      "old_id": "24e13592208f1de97da493c7eaa14fdd6d0e5985",
      "old_mode": 33188,
      "old_path": "include/pybind11/pybind11-inl.h",
      "new_id": "0cfe9fc28ce08d38fed96c35126650654041d669",
      "new_mode": 33188,
      "new_path": "include/pybind11/pybind11-inl.h"
    },
    {
      "type": "modify",
      "old_id": "131bd87710eedf8118824429f8fa4fb14ddcd36c",
      "old_mode": 33188,
      "old_path": "tests/test_thread.cpp",
      "new_id": "f64a1668503c8afc2bb202cd2c51cb521c52f27c",
      "new_mode": 33188,
      "new_path": "tests/test_thread.cpp"
    },
    {
      "type": "modify",
      "old_id": "d302c382c2f591ea31db9eed3217cd8c1a254340",
      "old_mode": 33188,
      "old_path": "tests/test_thread.py",
      "new_id": "d688f9ee91f28c0bd1a901aedb861472702defd1",
      "new_mode": 33188,
      "new_path": "tests/test_thread.py"
    }
  ]
}
