<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/140241>140241</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            cursor.extent or clang_getCursorExtent() crashes on TRANSLATION_UNIT cursor on macOS, but works on Linux
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            new issue
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          zokrezyl
      </td>
    </tr>
</table>

<pre>
    # Title:
`clang_getCursorExtent()` crashes on TRANSLATION_UNIT cursor on macOS but works on Linux

## Description:

When calling `clang_getCursorExtent()` on a `CursorKind.TRANSLATION_UNIT` cursor, and then accessing `.start` or `.end` of the resulting `CXSourceRange`, a **segmentation fault occurs on macOS**.

This happens **consistently across**:

- **Python versions**: 3.11, 3.12, 3.13, and 3.14
- **Clang versions**: 18.x.y and 19.x.y (built from Homebrew or official sources)
- **macOS versions**: (tested on macOS 14.4+ Apple Silicon and Intel)

## Reproducer (Python `clang.cindex` bindings):

```python
from clang import cindex

cindex.Config.set_library_file("/opt/homebrew/opt/llvm/lib/libclang.dylib")  # adjust if needed

index = cindex.Index.create()
tu = index.parse("example.cpp", args=["-std=c++17"])  # file contains `int main() { return 0; }`

cursor = tu.cursor  # this is of kind TRANSLATION_UNIT

# These work:
print(cursor.kind)
print(cursor.spelling)
print(cursor.location)

# This also works (struct is returned)
print(cursor.extent.ptr_data)
print(cursor.extent.begin_int_data)
print(cursor.extent.end_int_data)

# But this crashes:
print(cursor.extent.start)  # or `.end` → causes a segmentation fault on macOS
```

On Linux, this behaves safely — `extent.start.file` may be `None`, but no crash occurs.

## C-level Reproducer:

```c
CXIndex index = clang_createIndex(0, 0);
CXTranslationUnit tu = clang_parseTranslationUnit(index, "example.cpp", NULL, 0, NULL, 0, CXTranslationUnit_None);
CXCursor cursor = clang_getTranslationUnitCursor(tu);

CXSourceRange range = clang_getCursorExtent(cursor);
CXSourceLocation start = clang_getRangeStart(range);  // 💥 Segfaults on macOS
```

## Expected Behavior

`clang_getCursorExtent()` should never return a `CXSourceRange` that causes `clang_getRangeStart()` or `clang_getRangeEnd()` to crash, even for synthetic cursors like `TRANSLATION_UNIT`.

If no valid extent exists, it should:
- return a dummy or sentinel range, or
- document that `.extent` is unsafe to access on certain kinds (not currently documented in `libclang`)

## Notes

- This crash does not occur when calling `.extent.start` on normal entities like functions, structs, typedefs, etc.
- The bug only affects the `TRANSLATION_UNIT` cursor, which is returned by `clang_getTranslationUnitCursor()`.
- The Python `clang.cindex` binding merely exposes the crash; the underlying issue is in `clang_getRangeStart()` accessing bad memory.

## Suggested Fix

Either:

- Have `clang_getCursorExtent()` return a well-defined dummy `CXSourceRange` for `TRANSLATION_UNIT`, or
- Have `clang_getRangeStart()` gracefully reject invalid or synthetic ranges, or
- Document that `TRANSLATION_UNIT` has no valid range

</pre>
<img width="1" height="1" alt="" src="http://email.email.llvm.org/o/eJyUV0tv4zgS_jX0pRBBovw8-GA7MSbYIL3opLFzCyiqJHFCkQJJOfH8-gVJ-RlvZwcIHMks1vv7qsysFbVCXJLJmkzuR6x3jTbLv_W7wb_3clTocr8kNIdX4SSSfEXSFZmmXDJVv9XoNr2x2jx8OlSO0DmhCzJNgRtmG7SgFbz-XD2_PK1eH388v_16fnwFHm74o5bxHy9Q9A4-tHkP0k9C9Z_eRLoiNPd279FyIzontBqsp6v_NKiAMymFquF7b7QC5sXi6b-EKpNrr4LT4ZjQDTBVgvM2GOdo7WAlsY4ZFxSa8I6qDG-VFwaDtpdukN38-aJ7w_EnUzWSaRq0AqErQlcW6xaVYz4kqFgvHWjujR9zEuWSGOxrIyw0rOtQ2UED18oK64OUe2DcaGvjwTFDd4Pkv_eu0Qp2aKzQ6iQFeZJl3qk8yejwPz-EnifZ-EzHxmf3hopsnnwm-3AjW4RHQudFL6SDyugW_tAtFgY_fLp0VQkumAQb0mJ9ZU4WYiN8tUDo3KF1WJ66JRsnY0LXsOo6ifAipOC-vKqER-VQRr2n7vmJndFlz9F4ZUM2Dh2TcKFK_PQ1LIQqhaqDX4cc-rKFvy5cI-kqhBWugmg7bRwMGoJ8fE42WlWiTiy6NykKw8z-rRISQztSQre6c4RumyE5xy-k3LX-nyjiZ_Sw3IcvKKELAB8QK__qrQNRgUIssYymg2Ug-f3gUPIYPrlB5nAAQrpyfRCJEh0zdnAKP1nbSUx41wVTG2CmtiS_95xA6Z11JcnvOaFrQtfZzMtM7o8e-eCAa-WY8A06TYVy0DKhol0gszUYdL1RkJJ8DWR279MaUxa5wHvl-mR4C1qd73phPbjehSq_0MixyvDaoMXAILFynREB_FFb4m_H8K8ObIeBQG4eSs0DPs_7CQISmbR64CtC59aZnjvvaAwRb9vCwEhJ58xbyRz7nUyBtVBvQrlvJVGVV3KDn-vexfwNNHwzL4OSyGmHWl4SG3mgZD4lCwqc9RYtMLjFXQfSOkNM9OXHgc_pJvpTYMN2aMGyCuU-6k_JYuyNnvuTBMBMU2jZHgr0x89aHXjUDwylY3ADcyYXoN_cSdyhPAP_V0xzkq42fwaYwBl6wiCJsAlnhM6DzTQQwzpcejVMWRlS8EsJBwOs4t0AqysJQueRJugGbsLt-dfT02Dl6uWLtbeQiJMzcabBGZCOw_Dq5mYYb3PXH-8HFWeTCkz4vFBzNVMPU_LoQbz-NAAGQgEvNQTVL7HR5sFCvO57bkvoFsg2JYstWVCymsAL1qGx7G86ayj0w2eH3I-HtW8soc2xyN9sBLbRvSxB4Q7NgZzYrbkNrmHu0P7nei9iOuwZ5qvIg2efg4AbutZXFneooNIG7F65Bp3gQxEtSPEeev7GkjI0-mPlEbBjUpQQgQP4KayzXrNwQ3yx6-9OAZZ92-69mxaVEwolDNXYQMjdHZSa9x7gMe7ABTF109STXK88dH0ccTPyJeJoPPUHmg6cqLTzoZi4nhw0YgkijN7DbAtovpzWz9qhPSwwr0cGg1KjBa82oB0-rta_Sy6LC5_SpmUSfJxO4JDTqlfcxRVjA5G6w6Pbd1hiFZ7R8WSwj1D0NWjll6yqQu5sWPRuV-ZsffxoBG_OZwIU-4vO-F_IjG1yMv_tvgItGs-k-Nlp36Hevdhh-Tq89KpEI_deVFjbo_dKqG87-bT3FqyEFltt9pcc-9LXdVzNtmLYfx6Ea86o9g7-YDv8P9bzY3t-oJR3JVbCpyz26i1IVhFnN2pw1shfbN8KszaMY9VLuQeDf6Ef5CqC6gKXAST2TPn9NUpu9UPD7AmkEWfpalQu83KRL9gIl9lsPMsXk_lkMmqW80WJi4wv5mmKaTWdTvJsvpjP5-NpSdMipSOxpCmdpJNsmmXjcTZJxrOUL_LZdJZV-aygEzJOsWVCJn6TTLSpR6Hiy2yc0nE2kqxAaZdxpVP4Efsh7nIjs_SX7oq-tmScSs8kJzXO__JbXqwNPj-_qeo_-f13mOiXPwFHvZHLxrkuLC9hStTCNX2RcN2ebcve685oXztCtyEkS-h2iHm3pP8NAAD__xV7wLg">