<?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: Chisom</title>
    <description>The latest articles on DEV Community by Chisom (@sommi).</description>
    <link>https://dev.to/sommi</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.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3943844%2Fc55eac56-4da5-42f0-9ed6-64d0a6ed30c7.png</url>
      <title>DEV Community: Chisom</title>
      <link>https://dev.to/sommi</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/sommi"/>
    <language>en</language>
    <item>
      <title>Ghost in the Stack (Part 1): Why uninitialized variables remember old data</title>
      <dc:creator>Chisom</dc:creator>
      <pubDate>Sat, 23 May 2026 12:26:14 +0000</pubDate>
      <link>https://dev.to/sommi/ghost-in-the-stack-part-1-why-uninitialized-variables-remember-old-data-3kjb</link>
      <guid>https://dev.to/sommi/ghost-in-the-stack-part-1-why-uninitialized-variables-remember-old-data-3kjb</guid>
      <description>&lt;p&gt;Have you ever written a C program, run it, and watched it print values you never assigned? &lt;br&gt;
At first glance, it feels almost as if old data is haunting your program from beyond a function call, but what is happening under the hood is far more interesting:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;stack frame reuse&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;compiler behaviour&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;memory persistence&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;and the performance tradeoffs built into modern systems&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In this series, we'll go from high-level C code into stack frames, assembly instructions, and eventually real-world security implications.&lt;br&gt;
Today, in Part 1, we investigate one of the most common low-level surprises in C: uninitialized local variables appearing to "remember" old values.&lt;br&gt;
Consider the following program:&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;void&lt;/span&gt; &lt;span class="nf"&gt;Subtraction&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="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;100&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;b&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;35&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;c&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="n"&gt;b&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;PrintValues&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;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&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;"First value is %d&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Second value is %d&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;Third value is %d&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;These are the values for PrintValues function&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;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;k&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="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="n"&gt;Subtraction&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;PrintValues&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;If we compile without optimization: gcc -O0 main.c, we may observe output similar to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;First value is 100
Second value is 35
Third value is 65
These are the values for PrintValues function
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At first glance, this looks impossible. PrintValues never initializes its variables. So why does it print the exact same values previously used by Subtraction()? &lt;strong&gt;Important Warning: This is undefined behaviour&lt;/strong&gt;&lt;br&gt;
Before going deeper, we need to clarify something important.&lt;br&gt;
Reading uninitialized local variables in C is undefined behaviour.&lt;br&gt;
That means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;the C standard does not guarantee what happens&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;different compilers might behave differently&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;optimization levels may change the result&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;future executions may produce different outputs&lt;br&gt;
The behaviour shown above is simply one possible outcome observed under a particular compiler configuration.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  The Dirty Whiteboard Analogy
&lt;/h2&gt;

&lt;p&gt;To understand what's happening, forget the code for a moment. Imagine RAM as a whiteboard in a shared classroom. First teacher (Subtraction()). A math teacher walks into the room and writes: 100, 35, 65 on the whiteboard. After class ends, she leaves without erasing anything, because erasing takes time. For a brief moment, the room is empty. The writing is still visible. Nothing has overwritten it yet. Second teacher (PrintValues()). A history teacher enters the room immediately afterward. Instead of writing anything new, he simply reads whatever is already on the board. At a high level, this resembles what happens with stack memory. When a function returns, typical compiled code does not automatically erase the stack bytes previously used for local variables. Instead:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;the stack space becomes available for reuse&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;old data often remains there temporarily&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;another function may reuse the same stack offsets&lt;br&gt;
If the new function reads memory before writing new values, it may accidentally observe leftover bytes from an earlier stack frame.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;
  
  
  INSPECT THE ASSEMBLY FOR SUBTRACTION()
&lt;/h2&gt;

&lt;p&gt;Let's inspect the assembly generated for Subtraction(). Below is the disassembly produced by GDB on x86-64:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;push %rbp
mov %rsp,%rbp
sub $0x30,%rsp
movl $0x64,-0x4(%rbp)
movl $0x23,-0x8(%rbp)
mov -0x4(%rbp),%eax
sub -0x8(%rb),%eax
mov %eax,-0xc(%rbp)
mov -0xc(%rbp),%ecx
mov -0x8(%rbp),%edx
mov -0x4(%rbp),%eax
add $0x30,%rsp
pop %rbp
ret
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;push %rbp&lt;/code&gt;  - Save the base pointer onto the stack &lt;br&gt;
&lt;code&gt;mov %rsp,%rbp&lt;/code&gt; - Set the stack pointer as the base pointer.&lt;br&gt;
&lt;code&gt;sub $0x30,%rsp&lt;/code&gt; - Allocate 48 bytes of space on the stack&lt;br&gt;
&lt;code&gt;movl $0x64,-0x4(%rbp)&lt;/code&gt; - Store 100 into the first 4 bytes on the stack&lt;br&gt;
&lt;code&gt;movl $0x23,-0x8(%rbp)&lt;/code&gt; - Store 35 into the second slot&lt;br&gt;
&lt;code&gt;mov -0x4(%rbp),%eax&lt;/code&gt;  - Load 100 into the eax register&lt;br&gt;
&lt;code&gt;sub -0x8(%rbp),%eax&lt;/code&gt;  - Subtract 35 from eax, the result remains in eax&lt;br&gt;
&lt;code&gt;mov %eax,-0xc(%rbp)&lt;/code&gt;  - Move the result from the register to memory&lt;br&gt;
&lt;code&gt;mov -0xc(%rbp),%ecx&lt;/code&gt;  - Move to register&lt;br&gt;
&lt;code&gt;mov -0x8(%rbp),%edx&lt;/code&gt;  - Move to register&lt;br&gt;
&lt;code&gt;mov -0x4(%rbp),%eax&lt;/code&gt;  - Move to register&lt;br&gt;
&lt;code&gt;add $0x30,%rsp&lt;/code&gt;       - Clean up allocated stack space&lt;br&gt;
&lt;code&gt;pop %rbp&lt;/code&gt;             - Restore the previous stack frame&lt;br&gt;
&lt;code&gt;ret&lt;/code&gt;                  - Return control to the caller&lt;br&gt;
After the function returns, the stack frame is released. The stack pointer simply moves back, making that region available for reuse. The previous values often remain there temporarily until another operation overwrites them. Typically compiled code does not automatically clear old stack contents because doing so would introduce additional instructions and reduce performance.&lt;/p&gt;
&lt;h2&gt;
  
  
  ENTER PrintValues()
&lt;/h2&gt;

&lt;p&gt;Now let us examine the beginning assembly code generated for PrintValues()&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;push %rbp
mov %rsp,%rbp
sub $0x30,%rsp
mov -0xc(%rbp),%eax
mov -0x4(%rbp),%edx
mov -0x8(%rbp),%ecx
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice something very important. PrintValues() allocates a very similar stack layout. So this instruction:&lt;br&gt;
&lt;code&gt;mov -0x4(%rbp),%eax&lt;/code&gt; means read whatever bytes that exists here. If those bytes still contain leftover data from Subtraction(), then PrintValues() may appear to "remember" the earlier values.&lt;br&gt;
This teaches something deeper than uninitialized variables are dangerous. It reveals an important systems principle: memory is reused, not automatically cleaned.&lt;/p&gt;

</description>
      <category>c</category>
      <category>assembly</category>
      <category>security</category>
      <category>debugging</category>
    </item>
  </channel>
</rss>
