Thread (7 messages) flat view 7 messages, 5 authors, 2019-10-22

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
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help