On 04/29/2013 07:50 AM, Michal Privoznik wrote:
s/STRUP/STRDUP/ in the subject line.
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 _QUIET variant of a macro.
s/use/use the/
Thinking about backportability - it looks like Fedora 19 will probably
be based on libvirt 1.0.5 + patches. I'm hoping that if we backport
this patch, but not the syntax check or the general cleanups of using
VIR_STRDUP everywhere, then further backports of any new code that uses
VIR_STRDUP can be done by using this interface, and any merge conflicts
of code that used to use strdup should be fairly easy to resolve during
the backport process (of course, the IDEAL situation is that 1.0.5
doesn't have any bugs that require backporting across this refactoring,
right? :)
+++ b/docs/hacking.html.in
@@ -853,6 +853,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 the does not report
s/the does/they do/
+ out-of-memory error. Use VIR_STRDUP() or VIR_STRNDUP macros
instead.
+ Note, that these two behave in similar way to VIR_ALLOC: on success zero
s/in similar way/similar/
+ is returned, otherwise caller is left with negative one. In
very specific
s/caller is left with negative one/the result is -1 and dst is
guaranteed to be NULL/
+ case, when you don't want to report the out-of-memory
error, you can use
s/case/cases/
+ 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>
+++ 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's a one
s/there's a/there is/
+ * @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 othervise.
s/othervise/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's a one
s/there's a/there is/
+ * @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 virStrdup is called from. Consider
s/virStrdup/virStrndup/
+ * using VIR_STRNDUP which sets these automatically.
+ *
+ * Returns: 0 on success, -1 othervise.
s/othervise/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;
+}
Implementation of the helper functions looks correct.
diff --git a/src/util/virstring.h b/src/util/virstring.h
index 457caa2..620efba 100644
--- a/src/util/virstring.h
+++ b/src/util/virstring.h
@@ -87,4 +87,24 @@ 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))
+
+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);
+
+/* XXX Don't report OOM error for now, unless all code is adapted. */
I disagree. Since the calling convention changed, anywhere that we use
VIR_STRDUP should already be dealing with the new semantics of expecting
VIR_STRDUP to report the error. Passing false only made sense if you
were trying to make VIR_STRDUP a drop-in replacement for strdup (where
you could save work by doing a global search-and-replace for the
drop-in, then revisit code later for the new semantics). But since you
already have to revisit semantics for this macro, you might as well
assume OOM reporting from the beginning, by...
+# define VIR_STRDUP(dst, src) virStrdup(&(dst), src, false,
VIR_FROM_THIS, \
+ __FILE__, __FUNCTION__, __LINE__)
...doing s/false/true/
+# define VIR_STRDUP_QUIET(dst, src) virStrdup(&(dst), src,
false, 0, NULL, NULL, 0)
+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);
It is hard to read function and macro declarations intermixed like this.
I would much rather see this done like viralloc.h, by separating the
function declarations up front (and with a BIG disclaimer that most code
should not use it directly), then the macros down below, and with full
documentation of the macros (since their arguments are slightly
different than the arguments of the functions).
+
+/* XXX Don't report OOM error for now, unless all code is adapted. */
+# define VIR_STRNDUP(dst, src, n) virStrndup(&(dst), src, n, false, \
+ VIR_FROM_THIS, __FILE__, \
+ __FUNCTION__, __LINE__)
Again, s/false/true/ since you are already changing calling conventions
on anywhere converted to use this macro.
+
+# define VIR_STRNDUP_QUIET(dst, src, n) virStrndup(&(dst), src, n, false, \
+ 0, NULL, NULL, 0)
#endif /* __VIR_STRING_H__ */
Getting closer. Looking forward to v3.
--
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library
http://libvirt.org