From c3abb5c45988a0d7583f059974513722d82e2c2b Mon Sep 17 00:00:00 2001 From: Michal Privoznik Date: Wed, 3 Apr 2013 14:51:20 +0200 Subject: [PATCH] virstring: Introduce VIR_STRDUP and VIR_STRNDUP 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. --- HACKING | 11 ++++++ docs/hacking.html.in | 14 ++++++++ src/libvirt_private.syms | 2 ++ src/util/virstring.c | 74 ++++++++++++++++++++++++++++++++++++++++ src/util/virstring.h | 62 +++++++++++++++++++++++++++++++++ 5 files changed, 163 insertions(+) diff --git a/HACKING b/HACKING index e8bebd48e7..b70b89d016 100644 --- a/HACKING +++ b/HACKING @@ -719,6 +719,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 64cdcc2ee8..b15d18711c 100644 --- a/docs/hacking.html.in +++ b/docs/hacking.html.in @@ -855,6 +855,20 @@ 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/src/libvirt_private.syms b/src/libvirt_private.syms index 98660dc2b3..d4cb4a3b58 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1751,11 +1751,13 @@ virSkipSpaces; virSkipSpacesAndBackslash; virSkipSpacesBackwards; virStrcpy; +virStrdup; virStringArrayHasString; virStringFreeList; virStringJoin; virStringSplit; virStrncpy; +virStrndup; virStrToDouble; virStrToLong_i; virStrToLong_l; diff --git a/src/util/virstring.c b/src/util/virstring.c index 9b4cb0141b..394a558587 100644 --- a/src/util/virstring.c +++ b/src/util/virstring.c @@ -515,3 +515,77 @@ virArgvToString(const char *const *argv) return ret; } + +/** + * 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 457caa2fb5..4fba53b1bf 100644 --- a/src/util/virstring.h +++ b/src/util/virstring.h @@ -87,4 +87,66 @@ char *virStrncpy(char *dest, const char *src, size_t n, size_t destbytes) char *virStrcpy(char *dest, const char *src, size_t destbytes) ATTRIBUTE_RETURN_CHECK; # define virStrcpyStatic(dest, src) virStrcpy((dest), (src), sizeof(dest)) + + +/* 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__ */