惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

J
Java Code Geeks
aimingoo的专栏
aimingoo的专栏
Martin Fowler
Martin Fowler
C
Check Point Blog
G
Google Developers Blog
V
Visual Studio Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Google DeepMind News
Google DeepMind News
人人都是产品经理
人人都是产品经理
有赞技术团队
有赞技术团队
MongoDB | Blog
MongoDB | Blog
月光博客
月光博客
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
大猫的无限游戏
大猫的无限游戏
D
Docker
Hugging Face - Blog
Hugging Face - Blog
The GitHub Blog
The GitHub Blog
博客园 - 三生石上(FineUI控件)
A
About on SuperTechFans
Recent Announcements
Recent Announcements
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
阮一峰的网络日志
阮一峰的网络日志
Stack Overflow Blog
Stack Overflow Blog
Vercel News
Vercel News

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
Ghost in the Stack (Part 1): Why uninitialized variables ...
Chisom · 2026-05-23 · via DEV Community

Chisom

Have you ever written a C program, run it, and watched it print values you never assigned?
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:

  • stack frame reuse

  • compiler behaviour

  • memory persistence

  • and the performance tradeoffs built into modern systems

In this series, we'll go from high-level C code into stack frames, assembly instructions, and eventually real-world security implications.
Today, in Part 1, we investigate one of the most common low-level surprises in C: uninitialized local variables appearing to "remember" old values.
Consider the following program:

#include <stdio.h>
void Subtraction()
{
    int a = 100;
    int b = 35;
    int c = a - b;
}
void PrintValues()
{
    int i, j, k;
    printf("First value is %d\nSecond value is %d\nThird value is %d\nThese are the values for PrintValues function\n", i, j, k);
}
int main()
{
    Subtraction();
    PrintValues();
    return 0;
}

Enter fullscreen mode Exit fullscreen mode

If we compile without optimization: gcc -O0 main.c, we may observe output similar to this:

First value is 100
Second value is 35
Third value is 65
These are the values for PrintValues function

Enter fullscreen mode Exit fullscreen mode

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

  • the C standard does not guarantee what happens

  • different compilers might behave differently

  • optimization levels may change the result

  • future executions may produce different outputs
    The behaviour shown above is simply one possible outcome observed under a particular compiler configuration.

The Dirty Whiteboard Analogy

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:

  • the stack space becomes available for reuse

  • old data often remains there temporarily

  • another function may reuse the same stack offsets
    If the new function reads memory before writing new values, it may accidentally observe leftover bytes from an earlier stack frame.

INSPECT THE ASSEMBLY FOR SUBTRACTION()

Let's inspect the assembly generated for Subtraction(). Below is the disassembly produced by GDB on x86-64:

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

Enter fullscreen mode Exit fullscreen mode

push %rbp - Save the base pointer onto the stack
mov %rsp,%rbp - Set the stack pointer as the base pointer.
sub $0x30,%rsp - Allocate 48 bytes of space on the stack
movl $0x64,-0x4(%rbp) - Store 100 into the first 4 bytes on the stack
movl $0x23,-0x8(%rbp) - Store 35 into the second slot
mov -0x4(%rbp),%eax - Load 100 into the eax register
sub -0x8(%rbp),%eax - Subtract 35 from eax, the result remains in eax
mov %eax,-0xc(%rbp) - Move the result from the register to memory
mov -0xc(%rbp),%ecx - Move to register
mov -0x8(%rbp),%edx - Move to register
mov -0x4(%rbp),%eax - Move to register
add $0x30,%rsp - Clean up allocated stack space
pop %rbp - Restore the previous stack frame
ret - Return control to the caller
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.

ENTER PrintValues()

Now let us examine the beginning assembly code generated for PrintValues()

push %rbp
mov %rsp,%rbp
sub $0x30,%rsp
mov -0xc(%rbp),%eax
mov -0x4(%rbp),%edx
mov -0x8(%rbp),%ecx

Enter fullscreen mode Exit fullscreen mode

Notice something very important. PrintValues() allocates a very similar stack layout. So this instruction:
mov -0x4(%rbp),%eax 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.
This teaches something deeper than uninitialized variables are dangerous. It reveals an important systems principle: memory is reused, not automatically cleaned.