Merge branch 'Fix leaks in libbpf and selftests'

Andrii Nakryiko says:

====================

Fix all the memory leaks reported by ASAN. All but one are just improper
resource clean up in selftests. But one memory leak was discovered in libbpf,
leaving inner map's name leaked.

First patch fixes selftests' Makefile by passing through SAN_CFLAGS to linker.
Without that compiling with SAN_CFLAGS=-fsanitize=address kept failing.

Running selftests under ASAN in BPF CI is the next step, we just need to make
sure all the necessary libraries (libasan and liblsan) are installed on the
host and inside the VM. Would be great to get some help with that, but for now
make sure that test_progs run is clean from leak sanitizer errors.

v3->v4:
  - rebase on latest bpf-next;
v2->v3:
  - fix per-cpu array memory leaks in btf_iter.c selftests (Hengqi);
v1->v2:
  - call bpf_map__destroy() conditionally if map->inner_map is present.
====================

Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
Alexei Starovoitov 2021-11-07 09:14:15 -08:00
commit 5fd79ed9be
9 changed files with 29 additions and 16 deletions

View File

@ -9009,7 +9009,10 @@ int bpf_map__set_inner_map_fd(struct bpf_map *map, int fd)
pr_warn("error: inner_map_fd already specified\n");
return libbpf_err(-EINVAL);
}
zfree(&map->inner_map);
if (map->inner_map) {
bpf_map__destroy(map->inner_map);
zfree(&map->inner_map);
}
map->inner_map_fd = fd;
return 0;
}

View File

@ -24,6 +24,7 @@ SAN_CFLAGS ?=
CFLAGS += -g -O0 -rdynamic -Wall $(GENFLAGS) $(SAN_CFLAGS) \
-I$(CURDIR) -I$(INCLUDE_DIR) -I$(GENDIR) -I$(LIBDIR) \
-I$(TOOLSINCDIR) -I$(APIDIR) -I$(OUTPUT)
LDFLAGS += $(SAN_CFLAGS)
LDLIBS += -lcap -lelf -lz -lrt -lpthread
# Silence some warnings when compiled with clang

View File

@ -251,18 +251,23 @@ const char *btf_type_c_dump(const struct btf *btf)
d = btf_dump__new(btf, NULL, &opts, btf_dump_printf);
if (libbpf_get_error(d)) {
fprintf(stderr, "Failed to create btf_dump instance: %ld\n", libbpf_get_error(d));
return NULL;
goto err_out;
}
for (i = 1; i < btf__type_cnt(btf); i++) {
err = btf_dump__dump_type(d, i);
if (err) {
fprintf(stderr, "Failed to dump type [%d]: %d\n", i, err);
return NULL;
goto err_out;
}
}
btf_dump__free(d);
fflush(buf_file);
fclose(buf_file);
return buf;
err_out:
btf_dump__free(d);
fclose(buf_file);
return NULL;
}

View File

@ -699,14 +699,13 @@ static void test_bpf_percpu_hash_map(void)
char buf[64];
void *val;
val = malloc(8 * bpf_num_possible_cpus());
skel = bpf_iter_bpf_percpu_hash_map__open();
if (CHECK(!skel, "bpf_iter_bpf_percpu_hash_map__open",
"skeleton open failed\n"))
return;
skel->rodata->num_cpus = bpf_num_possible_cpus();
val = malloc(8 * bpf_num_possible_cpus());
err = bpf_iter_bpf_percpu_hash_map__load(skel);
if (CHECK(!skel, "bpf_iter_bpf_percpu_hash_map__load",
@ -770,6 +769,7 @@ free_link:
bpf_link__destroy(link);
out:
bpf_iter_bpf_percpu_hash_map__destroy(skel);
free(val);
}
static void test_bpf_array_map(void)
@ -870,14 +870,13 @@ static void test_bpf_percpu_array_map(void)
void *val;
int len;
val = malloc(8 * bpf_num_possible_cpus());
skel = bpf_iter_bpf_percpu_array_map__open();
if (CHECK(!skel, "bpf_iter_bpf_percpu_array_map__open",
"skeleton open failed\n"))
return;
skel->rodata->num_cpus = bpf_num_possible_cpus();
val = malloc(8 * bpf_num_possible_cpus());
err = bpf_iter_bpf_percpu_array_map__load(skel);
if (CHECK(!skel, "bpf_iter_bpf_percpu_array_map__load",
@ -933,6 +932,7 @@ free_link:
bpf_link__destroy(link);
out:
bpf_iter_bpf_percpu_array_map__destroy(skel);
free(val);
}
/* An iterator program deletes all local storage in a map. */

View File

@ -4046,11 +4046,9 @@ static void *btf_raw_create(const struct btf_header *hdr,
next_str_idx < strs_cnt ? strs_idx[next_str_idx] : NULL;
done:
free(strs_idx);
if (err) {
if (raw_btf)
free(raw_btf);
if (strs_idx)
free(strs_idx);
free(raw_btf);
return NULL;
}
return raw_btf;

View File

@ -814,21 +814,25 @@ static void test_btf_datasec(struct btf *btf, struct btf_dump *d, char *str,
static void test_btf_dump_datasec_data(char *str)
{
struct btf *btf = btf__parse("xdping_kern.o", NULL);
struct btf *btf;
struct btf_dump_opts opts = { .ctx = str };
char license[4] = "GPL";
struct btf_dump *d;
btf = btf__parse("xdping_kern.o", NULL);
if (!ASSERT_OK_PTR(btf, "xdping_kern.o BTF not found"))
return;
d = btf_dump__new(btf, NULL, &opts, btf_dump_snprintf);
if (!ASSERT_OK_PTR(d, "could not create BTF dump"))
return;
goto out;
test_btf_datasec(btf, d, str, "license",
"SEC(\"license\") char[4] _license = (char[4])['G','P','L',];",
license, sizeof(license));
out:
btf_dump__free(d);
btf__free(btf);
}
void test_btf_dump() {

View File

@ -433,7 +433,7 @@ static int setup_type_id_case_local(struct core_reloc_test_case *test)
static int setup_type_id_case_success(struct core_reloc_test_case *test) {
struct core_reloc_type_id_output *exp = (void *)test->output;
struct btf *targ_btf = btf__parse(test->btf_src_file, NULL);
struct btf *targ_btf;
int err;
err = setup_type_id_case_local(test);

View File

@ -204,8 +204,8 @@ static int pass_ack(struct migrate_reuseport_test_case *test_case)
{
int err;
err = bpf_link__detach(test_case->link);
if (!ASSERT_OK(err, "bpf_link__detach"))
err = bpf_link__destroy(test_case->link);
if (!ASSERT_OK(err, "bpf_link__destroy"))
return -1;
test_case->link = NULL;

View File

@ -111,4 +111,6 @@ void test_skb_ctx(void)
"ctx_out_mark",
"skb->mark == %u, expected %d\n",
skb.mark, 10);
bpf_object__close(obj);
}