[RFC PATCH] string: Add strzcmp for a length limited strcmp

From: Joe Perches
Date: Mon Oct 31 2016 - 14:34:58 EST


strncmp is commonly used when parsing early_param options where a
fixed string is matched without the trailing zero.

A few errors exist where string comparisons use strncmp and the
length of the comparison to perform is incorrectly specified.

ie:
strncmp(ptr, "string", 5)
where 5 should likely have been 6

There are a few of these in the kernel tree like:

drivers/net/ethernet/samsung/sxgbe/sxgbe_main.c:2307:
if (!strncmp(opt, "eee_timer:", 6)) {
sound/firewire/bebob/bebob.c:180:
return strncmp(name, "FW Audiophile Bootloader", 15) != 0;

Perhaps it would be useful to introduce a function that does a
strcmp limited to the length of the 2nd string argument.

The second argument for strzcmp requires a char [], not a const char *
using a macro and BUILD_BUG_ON.

Signed-off-by: Joe Perches <joe@xxxxxxxxxxx>
---
include/linux/string.h | 7 +++++++
lib/string.c | 18 ++++++++++++++++++
2 files changed, 25 insertions(+)

diff --git a/include/linux/string.h b/include/linux/string.h
index 26b6f6a66f83..536d00164b26 100644
--- a/include/linux/string.h
+++ b/include/linux/string.h
@@ -5,6 +5,7 @@
#include <linux/compiler.h> /* for inline */
#include <linux/types.h> /* for size_t */
#include <linux/stddef.h> /* for NULL */
+#include <linux/bug.h>
#include <stdarg.h>
#include <uapi/linux/string.h>

@@ -44,6 +45,12 @@ extern int strcmp(const char *,const char *);
#ifndef __HAVE_ARCH_STRNCMP
extern int strncmp(const char *,const char *,__kernel_size_t);
#endif
+int _strzcmp(const char *, const char *);
+#define strzcmp(s1, s2) \
+({ \
+ BUILD_BUG_ON(!__same_type(s2, char [])); \
+ _strzcmp(s1, s2); \
+})
#ifndef __HAVE_ARCH_STRCASECMP
extern int strcasecmp(const char *s1, const char *s2);
#endif
diff --git a/lib/string.c b/lib/string.c
index ed83562a53ae..ca9e4eb26b85 100644
--- a/lib/string.c
+++ b/lib/string.c
@@ -360,6 +360,24 @@ int strncmp(const char *cs, const char *ct, size_t count)
EXPORT_SYMBOL(strncmp);
#endif

+/**
+ * _strzcmp - Compare two strings limited to the length of the 2nd string
+ * @cs: 1st string
+ * @ct: 2nd string
+ */
+int _strzcmp(const char *cs, const char *ct)
+{
+ while (*cs == *ct && *cs != 0) {
+ cs++;
+ ct++;
+ }
+ if (*ct == 0)
+ return 0;
+
+ return *(unsigned char *)cs < *(unsigned char *)ct ? -1: 1;
+}
+EXPORT_SYMBOL(_strzcmp);
+
#ifndef __HAVE_ARCH_STRCHR
/**
* strchr - Find the first occurrence of a character in a string
--
2.10.0.rc2.1.g053435c