Following r1543145, the attached patch adds __attribute__((sentinel)) to
functions that require a null sentinel argument, to make GCC warn if the
argument is missing. Via a macro so only for GCC >= 4.0. (I don't see an
equivalent attribute for MSC but if there is one we can add it.)

The patch also changes SVN_NO_ERROR from "0" to "((svn_error_t *)0)". This
has the side effect of detecting other mis-uses: I committed two such fixes
as http://svn.apache.org/r1543193 and http://svn.apache.org/r1543216 . I
can't think of any negative consequences but shout out if you can.

If no objections I'll commit tomorrow.

- Julian
Following r1543145 (fixing a 'strange error' caused by a missing sentinel
argument), tag the functions that require a null sentinel value at the end
of their argument list such that GCC will warn if the sentinel argument is
missing.

I enabled this for GCC >= 4.0, according to anecdotal evidence. I don't see
an equivalent attribute for MSC but if there is one we can add it.

* subversion/include/svn_types.h
  (SVN_SENTINEL_NULL): Define.

* subversion/include/svn_dirent_uri.h
  (svn_dirent_join_many): Tag.

* subversion/include/svn_path.h
  (svn_path_join_many): Tag.

* subversion/include/svn_xml.h
  (svn_xml_make_open_tag): Tag.

* subversion/libsvn_ra_serf/ra_serf.h
  (svn_ra_serf__add_open_tag_buckets): Tag.

* subversion/svn/cl.h
  (svn_cl__try): Tag.

* subversion/include/svn_error.h
  (SVN_NO_ERROR): Define as a pointer type so that it can be detected as a
    valid sentinel argument (with svn_cl__try). This will also help to
    detect mis-use in other contexts.
--This line, and those below, will be ignored--
Index: subversion/include/svn_dirent_uri.h
===================================================================
--- subversion/include/svn_dirent_uri.h	(revision 1543175)
+++ subversion/include/svn_dirent_uri.h	(working copy)
@@ -215,13 +215,13 @@ svn_dirent_join(const char *base,
  *
  * @since New in 1.6.
  */
 char *
 svn_dirent_join_many(apr_pool_t *result_pool,
                      const char *base,
-                     ...);
+                     ...) SVN_SENTINEL_NULL;
 
 /** Join a base relpath (@a base) with a component (@a component).
  * @a component need not be a single component.
  *
  * If either @a base or @a component is the empty path, then the other
  * argument will be copied and returned.  If both are the empty path the
Index: subversion/include/svn_error.h
===================================================================
--- subversion/include/svn_error.h	(revision 1543175)
+++ subversion/include/svn_error.h	(working copy)
@@ -48,13 +48,13 @@ extern "C" {
 #ifdef SVN_DEBUG
 #define SVN_ERR__TRACING
 #endif
 
 
 /** the best kind of (@c svn_error_t *) ! */
-#define SVN_NO_ERROR   0
+#define SVN_NO_ERROR   ((svn_error_t *)0)
 
 /* The actual error codes are kept in a separate file; see comments
    there for the reasons why. */
 #include "svn_error_codes.h"
 
 /** Put an English description of @a statcode into @a buf and return @a buf,
Index: subversion/include/svn_path.h
===================================================================
--- subversion/include/svn_path.h	(revision 1543175)
+++ subversion/include/svn_path.h	(working copy)
@@ -128,13 +128,13 @@ svn_path_join(const char *base, const ch
  * @deprecated Provided for backward compatibility with the 1.6 API.
  * For new code, consider using svn_dirent_join_many() or a sequence of
  * calls to one of the *_join() functions.
  */
 SVN_DEPRECATED
 char *
-svn_path_join_many(apr_pool_t *pool, const char *base, ...);
+svn_path_join_many(apr_pool_t *pool, const char *base, ...) SVN_SENTINEL_NULL;
 
 
 /** Get the basename of the specified canonicalized @a path.  The
  * basename is defined as the last component of the path (ignoring any
  * trailing slashes).  If the @a path is root ("/"), then that is
  * returned.  Otherwise, the returned value will have no slashes in
Index: subversion/include/svn_types.h
===================================================================
--- subversion/include/svn_types.h	(revision 1543175)
+++ subversion/include/svn_types.h	(working copy)
@@ -86,12 +86,34 @@ extern "C" {
 #  endif
 # else
 #  define SVN_EXPERIMENTAL
 # endif
 #endif
 
+/** Macro used to mark functions that require a final null sentinel argument.
+ *
+ * @since New in 1.9.
+ */
+#ifndef SVN_SENTINEL_NULL
+# if !defined(SWIGPERL) && !defined(SWIGPYTHON) && !defined(SWIGRUBY)
+#  if defined(__has_attribute)
+#    if __has_attribute(__sentinel__)
+#      define SVN_SENTINEL_NULL __attribute__((sentinel))
+#    else
+#      define SVN_SENTINEL_NULL
+#    endif
+#  elif defined(__GNUC__) && (__GNUC__ >= 4)
+#   define SVN_SENTINEL_NULL __attribute__((sentinel))
+#  else
+#   define SVN_SENTINEL_NULL
+#  endif
+# else
+#  define SVN_SENTINEL_NULL
+# endif
+#endif
+
 
 /** Indicate whether the current platform supports unaligned data access.
  *
  * On the majority of machines running SVN (x86 / x64), unaligned access
  * is much cheaper than repeated aligned access. Define this macro to 1
  * on those machines.
Index: subversion/include/svn_xml.h
===================================================================
--- subversion/include/svn_xml.h	(revision 1543175)
+++ subversion/include/svn_xml.h	(working copy)
@@ -320,13 +320,13 @@ svn_xml_make_header(svn_stringbuf_t **st
  */
 void
 svn_xml_make_open_tag(svn_stringbuf_t **str,
                       apr_pool_t *pool,
                       enum svn_xml_open_tag_style style,
                       const char *tagname,
-                      ...);
+                      ...) SVN_SENTINEL_NULL;
 
 
 /** Like svn_xml_make_open_tag(), but takes a @c va_list instead of being
  * variadic.
  */
 void
Index: subversion/libsvn_ra_serf/ra_serf.h
===================================================================
--- subversion/libsvn_ra_serf/ra_serf.h	(revision 1543175)
+++ subversion/libsvn_ra_serf/ra_serf.h	(working copy)
@@ -1052,13 +1052,13 @@ svn_ra_serf__add_xml_header_buckets(serf
  * The bucket will be allocated from BKT_ALLOC.
  */
 void
 svn_ra_serf__add_open_tag_buckets(serf_bucket_t *agg_bucket,
                                   serf_bucket_alloc_t *bkt_alloc,
                                   const char *tag,
-                                  ...);
+                                  ...) SVN_SENTINEL_NULL;
 
 /*
  * Add the appropriate serf buckets to AGG_BUCKET representing xml tag close
  * with name TAG.
  *
  * The bucket will be allocated from BKT_ALLOC.
Index: subversion/svn/cl.h
===================================================================
--- subversion/svn/cl.h	(revision 1543175)
+++ subversion/svn/cl.h	(working copy)
@@ -323,13 +323,13 @@ extern const apr_getopt_option_t svn_cl_
  * forget to terminate the argument list with SVN_NO_ERROR.
  */
 svn_error_t *
 svn_cl__try(svn_error_t *err,
             apr_array_header_t *errors_seen,
             svn_boolean_t quiet,
-            ...);
+            ...) SVN_SENTINEL_NULL;
 
 
 /* Our cancellation callback. */
 svn_error_t *
 svn_cl__check_cancel(void *baton);
 

Reply via email to