Re: [PATCH bpf-next] libbpf: make LIBBPF_OPTS macro strictly a variable declaration
From: Andrii Nakryiko <hidden>
Date: 2019-10-21 17:39:00
Also in:
bpf
On Mon, Oct 21, 2019 at 10:18 AM Toke Høiland-Jørgensen [off-list ref] wrote:
Andrii Nakryiko [off-list ref] writes:quoted
LIBBPF_OPTS is implemented as a mix of field declaration and memset + assignment. This makes it neither variable declaration nor purely statements, which is a problem, because you can't mix it with either other variable declarations nor other function statements, because C90 compiler mode emits warning on mixing all that together. This patch changes LIBBPF_OPTS into a strictly declaration of variable and solves this problem, as can be seen in case of bpftool, which previously would emit compiler warning, if done this way (LIBBPF_OPTS as part of function variables declaration block). Signed-off-by: Andrii Nakryiko <redacted> ---
[...]
quoted
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h index 0fdf086beba7..bf105e9e866f 100644 --- a/tools/lib/bpf/libbpf.h +++ b/tools/lib/bpf/libbpf.h@@ -77,12 +77,13 @@ struct bpf_object_open_attr { * bytes, but that's the best way I've found and it seems to work in practice. */ #define LIBBPF_OPTS(TYPE, NAME, ...) \ - struct TYPE NAME; \ - memset(&NAME, 0, sizeof(struct TYPE)); \ - NAME = (struct TYPE) { \ - .sz = sizeof(struct TYPE), \ - __VA_ARGS__ \ - } + struct TYPE NAME = ({ \ + memset(&NAME, 0, sizeof(struct TYPE)); \ + (struct TYPE) { \ + .sz = sizeof(struct TYPE), \Wait, you can stick arbitrary code inside a variable initialisation block like this? How does that work? Is everything before the (struct type) just ignored (and is that a cast)?
Well, you definitely can still arbitrary code into a ({ }) expression
block, that's not that surprising.
The surprising bit that I discovered just recently was that stuff like
this compiles and works correctly, try it:
void *x = &x;
printf("%lx == %lx\n", x, &x);
So I'm using the fact that variable address is available inside
variable initialization block.
Beyond that, it's just a fancy, but standard (struct bla){ ...
initializer list ...} syntax (it's not a struct initializer syntax,
mind you, it's a struct assignment from struct literal). Fancy for
sure, but it works and solves problems I mentioned in commit
description.
-Toke