return (-off - 1) / BPF_REG_SIZE;
 }
 
+static struct bpf_func_state *func(struct bpf_verifier_env *env,
+                                  const struct bpf_reg_state *reg)
+{
+       struct bpf_verifier_state *cur = env->cur_state;
+
+       return cur->frame[reg->frameno];
+}
+
+static bool is_spi_bounds_valid(struct bpf_func_state *state, int spi, int nr_slots)
+{
+       int allocated_slots = state->allocated_stack / BPF_REG_SIZE;
+
+       /* We need to check that slots between [spi - nr_slots + 1, spi] are
+       * within [0, allocated_stack).
+       *
+       * Please note that the spi grows downwards. For example, a dynptr
+       * takes the size of two stack slots; the first slot will be at
+       * spi and the second slot will be at spi - 1.
+       */
+       return spi - nr_slots + 1 >= 0 && spi < allocated_slots;
+}
+
 static int dynptr_get_spi(struct bpf_verifier_env *env, struct bpf_reg_state *reg)
 {
        int off, spi;
                verbose(env, "cannot pass in dynptr at an offset=%d\n", off);
                return -EINVAL;
        }
-       return spi;
-}
-
-static bool is_spi_bounds_valid(struct bpf_func_state *state, int spi, int nr_slots)
-{
-       int allocated_slots = state->allocated_stack / BPF_REG_SIZE;
 
-       /* We need to check that slots between [spi - nr_slots + 1, spi] are
-        * within [0, allocated_stack).
-        *
-        * Please note that the spi grows downwards. For example, a dynptr
-        * takes the size of two stack slots; the first slot will be at
-        * spi and the second slot will be at spi - 1.
-        */
-       return spi - nr_slots + 1 >= 0 && spi < allocated_slots;
-}
-
-static struct bpf_func_state *func(struct bpf_verifier_env *env,
-                                  const struct bpf_reg_state *reg)
-{
-       struct bpf_verifier_state *cur = env->cur_state;
-
-       return cur->frame[reg->frameno];
+       if (!is_spi_bounds_valid(func(env, reg), spi, BPF_DYNPTR_NR_SLOTS))
+               return -ERANGE;
+       return spi;
 }
 
 static const char *kernel_type_name(const struct btf* btf, u32 id)
        if (spi < 0)
                return spi;
 
-       if (!is_spi_bounds_valid(state, spi, BPF_DYNPTR_NR_SLOTS))
-               return -EINVAL;
-
        /* We cannot assume both spi and spi - 1 belong to the same dynptr,
         * hence we need to call destroy_if_dynptr_stack_slot twice for both,
         * to ensure that for the following example:
        if (spi < 0)
                return spi;
 
-       if (!is_spi_bounds_valid(state, spi, BPF_DYNPTR_NR_SLOTS))
-               return -EINVAL;
-
        for (i = 0; i < BPF_REG_SIZE; i++) {
                state->stack[spi].slot_type[i] = STACK_INVALID;
                state->stack[spi - 1].slot_type[i] = STACK_INVALID;
 
 static bool is_dynptr_reg_valid_uninit(struct bpf_verifier_env *env, struct bpf_reg_state *reg)
 {
-       struct bpf_func_state *state = func(env, reg);
        int spi;
 
        if (reg->type == CONST_PTR_TO_DYNPTR)
                return false;
 
        spi = dynptr_get_spi(env, reg);
+       /* For -ERANGE (i.e. spi not falling into allocated stack slots), we
+        * will do check_mem_access to check and update stack bounds later, so
+        * return true for that case.
+        */
        if (spi < 0)
-               return false;
-
-       /* We will do check_mem_access to check and update stack bounds later */
-       if (!is_spi_bounds_valid(state, spi, BPF_DYNPTR_NR_SLOTS))
-               return true;
-
+               return spi == -ERANGE;
        /* We allow overwriting existing unreferenced STACK_DYNPTR slots, see
         * mark_stack_slots_dynptr which calls destroy_if_dynptr_stack_slot to
         * ensure dynptr objects at the slots we are touching are completely
        spi = dynptr_get_spi(env, reg);
        if (spi < 0)
                return false;
-       if (!is_spi_bounds_valid(state, spi, BPF_DYNPTR_NR_SLOTS) ||
-           !state->stack[spi].spilled_ptr.dynptr.first_slot)
+       if (!state->stack[spi].spilled_ptr.dynptr.first_slot)
                return false;
 
        for (i = 0; i < BPF_REG_SIZE; i++) {
        if (reg->type == PTR_TO_STACK) {
                int err = dynptr_get_spi(env, reg);
 
-               if (err < 0)
+               if (err < 0 && err != -ERANGE)
                        return err;
        }
 
                         */
                        if (reg->type == PTR_TO_STACK) {
                                spi = dynptr_get_spi(env, reg);
-                               if (spi < 0)
-                                       return spi;
-                               if (!is_spi_bounds_valid(state, spi, BPF_DYNPTR_NR_SLOTS) ||
-                                   !state->stack[spi].spilled_ptr.ref_obj_id) {
+                               if (spi < 0 || !state->stack[spi].spilled_ptr.ref_obj_id) {
                                        verbose(env, "arg %d is an unacquired reference\n", regno);
                                        return -EINVAL;
                                }