Learning Material
Estimate Time: 7 min read
Programs often store information in variables and collections so they can use it later. An array provides a fixed number of storage spaces, and a loop or copy operation can place values into those spaces. When information comes from outside a program, the program must make sure that the amount it stores fits the space it has reserved. This responsibility becomes important when a program handles text in C++, where writing beyond an array’s capacity can affect memory outside the array.
Lina is building a check-in program for a community event. The program prints each participant’s chosen name on a badge, and Lina reserves a small, fixed-size character array for each badge label. Normal names fit, so the program appears to work. But participants choose their own names, and one may submit a name much longer than the space Lina reserved. What happens when the program tries to copy that name into the array?
Learning Objectives
- Explain how a fixed-size character array stores text and why its capacity matters.
- Analyze how deliberately long input can cause a buffer overflow and describe the possible security consequences.
- Explain how checking the program’s actual input requirements and using suitable C++ string storage can prevent the overflow.
Understanding Fixed-Size Storage and Text
An array reserves a particular number of spaces. If a program creates an array with 12 character positions, the array can hold at most 12 characters. The program must keep every write within those positions. Unlike a collection that can grow as needed, a fixed-size array does not automatically expand when more data arrives.
Lina’s badge program uses a character array to hold a name. In C++, a C-style string also needs a special null character to mark where the text ends. That means an array with 12 positions can hold at most 11 ordinary text characters plus the ending null character. A shortened version of Lina’s copying code might look like this:
std::strcpy copies the source text and its ending null character into the destination
array. If submittedName contains 8 characters, the copy fits.
If it contains more than 11 characters, the copy needs more than the 12 positions
available in badgeLabel. The function does not check the array’s capacity before
copying.
This reveals a difference between the amount of data a program receives and the space it has reserved for that data. A short name fits Lina’s array; a long one does not. The array’s boundary is a real limit even if the program’s copying instruction does not enforce it. That relationship—data being written into a region with limited capacity—will explain why the same code can behave normally with one name and dangerously with another.
Exploring What Happens When Input Exceeds the Array
Lina’s program receives names from event participants.
Omar wants his full, 40-character online handle printed on his badge, so he submits it
even though Lina’s badge field was designed for short names.
The program passes the submitted text to std::strcpy without first checking its
length.
The source contains 40 characters, followed by a null character.
The copy therefore needs 41 positions, but badgeLabel has only 12. The first 12
positions fill the array; the remaining characters and ending null character are written
beyond its boundary.
A simplified view shows the mismatch:
badgeLabel capacity: [0][1][2][3][4][5][6][7][8][9][10][11]
copy required: 40 name characters, then an ending null character
The extra writes do not become part of a larger badgeLabel. They go outside the
storage reserved for that array.
C++ does not define what will happen after this out-of-bounds write.
The program might show damaged data, crash during check-in, or appear to work while
memory has still been corrupted.
The exact result can depend on the program and the system running it, so a successful
run with one long name does not show that the code is safe.
Writing beyond a buffer’s capacity is called a buffer overflow. A buffer is a region of memory used to hold data, and an overflow occurs when a program writes past that region. The underlying problem is also a memory-safety failure: the program has not kept its write within the memory reserved for the destination. Omar controls the name’s length, and Lina’s unchecked copy lets that control determine how far the write continues.
For the event, an overflow could corrupt program data or stop the check-in program, disrupting badge printing. In other software, corrupted memory can affect more important data or program behavior. The particular result is not guaranteed, but the security concern is clear: outside input can make the program write beyond the area it is meant to control. The program needs to establish that a name fits its requirements before copying it into fixed-size storage.
Designing a Safer Badge Label
Lina’s program does not need to accept every possible name.
The badge printer has room for at most 11 ordinary text characters, so the program can
enforce that requirement before using a submitted name.
It can also use std::string, which manages its own storage, instead of copying the
name into a fixed-size character array:
constexpr std::size_t maxLabelBytes = 11;
std::string submittedName = readName();
if (submittedName.empty() || submittedName.size() > maxLabelBytes) {
rejectName();
} else {
std::string badgeLabel = submittedName;
printBadge(badgeLabel);
}
For this example, names contain ordinary ASCII characters, so the 11-byte limit matches
the badge’s 11-character limit.
The program checks the name’s length before allowing it to become a badge label.
Omar’s 40-character handle is rejected, and the program does not copy it into a
12-character array. A valid name is stored in a std::string, which grows to hold its
contents rather than writing past a fixed array.
The length check still matters: it enforces the badge’s actual limit rather than
allowing a label that the printer cannot display as intended.
The check addresses the requirement, not just Omar’s particular 40-character name. Rejecting only that exact value would leave other overlong names unchecked. The same design reasoning applies whenever a program receives data for a limited space: it defines what fits, checks that requirement before relying on the data, and uses a storage method suited to the task. If a fixed-size array is required, the program must check the length before copying and ensure there is room for the ending null character as well as the text.
Lina’s revised program still receives names chosen by participants, but it no longer assumes that every name will fit. It establishes the allowed length before using a name for a badge, and its string storage avoids writing past a fixed boundary. The broader lesson is that input can influence not only a program’s decisions but also where it writes in memory. Safe C++ design keeps each write within the storage that belongs to it and checks outside data against the program’s real requirements before that data is used.