c++stringstdstrncpyc-standard-library

C++ custom-written strncpy without padding all characters to null is it safe?


#include <iostream>
using namespace std;

struct Packet {
    int a;
    char b[17];
    int c;
};

// char* dest has form char dest[n], src has length <= n and is null-terminated
// After the function, dest should satisfy:
// - If strlen(src)==n, dest is not null terminated
// - If strlen(src) < n, dest[n-1] = dest[strlen(src)] = '\0'
static void strncpy_faster(char* dest, const char* src, size_t n) {
    size_t i;
    for (i = 0; i < n; i++) {
      dest[i] = src[i];
      if (src[i] == '\0')
        break;
    }
    //while (i < n) {dest[i] = '\0'; i++;} // C standard strncpy do this
    if (i < n)
      dest[n - 1] = '\0';
 }
 
 string charArrayToString(const char* a, size_t n) {
    size_t len = 0;
    while (len < n && a[len]!='\0') len++;
    return std::string(a, a+len);
 }

int main()
{
    string s = "12341234123412345";
    Packet packet;
    
    strncpy_faster(packet.b, s.c_str(), 17);
    cout << charArrayToString(packet.b, sizeof(packet.b)) << "\n";
    
    s = "12345";
    strncpy_faster(packet.b, s.c_str(), 17);
    cout << charArrayToString(packet.b, sizeof(packet.b));
    return 0;
}

I'm dealing with struct that have fixed-size char arrays. Let's say I really, really want to keep struct size small (or I need to send them over network), so std::string is not used in my struct (it cost 32 bytes, while I have multiple small char arrays with size 4-20). I have 2 problems with strncpy:

So, my strncpy_faster only assign up to 2 positions to '\0': the last element of the array, and the position of strlen(src). Since std::string() requires a null-terminated char array (NTCA), I use charArrayToString() to convert non-NTCA to string.

Is this version of strncpy safe? Are there any C/C++ functions that requires strncpy to fill all leftover bytes with '\0', or do they only need a null terminator? I don't know why the standard requires strncpy to zero-out remaining bytes.


Solution

  • Is this version of strncpy safe?

    Yes.

    It's as safe as strncpy is. So.... not safe.

    Are there any C/C++ functions that requires strncpy to fill all leftover bytes with '\0', or do they only need a null terminator?

    No function require it.

    Notes from Linux man-pages man strcpy:

    NOTES

    Some programmers consider strncpy() to be inefficient and error prone. If the programmer knows (i.e., includes code to test!) that the size of dest is greater than the length of src, then strcpy() can be used.

    One valid (and intended) use of strncpy() is to copy a C string to a fixed-length buffer while ensuring both that the buffer is not overflowed and that unused bytes in the destination buffer are zeroed out (perhaps to prevent information leaks if the buffer is to be written to media or transmitted to another process via an interprocess communication technique).

    Consider using (and/or implementing) strlcpy. Remember about first rule of optimization.