On 25.01.2019 23:22, Ben Pfaff wrote:
> This member was write-only: it was initialized and never used later on.
> 
> Thanks to Esteban Rodriguez Betancourt <[email protected]> for the
> following additional rationale:
> 
>     In this case you are right, the "height" member is not only not
>     used, it is in fact not required, and can be safely removed,
>     without causing security issues.
> 
>     The code can't read past the end of the 'forward' array because
>     the skiplist "level" member, that specifies the maximum height of
>     the whole skiplist.
> 
>     The "level" field is updated in insertions and deletions, so that
>     in insertion the root node will point to the newly created item
>     (if there isn't a list there yet). At the deletions, if the
>     deleted item is the last one at that height then the root is
>     modified to point to NULL at that height, and the whole skiplist
>     height is decremented.
> 
>     For the forward_to case:
> 
>     - If a node is found in a list of level/height N, then it has
>       height N (that's why it was inserted in that list)
> 
>     - forward_to travels throught nodes in the same level, so it is
>       safe, as it doesn't go up.
> 
>     - If a node has height N, then it belongs to all the lists
>       initiated at root->forward[n, n-1 ,n-2, ..., 0]
> 
>     - forward_to may go to lower levels, but that is safe, because of
>       previous point.
> 
>     So, the protection is given by the "level" field in skiplist root
>     node, and it is enough to guarantee that the code won't go off
>     limits at 'forward' array. But yes, the height field is unused,
>     unneeded, and can be removed safely.
> 
> CC: Esteban Rodriguez Betancourt <[email protected]>
> Signed-off-by: Ben Pfaff <[email protected]>
> ---

Patch looks correct.
However, maybe we could use this field inside skiplist_delete ?

Here is the part of skiplist_delete function:

191     if (x && list->cmp(x->data, value, list->cfg) == 0) {
192         for (i = 0; i <= list->level; i++) {
193             if (!update[i]->forward[i] ||
194                 list->cmp(update[i]->forward[i]->data, value,
195                           list->cfg) != 0) {
196                 break;
197             }
198             update[i]->forward[i] = x->forward[i];
199         }

On above lines comparator (list->cmp) used to determine if our "x"
exists on current level (i). I think, that we can simply replace this
with checking: if (i > x->height || !update[i]->forward[i]).
We may probably skip the "update[i]->forward[i]" check because it
could not be NULL if we still have "x" on this level.

So, It looks like we could re-write above loop dropping all the checks:

    for (i = 0; i <= x->height; i++) {
        update[i]->forward[i] = x->forward[i];
    }

Any thoughts ?


>  lib/skiplist.c | 2 --
>  1 file changed, 2 deletions(-)
> 
> diff --git a/lib/skiplist.c b/lib/skiplist.c
> index 2cea6d8dfbee..1ae592623099 100644
> --- a/lib/skiplist.c
> +++ b/lib/skiplist.c
> @@ -40,7 +40,6 @@
>  /* Skiplist node container */
>  struct skiplist_node {
>      const void *data;                 /* Pointer to saved data. */
> -    int height;                       /* Height of this node. */
>      struct skiplist_node *forward[];  /* Links to the next nodes. */
>  };
>  
> @@ -66,7 +65,6 @@ skiplist_create_node(int level, const void *object)
>  
>      new_node = xmalloc(alloc_size);
>      new_node->data = object;
> -    new_node->height = level;
>      memset(new_node->forward, 0,
>             (level + 1) * sizeof new_node->forward[0]);
>  
> 
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to