Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Using strlen as a model, add length checking to create strnlen.
- Signed-off-by: Ken Steele <ken@tilera.com>
- Signed-off-by: Chris Metcalf <cmetcalf@tilera.com>
- ---
- v2 of the patch adds an "& 31" to the shift count for 32-bit strnlen.
- It turns out this doesn't affect the generated code at all, and it's
- technically more correct, as pointed out by Max Filippov <jcmvbkbc@gmail.com>.
- arch/tile/include/asm/string.h | 2 ++
- arch/tile/lib/Makefile | 2 +-
- arch/tile/lib/strnlen_32.c | 47 +++++++++++++++++++++++++++++++++++++++++
- arch/tile/lib/strnlen_64.c | 48 ++++++++++++++++++++++++++++++++++++++++++
- 4 files changed, 98 insertions(+), 1 deletion(-)
- create mode 100644 arch/tile/lib/strnlen_32.c
- create mode 100644 arch/tile/lib/strnlen_64.c
- diff --git a/arch/tile/include/asm/string.h b/arch/tile/include/asm/string.h
- index 7535cf1..92b271b 100644
- --- a/arch/tile/include/asm/string.h
- +++ b/arch/tile/include/asm/string.h
- @@ -21,8 +21,10 @@
- #define __HAVE_ARCH_MEMMOVE
- #define __HAVE_ARCH_STRCHR
- #define __HAVE_ARCH_STRLEN
- +#define __HAVE_ARCH_STRNLEN
- extern __kernel_size_t strlen(const char *);
- +extern __kernel_size_t strnlen(const char *, __kernel_size_t);
- extern char *strchr(const char *s, int c);
- extern void *memchr(const void *s, int c, size_t n);
- extern void *memset(void *, int, __kernel_size_t);
- diff --git a/arch/tile/lib/Makefile b/arch/tile/lib/Makefile
- index 985f598..5d84437 100644
- --- a/arch/tile/lib/Makefile
- +++ b/arch/tile/lib/Makefile
- @@ -4,7 +4,7 @@
- lib-y = cacheflush.o checksum.o cpumask.o delay.o uaccess.o \
- memmove.o memcpy_$(BITS).o memchr_$(BITS).o memset_$(BITS).o \
- - strchr_$(BITS).o strlen_$(BITS).o
- + strchr_$(BITS).o strlen_$(BITS).o strnlen_$(BITS).o
- ifeq ($(CONFIG_TILEGX),y)
- CFLAGS_REMOVE_memcpy_user_64.o = -fno-omit-frame-pointer
- diff --git a/arch/tile/lib/strnlen_32.c b/arch/tile/lib/strnlen_32.c
- new file mode 100644
- index 0000000..1434141
- --- /dev/null
- +++ b/arch/tile/lib/strnlen_32.c
- @@ -0,0 +1,47 @@
- +/*
- + * Copyright 2013 Tilera Corporation. All Rights Reserved.
- + *
- + * This program is free software; you can redistribute it and/or
- + * modify it under the terms of the GNU General Public License
- + * as published by the Free Software Foundation, version 2.
- + *
- + * This program is distributed in the hope that it will be useful, but
- + * WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- + * NON INFRINGEMENT. See the GNU General Public License for
- + * more details.
- + */
- +
- +#include <linux/types.h>
- +#include <linux/string.h>
- +#include <linux/module.h>
- +
- +size_t strnlen(const char *s, size_t count)
- +{
- + /* Get an aligned pointer. */
- + const uintptr_t s_int = (uintptr_t) s;
- + const uint32_t *p = (const uint32_t *)(s_int & -4);
- + size_t bytes_read = sizeof(*p) - (s_int & (sizeof(*p) - 1));
- + size_t len;
- + uint32_t v, bits;
- +
- + /* Avoid page fault risk by not reading any bytes when count is 0. */
- + if (count == 0)
- + return 0;
- +
- + /* Read first word, but force bytes before the string to be nonzero. */
- + v = *p | ((1 << ((s_int << 3) & 31)) - 1);
- +
- + while ((bits = __insn_seqb(v, 0)) == 0) {
- + if (bytes_read >= count) {
- + /* Read COUNT bytes and didn't find the terminator. */
- + return count;
- + }
- + v = *++p;
- + bytes_read += sizeof(v);
- + }
- +
- + len = ((const char *) p) + (__insn_ctz(bits) >> 3) - s;
- + return (len < count ? len : count);
- +}
- +EXPORT_SYMBOL(strnlen);
- diff --git a/arch/tile/lib/strnlen_64.c b/arch/tile/lib/strnlen_64.c
- new file mode 100644
- index 0000000..2e8de6a
- --- /dev/null
- +++ b/arch/tile/lib/strnlen_64.c
- @@ -0,0 +1,48 @@
- +/*
- + * Copyright 2013 Tilera Corporation. All Rights Reserved.
- + *
- + * This program is free software; you can redistribute it and/or
- + * modify it under the terms of the GNU General Public License
- + * as published by the Free Software Foundation, version 2.
- + *
- + * This program is distributed in the hope that it will be useful, but
- + * WITHOUT ANY WARRANTY; without even the implied warranty of
- + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
- + * NON INFRINGEMENT. See the GNU General Public License for
- + * more details.
- + */
- +
- +#include <linux/types.h>
- +#include <linux/string.h>
- +#include <linux/module.h>
- +#include "string-endian.h"
- +
- +size_t strnlen(const char *s, size_t count)
- +{
- + /* Get an aligned pointer. */
- + const uintptr_t s_int = (uintptr_t) s;
- + const uint64_t *p = (const uint64_t *)(s_int & -8);
- + size_t bytes_read = sizeof(*p) - (s_int & (sizeof(*p) - 1));
- + size_t len;
- + uint64_t v, bits;
- +
- + /* Avoid page fault risk by not reading any bytes when count is 0. */
- + if (count == 0)
- + return 0;
- +
- + /* Read and MASK the first word. */
- + v = *p | MASK(s_int);
- +
- + while ((bits = __insn_v1cmpeqi(v, 0)) == 0) {
- + if (bytes_read >= count) {
- + /* Read COUNT bytes and didn't find the terminator. */
- + return count;
- + }
- + v = *++p;
- + bytes_read += sizeof(v);
- + }
- +
- + len = ((const char *) p) + (CFZ(bits) >> 3) - s;
- + return (len < count ? len : count);
- +}
- +EXPORT_SYMBOL(strnlen);
- --
- 1.8.3.1
- --
- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
- the body of a message to majordomo@vger.kernel.org
- More majordomo info at http://vger.kernel.org/majordomo-info.html
- Please read the FAQ at http://www.tux.org/lkml/
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement