Re: [PATCH] staging: mt7621-eth: Refactor RX ring resource allocation and cleanup

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, May 30, 2018 at 11:16:10AM +1000, NeilBrown wrote:
> "obviously" we would first fix mtk_rx_free_frags() to do the right thing
> if ring->rx_data were NULL.  This is a crucial part of robust error
> handling.
> The very best error handling style is devm_*.  When that is not
> practical, kfree() style, which quietly accepts NULL, is a good second
> best.
> Could it be that the various bugs you have seen could be blamed on
> resource-release function which do not handle NULL well?  When these
> bugs were fixed, were they fixed by fixing the resource-release
> function (which would benefit many) or were they fixed by making the
> code more robust against a poor interface by adding more checking?

It's way way more complicated to review that sort of code.

With multi label style error handling, I can just track the most
recently allocated resource and tell from the goto if it frees what I
expected.

With one label error handling, I have to scroll down to the bottom of
the function.  Then jump to mtk_rx_free_frags().  Then carefully read
through it to see if can handle a partially allocated array.  Then I
have to jump back to the original code and scroll up to see if
ring->rx_data is zeroed memory and where ring->rx_buf_size gets set.

> 
> >
> > Multi label error handling is self documenting so you don't need to jump
> > to the bottom of the function.  You only need to track the most recently
> > allocated resource.
> >
> > 	foo = allocate_foo();
> > 	if (!foo)
> > 		return -ENOMEM;
> >
> > 	bar = allocate_bar();
> > 	if (!bar) {
> > 		ret = -ENOMEM;
> > 		goto err_free_foo;
> > 	}
> 
> I despise this structure because I cannot simply add
> 
>      baz = allocate_baz();
>      if (!baz) {
>      		ret = -ENOMEM;
>                 goto err_???;
>      }
> 
> in the between these two.  I would need to also change the err_free_foo
> to err_free_baz.

In the common case, you only need to update one goto.

	foo = allocate_foo();
	if (!foo)
		return -ENOMEM;

	ret = allocate_new();
	if (ret)
		goto free_foo;

	ret = -ENOMEM;
	bar = allocate_bar();
	if (!bar)
		goto free_new;  <-- changed

Which ever way you write error handling, it always needs to be updated
so this isn't worse than other styles.


> Possibly if the convention was "goto err_baz_failed" it might be
> workable. Then the failure code would get
> 
>    free_baz(baz);
> err_baz_failed:
> 
> added to it.  That would be less despicable, but not as good have
> ensuring that every free_XXX() correctly handled NULL.

When code uses "come from" style label names, the gotos look like this:

	foo = kmalloc();
	if (!foo)
		goto foo_failed;

That's useless, because it doesn't tell what the goto does.  Imagine if
functions were named after the call site.  It's the same concept.  I
have to scroll to the bottom to see what the goto does.

> 
> >
> > This style of error handling is the most maintainable.  For example, I
> > see bugs where people change a function from returning NULL to returning
> > an error pointer but the error handling was relying on that kfree(NULL)
> > is a no-op.  If you only free resources which have been allocated then
> > you avoid that.
> 
> You've just made an excellent case for changing kfree() to something like
> 
>  if (unlikely(ZERO_OR_NULL_PTR(objp) || IS_ERR(objp)))
>  	return;
> 
> I look forward do seeing your patch :-)
> 

I mentioned earlier that in the past few days I had seen four bugs
from one label style error handling.

2 were freeing uninitialized pointers (GCC didn't catch it).
2 were doing kfree(foo->bar); where foo was NULL.
1 was missing a free.

Changing kfree() wouldn't have fixed any of those problems.  One of the
kfree(foo->bar) bugs was actually slightly involved and we're still
figuring out what the right fix is.

The multi label bug was that was a missing free.  It was straight
forward to add a new free to right place.

regards,
dan carpenter
_______________________________________________
devel mailing list
devel@xxxxxxxxxxxxxxxxxxxxxx
http://driverdev.linuxdriverproject.org/mailman/listinfo/driverdev-devel



[Index of Archives]     [Linux Driver Backports]     [DMA Engine]     [Linux GPIO]     [Linux SPI]     [Video for Linux]     [Linux USB Devel]     [Linux Coverity]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux