* Unreachable code diagnostic
@ 2017-02-24 18:07 Matthew Wilcox
2017-02-24 18:33 ` Linus Torvalds
` (2 more replies)
0 siblings, 3 replies; 9+ messages in thread
From: Matthew Wilcox @ 2017-02-24 18:07 UTC (permalink / raw)
To: linux-sparse
I was recently sent some code that looked like this:
int foo()
{
lock();
return bar();
unlock();
}
When you're restructuring code that contains locks, this is a
*really* easy mistake to make. I've done it myself. But there's no
compiler warning for it! gcc doesn't have it, sparse doesn't have it.
I've mentioned it to the gcc developers and they don't seem terribly
enthusiastic (they had a -Wunreachable-code at one point, but it
got disabled, probably due to too many false positives like their
-Wmaybe-uninitialized).
Maybe sparse could warn about code after an unconditional return
statement? I wouldn't like to see it warn about code after a conditional
return statement where the condition is always true; I think that would
have a lot of false positives due to macros. For example, something
like this:
int foo()
{
int i = 0;
for (;;) {
if (i == FOO_MAX)
return i;
bar(i++);
}
}
if FOO_MAX happens to be 0 should silently optimise to 'return 0' and
not emit a warning.
I would like to see it warn in this case:
int foo()
{
return bar();
do { } while (0);
}
As that can be generated by the preprocessor in the case of optimising
away locks for the !SMP case, for example.
Any takers for this idea? :-)
^ permalink raw reply [flat|nested] 9+ messages in thread* Re: Unreachable code diagnostic 2017-02-24 18:07 Unreachable code diagnostic Matthew Wilcox @ 2017-02-24 18:33 ` Linus Torvalds 2017-02-24 20:11 ` Luc Van Oostenryck 2017-02-24 18:57 ` Josh Triplett 2017-02-24 19:26 ` Dan Carpenter 2 siblings, 1 reply; 9+ messages in thread From: Linus Torvalds @ 2017-02-24 18:33 UTC (permalink / raw) To: Matthew Wilcox; +Cc: Sparse Mailing-list On Fri, Feb 24, 2017 at 10:07 AM, Matthew Wilcox <willy@infradead.org> wrote: > > Maybe sparse could warn about code after an unconditional return > statement? This is not likely to be a very successful model, I suspect. You already partly see the problem: > I wouldn't like to see it warn about code after a conditional > return statement where the condition is always true; I think that would > have a lot of false positives due to macros. because the thing is, we actually have tons and tons of unreachable code due to things like if (IS_ENABLED(CONFIG_XYZ)) {... which allows us much cleaner code than using things like #ifdef's. So yes, unreachable code in general is actually very common. And it's not just in Linux - think of all the code you've ever seen that has used "ASSERT()", which often ends up doing exactly the same things. Even if you'd think that "when debugging isn't enabled, it just goes away entirely", you often end up having things that basically end up expanding to things like do { if (0) {..} } while (0) inside macros very consciously in order to avoid compiler warnings about unused variables etc when the variable is only used inside that debug statement. I realize that on the face of it, such a "if (0)" sounds insane, but you can seriously just grep for that pattern in Linux: [torvalds@i7 linux]$ git grep 'if (0)' | wc -l 156 now, getting back to your "limit it _only_ to code after an unconditional 'return' statement" suggestion. The reason I don't believe that will be all that useful either, is that a reasonable C compiler (or something like sparse) simply doesn't even see many conditionals. That comes largely from how the C pre-processor is such a separate phase and not actually integrated with the C syntax itself. So if any of the conditionals above end up being done as cpp macros, it's basically pretty much impossible to see them. You'd actually likely be better off with something that doesn't actually really parse the C code, but parses the code _without_ doing preprocessor expansion, and basically look at it without doing the full code analysis. More like what tools like checkpatch etc do - lookign for the superficial patterns, rather than the patterns that you see when you actually expand everything. I'm not disputing that you can always find particular cases where a warning would make sense, I just have a very strong suspicion that you end up having to limit the condition you search for _so_ much that it ends up being basically pointless for anything but the one or two cases you already knew about and that triggered it. Linus ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: Unreachable code diagnostic 2017-02-24 18:33 ` Linus Torvalds @ 2017-02-24 20:11 ` Luc Van Oostenryck 2017-02-24 20:43 ` Josh Triplett 0 siblings, 1 reply; 9+ messages in thread From: Luc Van Oostenryck @ 2017-02-24 20:11 UTC (permalink / raw) To: Linus Torvalds; +Cc: Matthew Wilcox, Sparse Mailing-list On Fri, Feb 24, 2017 at 10:33:37AM -0800, Linus Torvalds wrote: > On Fri, Feb 24, 2017 at 10:07 AM, Matthew Wilcox <willy@infradead.org> wrote: > > > > Maybe sparse could warn about code after an unconditional return > > statement? > > This is not likely to be a very successful model, I suspect. > > You already partly see the problem: > > > I wouldn't like to see it warn about code after a conditional > > return statement where the condition is always true; I think that would > > have a lot of false positives due to macros. > > because the thing is, we actually have tons and tons of unreachable > code due to things like > > if (IS_ENABLED(CONFIG_XYZ)) {... > > which allows us much cleaner code than using things like #ifdef's. > > So yes, unreachable code in general is actually very common. > snip snip > > now, getting back to your "limit it _only_ to code after an > unconditional 'return' statement" suggestion. The reason I don't > believe that will be all that useful either, is that a reasonable C > compiler (or something like sparse) simply doesn't even see many > conditionals. > > That comes largely from how the C pre-processor is such a separate > phase and not actually integrated with the C syntax itself. So if any > of the conditionals above end up being done as cpp macros, it's > basically pretty much impossible to see them. > > You'd actually likely be better off with something that doesn't > actually really parse the C code, but parses the code _without_ doing > preprocessor expansion, and basically look at it without doing the > full code analysis. More like what tools like checkpatch etc do - > lookign for the superficial patterns, rather than the patterns that > you see when you actually expand everything. > > I'm not disputing that you can always find particular cases where a > warning would make sense, I just have a very strong suspicion that you > end up having to limit the condition you search for _so_ much that it > ends up being basically pointless for anything but the one or two > cases you already knew about and that triggered it. > > Linus I'm not very sure what are the cases in wich Matthew is really interested but I suppose that, even after preprocessing and elimination of if (0) {...}, a return statement in the middle of a compound statement is very often unintentional. That should be easy to check. Luc Van Oostenryck ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: Unreachable code diagnostic 2017-02-24 20:11 ` Luc Van Oostenryck @ 2017-02-24 20:43 ` Josh Triplett 2017-02-24 20:47 ` Luc Van Oostenryck 0 siblings, 1 reply; 9+ messages in thread From: Josh Triplett @ 2017-02-24 20:43 UTC (permalink / raw) To: Luc Van Oostenryck; +Cc: Linus Torvalds, Matthew Wilcox, Sparse Mailing-list On Fri, Feb 24, 2017 at 09:11:53PM +0100, Luc Van Oostenryck wrote: > I'm not very sure what are the cases in wich Matthew is really > interested but I suppose that, even after preprocessing and > elimination of if (0) {...}, a return statement in the middle > of a compound statement is very often unintentional. > That should be easy to check. By "middle of a compound statement", you mean an unconditional return followed by more code? Yes, that seems like something reasonable to statically check. - Josh Triplett ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: Unreachable code diagnostic 2017-02-24 20:43 ` Josh Triplett @ 2017-02-24 20:47 ` Luc Van Oostenryck 0 siblings, 0 replies; 9+ messages in thread From: Luc Van Oostenryck @ 2017-02-24 20:47 UTC (permalink / raw) To: Josh Triplett; +Cc: Linus Torvalds, Matthew Wilcox, Sparse Mailing-list On Fri, Feb 24, 2017 at 12:43:56PM -0800, Josh Triplett wrote: > On Fri, Feb 24, 2017 at 09:11:53PM +0100, Luc Van Oostenryck wrote: > > I'm not very sure what are the cases in wich Matthew is really > > interested but I suppose that, even after preprocessing and > > elimination of if (0) {...}, a return statement in the middle > > of a compound statement is very often unintentional. > > That should be easy to check. > > By "middle of a compound statement", you mean an unconditional return > followed by more code? Yes, that seems like something reasonable to > statically check. > > - Josh Triplett Yes, it's what I meant. Luc ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: Unreachable code diagnostic 2017-02-24 18:07 Unreachable code diagnostic Matthew Wilcox 2017-02-24 18:33 ` Linus Torvalds @ 2017-02-24 18:57 ` Josh Triplett 2017-02-24 19:56 ` Luc Van Oostenryck 2017-02-24 21:05 ` Matthew Wilcox 2017-02-24 19:26 ` Dan Carpenter 2 siblings, 2 replies; 9+ messages in thread From: Josh Triplett @ 2017-02-24 18:57 UTC (permalink / raw) To: Matthew Wilcox; +Cc: linux-sparse On Fri, Feb 24, 2017 at 10:07:59AM -0800, Matthew Wilcox wrote: > I was recently sent some code that looked like this: > > int foo() > { > lock(); > return bar(); > unlock(); > } > > When you're restructuring code that contains locks, this is a > *really* easy mistake to make. I've done it myself. But there's no > compiler warning for it! gcc doesn't have it, sparse doesn't have it. Sparse does have a warning (via -Wcontext) for this, if you annotate lock() and unlock() with __acquires(somelock) and __releases(somelock), which expand to __attribute__((context(somelock,0,1))) and __attribute__((context(somelock,0,1))) respectively. You'll get a warning that foo() returns with the lock held. Not at all perfect, but it does have reasonable handling of conditionals, including a way to handle cond_lock(). ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: Unreachable code diagnostic 2017-02-24 18:57 ` Josh Triplett @ 2017-02-24 19:56 ` Luc Van Oostenryck 2017-02-24 21:05 ` Matthew Wilcox 1 sibling, 0 replies; 9+ messages in thread From: Luc Van Oostenryck @ 2017-02-24 19:56 UTC (permalink / raw) To: Josh Triplett; +Cc: Matthew Wilcox, linux-sparse On Fri, Feb 24, 2017 at 10:57:07AM -0800, Josh Triplett wrote: > On Fri, Feb 24, 2017 at 10:07:59AM -0800, Matthew Wilcox wrote: > > I was recently sent some code that looked like this: > > > > int foo() > > { > > lock(); > > return bar(); > > unlock(); > > } > > > > When you're restructuring code that contains locks, this is a > > *really* easy mistake to make. I've done it myself. But there's no > > compiler warning for it! gcc doesn't have it, sparse doesn't have it. > > Sparse does have a warning (via -Wcontext) for this, if you annotate > lock() and unlock() with __acquires(somelock) and __releases(somelock), > which expand to __attribute__((context(somelock,0,1))) and > __attribute__((context(somelock,0,1))) respectively. You'll get a > warning that foo() returns with the lock held. > > Not at all perfect, but it does have reasonable handling of > conditionals, including a way to handle cond_lock(). Absolutely, -Wcontext is even enabled by default. So with what is done in the kernel, you have something like: #define __acquires(x) __attribute__((context(x,0,1))) #define __releases(x) __attribute__((context(x,1,0))) void lock(void) __acquires(lock); void unlock(void) __releases(lock); int bar(void); static int foo(void) { lock(); return bar(); unlock(); } For which sparse returns the following warning: zz.c:9:5: warning: context imbalance in 'foo' - wrong count at exit But of course, that's just for code properly lock/context annotated and I'm not sure if what you're asking, which is much more general, is only motivated by lock/unlock problems or by others problems too. Luc Van Oostenryck ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: Unreachable code diagnostic 2017-02-24 18:57 ` Josh Triplett 2017-02-24 19:56 ` Luc Van Oostenryck @ 2017-02-24 21:05 ` Matthew Wilcox 1 sibling, 0 replies; 9+ messages in thread From: Matthew Wilcox @ 2017-02-24 21:05 UTC (permalink / raw) To: Josh Triplett; +Cc: linux-sparse On Fri, Feb 24, 2017 at 10:57:07AM -0800, Josh Triplett wrote: > On Fri, Feb 24, 2017 at 10:07:59AM -0800, Matthew Wilcox wrote: > > I was recently sent some code that looked like this: > > > > int foo() > > { > > lock(); > > return bar(); > > unlock(); > > } > > > > When you're restructuring code that contains locks, this is a > > *really* easy mistake to make. I've done it myself. But there's no > > compiler warning for it! gcc doesn't have it, sparse doesn't have it. > > Sparse does have a warning (via -Wcontext) for this, if you annotate > lock() and unlock() with __acquires(somelock) and __releases(somelock), > which expand to __attribute__((context(somelock,0,1))) and > __attribute__((context(somelock,0,1))) respectively. You'll get a > warning that foo() returns with the lock held. > > Not at all perfect, but it does have reasonable handling of > conditionals, including a way to handle cond_lock(). Ah, yes, thanks. I didn't actually try to compile the patch I was sent ... I was just bemused that the compiler didn't warn about this "obvious" wrongness. So I wrote a test-case, which of course didn't have any lock annotations. rcu_read_lock()/unlock() are correctly annotated and applying the patch I sent produces a sparse (and not gcc) warning. So I've asked the submitter to run sparse in future. (of course, this means they have to ignore all the *other* pre-existing sparse warnings, but that's not the fault of anyone on this mailing list) ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: Unreachable code diagnostic 2017-02-24 18:07 Unreachable code diagnostic Matthew Wilcox 2017-02-24 18:33 ` Linus Torvalds 2017-02-24 18:57 ` Josh Triplett @ 2017-02-24 19:26 ` Dan Carpenter 2 siblings, 0 replies; 9+ messages in thread From: Dan Carpenter @ 2017-02-24 19:26 UTC (permalink / raw) To: Matthew Wilcox; +Cc: linux-sparse Smatch works pretty well for finding unreachable code. regards, dan carpenter ^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2017-02-24 21:05 UTC | newest] Thread overview: 9+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2017-02-24 18:07 Unreachable code diagnostic Matthew Wilcox 2017-02-24 18:33 ` Linus Torvalds 2017-02-24 20:11 ` Luc Van Oostenryck 2017-02-24 20:43 ` Josh Triplett 2017-02-24 20:47 ` Luc Van Oostenryck 2017-02-24 18:57 ` Josh Triplett 2017-02-24 19:56 ` Luc Van Oostenryck 2017-02-24 21:05 ` Matthew Wilcox 2017-02-24 19:26 ` Dan Carpenter
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).