From: Michal Privoznik <mprivozn@xxxxxxxxxx> The code adaptation is not done right now, but in subsequent patches. Hence I am not implementing syntax-check rule as it would break compilation. Developers are strongly advised to use these new macros. They are similar to VIR_ALLOC() logic: VIR_STRDUP(dst, src) returns zero on success, -1 otherwise. In case you don't want to report OOM error, use the _QUIET variant of a macro. Conflicts: src/libvirt_private.syms src/util/virstring.h (cherry picked from commit c3abb5c45988a0d7583f059974513722d82e2c2b) --- HACKING | 11 +++++++ docs/hacking.html.in | 14 +++++++++ src/libvirt_private.syms | 2 ++ src/util/virstring.c | 74 ++++++++++++++++++++++++++++++++++++++++++++++++ src/util/virstring.h | 60 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 161 insertions(+) diff --git a/HACKING b/HACKING index 69ea96b..5b5c34b 100644 --- a/HACKING +++ b/HACKING @@ -535,6 +535,17 @@ sizeof(dest) returns something meaningful). Note that this is a macro, so arguments could be evaluated more than once. This is equivalent to virStrncpy(dest, src, strlen(src), sizeof(dest)). + VIR_STRDUP(char *dst, const char *src); + VIR_STRNDUP(char *dst, const char *src, size_t n); + +You should avoid using strdup or strndup directly as they do not report +out-of-memory error. Use VIR_STRDUP or VIR_STRNDUP macros instead. Note, that +these two behave similar to VIR_ALLOC: on success zero is returned, otherwise +the result is -1 and dst is guaranteed to be NULL. In very specific cases, +when you don't want to report the out-of-memory error, you can use +VIR_STRDUP_QUIET or VIR_STRNDUP_QUIET, but such usage is very rare and usually +considered a flaw. + Variable length string buffer ============================= diff --git a/docs/hacking.html.in b/docs/hacking.html.in index 89f9980..198afe7 100644 --- a/docs/hacking.html.in +++ b/docs/hacking.html.in @@ -641,6 +641,20 @@ virStrncpy(dest, src, strlen(src), sizeof(dest)). </p> +<pre> + VIR_STRDUP(char *dst, const char *src); + VIR_STRNDUP(char *dst, const char *src, size_t n); +</pre> + <p> + You should avoid using strdup or strndup directly as they do not report + out-of-memory error. Use VIR_STRDUP or VIR_STRNDUP macros instead. Note, + that these two behave similar to VIR_ALLOC: on success zero is returned, + otherwise the result is -1 and dst is guaranteed to be NULL. In very + specific cases, when you don't want to report the out-of-memory error, you + can use VIR_STRDUP_QUIET or VIR_STRNDUP_QUIET, but such usage is very rare + and usually considered a flaw. + </p> + <h2><a name="strbuf">Variable length string buffer</a></h2> <p> diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index f35fd63..21b593a 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1495,9 +1495,11 @@ virStrerror; # virstring.h +virStrdup; virStringSplit; virStringJoin; virStringFreeList; +virStrndup; # virtime.h diff --git a/src/util/virstring.c b/src/util/virstring.c index 92289eb..21142b4 100644 --- a/src/util/virstring.c +++ b/src/util/virstring.c @@ -177,3 +177,77 @@ size_t virStringListLength(char **strings) return i; } + +/** + * virStrdup: + * @dest: where to store duplicated string + * @src: the source string to duplicate + * @report: whether to report OOM error, if there is one + * @domcode: error domain code + * @filename: caller's filename + * @funcname: caller's funcname + * @linenr: caller's line number + * + * Wrapper over strdup, which reports OOM error if told so, + * in which case callers wants to pass @domcode, @filename, + * @funcname and @linenr which should represent location in + * caller's body where virStrdup is called from. Consider + * using VIR_STRDUP which sets these automatically. + * + * Returns: 0 on success, -1 otherwise. + */ +int +virStrdup(char **dest, + const char *src, + bool report, + int domcode, + const char *filename, + const char *funcname, + size_t linenr) +{ + if (!(*dest = strdup(src))) { + if (report) + virReportOOMErrorFull(domcode, filename, funcname, linenr); + return -1; + } + + return 0; +} + +/** + * virStrndup: + * @dest: where to store duplicated string + * @src: the source string to duplicate + * @n: how many bytes to copy + * @report: whether to report OOM error, if there is one + * @domcode: error domain code + * @filename: caller's filename + * @funcname: caller's funcname + * @linenr: caller's line number + * + * Wrapper over strndup, which reports OOM error if told so, + * in which case callers wants to pass @domcode, @filename, + * @funcname and @linenr which should represent location in + * caller's body where virStrndup is called from. Consider + * using VIR_STRNDUP which sets these automatically. + * + * Returns: 0 on success, -1 otherwise. + */ +int +virStrndup(char **dest, + const char *src, + size_t n, + bool report, + int domcode, + const char *filename, + const char *funcname, + size_t linenr) +{ + if (!(*dest = strndup(src, n))) { + if (report) + virReportOOMErrorFull(domcode, filename, funcname, linenr); + return -1; + } + + return 0; +} diff --git a/src/util/virstring.h b/src/util/virstring.h index d68ed2f..cd5ccda 100644 --- a/src/util/virstring.h +++ b/src/util/virstring.h @@ -37,4 +37,64 @@ void virStringFreeList(char **strings); size_t virStringListLength(char **strings); +/* Don't call these directly - use the macros below */ +int virStrdup(char **dest, const char *src, bool report, int domcode, + const char *filename, const char *funcname, size_t linenr) + ATTRIBUTE_RETURN_CHECK ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); + +int virStrndup(char **dest, const char *src, size_t n, bool report, int domcode, + const char *filename, const char *funcname, size_t linenr) + ATTRIBUTE_RETURN_CHECK ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2); + +/** + * VIR_STRDUP: + * @dst: variable to hold result (char*, not char**) + * @src: string to duplicate + * + * Duplicate @src string and store it into @dst. + * + * Returns -1 on failure (with OOM error reported), 0 on success + */ +# define VIR_STRDUP(dst, src) virStrdup(&(dst), src, true, VIR_FROM_THIS, \ + __FILE__, __FUNCTION__, __LINE__) + +/** + * VIR_STRDUP_QUIET: + * @dst: variable to hold result (char*, not char**) + * @src: string to duplicate + * + * Duplicate @src string and store it into @dst. + * + * Returns -1 on failure, 0 on success + */ +# define VIR_STRDUP_QUIET(dst, src) virStrdup(&(dst), src, false, 0, NULL, NULL, 0) + +/** + * VIR_STRNDUP: + * @dst: variable to hold result (char*, not char**) + * @src: string to duplicate + * @n: the maximum number of bytes to copy + * + * Duplicate @src string and store it into @dst. If @src is longer than @n, + * only @n bytes are copied and terminating null byte '\0' is added. + * + * Returns -1 on failure (with OOM error reported), 0 on success + */ +# define VIR_STRNDUP(dst, src, n) virStrndup(&(dst), src, n, true, \ + VIR_FROM_THIS, __FILE__, \ + __FUNCTION__, __LINE__) + +/** + * VIR_STRNDUP_QUIET: + * @dst: variable to hold result (char*, not char**) + * @src: string to duplicate + * @n: the maximum number of bytes to copy + * + * Duplicate @src string and store it into @dst. If @src is longer than @n, + * only @n bytes are copied and terminating null byte '\0' is added. + * + * Returns -1 on failure, 0 on success + */ +# define VIR_STRNDUP_QUIET(dst, src, n) virStrndup(&(dst), src, n, false, \ + 0, NULL, NULL, 0) #endif /* __VIR_STRING_H__ */ -- 1.8.5.2 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list