Re: [for-next][PATCH 23/24] string.h: Add strncmp_prefix() helper macro

Steven Rostedt
2018-12-21T20:35:31Z

On Fri, 21 Dec 2018 12:01:48 -0800
Linus Torvalds <torvalds@linux-foundation.org> wrote:

> On Fri, Dec 21, 2018 at 11:40 AM Steven Rostedt <rostedt@goodmis.org> wrote:
> >
> > OK, what about if we just use strlen() and say that this macro is not
> > safe for parameters with side effects.
>
> I think gcc follows simple assignments just fine, and does the
> optimized strlen() for them too.
>
> So why not just do
>
> #define have_prefix(str,prefix) ({ \
> const char *__pfx = prefix; \
> size_t __pfxlen = strlen(__pfx); \
> strncmp(str, __pfx, __pfxlen) ? 0 : __pfxlen); })
>
> and be done with it safely?
>
> The above is ENTIRELY untested.
>

At first I thought this would have issues, but with a slight change...

#define have_prefix(str, prefix) ({ \
const char *__pfx = (const char *)prefix; \

And the rest the same, it appears to work.

Need the cast because if for some reason someone passed in something
like "const unsigned char" then it wouldn't work. But that's just a nit.

So something like this then?

-- Steve

diff --git a/include/linux/string.h b/include/linux/string.h
index 27d0482e5e05..4586fee60194 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -14,6 +14,28 @@ 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);

+/**
+ * have_prefix - Test if a string has a given prefix
+ * @str: The string to test
+ * @prefix: The string to see if @str starts with
+ *
+ * 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 has_prefix().
+ *
+ * Returns: 0 if @str does not start with @prefix
+ strlen(@prefix) if @str does start with @prefix
+ */
+#define has_prefix(str, prefix) \
+ ({ \
+ const char *____prefix____ = (const char *)(prefix); \
+ int ____len____ = strlen(____prefix____); \
+ strncmp(str, ____prefix____, ____len____) == 0 ? \
+ ____len____ : 0; \
+ })
+
/*
* Include machine specific inline routines
*/