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

    <tr>
        <th>Summary</th>
        <td>
            [bindings] OCaml bindings will cause use after free, in consequence of mixed manual and automatic memory management
        </td>
    </tr>

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

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

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

<pre>
    ## Background

In LLVM OCaml bindings, most types (e.g. `LLVMContext`, `LLVMModule`) have lifetimes that are manually-managed. The user needs to explicitly call the dispose function of these types:

https://github.com/llvm/llvm-project/blob/7d742f97b035f8dd9adaeccb98a28d1b7586f343/llvm/bindings/ocaml/llvm/llvm_ocaml.c#L229-L240

However, the two builder types, `LLVMBuilder` and `LLVMDIBuilder`, have their lifetimes managed by the OCaml GC, disposing when and only when the value is collected. Notice the finalizer callback passed into the allocator:

https://github.com/llvm/llvm-project/blob/7d742f97b035f8dd9adaeccb98a28d1b7586f343/llvm/bindings/ocaml/llvm/llvm_ocaml.c#L1972-L1991

## The problem

**In this scenario, the builder types may unexpectedly outlive the contexts.** The user cannot manually free the values to mitigate the issue, since their lifetimes are managed by the GC.

If the OCaml GC collects the builder types **after** the contexts have been manually freed, the builders' dispose function may access data in the contexts already freed. This will cause a use-after-free issue.

The issue is especially troublesome on `LLVMDIBuilder`, where the dispose function also calls `LLVMDIBuilderFinalize`, which **will definitely** access the data in `LLVMModule`s.

https://github.com/llvm/llvm-project/blob/c2692afc0a92cd5da140dfcdfff7818a5b8ce997/llvm/bindings/ocaml/debuginfo/debuginfo_ocaml.c#L183-L208


An example program that triggers this bug may look like this:


```ocaml
let cx = Llvm.create_context () in
let m = Llvm.create_module cx in
let di_builder = Llvm_debuginfo.dibuilder m in
(*
  ... 
  user generates code using LLVM
  ...
*)
Llvm_debuginfo.dibuild_finalize di_builder;
(* di_builder is *not* freed here! *)

(* user exports code... *)
Llvm.dispose_module m;
Llvm.dispose_context cx;

let something = allocate () in ...
(* now the user allocates something and triggers a GC cycle.
   GC: sweeps di_builder;
       calls finalizer;
       finalizer accesses already-freed code.
  
   BOOM!
 *)
```


The following is part of a valgrind trace of this issue, recorded in a real program. This eventually caused a segmentation fault of the program.

```
==1437619== Invalid read of size 8
==1437619==    at 0x5AF1F99: llvm::MetadataTracking::track(void*, llvm::Metadata&, llvm::PointerUnion<llvm::MetadataAsValue*, llvm::Metadata*, llvm::DebugValueUser*>) (in /usr/lib/libLLVM.so.18.1)
==1437619==    by 0x59D1971: llvm::DIBuilder::finalizeSubprogram(llvm::DISubprogram*) (in /usr/lib/libLLVM.so.18.1)
==1437619==    by 0x59D1D3E: llvm::DIBuilder::finalize() (in /usr/lib/libLLVM.so.18.1)
==1437619==    by 0xD5346C: llvm_finalize_dibuilder (debuginfo_ocaml.c:184)
==1437619==    by 0xD6982D: caml_empty_minor_heap (minor_gc.c:413)
==1437619==    by 0xD69C97: caml_gc_dispatch (minor_gc.c:492)
==1437619==    by 0xD69E14: caml_alloc_small_dispatch (minor_gc.c:539)
...
==1437619==  Address 0x11d61408 is 56 bytes inside a block of size 120 free'd
==1437619==    at 0x4849424: operator delete(void*) (vg_replace_malloc.c:1131)
==1437619== by 0x5AC94B4: llvm::LLVMContextImpl::~LLVMContextImpl() [clone .part.0] (in /usr/lib/libLLVM.so.18.1)
==1437619==    by 0x5AB7DB4: llvm::LLVMContext::~LLVMContext() (in /usr/lib/libLLVM.so.18.1)
==1437619== by 0x59AC971: LLVMContextDispose (in /usr/lib/libLLVM.so.18.1)
==1437619== by 0xD55AE8: llvm_dispose_context (llvm_ocaml.c:237)
==1437619==    by 0x6DB022: camlLlvm__fun_3347 (in ...)
...
==1437619==  Block was alloc'd at
==1437619==    at 0x4845F93: operator new(unsigned long) (vg_replace_malloc.c:487)
==1437619==    by 0x5AF0AE3: llvm::MDNode::operator new(unsigned long, unsigned long, llvm::Metadata::StorageType) (in /usr/lib/libLLVM.so.18.1)
==1437619==    by 0x5A17A48: llvm::DISubprogram::getImpl(llvm::LLVMContext&, llvm::Metadata*, llvm::MDString*, llvm::MDString*, llvm::Metadata*, unsigned int, llvm::Metadata*, unsigned int, llvm::Metadata*, unsigned int, int, llvm::DINode::DIFlags, llvm::DISubprogram::DISPFlags, llvm::Metadata*, llvm::Metadata*, llvm::Metadata*, llvm::Metadata*, llvm::Metadata*, llvm::Metadata*, llvm::MDString*, llvm::Metadata::StorageType, bool) (in /usr/lib/libLLVM.so.18.1)
==1437619==    by 0x59D59F2: llvm::DIBuilder::createFunction(llvm::DIScope*, llvm::StringRef, llvm::StringRef, llvm::DIFile*, unsigned int, llvm::DISubroutineType*, unsigned int, llvm::DINode::DIFlags, llvm::DISubprogram::DISPFlags, llvm::MDTupleTypedArrayWrapper<llvm::DITemplateParameter>, llvm::DISubprogram*, llvm::MDTupleTypedArrayWrapper<llvm::DIType>, llvm::MDTupleTypedArrayWrapper<llvm::DINode>, llvm::StringRef) (in /usr/lib/libLLVM.so.18.1)
==1437619==    by 0x59E52DF: LLVMDIBuilderCreateFunction (in /usr/lib/libLLVM.so.18.1)
==1437619==    by 0xD539AD: llvm_dibuild_create_function_native (debuginfo_ocaml.c:285)
==1437619==    by 0x6D754A: camlLlvm_debuginfo__fun_1435 (in ...)
...
```

</pre>
<img width="1" height="1" alt="" src="http://email.email.llvm.org/o/eJzMWV1z66oV_TXKCxOPhCRbesiDYsW3mcm590zPubePHgRbMg0CF1AS34f-9g4g-TNfnabTnvGcWAg2m7XX2hswMYZ3EuAmym-jvL4ig90ofSN28k9NJLtqFNvdRDiNcIpuCX3stBoki-Iqiqt7iR4e_viGfluSXqCGS8ZlZyK8RL0yFtndFgyKcAGzboaieew6L5W08GKjeez6jY3fFBsE-LYSbcgTIMFbsLwHg-yGWEQ0oJ7IgQixu-6JJB2wGfq5ATQY0EgCMIOsQvCyFZxyK3aIEiGQ3QBi3GyVAdQOklquJFKtazcQHIzSKqxmY-3WP-FVhFcdt5uhmVHVR3glxNP053qr1d-B2givGqGaCK8WbJHhtlw0cZq3BWMlYQQobcqC4IIlzSIv5m2apQc7B6RWipJenM6w9m0zGuH0AePy-gFncfDwL-oZnkA74NzC7LNCzcAFAz0u5YDobWiP5jEikk2t9f2h3XX2UNsNcH0E-AgvanZ-lhDcX5auf4CSyw49b0B6y0qKXXhynZ-IGABxg6gSAqh1UfpVWU79NKjlkgj-J2gfnYbQR7QlxgBDXFrluxAhFCVW6f_ruCTlAl8_JGWZBB9HgThCbrVqBPRTu_vcO3C4QYaCJJqrKYAnwUM92aFBwsvW4yZ2SA1W8BAgRINszCxYPFCfEimV3YsDtRrgEAovip5b3hEbmrkxAzgHDJf0Mvij0I4J8MtyNsq9PSHEFGPzylqCl6S1jq3e4eNFBN41APLUb3YGjInw4lK-DidCKRiDGLEEcXlqnAgNhI0WXZLgBj1zIRAlgwFEHG7X3rVrD5ZHZFzizwkhx2EwW6Dce2e1GhoBRvWAlHxLTs8b0PB6ziHCKE96czF4NYpib4TTzQigd5tByyW3IHYjlOPi_TwjAOd51Mz-M-1QPC8xaWlMSkxZzkiSxaylrG3bRZEUJG8KCmW5eFc7DJqh47JVx99PVFSk1w84LkatxFUlEbyQfiu8jDpN-pD-reZdB9oEGTVD50kglHpEgj-Cb97nC_eZx-ETXIkrARbRFxSlNXoQT_2MaiAW1iNnXI1ylYfLsWt_0bP3yDob-06MryfST73X-2XOGJ9e9mGIn8M5h9BsNkP-i1dwBxI0seCSJnOqdvnVRXPqO-WRMoqr12dZT4n1yKkovd3Peuwr9-qUyrp2rxHkaBvhBO1nOQz0HsLLVmkb_PO-H3szG7k-QdSHiU9eTTjTl9GrgKCTk9245ToAx8wPh2jsF-9dkerZc967NHU2R0ZcOdozhfgMtaPCSxshV8HSCplngK25gAmFf0Gg-yp18u5Qu4L-YJ9prgOKHh3fPwy6_e23bxF2BeII2ImYe6q6jNMqIdSzWwI3aEu0dVsU4jJ4p7lfFKEQti3cHDK4Bqo088UTEaSBiEk1Y9aDJ5A2pFef-xgiyEDXg7TEZ6WWDMKO-6H92DMJue9pHaV1kqWLeVKGB3Qvn4jgzE3LnAXj2Fe80RkhRCyKX_JqlazK0gXCp420itLqG1ji8thPTegjl11odWt-jHDxpDjz8C1fGRLh-emL74pLC_p3yZWM0uXliMr84eriOxbPXtROa37M7yYUs_TOsTPChcu7eDUY7bIgb8L_Trgzo2ZJMUvGmL8OSLNzgJR1Ui6SU0AOZcU_TsT7MTRjiCJcHPc-flF9rW91evcp30bJfs3EdZ5m8-U07z63rQ8pNcLFZUFJq6TIPmF9Xha4dtbduDX0W7tb91wqvd4A2Trb4amj3miWpJ8yuiwXe6MdXbvUR6yv5Gf2Svwpe3dJtrfns93a9ESItw3naRkMj1nzNfMVY9rtHeKXJGHzJIsLl3LyOWp2LpdyaThzW6RGKPq4l3WCY18pIrxgHyg8K7Iyw95ztXVlTWnEQICFYy17pjx1aw1bQSise7_AEMMkfYcigZjVssxus1NiHp0t7_utCI3_PG8daZrfUqEkoJlLtrM4yuuv0kx1u6jfce3SrS9RzqjXajnmkiP79bgT_YIJ6jyv7oq9Ls-L-5iVjvSI08XHkM3r2xjjiep-f7NuB7lO02wxeu0I_RGzbz1jn4kJWwNHVUTsx2zNV2V6wlYJzxEuBumvRRgSSnbvEjYrPrHIvFrF1V16VvjqXxWD8P396ZfoouGV0uWfflilSQc_d1v4wlJQJYsqK85LwVHh8S0dTCp7nfzn1frNovut_mG12wp8_sWpqT1cXNr_TseL_vX9IZr1_UqQcBP2Hl71_Y_vr3R8G5b_6YsPob_k3xI1Sokv3ZLk5Qq_uyUJB7bVePA-3ypRtb3c_IWF_RXaTzXX9ysu4EP--HBrNVguRzQ-HPBlBKp_DlvhZ2WV1mT3N022WwfQ8tjaT-i3glj4TjTpwbr3d-_MeEmIz83i1n5u-JNjAyB3b4bl63h1l-N6NZXOPaOWJ1z6uu1tWdVHZTQc4ceLhunGaC2J5U_w1lYXF_lnSusiz6qT0nqw5YtskqX5G0X26Px3xW5SVqYluYKbZJHhPE3LJLva3LQJJu183uQJzVKM5-2cpkAWZcIYbfOkvOI3OMZ5nOIkzpMkz2Z5HGcxKQqIU8ZIkkRZDD3hYuawmCndXfnj7U2S4jRdXAnSgDD-twmMJTxPh18c5fWVvvGXV83QmSiLBTfWHMxYboX_UWN_MZXXZz9UHN8K-pvB1oIeN7ouwSOqpIF_DCDD6bvnL8DGG0t_2UAGq3piOUU99ErvxptTd76-GrS4-bdv3_zqTIRX4_KfbvC_AgAA__8GjN0z">