<div dir="auto">I see no need for docbook style comments for static functions.<div dir="auto">Especially in test only code</div></div><br><div class="gmail_quote gmail_quote_container"><div dir="ltr" class="gmail_attr">On Tue, Dec 16, 2025, 10:21 Marat Khalili <<a href="mailto:marat.khalili@huawei.com">marat.khalili@huawei.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Add tests for some simple cases:<br>
* Program with no instructions;<br>
* Program with only EXIT instruction but no return value set;<br>
* Program with return value set but no EXIT instruction;<br>
* Minimal valid program with return value set and an EXIT instruction.<br>
<br>
Fix found bugs:<br>
* a program with no instructions was accepted;<br>
* a program with no EXIT instruction read outside the buffer.<br>
<br>
Signed-off-by: Marat Khalili <<a href="mailto:marat.khalili@huawei.com" target="_blank" rel="noreferrer">marat.khalili@huawei.com</a>><br>
Acked-by: Konstantin Ananyev <<a href="mailto:konstantin.ananyev@huawei.com" target="_blank" rel="noreferrer">konstantin.ananyev@huawei.com</a>><br>
---<br>
 app/test/test_bpf.c    | 118 +++++++++++++++++++++++++++++++++++++++++<br>
 lib/bpf/bpf_load.c     |   2 +-<br>
 lib/bpf/bpf_validate.c |  20 +++++--<br>
 3 files changed, 135 insertions(+), 5 deletions(-)<br>
<br>
diff --git a/app/test/test_bpf.c b/app/test/test_bpf.c<br>
index b7c94ba1c7..6ecc49efff 100644<br>
--- a/app/test/test_bpf.c<br>
+++ b/app/test/test_bpf.c<br>
@@ -34,6 +34,124 @@ test_bpf(void)<br>
 #include <rte_ip.h><br>
<br>
<br>
+/* Tests of most simple BPF programs (no instructions, one instruction etc.) */<br>
+<br>
+/*<br>
+ * Try to load a simple bpf program from the instructions array.<br>
+ *<br>
+ * When `expected_errno` is zero, expect it to load successfully.<br>
+ * When `expected_errno` is non-zero, expect it to fail with this `rte_errno`.<br>
+ *<br>
+ * @param nb_ins<br>
+ *   Number of instructions in the `ins` array.<br>
+ * @param ins<br>
+ *   BPF instructions array.<br>
+ * @param expected_errno<br>
+ *   Expected result.<br>
+ * @return<br>
+ *   TEST_SUCCESS on success, error code on failure.<br>
+ */<br>
+static int<br>
+bpf_load_test(uint32_t nb_ins, const struct ebpf_insn *ins, int expected_errno)<br>
+{<br>
+       const struct rte_bpf_prm prm = {<br>
+               .ins = ins,<br>
+               .nb_ins = nb_ins,<br>
+               .prog_arg = {<br>
+                       .type = RTE_BPF_ARG_RAW,<br>
+                       .size = sizeof(uint64_t),<br>
+               },<br>
+       };<br>
+<br>
+       struct rte_bpf *const bpf = rte_bpf_load(&prm);<br>
+       const int actual_errno = rte_errno;<br>
+       rte_bpf_destroy(bpf);<br>
+<br>
+       if (expected_errno != 0) {<br>
+               RTE_TEST_ASSERT_EQUAL(bpf, NULL,<br>
+                       "expect rte_bpf_load() == NULL");<br>
+               RTE_TEST_ASSERT_EQUAL(actual_errno, expected_errno,<br>
+                       "expect rte_errno == %d, found %d",<br>
+                       expected_errno, actual_errno);<br>
+       } else<br>
+               RTE_TEST_ASSERT_NOT_EQUAL(bpf, NULL,<br>
+                       "expect rte_bpf_load() != NULL");<br>
+<br>
+       return TEST_SUCCESS;<br>
+}<br>
+<br>
+/*<br>
+ * Try and load completely empty BPF program.<br>
+ * Should fail because there is no EXIT (and also return value is undefined).<br>
+ */<br>
+static int<br>
+test_no_instructions(void)<br>
+{<br>
+       static const struct ebpf_insn ins[] = {};<br>
+       return bpf_load_test(RTE_DIM(ins), ins, EINVAL);<br>
+}<br>
+<br>
+REGISTER_FAST_TEST(bpf_no_instructions_autotest, true, true, test_no_instructions);<br>
+<br>
+/*<br>
+ * Try and load a BPF program comprising single EXIT instruction.<br>
+ * Should fail because the return value is undefined.<br>
+ */<br>
+static int<br>
+test_exit_only(void)<br>
+{<br>
+       static const struct ebpf_insn ins[] = {<br>
+               {<br>
+                       .code = (BPF_JMP | EBPF_EXIT),<br>
+               },<br>
+       };<br>
+       return bpf_load_test(RTE_DIM(ins), ins, EINVAL);<br>
+}<br>
+<br>
+REGISTER_FAST_TEST(bpf_exit_only_autotest, true, true, test_exit_only);<br>
+<br>
+/*<br>
+ * Try and load a BPF program with no EXIT instruction.<br>
+ * Should fail because of this.<br>
+ */<br>
+static int<br>
+test_no_exit(void)<br>
+{<br>
+       static const struct ebpf_insn ins[] = {<br>
+               {<br>
+                       /* Set return value to the program argument. */<br>
+                       .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),<br>
+                       .src_reg = EBPF_REG_1,<br>
+                       .dst_reg = EBPF_REG_0,<br>
+               },<br>
+       };<br>
+       return bpf_load_test(RTE_DIM(ins), ins, EINVAL);<br>
+}<br>
+<br>
+REGISTER_FAST_TEST(bpf_no_exit_autotest, true, true, test_no_exit);<br>
+<br>
+/*<br>
+ * Try and load smallest possible valid BPF program.<br>
+ */<br>
+static int<br>
+test_minimal_working(void)<br>
+{<br>
+       static const struct ebpf_insn ins[] = {<br>
+               {<br>
+                       /* Set return value to the program argument. */<br>
+                       .code = (EBPF_ALU64 | EBPF_MOV | BPF_X),<br>
+                       .src_reg = EBPF_REG_1,<br>
+                       .dst_reg = EBPF_REG_0,<br>
+               },<br>
+               {<br>
+                       .code = (BPF_JMP | EBPF_EXIT),<br>
+               },<br>
+       };<br>
+       return bpf_load_test(RTE_DIM(ins), ins, 0);<br>
+}<br>
+<br>
+REGISTER_FAST_TEST(bpf_minimal_working_autotest, true, true, test_minimal_working);<br>
+<br>
 /*<br>
  * Basic functional tests for librte_bpf.<br>
  * The main procedure - load eBPF program, execute it and<br>
diff --git a/lib/bpf/bpf_load.c b/lib/bpf/bpf_load.c<br>
index 556e613762..6983c026af 100644<br>
--- a/lib/bpf/bpf_load.c<br>
+++ b/lib/bpf/bpf_load.c<br>
@@ -88,7 +88,7 @@ rte_bpf_load(const struct rte_bpf_prm *prm)<br>
        int32_t rc;<br>
        uint32_t i;<br>
<br>
-       if (prm == NULL || prm->ins == NULL ||<br>
+       if (prm == NULL || prm->ins == NULL || prm->nb_ins == 0 ||<br>
                        (prm->nb_xsym != 0 && prm->xsym == NULL)) {<br>
                rte_errno = EINVAL;<br>
                return NULL;<br>
diff --git a/lib/bpf/bpf_validate.c b/lib/bpf/bpf_validate.c<br>
index 4f47d6dc7b..23444b3eaa 100644<br>
--- a/lib/bpf/bpf_validate.c<br>
+++ b/lib/bpf/bpf_validate.c<br>
@@ -1827,7 +1827,7 @@ add_edge(struct bpf_verifier *bvf, struct inst_node *node, uint32_t nidx)<br>
 {<br>
        uint32_t ne;<br>
<br>
-       if (nidx > bvf->prm->nb_ins) {<br>
+       if (nidx >= bvf->prm->nb_ins) {<br>
                RTE_BPF_LOG_LINE(ERR,<br>
                        "%s: program boundary violation at pc: %u, next pc: %u",<br>
                        __func__, get_node_idx(bvf, node), nidx);<br>
@@ -1886,14 +1886,20 @@ get_prev_node(struct bpf_verifier *bvf, struct inst_node *node)<br>
  * Control Flow Graph (CFG).<br>
  * Information collected at this path would be used later<br>
  * to determine is there any loops, and/or unreachable instructions.<br>
+ * PREREQUISITE: there is at least one node.<br>
  */<br>
 static void<br>
 dfs(struct bpf_verifier *bvf)<br>
 {<br>
        struct inst_node *next, *node;<br>
<br>
-       node = bvf->in;<br>
-       while (node != NULL) {<br>
+       RTE_ASSERT(bvf->nb_nodes != 0);<br>
+       /*<br>
+        * Since there is at least one node, node with index 0 always exists;<br>
+        * it is our program entry point.<br>
+        */<br>
+       node = &bvf->in[0];<br>
+       do {<br>
<br>
                if (node->colour == WHITE)<br>
                        set_node_colour(bvf, node, GREY);<br>
@@ -1923,7 +1929,7 @@ dfs(struct bpf_verifier *bvf)<br>
                        }<br>
                } else<br>
                        node = NULL;<br>
-       }<br>
+       } while (node != NULL);<br>
 }<br>
<br>
 /*<br>
@@ -2062,6 +2068,12 @@ validate(struct bpf_verifier *bvf)<br>
        if (rc != 0)<br>
                return rc;<br>
<br>
+       if (bvf->nb_nodes == 0) {<br>
+               RTE_BPF_LOG_LINE(ERR, "%s(%p) the program is empty",<br>
+                       __func__, bvf);<br>
+               return -EINVAL;<br>
+       }<br>
+<br>
        dfs(bvf);<br>
<br>
        RTE_LOG(DEBUG, BPF, "%s(%p) stats:\n"<br>
-- <br>
2.43.0<br>
<br>
</blockquote></div>