diff --git a/HACKING b/HACKING index e8bebd48e7e2a843ac4fa7c7de25bf2247cf8afb..b70b89d016d6f15326ac9832a2cdab43b611b85f 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 64cdcc2ee81b47a0fecafea70049d9da2d93f179..b15d18711c21983669fdfadea854e9db3d3e6af3 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 98660dc2b3520d09182bba85e2b1a4d234662049..d4cb4a3b589a1461953a5409992775102cfb09f7 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 9b4cb0141b591db90b70eff0bcb63403e6eca023..394a558587e66e3f472f44c731084e65a8532dea 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 457caa2fb51ca48926ec106052ea8d410505efa4..4fba53b1bfe8e824b87cc96594235c9498203968 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__ */