why gets and unbounded strcpy are dangerous
Some tools are dangerous not because you might misuse them but because they CANNOT be used safely at all. In C's standard library, a handful of old string functions fall into this category: by their very design they write an amount of data that the CALLER cannot control, into a buffer of FIXED size. The mismatch makes a buffer overflow not a risk but a near-certainty as soon as the input is large enough.
The worst offender is gets(). It reads a line from standard input into a buffer, but it has no parameter for the buffer's size, so it keeps writing until it hits a newline no matter how big the input is. There is no possible buffer large enough to be safe against arbitrary input, which is why gets() was officially removed from the C standard in C11 — it is the rare function the committee deleted outright. strcpy(dst, src) is nearly as bad in practice: it copies characters from src until it reaches the null terminator, with zero regard for how big dst is, so a too-long src overflows dst. strcat has the same flaw when appending. The standard 'n' variants take a size and are safer: snprintf is the recommended way to format into a buffer because it never writes past the size you give and always null-terminates. strncpy takes a size too, but carries its own caveat: if the source is exactly as long as the limit it does NOT add a terminating null, leaving you with an unterminated string that later reads run past — so even the 'safe' function needs care.
Why this matters: these functions are not theoretical relics; they appear in tutorials, legacy code, and quick scripts, and they are behind a great many historical security breaches. The practical rules are blunt: never call gets() (use fgets with an explicit size, or getline); prefer snprintf for formatting into buffers; treat strcpy and strcat as overflow waiting to happen unless you have already proven the destination is large enough; and when you use strncpy, terminate the result yourself. The real lesson underneath is that the size of the destination must travel with the destination — a function that does not take it cannot be safe.
char buf[64]; gets(buf); /* NEVER: no size; removed from C11 */ strcpy(buf, untrusted); /* overflows if untrusted > 63 chars */ /* safer replacements */ fgets(buf, sizeof buf, stdin); /* bounded line read */ snprintf(buf, sizeof buf, "%s", src); /* bounded, always terminated */
gets() and unbounded strcpy take no destination size and cannot be made safe. fgets and snprintf take a size; prefer them.
strncpy is safer than strcpy but is NOT automatically null-terminating: if the source fills the buffer exactly, no terminator is written and you are left with an unterminated string. Always terminate the result yourself, or prefer snprintf.