courses Memory: who owns what 2/5

Off By One

The tests pass, the sanitizer screams. One missing byte for the terminator.

Lesson

The idea: strings carry a hidden byte

A C string of n characters occupies n + 1 bytes. The last one is the terminating '\0'. strlen does not count it, and malloc does not add it for you.

Writing one byte past the end of a block is a heap buffer overflow. It often "works": the byte lands in padding, the tests stay green, and the corruption waits for a bad day.

The situation

upper_copy returns an upper-cased copy of a string. Run the tests: they pass. Now run the sanitizer: it does not.

Your mission

Read the sanitizer report: it names the block that was overrun, the line where it was allocated, and the function that wrote past its end. Compare how many bytes are allocated with how many bytes are written. Then give the junior the exact arithmetic.

What to watch for

  • Passing tests prove nothing about memory safety. Both tools must come back clean.
  • "Allocate more" is tempting. Does it hold for every length? Think about the empty string.

Try this exercise

Create a free account to tell the AI junior what to change, run the tests and the memory checker, and earn a completion code you can verify.

Starting code
upper.c
#include "upper.h"#include <ctype.h>#include <stdlib.h>#include <string.h> char *upper_copy(const char *s) {    size_t n = strlen(s);    char *out = malloc(n);    if (!out) return NULL;    for (size_t i = 0; i < n; i++) {        out[i] = (char)toupper((unsigned char)s[i]);    }    out[n] = '\0';    return out;}
upper.h
#ifndef UPPER_H#define UPPER_H/* Returns a new heap string with every letter upper-cased. The CALLER owns the result. */char *upper_copy(const char *s);#endif