|Parameter Passing and the Call Stack
IA Concept: Buffer Overflow
A comparison is often drawn between writing a good program and writing a good essay. While they differ in some distinct ways (i.e. writing more lines of code does not always get you closer to being done), they are also similar in many ways. For instance, you can take all of your thoughts and force them into one giant five-page paragraph, but this will certainly not produce a coherent essay. Although it is possible that all of your ideas will be expressed, they will not be expressed as cleanly as they would have been if they were broken up. Furthermore anyone reading this essay will be lost in a stream of consciousness.
Likewise, in order to write a good program, it is important to break up your thoughts into distinct pieces (often referred to as decomposition). Computer scientists have invested time and effort into building languages and tools that assist programmers in this process. The concept of modularity and objected oriented languages are a result of this, but in this lab we will focus on the most basic tool of decomposition, the method. Methods are coherent blocks of code that encapsulate functionality. However, in order to effectively use methods, one must be able to parameterize a method’s arguments through what is known as parameter passing.
Parameter passing differs from language to language, and thus computer scientists tend to study the mechanisms behind parameter passing in one language in order to not only become a better programmer in the language they are studying, but also to gain better intuition for how it works in other languages. Furthermore, there are certain classes of issues that are only analyzable through an understanding of how data is manipulated during the execution of a program.
This lab focuses on one of those problems, buffer overruns, and shows how understanding the run-time stack in C++ can help to both understand and prevent these fatal errors.
In this lab, you will:
Review basic parameter-passing concepts
Learn about the execution stack in C++
Be able to use this information to exploit a buffer overrun
We begin with a brief review of parameter passing, looking into how the stack is utilized to make it possible. But what is the stack? The stack can be thought of as a stack of plates that grows downward. Whenever a method is called, one of these plates (called a stack frame) is created with enough space to hold all the local variables. When we return from that method the stack frame for that method is popped off the stack, and its data is no more.
Let’s say for example we have the following C++ code:
When main is called, a stack frame is created with enough space for x and y as follows: