Add memcpy_a(), and use it instead of its pattern - #1308
Add memcpy_a(), and use it instead of its pattern#1308alejandro-colomar wants to merge 2 commits into
Conversation
593fd72 to
33c2c97
Compare
1ac79da to
3dc937d
Compare
ed73982 to
8262a4d
Compare
47529a5 to
21a9f6c
Compare
21a9f6c to
affe3d5
Compare
c606c9d to
1663d8a
Compare
kees
left a comment
There was a problem hiding this comment.
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.
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 function ‘f’:
mc.c:9:17: error: call to ‘fail_’ declared with attribute error:
9 | fail_(); \
| ^~~~~~~
mc.c:18:9: note: in expansion of macro ‘compiler_assert’
18 | compiler_assert(sizeof_a(dst) == sizeof_a(src)); \
| ^~~~~~~~~~~~~~~
mc.c:33:9: note: in expansion of macro ‘memcpy_a’
33 | 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).
Thanks! |
|
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. |
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. |
Hi Jonathan,
Thanks! :)
That's handled by sizeof_a(), which has magic sauce to make sure the argument is an array. |
d3e94c2 to
ba80e28
Compare
Signed-off-by: Alejandro Colomar <alx@kernel.org>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
Cc: @kees, @uecker
Revisions:
v1b
v1c
v1d
v1d
v1e
v2
v2b
v2c
v2d
v2e
v2f
v2g
v2h
v2i
v2j
v2k
v2l
v2m
v2n
v2o
v3
v3b
v4