Skip to content

Add memcpy_a(), and use it instead of its pattern - #1308

Open
alejandro-colomar wants to merge 2 commits into
shadow-maint:masterfrom
alejandro-colomar:mc
Open

Add memcpy_a(), and use it instead of its pattern#1308
alejandro-colomar wants to merge 2 commits into
shadow-maint:masterfrom
alejandro-colomar:mc

Conversation

@alejandro-colomar

@alejandro-colomar alejandro-colomar commented Jul 22, 2025

Copy link
Copy Markdown
Collaborator

Cc: @kees, @uecker


Revisions:

v1b
  • Rebase
$ git rd 
1:  dffde298 = 1:  6bc38c93 lib/string/strcpy/: MEMCPY(): Add macro
2:  bb82ea8f = 2:  fcbdb102 lib/utmp.c: prepare_utmp(): Use MEMCPY() instead of its pattern
v1c
  • Rebase
$ git rd 
1:  6bc38c93 = 1:  4e58e271 lib/string/strcpy/: MEMCPY(): Add macro
2:  fcbdb102 = 2:  593fd728 lib/utmp.c: prepare_utmp(): Use MEMCPY() instead of its pattern
v1d
  • Rebase
$ git rd 
1:  4e58e271 = 1:  547300ae lib/string/strcpy/: MEMCPY(): Add macro
2:  593fd728 = 2:  33c2c97f lib/utmp.c: prepare_utmp(): Use MEMCPY() instead of its pattern
v1d
  • Rebase
$ git rd 
1:  4fc3f696 = 1:  163d8535 lib/string/strcpy/: strncpytail(), STRNCPYTAIL(): Add APIs
2:  df8b604d ! 2:  95ab3cb6 lib/utmp.c: Use STRNCPYTAIL() instead of its pattern
    @@ Commit message
     
      ## lib/utmp.c ##
     @@
    - #include "string/strcmp/streq.h"
    + #include "string/strcmp/strneq.h"
      #include "string/strcmp/strprefix.h"
      #include "string/strcpy/strncpy.h"
     +#include "string/strcpy/strncpytail.h"
v1e
  • Rebase
$ git rd 
1:  c6e3fb88 = 1:  09766c81 lib/string/strcpy/: MEMCPY(): Add macro
2:  b490b803 ! 2:  136fb881 lib/utmp.c: prepare_utmp(): Use MEMCPY() instead of its pattern
    @@ lib/utmp.c
     +#include "string/strcpy/memcpy.h"
      #include "string/strcpy/strncpy.h"
      #include "string/strcpy/strtcpy.h"
    - #include "string/strdup/xstrdup.h"
    + #include "string/strdup/strdup.h"
     @@ lib/utmp.c: prepare_utmp(const char *name, const char *line, const char *host,
                        } else if (info->ai_family == AF_INET6) {
                                struct sockaddr_in6 *sa =
v2
$ git range-diff shadow/master..gh/mc gh/_a..mc 
1:  09766c81b ! 1:  03bbc341e lib/string/strcpy/: MEMCPY(): Add macro
    @@ Metadata
     Author: Alejandro Colomar <alx@kernel.org>
     
      ## Commit message ##
    -    lib/string/strcpy/: MEMCPY(): Add macro
    +    lib/string/strcpy/: memcpy_a(): Add macro
     
         Signed-off-by: Alejandro Colomar <alx@kernel.org>
     
    @@ lib/string/strcpy/memcpy.h (new)
     +#include <assert.h>
     +
     +
    -+#define MEMCPY(dst, src)                                              \
    ++// memcpy_a - memory copy array
    ++#define memcpy_a(dst, src)                                            \
     +({                                                                    \
    -+  static_assert(SIZEOF_ARRAY(dst) == SIZEOF_ARRAY(src), "");    \
    ++  static_assert(sizeof_a(dst) == sizeof_a(src), "");            \
     +                                                                      \
    -+  memcpy(dst, src, SIZEOF_ARRAY(dst));                          \
    ++  memcpy(dst, src, sizeof_a(dst));                              \
     +})
     +
     +
2:  136fb8812 ! 2:  e7edb3b27 lib/utmp.c: prepare_utmp(): Use MEMCPY() instead of its pattern
    @@ Metadata
     Author: Alejandro Colomar <alx@kernel.org>
     
      ## Commit message ##
    -    lib/utmp.c: prepare_utmp(): Use MEMCPY() instead of its pattern
    +    lib/utmp.c: prepare_utmp(): Use memcpy_a() instead of its pattern
     
         Signed-off-by: Alejandro Colomar <alx@kernel.org>
     
    @@ lib/utmp.c: prepare_utmp(const char *name, const char *line, const char *host,
     -                                  &(sa->sin6_addr),
     -                                  MIN (sizeof (utent->ut_addr_v6),
     -                                       sizeof (sa->sin6_addr)));
    -+                          MEMCPY(utent->ut_addr_v6, sa->sin6_addr.s6_addr);
    ++                          memcpy_a(utent->ut_addr_v6, sa->sin6_addr.s6_addr);
      # endif
                        }
                        freeaddrinfo (info);
v2b
  • Update lib/string/README.
$ git range-diff gh/_a gh/mc mc 
1:  03bbc341e ! 1:  c4cc91187 lib/string/strcpy/: memcpy_a(): Add macro
    @@ lib/Makefile.am: libshadow_la_SOURCES = \
        string/strcpy/stpecpy.h \
        string/strcpy/strncat.c \
     
    + ## lib/string/README ##
    +@@ lib/string/README: strcpy/ - String copying
    +   a size.  This makes it safer for chaining several calls.
    + 
    +   m/
    +-    MEMCPY()
    ++    memcpy_a()
    +   Like memcpy(3), but takes two arrays.
    + 
    + sprintf/ - Formatted string creation
    +
      ## lib/string/strcpy/memcpy.c (new) ##
     @@
     +// SPDX-FileCopyrightText: 2025, Alejandro Colomar <alx@kernel.org>
2:  e7edb3b27 = 2:  2c9c74b0f lib/utmp.c: prepare_utmp(): Use memcpy_a() instead of its pattern
v2c
  • Rebase
$ git range-diff gh/_a..gh/mc _a..mc
1:  c4cc91187 = 1:  c82bca8d0 lib/string/strcpy/: memcpy_a(): Add macro
2:  2c9c74b0f ! 2:  1ac79da9e lib/utmp.c: prepare_utmp(): Use memcpy_a() instead of its pattern
    @@ lib/utmp.c
      #include "string/strcmp/strprefix.h"
     +#include "string/strcpy/memcpy.h"
      #include "string/strcpy/strncpy.h"
    - #include "string/strcpy/strtcpy.h"
      #include "string/strdup/strdup.h"
    + #include "string/strdup/strndup.h"
     @@ lib/utmp.c: prepare_utmp(const char *name, const char *line, const char *host,
                        } else if (info->ai_family == AF_INET6) {
                                struct sockaddr_in6 *sa =
v2d
  • Rebase
$ git range-diff gh/_a..gh/mc _a..mc
1:  c82bca8d0 = 1:  3e22dd033 lib/string/strcpy/: memcpy_a(): Add macro
2:  1ac79da9e = 2:  3dc937da5 lib/utmp.c: prepare_utmp(): Use memcpy_a() instead of its pattern
v2e
  • Rebase
$ git range-diff gh/_a..gh/mc shadow/master..mc 
1:  3e22dd033 = 1:  f3b1edd31 lib/string/strcpy/: memcpy_a(): Add macro
2:  3dc937da5 = 2:  ed7398219 lib/utmp.c: prepare_utmp(): Use memcpy_a() instead of its pattern
v2f
  • Rebase
$ git rd 
1:  f3b1edd31 = 1:  2e5f5f92c lib/string/strcpy/: memcpy_a(): Add macro
2:  ed7398219 ! 2:  8262a4dc3 lib/utmp.c: prepare_utmp(): Use memcpy_a() instead of its pattern
    @@ lib/utmp.c: prepare_utmp(const char *name, const char *line, const char *host,
                                        (struct sockaddr_in6 *) info->ai_addr;
     -                          memcpy (utent->ut_addr_v6,
     -                                  &(sa->sin6_addr),
    --                                  MIN (sizeof (utent->ut_addr_v6),
    --                                       sizeof (sa->sin6_addr)));
    +-                                  MIN(sizeof(utent->ut_addr_v6),
    +-                                      sizeof(sa->sin6_addr)));
     +                          memcpy_a(utent->ut_addr_v6, sa->sin6_addr.s6_addr);
      # endif
                        }
v2g
  • Rebase
$ git rd 
1:  2e5f5f92c = 1:  3fa525926 lib/string/strcpy/: memcpy_a(): Add macro
2:  8262a4dc3 = 2:  47529a5b8 lib/utmp.c: prepare_utmp(): Use memcpy_a() instead of its pattern
v2h
  • Rebase
$ git rd 
1:  3fa525926 = 1:  a717e5bb3 lib/string/strcpy/: memcpy_a(): Add macro
2:  47529a5b8 = 2:  21a9f6c38 lib/utmp.c: prepare_utmp(): Use memcpy_a() instead of its pattern
v2i
  • Rebase
$ git rd 
1:  a717e5bb3 = 1:  35f71d23a lib/string/strcpy/: memcpy_a(): Add macro
2:  21a9f6c38 = 2:  affe3d5a9 lib/utmp.c: prepare_utmp(): Use memcpy_a() instead of its pattern
v2j
  • Rebase
$ git rd 
1:  35f71d23aca9 = 1:  4b4ad74692d0 lib/string/strcpy/: memcpy_a(): Add macro
2:  affe3d5a9616 ! 2:  c606c9d28684 lib/utmp.c: prepare_utmp(): Use memcpy_a() instead of its pattern
    @@ lib/utmp.c
      #include "string/strcmp/strprefix.h"
     +#include "string/strcpy/memcpy.h"
      #include "string/strcpy/strncpy.h"
    + #include "string/strdup/memdup.h"
      #include "string/strdup/strdup.h"
    - #include "string/strdup/strndup.h"
     @@ lib/utmp.c: prepare_utmp(const char *name, const char *line, const char *host,
                        } else if (info->ai_family == AF_INET6) {
                                struct sockaddr_in6 *sa =
v2k
  • Rebase
$ git rd 
1:  4b4ad746 = 1:  ef2d1535 lib/string/strcpy/: memcpy_a(): Add macro
2:  c606c9d2 = 2:  1663d8a2 lib/utmp.c: prepare_utmp(): Use memcpy_a() instead of its pattern
v2l
  • Rebase
$ git rd 
1:  ef2d1535 = 1:  4cb63560 lib/string/strcpy/: memcpy_a(): Add macro
2:  1663d8a2 = 2:  4893be27 lib/utmp.c: prepare_utmp(): Use memcpy_a() instead of its pattern
v2m
  • Rebase
$ git rd 
1:  4cb635604bcb = 1:  25f1333d2ec8 lib/string/strcpy/: memcpy_a(): Add macro
2:  4893be270c99 = 2:  7613ad8dd644 lib/utmp.c: prepare_utmp(): Use memcpy_a() instead of its pattern
v2n
  • Rebase
$ git rd 
1:  25f1333d2ec8 = 1:  1528fe36e36b lib/string/strcpy/: memcpy_a(): Add macro
2:  7613ad8dd644 = 2:  6255ecf45cd6 lib/utmp.c: prepare_utmp(): Use memcpy_a() instead of its pattern
v2o
  • Rebase
$ git rd 
1:  1528fe36e36b = 1:  063a158fc7cc lib/string/strcpy/: memcpy_a(): Add macro
2:  6255ecf45cd6 = 2:  c55bfb47cecf lib/utmp.c: prepare_utmp(): Use memcpy_a() instead of its pattern
v3
  • Use <memory.h> instead of <string.h>. Historically, and morally, it's more appropriate. It's quite portable, so it should be fine, even though it's non-standard. See memory.h(3head).
$ git rd 
1:  063a158fc7cc ! 1:  ae476d2d4f00 lib/string/strcpy/: memcpy_a(): Add macro
    @@ lib/string/strcpy/memcpy.h (new)
     +
     +#include "config.h"
     +
    -+#include <string.h>
    ++#include <memory.h>
     +
     +#include "sizeof.h"
     +
2:  c55bfb47cecf = 2:  d3e94c2d9bfe lib/utmp.c: prepare_utmp(): Use memcpy_a() instead of its pattern
v3b
  • wsfix
$ git rd 
1:  ae476d2d4f00 ! 1:  81ee46501194 lib/string/strcpy/: memcpy_a(): Add macro
    @@ lib/string/strcpy/memcpy.h (new)
     +#define memcpy_a(dst, src)                                            \
     +({                                                                    \
     +  static_assert(sizeof_a(dst) == sizeof_a(src), "");            \
    -+                                                                      \
    ++                                                                \
     +  memcpy(dst, src, sizeof_a(dst));                              \
     +})
     +
2:  d3e94c2d9bfe = 2:  ba80e2885cf9 lib/utmp.c: prepare_utmp(): Use memcpy_a() instead of its pattern
v4
  • Move API to a new lib/memory/. [@ikerexxe ]
$ git rd --creation-factor=99 
1:  81ee46501194 ! 1:  aa8bdefd8bab lib/string/strcpy/: memcpy_a(): Add macro
    @@ Metadata
     Author: Alejandro Colomar <alx@kernel.org>
     
      ## Commit message ##
    -    lib/string/strcpy/: memcpy_a(): Add macro
    +    lib/memory/memcpy/: memcpy_a(): Add macro
     
         Signed-off-by: Alejandro Colomar <alx@kernel.org>
     
      ## lib/Makefile.am ##
     @@ lib/Makefile.am: libshadow_la_SOURCES = \
    -   string/strcmp/strneq.h \
    -   string/strcmp/strprefix.c \
    -   string/strcmp/strprefix.h \
    -+  string/strcpy/memcpy.c \
    -+  string/strcpy/memcpy.h \
    -   string/strcpy/stpecpy.c \
    -   string/strcpy/stpecpy.h \
    -   string/strcpy/strncat.c \
    +   lockpw.c \
    +   loginprompt.c \
    +   mail.c \
    ++  memory/memcpy/memcpy.c \
    ++  memory/memcpy/memcpy.h \
    +   motd.c \
    +   myname.c \
    +   nss.c \
     
    - ## lib/string/README ##
    -@@ lib/string/README: strcpy/ - String copying
    -   a size.  This makes it safer for chaining several calls.
    - 
    -   m/
    --    MEMCPY()
    -+    memcpy_a()
    -   Like memcpy(3), but takes two arrays.
    - 
    - sprintf/ - Formatted string creation
    -
    - ## lib/string/strcpy/memcpy.c (new) ##
    + ## lib/memory/memcpy/memcpy.c (new) ##
     @@
    -+// SPDX-FileCopyrightText: 2025, Alejandro Colomar <alx@kernel.org>
    ++// SPDX-FileCopyrightText: 2025-2026, Alejandro Colomar <alx@kernel.org>
     +// SPDX-License-Identifier: BSD-3-Clause
     +
     +
     +#include "config.h"
     +
    -+#include "string/strcpy/memcpy.h"
    ++#include "memory/memcpy/memcpy.h"
     
    - ## lib/string/strcpy/memcpy.h (new) ##
    + ## lib/memory/memcpy/memcpy.h (new) ##
     @@
    -+// SPDX-FileCopyrightText: 2025, Alejandro Colomar <alx@kernel.org>
    ++// SPDX-FileCopyrightText: 2025-2026, Alejandro Colomar <alx@kernel.org>
     +// SPDX-License-Identifier: BSD-3-Clause
     +
     +
    -+#ifndef SHADOW_INCLUDE_LIB_STRING_STRCPY_MEMCPY_H_
    -+#define SHADOW_INCLUDE_LIB_STRING_STRCPY_MEMCPY_H_
    ++#ifndef SHADOW_INCLUDE_LIB_MEMORY_MEMCPY_MEMCPY_H_
    ++#define SHADOW_INCLUDE_LIB_MEMORY_MEMCPY_MEMCPY_H_
     +
     +
     +#include "config.h"
    @@ lib/string/strcpy/memcpy.h (new)
     +
     +
     +#endif  // include guard
    +
    + ## lib/string/README ##
    +@@ lib/string/README: strcpy/ - String copying
    +   a size.  This makes it safer for chaining several calls.
    + 
    +   m/
    +-    MEMCPY()
    ++    memcpy_a()
    +   Like memcpy(3), but takes two arrays.
    + 
    + sprintf/ - Formatted string creation
2:  ba80e2885cf9 ! 2:  fc89d8f3710b lib/utmp.c: prepare_utmp(): Use memcpy_a() instead of its pattern
    @@ Commit message
     
      ## lib/utmp.c ##
     @@
    + #include "alloc/malloc.h"
    + #include "attr.h"
    + #include "io/syslog.h"
    ++#include "memory/memcpy/memcpy.h"
    + #include "sizeof.h"
    + #include "string/strchr/strnul.h"
      #include "string/strcmp/streq.h"
    - #include "string/strcmp/strneq.h"
    - #include "string/strcmp/strprefix.h"
    -+#include "string/strcpy/memcpy.h"
    - #include "string/strcpy/strncpy.h"
    - #include "string/strdup/memdup.h"
    - #include "string/strdup/strdup.h"
     @@ lib/utmp.c: prepare_utmp(const char *name, const char *line, const char *host,
                        } else if (info->ai_family == AF_INET6) {
                                struct sockaddr_in6 *sa =

@alejandro-colomar
alejandro-colomar marked this pull request as ready for review July 22, 2025 12:43
@alejandro-colomar alejandro-colomar added the Simpler A good issue for a new beginner label Aug 16, 2025
@alejandro-colomar
alejandro-colomar marked this pull request as draft November 1, 2025 17:17
@alejandro-colomar alejandro-colomar changed the title Add MEMCPY(), and use it instead of its pattern Add memcpy_a(), and use it instead of its pattern Nov 1, 2025
@alejandro-colomar
alejandro-colomar force-pushed the mc branch 3 times, most recently from 1ac79da to 3dc937d Compare November 6, 2025 13:06
@alejandro-colomar
alejandro-colomar force-pushed the mc branch 2 times, most recently from ed73982 to 8262a4d Compare November 28, 2025 21:27
@alejandro-colomar
alejandro-colomar marked this pull request as ready for review November 28, 2025 21:27
@alejandro-colomar
alejandro-colomar force-pushed the mc branch 2 times, most recently from 47529a5 to 21a9f6c Compare December 7, 2025 13:14
@alejandro-colomar alejandro-colomar self-assigned this Dec 11, 2025
@alejandro-colomar
alejandro-colomar force-pushed the mc branch 2 times, most recently from c606c9d to 1663d8a Compare February 26, 2026 16:06

@kees kees left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same comments here about array vs size-known pointers. I do like the compile-time validation that the src/dst are required to be identical sizes, though! That's a very tight control.

@alejandro-colomar

alejandro-colomar commented Feb 26, 2026

Copy link
Copy Markdown
Collaborator Author

@kees

Same comments here about array vs size-known pointers.

Given that we have full control of the sizes at compile time, we require arrays as inputs. (It wouldn't make sense to have pointers as long as we require knowing their sizes at compile time.)

If we had more uses of memcpy(3), it could certainly be interesting to allow using it with array parameters, or other creatures (e.g., pointers) whose size is only known at run time but whose equality might be known at compile time.

This is a great use case for the compiler_assert() macro:

alx@devuan:~/tmp$ cat mc.c 
#include <string.h>
#include <strings.h>

#define compiler_assert(e)  do                                        \
{                                                                     \
	[[gnu::error("")]] extern void fail_(void);                   \
                                                                      \
	if (!(e))                                                     \
		fail_();                                              \
} while (0)

#define countof(a)   (sizeof(a) / sizeof(*(a)))
#define sizeof_a(a)  (countof(a) * sizeof((a)[0]))
#define bzero_a(a)   bzero(a, sizeof_a(a))

#define memcpy_a(dst, src)                                            \
({                                                                    \
	compiler_assert(sizeof_a(dst) == sizeof_a(src));              \
	                                                              \
	memcpy(dst, src, sizeof_a(dst));                              \
})

void g(char *);

void
f(size_t n)
{
	char a1[n];
	char a2[n];

	bzero_a(a1);

	memcpy_a(a2, a1);

	g(a2);  // To make sure the arrays are used.
}
alx@devuan:~/tmp$ gcc -S -Wall -Wextra mc.c 
mc.c: In functionf’:
mc.c:9:17: error: call tofail_declared with attribute error: 
    9 |                 fail_();                                              \
      |                 ^~~~~~~
mc.c:18:9: note: in expansion of macrocompiler_assert18 |         compiler_assert(sizeof_a(dst) == sizeof_a(src));              \
      |         ^~~~~~~~~~~~~~~
mc.c:33:9: note: in expansion of macromemcpy_a33 |         memcpy_a(a2, a1);
      |         ^~~~~~~~
alx@devuan:~/tmp$ gcc -S -Wall -Wextra -O1 mc.c 
alx@devuan:~/tmp$ 

This macro requires some optimizations to build correctly, as otherwise the equality can't be guaranteed.

We may want to call this macro optimizer_assert() instead...

Cc: @jwakely, @jonnygrant

See also https://github.com/jonnygrant/compile_assert and jonnygrant/compile_assert#1 (comment).

I do like the compile-time validation that the src/dst are required to be identical sizes, though! That's a very tight control.

Thanks!

@alejandro-colomar

alejandro-colomar commented Feb 26, 2026

Copy link
Copy Markdown
Collaborator Author

In this project, we don't have any remaining uses of memcpy(3) that don't use regular arrays, so we can omit the compiler_assert() magic.

$ grep -rn 'memcpy *(' src/ lib*
lib/string/README:208:	Like memcpy(3), but takes two arrays.
lib/string/strcpy/memcpy.h:23:	memcpy(dst, src, sizeof_a(dst));                              \

But it would certainly be interesting, if we ever need it.

@jonnygrant

Copy link
Copy Markdown

@kees

Same comments here about array vs size-known pointers.

Given that we have full control of the sizes at compile time, we require arrays as inputs. (It wouldn't make sense to have pointers as long as we require knowing their sizes at compile time.)

If we had more uses of memcpy(3), it could certainly be interesting to allow using it with array parameters, or other creatures (e.g., pointers) whose size is only known at run time but whose equality might be known at compile time.

This is a great use case for the compiler_assert() macro:

alx@devuan:~/tmp$ cat mc.c 
#include <string.h>
#include <strings.h>

#define compiler_assert(e)  do                                        \
{                                                                     \
	[[gnu::error("")]] extern void fail_(void);                   \
                                                                      \
	if (!(e))                                                     \
		fail_();                                              \
} while (0)

#define countof(a)   (sizeof(a) / sizeof(*(a)))
#define sizeof_a(a)  (countof(a) * sizeof((a)[0]))
#define bzero_a(a)   bzero(a, sizeof_a(a))

#define memcpy_a(dst, src)                                            \
({                                                                    \
	compiler_assert(sizeof_a(dst) == sizeof_a(src));              \
	                                                              \
	memcpy(dst, src, sizeof_a(dst));                              \
})

void g(char *);

void
f(size_t n)
{
	char a1[n];
	char a2[n];

	bzero_a(a1);

	memcpy_a(a2, a1);

	g(a2);  // To make sure the arrays are used.
}
alx@devuan:~/tmp$ gcc -S -Wall -Wextra mc.c 
mc.c: In functionf’:
mc.c:9:17: error: call tofail_declared with attribute error: 
    9 |                 fail_();                                              \
      |                 ^~~~~~~
mc.c:18:9: note: in expansion of macrocompiler_assert18 |         compiler_assert(sizeof_a(dst) == sizeof_a(src));              \
      |         ^~~~~~~~~~~~~~~
mc.c:33:9: note: in expansion of macromemcpy_a33 |         memcpy_a(a2, a1);
      |         ^~~~~~~~
alx@devuan:~/tmp$ gcc -S -Wall -Wextra -O1 mc.c 
alx@devuan:~/tmp$ 

This macro requires some optimizations to build correctly, as otherwise the equality can't be guaranteed.

We may want to call this macro optimizer_assert() instead...

Cc: @jwakely, @jonnygrant

See also https://github.com/jonnygrant/compile_assert and jonnygrant/compile_assert#1 (comment).

I do like the compile-time validation that the src/dst are required to be identical sizes, though! That's a very tight control.

Thanks!

Hi Alejandro,

It looks good, if the application code calling memcpy_a can see both src and dst, I think the tricky thing is they must be both arrays within scope, I recall sizeof won't work with a malloc pointer.

@alejandro-colomar

alejandro-colomar commented Mar 2, 2026

Copy link
Copy Markdown
Collaborator Author

Hi Alejandro,

Hi Jonathan,

It looks good, if the application code calling memcpy_a can see both src and dst,

Thanks! :)

I think the tricky thing is they must be both arrays within scope, I recall sizeof won't work with a malloc pointer.

That's handled by sizeof_a(), which has magic sauce to make sure the argument is an array.

Signed-off-by: Alejandro Colomar <alx@kernel.org>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

New API Simpler A good issue for a new beginner

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants