logd: log_strtok_r deal with nuls
Rename to log_strntok_r and change from dealing with strings
to dealing with a string and an associated length.
Bug: 23517551
Change-Id: Ia72f1305a53f55eeef9861ac378fb8205fd2378e
diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp
index 0965ffd..f0b18da 100644
--- a/logd/LogKlog.cpp
+++ b/logd/LogKlog.cpp
@@ -39,14 +39,15 @@
// Parsing is hard
// called if we see a '<', s is the next character, returns pointer after '>'
-static char *is_prio(char *s) {
- if (!isdigit(*s++)) {
+static char *is_prio(char *s, size_t len) {
+ if (!len || !isdigit(*s++)) {
return NULL;
}
- static const size_t max_prio_len = 4;
- size_t len = 0;
+ --len;
+ static const size_t max_prio_len = (len < 4) ? len : 4;
+ size_t priolen = 0;
char c;
- while (((c = *s++)) && (++len <= max_prio_len)) {
+ while (((c = *s++)) && (++priolen <= max_prio_len)) {
if (!isdigit(c)) {
return ((c == '>') && (*s == '[')) ? s : NULL;
}
@@ -55,16 +56,19 @@
}
// called if we see a '[', s is the next character, returns pointer after ']'
-static char *is_timestamp(char *s) {
- while (*s == ' ') {
+static char *is_timestamp(char *s, size_t len) {
+ while (len && (*s == ' ')) {
++s;
+ --len;
}
- if (!isdigit(*s++)) {
+ if (!len || !isdigit(*s++)) {
return NULL;
}
+ --len;
bool first_period = true;
char c;
- while ((c = *s++)) {
+ while (len && ((c = *s++))) {
+ --len;
if ((c == '.') && first_period) {
first_period = false;
} else if (!isdigit(c)) {
@@ -85,7 +89,11 @@
// space is one more than <digit> of 9
#define OPEN_BRACKET_SPACE ((char)(OPEN_BRACKET_SIG | 10))
-char *log_strtok_r(char *s, char **last) {
+char *log_strntok_r(char *s, size_t *len, char **last, size_t *sublen) {
+ *sublen = 0;
+ if (!*len) {
+ return NULL;
+ }
if (!s) {
if (!(s = *last)) {
return NULL;
@@ -95,6 +103,7 @@
if ((*s & SIGNATURE_MASK) == LESS_THAN_SIG) {
*s = (*s & ~SIGNATURE_MASK) + '0';
*--s = '<';
+ ++*len;
}
// fixup for log signature split [,
// OPEN_BRACKET_SPACE is space, OPEN_BRACKET_SIG + <digit>
@@ -105,24 +114,30 @@
*s = (*s & ~SIGNATURE_MASK) + '0';
}
*--s = '[';
+ ++*len;
}
}
- s += strspn(s, "\r\n");
+ while (*len && ((*s == '\r') || (*s == '\n'))) {
+ ++s;
+ --*len;
+ }
- if (!*s) { // no non-delimiter characters
+ if (!*len) {
*last = NULL;
return NULL;
}
char *peek, *tok = s;
for (;;) {
- char c = *s++;
- switch (c) {
- case '\0':
+ if (*len == 0) {
*last = NULL;
return tok;
-
+ }
+ char c = *s++;
+ --*len;
+ size_t adjust;
+ switch (c) {
case '\r':
case '\n':
s[-1] = '\0';
@@ -130,7 +145,7 @@
return tok;
case '<':
- peek = is_prio(s);
+ peek = is_prio(s, *len);
if (!peek) {
break;
}
@@ -141,14 +156,26 @@
*last = s;
return tok;
}
+ adjust = peek - s;
+ if (adjust > *len) {
+ adjust = *len;
+ }
+ *sublen += adjust;
+ *len -= adjust;
s = peek;
- if ((*s == '[') && ((peek = is_timestamp(s + 1)))) {
+ if ((*s == '[') && ((peek = is_timestamp(s + 1, *len - 1)))) {
+ adjust = peek - s;
+ if (adjust > *len) {
+ adjust = *len;
+ }
+ *sublen += adjust;
+ *len -= adjust;
s = peek;
}
break;
case '[':
- peek = is_timestamp(s);
+ peek = is_timestamp(s, *len);
if (!peek) {
break;
}
@@ -163,9 +190,16 @@
*last = s;
return tok;
}
+ adjust = peek - s;
+ if (adjust > *len) {
+ adjust = *len;
+ }
+ *sublen += adjust;
+ *len -= adjust;
s = peek;
break;
}
+ ++*sublen;
}
// NOTREACHED
}
@@ -212,13 +246,13 @@
bool full = len == (sizeof(buffer) - 1);
char *ep = buffer + len;
*ep = '\0';
- len = 0;
+ size_t sublen;
for(char *ptr = NULL, *tok = buffer;
- ((tok = log_strtok_r(tok, &ptr)));
+ ((tok = log_strntok_r(tok, &len, &ptr, &sublen)));
tok = NULL) {
- if (((tok + strlen(tok)) == ep) && (retval != 0) && full) {
- len = strlen(tok);
- memmove(buffer, tok, len);
+ if (((tok + sublen) >= ep) && (retval != 0) && full) {
+ memmove(buffer, tok, sublen);
+ len = sublen;
break;
}
if (*tok) {
diff --git a/logd/LogKlog.h b/logd/LogKlog.h
index 7e4fde0..b0ea864 100644
--- a/logd/LogKlog.h
+++ b/logd/LogKlog.h
@@ -21,7 +21,7 @@
#include <log/log_read.h>
#include "LogReader.h"
-char *log_strtok_r(char *str, char **saveptr);
+char *log_strntok_r(char *s, size_t *len, char **saveptr, size_t *sublen);
class LogKlog : public SocketListener {
LogBuffer *logbuf;
diff --git a/logd/main.cpp b/logd/main.cpp
index f90da37..aa447f9 100644
--- a/logd/main.cpp
+++ b/logd/main.cpp
@@ -282,30 +282,31 @@
return;
}
- int len = klogctl(KLOG_SIZE_BUFFER, NULL, 0);
- if (len <= 0) {
- return;
- }
-
- len += 1024; // Margin for additional input race or trailing nul
- std::unique_ptr<char []> buf(new char[len]);
-
- int rc = klogctl(KLOG_READ_ALL, buf.get(), len);
+ int rc = klogctl(KLOG_SIZE_BUFFER, NULL, 0);
if (rc <= 0) {
return;
}
- if (rc < len) {
+ size_t len = rc + 1024; // Margin for additional input race or trailing nul
+ std::unique_ptr<char []> buf(new char[len]);
+
+ rc = klogctl(KLOG_READ_ALL, buf.get(), len);
+ if (rc <= 0) {
+ return;
+ }
+
+ if ((size_t)rc < len) {
len = rc + 1;
}
- buf[len - 1] = '\0';
+ buf[--len] = '\0';
if (kl) {
kl->synchronize(buf.get());
}
+ size_t sublen;
for (char *ptr = NULL, *tok = buf.get();
- (rc >= 0) && ((tok = log_strtok_r(tok, &ptr)));
+ (rc >= 0) && ((tok = log_strntok_r(tok, &len, &ptr, &sublen)));
tok = NULL) {
if (al) {
rc = al->log(tok);