linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC][PATCH] string.h: Add strncmp_prefix() helper macro
@ 2018-12-19 21:32 Bryana Rostedt
  2018-12-19 21:54 ` Joe Perches
  2018-12-19 22:05 ` Joe Perches
  0 siblings, 2 replies; 6+ messages in thread
From: Bryana Rostedt @ 2018-12-19 21:32 UTC (permalink / raw)
  To: LKML
  Cc: Linus Torvalds, Andrew Morton, Ingo Molnar, Tom Zanussi,
	Joe Perches, Greg Kroah-Hartman, Alexander Shishkin

A discussion came up in the trace triggers thread about converting a
bunch of:

 strncmp(str, "const", sizeof("const") - 1)

use cases into a helper macro. It started with:

#define strncmp_const(str, const) \
	strncmp(str, const, sizeof(const) - 1)

But then Joe Perches mentioned that if a const is not used, the
sizeof() will be the size of a pointer, which can be bad. And that
gcc will optimize strlen("const") into "sizeof("const") - 1".

Thinking about this more, a quick grep in the kernel tree found several
(thousands!) of cases that use this construct. A quick grep also
revealed that there's probably several bugs in that use case. Some are
that people forgot the "- 1" (which I found) and others could be that
the constant for the sizeof is different than the constant (although, I
haven't found any of those, but I also didn't look hard).

I figured the best thing to do is to create a helper macro and place it
into include/linux/string.h. And go around and fix all the open coded
versions of it later.

I plan on only applying this patch and updating the tracing hooks for
this merge window. And perhaps use it to fix some of the bugs that were
found.

I was going to just use:

#define strncmp_prefix(str, prefix) \
	strncmp(str, prefix, strlen(prefix))

but then realized that "prefix" is used twice, and will break if
someone does something like:

	strncmp_prefix(str, ptr++);

So instead I check with __builtin_constant_p() to see if the second
parameter is truly a constant, which I use sizeof() anyway (why bother
gcc to optimize it, if we already know it's a constant), and copy the
parameter into a local variable and use that local variable for the non
constant part (with strlen).

Link: http://lkml.kernel.org/r/e3e754f2bd18e56eaa8baf79bee619316ebf4cfc.1545161087.git.tom.zanussi@linux.intel.com

Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
---
diff --git a/include/linux/string.h b/include/linux/string.h
index 27d0482e5e05..3dc743e3a0ba 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -14,6 +14,27 @@ extern void *memdup_user(const void __user *, size_t);
 extern void *vmemdup_user(const void __user *, size_t);
 extern void *memdup_user_nul(const void __user *, size_t);
 
+/*
+ * A common way to test a prefix of a string is to do:
+ *  strncmp(str, prefix, sizeof(prefix) - 1)
+ *
+ * But this can lead to bugs due to typos, or if prefix is a pointer
+ * and not a constant. Instead use strncmp_prefix().
+ */
+#define strncmp_prefix(str, prefix)					\
+	({								\
+		int ____strcmp_prefix_ret____;				\
+		char *____strcmp_prefix____ = prefix;			\
+		if (__builtin_constant_p(&prefix))			\
+			____strcmp_prefix_ret____ =			\
+				strncmp(str, prefix, sizeof(prefix) - 1); \
+		else							\
+			____strcmp_prefix_ret____ =			\
+				strncmp(str, ____strcmp_prefix____,	\
+					strlen(____strcmp_prefix____));	\
+		____strcmp_prefix_ret____;				\
+	})
+
 /*
  * Include machine specific inline routines
  */

^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [RFC][PATCH] string.h: Add strncmp_prefix() helper macro
  2018-12-19 21:32 [RFC][PATCH] string.h: Add strncmp_prefix() helper macro Bryana Rostedt
@ 2018-12-19 21:54 ` Joe Perches
  2018-12-19 22:21   ` Steven Rostedt
  2018-12-20  1:43   ` Steven Rostedt
  2018-12-19 22:05 ` Joe Perches
  1 sibling, 2 replies; 6+ messages in thread
From: Joe Perches @ 2018-12-19 21:54 UTC (permalink / raw)
  To: Bryana Rostedt, LKML
  Cc: Linus Torvalds, Andrew Morton, Ingo Molnar, Tom Zanussi,
	Greg Kroah-Hartman, Alexander Shishkin

On Wed, 2018-12-19 at 16:32 -0500, Bryana Rostedt wrote:
> A discussion came up in the trace triggers thread about converting a
> bunch of:
> 
>  strncmp(str, "const", sizeof("const") - 1)
> 
> use cases into a helper macro. It started with:
> 
> #define strncmp_const(str, const) \
> 	strncmp(str, const, sizeof(const) - 1)
> 
> But then Joe Perches mentioned that if a const is not used, the
> sizeof() will be the size of a pointer, which can be bad. And that
> gcc will optimize strlen("const") into "sizeof("const") - 1".
> 
> Thinking about this more, a quick grep in the kernel tree found several
> (thousands!) of cases that use this construct. A quick grep also
> revealed that there's probably several bugs in that use case. Some are
> that people forgot the "- 1" (which I found) and others could be that
> the constant for the sizeof is different than the constant (although, I
> haven't found any of those, but I also didn't look hard).
> 
> I figured the best thing to do is to create a helper macro and place it
> into include/linux/string.h. And go around and fix all the open coded
> versions of it later.
> 
> I plan on only applying this patch and updating the tracing hooks for
> this merge window. And perhaps use it to fix some of the bugs that were
> found.
> 
> I was going to just use:
> 
> #define strncmp_prefix(str, prefix) \
> 	strncmp(str, prefix, strlen(prefix))
> 
> but then realized that "prefix" is used twice, and will break if
> someone does something like:
> 
> 	strncmp_prefix(str, ptr++);
> 
> So instead I check with __builtin_constant_p() to see if the second
> parameter is truly a constant, which I use sizeof() anyway (why bother
> gcc to optimize it, if we already know it's a constant), and copy the
> parameter into a local variable and use that local variable for the non
> constant part (with strlen).
> 
> Link: http://lkml.kernel.org/r/e3e754f2bd18e56eaa8baf79bee619316ebf4cfc.1545161087.git.tom.zanussi@linux.intel.com
> 
> Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
> ---
> diff --git a/include/linux/string.h b/include/linux/string.h
> index 27d0482e5e05..3dc743e3a0ba 100644
> --- a/include/linux/string.h
> +++ b/include/linux/string.h
> @@ -14,6 +14,27 @@ extern void *memdup_user(const void __user *, size_t);
>  extern void *vmemdup_user(const void __user *, size_t);
>  extern void *memdup_user_nul(const void __user *, size_t);
>  
> +/*
> + * A common way to test a prefix of a string is to do:
> + *  strncmp(str, prefix, sizeof(prefix) - 1)
> + *
> + * But this can lead to bugs due to typos, or if prefix is a pointer
> + * and not a constant. Instead use strncmp_prefix().
> + */
> +#define strncmp_prefix(str, prefix)					\e
> +	({								\
> +		int ____strcmp_prefix_ret____;				\
> +		char *____strcmp_prefix____ = prefix;			\

This creates a warning and discards any const from prefix when used like

	static const char foo[] = "bar";

	strncmp_prefix(str, foo);

> +		if (__builtin_constant_p(&prefix))			\
> +			____strcmp_prefix_ret____ =			\
> +				strncmp(str, prefix, sizeof(prefix) - 1); \
> +		else							\
> +			____strcmp_prefix_ret____ =			\
> +				strncmp(str, ____strcmp_prefix____,	\
> +					strlen(____strcmp_prefix____));	\
> +		____strcmp_prefix_ret____;				\
> +	})
> +

Perhaps

#define strncmp_prefix(str, prefix)					\
({									\
	typeof(prefix) p = (prefix);					\
	strncmp(str, p, strlen(p));					\
})



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [RFC][PATCH] string.h: Add strncmp_prefix() helper macro
  2018-12-19 21:32 [RFC][PATCH] string.h: Add strncmp_prefix() helper macro Bryana Rostedt
  2018-12-19 21:54 ` Joe Perches
@ 2018-12-19 22:05 ` Joe Perches
  2018-12-20  1:46   ` Steven Rostedt
  1 sibling, 1 reply; 6+ messages in thread
From: Joe Perches @ 2018-12-19 22:05 UTC (permalink / raw)
  To: Bryana Rostedt, LKML
  Cc: Linus Torvalds, Andrew Morton, Ingo Molnar, Tom Zanussi,
	Greg Kroah-Hartman, Alexander Shishkin

On Wed, 2018-12-19 at 16:32 -0500, Bryana Rostedt wrote:
> a quick grep in the kernel tree found several
> (thousands!) of cases that use this construct. A quick grep also
> revealed that there's probably several bugs in that use case. Some are
> that people forgot the "- 1" (which I found) and others could be that
> the constant for the sizeof is different than the constant (although, I
> haven't found any of those, but I also didn't look hard).

Several dozen cases exist like strncmp(foo, "bar", 4)
where it might as well use strcmp instead.

And a few mismatches exist like:

drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c:2285:		if (!strncmp(opt, "eee_timer:", 6)) {
tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c:318:	if (!strncmp(s, "power", 9))
tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c:321:	if (!strncmp(s, "balance-power", 17))
j


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [RFC][PATCH] string.h: Add strncmp_prefix() helper macro
  2018-12-19 21:54 ` Joe Perches
@ 2018-12-19 22:21   ` Steven Rostedt
  2018-12-20  1:43   ` Steven Rostedt
  1 sibling, 0 replies; 6+ messages in thread
From: Steven Rostedt @ 2018-12-19 22:21 UTC (permalink / raw)
  To: Joe Perches, LKML
  Cc: Linus Torvalds, Andrew Morton, Ingo Molnar, Tom Zanussi,
	Greg Kroah-Hartman, Alexander Shishkin

Seems that I sent this as my daughter.

I'm not home now but will resend again as myself when I am.

-- Steve

On December 19, 2018 4:54:57 PM EST, Joe Perches <joe@perches.com> wrote:
>On Wed, 2018-12-19 at 16:32 -0500, Bryana Rostedt wrote:
>> A discussion came up in the trace triggers thread about converting a
>> bunch of:
>> 
>>  strncmp(str, "const", sizeof("const") - 1)
>> 
>> use cases into a helper macro. It started with:
>> 
>> #define strncmp_const(str, const) \
>> 	strncmp(str, const, sizeof(const) - 1)
>> 
>> But then Joe Perches mentioned that if a const is not used, the
>> sizeof() will be the size of a pointer, which can be bad. And that
>> gcc will optimize strlen("const") into "sizeof("const") - 1".
>> 
>> Thinking about this more, a quick grep in the kernel tree found
>several
>> (thousands!) of cases that use this construct. A quick grep also
>> revealed that there's probably several bugs in that use case. Some
>are
>> that people forgot the "- 1" (which I found) and others could be that
>> the constant for the sizeof is different than the constant (although,
>I
>> haven't found any of those, but I also didn't look hard).
>> 
>> I figured the best thing to do is to create a helper macro and place
>it
>> into include/linux/string.h. And go around and fix all the open coded
>> versions of it later.
>> 
>> I plan on only applying this patch and updating the tracing hooks for
>> this merge window. And perhaps use it to fix some of the bugs that
>were
>> found.
>> 
>> I was going to just use:
>> 
>> #define strncmp_prefix(str, prefix) \
>> 	strncmp(str, prefix, strlen(prefix))
>> 
>> but then realized that "prefix" is used twice, and will break if
>> someone does something like:
>> 
>> 	strncmp_prefix(str, ptr++);
>> 
>> So instead I check with __builtin_constant_p() to see if the second
>> parameter is truly a constant, which I use sizeof() anyway (why
>bother
>> gcc to optimize it, if we already know it's a constant), and copy the
>> parameter into a local variable and use that local variable for the
>non
>> constant part (with strlen).
>> 
>> Link:
>http://lkml.kernel.org/r/e3e754f2bd18e56eaa8baf79bee619316ebf4cfc.1545161087.git.tom.zanussi@linux.intel.com
>> 
>> Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
>> ---
>> diff --git a/include/linux/string.h b/include/linux/string.h
>> index 27d0482e5e05..3dc743e3a0ba 100644
>> --- a/include/linux/string.h
>> +++ b/include/linux/string.h
>> @@ -14,6 +14,27 @@ extern void *memdup_user(const void __user *,
>size_t);
>>  extern void *vmemdup_user(const void __user *, size_t);
>>  extern void *memdup_user_nul(const void __user *, size_t);
>>  
>> +/*
>> + * A common way to test a prefix of a string is to do:
>> + *  strncmp(str, prefix, sizeof(prefix) - 1)
>> + *
>> + * But this can lead to bugs due to typos, or if prefix is a pointer
>> + * and not a constant. Instead use strncmp_prefix().
>> + */
>> +#define strncmp_prefix(str, prefix)					\e
>> +	({								\
>> +		int ____strcmp_prefix_ret____;				\
>> +		char *____strcmp_prefix____ = prefix;			\
>
>This creates a warning and discards any const from prefix when used
>like
>
>	static const char foo[] = "bar";
>
>	strncmp_prefix(str, foo);
>
>> +		if (__builtin_constant_p(&prefix))			\
>> +			____strcmp_prefix_ret____ =			\
>> +				strncmp(str, prefix, sizeof(prefix) - 1); \
>> +		else							\
>> +			____strcmp_prefix_ret____ =			\
>> +				strncmp(str, ____strcmp_prefix____,	\
>> +					strlen(____strcmp_prefix____));	\
>> +		____strcmp_prefix_ret____;				\
>> +	})
>> +
>
>Perhaps
>
>#define strncmp_prefix(str, prefix)					\
>({									\
>	typeof(prefix) p = (prefix);					\
>	strncmp(str, p, strlen(p));					\
>})

-- 
Sent from my Android device with K-9 Mail. Please excuse my brevity and top posting.

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [RFC][PATCH] string.h: Add strncmp_prefix() helper macro
  2018-12-19 21:54 ` Joe Perches
  2018-12-19 22:21   ` Steven Rostedt
@ 2018-12-20  1:43   ` Steven Rostedt
  1 sibling, 0 replies; 6+ messages in thread
From: Steven Rostedt @ 2018-12-20  1:43 UTC (permalink / raw)
  To: Joe Perches
  Cc: LKML, Linus Torvalds, Andrew Morton, Ingo Molnar, Tom Zanussi,
	Greg Kroah-Hartman, Alexander Shishkin

[ Sending now as myself and not my daughter :-p ]

On Wed, Dec 19, 2018 at 01:54:57PM -0800, Joe Perches wrote:
> On Wed, 2018-12-19 at 16:32 -0500, Bryana Rostedt wrote:
> >  
> > +/*
> > + * A common way to test a prefix of a string is to do:
> > + *  strncmp(str, prefix, sizeof(prefix) - 1)
> > + *
> > + * But this can lead to bugs due to typos, or if prefix is a pointer
> > + * and not a constant. Instead use strncmp_prefix().
> > + */
> > +#define strncmp_prefix(str, prefix)					\e
> > +	({								\
> > +		int ____strcmp_prefix_ret____;				\
> > +		char *____strcmp_prefix____ = prefix;			\
> 
> This creates a warning and discards any const from prefix when used like
> 
> 	static const char foo[] = "bar";
> 
> 	strncmp_prefix(str, foo);
> 
> > +		if (__builtin_constant_p(&prefix))			\
> > +			____strcmp_prefix_ret____ =			\
> > +				strncmp(str, prefix, sizeof(prefix) - 1); \
> > +		else							\
> > +			____strcmp_prefix_ret____ =			\
> > +				strncmp(str, ____strcmp_prefix____,	\
> > +					strlen(____strcmp_prefix____));	\
> > +		____strcmp_prefix_ret____;				\
> > +	})
> > +
> 
> Perhaps
> 
> #define strncmp_prefix(str, prefix)					\
> ({									\
> 	typeof(prefix) p = (prefix);					\
> 	strncmp(str, p, strlen(p));					\


I'll have to see how all supported  gcc optimizes that.

I could just move the prefix assignment in the else part, which gets compiled
out on constants anyway, just to be safe, and also shows exactly what is
happening and not worrying about gcc doing the "right" thing.

-- Steve


> })
> 

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [RFC][PATCH] string.h: Add strncmp_prefix() helper macro
  2018-12-19 22:05 ` Joe Perches
@ 2018-12-20  1:46   ` Steven Rostedt
  0 siblings, 0 replies; 6+ messages in thread
From: Steven Rostedt @ 2018-12-20  1:46 UTC (permalink / raw)
  To: Joe Perches
  Cc: LKML, Linus Torvalds, Andrew Morton, Ingo Molnar, Tom Zanussi,
	Greg Kroah-Hartman, Alexander Shishkin

[ Another email not as my daughter. ]

On Wed, Dec 19, 2018 at 02:05:32PM -0800, Joe Perches wrote:
> On Wed, 2018-12-19 at 16:32 -0500, Bryana Rostedt wrote:
> > a quick grep in the kernel tree found several
> > (thousands!) of cases that use this construct. A quick grep also
> > revealed that there's probably several bugs in that use case. Some are
> > that people forgot the "- 1" (which I found) and others could be that
> > the constant for the sizeof is different than the constant (although, I
> > haven't found any of those, but I also didn't look hard).
> 
> Several dozen cases exist like strncmp(foo, "bar", 4)
> where it might as well use strcmp instead.
> 
> And a few mismatches exist like:
> 
> drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c:2285:		if (!strncmp(opt, "eee_timer:", 6)) {
> tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c:318:	if (!strncmp(s, "power", 9))
> tools/power/x86/x86_energy_perf_policy/x86_energy_perf_policy.c:321:	if (!strncmp(s, "balance-power", 17))
> j

Yeah I saw these too. But that's just more justification to get a helper
function applied.

I'll look at the options, and then just add it to my queue for the next merge
window. I'll have to add the commit that is added as a requirement of other
patches that will sure need to go to stable.

-- Steve


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2018-12-20  1:46 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-12-19 21:32 [RFC][PATCH] string.h: Add strncmp_prefix() helper macro Bryana Rostedt
2018-12-19 21:54 ` Joe Perches
2018-12-19 22:21   ` Steven Rostedt
2018-12-20  1:43   ` Steven Rostedt
2018-12-19 22:05 ` Joe Perches
2018-12-20  1:46   ` Steven Rostedt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).