<!doctype html><htmllang=endir=ltrclass="blog-wrapper blog-post-page plugin-blog plugin-id-default"data-has-hydrated=false><metacharset=UTF-8><metaname=generatorcontent="Docusaurus v3.6.1"><titledata-rh=true>QADAPT - debug_assert! for allocations | The Old Speice Guy</title><metadata-rh=truename=viewportcontent="width=device-width,initial-scale=1.0"><metadata-rh=truename=twitter:cardcontent=summary_large_image><metadata-rh=trueproperty=og:urlcontent=https://speice.io/2018/12/allocation-safety><metadata-rh=trueproperty=og:localecontent=en><metadata-rh=truename=docusaurus_localecontent=en><metadata-rh=truename=docusaurus_tagcontent=default><metadata-rh=truename=docsearch:languagecontent=en><metadata-rh=truename=docsearch:docusaurus_tagcontent=default><metadata-rh=trueproperty=og:titlecontent="QADAPT - debug_assert! for allocations | The Old Speice Guy"><metadata-rh=truename=descriptioncontent="I think it's part of the human condition to ignore perfectly good advice when it comes our way. A"><metadata-rh=trueproperty=og:descriptioncontent="I think it's part of the human condition to ignore perfectly good advice when it comes our way. A"><metadata-rh=trueproperty=og:typecontent=article><metadata-rh=trueproperty=article:published_timecontent=2018-12-15T12:00:00.000Z><linkdata-rh=truerel=iconhref=/img/favicon.ico><linkdata-rh=truerel=canonicalhref=https://speice.io/2018/12/allocation-safety><linkdata-rh=truerel=alternatehref=https://speice.io/2018/12/allocation-safetyhreflang=en><linkdata-rh=truerel=alternatehref=https://speice.io/2018/12/allocation-safetyhreflang=x-default><scriptdata-rh=truetype=application/ld+json>{"@context":"https://schema.org","@id":"https://speice.io/2018/12/allocation-safety","@type":"BlogPosting","author":{"@type":"Person","name":"Bradlee Speice"},"dateModified":"2024-11-10T02:05:00.000Z","datePublished":"2018-12-15T12:00:00.000Z","description":"I think it's part of the human condition to ignore perfectly good advice when it comes our way. A","headline":"QADAPT - debug_assert! for allocations","isPartOf":{"@id":"https://speice.io/","@type":"Blog","name":"Blog"},"keywords":[],"mainEntityOfPage":"https://speice.io/2018/12/allocation-safety","name":"QADAPT - debug_assert! for allocations","url":"https://speice.io/2018/12/allocation-safety"}</script><linkrel=alternatetype=application/rss+xmlhref=/rss.xmltitle="The Old Speice Guy RSS Feed"><linkrel=alternatetype=application/atom+xmlhref=/atom.xmltitle="The Old Speice Guy Atom Feed"><linkrel=stylesheethref=/katex/katex.min.css><linkrel=stylesheethref=/assets/css/styles.16c3428d.css><scriptsrc=/assets/js/runtime~main.29a27dcf.jsdefer></script><scriptsrc=/assets/js/main.d461af80.jsdefer></script><bodyclass=navigation-with-keyboard><script>!function(){vart,e=function(){try{returnnewURLSearchParams(window.location.search).get("docusaurus-theme")}catch(t){}}()||function(){try{returnwindow.localStorage.getItem("theme")}catch(t){}}();t=null!==e?e:"light",document.documentElement.setAttribute("data-theme",t)}(),function(){try{for(var[t,e]ofnewURLSearchParams(window.location.search).entries())if(t.startsWith("docusaurus-data-")){vara=t.replace("docusaurus-data-","data-");document.documentElement.setAttribute(a,e)}}catch(t){}}()</script><divid=__docusaurus><divrole=regionaria-label="Skip to main content"><aclass=skipToContent_fXgnhref=#__docusaurus_skipToContent_fallback>Skip to main content</a></div><navaria-label=Mainclass="navbar navbar--fixed-top"><divclass=navbar__inner><divclass=navbar__items><buttonaria-label="Toggle navigation bar"aria-expanded=falseclass="navbar__toggle clean-btn"type=button><svgwidth=30height=30viewBox="0 0 30 30"aria-hidden=true><pathstroke=currentColorstroke-linecap=roundstroke-miterlimit=10stroke-width=2d="M4 7h22M4 15h22M4 23h22"/></svg></button><aclass=navbar__brandhref=/><divclass=navbar__logo><imgsrc=/img/logo.svgalt="Sierpinski Gasket"class="themedComponent_mlkZ themedComponent--light_NVdE"><imgsrc=/img/logo-dark.svg
<p>And <em>that's</em> the part I'm going to focus on.</p>
<h2class="anchor anchorWithStickyNavbar_LWe7"id=why-an-allocator>Why an Allocator?<ahref=#why-an-allocatorclass=hash-linkaria-label="Direct link to Why an Allocator?"title="Direct link to Why an Allocator?"></a></h2>
<p>So why, after complaining about allocators, would I still want to write one? There are three reasons
for that:</p>
<ol>
<li>Allocation/dropping is slow</li>
<li>It's difficult to know exactly when Rust will allocate or drop, especially when using code that
you did not write</li>
<li>I want automated tools to verify behavior, instead of inspecting by hand</li>
</ol>
<p>When I say "slow," it's important to define the terms. If you're writing web applications, you'll
spend orders of magnitude more time waiting for the database than you will the allocator. However,
there's still plenty of code where micro- or nano-seconds matter; think
<ahref=https://polysync.io/blog/session-types-for-hearty-codecs/target=_blankrel="noopener noreferrer">self-driving cars</a>, and
<ahref=https://carllerche.github.io/bytes/bytes/index.htmltarget=_blankrel="noopener noreferrer">networking</a>. In these situations it's simply
unacceptable for you to spend time doing things that are not your program, and waiting on the
allocator is not cool.</p>
<p>As I continue to learn Rust, it's difficult for me to predict where exactly allocations will happen.
So, I propose we play a quick trivia game: <strong>Does this code invoke the allocator?</strong></p>
<h3class="anchor anchorWithStickyNavbar_LWe7"id=example-1>Example 1<ahref=#example-1class=hash-linkaria-label="Direct link to Example 1"title="Direct link to Example 1"></a></h3>
<p><strong>No</strong>: Rust <ahref=https://doc.rust-lang.org/std/mem/fn.size_of.htmltarget=_blankrel="noopener noreferrer">knows how big</a> the <code>Vec</code> type is,
and reserves a fixed amount of memory on the stack for the <code>v</code> vector. However, if we wanted to
reserve extra space (using <code>Vec::with_capacity</code>) the allocator would get invoked.</p>
<h3class="anchor anchorWithStickyNavbar_LWe7"id=example-2>Example 2<ahref=#example-2class=hash-linkaria-label="Direct link to Example 2"title="Direct link to Example 2"></a></h3>
<p><strong>Yes</strong>: Because Boxes allow us to work with things that are of unknown size, it has to allocate on
the heap. While the <code>Box</code> is unnecessary in this snippet (release builds will optimize out the
allocation), reserving heap space more generally is needed to pass a dynamically sized type to
another function.</p>
<h3class="anchor anchorWithStickyNavbar_LWe7"id=example-3>Example 3<ahref=#example-3class=hash-linkaria-label="Direct link to Example 3"title="Direct link to Example 3"></a></h3>
<p><strong>Maybe</strong>: Depending on whether the Vector we were given has space available, we may or may not
allocate. Especially when dealing with code that you did not author, it's difficult to verify that
things behave as you expect them to.</p>
<h2class="anchor anchorWithStickyNavbar_LWe7"id=blowing-things-up>Blowing Things Up<ahref=#blowing-things-upclass=hash-linkaria-label="Direct link to Blowing Things Up"title="Direct link to Blowing Things Up"></a></h2>
<p>So, how exactly does QADAPT solve these problems? <strong>Whenever an allocation or drop occurs in code
marked allocation-safe, QADAPT triggers a thread panic.</strong> We don't want to let the program continue
as if nothing strange happened, <em>we want things to explode</em>.</p>
<p>However, you don't want code to panic in production because of circumstances you didn't predict.
Just like <ahref=https://doc.rust-lang.org/std/macro.debug_assert.htmltarget=_blankrel="noopener noreferrer"><code>debug_assert!</code></a>, <strong>QADAPT will
strip out its own code when building in release mode to guarantee no panics and no performance
impact.</strong></p>
<p>Finally, there are three ways to have QADAPT check that your code will not invoke the allocator:</p>
<h3class="anchor anchorWithStickyNavbar_LWe7"id=using-a-procedural-macro>Using a procedural macro<ahref=#using-a-procedural-macroclass=hash-linkaria-label="Direct link to Using a procedural macro"title="Direct link to Using a procedural macro"></a></h3>
<p>The easiest method, watch an entire function for allocator invocation:</p>
<h3class="anchor anchorWithStickyNavbar_LWe7"id=using-a-regular-macro>Using a regular macro<ahref=#using-a-regular-macroclass=hash-linkaria-label="Direct link to Using a regular macro"title="Direct link to Using a regular macro"></a></h3>
<h3class="anchor anchorWithStickyNavbar_LWe7"id=using-function-calls>Using function calls<ahref=#using-function-callsclass=hash-linkaria-label="Direct link to Using function calls"title="Direct link to Using function calls"></a></h3>
<h3class="anchor anchorWithStickyNavbar_LWe7"id=caveats>Caveats<ahref=#caveatsclass=hash-linkaria-label="Direct link to Caveats"title="Direct link to Caveats"></a></h3>
<p>It's important to point out that QADAPT code is synchronous, so please be careful when mixing in
<h2class="anchor anchorWithStickyNavbar_LWe7"id=conclusion>Conclusion<ahref=#conclusionclass=hash-linkaria-label="Direct link to Conclusion"title="Direct link to Conclusion"></a></h2>
<p>While there's a lot more to writing high-performance code than managing your usage of the allocator,
it's critical that you do use the allocator correctly. QADAPT will verify that your code is doing
what you expect. It's usable even on stable Rust from version 1.31 onward, which isn't the case for
most allocators. Version 1.0 was released today, and you can check it out over at
<ahref=https://crates.io/crates/qadapttarget=_blankrel="noopener noreferrer">crates.io</a> or on <ahref=https://github.com/bspeice/qadapttarget=_blankrel="noopener noreferrer">github</a>.</p>
<p>I'm hoping to write more about high-performance Rust in the future, and I expect that QADAPT will