<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>nu1lptr - Security</title>
    <subtitle>Learner &#x2F;&#x2F; Cybersecurity Ph.D.@UMich CSE &#x2F;&#x2F; Photographer</subtitle>
    <link rel="self" type="application/atom+xml" href="https://shengtuo.me/tags/security/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://shengtuo.me"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-09-21T18:00:00-07:00</updated>
    <id>https://shengtuo.me/tags/security/atom.xml</id>
    <entry xml:lang="en">
        <title>rllvm: From Capture to Query</title>
        <published>2026-09-21T18:00:00-07:00</published>
        <updated>2026-09-21T18:00:00-07:00</updated>
        
        <author>
          <name>
            Shengtuo Hu
          </name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://shengtuo.me/blog/from-capture-to-query/"/>
        <id>https://shengtuo.me/blog/from-capture-to-query/</id>
        
        <content type="html" xml:base="https://shengtuo.me/blog/from-capture-to-query/">&lt;h2 id=&quot;tl-dr&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#tl-dr&quot; aria-label=&quot;Anchor link for: tl-dr&quot;&gt;&lt;i class=&quot;icon&quot;&gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
TL;DR&lt;&#x2F;h2&gt;
&lt;p&gt;The first two posts in this series were about producing artifacts: extracting
&lt;a href=&quot;https:&#x2F;&#x2F;shengtuo.me&#x2F;blog&#x2F;whole-program-bitcode&#x2F;&quot;&gt;whole-program bitcode&lt;&#x2F;a&gt;, then keeping the
modules and their provenance in a
&lt;a href=&quot;https:&#x2F;&#x2F;shengtuo.me&#x2F;blog&#x2F;beyond-single-bitcode-file&#x2F;&quot;&gt;catalog&lt;&#x2F;a&gt; instead of merging them away.
&lt;code&gt;rllvm-query&lt;&#x2F;code&gt; adds the step those were building toward. It reads a catalog and
answers questions in source terms: who defines this, who calls it, what does it
call, what path reaches it.&lt;&#x2F;p&gt;
&lt;p&gt;This post puts that step to work on a program written in two languages. The
example is CVE-2026-11941, a use-after-free in Cloudflare&#x27;s quiche that is made
entirely of safe Rust and still hands C a pointer to freed memory. The queries
locate it, scan the rest of the library for the same shape, and then run out of
road in a place worth being precise about.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;a-blind-spot-in-mixed-language-programs&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#a-blind-spot-in-mixed-language-programs&quot; aria-label=&quot;Anchor link for: a-blind-spot-in-mixed-language-programs&quot;&gt;&lt;i class=&quot;icon&quot;&gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
A blind spot in mixed-language programs&lt;&#x2F;h2&gt;
&lt;p&gt;Programs written in a single language are becoming the exception. A Rust crate
pulls in a &lt;code&gt;-sys&lt;&#x2F;code&gt; dependency and half of its real work happens in C. A C
codebase adopts Rust one module at a time.&lt;&#x2F;p&gt;
&lt;p&gt;The boundary between the two is the riskiest part of such a program. Ownership
stops being tracked there, error conventions stop matching, and who frees what
has to be written in a comment because no type carries it across. It is also the
one place that ordinary tooling does not look, for an understandable reason:
every ecosystem&#x27;s index is scoped to its own build. &lt;code&gt;rust-analyzer&lt;&#x2F;code&gt; stops at the
&lt;code&gt;extern &quot;C&quot;&lt;&#x2F;code&gt; declaration, because Cargo compiled nothing past it. &lt;code&gt;clangd&lt;&#x2F;code&gt; never
heard of the Rust caller. &lt;code&gt;cargo audit&lt;&#x2F;code&gt; reasons over the dependency graph, which
suits crates and says nothing about the BoringSSL that a build script compiled
along the way. &lt;code&gt;unsafe&lt;&#x2F;code&gt; marks where Rust stops trusting itself, and stays silent
about the other side.&lt;&#x2F;p&gt;
&lt;p&gt;So the questions that matter most at the boundary are the ones nobody can ask.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;getting-both-languages-into-one-module&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#getting-both-languages-into-one-module&quot; aria-label=&quot;Anchor link for: getting-both-languages-into-one-module&quot;&gt;&lt;i class=&quot;icon&quot;&gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
Getting both languages into one module&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;rustc&lt;&#x2F;code&gt; and &lt;code&gt;clang&lt;&#x2F;code&gt; are both LLVM front ends. Once a call across the boundary
becomes an LLVM &lt;code&gt;call&lt;&#x2F;code&gt; instruction, the language has been erased: there is a
caller, a callee, and a source location for each. The boundary belongs to how we
build software rather than to the compiled program, so the whole job reduces to
capturing both halves at once. That used to take one environment variable. Now
it takes two.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#31333d;color:#ffffffc4;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#dbbb3d;&quot;&gt;export &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#a3cbe3;&quot;&gt;CC&lt;&#x2F;span&gt;&lt;span style=&quot;color:#db7c6d;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;rllvm-cc &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#a3cbe3;&quot;&gt;CXX&lt;&#x2F;span&gt;&lt;span style=&quot;color:#db7c6d;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;rllvm-cxx &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#a3cbe3;&quot;&gt;RUSTC_WRAPPER&lt;&#x2F;span&gt;&lt;span style=&quot;color:#db7c6d;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;rllvm-rustc
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;h1994st&#x2F;rllvm&#x2F;tree&#x2F;main&#x2F;examples&#x2F;ffi&quot;&gt;&lt;code&gt;examples&#x2F;ffi&lt;&#x2F;code&gt;&lt;&#x2F;a&gt;
directory holds the smallest version of this I could write: two programs whose
call graphs cross the boundary, one led from each language, because the gap in
the tooling runs both ways.&lt;&#x2F;p&gt;
&lt;figure class=&quot;ffi-fig ffi-crossings&quot; aria-label=&quot;Two small programs whose call graphs cross the FFI boundary, one led from Rust and one led from C&quot;&gt;
&lt;div class=&quot;ffi-group&quot;&gt;
&lt;span class=&quot;ffi-kicker&quot;&gt;Rust-led&lt;&#x2F;span&gt;
&lt;ol&gt;
&lt;li&gt;&lt;span class=&quot;ffi-lang is-rust&quot;&gt;Rust&lt;&#x2F;span&gt;&lt;span class=&quot;ffi-fn&quot;&gt;main::main&lt;&#x2F;span&gt;&lt;span class=&quot;ffi-arrow&quot;&gt;&amp;#9656;&lt;&#x2F;span&gt;&lt;span class=&quot;ffi-lang is-c&quot;&gt;C&lt;&#x2F;span&gt;&lt;span class=&quot;ffi-fn&quot;&gt;c_double&lt;&#x2F;span&gt;&lt;span class=&quot;ffi-arrow&quot;&gt;&amp;#9656;&lt;&#x2F;span&gt;&lt;span class=&quot;ffi-lang is-rust&quot;&gt;Rust&lt;&#x2F;span&gt;&lt;span class=&quot;ffi-fn&quot;&gt;rust_add&lt;&#x2F;span&gt;&lt;span class=&quot;ffi-where&quot;&gt;main.rs:12&lt;&#x2F;span&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;span class=&quot;ffi-lang is-rust&quot;&gt;Rust&lt;&#x2F;span&gt;&lt;span class=&quot;ffi-fn&quot;&gt;main::main&lt;&#x2F;span&gt;&lt;span class=&quot;ffi-arrow&quot;&gt;&amp;#9656;&lt;&#x2F;span&gt;&lt;span class=&quot;ffi-lang is-cxx&quot;&gt;C++&lt;&#x2F;span&gt;&lt;span class=&quot;ffi-fn&quot;&gt;cxx_triple&lt;&#x2F;span&gt;&lt;span class=&quot;ffi-where&quot;&gt;main.rs:13&lt;&#x2F;span&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;div&gt;
&lt;div class=&quot;ffi-group&quot;&gt;
&lt;span class=&quot;ffi-kicker&quot;&gt;C-led&lt;&#x2F;span&gt;
&lt;ol&gt;
&lt;li&gt;&lt;span class=&quot;ffi-lang is-c&quot;&gt;C&lt;&#x2F;span&gt;&lt;span class=&quot;ffi-fn&quot;&gt;main&lt;&#x2F;span&gt;&lt;span class=&quot;ffi-arrow&quot;&gt;&amp;#9656;&lt;&#x2F;span&gt;&lt;span class=&quot;ffi-lang is-rust&quot;&gt;Rust&lt;&#x2F;span&gt;&lt;span class=&quot;ffi-fn&quot;&gt;rust_scale&lt;&#x2F;span&gt;&lt;span class=&quot;ffi-arrow&quot;&gt;&amp;#9656;&lt;&#x2F;span&gt;&lt;span class=&quot;ffi-lang is-c&quot;&gt;C&lt;&#x2F;span&gt;&lt;span class=&quot;ffi-fn&quot;&gt;c_offset&lt;&#x2F;span&gt;&lt;span class=&quot;ffi-where&quot;&gt;c_main.c:8&lt;&#x2F;span&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;div&gt;
&lt;figcaption&gt;One module holds all three languages, and each crossing is reported at the line that makes the call. Direction matters more than it looks: a Rust staticlib drags in a prebuilt &lt;b&gt;std&lt;&#x2F;b&gt; that never went through the wrapper, so whichever language leads decides how much of the program you can see.&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;a-real-bug-where-the-languages-meet&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#a-real-bug-where-the-languages-meet&quot; aria-label=&quot;Anchor link for: a-real-bug-where-the-languages-meet&quot;&gt;&lt;i class=&quot;icon&quot;&gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
A real bug where the languages meet&lt;&#x2F;h2&gt;
&lt;p&gt;quiche is Cloudflare&#x27;s QUIC and HTTP&#x2F;3 library: a Cargo workspace that also
builds BoringSSL through a build script and exposes a C API behind a feature
flag. In June it published
&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;cloudflare&#x2F;quiche&#x2F;security&#x2F;advisories&#x2F;GHSA-mh64-ph39-mrc9&quot;&gt;GHSA-mh64-ph39-mrc9&lt;&#x2F;a&gt;,
CVE-2026-11941, a use-after-free in two of its FFI functions, fixed in 0.29.2.&lt;&#x2F;p&gt;
&lt;p&gt;The entire defect, from &lt;code&gt;quiche&#x2F;src&#x2F;ffi.rs&lt;&#x2F;code&gt; at 0.29.1:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;rust&quot; style=&quot;background-color:#31333d;color:#ffffffc4;&quot; class=&quot;language-rust &quot;&gt;&lt;code class=&quot;language-rust&quot; data-lang=&quot;rust&quot;&gt;&lt;span style=&quot;color:#a3cbe3;&quot;&gt;impl&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#dbbb3d;&quot;&gt;&amp;#39;a&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; Iterator &lt;&#x2F;span&gt;&lt;span style=&quot;color:#db7c6d;&quot;&gt;for &lt;&#x2F;span&gt;&lt;span&gt;ConnectionIdIter&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#dbbb3d;&quot;&gt;&amp;#39;a&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3cbe3;&quot;&gt;type &lt;&#x2F;span&gt;&lt;span&gt;Item &lt;&#x2F;span&gt;&lt;span style=&quot;color:#db7c6d;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span&gt;ConnectionId&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#dbbb3d;&quot;&gt;&amp;#39;a&lt;&#x2F;span&gt;&lt;span&gt;&amp;gt;;
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3cbe3;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a2ba43;&quot;&gt;next&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color:#db7c6d;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#dbbb3d;&quot;&gt;mut &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e7e7e7;&quot;&gt;Option&lt;&#x2F;span&gt;&lt;span&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3cbe3;&quot;&gt;Self::&lt;&#x2F;span&gt;&lt;span&gt;Item&amp;gt; {
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3cbe3;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; v &lt;&#x2F;span&gt;&lt;span style=&quot;color:#db7c6d;&quot;&gt;= &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#a3cbe3;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.cids.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#db7c6d;&quot;&gt;get&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#a3cbe3;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.index)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#db7c6d;&quot;&gt;?&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#a3cbe3;&quot;&gt;self&lt;&#x2F;span&gt;&lt;span&gt;.index &lt;&#x2F;span&gt;&lt;span style=&quot;color:#db7c6d;&quot;&gt;+= 1&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e7e7e7;&quot;&gt;Some&lt;&#x2F;span&gt;&lt;span&gt;(v.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#db7c6d;&quot;&gt;clone&lt;&#x2F;span&gt;&lt;span&gt;())            &lt;&#x2F;span&gt;&lt;span style=&quot;color:#707180;&quot;&gt;&#x2F;&#x2F; an owned ConnectionId
&lt;&#x2F;span&gt;&lt;span&gt;    }
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;#[&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#a3cbe3;&quot;&gt;no_mangle&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#dbbb3d;&quot;&gt;pub &lt;&#x2F;span&gt;&lt;span style=&quot;color:#db7c6d;&quot;&gt;extern &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;C&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3cbe3;&quot;&gt;fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a2ba43;&quot;&gt;quiche_connection_id_iter_next&lt;&#x2F;span&gt;&lt;span&gt;(
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;iter&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#db7c6d;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#dbbb3d;&quot;&gt;mut&lt;&#x2F;span&gt;&lt;span&gt; ConnectionIdIter,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;out&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#db7c6d;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#dbbb3d;&quot;&gt;mut *const &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3cbe3;&quot;&gt;u8&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;out_len&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#db7c6d;&quot;&gt;&amp;amp;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#dbbb3d;&quot;&gt;mut&lt;&#x2F;span&gt;&lt;span&gt; size_t,
&lt;&#x2F;span&gt;&lt;span&gt;) -&amp;gt; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3cbe3;&quot;&gt;bool &lt;&#x2F;span&gt;&lt;span&gt;{
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#db7c6d;&quot;&gt;if &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3cbe3;&quot;&gt;let &lt;&#x2F;span&gt;&lt;span style=&quot;color:#e7e7e7;&quot;&gt;Some&lt;&#x2F;span&gt;&lt;span&gt;(conn_id) &lt;&#x2F;span&gt;&lt;span style=&quot;color:#db7c6d;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; iter.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#db7c6d;&quot;&gt;next&lt;&#x2F;span&gt;&lt;span&gt;() {   &lt;&#x2F;span&gt;&lt;span style=&quot;color:#707180;&quot;&gt;&#x2F;&#x2F; owned; dropped below
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#a3cbe3;&quot;&gt;let&lt;&#x2F;span&gt;&lt;span&gt; id &lt;&#x2F;span&gt;&lt;span style=&quot;color:#db7c6d;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; conn_id.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#db7c6d;&quot;&gt;as_ref&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#db7c6d;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;out &lt;&#x2F;span&gt;&lt;span style=&quot;color:#db7c6d;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; id.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#db7c6d;&quot;&gt;as_ptr&lt;&#x2F;span&gt;&lt;span&gt;();                &lt;&#x2F;span&gt;&lt;span style=&quot;color:#707180;&quot;&gt;&#x2F;&#x2F; escapes to C
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#db7c6d;&quot;&gt;*&lt;&#x2F;span&gt;&lt;span&gt;out_len &lt;&#x2F;span&gt;&lt;span style=&quot;color:#db7c6d;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt; id.&lt;&#x2F;span&gt;&lt;span style=&quot;color:#db7c6d;&quot;&gt;len&lt;&#x2F;span&gt;&lt;span&gt;();
&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#db7c6d;&quot;&gt;return &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;true&lt;&#x2F;span&gt;&lt;span&gt;;
&lt;&#x2F;span&gt;&lt;span&gt;    }                                      &lt;&#x2F;span&gt;&lt;span style=&quot;color:#707180;&quot;&gt;&#x2F;&#x2F; conn_id freed here
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;false
&lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;There is no &lt;code&gt;unsafe&lt;&#x2F;code&gt; block. The borrow checker is satisfied and it is right to
be: &lt;code&gt;conn_id&lt;&#x2F;code&gt; is an owned value, dropped correctly at the end of its scope.
Every guarantee Rust makes holds.&lt;&#x2F;p&gt;
&lt;p&gt;What goes wrong is that a raw pointer into that value crossed an &lt;code&gt;extern &quot;C&quot;&lt;&#x2F;code&gt;
signature on the way out, and C reads it after the drop. Rust&#x27;s ownership model
ends at the signature, and both halves of this program are correct on their own.&lt;&#x2F;p&gt;
&lt;figure class=&quot;ffi-fig&quot; aria-label=&quot;A timeline showing the ConnectionId being cloned, its pointer escaping to C, the value being dropped, and C reading the freed memory&quot;&gt;
&lt;div class=&quot;ffi-life&quot;&gt;
&lt;div class=&quot;ffi-step is-alive&quot;&gt;&lt;span class=&quot;ffi-side&quot;&gt;Rust&lt;&#x2F;span&gt;&lt;span class=&quot;ffi-what&quot;&gt;clone a &lt;b&gt;ConnectionId&lt;&#x2F;b&gt; out of the iterator&lt;span class=&quot;ffi-at&quot;&gt;ffi.rs:1157&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;ffi-bar&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;div&gt;
&lt;div class=&quot;ffi-step is-alive&quot;&gt;&lt;span class=&quot;ffi-side&quot;&gt;Rust&lt;&#x2F;span&gt;&lt;span class=&quot;ffi-what&quot;&gt;*out = id.as_ptr(), the pointer escapes&lt;span class=&quot;ffi-at&quot;&gt;ffi.rs:1158&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;ffi-bar&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;div&gt;
&lt;div class=&quot;ffi-step is-dead&quot;&gt;&lt;span class=&quot;ffi-side&quot;&gt;Rust&lt;&#x2F;span&gt;&lt;span class=&quot;ffi-what&quot;&gt;drop_glue::&amp;lt;ConnectionId&amp;gt;, the buffer is freed&lt;span class=&quot;ffi-at&quot;&gt;ffi.rs:1162&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;ffi-bar&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;div&gt;
&lt;div class=&quot;ffi-return&quot;&gt;return to C, and out still holds the pointer&lt;&#x2F;div&gt;
&lt;div class=&quot;ffi-step is-dead is-fault&quot;&gt;&lt;span class=&quot;ffi-side&quot;&gt;C&lt;&#x2F;span&gt;&lt;span class=&quot;ffi-what&quot;&gt;fprintf(&quot;%02x&quot;, cid[i])&lt;span class=&quot;ffi-at&quot;&gt;cid_logger.c:21&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;ffi-bar&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;div&gt;
&lt;&#x2F;div&gt;
&lt;figcaption&gt;The solid bar is the value&#x27;s lifetime; the dashed continuation is the pointer outliving it. Only the join between the two halves is wrong, and the join is what neither language&#x27;s tooling reads.&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;asking-rllvm-query-about-it&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#asking-rllvm-query-about-it&quot; aria-label=&quot;Anchor link for: asking-rllvm-query-about-it&quot;&gt;&lt;i class=&quot;icon&quot;&gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
Asking rllvm-query about it&lt;&#x2F;h2&gt;
&lt;p&gt;What follows runs against quiche 0.29.1 with the FFI feature on, plus a small C
program that uses the iterator the way the advisory describes.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#31333d;color:#ffffffc4;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;font-weight:bold;color:#a3cbe3;&quot;&gt;git&lt;&#x2F;span&gt;&lt;span&gt; clone https:&#x2F;&#x2F;github.com&#x2F;cloudflare&#x2F;quiche &lt;&#x2F;span&gt;&lt;span style=&quot;color:#db7c6d;&quot;&gt;&amp;amp;&amp;amp; cd&lt;&#x2F;span&gt;&lt;span&gt; quiche
&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#a3cbe3;&quot;&gt;git&lt;&#x2F;span&gt;&lt;span&gt; checkout 0.29.1
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#dbbb3d;&quot;&gt;export &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#a3cbe3;&quot;&gt;RUSTC_WRAPPER&lt;&#x2F;span&gt;&lt;span style=&quot;color:#db7c6d;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;rllvm-rustc &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#a3cbe3;&quot;&gt;CC&lt;&#x2F;span&gt;&lt;span style=&quot;color:#db7c6d;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;rllvm-cc
&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#a3cbe3;&quot;&gt;cargo&lt;&#x2F;span&gt;&lt;span&gt; build&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt; -p&lt;&#x2F;span&gt;&lt;span&gt; quiche&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt; --features&lt;&#x2F;span&gt;&lt;span&gt; ffi
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#a3cbe3;&quot;&gt;rllvm-cc&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt; -g -Iquiche&lt;&#x2F;span&gt;&lt;span&gt;&#x2F;include cid_logger.c \
&lt;&#x2F;span&gt;&lt;span&gt;    target&#x2F;debug&#x2F;libquiche.a&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt; -o&lt;&#x2F;span&gt;&lt;span&gt; cid_logger
&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#a3cbe3;&quot;&gt;rllvm-get-bc&lt;&#x2F;span&gt;&lt;span&gt; cid_logger&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt; --output-dir&lt;&#x2F;span&gt;&lt;span&gt; cat
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The binary now records both halves. Every answer below is JSON; I have reduced
each one to the fields under discussion, and shortened Rust crate paths to fit.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#31333d;color:#ffffffc4;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;font-weight:bold;color:#a3cbe3;&quot;&gt;CAT&lt;&#x2F;span&gt;&lt;span style=&quot;color:#db7c6d;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;cat&#x2F;catalog.json
&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#a3cbe3;&quot;&gt;FN&lt;&#x2F;span&gt;&lt;span style=&quot;color:#db7c6d;&quot;&gt;=&lt;&#x2F;span&gt;&lt;span&gt;quiche_connection_id_iter_next
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The definition is Rust, and the caller is C, each reported at its own line:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#31333d;color:#ffffffc4;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;font-weight:bold;color:#a3cbe3;&quot;&gt;rllvm-query&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt; --catalog &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#a3cbe3;&quot;&gt;CAT&lt;&#x2F;span&gt;&lt;span&gt; defs &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#a3cbe3;&quot;&gt;FN
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#707180;&quot;&gt;#   quiche&#x2F;src&#x2F;ffi.rs:1154
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#a3cbe3;&quot;&gt;rllvm-query&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt; --catalog &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#a3cbe3;&quot;&gt;CAT&lt;&#x2F;span&gt;&lt;span&gt; callers &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#a3cbe3;&quot;&gt;FN
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#707180;&quot;&gt;#   log_source_ids   at cid_logger.c:19
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;callees&lt;&#x2F;code&gt; on the FFI function is the bug in three lines. Rust symbols come back
demangled, so a cross-language answer reads as one answer:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#31333d;color:#ffffffc4;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;font-weight:bold;color:#a3cbe3;&quot;&gt;rllvm-query&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt; --catalog &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#a3cbe3;&quot;&gt;CAT&lt;&#x2F;span&gt;&lt;span&gt; callees &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#a3cbe3;&quot;&gt;FN
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#707180;&quot;&gt;#   ffi.rs:1157  &amp;lt;ConnectionIdIter as Iterator&amp;gt;::next
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#707180;&quot;&gt;#   ffi.rs:1158  &amp;lt;ConnectionId as AsRef&amp;lt;[u8]&amp;gt;&amp;gt;::as_ref
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#707180;&quot;&gt;#   ffi.rs:1162  core::ptr::drop_glue::&amp;lt;ConnectionId&amp;gt;
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Clone, take a pointer, free. Run the same query against 0.29.2 and the
&lt;code&gt;drop_glue&lt;&#x2F;code&gt; line is gone, because the fix stopped owning anything:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#31333d;color:#ffffffc4;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;color:#707180;&quot;&gt;#   ffi.rs:1146  &amp;lt;Vec&amp;lt;ConnectionId&amp;gt; as Deref&amp;gt;::deref
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#707180;&quot;&gt;#   ffi.rs:1146  &amp;lt;[ConnectionId]&amp;gt;::get::&amp;lt;usize&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#707180;&quot;&gt;#   ffi.rs:1147  &amp;lt;ConnectionId as AsRef&amp;lt;[u8]&amp;gt;&amp;gt;::as_ref
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;&lt;code&gt;reach&lt;&#x2F;code&gt; walks from the C entry point to the Rust function, and records the
crossing as its own kind of step:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;json&quot; style=&quot;background-color:#31333d;color:#ffffffc4;&quot; class=&quot;language-json &quot;&gt;&lt;code class=&quot;language-json&quot; data-lang=&quot;json&quot;&gt;&lt;span&gt;[
&lt;&#x2F;span&gt;&lt;span&gt;  { &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;kind&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;call&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;function&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: { &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;symbol&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;main&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span&gt;},
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;block_index&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#db7c6d;&quot;&gt;3&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;instruction_index&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#db7c6d;&quot;&gt;1 &lt;&#x2F;span&gt;&lt;span&gt;},
&lt;&#x2F;span&gt;&lt;span&gt;  { &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;kind&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;call&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;function&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: { &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;symbol&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;log_source_ids&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span&gt;},
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;block_index&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#db7c6d;&quot;&gt;1&lt;&#x2F;span&gt;&lt;span&gt;, &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;instruction_index&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color:#db7c6d;&quot;&gt;1 &lt;&#x2F;span&gt;&lt;span&gt;},
&lt;&#x2F;span&gt;&lt;span&gt;  { &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;kind&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;binding&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;symbol&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;quiche_connection_id_iter_next&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;,
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;declared_in&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: [ &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;e98486…&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span&gt;],
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;candidates&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: [ { &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;function&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: { &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;module_id&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;00a3d4…&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span&gt;} } ],
&lt;&#x2F;span&gt;&lt;span&gt;    &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;status&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt;unique&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot; &lt;&#x2F;span&gt;&lt;span&gt;}
&lt;&#x2F;span&gt;&lt;span&gt;]
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Two ordinary calls inside C, then a &lt;code&gt;binding&lt;&#x2F;code&gt;: a C declaration that resolved to
one candidate definition in a Rust module. The answer distinguishes a call it
observed from a link it resolved, and says which one carries the path.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;scanning-the-whole-ffi-surface&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#scanning-the-whole-ffi-surface&quot; aria-label=&quot;Anchor link for: scanning-the-whole-ffi-surface&quot;&gt;&lt;i class=&quot;icon&quot;&gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
Scanning the whole FFI surface&lt;&#x2F;h2&gt;
&lt;p&gt;Everything above starts from knowing the answer. The more useful question is
whether the bug has a shape you can search for, stated without reference to the
CVE:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;An &lt;code&gt;extern &quot;C&quot;&lt;&#x2F;code&gt; entry point hands C a raw pointer into a value, and then drops
that value before returning.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;In call-graph terms that is two conditions on one function&#x27;s callees: something
that takes a pointer into &lt;code&gt;T&lt;&#x2F;code&gt;, and &lt;code&gt;drop_glue::&amp;lt;T&amp;gt;&lt;&#x2F;code&gt;. Both already appear in the
output, so the scan is a loop.&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;bash&quot; style=&quot;background-color:#31333d;color:#ffffffc4;&quot; class=&quot;language-bash &quot;&gt;&lt;code class=&quot;language-bash&quot; data-lang=&quot;bash&quot;&gt;&lt;span style=&quot;font-weight:bold;color:#a3cbe3;&quot;&gt;nm&lt;&#x2F;span&gt;&lt;span&gt; target&#x2F;debug&#x2F;libquiche.a \
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;color:#db7c6d;&quot;&gt;| &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#a3cbe3;&quot;&gt;awk &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span&gt;$2==&amp;quot;T&amp;quot; &amp;amp;&amp;amp; $3 ~ &#x2F;^_quiche_&#x2F;&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;#39; &lt;&#x2F;span&gt;&lt;span style=&quot;color:#db7c6d;&quot;&gt;| &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#a3cbe3;&quot;&gt;sort&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt; -u &lt;&#x2F;span&gt;&lt;span style=&quot;color:#db7c6d;&quot;&gt;&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt; surface.txt
&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#a3cbe3;&quot;&gt;wc&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt; -l &lt;&#x2F;span&gt;&lt;span style=&quot;color:#db7c6d;&quot;&gt;&amp;lt;&lt;&#x2F;span&gt;&lt;span&gt; surface.txt        &lt;&#x2F;span&gt;&lt;span style=&quot;color:#707180;&quot;&gt;# 169 entry points
&lt;&#x2F;span&gt;&lt;span&gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#db7c6d;&quot;&gt;for&lt;&#x2F;span&gt;&lt;span&gt; fn &lt;&#x2F;span&gt;&lt;span style=&quot;color:#db7c6d;&quot;&gt;in &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#a3cbe3;&quot;&gt;cat&lt;&#x2F;span&gt;&lt;span&gt; surface.txt)&lt;&#x2F;span&gt;&lt;span style=&quot;color:#db7c6d;&quot;&gt;; do
&lt;&#x2F;span&gt;&lt;span&gt;  &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#a3cbe3;&quot;&gt;rllvm-query&lt;&#x2F;span&gt;&lt;span style=&quot;color:#ffffff;&quot;&gt; --catalog &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;$&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#a3cbe3;&quot;&gt;CAT&lt;&#x2F;span&gt;&lt;span&gt; callees &lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;$&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#a3cbe3;&quot;&gt;fn&lt;&#x2F;span&gt;&lt;span style=&quot;font-weight:bold;color:#dbbb3d;&quot;&gt;&amp;quot;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#db7c6d;&quot;&gt;done
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#707180;&quot;&gt;# keep any whose callees hold both drop_glue::&amp;lt;T&amp;gt;
&lt;&#x2F;span&gt;&lt;span style=&quot;color:#707180;&quot;&gt;# and something that takes a pointer into T
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The leading underscore is Mach-O&#x27;s prefix on C symbols; an ELF build wants
&lt;code&gt;&#x2F;^quiche_&#x2F;&lt;&#x2F;code&gt; instead. That platform dependency, and the fact that this step
reaches for &lt;code&gt;nm&lt;&#x2F;code&gt; at all, is a gap: the catalog already knows which functions a
Rust module exported to C, so &lt;code&gt;rllvm-query&lt;&#x2F;code&gt; should be able to list them itself
(&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;h1994st&#x2F;rllvm&#x2F;issues&#x2F;243&quot;&gt;#243&lt;&#x2F;a&gt;).&lt;&#x2F;p&gt;
&lt;p&gt;169 entry points reduce to 7 candidates, and both functions the advisory names
are among them:&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Candidate&lt;&#x2F;th&gt;&lt;th&gt;Reading it&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;quiche_connection_id_iter_next&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;strong&gt;CVE-2026-11941&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;quiche_conn_retired_scid_next&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;&lt;strong&gt;CVE-2026-11941&lt;&#x2F;strong&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;quiche_conn_source_id&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;safe: the dropped &lt;code&gt;ConnectionId&lt;&#x2F;code&gt; is the borrowed variant&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;quiche_conn_destination_id&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;safe: the same&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;quiche_accept&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;filter noise: the match was &lt;code&gt;Option::as_ref&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;quiche_conn_new_with_tls&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;filter noise: the same&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;quiche_h3_take_last_priority_update&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;safe &lt;em&gt;if&lt;&#x2F;em&gt; the C callback behaves&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;One caveat on how much this proves. I wrote the filter after reading the
advisory. The shape is general, since handing C a pointer into something you
then drop is a whole class of FFI bug. This run still does not establish that I
would have picked it blind. What it does establish is that the class fits in two
predicates over ordinary output, that it ranks both real defects into seven of a
hundred and sixty-nine, and that the signal disappears when the bug is fixed.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;does-it-affect-my-build&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#does-it-affect-my-build&quot; aria-label=&quot;Anchor link for: does-it-affect-my-build&quot;&gt;&lt;i class=&quot;icon&quot;&gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
Does it affect my build?&lt;&#x2F;h2&gt;
&lt;p&gt;&lt;code&gt;cargo audit&lt;&#x2F;code&gt; gives one answer for any quiche below 0.29.2: vulnerable. The
advisory is more careful, and names the thing that actually decides it.&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;Only applications using those FFI functions are affected. The FFI API is
disabled by default by a build-time feature flag.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;That is a whole-program question, with four different true answers depending on
how the program was built.&lt;&#x2F;p&gt;
&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Build&lt;&#x2F;th&gt;&lt;th&gt;Definition present&lt;&#x2F;th&gt;&lt;th&gt;Callers&lt;&#x2F;th&gt;&lt;th&gt;What is true&lt;&#x2F;th&gt;&lt;&#x2F;tr&gt;&lt;&#x2F;thead&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;default features&lt;&#x2F;td&gt;&lt;td&gt;no&lt;&#x2F;td&gt;&lt;td&gt;n&#x2F;a&lt;&#x2F;td&gt;&lt;td&gt;the code was never compiled&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--features ffi&lt;&#x2F;code&gt;, quiche&#x27;s own &lt;code&gt;client.c&lt;&#x2F;code&gt;&lt;&#x2F;td&gt;&lt;td&gt;yes&lt;&#x2F;td&gt;&lt;td&gt;0&lt;&#x2F;td&gt;&lt;td&gt;linked in, never called&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;code&gt;--features ffi&lt;&#x2F;code&gt;, a C app that iterates CIDs&lt;&#x2F;td&gt;&lt;td&gt;yes&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;reachable&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;tr&gt;&lt;td&gt;0.29.2, same C app&lt;&#x2F;td&gt;&lt;td&gt;yes&lt;&#x2F;td&gt;&lt;td&gt;1&lt;&#x2F;td&gt;&lt;td&gt;fixed&lt;&#x2F;td&gt;&lt;&#x2F;tr&gt;
&lt;&#x2F;tbody&gt;&lt;&#x2F;table&gt;
&lt;p&gt;The second row is worth sitting with. &lt;code&gt;nm&lt;&#x2F;code&gt; confirms
&lt;code&gt;_quiche_connection_id_iter_next&lt;&#x2F;code&gt; is in that binary as a defined symbol, and
&lt;code&gt;callers&lt;&#x2F;code&gt; still returns zero. Present and reachable are different facts, and
only one of them describes your risk.&lt;&#x2F;p&gt;
&lt;p&gt;For a caller that does exist, &lt;code&gt;callees&lt;&#x2F;code&gt; on it gives the order of operations, so
you can see what happens after the crossing:&lt;&#x2F;p&gt;
&lt;pre data-lang=&quot;txt&quot; style=&quot;background-color:#31333d;color:#ffffffc4;&quot; class=&quot;language-txt &quot;&gt;&lt;code class=&quot;language-txt&quot; data-lang=&quot;txt&quot;&gt;&lt;span&gt;blk 0 #7   line 14   quiche_conn_source_ids
&lt;&#x2F;span&gt;&lt;span&gt;blk 1 #1   line 19   quiche_connection_id_iter_next   &amp;lt;- the crossing
&lt;&#x2F;span&gt;&lt;span&gt;blk 4 #6   line 21   fprintf                          &amp;lt;- after it
&lt;&#x2F;span&gt;&lt;span&gt;blk 6 #1   line 23   fprintf                          &amp;lt;- after it
&lt;&#x2F;span&gt;&lt;span&gt;blk 7 #1   line 26   quiche_connection_id_iter_free
&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Anything sequenced after the crossing is a candidate consumer of a pointer that
Rust has already freed. The two &lt;code&gt;fprintf&lt;&#x2F;code&gt; calls are a three-line reading window.&lt;&#x2F;p&gt;
&lt;figure class=&quot;ffi-fig ffi-funnel&quot; aria-label=&quot;Each step narrows the search: 169 FFI entry points, 7 candidates, 1 caller, 3 lines of C to read&quot;&gt;
&lt;div class=&quot;ffi-rung&quot;&gt;&lt;span class=&quot;ffi-count&quot;&gt;169&lt;&#x2F;span&gt;&lt;span class=&quot;ffi-track&quot;&gt;&lt;span class=&quot;ffi-fill&quot; style=&quot;--w:100%&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;ffi-label&quot;&gt;&lt;b&gt;FFI entry points&lt;&#x2F;b&gt;, listed by nm&lt;&#x2F;span&gt;&lt;&#x2F;div&gt;
&lt;div class=&quot;ffi-rung&quot;&gt;&lt;span class=&quot;ffi-count&quot;&gt;7&lt;&#x2F;span&gt;&lt;span class=&quot;ffi-track&quot;&gt;&lt;span class=&quot;ffi-fill&quot; style=&quot;--w:34%&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;ffi-label&quot;&gt;&lt;b&gt;candidates&lt;&#x2F;b&gt;: callees take a pointer into T and drop T&lt;&#x2F;span&gt;&lt;&#x2F;div&gt;
&lt;div class=&quot;ffi-rung&quot;&gt;&lt;span class=&quot;ffi-count&quot;&gt;1&lt;&#x2F;span&gt;&lt;span class=&quot;ffi-track&quot;&gt;&lt;span class=&quot;ffi-fill&quot; style=&quot;--w:16%&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;ffi-label&quot;&gt;&lt;b&gt;caller&lt;&#x2F;b&gt;, with a file and a line&lt;&#x2F;span&gt;&lt;&#x2F;div&gt;
&lt;div class=&quot;ffi-rung&quot;&gt;&lt;span class=&quot;ffi-count&quot;&gt;3&lt;&#x2F;span&gt;&lt;span class=&quot;ffi-track&quot;&gt;&lt;span class=&quot;ffi-fill&quot; style=&quot;--w:7%&quot;&gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;span class=&quot;ffi-label&quot;&gt;&lt;b&gt;lines of C&lt;&#x2F;b&gt; left to read&lt;&#x2F;span&gt;&lt;&#x2F;div&gt;
&lt;figcaption&gt;The bars are illustrative rather than to scale. Every step is mechanical except the last one, which is the point: the tool decides where to look and a person decides what is there.&lt;&#x2F;figcaption&gt;
&lt;&#x2F;figure&gt;
&lt;h2 id=&quot;where-the-answers-stop&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#where-the-answers-stop&quot; aria-label=&quot;Anchor link for: where-the-answers-stop&quot;&gt;&lt;i class=&quot;icon&quot;&gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
Where the answers stop&lt;&#x2F;h2&gt;
&lt;p&gt;Five of those seven candidates are safe, for two different kinds of reason.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;ConnectionId&lt;&#x2F;code&gt; is a Cow-like type: &lt;code&gt;enum { Vec(Vec&amp;lt;u8&amp;gt;), Ref(&amp;amp;&#x27;a [u8]) }&lt;&#x2F;code&gt;.
&lt;code&gt;quiche_conn_source_id&lt;&#x2F;code&gt; drops one, but it drops the &lt;em&gt;borrowed&lt;&#x2F;em&gt; variant, so the
drop frees nothing and the pointer stays valid. The call graph sees
&lt;code&gt;drop_glue::&amp;lt;ConnectionId&amp;gt;&lt;&#x2F;code&gt; either way and cannot separate the two.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;quiche_accept&lt;&#x2F;code&gt; and &lt;code&gt;quiche_conn_new_with_tls&lt;&#x2F;code&gt; are the cheaper kind of wrong.
Both call &lt;code&gt;Option::as_ref&lt;&#x2F;code&gt;, a borrow helper that hands out no raw pointer at
all, and my filter matched on the method name. Neither function gives C a
pointer into anything it later drops, so the pattern never applied to them.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;code&gt;quiche_h3_take_last_priority_update&lt;&#x2F;code&gt; is more interesting. It takes a pointer
into an owned &lt;code&gt;Vec&amp;lt;u8&amp;gt;&lt;&#x2F;code&gt;, passes it to a callback supplied by C, and frees the
buffer when the callback returns. Whether that is safe depends on what the C
callback does with the pointer, and the contract lives in a header comment that
nothing enforces. I called it safe above by reading the Rust and assuming the C
behaves. That was an assumption rather than an analysis.&lt;&#x2F;p&gt;
&lt;p&gt;The Cow case and the callback case ask the same question: does this pointer
outlive the value behind it? &lt;code&gt;rllvm-query&lt;&#x2F;code&gt; does not perform data-flow analysis,
so it cannot answer either.
The same limit shows up at indirect calls, where &lt;code&gt;indirect-targets&lt;&#x2F;code&gt; reports a
target set when LLVM recorded one and reports the callback above as unresolved.
Tracking a value through a store, which is how the C side would retain that
pointer, is outside what a call graph describes at all.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;what-comes-next&quot;&gt;&lt;a class=&quot;zola-anchor&quot; href=&quot;#what-comes-next&quot; aria-label=&quot;Anchor link for: what-comes-next&quot;&gt;&lt;i class=&quot;icon&quot;&gt;&lt;&#x2F;i&gt;&lt;&#x2F;a&gt;
What comes next&lt;&#x2F;h2&gt;
&lt;p&gt;Two things, in the order I care about them.&lt;&#x2F;p&gt;
&lt;p&gt;The queries in this post form a short procedure: is the function here, does
anything call it, what happens after the crossing. Two of those steps can end
the investigation early. That belongs in tooling rather than in a blog post.
&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;h1994st&#x2F;rllvm&#x2F;issues&#x2F;188&quot;&gt;Issue #188&lt;&#x2F;a&gt; is a Claude Code
plugin bundling the MCP server with two skills: how to capture bitcode for the
build in front of you, and how to read an answer without over-claiming it. An
assistant reading source approximates a call graph by matching names, and across
an FFI boundary it cannot even approximate. The early exits matter most, because
&quot;the version range matches, therefore you are affected&quot; is the failure an agent
would otherwise reproduce at scale.&lt;&#x2F;p&gt;
&lt;p&gt;The second is the data flow this post kept needing. I would rather borrow that
than build it. &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;secure-software-engineering&#x2F;phasar&quot;&gt;PhASAR&lt;&#x2F;a&gt;
and &lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;SVF-tools&#x2F;SVF&quot;&gt;SVF&lt;&#x2F;a&gt; have solved pointer and value
analysis for years, and have always taken whole-program C and C++ bitcode.
Getting that file out of a real build was the awkward step they were waiting on.
A module with Rust in it too is new input for tools that already work. Running
them behind the same query contract
(&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;h1994st&#x2F;rllvm&#x2F;issues&#x2F;149&quot;&gt;#149&lt;&#x2F;a&gt;,
&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;h1994st&#x2F;rllvm&#x2F;issues&#x2F;242&quot;&gt;#242&lt;&#x2F;a&gt;) is what would separate a
borrowed &lt;code&gt;ConnectionId&lt;&#x2F;code&gt; from an owned one, and say whether a pointer escapes
past a drop. The output should stay evidence: sources, sinks, and the path. A
tool that reports &quot;vulnerable&quot; without showing its work has only moved the
guessing somewhere else.&lt;&#x2F;p&gt;
&lt;p&gt;Indirect calls remain the hard problem they have always been. I do not expect
that to change soon, and the honest move is to keep saying so in the answer.&lt;&#x2F;p&gt;
&lt;hr &#x2F;&gt;
&lt;p&gt;&lt;code&gt;rllvm&lt;&#x2F;code&gt; is Apache-2.0 and available on
&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;h1994st&#x2F;rllvm&quot;&gt;GitHub&lt;&#x2F;a&gt;, including the
&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;h1994st&#x2F;rllvm&#x2F;tree&#x2F;main&#x2F;examples&#x2F;ffi&quot;&gt;FFI example&lt;&#x2F;a&gt; and
&lt;a rel=&quot;noopener&quot; target=&quot;_blank&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;h1994st&#x2F;rllvm&#x2F;tree&#x2F;main&#x2F;examples&#x2F;external&#x2F;quiche&quot;&gt;notes on quiche&lt;&#x2F;a&gt;
used here. Measurements were taken on arm64 macOS against quiche 0.29.1 and
0.29.2, built with rustc 1.98.0 and read with LLVM 23.1.1.&lt;&#x2F;p&gt;
</content>
        
    </entry>
</feed>
