Commit c3808550 authored by Thomas Haller's avatar Thomas Haller

shared: change nm_utils_strbuf_seek_end() handling truncated strings

Ok, I changed my mind.

The new behavior seems to make more sense to me. Not that it matters,
because we always use nm_utils_strbuf*() API with buffers that we expect
to be large enough to contain the result. And when truncation occurs,
we usually don't care much about it. That is, there is no code that
uses nm_utils_strbuf*() API and handles string truncation in particular.
parent d45e0b65
......@@ -133,9 +133,29 @@ nm_utils_strbuf_append (char **buf, gsize *len, const char *format, ...)
*
* nm_utils_strbuf_append (&buf, &len, ...);
*
* They only behave differently, if the string fits exactly
* into the buffer without truncation. The former cannot distinguish
* the two cases, while the latter can.
* The only difference is the behavior when the string got truncated:
* nm_utils_strbuf_append() will recognize that and set the remaining
* length to zero.
*
* In general, the behavior is:
*
* - if *len is zero, do nothing
* - if the buffer contains a NUL byte within the first *len characters,
* the buffer is pointed to the NUL byte and len is adjusted. In this
* case, the remaining *len is always >= 1.
* In particular, that is also the case if the NUL byte is at the very last
* position ((*buf)[*len -1]). That happens, when the previous operation
* either fit the string exactly into the buffer or the string was truncated
* by g_snprintf(). The difference cannot be determined.
* - if the buffer contains no NUL bytes within the first *len characters,
* write NUL at the last position, set *len to zero, and point *buf past
* the NUL byte. This would happen with
*
* strncpy (buf, long_str, len);
* nm_utils_strbuf_seek_end (&buf, &len).
*
* where strncpy() does truncate the string and not NUL terminate it.
* nm_utils_strbuf_seek_end() would then NUL terminate it.
*/
void
nm_utils_strbuf_seek_end (char **buf, gsize *len)
......@@ -146,11 +166,24 @@ nm_utils_strbuf_seek_end (char **buf, gsize *len)
nm_assert (len);
nm_assert (buf && *buf);
if (*len == 0)
if (*len <= 1) {
if ( *len == 1
&& (*buf)[0])
goto truncate;
return;
}
end = memchr (*buf, 0, *len);
if (!end) {
if (end) {
l = end - *buf;
nm_assert (l < *len);
*buf = end;
*len -= l;
return;
}
truncate:
/* hm, no NUL character within len bytes.
* Just NUL terminate the array and consume them
* all. */
......@@ -158,43 +191,6 @@ nm_utils_strbuf_seek_end (char **buf, gsize *len)
(*buf)[-1] = '\0';
*len = 0;
return;
}
l = end - *buf;
nm_assert (l < *len);
*buf = end;
*len -= l;
if (*len == 1) {
/* the last character of a buffer is the '\0'. There are two
* cases why that may happen:
* - but string was truncated
* - the string fit exactly into the buffer.
* Here we cannot distinguish between the two, so assume the string
* was truncated and signal that by setting @len to 0 and pointing the
* buffer *past* the end (like all other nm_utils_strbuf_*() functions).
*
* Note that nm_utils_strbuf_append_str() can distinguish between
* the two cases, and leaves @len at 1, if the string was not actually
* truncated.
*
* For consistancy, it might be better not to do this and just
* seek to end of the buffer (not past it). However, that would mean,
* in a series of
* g_snprintf()
* nm_utils_strbuf_seek_end()
* the length would never reach zero, but stay at 1. With this,
* it reaches len 0 early.
* It seems better to declare the buffer as fully consumed and set
* the length to zero.
*
* If the caller does not care about truncation, then this behavior
* is more sensible. If the caller cares about truncation, it must
* check earlier (right when the truncation occures).
*/
(*buf)++;
*len = 0;
}
}
/*****************************************************************************/
......
......@@ -1485,25 +1485,23 @@ test_nm_utils_strbuf_append (void)
g_assert (t_buf[-1] == '\0');
} else {
nm_utils_strbuf_seek_end (&t_buf, &t_len);
if (strlen (str) + 1 == buf_len) {
/* Special case: we appended a string that fit into the buffer
* exactly, without truncation.
* If we would append the string via nm_utils_strbuf_append(),
* then it would have recognized that the string was not truncated
* and leave len==1, and pointing the buffer to the terminating NUL
* (at the very end, not past it).
if ( buf_len > 0
&& strlen (str) + 1 > buf_len) {
/* the buffer was truncated by g_snprintf() above.
*
* But nm_utils_strbuf_seek_end() cannot distinguish whether
* truncation occured, and assumes the buffer was indeed truncated.
* But nm_utils_strbuf_seek_end() does not recognize that and returns
* a remaining length of 1.
*
* Assert for that, but also adjust the numbers, so that the assertions
* below pass (the assertions below theck for the nm_utils_strbuf_append()
* case). */
g_assert (t_len == 0);
g_assert (t_buf == &buf[buf_len]);
g_assert (t_buf[-1] == '\0');
t_len = 1;
t_buf--;
* Note that other nm_utils_strbuf_append*() functions recognize
* truncation, and properly set the remaining length to zero.
* As the assertions below check for the behavior of nm_utils_strbuf_append*(),
* we assert here that nm_utils_strbuf_seek_end() behaved as expected, and then
* adjust t_buf/t_len according to the "is-truncated" case. */
g_assert (t_len == 1);
g_assert (t_buf == &buf[buf_len - 1]);
g_assert (t_buf[0] == '\0');
t_len = 0;
t_buf++;
}
}
break;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment