There's a few ways to deal with this.
First, and perhaps most important, is to avoid fixed memory allocations especially when dealing with input. In your example above instead of copying to a fixed size buffer you can make the buffer the size you need.
char password_copy[strlen(password) + 1];
strcpy(password_copy, password);
But that's not always possible. Maybe you've got already allocated memory. Maybe you do want to truncate the input (though 16 is far too small for a password).
One is to not use the C string handling functions at all, they're riddled with flaws and security holes. Instead use a library like Gnome Lib which features the G_String type. G_Strings track their length and allocated size. This takes a little more memory, but it's faster. Finding the length of the string, something that happens a lot, doesn't require iterating through every byte of the string.
G_Strings have their own set of string handling functions which are much handier than the C ones. It also can grow strings as necessary or allocate new strings for you.
/* Allocate memory for the copy and copy the password */
G_String *password_copy = g_string_new(password);
For compatibility with regular string functions password_copy->str returns a normal char *.
This is IMO the best way. You no longer have to remember to check string lengths and allocated sizes and worry about null bytes everywhere you use strings. You will forget. Let the computer do that.
If you must use C standard functions, don't use strncpy because it fails to guarantee the truncated string will be null terminated. Instead use strlcpy. It's like strncpy but it guarantees the copied string will be null terminated. strlcpy is a BSD extension, so it's not guaranteed to be portable. glibc refuses to implement it.
For maximum portability, efficiency, and safety use strlcpy and provide a fallback using memmove and #ifndef strlcpy so it will only be used if strlcpy is not already available.
#include <string.h>
#include <stdio.h>
#ifndef strlcpy
size_t strlcpy(char * restrict dst, const char * restrict src, size_t dst_size) {
/* size is the allocated size. len leaves space for the null byte */
size_t dst_len = dst_size - 1;
size_t src_len = strlen(src);
/* Use the smaller of the two string lengths to avoid buffer overflow */
size_t move_len = src_len > dst_len ? dst_len : src_len;
/* Copy the string, truncate if necessary. It will work
* even if src and dst overlap. */
memmove(dst, src, move_len);
/* Guarantee there's a null byte */
dst[move_len] = '\0';
/* strlcpy returns the size of the string it tried to make.
* This is used to detect truncation. */
return src_len;
}
#endif
int main()
{
char dst[10];
char *src = "12345678901234567890";
printf("%zu\n", strlcpy(dst, src, 10));
printf("src: %s, dst: %s\n", src, dst);
return 0;
}
strcpywith a safe function. What are you looking to accomplish by keepingstrcpy?char password_buffer[strlen(password)+1]. Welcome to stack overflow.passwordat all?strcpy