<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Manish Sah</title>
    <description>The latest articles on DEV Community by Manish Sah (@csemanish12).</description>
    <link>https://dev.to/csemanish12</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F518218%2F515afa25-1c3d-4b7d-8387-0c66d2377fa7.jpeg</url>
      <title>DEV Community: Manish Sah</title>
      <link>https://dev.to/csemanish12</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/csemanish12"/>
    <language>en</language>
    <item>
      <title>Rust vs C: Why 'Index Out of Bounds' Is a Feature, Not a Bug</title>
      <dc:creator>Manish Sah</dc:creator>
      <pubDate>Thu, 23 Jul 2026 06:38:58 +0000</pubDate>
      <link>https://dev.to/csemanish12/rust-vs-c-why-index-out-of-bounds-is-a-feature-not-a-bug-4pi</link>
      <guid>https://dev.to/csemanish12/rust-vs-c-why-index-out-of-bounds-is-a-feature-not-a-bug-4pi</guid>
      <description>&lt;p&gt;C lets you read and write past the end of an array without complaint. Rust refuses. That one design decision is the difference between a crash and a remote code execution vulnerability.&lt;/p&gt;

&lt;p&gt;Imagine you're building a feature where users can select an item from a list. In Rust, if you try to pull index &lt;code&gt;10&lt;/code&gt; out of a 5-element array, the program stops dead in its tracks:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="c1"&gt;// src/main.rs&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Please enter an array index."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="nn"&gt;io&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;stdin&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;.read_line&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nf"&gt;.expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Failed to read line"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;usize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;
        &lt;span class="nf"&gt;.trim&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;.parse&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="nf"&gt;.expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Index entered was not a number"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

    &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"The value of the element at index {index} is: {element}"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Feed it &lt;code&gt;10&lt;/code&gt;, and Rust panics instantly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;thread 'main' panicked at src/main.rs:19:19:
index out of bounds: the len is 5 but the index is 10
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is a &lt;strong&gt;runtime check&lt;/strong&gt;, not a compile-time one — Rust doesn't know at compile time what &lt;code&gt;index&lt;/code&gt; will be, so it verifies bounds every time you index into the array, then deliberately crashes rather than continue.&lt;/p&gt;

&lt;p&gt;But what happens in &lt;strong&gt;C&lt;/strong&gt; in this exact situation? And why does C's behavior here account for some of the most damaging security exploits in software history?&lt;/p&gt;




&lt;h2&gt;
  
  
  1.  C: Raw Pointer Math, No Guardrails
&lt;/h2&gt;

&lt;p&gt;C takes the opposite approach: it assumes you know what you're doing, so indexing performs &lt;strong&gt;zero bounds checking&lt;/strong&gt;. &lt;code&gt;a[10]&lt;/code&gt; is really just:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;address = start_address_of_array + (index * element_size)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The CPU jumps straight to that computed address and reads (or writes) whatever is sitting there — no validation involved.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="c1"&gt;// Index 10 is well past the 5-element array&lt;/span&gt;
    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Value: %d&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What actually happens is undefined behavior, which in practice means one of:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Garbage data&lt;/strong&gt; — it prints whatever bits happen to live in adjacent memory.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Segmentation fault&lt;/strong&gt; — if the computed address falls outside memory your process is allowed to touch, the OS kills the process.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Silent memory corruption&lt;/strong&gt; — if you &lt;em&gt;write&lt;/em&gt; past the boundary (&lt;code&gt;a[10] = 99&lt;/code&gt;), you silently overwrite whatever variable happens to occupy that memory.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  2. Why This Is a Security Problem, Not Just a Bug
&lt;/h2&gt;

&lt;p&gt;Here's a simplified picture of how a C function's local variables can be laid out on the stack:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[ High Memory Address ]
+-----------------------------------+
|   Return Address                  |  &amp;lt;-- Tells CPU where to jump next
+-----------------------------------+
|   Saved Frame Pointer             |
+-----------------------------------+
|   admin_password = "Secret"       |  &amp;lt;-- Neighboring variable
+-----------------------------------+
|   a[4]  |  a[3]  |  a[2]  |  a[1] |  &amp;lt;-- Your array (5 integers)
+-----------------------------------+
[ Low Memory Address ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Caveat:&lt;/strong&gt; this is illustrative, not guaranteed. Real compilers reorder locals, insert padding, and add mitigations like stack canaries and ASLR (address space layout randomization) specifically to make this layout unpredictable. But the underlying principle holds: on the stack, your array and other local variables — including, eventually, the return address — live in contiguous memory with nothing stopping you from walking off the end of one into another.&lt;/p&gt;




&lt;h2&gt;
  
  
  3. How Attackers Exploit Unchecked Array Access
&lt;/h2&gt;

&lt;p&gt;Unchecked bounds lead to two main vulnerability classes.&lt;/p&gt;

&lt;h3&gt;
  
  
  A. Out-of-Bounds Read (Information Leak)
&lt;/h3&gt;

&lt;p&gt;If an attacker can influence which index or offset gets read, they can pull adjacent memory out of the process — including secrets that were never meant to leave it, like session tokens or other variables sitting nearby in memory.&lt;/p&gt;

&lt;h3&gt;
  
  
  B. Out-of-Bounds Write / Buffer Overflow (Arbitrary Code Execution)
&lt;/h3&gt;

&lt;p&gt;If an application lets you write past the end of an array, you can start overwriting things that control program flow.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cp"&gt;#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
#include&lt;/span&gt; &lt;span class="cpf"&gt;&amp;lt;string.h&amp;gt;&lt;/span&gt;&lt;span class="cp"&gt;
&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;secret_admin_panel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Access Granted: Welcome Admin!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;user_login&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;is_admin&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;              &lt;span class="c1"&gt;// Flag: 0 = User, 1 = Admin&lt;/span&gt;
    &lt;span class="kt"&gt;char&lt;/span&gt; &lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;              &lt;span class="c1"&gt;// Array sized for 8 characters&lt;/span&gt;

    &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Enter username: "&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;gets&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;                &lt;span class="c1"&gt;// UNSAFE: no length checking&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;is_admin&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;secret_admin_panel&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello, regular user.&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;gets()&lt;/code&gt; is used here deliberately as a textbook example — it was actually &lt;strong&gt;removed from the C standard in C11&lt;/strong&gt; because it's impossible to use safely, but plenty of legacy code and CTF challenges still rely on this exact pattern.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step by step:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;username&lt;/code&gt; gets 8 bytes, and &lt;code&gt;is_admin&lt;/code&gt; happens to sit next to it on the stack.&lt;/li&gt;
&lt;li&gt;Input &lt;code&gt;AAAAAAAAA&lt;/code&gt; (9 characters) overflows the buffer by one byte, overwriting &lt;code&gt;is_admin&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;is_admin&lt;/code&gt; is no longer &lt;code&gt;0&lt;/code&gt;, so &lt;code&gt;if (is_admin != 0)&lt;/code&gt; evaluates true — admin access granted.&lt;/li&gt;
&lt;li&gt;With a larger payload, an attacker can keep writing past local variables entirely and overwrite the &lt;strong&gt;return address&lt;/strong&gt;. When the function returns, the CPU jumps straight into attacker-controlled memory.&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  4. Rust's Answer: Panic by Default, &lt;code&gt;Option&lt;/code&gt; When You Want Control
&lt;/h2&gt;

&lt;p&gt;Rust's decision to panic on out-of-bounds access is deliberate: fail loudly and immediately rather than silently corrupt memory. But indexing with &lt;code&gt;[]&lt;/code&gt; isn't your only option. If you want to handle the invalid case yourself instead of crashing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="nf"&gt;.get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;Some&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Value: {value}"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nb"&gt;None&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Index out of bounds — handled gracefully"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;a.get(index)&lt;/code&gt; returns &lt;code&gt;Option&amp;lt;&amp;amp;T&amp;gt;&lt;/code&gt; — &lt;code&gt;None&lt;/code&gt; instead of a panic. This is the idiomatic way to handle user-controlled indices in production Rust code: &lt;code&gt;[]&lt;/code&gt; when you're certain the index is valid (and want a loud crash if you're wrong), &lt;code&gt;.get()&lt;/code&gt; when the index comes from outside and you want to handle failure explicitly.&lt;/p&gt;




&lt;h2&gt;
  
  
  Quick Comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;C&lt;/th&gt;
&lt;th&gt;Rust&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Out-of-bounds access&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Undefined behavior (reads/writes raw memory)&lt;/td&gt;
&lt;td&gt;Panics by default; &lt;code&gt;.get()&lt;/code&gt; returns &lt;code&gt;None&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;When is it checked&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Never&lt;/td&gt;
&lt;td&gt;Every access, at runtime&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Security risk&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Critical — buffer overflows, remote code execution&lt;/td&gt;
&lt;td&gt;Low — safe Rust can't produce this class of memory corruption&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Escape hatch&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;None (by design)&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;.get()&lt;/code&gt; / &lt;code&gt;Option&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Note the "safe Rust" qualifier: inside an &lt;code&gt;unsafe&lt;/code&gt; block, Rust lets you opt back into raw pointer access with the same risks C has. The safety guarantee applies to code that doesn't reach for &lt;code&gt;unsafe&lt;/code&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  Wrap-Up
&lt;/h2&gt;

&lt;p&gt;When Rust panics on a bad index, it can feel like the language is getting in your way. But that's the point — the crash is the safety mechanism. C's willingness to let you read and write past the end of an array isn't a missing feature; it's a design tradeoff from an era that prioritized raw performance over runtime checks, and it's directly responsible for decades of the worst vulnerabilities in software history.&lt;/p&gt;

&lt;p&gt;Have you run into a memory bug like this in production? Let's talk in the comments.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Source: &lt;a href="https://doc.rust-lang.org/std/primitive.slice.html#method.get" rel="noopener noreferrer"&gt;Rust documentation on slices and &lt;code&gt;Option&lt;/code&gt;&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>rust</category>
      <category>c</category>
      <category>security</category>
      <category>memorysafety</category>
    </item>
    <item>
      <title>Rust Strings Demystified: Literals, Slices, and Fat Pointers Under the Hood</title>
      <dc:creator>Manish Sah</dc:creator>
      <pubDate>Wed, 22 Jul 2026 03:54:29 +0000</pubDate>
      <link>https://dev.to/csemanish12/rust-strings-demystified-literals-slices-and-fat-pointers-under-the-hood-4o34</link>
      <guid>https://dev.to/csemanish12/rust-strings-demystified-literals-slices-and-fat-pointers-under-the-hood-4o34</guid>
      <description>&lt;p&gt;When developers switch to Rust from high-level languages like Python or JavaScript, one of the first mental speedbumps is the string system.&lt;/p&gt;

&lt;p&gt;Why are there two main string types (&lt;code&gt;String&lt;/code&gt; vs &lt;code&gt;&amp;amp;str&lt;/code&gt;)? What actually happens when a function returns &lt;code&gt;"Yummy!"&lt;/code&gt;? And why is a string slice called a &lt;strong&gt;"fat pointer"&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;In this post we'll look under the hood at how Rust lays out string literals, string slices, and pointers in memory — and why this design makes Rust strings fast and memory-efficient.&lt;/p&gt;




&lt;h2&gt;
  
  
  1. Literal vs. Slice
&lt;/h2&gt;

&lt;p&gt;Two terms get conflated a lot, so let's separate them:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Literal:&lt;/strong&gt; text hardcoded directly into your &lt;code&gt;.rs&lt;/code&gt; source file (e.g., &lt;code&gt;"Hello, world!"&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Slice (&lt;code&gt;&amp;amp;str&lt;/code&gt;):&lt;/strong&gt; a &lt;em&gt;view&lt;/em&gt; into a contiguous run of valid UTF-8 bytes somewhere in memory, without owning them.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The relationship between the two:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Every string literal is a string slice, but not every string slice is a string literal.&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// 1. A string literal — embedded in the compiled binary.&lt;/span&gt;
    &lt;span class="c1"&gt;// Type: &amp;amp;'static str&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;literal&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Hello, world!"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="c1"&gt;// 2. A dynamic String — allocated at runtime on the heap.&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;user_input&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;user_input&lt;/span&gt;&lt;span class="nf"&gt;.push_str&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Rustacean"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// 3. A slice into that heap string.&lt;/span&gt;
    &lt;span class="c1"&gt;// Type: &amp;amp;str (points into user_input's heap buffer, not the binary)&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;dynamic_slice&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;user_input&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// "Rust"&lt;/span&gt;

    &lt;span class="c1"&gt;// Both are &amp;amp;str, so the same function accepts either.&lt;/span&gt;
    &lt;span class="nf"&gt;print_slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;literal&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;       &lt;span class="c1"&gt;// "Hello, world!"&lt;/span&gt;
    &lt;span class="nf"&gt;print_slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dynamic_slice&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// "Rust"&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;print_slice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Printing slice: {}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;slice&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;literal&lt;/code&gt; is a string literal, so its type is &lt;code&gt;&amp;amp;'static str&lt;/code&gt; — it's embedded directly in the binary.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;dynamic_slice&lt;/code&gt; is a valid &lt;code&gt;&amp;amp;str&lt;/code&gt;, but &lt;strong&gt;not&lt;/strong&gt; a literal — it was carved out of &lt;code&gt;user_input&lt;/code&gt; at runtime and didn't exist in your source code.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  2. Normal Pointer vs. Fat Pointer
&lt;/h2&gt;

&lt;p&gt;In C, a string pointer is a plain 8-byte address (on 64-bit). String functions scan forward byte-by-byte until they hit a null terminator (&lt;code&gt;\0&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;Rust drops null terminators entirely. Instead, &lt;code&gt;&amp;amp;str&lt;/code&gt; is a &lt;strong&gt;fat pointer&lt;/strong&gt;: two 64-bit fields packed back to back, 16 bytes total on a 64-bit target.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────────┬─────────────────────────┐
│     Pointer (8 bytes)   │     Length (8 bytes)    │
├─────────────────────────┼─────────────────────────┤
│  0x00007FFF00401050     │            6             │
└─────────────────────────┴─────────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Pointer:&lt;/strong&gt; the address of the first byte.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Length:&lt;/strong&gt; the number of bytes in the slice.&lt;/li&gt;
&lt;/ol&gt;

&lt;blockquote&gt;
&lt;p&gt;Note: this ptr-then-length picture is the right &lt;em&gt;mental model&lt;/em&gt;, but Rust doesn't guarantee that exact field ordering as part of its stable ABI. What &lt;em&gt;is&lt;/em&gt; guaranteed is that a &lt;code&gt;&amp;amp;str&lt;/code&gt;/&lt;code&gt;&amp;amp;[T]&lt;/code&gt; reference is two machine words wide.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  3. What Happens When a Function Returns &lt;code&gt;"Yummy!"&lt;/code&gt;?
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;picky_eater&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;food&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;food&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"strawberry"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;"Yummy!"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;food&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s"&gt;"potato"&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;"I guess I can eat that."&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="s"&gt;"No thanks!"&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step A: The read-only data segment (&lt;code&gt;.rodata&lt;/code&gt;)
&lt;/h3&gt;

&lt;p&gt;At compile time, string literals like &lt;code&gt;"Yummy!"&lt;/code&gt; get written into the binary's read-only data segment (&lt;code&gt;.rodata&lt;/code&gt;). When the OS loads the binary, that data lands at a fixed address in RAM for the entire life of the program — which is exactly why literals get the &lt;code&gt;'static&lt;/code&gt; lifetime.&lt;/p&gt;

&lt;p&gt;Say the OS loads &lt;code&gt;"Yummy!"&lt;/code&gt; at &lt;code&gt;0x00007FFF00401050&lt;/code&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Address&lt;/th&gt;
&lt;th&gt;Byte (hex)&lt;/th&gt;
&lt;th&gt;Character&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x00007FFF00401050&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x59&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;'Y'&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x00007FFF00401051&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x75&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;'u'&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x00007FFF00401052&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x6D&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;'m'&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x00007FFF00401053&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x6D&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;'m'&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x00007FFF00401054&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x79&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;'y'&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;0x00007FFF00401055&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;0x21&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;'!'&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Step B: Constructing and returning the fat pointer
&lt;/h3&gt;

&lt;p&gt;Rust doesn't copy those 6 bytes onto the stack. It just constructs a 16-byte fat pointer:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Pointer&lt;/strong&gt; = &lt;code&gt;0x00007FFF00401050&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Length&lt;/strong&gt; = &lt;code&gt;6&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Since the underlying bytes live in &lt;code&gt;.rodata&lt;/code&gt; for the program's entire lifetime, returning this pointer is completely safe — you're never pointing at stack memory that disappears when the function returns.&lt;/p&gt;




&lt;h2&gt;
  
  
  4. Zero-Cost Slicing (and its one sharp edge)
&lt;/h2&gt;

&lt;p&gt;Because length is metadata on the pointer itself, sub-slicing is zero-cost:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;full&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Yummy!"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;sub&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;full&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt; &lt;span class="c1"&gt;// "ummy"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No new allocation, no copy — just a new 16-byte fat pointer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Memory:     [  'Y'  |  'u'  |  'm'  |  'm'  |  'y'  |  '!'  ]
Address:     ...1050  ...1051  ...1052  ...1053  ...1054  ...1055
             ▲        ▲                             ▲
             │        └──────────────┬──────────────┘
             │                       │
`full`:  ptr = ...1050, len = 6      │
`sub`:   ptr = ...1051, len = 4 ─────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;full&lt;/code&gt;: pointer = &lt;code&gt;0x...1050&lt;/code&gt;, length = &lt;code&gt;6&lt;/code&gt; (&lt;code&gt;"Yummy!"&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sub&lt;/code&gt;: pointer = &lt;code&gt;0x...1051&lt;/code&gt; (offset by 1 byte), length = &lt;code&gt;4&lt;/code&gt; (&lt;code&gt;"ummy"&lt;/code&gt;)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Both slices point into the exact same memory.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The gotcha:&lt;/strong&gt; those slice indices are &lt;em&gt;byte&lt;/em&gt; offsets, and Rust requires them to land on UTF-8 character boundaries. &lt;code&gt;&amp;amp;full[1..5]&lt;/code&gt; works because every character in &lt;code&gt;"Yummy!"&lt;/code&gt; is a single ASCII byte. Slice a multi-byte character (say, an emoji or accented letter) in the middle of its encoding, and Rust panics at runtime rather than handing back corrupted UTF-8. Coming from Python, where &lt;code&gt;str[1:5]&lt;/code&gt; just silently does the "wrong" thing on multi-byte content, this is worth internalizing early.&lt;/p&gt;




&lt;h2&gt;
  
  
  5. Summary Cheat Sheet
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Concept&lt;/th&gt;
&lt;th&gt;Definition&lt;/th&gt;
&lt;th&gt;Lifetime / Memory&lt;/th&gt;
&lt;th&gt;Size&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Literal&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Text hardcoded in source (&lt;code&gt;"..."&lt;/code&gt;).&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;'static&lt;/code&gt;, lives in &lt;code&gt;.rodata&lt;/code&gt;.&lt;/td&gt;
&lt;td&gt;Embedded in the binary.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Slice (&lt;code&gt;&amp;amp;str&lt;/code&gt;)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;A view (pointer + length) into valid UTF-8 bytes.&lt;/td&gt;
&lt;td&gt;Depends on what it borrows.&lt;/td&gt;
&lt;td&gt;16 bytes (fat pointer).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;&lt;code&gt;String&lt;/code&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Owned, growable, heap-allocated UTF-8 buffer.&lt;/td&gt;
&lt;td&gt;RAII — dropped when it goes out of scope.&lt;/td&gt;
&lt;td&gt;24 bytes (pointer, length, and capacity fields).&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Why this design matters
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;O(1) length lookups&lt;/strong&gt; — &lt;code&gt;.len()&lt;/code&gt; costs nothing at runtime; the length is already sitting in the fat pointer.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Zero-copy passing&lt;/strong&gt; — handing a 1 GB string slice to a function copies 16 bytes of pointer metadata, not the string.&lt;/li&gt;
&lt;/ol&gt;

</description>
      <category>computerscience</category>
      <category>performance</category>
      <category>programming</category>
      <category>rust</category>
    </item>
  </channel>
</rss>
