Use memccpy function to replace unsafe and inefficient str[n]cpy, str[n]cat, etc

The memccpy function can replace the unsafe and inefficient str[n]cpy, str[n]cat, etc

The memccpy function is in the POSIX standard library and recently added to the C23 standard library. In the C runtime of MSVC, it starts with an underscore_ Memccpy exists. Functions that do not begin with an underscore are currently deprecated (these functions may be marked with deprecated in the future)

str[n]cpy and strcat are one of the culprits of buffer overflow. If src in str[n]cpy or src or dst in strcat is user input, these functions are unsafe; Although strncat is safe, it has to scan dst every time, which is inefficient

memccpy can replace these functions, and as long as you check whether the return value is NULL, you can determine whether it overflows, which ensures security and makes programming more convenient

--------------------------------

memccpy

Defined in header file < string h>

void *memccpy(void * restrict dest, const void * restrict src, int c, size_t count);

Copy characters from the object pointed to by {src} to the object pointed to by {dest}, and stop after any of the following two conditions are met:

  • Copied {count} characters
  • Found (and copied) the character (unsigned char)c.

Translate the array of # src # and # dest # objects as # unsigned # char #.

The behavior is undefined if any of the following conditions are met:

  • An access past the end of the {dest} array occurred
  • Object overlap (this violates restrict (contract)
  • dest , or , src , is an illegal or null pointer value

parameter

dest-Pointer to the object to copy
src-Pointer to the copy source object
c-The terminating character is first converted to an unsigned char
count-Number of characters to copy

Return value

If the character (unsigned char)c , is found, memccpy , returns the pointer to the character after (unsigned char)c , in , dest , otherwise, returns a null pointer.

annotation

Function is equivalent to POSIX memccpy .

memccpy(dest, src, 0, count) behaves similarly strncpy (dest, src, count), except that the former returns a pointer to the end of the written buffer and does not fill the target array with zero. Thus, memccpy is useful for efficiently connecting multiple strings.

char bigString[1000];
char* end = bigString + sizeof bigString;
 
char* p = memccpy(bigString, "John, ", 0, sizeof bigString);
if (p) p = memccpy(p - 1, "Paul, ", 0, end - p);
if (p) p = memccpy(p - 1, "George, ", 0, end - p);
if (p) p = memccpy(p - 1, "Joel ", 0, end - p);
 
puts(bigString); // John, Paul, George, Joel

Example

#include <ctype.h>
#include <stdio.h>
#include <string.h>
 
int main(void)
{
    const char src[] = "Stars: Altair, Sun, Vega.";
    const char terminal[] = {':', ' ', ',', '.', '!'};
    char dest[sizeof src];
    const char alt = '@';
 
    for (size_t i = 0; i != sizeof terminal; ++i) {
 
        void *to = memccpy(dest, src, terminal[i], sizeof dest);
 
        printf("Terminal '%c' (%s):\t\"", terminal[i], to ? "found" : "absent");
 
        // If the 'terminal' character is not found - print the entire ` dest`
        to = to ? to : dest + sizeof dest;
 
        for (char *from = dest; from != to; ++from)
            putchar(isprint(*from) ? *from : alt);
 
        puts("\"");
    }
 
 
    puts("\n" "Separate star names from distances (ly):");
    const char *star_distance[] = {
        "Arcturus : 37", "Vega : 25", "Capella : 43", "Rigel : 860", "Procyon : 11"
    };
    char names_only[64];
    char *first = names_only;
    char *last = names_only + sizeof names_only;
 
    for (size_t t = 0; t != (sizeof star_distance)/(sizeof star_distance[0]); ++t) {
        if (first) {
            first = memccpy(first, star_distance[t], ' ', last - first);
        } else break;
    }
    if (first) {
        *first = '\0';
        puts(names_only);
    } else {
        puts("Buffer is too small.");
    }
}

Output:

Terminal ':' (found):   "Stars:"
Terminal ' ' (found):   "Stars: "
Terminal ',' (found):   "Stars: Altair,"
Terminal '.' (found):   "Stars: Altair, Sun, Vega."
Terminal '!' (absent):  "Stars: Altair, Sun, Vega.@"
 
Separate star names from distances (ly):
Arcturus Vega Capella Rigel Procyon

reference material:

memccpy - cppreference.com

_memccpy | Microsoft Docs

Keywords: C++ security

Added by jokeruk on Tue, 04 Jan 2022 18:44:48 +0200