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
[email protected]
http://openvswitch.org/mailman/listinfo/dev