Array brace-enclosed initialization


Federico Parola <fede.parola@...>
 

Hello everybody,
in my XDP eBPF program I'm trying to initialize an array with a brace-enclosed list, however my code is rejected by the verifier.
Here is a simple piece of code to replicate the problem:

#include <linux/bpf.h>

#ifndef __section
# define __section(NAME)                  \
   __attribute__((section(NAME), used))
#endif

#ifndef BPF_FUNC
# define BPF_FUNC(NAME, ...)              \
   (*NAME)(__VA_ARGS__) = (void *)BPF_FUNC_##NAME
#endif

#ifndef printk
# define printk(fmt, ...)                                      \
    ({                                                         \
        char ____fmt[] = fmt;                                  \
        trace_printk(____fmt, sizeof(____fmt), ##__VA_ARGS__); \
    })
#endif

static void BPF_FUNC(trace_printk, const char *fmt, int fmt_size, ...);

__section("prog")
int xdp_prog(struct xdp_md *ctx) {
  int i;
  int array[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};

#pragma nounroll
  for (i = 0; i < 10; i++) {
    printk("%d", array[i]);
  }

  return XDP_PASS;
}

char __license[] __section("license") = "GPL"
This is the error reported by the verifier:
0: (b7) r6 = 0
1: (b7) r7 = 25637
2: (b7) r8 = 0
3: (73) *(u8 *)(r10 -2) = r6
last_idx 3 first_idx 0
regs=40 stack=0 before 2: (b7) r8 = 0
regs=40 stack=0 before 1: (b7) r7 = 25637
regs=40 stack=0 before 0: (b7) r6 = 0
4: (6b) *(u16 *)(r10 -4) = r7
5: (18) r1 = 0x0
7: (0f) r1 += r8
8: (61) r3 = *(u32 *)(r1 +0)
R1 invalid mem access 'inv'
processed 8 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0
I tried compiling with clang-6 and clang-9 with optimizaton set to O1 and O2, but I get this error in all cases.
If I initialize the array in another way (e.g. with a loop) the program works correctly.
The eBPF bytecode generated by clang is the following:
	.text
	.file	"test.c"
	.section	prog,"ax",@progbits
	.globl	xdp_prog                # -- Begin function xdp_prog
	.p2align	3
	.type	xdp_prog,@function
xdp_prog:                               # @xdp_prog
# %bb.0:
	r6 = 0
	r7 = 25637
	r8 = 0
LBB0_1:                                 # =>This Inner Loop Header: Depth=1
	*(u8 *)(r10 - 2) = r6
	*(u16 *)(r10 - 4) = r7
	r1 = .L__const.xdp_prog.array ll
	r1 += r8
	r3 = *(u32 *)(r1 + 0)
	r1 = r10
	r1 += -4
	r2 = 3
	call 6
	r8 += 4
	if r8 != 24 goto LBB0_1
# %bb.2:
	r0 = 2
	exit
.Lfunc_end0:
	.size	xdp_prog, .Lfunc_end0-xdp_prog
                                        # -- End function
	.type	.L__const.xdp_prog.array,@object # @__const.xdp_prog.array
	.section	.rodata,"a",@progbits
	.p2align	2
.L__const.xdp_prog.array:
	.long	0                       # 0x0
	.long	1                       # 0x1
	.long	2                       # 0x2
	.long	3                       # 0x3
	.long	4                       # 0x4
	.long	5                       # 0x5
	.long	6                       # 0x6
	.long	7                       # 0x7
	.long	8                       # 0x8
	.long	9                       # 0x9
	.size	.L__const.xdp_prog.array, 40

	.type	.L__const.xdp_prog.____fmt,@object # @__const.xdp_prog.____fmt
	.section	.rodata.str1.1,"aMS",@progbits,1
.L__const.xdp_prog.____fmt:
	.asciz	"%d"
	.size	.L__const.xdp_prog.____fmt, 3

	.type	__license,@object       # @__license
	.section	license,"aw",@progbits
	.globl	__license
__license:
	.asciz	"GPL"
	.size	__license, 4


	.addrsig
	.addrsig_sym xdp_prog
	.addrsig_sym __license
It seems like the array in the stack is not initialized in the code. With some declarations the code works, for example decalring the array in the following way:
int array[10] = {0, 1, 2, 3};
everything works, the generated bytecode is the following:
	.text
	.file	"test.c"
	.section	prog,"ax",@progbits
	.globl	xdp_prog                # -- Begin function xdp_prog
	.p2align	3
	.type	xdp_prog,@function
xdp_prog:                               # @xdp_prog
# %bb.0:
	r1 = 2
	*(u32 *)(r10 - 36) = r1
	r6 = 0
	*(u32 *)(r10 - 8) = r6
	*(u32 *)(r10 - 12) = r6
	*(u32 *)(r10 - 16) = r6
	*(u32 *)(r10 - 20) = r6
	*(u32 *)(r10 - 24) = r6
	*(u32 *)(r10 - 28) = r6
	*(u32 *)(r10 - 4) = r6
	r1 = 3
	*(u32 *)(r10 - 32) = r1
	r1 = 1
	*(u32 *)(r10 - 40) = r1
	*(u8 *)(r10 - 42) = r6
	r7 = 25637
	*(u16 *)(r10 - 44) = r7
	r1 = r10
	r1 += -44
	r2 = 3
	r3 = 1
	call 6
	r8 = 4
LBB0_1:                                 # =>This Inner Loop Header: Depth=1
	r1 = r10
	r1 += -40
	r1 += r8
	r3 = *(u32 *)(r1 + 0)
	*(u8 *)(r10 - 42) = r6
	*(u16 *)(r10 - 44) = r7
	r1 = r10
	r1 += -44
	r2 = 3
	call 6
	r8 += 4
	if r8 != 24 goto LBB0_1
# %bb.2:
	r0 = 2
	exit
.Lfunc_end0:
	.size	xdp_prog, .Lfunc_end0-xdp_prog
                                        # -- End function
	.type	.L__const.xdp_prog.____fmt,@object # @__const.xdp_prog.____fmt
	.section	.rodata.str1.1,"aMS",@progbits,1
.L__const.xdp_prog.____fmt:
	.asciz	"%d"
	.size	.L__const.xdp_prog.____fmt, 3

	.type	__license,@object       # @__license
	.section	license,"aw",@progbits
	.globl	__license
__license:
	.asciz	"GPL"
	.size	__license, 4


	.addrsig
	.addrsig_sym xdp_prog
	.addrsig_sym __license
This time the array is correctly initialized into code.
Is this a clang bug?

Join iovisor-dev@lists.iovisor.org to automatically receive all group messages.