kernel.h: Skip single-eval logic on literals in min()/max()
Subsystems (4)
PATCH v3 1/1 kernel.h: Skip single-eval logic on literals in min()/max()
When max() is used in stack array size calculations from literal values (e.g. "char foo[max(sizeof(struct1), sizeof(struct2))]", the compiler thinks this is a dynamic calculation due to the single-eval logic, which is not needed in the literal case. This change removes several accidental stack VLAs from an x86 allmodconfig build:
$ diff -u before.txt after.txt | grep ^- -drivers/input/touchscreen/cyttsp4_core.c:871:2: warning: ISO C90 forbids variable length array ‘ids’ [-Wvla] -fs/btrfs/tree-checker.c:344:4: warning: ISO C90 forbids variable length array ‘namebuf’ [-Wvla] -lib/vsprintf.c:747:2: warning: ISO C90 forbids variable length array ‘sym’ [-Wvla] -net/ipv4/proc.c:403:2: warning: ISO C90 forbids variable length array ‘buff’ [-Wvla] -net/ipv6/proc.c:198:2: warning: ISO C90 forbids variable length array ‘buff’ [-Wvla] -net/ipv6/proc.c:218:2: warning: ISO C90 forbids variable length array ‘buff64’ [-Wvla]
Based on an earlier patch from Josh Poimboeuf.
---
v3:
- drop __builtin_types_compatible_p() (Rasmus, Linus) v2:
- fix copy/paste-o max1_/max2_ (ijc)
- clarify "compile-time" constant in comment (Rasmus)
- clean up formatting on min_t()/max_t()
--- include/linux/kernel.h | 48 ++++++++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 18 deletions(-)
include/linux/kernel.h +30 -18
@@ -787,37 +787,55 @@ static inline void ftrace_dump(enum ftrace_dump_mode oops_dump_mode) { }* strict type-checking.. See the * "unnecessary" pointer comparison. */ -#define __min (t1, t2, min1, min2, x, y) ({ \ +#define __single_eval_min (t1, t2, min1, min2, x, y) ({ \ t1 min1 = (x); \ t2 min2 = (y); \ (void) (&min1 == &min2); \ min1 < min2 ? min1 : min2; }) +/* +* In the case of compile-time constant values, there is no need to do +* the double-evaluation protection, so the raw comparison can be made. +* This allows min()/max() to be used in stack array allocations and +* avoid the compiler thinking it is a dynamic value leading to an +* accidental VLA. +*/ +#define __min (t1, t2, x, y) \ + __builtin_choose_expr(__builtin_constant_p(x) && \ + __builtin_constant_p(y), \ + (t1)(x) < (t2)(y) ? (t1)(x) : (t2)(y), \ + __single_eval_min(t1, t2, \ + __UNIQUE_ID(min1_), \ + __UNIQUE_ID(min2_), \ + x, y)) +/** * min - return minimum of two values of the same or compatible types * @x: first value * @y: second value */ -#define min (x, y) \ - __min(typeof(x), typeof(y), \ - __UNIQUE_ID(min1_), __UNIQUE_ID(min2_), \ - x, y) +#define min (x, y) __min(typeof(x), typeof(y), x, y) -#define __max (t1, t2, max1, max2, x, y) ({ \ +#define __single_eval_max (t1, t2, max1, max2, x, y) ({ \ t1 max1 = (x); \ t2 max2 = (y); \ (void) (&max1 == &max2); \ max1 > max2 ? max1 : max2; }) +#define __max (t1, t2, x, y) \ + __builtin_choose_expr(__builtin_constant_p(x) && \ + __builtin_constant_p(y), \ + (t1)(x) > (t2)(y) ? (t1)(x) : (t2)(y), \ + __single_eval_max(t1, t2, \ + __UNIQUE_ID(max1_), \ + __UNIQUE_ID(max2_), \ + x, y))/** * max - return maximum of two values of the same or compatible types * @x: first value * @y: second value */ -#define max (x, y) \ - __max(typeof(x), typeof(y), \ - __UNIQUE_ID(max1_), __UNIQUE_ID(max2_), \ - x, y) +#define max (x, y) __max(typeof(x), typeof(y), x, y)/** * min3 - return minimum of three values
@@ -869,10 +887,7 @@ static inline void ftrace_dump(enum ftrace_dump_mode oops_dump_mode) { }* @x: first value * @y: second value */ -#define min_t (type, x, y) \ - __min(type, type, \ - __UNIQUE_ID(min1_), __UNIQUE_ID(min2_), \ - x, y) +#define min_t (type, x, y) __min(type, type, x, y)/** * max_t - return maximum of two values, using the specified type
@@ -880,10 +895,7 @@ static inline void ftrace_dump(enum ftrace_dump_mode oops_dump_mode) { }* @x: first value * @y: second value */ -#define max_t (type, x, y) \ - __max(type, type, \ - __UNIQUE_ID(min1_), __UNIQUE_ID(min2_), \ - x, y) +#define max_t (type, x, y) __max(type, type, x, y)/** * clamp_t - return a value clamped to a given range using a given type
Signature · 6 lines
2.7.4 -- Kees Cook Pixel Security
Quoted 5 lines · Kees Cook
When
max()is used in stack array size calculations from literal values (e.g. "char foo[max(sizeof(struct1), sizeof(struct2))]", the compiler thinks this is a dynamic calculation due to the single-eval logic, which is not needed in the literal case. This change removes several accidental stack VLAs from an x86 allmodconfig build:
Ok, looks good.
I just have a couple of questions about applying it.
In particular, if this will help people working on getting rid of VLA's in the short term, I can apply it directly. But if people who are looking at it (anybody else than Kees?) don't much care, then this might be a 4.17 thing or at least "random -mm queue"?
The other unrelated reaction I had to this was that "we're passing those types down very deep, even though nobody _cares_ about them all that much at that deep level".
Honestly, the only case that really cares is the very top level, and the rest could just take the properly cast versions.
For example, "max_t/min_t" really don't care at all, since they - by definition - just take the single specified type.
So I'm wondering if we should just drop the types from __max/__min (and everything they call) entirely, and instead do
#define __check_type(x,y) ((void)((typeof(x)*)1==(typeof(y)*)1))
#define min(x,y) (__check_type(x,y),__min(x,y))
#define max(x,y) (__check_type(x,y),__max(x,y))
#define min_t(t,x,y) __min((t)(x),(t)(y))
#define max_t(t,x,y) __max((t)(x),(t)(y))and then __min/__max and friends are much simpler (and can just assume that the type is already fine, and the casting has been done).
This is technically entirely independent of this VLA cleanup thing, but the "passing the types around unnecessarily" just becomes more obvious when there's now another level of macros, _and_ it's a more complex expression too.
Yes, yes, the __single_eval_xyz() functions still end up wanting the types for the declaration of the new single-evaluation variables, but the 'typeof' pattern is the standard pattern, so
#define __single_eval_max(max1, max2, x, y) ({ \
typeof (x) max1 = (x); \
typeof (y) max2 = (y); \
max1 > max2 ? max1 : max2; })actually looks more natural to me than passing the two types in as arguments to the macro.
(That form also is amenable to things like "__auto_type" etc simplifications).
Side note: do we *really* need the unique variable names? That's what makes those things _really_ illegible. I thgink it's done just for a sparse warning that we should probably ignore. It's off by default anyway exactly because it doesn't work that well due to nested macro expansions like this.
There is very real value to keeping our odd macros legible, I feel. Even when they are complicated by issues like this, it would be good to keep them as simple as possible.
Comments?
Linus
Quoted 7 lines · Linus Torvalds
Quoted 5 lines · Kees Cook
When
max()is used in stack array size calculations from literal values (e.g. "char foo[max(sizeof(struct1), sizeof(struct2))]", the compiler thinks this is a dynamic calculation due to the single-eval logic, which is not needed in the literal case. This change removes several accidental stack VLAs from an x86 allmodconfig build:
Quoted 6 lines
Ok, looks good.
I just have a couple of questions about applying it.
In particular, if this will help people working on getting rid of VLA's in the short term, I can apply it directly.
AFAIK, all the VLAs effected by max() are fixed with this patch. i.e. no other VLA work I'm aware of depends on this (famous last words).
Quoted 1 line
But if people who are looking at it (anybody else than Kees?)
FWIW, I've seen at least 6 other people helping out now with VLA clean up patches. Whee. :)
Quoted 2 lines
don't much care, then this
might be a 4.17 thing or at least "random -mm queue"?
Andrew has this (v2) queued in -mm for 4.17. I didn't view VLA clean up (or this macro change) as urgent by any means.
Quoted 7 lines
#define __single_eval_max(max1, max2, x, y) ({ \ typeof (x) max1 = (x); \ typeof (y) max2 = (y); \ max1 > max2 ? max1 : max2; })actually looks more natural to me than passing the two types in as arguments to the macro.
I (obviously) didn't design this macro originally, but my take on this was that it's safer to keep the type check together with the comparison so that it is never possible for someone to run off and use __single_eval_max() directly and accidentally bypass the type check. While it does look silly from the max_t()/min_t() perspective, it just seems more defensive.
Quoted 1 line
(That form also is amenable to things like "
__auto_type" etc simplifications).
Agreed, I think that's the biggest reason to lift the types. However, since we're still not actually doing anything with the types (i.e. this change doesn't weaken the type checking), I would think it would be orthogonal. While it would be nice to resolve differing types sanely, there doesn't appear to be a driving reason to make this change. The example case of max(5, sizeof(thing)) doesn't currently exist in the code and I don't see how making min()/max() _less_ strict would be generically useful (in fact, it has proven useful to have strict type checking).
Quoted 5 lines
Side note: do we *really* need the unique variable names? That's what makes those things _really_ illegible. I thgink it's done just for a sparse warning that we should probably ignore. It's off by default anyway exactly because it doesn't work that well due to nested macro expansions like this.
That I'm not sure about. I'd be fine to remove them; I left them in place because it seemed quite intentional. :)
Quoted 5 lines
There is very real value to keeping our odd macros legible, I feel. Even when they are complicated by issues like this, it would be good to keep them as simple as possible.
Comments?
I'm open to whatever! I'm just glad this gets to kill a handful of "accidental" stack VLAs. :)
-Kees
Signature · 90 lines
Kees Cook Pixel Security<div class="gmail_extra"><br><div class="gmail_quote">On Fri, Mar 9, 2018 at 1:10 PM, Linus Torvalds <span dir="ltr"><<a href="mailto:[email protected]" target="_blank">[email protected]</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">On Fri, Mar 9, 2018 at 12:05 PM, Kees Cook <<a href="mailto:[email protected]">[email protected]</a>> wrote:<br> > When max() is used in stack array size calculations from literal values<br> > (e.g. "char foo[max(sizeof(struct1), sizeof(struct2))]", the compiler<br> > thinks this is a dynamic calculation due to the single-eval logic, which<br> > is not needed in the literal case. This change removes several accidental<br> > stack VLAs from an x86 allmodconfig build:<br> <br> </span>Ok, looks good.<br> <br> I just have a couple of questions about applying it.<br> <br> In particular, if this will help people working on getting rid of<br> VLA's in the short term, I can apply it directly. But if people who<br> are looking at it (anybody else than Kees?) don't much care, then this<br> might be a 4.17 thing or at least "random -mm queue"?<br> <br> The other unrelated reaction I had to this was that "we're passing<br> those types down very deep, even though nobody _cares_ about them all<br> that much at that deep level".<br> <br> Honestly, the only case that really cares is the very top level, and<br> the rest could just take the properly cast versions.<br> <br> For example, "max_t/min_t" really don't care at all, since they - by<br> definition - just take the single specified type.<br> <br> So I'm wondering if we should just drop the types from __max/__min<br> (and everything they call) entirely, and instead do<br> <br> #define __check_type(x,y) ((void)((typeof(x)*)1==(<wbr>typeof(y)*)1))<br> #define min(x,y) (__check_type(x,y),__min(x,y))<br> #define max(x,y) (__check_type(x,y),__max(x,y))<br> <br> #define min_t(t,x,y) __min((t)(x),(t)(y))<br> #define max_t(t,x,y) __max((t)(x),(t)(y))<br> <br> and then __min/__max and friends are much simpler (and can just assume<br> that the type is already fine, and the casting has been done).<br> <br> This is technically entirely independent of this VLA cleanup thing,<br> but the "passing the types around unnecessarily" just becomes more<br> obvious when there's now another level of macros, _and_ it's a more<br> complex expression too.<br> <br> Yes, yes, the __single_eval_xyz() functions still end up wanting the<br> types for the declaration of the new single-evaluation variables, but<br> the 'typeof' pattern is the standard pattern, so<br> <br> #define __single_eval_max(max1, max2, x, y) ({ \<br> typeof (x) max1 = (x); \<br> typeof (y) max2 = (y); \<br> <span class=""> max1 > max2 ? max1 : max2; })<br> <br> </span>actually looks more natural to me than passing the two types in as<br> arguments to the macro.<br> <br> (That form also is amenable to things like "__auto_type" etc simplifications).<br> <br> Side note: do we *really* need the unique variable names? That's what<br> makes those things _really_ illegible. I thgink it's done just for a<br> sparse warning that we should probably ignore. It's off by default<br> anyway exactly because it doesn't work that well due to nested macro<br> expansions like this.<br> <br> There is very real value to keeping our odd macros legible, I feel.<br> Even when they are complicated by issues like this, it would be good<br> to keep them as simple as possible.<br> <br> Comments?<br> <span class="HOEnZb"><font color="#888888"><br> Linus<br> </font></span></blockquote></div><br><br clear="all"><div><br></div>-- <br><div class="gmail_signature" data-smartmail="gmail_signature">Kees Cook<br>Pixel Security</div> </div>
Quoted 7 lines · Linus Torvalds
Quoted 5 lines · Kees Cook
When
max()is used in stack array size calculations from literal values (e.g. "char foo[max(sizeof(struct1), sizeof(struct2))]", the compiler thinks this is a dynamic calculation due to the single-eval logic, which is not needed in the literal case. This change removes several accidental stack VLAs from an x86 allmodconfig build:
Quoted 8 lines
Ok, looks good.
I just have a couple of questions about applying it.
In particular, if this will help people working on getting rid of VLA's in the short term, I can apply it directly. But if people who are looking at it (anybody else than Kees?) don't much care, then this might be a 4.17 thing or at least "random -mm queue"?
It's easy enough to work on the other VLA removals without basing on this, no rush.
thanks,
Tobin.
The amount of replicated defined could also be reduced by passing > or < to a min_max() macro.
So you start off with something like:
#define min(x, y) __min_max(x, <, y)
#define max(x, y) __min_max(x, >, y)
then have:
#define __min_max(x, cond, y) ((x) cond (y) ? (x) : (y))
in all its associated flavours.
David
Quoted 14 lines · On Fri, 9 Mar 2018 12:05:36 -0800 Kees Cook <[email protected]> wrote:
When
max()is used in stack array size calculations from literal values (e.g. "char foo[max(sizeof(struct1), sizeof(struct2))]", the compiler thinks this is a dynamic calculation due to the single-eval logic, which is not needed in the literal case. This change removes several accidental stack VLAs from an x86 allmodconfig build:$ diff -u before.txt after.txt | grep ^-(quoted diff) +0
-6-drivers/input/touchscreen/cyttsp4_core.c:871:2: warning: ISO C90 forbids variable length array ‘ids’ [-Wvla] -fs/btrfs/tree-checker.c:344:4: warning: ISO C90 forbids variable length array ‘namebuf’ [-Wvla] -lib/vsprintf.c:747:2: warning: ISO C90 forbids variable length array ‘sym’ [-Wvla] -net/ipv4/proc.c:403:2: warning: ISO C90 forbids variable length array ‘buff’ [-Wvla] -net/ipv6/proc.c:198:2: warning: ISO C90 forbids variable length array ‘buff’ [-Wvla] -net/ipv6/proc.c:218:2: warning: ISO C90 forbids variable length array ‘buff64’ [-Wvla]
Quoted 1 line
Based on an earlier patch from Josh Poimboeuf.
v1, v2 and v3 of this patch all fail with gcc-4.4.4:
./include/linux/jiffies.h: In function 'jiffies_delta_to_clock_t':./include/linux/jiffies.h:444: error: first argument to '__builtin_choose_expr' not a constant
That's with
#define __max(t1, t2, x, y) \ __builtin_choose_expr(__builtin_constant_p(x) && \ __builtin_constant_p(y) && \ __builtin_types_compatible_p(t1, t2), \ (t1)(x) > (t2)(y) ? (t1)(x) : (t2)(y), \ __single_eval_max(t1, t2, \ __UNIQUE_ID(max1_), \ __UNIQUE_ID(max2_), \ x, y))
/**
* max - return maximum of two values of the same or compatible types
* @x: first value
* @y: second value
*/
#define max(x, y) __max(typeof(x), typeof(y), x, y)
A brief poke failed to reveal a workaround - gcc-4.4.4 doesn't appear to know that __builtin_constant_p(x) is a constant. Or something.
Sigh. Wasn't there some talk about modernizing our toolchain requirements?
Quoted 3 lines · Andrew Morton
A brief poke failed to reveal a workaround - gcc-4.4.4 doesn't appear to know that
__builtin_constant_p(x)is a constant. Or something.
LOL.
I suspect it might be that it wants to evaluate __builtin_choose_expr() at an earlier stage than it evaluates __builtin_constant_p(), so it's not that it doesn't know that __builtin_constant_p() is a constant, it just might not know it *yet*.
Maybe.
Side note, if it's not that, but just the "complex" expression that has the logical 'and' etc, maybe the code could just use
__builtin_constant_p((x)+(y))
or something.
But yeah:
Quoted 2 lines
Sigh. Wasn't there some talk about modernizing our toolchain requirements?
Maybe it's just time to give up on 4.4. We wanted 4.5 for "asm goto", and once we upgrade to 4.5 I think Arnd said that no distro actually ships it, so we might as well go to 4.6.
So maybe this is just the excuse to finally make that official, if there is no clever workaround any more.
Linus
Quoted 12 lines · On Fri, 9 Mar 2018 16:28:51 -0800 Linus Torvalds…
Quoted 3 lines · Andrew Morton
A brief poke failed to reveal a workaround - gcc-4.4.4 doesn't appear to know that
__builtin_constant_p(x)is a constant. Or something.LOL.
I suspect it might be that it wants to evaluate
__builtin_choose_expr()at an earlier stage than it evaluates__builtin_constant_p(), so it's not that it doesn't know that__builtin_constant_p()is a constant, it just might not know it *yet*.
Quoted 8 lines
Maybe.
Side note, if it's not that, but just the "complex" expression that has the logical 'and' etc, maybe the code could just use
__builtin_constant_p((x)+(y))
or something.
I'll do a bit more poking at it.
Quoted 11 lines
But yeah:
Quoted 2 lines
Sigh. Wasn't there some talk about modernizing our toolchain requirements?
Maybe it's just time to give up on 4.4. We wanted 4.5 for "asm goto", and once we upgrade to 4.5 I think Arnd said that no distro actually ships it, so we might as well go to 4.6.
So maybe this is just the excuse to finally make that official, if there is no clever workaround any more.
I wonder which gcc versions actually accept Kees's addition.
Quoted 2 lines · Andrew Morton
I wonder which gcc versions actually accept Kees's addition.
Note that we already do have this pattern, as seen by:
git grep -2 __builtin_choose_expr | grep -2 __builtin_constant_p
which show drivers/pinctrl/intel/pinctrl-intel.h, so the pattern already exists current kernels and _works_ - it apparently just doesn't work in slightly more complicated cases.
It's one reason why I wondered if simplifying the expression to have just that single __builtin_constant_p() might not end up working..
Linus
Quoted 3 lines · Linus Torvalds
Quoted 2 lines · Andrew Morton
I wonder which gcc versions actually accept Kees's addition.
Ah, my old nemesis, gcc 4.4.4. *sob*
Quoted 7 lines
Note that we already do have this pattern, as seen by:
git grep -2
__builtin_choose_expr| grep -2__builtin_constant_pwhich show
drivers/pinctrl/intel/pinctrl-intel.h, so the pattern already exists current kernels and _works_ - it apparently just doesn't work in slightly more complicated cases.
Fun. Yeah, so all the PIN_GROUP() callers have either a literal or an array name for that argument, so the argument to __builtin_constant_p() isn't complex.
git grep '\bPIN_GROUP\b' | egrep -v '(1|2|3|true|false)\)'
Quoted 2 lines
It's one reason why I wondered if simplifying the expression to have just that single
__builtin_constant_p()might not end up working..
Yeah, it seems like it doesn't bail out as "false" for complex expressions given to __builtin_constant_p().
If no magic solution, then which of these?
- go back to my original "multi-eval max only for constants" macro (meh)
- add gcc version checks around this and similarly for -Wvla in the future (eww)
- raise gcc version (yikes)
-Kees
Signature · 30 lines
Kees Cook Pixel Security<div class="gmail_extra"><br><div class="gmail_quote">On Fri, Mar 9, 2018 at 4:38 PM, Linus Torvalds <span dir="ltr"><<a href="mailto:[email protected]" target="_blank">[email protected]</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">On Fri, Mar 9, 2018 at 4:32 PM, Andrew Morton <<a href="mailto:[email protected]">[email protected]</a>> wrote:<br> ><br> > I wonder which gcc versions actually accept Kees's addition.<br> <br> </span>Note that we already do have this pattern, as seen by:<br> <br> git grep -2 __builtin_choose_expr | grep -2 __builtin_constant_p<br> <br> which show drivers/pinctrl/intel/pinctrl-<wbr>intel.h, so the pattern<br> already exists current kernels and _works_ - it apparently just<br> doesn't work in slightly more complicated cases.<br> <br> It's one reason why I wondered if simplifying the expression to have<br> just that single __builtin_constant_p() might not end up working..<br> <span class="HOEnZb"><font color="#888888"><br> Linus<br> </font></span></blockquote></div><br><br clear="all"><div><br></div>-- <br><div class="gmail_signature" data-smartmail="gmail_signature">Kees Cook<br>Pixel Security</div> </div>
Quoted 4 lines · Kees Cook
--
Kees Cook
Pixel Security<div class="gmail_extra"><br><div class="gmail_quote">On [...]
WTF, gmail just blasted HTML into my explicitly plain-text email?! Apologies...
Signature · 98 lines
Kees Cook Pixel Security<div class="gmail_extra"><br><div class="gmail_quote">On Fri, Mar 9, 2018 at 5:30 PM, Kees Cook <span dir="ltr"><<a href="mailto:[email protected]" target="_blank">[email protected]</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">On Fri, Mar 9, 2018 at 4:38 PM, Linus Torvalds<br> <<a href="mailto:[email protected]">[email protected]</a><wbr>> wrote:<br> > On Fri, Mar 9, 2018 at 4:32 PM, Andrew Morton <<a href="mailto:[email protected]">[email protected]</a>> wrote:<br> >><br> >> I wonder which gcc versions actually accept Kees's addition.<br> <br> </span>Ah, my old nemesis, gcc 4.4.4. *sob*<br> <span class=""><br> > Note that we already do have this pattern, as seen by:<br> ><br> > git grep -2 __builtin_choose_expr | grep -2 __builtin_constant_p<br> ><br> > which show drivers/pinctrl/intel/pinctrl-<wbr>intel.h, so the pattern<br> > already exists current kernels and _works_ - it apparently just<br> > doesn't work in slightly more complicated cases.<br> <br> </span>Fun. Yeah, so all the PIN_GROUP() callers have either a literal or an<br> array name for that argument, so the argument to<br> __builtin_constant_p() isn't complex.<br> <br> git grep '\bPIN_GROUP\b' | egrep -v '(1|2|3|true|false)\)'<br> <span class=""><br> > It's one reason why I wondered if simplifying the expression to have<br> > just that single __builtin_constant_p() might not end up working..<br> <br> </span>Yeah, it seems like it doesn't bail out as "false" for complex<br> expressions given to __builtin_constant_p().<br> <br> If no magic solution, then which of these?<br> <br> - go back to my original "multi-eval max only for constants" macro (meh)<br> - add gcc version checks around this and similarly for -Wvla in the future (eww)<br> - raise gcc version (yikes)<br> <br> -Kees<br> <br> --<br> Kees Cook<br> Pixel Security<div class="gmail_extra"><br><div class="gmail_quote">On<br> Fri, Mar 9, 2018 at 4:38 PM, Linus Torvalds <span dir="ltr">&lt;<a<br> <span class="">href="mailto:<a href="mailto:[email protected]">torvalds@linux-<wbr>foundation.org</a>"<br> target="_blank"><a href="mailto:[email protected]">torvalds@<wbr>linux-foundation.org</a></a>&gt;</<wbr>span><br> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0<br> </span>.8ex;border-left:1px #ccc solid;padding-left:1ex"><span class="">On<br> Fri, Mar 9, 2018 at 4:32 PM, Andrew Morton &lt;<a<br> href="mailto:<a href="mailto:[email protected]">akpm@linux-<wbr>foundation.org</a>"><a href="mailto:[email protected]">akpm@linux-<wbr>foundation.org</a></a>&gt;<br> wrote:<br><br> &gt;<br><br> &gt; I wonder which gcc versions actually accept Kees's addition.<br><br> <br><br> </span>Note that we already do have this pattern, as seen by:<br><br> <br><br> &nbsp; git grep -2&nbsp; __builtin_choose_expr | grep -2<br> __builtin_constant_p<br><br> <br><br> which show drivers/pinctrl/intel/pinctrl-<wbr><wbr>intel.h, so the pattern<br><br> already exists current kernels and _works_ - it apparently just<br><br> doesn't work in slightly more complicated cases.<br><br> <br><br> It's one reason why I wondered if simplifying the expression to have<br><br> just that single __builtin_constant_p() might not end up working..<br><br> <div class="HOEnZb"><div class="h5"><span class="HOEnZb"><font color="#888888"><br><br> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Linus<br><br> </font></span></blockquote></<wbr>div><br><br clear="all"><div><br></div>--<br> <br><div class="gmail_signature" data-smartmail="gmail_<wbr>signature">Kees<br> Cook<br>Pixel Security</div><br> </div><br> </div></div></blockquote></div><br><br clear="all"><div><br></div>-- <br><div class="gmail_signature" data-smartmail="gmail_signature">Kees Cook<br>Pixel Security</div> </div>
Quoted 2 lines · Kees Cook
WTF, gmail just blasted HTML into my explicitly plain-text email?! Apologies...
There's more now in your email, I think maybe it's triggered by your signature file and some gmail web interface bug. Or it just tries to force quote using html.
There's some html email disease inside google, where some parts of the company seems to think that html email is _good_.
The official gmail Android app is a big pain, int hat it doesn't *have* a plain-text mode, even though it knows how to format the plain-text part of the email.
You might want to be on the lookout for some bad drugs at the office. Because the world would thank you if you took them away from the gmail app people.
Linus
Quoted 11 lines · On Fri, 9 Mar 2018 17:30:15 -0800 Kees Cook <[email protected]> wrote:
Quoted 2 lines
It's one reason why I wondered if simplifying the expression to have just that single
__builtin_constant_p()might not end up working..Yeah, it seems like it doesn't bail out as "false" for complex expressions given to
__builtin_constant_p().If no magic solution, then which of these?
- go back to my original "multi-eval max only for constants" macro (meh)
- add gcc version checks around this and similarly for -Wvla in the future (eww)
- raise gcc version (yikes)
Replacing the __builtin_choose_expr() with ?: works of course. What will be the runtime effects?
I tried replacing
__builtin_choose_expr(__builtin_constant_p(x) &&
__builtin_constant_p(y),with
__builtin_choose_expr(__builtin_constant_p(x + y),
but no success.
I'm not sure what else to try to trick gcc into working.
include/linux/kernel.h renamed from include/linux/kernel.h~kernelh-skip-single-eval-logic-on-literals-in-min-max-v3-fix +9 -14
@@ -804,13 +804,10 @@ static inline void ftrace_dump(enum ftra* accidental VLA. */ #define __min (t1, t2, x, y) \ - __builtin_choose_expr(__builtin_constant_p(x) && \ - __builtin_constant_p(y), \ - (t1)(x) < (t2)(y) ? (t1)(x) : (t2)(y), \ - __single_eval_min(t1, t2, \ - __UNIQUE_ID(min1_), \ - __UNIQUE_ID(min2_), \ - x, y)) + ((__builtin_constant_p(x) && __builtin_constant_p(y)) ? \ + ((t1)(x) < (t2)(y) ? (t1)(x) : (t2)(y)) : \ + (__single_eval_min(t1, t2, __UNIQUE_ID(min1_), \ + __UNIQUE_ID(min2_), x, y)))/** * min - return minimum of two values of the same or compatible types
@@ -826,13 +823,11 @@ static inline void ftrace_dump(enum ftra max1 > max2 ? max1 : max2; })#define __max (t1, t2, x, y) \ - __builtin_choose_expr(__builtin_constant_p(x) && \ - __builtin_constant_p(y), \ - (t1)(x) > (t2)(y) ? (t1)(x) : (t2)(y), \ - __single_eval_max(t1, t2, \ - __UNIQUE_ID(max1_), \ - __UNIQUE_ID(max2_), \ - x, y)) + ((__builtin_constant_p(x) && __builtin_constant_p(y)) ? \ + ((t1)(x) > (t2)(y) ? (t1)(x) : (t2)(y)) : \ + (__single_eval_max(t1, t2, __UNIQUE_ID(max1_), \ + __UNIQUE_ID(max2_), x, y))) +/** * max - return maximum of two values of the same or compatible types * @x: first value
_
Quoted 2 lines · Andrew Morton
Replacing the
__builtin_choose_expr()with ?: works of course.
Hmm. That sounds like the right thing to do. We were so myopically staring at the __builtin_choose_expr() problem that we overlooked the obvious solution.
Using __builtin_constant_p() together with a ?: is in fact our common pattern, so that should be fine. The only real reason to use __builtin_choose_expr() is if you want to get the *type* to vary depending on which side you choose, but that's not an issue for min/max.
Quoted 1 line
What will be the runtime effects?
There should be none. Gcc will turn the conditional for the ?: into a constant, and DTRT.
Linus
Quoted 9 lines · Linus Torvalds
Quoted 2 lines · Andrew Morton
Replacing the
__builtin_choose_expr()with ?: works of course.Hmm. That sounds like the right thing to do. We were so myopically staring at the
__builtin_choose_expr()problem that we overlooked the obvious solution.
Quoted 5 lines
Using
__builtin_constant_p()together with a ?: is in fact our common pattern, so that should be fine. The only real reason to use__builtin_choose_expr()is if you want to get the *type* to vary depending on which side you choose, but that's not an issue for min/max.
This doesn't solve it for -Wvla, unfortunately. That was the point of Josh's original suggestion of __builtin_choose_expr().
Try building with KCFLAGS=-Wval and checking net/ipv6/proc.c:
net/ipv6/proc.c: In function ‘snmp6_seq_show_item’:net/ipv6/proc.c:198:2: warning: ISO C90 forbids array ‘buff’ whose size can’t be evaluated [-Wvla]
unsigned long buff[SNMP_MIB_MAX];
^~~~~~~~
-Kees
Signature · 2 lines
Kees Cook Pixel Security
Quoted 20 lines · On Mon, 12 Mar 2018 21:28:57 -0700 Kees Cook <[email protected]> wrote:
Quoted 9 lines · Linus Torvalds
Quoted 2 lines · Andrew Morton
Replacing the
__builtin_choose_expr()with ?: works of course.Hmm. That sounds like the right thing to do. We were so myopically staring at the
__builtin_choose_expr()problem that we overlooked the obvious solution.Quoted 5 lines
Using
__builtin_constant_p()together with a ?: is in fact our common pattern, so that should be fine. The only real reason to use__builtin_choose_expr()is if you want to get the *type* to vary depending on which side you choose, but that's not an issue for min/max.This doesn't solve it for -Wvla, unfortunately. That was the point of Josh's original suggestion of
__builtin_choose_expr().
Quoted 7 lines
Try building with KCFLAGS=-Wval and checking
net/ipv6/proc.c:
net/ipv6/proc.c: In function ‘snmp6_seq_show_item’:net/ipv6/proc.c:198:2: warning: ISO C90 forbids array ‘buff’ whose size can’t be evaluated [-Wvla]
unsigned long buff[SNMP_MIB_MAX];
^~~~~~~~
PITA. Didn't we once have a different way of detecting VLAs? Some post-compilation asm parser, iirc.
I suppose the world wouldn't end if we had a gcc version ifdef in kernel.h. We'll get to remove it in, oh, ten years.
Quoted 30 lines · Andrew Morton
Quoted 20 lines · On Mon, 12 Mar 2018 21:28:57 -0700 Kees Cook <[email protected]> wrote:
Quoted 9 lines · Linus Torvalds
Quoted 2 lines · Andrew Morton
Replacing the
__builtin_choose_expr()with ?: works of course.Hmm. That sounds like the right thing to do. We were so myopically staring at the
__builtin_choose_expr()problem that we overlooked the obvious solution.Quoted 5 lines
Using
__builtin_constant_p()together with a ?: is in fact our common pattern, so that should be fine. The only real reason to use__builtin_choose_expr()is if you want to get the *type* to vary depending on which side you choose, but that's not an issue for min/max.This doesn't solve it for -Wvla, unfortunately. That was the point of Josh's original suggestion of
__builtin_choose_expr().Quoted 7 lines
Try building with KCFLAGS=-Wval and checking
net/ipv6/proc.c:
net/ipv6/proc.c: In function ‘snmp6_seq_show_item’:net/ipv6/proc.c:198:2: warning: ISO C90 forbids array ‘buff’ whose size can’t be evaluated [-Wvla]
unsigned long buff[SNMP_MIB_MAX];
^~~~~~~~
Quoted 5 lines
PITA. Didn't we once have a different way of detecting VLAs? Some post-compilation asm parser, iirc.
I suppose the world wouldn't end if we had a gcc version ifdef in
kernel.h. We'll get to remove it in, oh, ten years.
For fixing only 6 VLAs, we don't need all this effort. When it looked like we could get away with just a "better" max(), sure. ;)
I'll send a "const_max()" which will refuse to work on non-constant-values (so it doesn't get accidentally used on variables that could be exposed to double-evaluation), and will work for stack array declarations (to avoid the overly-sensitive -Wvla checks).
-Kees
Signature · 2 lines
Kees Cook Pixel Security
From: Kees Cook
Quoted 1 line
Sent: 13 March 2018 22:15
...
Quoted 4 lines
I'll send a "
const_max()" which will refuse to work on non-constant-values (so it doesn't get accidentally used on variables that could be exposed to double-evaluation), and will work for stack array declarations (to avoid the overly-sensitive -Wvla checks).
ISTR the definitions were of the form:
char foo[max(sizeof (struct bah), sizeof (struct baz))];
This doesn't generate a 'foo' with the required alignment. It would be much better to use a union.
David
Quoted 16 lines · Andrew Morton
Quoted 14 lines · On Fri, 9 Mar 2018 12:05:36 -0800 Kees Cook <[email protected]> wrote:
When
max()is used in stack array size calculations from literal values (e.g. "char foo[max(sizeof(struct1), sizeof(struct2))]", the compiler thinks this is a dynamic calculation due to the single-eval logic, which is not needed in the literal case. This change removes several accidental stack VLAs from an x86 allmodconfig build:$ diff -u before.txt after.txt | grep ^-(quoted diff) +0
-6-drivers/input/touchscreen/cyttsp4_core.c:871:2: warning: ISO C90 forbids variable length array ‘ids’ [-Wvla] -fs/btrfs/tree-checker.c:344:4: warning: ISO C90 forbids variable length array ‘namebuf’ [-Wvla] -lib/vsprintf.c:747:2: warning: ISO C90 forbids variable length array ‘sym’ [-Wvla] -net/ipv4/proc.c:403:2: warning: ISO C90 forbids variable length array ‘buff’ [-Wvla] -net/ipv6/proc.c:198:2: warning: ISO C90 forbids variable length array ‘buff’ [-Wvla] -net/ipv6/proc.c:218:2: warning: ISO C90 forbids variable length array ‘buff64’ [-Wvla]
Quoted 6 lines
Quoted 1 line
Based on an earlier patch from Josh Poimboeuf.
v1, v2 and v3 of this patch all fail with gcc-4.4.4:
./include/linux/jiffies.h: In function 'jiffies_delta_to_clock_t':./include/linux/jiffies.h:444: error: first argument to '__builtin_choose_expr' not a constant
I'm seeing that problem with
Quoted 1 line
gcc --version
gcc (SUSE Linux) 4.8.5
in mmotm.
Quoted 24 lines
That's with
#define __max(t1, t2, x, y) \ __builtin_choose_expr(__builtin_constant_p(x) && \ __builtin_constant_p(y) && \ __builtin_types_compatible_p(t1, t2), \ (t1)(x) > (t2)(y) ? (t1)(x) : (t2)(y), \ __single_eval_max(t1, t2, \ __UNIQUE_ID(max1_), \ __UNIQUE_ID(max2_), \ x, y))/**
* max - return maximum of two values of the same or compatible types
* @x: first value
* @y: second value
*/
#definemax(x, y)__max(typeof(x), typeof(y), x, y)A brief poke failed to reveal a workaround - gcc-4.4.4 doesn't appear to know that
__builtin_constant_p(x)is a constant. Or something.Sigh. Wasn't there some talk about modernizing our toolchain requirements?
Signature · 1 line
~Randy
Quoted 21 lines · Randy Dunlap
Quoted 20 lines · Andrew Morton
Quoted 14 lines · On Fri, 9 Mar 2018 12:05:36 -0800 Kees Cook <[email protected]> wrote:
When
max()is used in stack array size calculations from literal values (e.g. "char foo[max(sizeof(struct1), sizeof(struct2))]", the compiler thinks this is a dynamic calculation due to the single-eval logic, which is not needed in the literal case. This change removes several accidental stack VLAs from an x86 allmodconfig build:$ diff -u before.txt after.txt | grep ^-(quoted diff) +0
-6-drivers/input/touchscreen/cyttsp4_core.c:871:2: warning: ISO C90 forbids variable length array ‘ids’ [-Wvla] -fs/btrfs/tree-checker.c:344:4: warning: ISO C90 forbids variable length array ‘namebuf’ [-Wvla] -lib/vsprintf.c:747:2: warning: ISO C90 forbids variable length array ‘sym’ [-Wvla] -net/ipv4/proc.c:403:2: warning: ISO C90 forbids variable length array ‘buff’ [-Wvla] -net/ipv6/proc.c:198:2: warning: ISO C90 forbids variable length array ‘buff’ [-Wvla] -net/ipv6/proc.c:218:2: warning: ISO C90 forbids variable length array ‘buff64’ [-Wvla]Quoted 1 line
Based on an earlier patch from Josh Poimboeuf.
v1, v2 and v3 of this patch all fail with gcc-4.4.4:
Quoted 7 lines
Quoted 2 lines
./include/linux/jiffies.h: In function 'jiffies_delta_to_clock_t':./include/linux/jiffies.h:444: error: first argument to '__builtin_choose_expr' not a constantI'm seeing that problem with
Quoted 1 line
gcc --version
gcc (SUSE Linux) 4.8.5
Same here, 4.8.5 fails. gcc 5.4.1 seems to work. I compiled a minimal 5.1.0 and it seems to work as well.
Cheers,
Miguel
Quoted 26 lines · Miguel Ojeda
Quoted 25 lines · Randy Dunlap
Quoted 22 lines · Andrew Morton
Quoted 14 lines · On Fri, 9 Mar 2018 12:05:36 -0800 Kees Cook <[email protected]> wrote:
When
max()is used in stack array size calculations from literal values (e.g. "char foo[max(sizeof(struct1), sizeof(struct2))]", the compiler thinks this is a dynamic calculation due to the single-eval logic, which is not needed in the literal case. This change removes several accidental stack VLAs from an x86 allmodconfig build:$ diff -u before.txt after.txt | grep ^-(quoted diff) +0
-6-drivers/input/touchscreen/cyttsp4_core.c:871:2: warning: ISO C90 forbids variable length array ‘ids’ [-Wvla] -fs/btrfs/tree-checker.c:344:4: warning: ISO C90 forbids variable length array ‘namebuf’ [-Wvla] -lib/vsprintf.c:747:2: warning: ISO C90 forbids variable length array ‘sym’ [-Wvla] -net/ipv4/proc.c:403:2: warning: ISO C90 forbids variable length array ‘buff’ [-Wvla] -net/ipv6/proc.c:198:2: warning: ISO C90 forbids variable length array ‘buff’ [-Wvla] -net/ipv6/proc.c:218:2: warning: ISO C90 forbids variable length array ‘buff64’ [-Wvla]Quoted 1 line
Based on an earlier patch from Josh Poimboeuf.
v1, v2 and v3 of this patch all fail with gcc-4.4.4:
./include/linux/jiffies.h: In function 'jiffies_delta_to_clock_t':./include/linux/jiffies.h:444: error: first argument to '__builtin_choose_expr' not a constant
Quoted 7 lines
Quoted 3 lines
I'm seeing that problem with
Quoted 1 line
gcc --version
gcc (SUSE Linux) 4.8.5
Same here, 4.8.5 fails. gcc 5.4.1 seems to work. I compiled a minimal 5.1.0 and it seems to work as well.
Just compiled 4.9.0 and it seems to work -- so that would be the minimum required.
Sigh...
Some enterprise distros are either already shipping gcc >= 5 or will probably be shipping it soon (e.g. RHEL 8), so how much does it hurt to ask for a newer gcc? Are there many users/companies out there using enterprise distributions' gcc to compile and run the very latest kernels?
Miguel
Quoted 11 lines · Miguel Ojeda
Just compiled 4.9.0 and it seems to work -- so that would be the minimum required.
Sigh...
Some enterprise distros are either already shipping gcc >= 5 or will probably be shipping it soon (e.g. RHEL 8), so how much does it hurt to ask for a newer gcc? Are there many users/companies out there using enterprise distributions' gcc to compile and run the very latest kernels?
I wouldn't mind upping the compiler requirements, and we have other reasons to go to 4.6.
But _this_ particular issue doesn't seem worth it to then go even further. Annoying.
Linus
Quoted 26 lines · Miguel Ojeda
Quoted 25 lines · Randy Dunlap
Quoted 22 lines · Andrew Morton
Quoted 14 lines · On Fri, 9 Mar 2018 12:05:36 -0800 Kees Cook <[email protected]> wrote:
When
max()is used in stack array size calculations from literal values (e.g. "char foo[max(sizeof(struct1), sizeof(struct2))]", the compiler thinks this is a dynamic calculation due to the single-eval logic, which is not needed in the literal case. This change removes several accidental stack VLAs from an x86 allmodconfig build:$ diff -u before.txt after.txt | grep ^-(quoted diff) +0
-6-drivers/input/touchscreen/cyttsp4_core.c:871:2: warning: ISO C90 forbids variable length array ‘ids’ [-Wvla] -fs/btrfs/tree-checker.c:344:4: warning: ISO C90 forbids variable length array ‘namebuf’ [-Wvla] -lib/vsprintf.c:747:2: warning: ISO C90 forbids variable length array ‘sym’ [-Wvla] -net/ipv4/proc.c:403:2: warning: ISO C90 forbids variable length array ‘buff’ [-Wvla] -net/ipv6/proc.c:198:2: warning: ISO C90 forbids variable length array ‘buff’ [-Wvla] -net/ipv6/proc.c:218:2: warning: ISO C90 forbids variable length array ‘buff64’ [-Wvla]Quoted 1 line
Based on an earlier patch from Josh Poimboeuf.
v1, v2 and v3 of this patch all fail with gcc-4.4.4:
./include/linux/jiffies.h: In function 'jiffies_delta_to_clock_t':./include/linux/jiffies.h:444: error: first argument to '__builtin_choose_expr' not a constant
Quoted 6 lines
Quoted 3 lines
I'm seeing that problem with
Quoted 1 line
gcc --version
gcc (SUSE Linux) 4.8.5
Same here, 4.8.5 fails. gcc 5.4.1 seems to work. I compiled a minimal 5.1.0 and it seems to work as well.
And sparse freaks out too:
drivers/net/ethernet/via/via-velocity.c:97:26: sparse: incorrect
type in initializer (different address spaces) @@ expected void
*addr @@ got struct mac_regs [noderef] <avoid *addr @@
drivers/net/ethernet/via/via-velocity.c:97:26: expected void *addr
drivers/net/ethernet/via/via-velocity.c:97:26: got structmac_regs [noderef] <asn:2>*mac_regs
drivers/net/ethernet/via/via-velocity.c:100:49: sparse: incorrect
type in argument 2 (different base types) @@ expected restrictedpci_power_t [usertype] state @@ got _t [usertype] state @@
Alright, I'm giving up on fixing max(). I'll go back to STACK_MAX() or some other name for the simple macro. Bleh.
-Kees
Signature · 2 lines
Kees Cook Pixel Security
Quoted 6 lines · Kees Cook
And sparse freaks out too:
drivers/net/ethernet/via/via-velocity.c:97:26: sparse: incorrect
type in initializer (different address spaces) @@ expected void
*addr @@ got structmac_regs[noderef] <avoid *addr @@
Actually, this seems a valid warning - it's assigning a __iomem pointer to a regular void, and dropping the iomem in the process.
Sparse does *not* like VLA's, so what may be going on is that fixing something VLA-related in your tree just makes sparse (correctly) check something that it had given up on before.
So don't worry about the sparse ones, if they are new. They seem correct.
Linus
Quoted 3 lines · Kees Cook
Alright, I'm giving up on fixing
max(). I'll go back toSTACK_MAX()or some other name for the simple macro. Bleh.
Oh, and I'm starting to see the real problem.
It's not that our current "min/max()" are broiken. It's that "-Wvla" is garbage.
Lookie here:
int array[(1,2)];
results in gcc saying
warning: ISO C90 forbids variable length array ‘array’ [-Wvla]
int array[(1,2)];
^~~and that error message - and the name of the flag - is obviously pure garbage.
What is *actually* going on is that ISO C90 requires an array size to be not a constant value, but a constant *expression*. Those are two different things.
A constant expression has little to do with "compile-time constant". It's a more restricted form of it, and has actual syntax requirements. A comma expression is not a constant expression, for example, which was why I tested this.
So "-Wvla" is garbage, with a misleading name, and a misleading warning string. It has nothing to do with "variable length" and whether the compiler can figure it out at build time, and everything to do with a _syntax_ rule.
Linus
Quoted 30 lines · Linus Torvalds
Quoted 3 lines · Kees Cook
Alright, I'm giving up on fixing
max(). I'll go back toSTACK_MAX()or some other name for the simple macro. Bleh.Oh, and I'm starting to see the real problem.
It's not that our current "min/max()" are broiken. It's that "-Wvla" is garbage.
Lookie here:
int array[(1,2)];results in gcc saying
warning: ISO C90 forbids variable length array ‘array’ [-Wvla] int array[(1,2)]; ^~~and that error message - and the name of the flag - is obviously pure garbage.
What is *actually* going on is that ISO C90 requires an array size to be not a constant value, but a constant *expression*. Those are two different things.
A constant expression has little to do with "compile-time constant". It's a more restricted form of it, and has actual syntax requirements. A comma expression is not a constant expression, for example, which was why I tested this.
Quoted 4 lines
So "-Wvla" is garbage, with a misleading name, and a misleading warning string. It has nothing to do with "variable length" and whether the compiler can figure it out at build time, and everything to do with a _syntax_ rule.
The warning string is basically the same to the one used for C++, i.e.:
int size2 = 2;
constexpr int size3 = 2;
int array1[(2,2)];
int array2[(size2, size2)];
int array3[(size3, size3)];only warns for array2 with:
warning: ISO C++ forbids variable length array 'array2' [-Wvla]
int array2[(size2, size2)];
So the warning is probably implemented to just trigger whenever VLAs are used but the given standard does not allow them, for all languages. The problem is why the ISO C90 frontend is not giving an error for using invalid syntax for array sizes to begin with?
Miguel
Quoted 5 lines · Miguel Ojeda
So the warning is probably implemented to just trigger whenever VLAs are used but the given standard does not allow them, for all languages. The problem is why the ISO C90 frontend is not giving an error for using invalid syntax for array sizes to begin with?
So in *historical* context - when a compiler didn't do variable length arrays at all - the original semantics of C "constant expressions" actually make a ton of sense.
You can basically think of a constant expression as something that can be (historically) handled by the front-end without any real complexity, and no optimization phases - just evaluating a simple parse tree with purely compile-time constants.
So there's a good and perfectly valid reason for why C limits certain expressions to just a very particular subset. It's not just array sizes, it's case statements etc too. And those are very much part of the C standard.
So an error message like
warning: ISO C90 requires array sizes to be constant-expressions
would be technically correct and useful from a portability angle. It tells you when you're doing something non-portable, and should be automatically enabled with "-ansi -pedantic", for example.
So what's misleading is actually the name of the warning and the message, not that it happens. The warning isn't about "variable length", it's literally about the rules for what a "constant-expression" is.
And in C, the expression (2,3) has a constant _value_ (namely 3), but it isn't a constant-expression as specified by the language.
Now, the thing is that once you actually do variable length arrays, those old front-end rules make no sense any more (outside of the "give portability warnings" thing).
Because once you do variable length arrays, you obviously _parse_ everything just fine, and you're doing to evaluate much more complex expressions than some limited constant-expression rule.
And at that point it would make a whole lot more sense to add a *new* warning that basically says "I have to generate code for a variable-sized array", if you actually talk about VLA's.
But that's clearly not what gcc actually did.
So the problem really is that -Wvla doesn't actually warn about VLA's, but about something technically completely different.
And that's why those stupid syntactic issues with min/max matter. It's not whether the end result is a compile-time constant or not, it's about completely different issues, like whether there is a comma-expression in it.
Linus
Quoted 39 lines · Linus Torvalds
So in *historical* context - when a compiler didn't do variable length arrays at all - the original semantics of C "constant expressions" actually make a ton of sense.
You can basically think of a constant expression as something that can be (historically) handled by the front-end without any real complexity, and no optimization phases - just evaluating a simple parse tree with purely compile-time constants.
So there's a good and perfectly valid reason for why C limits certain expressions to just a very particular subset. It's not just array sizes, it's case statements etc too. And those are very much part of the C standard.
So an error message like
warning: ISO C90 requires array sizes to be constant-expressions
would be technically correct and useful from a portability angle. It tells you when you're doing something non-portable, and should be automatically enabled with "-ansi -pedantic", for example.
So what's misleading is actually the name of the warning and the message, not that it happens. The warning isn't about "variable length", it's literally about the rules for what a "constant-expression" is.
And in C, the expression (2,3) has a constant _value_ (namely 3), but it isn't a constant-expression as specified by the language.
Now, the thing is that once you actually do variable length arrays, those old front-end rules make no sense any more (outside of the "give portability warnings" thing).
Because once you do variable length arrays, you obviously _parse_ everything just fine, and you're doing to evaluate much more complex expressions than some limited constant-expression rule.
Quoted 9 lines
And at that point it would make a whole lot more sense to add a *new* warning that basically says "I have to generate code for a variable-sized array", if you actually talk about VLA's.
But that's clearly not what gcc actually did.
So the problem really is that -Wvla doesn't actually warn about VLA's, but about something technically completely different.
I *think* I followed your reasoning. For gcc, -Wvla is the "I have to generate code for a variable-sized array" one; but in this case, the array size is the actual issue that you would have liked to be warned about; since people writing:
int a[(2,3)];
did not really mean to declare a VLA. Therefore, you say warning them about the "warning: ISO C90 requires array sizes to be constant-expressions" (let's call it -Wpedantic-array-sizes) would be more helpful here instead of saying stuff about VLAs.
In my case, I was just expecting gcc to give us both warnings and that's it, instead of trying to be smart and give only the -Wpedantic-array-sizes one (which is the one I was wondering in my previous email about why it was missing). I think it would be clear enough if both warnings are shown are the same time. And it makes sense, since if you write that line in ISO C90 it means there really are 2 things going wrong in the end (fishy syntax while in ISO C90 mode and, due to that, VLA code generated as well), no?
Thanks for taking the time to write about the historical context, by the way!
Miguel
Quoted 6 lines
And that's why those stupid syntactic issues with min/max matter. It's not whether the end result is a compile-time constant or not, it's about completely different issues, like whether there is a comma-expression in it.
Linus
Quoted 16 lines · Linus Torvalds
So an error message like
warning: ISO C90 requires array sizes to be constant-expressions
would be technically correct and useful from a portability angle. It tells you when you're doing something non-portable, and should be automatically enabled with "-ansi -pedantic", for example.
So what's misleading is actually the name of the warning and the message, not that it happens. The warning isn't about "variable length", it's literally about the rules for what a "constant-expression" is.
And in C, the expression (2,3) has a constant _value_ (namely 3), but it isn't a constant-expression as specified by the language.
Quoted 7 lines
Now, the thing is that once you actually do variable length arrays, those old front-end rules make no sense any more (outside of the "give portability warnings" thing).
Because once you do variable length arrays, you obviously _parse_ everything just fine, and you're doing to evaluate much more complex expressions than some limited constant-expression rule.
BTW., while I fully agree with everything you said, it's not entirely correct to claim that if a C compiler can generate VLA code it is necessarily able to parse and evaluate constant array sizes "just fine".
Constant expressions are typically parsed very early on, at the preprocessing stage. They can be used with some preprocessor directives as well, such as '#if' (with some further limitations on their syntax).
If VLA support is implemented in a later stage, and results in heavy-handed code generation that will technically work for constant value expressions as well but results in suboptimal code, then a warning should probably be emitted - and it wouldn't be pedantic.
The existing warning is still very misleading:
warning: ISO C90 forbids variable length array ‘array’ [-Wvla]
... and if my above theory is correct then I think a better warning would be something like:
warning: Array declaration is not a C90 constant expression, resulting in VLA code generation
... and note that in this specific case it's not misleading to talk about VLAs in the warning text, because the array size, even if it's constant value, results in VLA code generation.
I don't know whether GCC has such a limitation, but a quick experiment with GCC 7.2 suggests that a (2,3) array size expression results in a lot more code being generated than with a constant expression.
Thanks,
Ingo
Quoted 8 lines · Ingo Molnar
BTW., while I fully agree with everything you said, it's not entirely correct to claim that if a C compiler can generate VLA code it is necessarily able to parse and evaluate constant array sizes "just fine".
Constant expressions are typically parsed very early on, at the preprocessing stage. They can be used with some preprocessor directives as well, such as '#if' (with some further limitations on their syntax).
Yes. But constant simplification and CSE etc is just a very fundamental part of a compiler, and anybody who actually implements VLA's would have to do it anyway.
So no, a message like
warning: Array declaration is not a C90 constant expression,
resulting in VLA code generation
would be moronic. Only some completely mindless broken shit would do "oh, it's not a parse-time constant, so it will be variable". The two just do not follow AT ALL.
So the message might be about _possibly_ resulting in VLA code generation, but honestly, at that point you should just add the warning when you actually generate the code to do the stack allocation.
Because at that point, you know whether it's variable or not.
And trust me, it won't be variable for things like (2,3), or even for our "max()" thing with other odd builtins. Not unless the compiler doesn't really support VLA at all (maybe some bolted-on crazy thing that just turns a VLA at the front-end time into just an alloca), or the user has explicitly asked to disable some fundamental optimization phase.
Linus
Steven Rostedt
maintainercover tracing: Rewrite the function filter code
Al Viro reviewed the ftrace event filter logic and was horrified. He wrote Tom and I a lengthy private email with a formal proof on how to do it simpler as well as more efficient.
Currently the filter logic creates a binary search tree (with some optimizations), and walks it to get a result.
Say we had the following filter: a && !(!b || c) || d && !e Where each letter is a predicate. A tree would be made to look something like:
||
/ \
&& &&
/ | | \
a !|| d !e
/ \
!b cIf a == 1, b == 1, c == 1, d == 1, e == 0, then all nodes would be walked.
|| -> && -> a -> && -> !|| -> !b -> !|| -> c -> !|| -> && -> || -> && -> d -> && -> !e -> && -> || -> return TRUE!
That's 16 steps across vertices.
Al's method would create a program using an array that denotes the predicate function, when to branch, and a target to branch to if the value is the same as when to branch. Storing the array as:
prog[0] = { a, 0, 2}; // predicate, when_to_branch, target prog[1] = { b, 0, 2};
prog[2] = { c, 0, 4};
prog[3] = { d, 0, 5};
prog[4] = { e, 1, 5};
prog[5] = { NULL, 0, 1}; // TRUE
prog[6] = { NULL, 0, 0}; // FALSE
Where the code to execute the above looks like:
for (i = 0; prog[i].pred; i++) {
struct filter_pred *pred = prog[i].pred;
int match = pred->fn(pred, rec);
if (match == prog[i].when_to_branch)
i = prog[i].target;
}
return prog[i].target;Which translates the above program array into:
n0: if (!a) goto n3;
n1: if (!b) goto n3;
n2: if (!c) goto T;
n3: if (!d) goto F;
n4: if (e) goto F;
T: return TRUE;
F: return FALSE;
And the above example only takes 6 steps to return TRUE.
Special thanks goes out to Al for his patience and his time that he spent in educating us in a proper logical parser.
Two patches were added to do some initial clean up. The last patch implements Al's suggestions. I wrote up a very lengthy comment describing what Al taught us in my own words (hopefully I got it right), and the implementation is similar to what Al showed with a few changes (again, hopefully I got that right too). I tested this with lots of different filters and it looks to be holding up.
Jiri,
This affects perf as well. I ran some tests and I believe I got it woking as it does today.
Steven Rostedt (VMware) (3):
tracing: Combine enum and arrays into single macro in filter code
tracing: Clean up and document pred_funcs_##type creation and use
tracing: Rewrite filter logic to be simpler and faster
----
kernel/trace/trace.h | 15 +- kernel/trace/trace_events_filter.c | 2372 ++++++++++++++++-------------------- 2 files changed, 1083 insertions(+), 1304 deletions(-)
Steven Rostedt
maintainerPATCH 1/3 tracing: Combine enum and arrays into single macro in filter code
From: "Steven Rostedt (VMware)" <[email protected]>
Instead of having a separate enum that is the index into another array, like a string array, make a single macro that combines them into a single list, and then the two can not get out of sync. This makes it easier to add and remove items.
The macro trick is:
#define DOGS \
C( JACK, "Jack Russell") \ C( ITALIAN, "Italian Greyhound") \ C( GERMAN, "German Shepherd")
#undef C
#define C(a, b) a
enum { DOGS };
#undef C
#define C(a, b) b
static char dogs[] = { DOGS };
--- kernel/trace/trace_events_filter.c | 112 ++++++++++++++++--------------------- 1 file changed, 48 insertions(+), 64 deletions(-)
kernel/trace/trace_events_filter.c +48 -64
@@ -33,22 +33,26 @@"# Only events with the given fields will be affected.\n" \ "# If no events are modified, an error message will be displayed here" -enum filter_op_ids -{ -OP_OR , -OP_AND , -OP_GLOB , -OP_NE , -OP_EQ , -OP_LT , -OP_LE , -OP_GT , -OP_GE , -OP_BAND , -OP_NOT , -OP_NONE , - OP_OPEN_PAREN, -}; +#define OPS \ + C( OP_OR, "||", 1 ), \ + C( OP_AND, "&&", 2 ), \ + C( OP_GLOB, "~", 4 ), \ + C( OP_NE, "!=", 4 ), \ + C( OP_EQ, "==", 4 ), \ + C( OP_LT, "<", 5 ), \ + C( OP_LE, "<=", 5 ), \ + C( OP_GT, ">", 5 ), \ + C( OP_GE, ">=", 5 ), \ + C( OP_BAND, "&", 6 ), \ + C( OP_NOT, "!", 6 ), \ + C( OP_NONE, "OP_NONE", 0 ), \ + C( OP_OPEN_PAREN, "(", 0 ), \ + C( OP_MAX, NULL, 0 ) + +#undef C +#define C (a, b, c) a + +enum filter_op_ids {OPS };struct filter_op {int id;
@@ -56,56 +60,36 @@ struct filter_op {int precedence; }; -/* Order must be the same as enum filter_op_ids above */ -static struct filter_op filter_ops[] = { - {OP_OR ,"||" ,1 }, - {OP_AND ,"&&" ,2 }, - {OP_GLOB ,"~" ,4 }, - {OP_NE ,"!=" ,4 }, - {OP_EQ ,"==" ,4 }, - {OP_LT ,"<" ,5 }, - {OP_LE ,"<=" ,5 }, - {OP_GT ,">" ,5 }, - {OP_GE ,">=" ,5 }, - {OP_BAND ,"&" ,6 }, - {OP_NOT ,"!" ,6 }, - {OP_NONE ,"OP_NONE" ,0 }, - {OP_OPEN_PAREN ,"(" ,0 }, -}; +#undef C +#define C (a, b, c) { a, b, c } -enum { -FILT_ERR_NONE , -FILT_ERR_INVALID_OP , -FILT_ERR_UNBALANCED_PAREN , -FILT_ERR_TOO_MANY_OPERANDS , -FILT_ERR_OPERAND_TOO_LONG , -FILT_ERR_FIELD_NOT_FOUND , -FILT_ERR_ILLEGAL_FIELD_OP , -FILT_ERR_ILLEGAL_INTVAL , -FILT_ERR_BAD_SUBSYS_FILTER , -FILT_ERR_TOO_MANY_PREDS , -FILT_ERR_MISSING_FIELD , -FILT_ERR_INVALID_FILTER , -FILT_ERR_IP_FIELD_ONLY , -FILT_ERR_ILLEGAL_NOT_OP , -}; +static struct filter_op filter_ops[] = {OPS }; -static char *err_text[] = { -"No error" , -"Invalid operator" , -"Unbalanced parens" , -"Too many operands" , -"Operand too long" , -"Field not found" , -"Illegal operation for field type" , -"Illegal integer value" , -"Couldn't find or set field in one of a subsystem's events" , -"Too many terms in predicate expression" , -"Missing field name and/or value" , -"Meaningless filter expression" , -"Only 'ip' field is supported for function trace" , -"Illegal use of '!'" , -}; +#define ERRORS \ + C( NONE, "No error"), \ + C( INVALID_OP, "Invalid operator"), \ + C( UNBALANCED_PAREN, "Unbalanced parens"), \ + C( TOO_MANY_OPERANDS, "Too many operands"), \ + C( OPERAND_TOO_LONG, "Operand too long"), \ + C( FIELD_NOT_FOUND, "Field not found"), \ + C( ILLEGAL_FIELD_OP, "Illegal operation for field type"), \ + C( ILLEGAL_INTVAL, "Illegal integer value"), \ + C( BAD_SUBSYS_FILTER, "Couldn't find or set field in one of a subsystem's events"), \ + C( TOO_MANY_PREDS, "Too many terms in predicate expression"), \ + C( MISSING_FIELD, "Missing field name and/or value"), \ + C( INVALID_FILTER, "Meaningless filter expression"), \ + C( IP_FIELD_ONLY, "Only 'ip' field is supported for function trace"), \ + C( ILLEGAL_NOT_OP, "Illegal use of '!'"), + +#undef C +#define C (a, b) FILT_ERR_##a + +enum {ERRORS }; + +#undef C +#define C (a, b) b + +static char *err_text[] = {ERRORS };struct opstack_op {enum filter_op_ids op;
Signature · 1 line
2.15.1
Re: [PATCH 1/3] tracing: Combine enum and arrays into single macro in filter code
Quoted 17 lines · On Fri, 09 Mar 2018 21:34:43 -0500 Steven Rostedt <[email protected]> wrote:
From: "Steven Rostedt (VMware)" <[email protected]>
Instead of having a separate enum that is the index into another array, like a string array, make a single macro that combines them into a single list, and then the two can not get out of sync. This makes it easier to add and remove items.
The macro trick is:
#define DOGS \
C( JACK, "Jack Russell") \ C( ITALIAN, "Italian Greyhound") \ C( GERMAN, "German Shepherd")#undef C
#defineC(a, b)a
Quoted 6 lines
enum { DOGS };
#undef C
#defineC(a, b)bstatic char dogs[] = { DOGS };
Looks good to me, and nice idea :)
Thanks,
Quoted 142 lines
Signed-off-by Steven Rostedt (VMware) <[email protected]>--- kernel/trace/trace_events_filter.c | 112 ++++++++++++++++--------------------- 1 file changed, 48 insertions(+), 64 deletions(-)kernel/trace/trace_events_filter.c +48
-64@@ -33,22 +33,26 @@"# Only events with the given fields will be affected.\n" \ "# If no events are modified, an error message will be displayed here" -enum filter_op_ids -{ -OP_OR , -OP_AND , -OP_GLOB , -OP_NE , -OP_EQ , -OP_LT , -OP_LE , -OP_GT , -OP_GE , -OP_BAND , -OP_NOT , -OP_NONE , - OP_OPEN_PAREN, -}; +#define OPS \ + C( OP_OR, "||", 1 ), \ + C( OP_AND, "&&", 2 ), \ + C( OP_GLOB, "~", 4 ), \ + C( OP_NE, "!=", 4 ), \ + C( OP_EQ, "==", 4 ), \ + C( OP_LT, "<", 5 ), \ + C( OP_LE, "<=", 5 ), \ + C( OP_GT, ">", 5 ), \ + C( OP_GE, ">=", 5 ), \ + C( OP_BAND, "&", 6 ), \ + C( OP_NOT, "!", 6 ), \ + C( OP_NONE, "OP_NONE", 0 ), \ + C( OP_OPEN_PAREN, "(", 0 ), \ + C( OP_MAX, NULL, 0 ) + +#undef C +#define C (a, b, c) a + +enum filter_op_ids {OPS };struct filter_op {int id;@@ -56,56 +60,36 @@ struct filter_op {int precedence; }; -/* Order must be the same as enum filter_op_ids above */ -static struct filter_op filter_ops[] = { - {OP_OR ,"||" ,1 }, - {OP_AND ,"&&" ,2 }, - {OP_GLOB ,"~" ,4 }, - {OP_NE ,"!=" ,4 }, - {OP_EQ ,"==" ,4 }, - {OP_LT ,"<" ,5 }, - {OP_LE ,"<=" ,5 }, - {OP_GT ,">" ,5 }, - {OP_GE ,">=" ,5 }, - {OP_BAND ,"&" ,6 }, - {OP_NOT ,"!" ,6 }, - {OP_NONE ,"OP_NONE" ,0 }, - {OP_OPEN_PAREN ,"(" ,0 }, -}; +#undef C +#define C (a, b, c) { a, b, c } -enum { -FILT_ERR_NONE , -FILT_ERR_INVALID_OP , -FILT_ERR_UNBALANCED_PAREN , -FILT_ERR_TOO_MANY_OPERANDS , -FILT_ERR_OPERAND_TOO_LONG , -FILT_ERR_FIELD_NOT_FOUND , -FILT_ERR_ILLEGAL_FIELD_OP , -FILT_ERR_ILLEGAL_INTVAL , -FILT_ERR_BAD_SUBSYS_FILTER , -FILT_ERR_TOO_MANY_PREDS , -FILT_ERR_MISSING_FIELD , -FILT_ERR_INVALID_FILTER , -FILT_ERR_IP_FIELD_ONLY , -FILT_ERR_ILLEGAL_NOT_OP , -}; +static struct filter_op filter_ops[] = {OPS }; -static char *err_text[] = { -"No error" , -"Invalid operator" , -"Unbalanced parens" , -"Too many operands" , -"Operand too long" , -"Field not found" , -"Illegal operation for field type" , -"Illegal integer value" , -"Couldn't find or set field in one of a subsystem's events" , -"Too many terms in predicate expression" , -"Missing field name and/or value" , -"Meaningless filter expression" , -"Only 'ip' field is supported for function trace" , -"Illegal use of '!'" , -}; +#define ERRORS \ + C( NONE, "No error"), \ + C( INVALID_OP, "Invalid operator"), \ + C( UNBALANCED_PAREN, "Unbalanced parens"), \ + C( TOO_MANY_OPERANDS, "Too many operands"), \ + C( OPERAND_TOO_LONG, "Operand too long"), \ + C( FIELD_NOT_FOUND, "Field not found"), \ + C( ILLEGAL_FIELD_OP, "Illegal operation for field type"), \ + C( ILLEGAL_INTVAL, "Illegal integer value"), \ + C( BAD_SUBSYS_FILTER, "Couldn't find or set field in one of a subsystem's events"), \ + C( TOO_MANY_PREDS, "Too many terms in predicate expression"), \ + C( MISSING_FIELD, "Missing field name and/or value"), \ + C( INVALID_FILTER, "Meaningless filter expression"), \ + C( IP_FIELD_ONLY, "Only 'ip' field is supported for function trace"), \ + C( ILLEGAL_NOT_OP, "Illegal use of '!'"), + +#undef C +#define C (a, b) FILT_ERR_##a + +enum {ERRORS }; + +#undef C +#define C (a, b) b + +static char *err_text[] = {ERRORS };struct opstack_op {enum filter_op_ids op;Signature · 1 line
2.15.1
Signature · 1 line
Masami Hiramatsu <[email protected]>
Steven Rostedt
maintainerPATCH 2/3 tracing: Clean up and document pred_funcs_##type creation and use
In reply to Steven RostedtFrom: "Steven Rostedt (VMware)" <[email protected]>
The pred_funcs_##type arrays consist of five functions that are assigned based on the ops. The array must be in the same order of the ops each function represents. The PRED_FUNC_START macro denotes the op enum that starts the op that maps to the pred_funcs_##type arrays. This is all very subtle and prone to bugs if the code is changed.
Add comments describing how PRED_FUNC_START and pred_funcs_##type array is used, and also a PRED_FUNC_MAX that is the maximum number of functions in the arrays.
Clean up select_comparison_fn() that assigns the predicates to the pred_funcs_##type array function as well as add protection in case an op is passed in that does not map correctly to the array.
--- kernel/trace/trace_events_filter.c | 46 ++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 14 deletions(-)
kernel/trace/trace_events_filter.c +32 -14
@@ -65,6 +65,13 @@ struct filter_op {static struct filter_op filter_ops[] = {OPS }; +/* +* pred functions are OP_LT, OP_LE, OP_GT, OP_GE, and OP_BAND +* pred_funcs_##type below must match the order of them above. +*/ +#define PRED_FUNC_START OP_LT +#define PRED_FUNC_MAX (OP_BAND - PRED_FUNC_START) +#define ERRORS \ C( NONE, "No error"), \ C( INVALID_OP, "Invalid operator"), \
@@ -172,8 +179,6 @@ static const filter_pred_fn_t pred_funcs_##type[] = { \ filter_pred_BAND_##type, \ }; -#define PRED_FUNC_START OP_LT -#define DEFINE_EQUALITY_PRED (size) \ static int filter_pred_##size(struct filter_pred *pred, void *event) \ { \
@@ -946,39 +951,52 @@ static filter_pred_fn_t select_comparison_fn(enum filter_op_ids op, int field_size, int field_is_signed) {filter_pred_fn_t fn =NULL ; +int pred_func_index =-1 ; + +switch (op) { +case OP_EQ : +case OP_NE : +break ; +default : +if (WARN_ON_ONCE (op <PRED_FUNC_START )) +return NULL ; + pred_func_index = op -PRED_FUNC_START ; +if (WARN_ON_ONCE (pred_func_index >PRED_FUNC_MAX )) +return NULL ; + }switch (field_size) {case 8 : -if (op ==OP_EQ || op ==OP_NE ) +if (pred_func_index <0 ) fn = filter_pred_64;else if (field_is_signed) - fn = pred_funcs_s64[op -PRED_FUNC_START ]; + fn = pred_funcs_s64[pred_func_index];else - fn = pred_funcs_u64[op -PRED_FUNC_START ]; + fn = pred_funcs_u64[pred_func_index];break ;case 4 : -if (op ==OP_EQ || op ==OP_NE ) +if (pred_func_index <0 ) fn = filter_pred_32;else if (field_is_signed) - fn = pred_funcs_s32[op -PRED_FUNC_START ]; + fn = pred_funcs_s32[pred_func_index];else - fn = pred_funcs_u32[op -PRED_FUNC_START ]; + fn = pred_funcs_u32[pred_func_index];break ;case 2 : -if (op ==OP_EQ || op ==OP_NE ) +if (pred_func_index <0 ) fn = filter_pred_16;else if (field_is_signed) - fn = pred_funcs_s16[op -PRED_FUNC_START ]; + fn = pred_funcs_s16[pred_func_index];else - fn = pred_funcs_u16[op -PRED_FUNC_START ]; + fn = pred_funcs_u16[pred_func_index];break ;case 1 : -if (op ==OP_EQ || op ==OP_NE ) +if (pred_func_index <0 ) fn = filter_pred_8;else if (field_is_signed) - fn = pred_funcs_s8[op -PRED_FUNC_START ]; + fn = pred_funcs_s8[pred_func_index];else - fn = pred_funcs_u8[op -PRED_FUNC_START ]; + fn = pred_funcs_u8[pred_func_index];break ; }
Signature · 1 line
2.15.1
Re: [PATCH 2/3] tracing: Clean up and document pred_funcs_##type creation and use
Quoted 8 lines · On Fri, 09 Mar 2018 21:34:44 -0500 Steven Rostedt <[email protected]> wrote:
From: "Steven Rostedt (VMware)" <[email protected]>
The pred_funcs_##type arrays consist of five functions that are assigned based on the ops. The array must be in the same order of the ops each function represents. The
PRED_FUNC_STARTmacro denotes the op enum that starts the op that maps to the pred_funcs_##type arrays. This is all very subtle and prone to bugs if the code is changed.
Quoted 8 lines
Add comments describing how
PRED_FUNC_STARTand pred_funcs_##type array is used, and also aPRED_FUNC_MAXthat is the maximum number of functions in the arrays.Clean up
select_comparison_fn()that assigns the predicates to the pred_funcs_##type array function as well as add protection in case an op is passed in that does not map correctly to the array.
This looks good to me.
Thanks,
Quoted 101 lines
Signed-off-by Steven Rostedt (VMware) <[email protected]>--- kernel/trace/trace_events_filter.c | 46 ++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 14 deletions(-)kernel/trace/trace_events_filter.c +32
-14@@ -65,6 +65,13 @@ struct filter_op {static struct filter_op filter_ops[] = {OPS }; +/* +* pred functions are OP_LT, OP_LE, OP_GT, OP_GE, and OP_BAND +* pred_funcs_##type below must match the order of them above. +*/ +#define PRED_FUNC_START OP_LT +#define PRED_FUNC_MAX (OP_BAND - PRED_FUNC_START) +#define ERRORS \ C( NONE, "No error"), \ C( INVALID_OP, "Invalid operator"), \@@ -172,8 +179,6 @@ static const filter_pred_fn_t pred_funcs_##type[] = { \ filter_pred_BAND_##type, \ }; -#define PRED_FUNC_START OP_LT -#define DEFINE_EQUALITY_PRED (size) \ static int filter_pred_##size(struct filter_pred *pred, void *event) \ { \@@ -946,39 +951,52 @@ static filter_pred_fn_t select_comparison_fn(enum filter_op_ids op, int field_size, int field_is_signed) {filter_pred_fn_t fn =NULL ; +int pred_func_index =-1 ; + +switch (op) { +case OP_EQ : +case OP_NE : +break ; +default : +if (WARN_ON_ONCE (op <PRED_FUNC_START )) +return NULL ; + pred_func_index = op -PRED_FUNC_START ; +if (WARN_ON_ONCE (pred_func_index >PRED_FUNC_MAX )) +return NULL ; + }switch (field_size) {case 8 : -if (op ==OP_EQ || op ==OP_NE ) +if (pred_func_index <0 ) fn = filter_pred_64;else if (field_is_signed) - fn = pred_funcs_s64[op -PRED_FUNC_START ]; + fn = pred_funcs_s64[pred_func_index];else - fn = pred_funcs_u64[op -PRED_FUNC_START ]; + fn = pred_funcs_u64[pred_func_index];break ;case 4 : -if (op ==OP_EQ || op ==OP_NE ) +if (pred_func_index <0 ) fn = filter_pred_32;else if (field_is_signed) - fn = pred_funcs_s32[op -PRED_FUNC_START ]; + fn = pred_funcs_s32[pred_func_index];else - fn = pred_funcs_u32[op -PRED_FUNC_START ]; + fn = pred_funcs_u32[pred_func_index];break ;case 2 : -if (op ==OP_EQ || op ==OP_NE ) +if (pred_func_index <0 ) fn = filter_pred_16;else if (field_is_signed) - fn = pred_funcs_s16[op -PRED_FUNC_START ]; + fn = pred_funcs_s16[pred_func_index];else - fn = pred_funcs_u16[op -PRED_FUNC_START ]; + fn = pred_funcs_u16[pred_func_index];break ;case 1 : -if (op ==OP_EQ || op ==OP_NE ) +if (pred_func_index <0 ) fn = filter_pred_8;else if (field_is_signed) - fn = pred_funcs_s8[op -PRED_FUNC_START ]; + fn = pred_funcs_s8[pred_func_index];else - fn = pred_funcs_u8[op -PRED_FUNC_START ]; + fn = pred_funcs_u8[pred_func_index];break ; }Signature · 1 line
2.15.1
Signature · 1 line
Masami Hiramatsu <[email protected]>
Steven Rostedt
maintainerPATCH 3/3 tracing: Rewrite filter logic to be simpler and faster
In reply to Steven RostedtFrom: "Steven Rostedt (VMware)" <[email protected]>
Al Viro reviewed the filter logic of ftrace trace events and found it to be very troubling. It creates a binary tree based on the logic operators and walks it during tracing. He sent myself and Tom Zanussi a long explanation (and formal proof) of how to do the string parsing better and end up with a program array that can be simply iterated to come up with the correct results.
I took his ideas and his pseudo code and rewrote the filter logic based on them. In doing so, I was able to remove a lot of code, and have a much more condensed filter logic in the process. I wrote a very long comment describing the methadology that Al proposed in my own words. For more info on how this works, read the comment above predicate_parse().
--- kernel/trace/trace.h | 15 +- kernel/trace/trace_events_filter.c | 2308 ++++++++++++++++-------------------- 2 files changed, 1050 insertions(+), 1273 deletions(-)
kernel/trace/trace.h +5 -10
@@ -1216,12 +1216,11 @@ struct ftrace_event_field {int is_signed; }; +struct prog_entry ; +struct event_filter { -int n_preds;/* Number assigned */ -int a_preds;/* allocated */ -struct filter_pred __rcu *preds; -struct filter_pred __rcu *root; -char *filter_string; +struct prog_entry *prog; +char *filter_string; };struct event_subsystem {
@@ -1413,12 +1412,8 @@ struct filter_pred {unsigned short *ops;struct ftrace_event_field *field;int offset; -int not; +int not;int op; -unsigned short index; -unsigned short parent; -unsigned short left; -unsigned short right; };static inline bool is_string_field (struct ftrace_event_field *field)
kernel/trace/trace_events_filter.c +1045 -1263
2,689 lines not on this page · raw message
Signature · 1 line
2.15.1
Steven Rostedt
maintainerRe: [PATCH 3/3] tracing: Rewrite filter logic to be simpler and faster
Quoted 1 line · On Fri, 09 Mar 2018 21:34:45 -0500 Steven Rostedt <[email protected]> wrote:
2 files changed, 1050 insertions(+), 1273 deletions(-)
BTW, it's a bit bigger impact than 223 deletions. As I added a lot of comments to explain the logic better. Removing comments and white space from the modifications we have:
649 insertions(+), 1035 deletions(-)
That's 386 lines of code removed.
-- Steve
Steven Rostedt
maintainerRe: [PATCH 3/3] tracing: Rewrite filter logic to be simpler and faster
I don't know what the hell happened, but claws mail just inserted a ton of people into the Cc (I didn't add you). I noticed it just after I hit send. The added Cc looks like it came from the email right after the email I was replying to "Subject: Re: [PATCH v3] kernel.h: Skip single-eval logic on literals in min()/max()".
Sorry for the spam.
-- Steve
Quoted 9 lines · On Fri, 9 Mar 2018 22:10:19 -0500 Steven Rostedt <[email protected]> wrote:
Quoted 1 line · On Fri, 09 Mar 2018 21:34:45 -0500 Steven Rostedt <[email protected]> wrote:
2 files changed, 1050 insertions(+), 1273 deletions(-)BTW, it's a bit bigger impact than 223 deletions. As I added a lot of comments to explain the logic better. Removing comments and white space from the modifications we have:
Quoted 5 lines
649 insertions(+), 1035 deletions(-)
That's 386 lines of code removed.
-- Steve
'
Steven Rostedt
maintainerRe: [PATCH 3/3] tracing: Rewrite filter logic to be simpler and faster
Quoted 1 line · On Fri, 9 Mar 2018 22:15:23 -0500 Steven Rostedt <[email protected]> wrote:
Sorry for the spam.
A little more spam ;-)
I know what happened, as I'm able to recreate it. For those that use claws-mail, be careful.
I clicked on the email I wanted to reply to. Then I must have hit the down arrow key, as it moved the selected email to the next email. I hit "Reply All", and it showed the email I clicked on (as well as the subject), but the Cc list belonged to the email that was selected by the down arrow key.
That's a nasty subtle bug. I think I'll go report this to the claws folks.
-- Steve
Steven Rostedt
maintainerRe: [PATCH 3/3] tracing: Rewrite filter logic to be simpler and faster
In reply to Steven Rostedt[ This time replying to the email I expected to ]
Quoted 1 line · On Fri, 09 Mar 2018 21:34:45 -0500 Steven Rostedt <[email protected]> wrote:
2 files changed, 1050 insertions(+), 1273 deletions(-)
BTW, it's a bit bigger impact than 223 deletions. As I added a lot of comments to explain the logic better. Removing comments and white space from the modifications we have:
649 insertions(+), 1035 deletions(-)
That's 386 lines of code removed.
-- Steve
Re: [PATCH 3/3] tracing: Rewrite filter logic to be simpler and faster
In reply to Steven RostedtOn Fri, Mar 09, 2018 at 09:34:45PM -0500, Steven Rostedt wrote:
SNIP
kernel/trace/trace_events_filter.c enum { ERRORS }; · line 168
Quoted 11 lines
kernel/trace/trace_events_filter.c +9
-1-/* If not of not match is equal to not of not, then it is a match */ +/* +* Without going into a formal proof, this explains the method that is used in +* parsing the logical expressions. +* +* For example, if we have: "a && !(!b || (c && g)) || d || e && !f" +* The first pass will convert it into the following program: +* +* n1: r=a; l1: if (!r) goto l4; +* n2: r=b; l2: if (!r) goto l4;
got stuck in here.. should that be 'goto l5' ?
jirka
Quoted 7 lines
+ * n3: r=c; r=!r; l3: if (r) goto l4;
+ * n4: r=g; r=!r; l4: if (r) goto l5;
+ * n5: r=d; l5: if (r) goto T
+ * n6: r=e; l6: if (!r) goto l7;
+ * n7: r=f; r=!r; l7: if (!r) goto F
+ * T: return TRUE
+ * F: return FALSE
jirka
Steven Rostedt
maintainerRe: [PATCH 3/3] tracing: Rewrite filter logic to be simpler and faster
Quoted 5 lines · On Mon, 12 Mar 2018 13:42:46 +0100 Jiri Olsa <[email protected]> wrote:
On Fri, Mar 09, 2018 at 09:34:45PM -0500, Steven Rostedt wrote:
SNIP
Quoted 1 line
Quoted 12 lines
kernel/trace/trace_events_filter.c enum { ERRORS }; · line 168
Quoted 10 lines
kernel/trace/trace_events_filter.c +9
-1-/* If not of not match is equal to not of not, then it is a match */ +/* +* Without going into a formal proof, this explains the method that is used in +* parsing the logical expressions. +* +* For example, if we have: "a && !(!b || (c && g)) || d || e && !f" +* The first pass will convert it into the following program: +* +* n1: r=a; l1: if (!r) goto l4; +* n2: r=b; l2: if (!r) goto l4; got stuck in here.. should that be 'goto l5' ?
Nope, this is correct. In fact, my user space implementation of the code is what generated this output.
!(!b || (c && g)) is the same as (b && (!c || !g)), so we can rewrite the above as:
a && b && (!c || !g) || d || e && !f
Which makes it more obvious why it is goto l4.
And since we have:
n1: r=a; l1: if (!r) goto l4;
n2: r=b; l2: if (!r) goto l4;
n3: r=c; r=!r; l3: if (r) goto l4;
n4: r=g; r=!r; l4: if (r) goto l5;
n5; r=d; l5: if (r) goto T;
If a is true, if (!r) is false so we continue to n2.
If b is false, then if (!r) is true, so we take the branch. Let's see what that does:
l4: if (r) goto l5;
But since we jumped because r is false, then this if statement is guaranteed to be false, and we continue to n5. Then we need to test d.
a && b && ... || d
You can see how that is correct. If a is true and then be is false, then we ignore the rest of the && statement and jump to testing the other side of || which is d.
-- Steve
Quoted 12 lines
jirka
Quoted 7 lines
+ * n3: r=c; r=!r; l3: if (r) goto l4;
+ * n4: r=g; r=!r; l4: if (r) goto l5;
+ * n5: r=d; l5: if (r) goto T
+ * n6: r=e; l6: if (!r) goto l7;
+ * n7: r=f; r=!r; l7: if (!r) goto F
+ * T: return TRUE
+ * F: return FALSEjirka
Re: [PATCH 3/3] tracing: Rewrite filter logic to be simpler and faster
In reply to Steven RostedtQuoted 9 lines · Steven Rostedt
From: "Steven Rostedt (VMware)" <[email protected]>
Al Viro reviewed the filter logic of ftrace trace events and found it to be very troubling. It creates a binary tree based on the logic operators and walks it during tracing. He sent myself and Tom Zanussi a long explanation (and formal proof) of how to do the string parsing better and end up with a program array that can be simply iterated to come up with the correct results.
Quoted 8 lines
I took his ideas and his pseudo code and rewrote the filter logic based on them. In doing so, I was able to remove a lot of code, and have a much more condensed filter logic in the process. I wrote a very long comment describing the methadology that Al proposed in my own words. For more info on how this works, read the comment above
predicate_parse().Suggested-by Al Viro <[email protected]>Signed-off-by Steven Rostedt (VMware) <[email protected]>
got it crashed when clearing the filter via 'echo > filter'
jirka
---
ibm-x3650m4-01 login: [ 803.551062] BUG: unable to handle kernel paging request at ffff972acc154c34
[ 803.558846] IP: process_preds+0x5e9/0x680 [ 803.563318] PGD 251bbf067 P4D 251bbf067 PUD 0 [ 803.568280] Oops: 0000 [#1] SMP PTI [ 803.572172] Modules linked in: intel_rapl sb_edac x86_pkg_temp_thermal intel_powerclamp coretemp kvm_intel kvm igb irqbypass crct10dif_pclmul ptp crc32_pclmul ipmi_ssmi_msghandler intel_rapl_perf wmi i2c_i801 mii lpc_ich xfs libcrc32c mgag200 i2c_algo_bit drm_kms_helper ttm crc32c_intel drm megaraid_sas [ 803.618767] CPU: 13 PID: 1297 Comm: bash Not tainted 4.16.0-rc4+ #96 [ 803.625857] Hardware name: IBM System x3650 M4 : -[7915E2G]-/00Y7683, BIOS -[VVE124AUS-1.30]- 11/21/2012 [ 803.636441] RIP: 0010:process_preds+0x5e9/0x680 [ 803.641496] RSP: 0018:ffffa8aac2b9fd30 EFLAGS: 00010286 [ 803.647327] RAX: ffff972375def4e0 RBX: ffff972575b84e08 RCX: 00000000fffffffe [ 803.655289] RDX: ffff972acc154c30 RSI: ffff972375def500 RDI: 0000000000023ee0 [ 803.663251] RBP: ffff972575b84198 R08: ffff972377be3ee0 R09: ffff972575b84210 [ 803.671213] R10: 0000000000000000 R11: 0000000040000000 R12: ffff972575b84ff0 [ 803.679176] R13: 0000000000000001 R14: 00000000fffffff4 R15: ffff972575b84ff0 [ 803.687139] FS: 00007f216a513700(0000) GS:ffff972377bc0000(0000) knlGS:0000000000000000 [ 803.696169] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 803.702581] CR2: ffff972acc154c34 CR3: 0000000274478001 CR4: 00000000000606e0 [ 803.710544] Call Trace: [ 803.713278] create_filter+0x80/0xc0 [ 803.717268] apply_event_filter+0xb8/0x120 [ 803.721837] event_filter_write+0x5d/0xb0 [ 803.726312] __vfs_write+0x33/0x170 [ 803.730207] ? __inode_security_revalidate+0x4a/0x70 [ 803.735740] ? selinux_file_permission+0xce/0x120 [ 803.740989] ? _cond_resched+0x16/0x40 [ 803.745173] vfs_write+0xb0/0x190 [ 803.748870] SyS_write+0x52/0xc0 [ 803.752473] do_syscall_64+0x6e/0x180 [ 803.756560] entry_SYSCALL_64_after_hwframe+0x3d/0xa2 [ 803.762196] RIP: 0033:0x7f2169c00b50 [ 803.766182] RSP: 002b:00007ffc35e05db8 EFLAGS: 00000246 ORIG_RAX: 0000000000000001 [ 803.774630] RAX: ffffffffffffffda RBX: 0000000000000001 RCX: 00007f2169c00b50 [ 803.782592] RDX: 0000000000000001 RSI: 0000560031449e00 RDI: 0000000000000001 [ 803.790555] RBP: 0000560031449e00 R08: 00007f2169ecb740 R09: 00007f216a513700 [ 803.798517] R10: 0000560031453a00 R11: 0000000000000246 R12: 0000000000000001 [ 803.806479] R13: 0000000000000001 R14: 00007f2169eca5e0 R15: 00007f2169ec63c0 [ 803.814443] Code: 02 00 00 00 00 44 89 10 c7 40 04 00 00 00 00 83 e9 01 83 f9 ff 74 22 48 63 c1 48 c1 e0 04 48 01 f0 48 63 10 48 c1 e2 04 48 01 f2 <8b> 5a 04 39 58 04 [ 803.835544] RIP: process_preds+0x5e9/0x680 RSP: ffffa8aac2b9fd30 [ 803.842247] CR2: ffff972acc154c34 [ 803.845945] ---[ end trace 81df1915c389f53d ]---
Steven Rostedt
maintainerRe: [PATCH 3/3] tracing: Rewrite filter logic to be simpler and faster
Quoted 1 line · On Mon, 12 Mar 2018 16:10:17 +0100 Jiri Olsa <[email protected]> wrote:
got it crashed when clearing the filter via 'echo > filter'
Awesome. I'll go and test this out. Thanks!
Hmm, could you pull my tree and test my branch: ftrace/core. I may have already fixed this but haven't posted the latest (which I'll do before pushing to next).
-- Steve
Re: [PATCH 3/3] tracing: Rewrite filter logic to be simpler and faster
Quoted 10 lines · Steven Rostedt
Quoted 1 line · On Mon, 12 Mar 2018 16:10:17 +0100 Jiri Olsa <[email protected]> wrote:
got it crashed when clearing the filter via 'echo > filter'
Awesome. I'll go and test this out. Thanks!
Hmm, could you pull my tree and test my branch: ftrace/core. I may have already fixed this but haven't posted the latest (which I'll do before pushing to next).
I couldn't apply your patches from mailbox so I used your ftrace/core already
jirka
Steven Rostedt
maintainerRe: [PATCH 3/3] tracing: Rewrite filter logic to be simpler and faster
Quoted 6 lines · On Mon, 12 Mar 2018 19:54:14 +0100 Jiri Olsa <[email protected]> wrote:
Quoted 5 lines · Steven Rostedt
Quoted 1 line · On Mon, 12 Mar 2018 16:10:17 +0100 Jiri Olsa <[email protected]> wrote:
got it crashed when clearing the filter via 'echo > filter'
Quoted 8 lines
Quoted 5 lines
Awesome. I'll go and test this out. Thanks!
Hmm, could you pull my tree and test my branch: ftrace/core. I may have already fixed this but haven't posted the latest (which I'll do before pushing to next).
I couldn't apply your patches from mailbox so I used your ftrace/core already
Ug, I'm able to reproduce it. Damn, this passed my test suite. How did it not trigger this. I need to look at my test cases!
-- Steve
Steven Rostedt
maintainerRe: [PATCH 3/3] tracing: Rewrite filter logic to be simpler and faster
In reply to Jiri OlsaQuoted 6 lines · On Mon, 12 Mar 2018 19:54:14 +0100 Jiri Olsa <[email protected]> wrote:
Quoted 5 lines · Steven Rostedt
Quoted 1 line · On Mon, 12 Mar 2018 16:10:17 +0100 Jiri Olsa <[email protected]> wrote:
got it crashed when clearing the filter via 'echo > filter'
Quoted 8 lines
Quoted 5 lines
Awesome. I'll go and test this out. Thanks!
Hmm, could you pull my tree and test my branch: ftrace/core. I may have already fixed this but haven't posted the latest (which I'll do before pushing to next).
I couldn't apply your patches from mailbox so I used your ftrace/core already
Jiri, If you apply the below, does it fix it for you?
-- Steve
kernel/trace/trace_events_filter.c +7 -4
@@ -1498,11 +1498,14 @@ static int process_preds(struct trace_event_call *call,return ret; } - prog =predicate_parse (filter_string, nr_parens, nr_preds, +if (!nr_preds) { + prog =NULL ; + }else { + prog =predicate_parse (filter_string, nr_parens, nr_preds, parse_pred, call, pe); -if (IS_ERR (prog)) -return PTR_ERR (prog); - +if (IS_ERR (prog)) +return PTR_ERR (prog); + }rcu_assign_pointer (filter->prog, prog);return 0 ; }
Re: [PATCH 3/3] tracing: Rewrite filter logic to be simpler and faster
Quoted 11 lines · Steven Rostedt
Quoted 8 lines · On Mon, 12 Mar 2018 19:54:14 +0100 Jiri Olsa <[email protected]> wrote:
Quoted 7 lines · Steven Rostedt
Quoted 1 line · On Mon, 12 Mar 2018 16:10:17 +0100 Jiri Olsa <[email protected]> wrote:
got it crashed when clearing the filter via 'echo > filter'
Awesome. I'll go and test this out. Thanks!
Quoted 8 lines
Quoted 6 lines
Quoted 3 lines
Hmm, could you pull my tree and test my branch: ftrace/core. I may have already fixed this but haven't posted the latest (which I'll do before pushing to next).
I couldn't apply your patches from mailbox so I used your ftrace/core already
Jiri, If you apply the below, does it fix it for you?
yes, the crash is gone and I can set filter ftrace/function, but I'm still having some issues put that filter through perf
# perf record -e ftrace:function --filter "ip == 0xffffffffa41e8490" ls
but I might be just missing something.. it's been a while ;-) I'm looking to that
jirka
Quoted 26 lines
-- Steve
kernel/trace/trace_events_filter.c +7
-4@@ -1498,11 +1498,14 @@ static int process_preds(struct trace_event_call *call,return ret; } - prog =predicate_parse (filter_string, nr_parens, nr_preds, +if (!nr_preds) { + prog =NULL ; + }else { + prog =predicate_parse (filter_string, nr_parens, nr_preds, parse_pred, call, pe); -if (IS_ERR (prog)) -return PTR_ERR (prog); - +if (IS_ERR (prog)) +return PTR_ERR (prog); + }rcu_assign_pointer (filter->prog, prog);return 0 ; }
Steven Rostedt
maintainerRe: [PATCH 3/3] tracing: Rewrite filter logic to be simpler and faster
Quoted 3 lines · On Tue, 13 Mar 2018 11:14:01 +0100 Jiri Olsa <[email protected]> wrote:
Quoted 1 line
Jiri, If you apply the below, does it fix it for you?
yes, the crash is gone and I can set filter ftrace/function,
Great!
Quoted 5 lines
but I'm still having some issues put that filter through perf
# perf record -e ftrace:function --filter "ip == 0xffffffffa41e8490" lsbut I might be just missing something.. it's been a while ;-) I'm looking to that
I have to ask. Did that work with the old code? The ftrace filter was special in the old code and I tried to simulate it in the new code. I'm not sure I checked if ip can take an address, but from what the code looked like, it wouldn't. It looked like it required a name of a function. Something that gets passed into "set_ftrace_filter" which is not an address.
So instead of doing something like:
perf record -e ftrace:function --filter "ip == 0xffffffff810ccfa0" ls
You would need to do
perf record -e ftrace:function --filter "ip == schedule_tail" ls
because perf doesn't use the filter for the function, it uses the ftrace_ops->hash tables. If it would simply take the address, we could just use the trace_events_filter logic, and not make it a special case.
-- Steve
Re: [PATCH 3/3] tracing: Rewrite filter logic to be simpler and faster
Quoted 26 lines · Steven Rostedt
Quoted 3 lines · On Tue, 13 Mar 2018 11:14:01 +0100 Jiri Olsa <[email protected]> wrote:
Quoted 1 line
Jiri, If you apply the below, does it fix it for you?
yes, the crash is gone and I can set filter ftrace/function,
Great!
Quoted 5 lines
but I'm still having some issues put that filter through perf
# perf record -e ftrace:function --filter "ip == 0xffffffffa41e8490" lsbut I might be just missing something.. it's been a while ;-) I'm looking to that
I have to ask. Did that work with the old code? The ftrace filter was special in the old code and I tried to simulate it in the new code. I'm not sure I checked if ip can take an address, but from what the code looked like, it wouldn't. It looked like it required a name of a function. Something that gets passed into "
set_ftrace_filter" which is not an address.So instead of doing something like:
perf record -e ftrace:function --filter "ip ==
0xffffffff810ccfa0" ls
Quoted 7 lines
You would need to do
perf record -e ftrace:function --filter "ip ==
schedule_tail" lsbecause perf doesn't use the filter for the function, it uses the
ftrace_ops->hashtables. If it would simply take the address, we could just use thetrace_events_filterlogic, and not make it a special case.
ok, that's what I've been missing.. for some reason I thought we need to pass the address.. everything checks out then
I checked few filters and it seems to work properly to me
thanks,
jirka
Re: [PATCH 0/3] tracing: Rewrite the function filter code
In reply to Steven RostedtOn Fri, Mar 09, 2018 at 09:34:42PM -0500, Steven Rostedt wrote:
SNIP
Quoted 11 lines
Special thanks goes out to Al for his patience and his time that he spent in educating us in a proper logical parser.
Two patches were added to do some initial clean up. The last patch implements Al's suggestions. I wrote up a very lengthy comment describing what Al taught us in my own words (hopefully I got it right), and the implementation is similar to what Al showed with a few changes (again, hopefully I got that right too). I tested this with lots of different filters and it looks to be holding up.
Quoted 4 lines
Jiri,
This affects perf as well. I ran some tests and I believe I got it woking as it does today.
nice, it looks ok to me.. I guess the only concern is the filter for ftrace:function event, which uses the pred parsing code just to get the 'ip == ...' pairs and feeds it to ftrace_ops filter api
I'll check and make some tests
I think tracepoint events filters should be working without any special care because they use the same api as ftrace filters
jirka