Skip to main content

Linux 7.2 Removes strncpy After 37 Years of C Safety Debt

·1405 words·7 mins
Linux C Programming Rust Kernel Development Memory Safety Systems Programming Open Source Software Security Linux Kernel
Table of Contents

Linux 7.2 Removes strncpy After 37 Years of C Safety Debt

During the Linux 7.2 merge window, kernel developers completed a milestone that appears trivial at first glance but carries significant implications for systems programming: the complete removal of the strncpy() API from the Linux kernel.

The effort spanned six years, required more than 360 patches, and touched hundreds of locations throughout the codebase. While this may seem like a routine refactoring task, it is better understood as the conclusion of a decades-long lesson about the hidden costs of unsafe APIs and the structural limitations of C’s memory model.

More importantly, the migration highlights a broader industry trend: the gradual transition from defensive programming practices toward memory-safe language designs.

🔍 Why strncpy() Was Fundamentally Problematic
#

The controversy surrounding strncpy() is not the result of an implementation bug. The problems originate from the API’s original design.

The function signature is straightforward:

strncpy(dst, src, n);

Its behavior follows three rules:

  1. Copy up to n bytes from src to dst.
  2. If src is shorter than n, pad the remaining bytes with \0.
  3. If src is equal to or longer than n, do not append a null terminator.

The third rule is where most of the danger begins.

Missing Null-Termination Creates Hidden Risks
#

Many developers assume that copying a string results in a valid C string. However, strncpy() does not guarantee this outcome.

Consider the following pattern:

char buf[16];
strncpy(buf, input, sizeof(buf));
printf("%s\n", buf);

If input contains 16 or more bytes, buf will not be null-terminated. Any subsequent operation relying on string semantics becomes unsafe.

Common examples include:

  • strlen()
  • printf("%s")
  • strcmp()
  • strcat()

The correctness of these operations depends on assumptions that cannot always be verified at compile time.

Inside the Linux kernel, where buffer sizes often depend on hardware descriptors, runtime configurations, or user input, such assumptions become particularly dangerous.

The Padding Behavior Is Also Wasteful
#

A second issue is less visible but equally problematic.

When the source string is shorter than the destination buffer, strncpy() fills the remaining space with zeros.

For example:

char buf[4096];
strncpy(buf, "hello", sizeof(buf));

Only five bytes of meaningful data are copied, yet the function writes thousands of additional bytes.

This behavior can introduce:

  • Unnecessary memory writes
  • Cache pollution
  • Reduced performance on hot paths
  • Additional memory subsystem pressure

The Linux kernel increasingly views such behavior as unacceptable overhead.

A Historical Artifact Misused for Decades
#

The irony is that strncpy() was not originally designed for modern string handling.

Its purpose was copying data into fixed-width, space-constrained records such as directory entries in early Unix filesystems.

When ANSI C standardized the function in 1989, it inherited a design optimized for a narrow use case. Over time, developers adopted it as a generic string-copy routine, exposing countless applications to subtle bugs and security vulnerabilities.

🛠️ From strlcpy() to strscpy(): Two Attempts to Fix C Strings
#

The Linux kernel’s migration away from strncpy() did not happen overnight.

Instead, it followed a decades-long evolution of safer APIs.

First Generation: strlcpy()
#

In 1998, OpenBSD developers Theo de Raadt and Todd C. Miller introduced strlcpy().

The API addressed the most dangerous flaw of strncpy() by guaranteeing null-termination.

Its advantages included:

  • No unnecessary padding
  • Predictable behavior
  • Easier truncation detection
  • Safer interaction with standard string functions

As a result, strlcpy() gained widespread adoption across Unix-like systems, including Linux.

The Hidden Problem in strlcpy()
#

Although significantly safer, strlcpy() introduced a different issue.

To return the full length of the source string, it must scan the entire source buffer.

This means that even if only a few bytes are copied, the function continues reading until it finds a terminating null character.

If the source pointer references:

  • Untrusted memory
  • Corrupted data
  • A non-null-terminated buffer

the function may perform out-of-bounds reads.

For kernel code, that risk remained unacceptable.

Linux’s Solution: strscpy()
#

In 2015, Linux introduced strscpy().

The API was designed specifically around kernel safety requirements.

Key characteristics include:

  • Guaranteed null-termination
  • No zero-padding overhead
  • Bounded source reads
  • Explicit truncation reporting

Unlike strlcpy(), it never scans beyond the specified boundary.

A successful copy returns the number of bytes copied.

A truncated copy returns:

-E2BIG

This design minimizes ambiguity while maintaining performance and safety.

⏳ Why Removing strncpy() Took Six Years
#

The technical replacement itself was relatively simple.

In many locations, migrating from:

strncpy(...)

to:

strscpy(...)

required only minor code changes.

The real challenge was verification.

Every Usage Had to Be Audited
#

Kernel maintainers needed to answer several questions for every occurrence.

For example:

  • Was the code relying on automatic padding?
  • Did downstream logic assume unused bytes were zero-filled?
  • Were structures serialized with expectations about padding?
  • Did any subsystem depend on legacy behavior?

Each conversion required careful review.

The majority of effort was spent proving that replacing the API would not introduce subtle regressions.

This explains why the migration ultimately required:

  • More than 360 patches
  • Hundreds of modified files
  • Multiple years of review cycles

The bottleneck was never writing code.

The bottleneck was understanding decades of accumulated assumptions.

🦀 Rust’s Perspective: Eliminating Entire Categories of Bugs
#

The most interesting aspect of this migration may not be the replacement API itself.

Instead, it highlights how different language designs approach safety.

C Relies on Programmer Discipline
#

In C, strings are represented as raw memory terminated by a sentinel value.

Nothing in the type system guarantees:

  • Proper termination
  • Correct buffer sizes
  • Valid lengths
  • Safe truncation handling

Developers must manually enforce these constraints.

As a result, APIs such as strncpy() can survive for decades despite known flaws.

Rust Moves Safety Into the Type System
#

Rust takes a fundamentally different approach.

A string slice:

&str

contains:

  • A pointer
  • An explicit length

The compiler always knows the boundaries.

There is no concept of accidentally forgetting a null terminator because null terminators are not part of the string model.

Similarly, operations such as:

copy_from_slice()

require matching lengths.

Violations become compile-time errors rather than runtime bugs.

Unsafe Code Becomes Explicit
#

Rust does not eliminate memory hazards entirely.

Raw pointers and low-level operations remain available through:

unsafe

blocks.

The difference is that unsafe regions are isolated and visible.

By contrast, large portions of a C codebase effectively operate as one giant implicit unsafe block.

This distinction significantly reduces the surface area where memory errors can occur.

🔒 What This Means for Linux and Systems Programming
#

Linux’s adoption of Rust remains gradual.

As of mid-2026, Rust support is primarily concentrated in selected drivers and infrastructure components rather than the kernel core.

However, the removal of strncpy() provides a compelling case study.

An API introduced nearly four decades ago required:

  • Thirty-seven years of operational experience
  • Countless bug reports
  • Numerous security incidents
  • Six years of coordinated cleanup

before it was finally eradicated.

A memory-safe language can often eliminate the same category of error before code is ever compiled.

That difference has profound implications for long-term maintenance.

🌐 Implications for Linux-Based Operating Systems
#

The significance extends beyond the upstream Linux kernel.

Many operating systems and enterprise distributions inherit substantial portions of Linux’s C codebase, including:

  • HarmonyOS
  • openEuler
  • OpenAnolis
  • Embedded Linux platforms
  • Enterprise Linux distributions

When upstream maintainers spend years removing unsafe APIs, downstream projects face an important decision.

They can:

  1. Continuously backport safety improvements.
  2. Continue carrying legacy technical debt.
  3. Invest in memory-safe languages for future development.

The cost of postponing such transitions grows over time.

Every unsafe abstraction that remains in production code represents a future maintenance burden and a potential security liability.

📌 Conclusion
#

The removal of strncpy() from Linux 7.2 is more than a cleanup milestone. It is a reminder that software engineering decisions can carry consequences for decades.

The function was not removed because developers suddenly discovered a bug. It was removed because the industry gradually recognized that the API’s design itself was flawed. Over time, kernel maintainers concluded that the safest path was complete elimination rather than continued mitigation.

The six-year migration demonstrates how difficult it is to remove unsafe abstractions once they become deeply embedded in critical infrastructure. At the same time, it strengthens the argument for memory-safe languages such as Rust, where entire classes of string-handling mistakes can be prevented by design rather than corrected through years of auditing.

In that sense, Linux’s removal of strncpy() is not merely the end of a legacy API. It is a visible example of how systems programming is slowly shifting from managing safety debt toward preventing it from accumulating in the first place.

Related

What Comes After eBPF? Exploring the KernelScript Experiment
·1436 words·7 mins
Linux EBPF KernelScript Kernel Development Open Source Systems Programming Rust Networking Cloud Native Linux Foundation
Linux Kernel Development (3rd Edition): Complete Technical Overview
·1141 words·6 mins
Linux Linux Kernel Operating-Systems Kernel Development Systems Programming Linux Internals Computer Science Software-Engineering
Understanding the Linux Kernel (3rd Edition): Complete Guide
·1033 words·5 mins
Linux Linux Kernel Kernel Development Operating-Systems System Programming VFS Memory Management Kernel Architecture