On Tue, Jan 27, 2015 at 09:22:00AM +0900, Simon Horman wrote:
> Hi Ben, Hi Thomas,
> 
> On Mon, Jan 26, 2015 at 11:19:53AM -0800, Ben Pfaff wrote:
> > On Mon, Jan 26, 2015 at 02:44:07PM +0100, Thomas Graf wrote:
> > > On 01/26/15 at 05:30pm, Simon Horman wrote:
> > > > On Mon, Jan 26, 2015 at 04:40:49PM +0900, Simon Horman wrote:
> > > > > * Although somewhat cure the approach of setting the next field to 
> > > > > NULL
> > > > 
> > > > s/cure/crude/
> > > > 
> > > > >   seems far less dangerous than trying to update the list 
> > > > > infrastructure
> > > > >   to handle this case.
> > > 
> > > list_moved() not handling the list_empty() case is somewhat rude.
> > > Why not just handle that special case and call list_init() in
> > > list_moved() instead? I realize it's currently documented to fail in
> > > list_moved() but I don't see any side effect in handling this properly
> > > because any caller doing so right now would be buggy.
> > 
> > I'd prefer to handle that case in list_moved() but I don't know a safe
> > way to detect it, that is, a way that doesn't try to read from
> > possibly freed memory.
> 
> Likewise.

[...]

> > It's possible if we make list_moved() take the previous location of
> > the list, e.g. something like this (compile-tested only):
> 
> This seems to solve the problem I observed. Or at least the test I included
> in my patch passes.
> 
> However, I'm not sure about the correctness of the use of memory.
> More on that below.
> 
> >  /* Adjusts pointers around 'list' to compensate for 'list' having been 
> > moved
> > - * around in memory (e.g. as a consequence of realloc()).
> > - *
> > - * This always works if 'list' is a member of a list, or if 'list' is the 
> > head
> > - * of a non-empty list.  It fails badly, however, if 'list' is the head of 
> > an
> > - * empty list; just use list_init() in that case. */
> > + * around in memory (e.g. as a consequence of realloc()), with original
> > + * location 'orig'. */
> >  static inline void
> > -list_moved(struct ovs_list *list)
> > +list_moved(struct ovs_list *list, const struct ovs_list *orig)
> >  {
> > -    list->prev->next = list->next->prev = list;
> > +    if (list->next == orig) {
> > +        list_init(list);
> > +    } else {
> > +        list->prev->next = list->next->prev = list;
> > +    }
> >  }

[...]

> >          if (*n_gms >= allocated_gms) {
> > +            struct ofputil_group_mod *new_gms;
> >              size_t i;
> >  
> > -            *gms = x2nrealloc(*gms, &allocated_gms, sizeof **gms);
> > +            new_gms = x2nrealloc(*gms, &allocated_gms, sizeof **gms);
> 
> *gms might have been freed by the realloc() call indirectly made by
> x2nrealloc(). But *gms is accessed below.

Are you sure?  What *gms points to, that is, **gms, is freed, but *gms
should still point to the same location.  list_moved() never
dereferences 'orig', only compares it against list->next.  In a very
language-lawyer way, working with a pointer to freed memory may be
technically "undefined behavior", but I don't know of bad effects in
practice.
_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to