diff options
author | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2021-12-19 02:38:04 +0100 |
---|---|---|
committer | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2021-12-19 02:38:04 +0100 |
commit | 3614e5877818a3f3e187b43f8247cabaf842c39f (patch) | |
tree | b93802bf8a26fbebb3c9068b273c8a92e0a97afd /src/string-utils.h | |
parent | 4ccae4f8c6e9724c7b5a891aecfe37475549ee6a (diff) | |
download | sciteco-3614e5877818a3f3e187b43f8247cabaf842c39f.tar.gz |
safer use of memcpy() and memchr(): we must not pass in NULL pointers
* The C standard actually forbids this (undefined behaviour) even though
it seems intuitive that something like `memcpy(foo, NULL, 0)` does no harm.
* It turned out, there were actual real bugs related to this.
If memchr() was called with a variable that can be NULL,
the compiler could assume that the variable is actually always non-NULL
(since glibc declares memchr() with nonnull), consequently eliminating
checks for NULL afterwards.
The same could theoretically happen with memcpy().
This manifested itself in the empty search crashing when building with -O3.
Test case:
sciteco -e '@S//'
* Consequently, the nightly builds (at least for Ubuntu) also had this bug.
* In some cases, the passed in pointers are passed down from the caller but
should not be NULL, so I added runtime assertions to guard against it.
Diffstat (limited to 'src/string-utils.h')
-rw-r--r-- | src/string-utils.h | 17 |
1 files changed, 13 insertions, 4 deletions
diff --git a/src/string-utils.h b/src/string-utils.h index 40f1b21..3fb37dc 100644 --- a/src/string-utils.h +++ b/src/string-utils.h @@ -67,7 +67,8 @@ static inline void teco_string_init(teco_string_t *target, const gchar *str, gsize len) { target->data = g_malloc(len + 1); - memcpy(target->data, str, len); + if (str) + memcpy(target->data, str, len); target->len = len; target->data[target->len] = '\0'; } @@ -98,7 +99,8 @@ static inline void teco_string_append(teco_string_t *target, const gchar *str, gsize len) { target->data = g_realloc(target->data, target->len + len + 1); - memcpy(target->data + target->len, str, len); + if (str) + memcpy(target->data + target->len, str, len); target->len += len; target->data[target->len] = '\0'; } @@ -147,10 +149,17 @@ gint teco_string_casecmp(const teco_string_t *a, const gchar *b, gsize b_len); static inline gboolean teco_string_contains(const teco_string_t *str, gchar chr) { - return memchr(str->data, chr, str->len) != NULL; + return str->data && memchr(str->data, chr, str->len); } -/** @memberof teco_string_t */ +/** + * Get index of character in string. + * + * @return Index of character in string. 0 refers to the first character. + * In case of search failure, a negative value is returned. + * + * @memberof teco_string_t + */ static inline gint teco_string_rindex(const teco_string_t *str, gchar chr) { |