Skip to contentSkip to conversation

implement strnlen for systems that need it

PATCH Superseded John Arbuckle 6 participants 11 messages Oct 20, 2017 – Oct 24, 2017 6 messages not in the archive

v2 of 4 Superseded Latest is v4 →

lore
Share & tools
lore
#0 lore raw

PATCH v2 1/1 implement strnlen for systems that need it

Prior the Mac OS 10.7, the function strnlen() was not available. This patch implements strnlen() on Mac OS X versions that are below 10.7.

---
v2 changes:
- Simplified the code to make it static inline'ed
- Changed the type of count to size_t

 libfdt/libfdt_env.h | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)
libfdt/libfdt_env.h +29 -0
index 952056c..2569339 100644
@@ -109,4 +109,33 @@ static inline fdt64_t cpu_to_fdt64(uint64_t x)
 #undef CPU_TO_FDT16
 #undef EXTRACT_BYTE
 
+#ifdef __APPLE__
+#include <AvailabilityMacros.h>
+
+#define MAC_OS_X_VERSION_10_7 1070
+
+/* strnlen() is not available on Mac OS < 10.7 */
+# if (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7)
+
+/*
+ * strnlen: returns the length of a string or max_count - which ever is smallest
+ * Input 1 string: the string whose size is to be determined
+ * Input 2 max_count: the maximum value returned by this function
+ * Output: length of the string or max_count (the smallest of the two)
+ */
+static inline size_t strnlen(const char *string, size_t max_count)
+{
+    size_t count;
+    for (count = 0; count < max_count; count++) {
+        if (string[count] == '\0') {
+            break;
+        }
+    }
+    return count;
+}
+
+#endif /* (MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_7) */
+
+#endif /* __APPLE__ */
+
 #endif /* _LIBFDT_ENV_H */
Signature · 1 line
2.13.5 (Apple Git-94)

A message that is not in the archive (sent off-list or not yet received): 20171020175548.2566-1-programmingkidx-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org

#2 lore raw

libfdt/libfdt_env.h static inline fdt64_t cpu_to_fdt64(uint64_t x) · line 134

Quoted 9 lines · John Arbuckle
libfdt/libfdt_env.h +9 -0
+static inline size_t strnlen(const char *string, size_t max_count)
+{
+    size_t count;
+    for (count = 0; count < max_count; count++) {
+        if (string[count] == '\0') {
+            break;
+        }
+    }
+    return count;

Not to nitpick, but

  const char *p = memchr(string, 0, max_count);
  return p ? max_count : p - string;

r~

A message that is not in the archive (sent off-list or not yet received): f9bd98f1-d45c-6d3a-c35c-c67da67c881f-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org

#4 lore raw
Quoted 13 lines · Richard Henderson

libfdt/libfdt_env.h static inline fdt64_t cpu_to_fdt64(uint64_t x) · line 134

Quoted 9 lines · John Arbuckle
libfdt/libfdt_env.h +9 -0
+static inline size_t strnlen(const char *string, size_t max_count)
+{
+    size_t count;
+    for (count = 0; count < max_count; count++) {
+        if (string[count] == '\0') {
+            break;
+        }
+    }
+    return count;

Not to nitpick, but

Quoted 2 lines
  const char *p = memchr(string, 0, max_count);
  return p ? max_count : p - string;

Richard's right, that's definitely a better implementation.

Signature · 4 lines
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson
#5 lore raw
Quoted 17 lines · David Gibson
Quoted 13 lines · Richard Henderson

libfdt/libfdt_env.h static inline fdt64_t cpu_to_fdt64(uint64_t x) · line 134

Quoted 9 lines · John Arbuckle
libfdt/libfdt_env.h +9 -0
+static inline size_t strnlen(const char *string, size_t max_count)
+{
+    size_t count;
+    for (count = 0; count < max_count; count++) {
+        if (string[count] == '\0') {
+            break;
+        }
+    }
+    return count;

Not to nitpick, but

Quoted 4 lines
Quoted 2 lines

const char *p = memchr(string, 0, max_count);
return p ? max_count : p - string;

Richard's right, that's definitely a better implementation.

His implementation is smaller, but this one is even smaller. Plus it uses the familiar strlen() function:

size_t strnlen(const char *string, size_t max_count)

{
    return strlen(string) < max_count ? strlen(string) : max_count;
}
#6 lore raw
Quoted 7 lines

... this one is even smaller. Plus it uses the familiar strlen() function:

size_t strnlen(const char *string, size_t max_count)

{
     return strlen(string) < max_count ? strlen(string) : max_count;
}

Please do not use that implementation.
The major goal of strnlen is to avoid looking beyond &string[max_count]. strlen(string) looks all the way to the end, which may be very much longer than max_count; and which may cause SIGSEGV by running into a memory page that does not exist before the terminating '\0' is found.
[Besides, some compilers do not recognize that "strlen(string)"
need not be evaluated twice.]

A message that is not in the archive (sent off-list or not yet received): 82BA0070-FFBB-4868-AE48-D7A3671621C5-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org

#8 lore raw
Quoted 20 lines · Programmingkid
Quoted 20 lines · David Gibson
Quoted 16 lines · Richard Henderson

Review

Quoted 10 lines · John Arbuckle
(quoted diff) +9 -0
+static inline size_t strnlen(const char *string, size_t max_count)
+{
+    size_t count;
+    for (count = 0; count < max_count; count++) {
+        if (string[count] == '\0') {
+            break;
+        }
+    }
+    return count;

Not to nitpick, but

 const char *p = memchr(string, 0, max_count);
 return p ? max_count : p - string;

Quoted 7 lines
Quoted 1 line

Richard's right, that's definitely a better implementation.

His implementation is smaller, but this one is even smaller. Plus it uses the familiar strlen() function:

size_t strnlen(const char *string, size_t max_count)
{
    return strlen(string) < max_count ? strlen(string) : max_count; }

That is not a proper implementation of strnlen(), which is not supposed to access any source-string bytes beyond max_count.

-- Ian

A message that is not in the archive (sent off-list or not yet received): [email protected]

#10 lore raw
Quoted 32 lines · Ian Lepore
Quoted 20 lines · Programmingkid
Quoted 20 lines · David Gibson
Quoted 16 lines · Richard Henderson

Review

Quoted 10 lines · John Arbuckle
(quoted diff) +9 -0
+static inline size_t strnlen(const char *string, size_t max_count)
+{
+    size_t count;
+    for (count = 0; count < max_count; count++) {
+        if (string[count] == '\0') {
+            break;
+        }
+    }
+    return count;

Not to nitpick, but

const char *p = memchr(string, 0, max_count);
return p ? max_count : p - string;

Quoted 7 lines
Quoted 1 line

Richard's right, that's definitely a better implementation.

His implementation is smaller, but this one is even smaller. Plus it uses the familiar strlen() function:

size_t strnlen(const char *string, size_t max_count)

{
    return strlen(string) < max_count ? strlen(string) : max_count;
}
Quoted 4 lines

That is not a proper implementation of strnlen(), which is not supposed to access any source-string bytes beyond max_count.

-- Ian

http://pubs.opengroup.org/onlinepubs/9699919799/functions/strlen.html
This specification document should help anyone who wants more info.

The first implementation using the loop would never access anything beyond max_count. My second implementation does go beyond max_count. The implementation using memchr() will probably live up the requirement so I guess it wins.

Thank you Ian for this information.

#11 lore raw
In reply to David Gibson
Quoted 17 lines · David Gibson
Quoted 13 lines · Richard Henderson

libfdt/libfdt_env.h static inline fdt64_t cpu_to_fdt64(uint64_t x) · line 134

Quoted 9 lines · John Arbuckle
libfdt/libfdt_env.h +9 -0
+static inline size_t strnlen(const char *string, size_t max_count)
+{
+    size_t count;
+    for (count = 0; count < max_count; count++) {
+        if (string[count] == '\0') {
+            break;
+        }
+    }
+    return count;

Not to nitpick, but

Quoted 4 lines
Quoted 2 lines

const char *p = memchr(string, 0, max_count);
return p ? max_count : p - string;

Richard's right, that's definitely a better implementation.

I was just wondering, what if we rewrote the code to use strlen() instead of strnlen(). Would that be an acceptable solution?

A message that is not in the archive (sent off-list or not yet received): 4CE427C5-BD1A-4911-9B10-CC1C0F80FD12-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org

#13 lore raw
Quoted 17 lines · Programmingkid
Quoted 17 lines · David Gibson
Quoted 13 lines · Richard Henderson

Review

Quoted 9 lines · John Arbuckle
(quoted diff) +9 -0
+static inline size_t strnlen(const char *string, size_t max_count)
+{
+    size_t count;
+    for (count = 0; count < max_count; count++) {
+        if (string[count] == '\0') {
+            break;
+        }
+    }
+    return count;

Not to nitpick, but

Quoted 7 lines
Quoted 4 lines
Quoted 2 lines

const char *p = memchr(string, 0, max_count);
return p ? max_count : p - string;

Richard's right, that's definitely a better implementation.

I was just wondering, what if we rewrote the code to use strlen() instead of strnlen(). Would that be an acceptable solution?

Only if you can do so safely - i.e. without accessing memory beyond what we're supposed to. I don't think you'll be able to do that without effectively re-implementing strnlen(), there's a reason I used it in the first place, after all.

Signature · 4 lines
David Gibson			| I'll have my music baroque, and my code
david AT gibson.dropbear.id.au	| minimalist, thank you.  NOT _the_ _other_
				| _way_ _around_!
http://www.ozlabs.org/~dgibson
#14 lore raw
In reply to a message not in the archive
Quoted 13 lines · Richard Henderson

libfdt/libfdt_env.h static inline fdt64_t cpu_to_fdt64(uint64_t x) · line 134

Quoted 9 lines · John Arbuckle
libfdt/libfdt_env.h +9 -0
+static inline size_t strnlen(const char *string, size_t max_count)
+{
+    size_t count;
+    for (count = 0; count < max_count; count++) {
+        if (string[count] == '\0') {
+            break;
+        }
+    }
+    return count;

Not to nitpick, but

Quoted 2 lines
  const char *p = memchr(string, 0, max_count);
  return p ? max_count : p - string;

Am I misreading that, or do you have the ?: arms the wrong way around there?

thanks
-- PMM

A message that is not in the archive (sent off-list or not yet received): CAFEAcA8WnzZpdTWjJafLDjTCOpT_=azr6T+8UAnMNyDiD2ZxAQ-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org

#16 lore raw
Quoted 18 lines · Peter Maydell
Quoted 13 lines · Richard Henderson

libfdt/libfdt_env.h static inline fdt64_t cpu_to_fdt64(uint64_t x) · line 134

Quoted 9 lines · John Arbuckle
libfdt/libfdt_env.h +9 -0
+static inline size_t strnlen(const char *string, size_t max_count)
+{
+    size_t count;
+    for (count = 0; count < max_count; count++) {
+        if (string[count] == '\0') {
+            break;
+        }
+    }
+    return count;

Not to nitpick, but

Quoted 8 lines
Quoted 2 lines

const char *p = memchr(string, 0, max_count);
return p ? max_count : p - string;

Am I misreading that, or do you have the ?: arms the wrong way around there?

thanks
-- PMM

Yes. It should read:

return p ? p - string : max_count;