Pointers & Memory · intermediate · ~12 min
Combine capacity, lifetime, initialization, and arithmetic checks before accessing memory.
Memory safety combines several obligations: access a live object, stay within its bounds, initialize values before reading, and calculate sizes without overflow. Use a small checked copy to connect these obligations before trying larger security exercises.
A valid pointer alone says nothing about how many elements can be written. Carry capacity with the destination and a count with the source. Compute a safe copy count before the loop and preserve storage beyond the intended range.
Check integer arithmetic before using its result for an allocation or a bound. Signed overflow is undefined behavior; comparing a wrapped result afterward is too late.
Capacity checks cannot validate object lifetime or ownership automatically. State those preconditions explicitly. Tests should target one failed obligation at a time so their feedback explains what went wrong.
Memory safety combines several obligations: access a live object, stay within its bounds, initialize values before reading, and calculate sizes without overflow. Use a small checked copy to connect these obligations before trying larger security exercises.
#include <stdio.h>
int copy_prefix(int *dst, int cap, const int *src, int n) {
int count = n < cap ? n : cap;
for (int i = 0; i < count; ++i) dst[i] = src[i];
return count;
}
int main(void) {
int src[] = {1, 2, 3};
int dst[2] = {0};
int count = copy_prefix(dst, 2, src, 3);
printf("%d: %d %d\n", count, dst[0], dst[1]);
return 0;
}
Expected output on a successful allocation, where applicable:
2: 1 2
For this example, counts are nonnegative, the buffers are live and disjoint, and their stated extents are valid. The minimum count limits writes to the two-element destination.
Validate arithmetic before calculating sizes, cap accesses by real extents, and keep objects alive. Document what a helper checks and what it requires from its caller.