This discussion started out on private@ when discussing how far we
should go in fixing the security issue.  With Greg's permission I'm
moving the discussion here:

I'd posted the patch which is attached to this email with some
thoughts about implementing input validation.  And ended with the
following statement:

On Wed, Mar 6, 2013 at 10:22 PM, Ben Reser <[email protected]> wrote:
>> This is actually a pretty common pattern for us to not bother to check
>> incoming arguments, so I'm not sure how the project feels about this
>> in general.

Greg responded as such:

On Wed, Mar 6, 2013 at 7:51 PM, Greg Stein <[email protected]> wrote:
> This is my concern. We said long ago, "if the caller screws up, then
> that is there problem. the function is perfectly entitled to core dump
> on malformed params."

Couple of thoughts on this:

1) In this case the caller is us.  If we can't get this right all the
time, is it really reasonable to expect others to do so?

2) I don't think there is any case where we'd consider dumping core is
appropriate on the server side.  Client side I think is a tad
different.  But in my opinion we should harden the APIs that are
needed on the server side as much as is reasonable.

3) I think it's safe to say that the last 15 years has proven out that
this just isn't a good coding practice.  If you look at secure coding
guidelines you will always find that functions should validate their
arguments.  E.G.
https://www.securecoding.cert.org/confluence/display/seccode/API00-C.+Functions+should+validate+their+parameters

I tend to think there's some middle ground here.  Obviously it's
impossible to check everything.  You'll note that my patch only
checked things that the function was directly dereferencing.

If we'd had this sort of simple checking in place we'd be talking
about a bug fix to our code and not a security issue.  In fact I'd
guess we probably wouldn't be talking about this at all unless someone
asked about the error message in their logs.

> My feeling is that we need to fix the problems in mod_dav_svn rather
> than attempt to paper over them at the lower level.
>
> Your interim solution to deny a PROPFIND on an activity should be just
> fine. We should never need to do that. The activity is just a handle
> on the server-side fs-txn.

Just to be clear I'm 100% in agreement that Philip's patch is correct.
 I just think we should go the extra mile.  We're going to look really
silly if there are similar security issues with different
URLs/methods.  We don't really know how the person found the issue at
hand.  They may very well be continuing to look for similar issues and
may find some other URL we aren't properly handling.  Issues we could
solve now.

An alternative approach would be sitting down and go through all the
access patterns and checking them.  However, I'd expect that to take
time that nobody probably really has right now.  On top of that, this
process needs to be repeated whenever we make changes to mod_dav_svn
to make sure things haven't changed.

Quite frankly as a project I don't think we have the bandwidth to do that.
Index: libsvn_fs/fs-loader.c
===================================================================
--- libsvn_fs/fs-loader.c       (revision 1453607)
+++ libsvn_fs/fs-loader.c       (working copy)
@@ -58,6 +58,17 @@
 
 #define FS_TYPE_FILENAME "fs-type"
 
+#define ENSURE(expr)                                                    \
+  do {                                                                  \
+    if (!(expr))                                                        \
+      SVN_ERR(svn_error_createf(SVN_ERR_INCORRECT_PARAMS, NULL,         \
+              "%s: %s: %s", _("Incorrect parameters given"),            \
+              _("Ensure expression false"), #expr));                    \
+  } while (0)
+
+#define ENSURE_VTABLE(obj, func) \
+    ENSURE(obj && obj->vtable && obj->vtable->func)
+
 /* A pool common to all FS objects.  See the documentation on the
    open/create functions in fs-loader.h and for svn_fs_initialize(). */
 static apr_pool_t *common_pool;
@@ -508,6 +519,8 @@
 const char *
 svn_fs_path(svn_fs_t *fs, apr_pool_t *pool)
 {
+  if (!fs)
+    return NULL;
   return apr_pstrdup(pool, fs->path);
 }
 
@@ -633,6 +646,7 @@
                   svn_revnum_t revision,
                   apr_pool_t *scratch_pool)
 {
+  ENSURE_VTABLE(fs, verify_rev);
   SVN_ERR(fs->vtable->verify_rev(fs, revision, scratch_pool));
 
   return SVN_NO_ERROR;
@@ -644,6 +658,7 @@
               void *baton,
               apr_pool_t *pool)
 {
+  ENSURE_VTABLE(fs, freeze);
   SVN_ERR(fs->vtable->freeze(fs, freeze_body, baton, pool));
 
   return SVN_NO_ERROR;
@@ -657,6 +672,7 @@
 {
   fs_library_vtable_t *vtable;
 
+  ENSURE(fs);
   SVN_ERR(get_library_vtable(&vtable, SVN_FS_TYPE_BDB, fs->pool));
 
   /* Create the FS directory and write out the fsap-name file. */
@@ -674,6 +690,7 @@
 {
   fs_library_vtable_t *vtable;
 
+  ENSURE(fs);
   SVN_ERR(fs_library_vtable(&vtable, path, fs->pool));
   SVN_MUTEX__WITH_LOCK(common_pool_lock,
                        vtable->open_fs(fs, path, fs->pool, common_pool));
@@ -710,6 +727,7 @@
 svn_fs_set_berkeley_errcall(svn_fs_t *fs,
                             void (*handler)(const char *errpfx, char *msg))
 {
+  ENSURE_VTABLE(fs, bdb_set_errcall);
   return svn_error_trace(fs->vtable->bdb_set_errcall(fs, handler));
 }
 
@@ -733,6 +751,7 @@
 svn_fs_begin_txn2(svn_fs_txn_t **txn_p, svn_fs_t *fs, svn_revnum_t rev,
                   apr_uint32_t flags, apr_pool_t *pool)
 {
+  ENSURE_VTABLE(fs, begin_txn);
   return svn_error_trace(fs->vtable->begin_txn(txn_p, fs, rev, flags, pool));
 }
 
@@ -754,7 +773,11 @@
   svn_fs_root_t *txn_root;
   svn_fs_t *fs;
   const char *fs_path;
+#endif
+  
+  ENSURE(new_rev);
 
+#ifdef PACK_AFTER_EVERY_COMMIT
   *new_rev = SVN_INVALID_REVNUM;
   SVN_ERR(svn_fs_txn_root(&txn_root, txn, pool));
   fs = svn_fs_root_fs(txn_root);
@@ -761,6 +784,7 @@
   fs_path = svn_fs_path(fs, pool);
 #endif
 
+  ENSURE_VTABLE(txn, commit);
   err = txn->vtable->commit(conflict_p, new_rev, txn, pool);
 
 #ifdef SVN_DEBUG
@@ -796,6 +820,7 @@
 svn_error_t *
 svn_fs_abort_txn(svn_fs_txn_t *txn, apr_pool_t *pool)
 {
+  ENSURE_VTABLE(txn, abort);
   return svn_error_trace(txn->vtable->abort(txn, pool));
 }
 
@@ -802,6 +827,7 @@
 svn_error_t *
 svn_fs_purge_txn(svn_fs_t *fs, const char *txn_id, apr_pool_t *pool)
 {
+  ENSURE_VTABLE(fs, purge_txn);
   return svn_error_trace(fs->vtable->purge_txn(fs, txn_id, pool));
 }
 
@@ -808,6 +834,7 @@
 svn_error_t *
 svn_fs_txn_name(const char **name_p, svn_fs_txn_t *txn, apr_pool_t *pool)
 {
+  ENSURE(txn);
   *name_p = apr_pstrdup(pool, txn->id);
   return SVN_NO_ERROR;
 }
@@ -815,6 +842,8 @@
 svn_revnum_t
 svn_fs_txn_base_revision(svn_fs_txn_t *txn)
 {
+  if (!txn)
+    return SVN_INVALID_REVNUM;
   return txn->base_rev;
 }
 
@@ -822,6 +851,7 @@
 svn_fs_open_txn(svn_fs_txn_t **txn, svn_fs_t *fs, const char *name,
                 apr_pool_t *pool)
 {
+  ENSURE_VTABLE(fs, open_txn);
   return svn_error_trace(fs->vtable->open_txn(txn, fs, name, pool));
 }
 
@@ -829,6 +859,7 @@
 svn_fs_list_transactions(apr_array_header_t **names_p, svn_fs_t *fs,
                          apr_pool_t *pool)
 {
+  ENSURE_VTABLE(fs, list_transactions);
   return svn_error_trace(fs->vtable->list_transactions(names_p, fs, pool));
 }
 
@@ -836,6 +867,7 @@
 svn_fs_txn_prop(svn_string_t **value_p, svn_fs_txn_t *txn,
                 const char *propname, apr_pool_t *pool)
 {
+  ENSURE_VTABLE(txn, get_prop);
   return svn_error_trace(txn->vtable->get_prop(value_p, txn, propname, pool));
 }
 
@@ -842,6 +874,7 @@
 svn_error_t *
 svn_fs_txn_proplist(apr_hash_t **table_p, svn_fs_txn_t *txn, apr_pool_t *pool)
 {
+  ENSURE_VTABLE(txn, get_proplist);
   return svn_error_trace(txn->vtable->get_proplist(table_p, txn, pool));
 }
 
@@ -849,6 +882,7 @@
 svn_fs_change_txn_prop(svn_fs_txn_t *txn, const char *name,
                        const svn_string_t *value, apr_pool_t *pool)
 {
+  ENSURE_VTABLE(txn, change_prop);
   return svn_error_trace(txn->vtable->change_prop(txn, name, value, pool));
 }
 
@@ -856,6 +890,7 @@
 svn_fs_change_txn_props(svn_fs_txn_t *txn, const apr_array_header_t *props,
                         apr_pool_t *pool)
 {
+  ENSURE_VTABLE(txn, change_props);
   return svn_error_trace(txn->vtable->change_props(txn, props, pool));
 }
 
@@ -866,9 +901,11 @@
 svn_fs_revision_root(svn_fs_root_t **root_p, svn_fs_t *fs, svn_revnum_t rev,
                      apr_pool_t *pool)
 {
+  apr_pool_t *subpool;
+  ENSURE_VTABLE(fs, revision_root);
   /* We create a subpool for each root object to allow us to implement
      svn_fs_close_root.  */
-  apr_pool_t *subpool = svn_pool_create(pool);
+  subpool = svn_pool_create(pool);
   return svn_error_trace(fs->vtable->revision_root(root_p, fs, rev, subpool));
 }
 
@@ -875,9 +912,11 @@
 svn_error_t *
 svn_fs_txn_root(svn_fs_root_t **root_p, svn_fs_txn_t *txn, apr_pool_t *pool)
 {
+  apr_pool_t *subpool;
+  ENSURE_VTABLE(txn, root);
   /* We create a subpool for each root object to allow us to implement
      svn_fs_close_root.  */
-  apr_pool_t *subpool = svn_pool_create(pool);
+  subpool = svn_pool_create(pool);
   return svn_error_trace(txn->vtable->root(root_p, txn, subpool));
 }
 
@@ -884,12 +923,15 @@
 void
 svn_fs_close_root(svn_fs_root_t *root)
 {
-  svn_pool_destroy(root->pool);
+  if (root)
+    svn_pool_destroy(root->pool);
 }
 
 svn_fs_t *
 svn_fs_root_fs(svn_fs_root_t *root)
 {
+  if (!root)
+    return NULL;
   return root->fs;
 }
 
@@ -896,6 +938,8 @@
 svn_boolean_t
 svn_fs_is_txn_root(svn_fs_root_t *root)
 {
+  if (!root)
+    return FALSE;
   return root->is_txn_root;
 }
 
@@ -902,6 +946,8 @@
 svn_boolean_t
 svn_fs_is_revision_root(svn_fs_root_t *root)
 {
+  if (!root)
+    return FALSE;
   return !root->is_txn_root;
 }
 
@@ -908,6 +954,8 @@
 const char *
 svn_fs_txn_root_name(svn_fs_root_t *root, apr_pool_t *pool)
 {
+  if (!root)
+    return NULL;
   return root->is_txn_root ? apr_pstrdup(pool, root->txn) : NULL;
 }
 
@@ -914,6 +962,8 @@
 svn_revnum_t
 svn_fs_txn_root_base_revision(svn_fs_root_t *root)
 {
+  if (!root)
+    return SVN_INVALID_REVNUM;
   return root->is_txn_root ? root->rev : SVN_INVALID_REVNUM;
 }
 
@@ -920,6 +970,8 @@
 svn_revnum_t
 svn_fs_revision_root_revision(svn_fs_root_t *root)
 {
+  if (!root)
+    return SVN_INVALID_REVNUM;
   return root->is_txn_root ? SVN_INVALID_REVNUM : root->rev;
 }
 
@@ -927,6 +979,7 @@
 svn_fs_paths_changed2(apr_hash_t **changed_paths_p, svn_fs_root_t *root,
                       apr_pool_t *pool)
 {
+  ENSURE_VTABLE(root, paths_changed);
   return root->vtable->paths_changed(changed_paths_p, root, pool);
 }
 
@@ -937,6 +990,7 @@
   apr_hash_t *changed_paths_new_structs;
   apr_hash_index_t *hi;
 
+  ENSURE(changed_paths_p);
   SVN_ERR(svn_fs_paths_changed2(&changed_paths_new_structs, root, pool));
   *changed_paths_p = apr_hash_make(pool);
   for (hi = apr_hash_first(pool, changed_paths_new_structs);
@@ -964,6 +1018,7 @@
 svn_fs_check_path(svn_node_kind_t *kind_p, svn_fs_root_t *root,
                   const char *path, apr_pool_t *pool)
 {
+  ENSURE_VTABLE(root, check_path);
   return svn_error_trace(root->vtable->check_path(kind_p, root, path, pool));
 }
 
@@ -971,6 +1026,7 @@
 svn_fs_node_history(svn_fs_history_t **history_p, svn_fs_root_t *root,
                     const char *path, apr_pool_t *pool)
 {
+  ENSURE_VTABLE(root, node_history);
   return svn_error_trace(root->vtable->node_history(history_p, root, path,
                                                     pool));
 }
@@ -981,6 +1037,8 @@
 {
   svn_node_kind_t kind;
 
+  ENSURE_VTABLE(root, check_path);
+  ENSURE(is_dir);
   SVN_ERR(root->vtable->check_path(&kind, root, path, pool));
   *is_dir = (kind == svn_node_dir);
   return SVN_NO_ERROR;
@@ -992,6 +1050,8 @@
 {
   svn_node_kind_t kind;
 
+  ENSURE_VTABLE(root, check_path);
+  ENSURE(is_file);
   SVN_ERR(root->vtable->check_path(&kind, root, path, pool));
   *is_file = (kind == svn_node_file);
   return SVN_NO_ERROR;
@@ -1001,6 +1061,7 @@
 svn_fs_node_id(const svn_fs_id_t **id_p, svn_fs_root_t *root,
                const char *path, apr_pool_t *pool)
 {
+  ENSURE_VTABLE(root, node_id);
   return svn_error_trace(root->vtable->node_id(id_p, root, path, pool));
 }
 
@@ -1008,6 +1069,7 @@
 svn_fs_node_created_rev(svn_revnum_t *revision, svn_fs_root_t *root,
                         const char *path, apr_pool_t *pool)
 {
+  ENSURE_VTABLE(root, node_created_rev);
   return svn_error_trace(root->vtable->node_created_rev(revision, root, path,
                                                         pool));
 }
@@ -1016,6 +1078,7 @@
 svn_fs_node_origin_rev(svn_revnum_t *revision, svn_fs_root_t *root,
                        const char *path, apr_pool_t *pool)
 {
+  ENSURE_VTABLE(root, node_origin_rev);
   return svn_error_trace(root->vtable->node_origin_rev(revision, root, path,
                                                        pool));
 }
@@ -1024,6 +1087,7 @@
 svn_fs_node_created_path(const char **created_path, svn_fs_root_t *root,
                          const char *path, apr_pool_t *pool)
 {
+  ENSURE_VTABLE(root, node_created_path);
   return svn_error_trace(root->vtable->node_created_path(created_path, root,
                                                          path, pool));
 }
@@ -1032,6 +1096,7 @@
 svn_fs_node_prop(svn_string_t **value_p, svn_fs_root_t *root,
                  const char *path, const char *propname, apr_pool_t *pool)
 {
+  ENSURE_VTABLE(root, node_prop);
   return svn_error_trace(root->vtable->node_prop(value_p, root, path,
                                                  propname, pool));
 }
@@ -1040,6 +1105,7 @@
 svn_fs_node_proplist(apr_hash_t **table_p, svn_fs_root_t *root,
                      const char *path, apr_pool_t *pool)
 {
+  ENSURE_VTABLE(root, node_proplist);
   return svn_error_trace(root->vtable->node_proplist(table_p, root, path,
                                                      pool));
 }
@@ -1049,6 +1115,7 @@
                         const char *name, const svn_string_t *value,
                         apr_pool_t *pool)
 {
+  ENSURE_VTABLE(root, change_node_prop);
   return svn_error_trace(root->vtable->change_node_prop(root, path, name,
                                                         value, pool));
 }
@@ -1058,6 +1125,7 @@
                      const char *path1, svn_fs_root_t *root2,
                      const char *path2, apr_pool_t *pool)
 {
+  ENSURE_VTABLE(root1, props_changed);
   return svn_error_trace(root1->vtable->props_changed(changed_p,
                                                       root1, path1,
                                                       root2, path2,
@@ -1068,6 +1136,7 @@
 svn_fs_copied_from(svn_revnum_t *rev_p, const char **path_p,
                    svn_fs_root_t *root, const char *path, apr_pool_t *pool)
 {
+  ENSURE_VTABLE(root, copied_from);
   return svn_error_trace(root->vtable->copied_from(rev_p, path_p, root, path,
                                                    pool));
 }
@@ -1076,6 +1145,7 @@
 svn_fs_closest_copy(svn_fs_root_t **root_p, const char **path_p,
                     svn_fs_root_t *root, const char *path, apr_pool_t *pool)
 {
+  ENSURE_VTABLE(root, closest_copy);
   return svn_error_trace(root->vtable->closest_copy(root_p, path_p,
                                                     root, path, pool));
 }
@@ -1090,6 +1160,7 @@
                       apr_pool_t *result_pool,
                       apr_pool_t *scratch_pool)
 {
+  ENSURE_VTABLE(root, get_mergeinfo);
   return svn_error_trace(root->vtable->get_mergeinfo(
     catalog, root, paths, inherit, include_descendants,
     adjust_inherited_mergeinfo, result_pool, scratch_pool));
@@ -1103,6 +1174,7 @@
                      svn_boolean_t include_descendants,
                      apr_pool_t *pool)
 {
+  ENSURE_VTABLE(root, get_mergeinfo);
   return svn_error_trace(root->vtable->get_mergeinfo(catalog, root, paths,
                                                      inherit,
                                                      include_descendants,
@@ -1115,6 +1187,7 @@
              const char *target_path, svn_fs_root_t *ancestor_root,
              const char *ancestor_path, apr_pool_t *pool)
 {
+  ENSURE_VTABLE(target_root, merge);
   return svn_error_trace(target_root->vtable->merge(conflict_p,
                                                     source_root, source_path,
                                                     target_root, target_path,
@@ -1126,6 +1199,7 @@
 svn_fs_dir_entries(apr_hash_t **entries_p, svn_fs_root_t *root,
                    const char *path, apr_pool_t *pool)
 {
+  ENSURE_VTABLE(root, dir_entries);
   return svn_error_trace(root->vtable->dir_entries(entries_p, root, path,
                                                    pool));
 }
@@ -1133,6 +1207,7 @@
 svn_error_t *
 svn_fs_make_dir(svn_fs_root_t *root, const char *path, apr_pool_t *pool)
 {
+  ENSURE_VTABLE(root, make_dir);
   SVN_ERR(svn_fs__path_valid(path, pool));
   return svn_error_trace(root->vtable->make_dir(root, path, pool));
 }
@@ -1140,6 +1215,7 @@
 svn_error_t *
 svn_fs_delete(svn_fs_root_t *root, const char *path, apr_pool_t *pool)
 {
+  ENSURE_VTABLE(root, delete_node);
   return svn_error_trace(root->vtable->delete_node(root, path, pool));
 }
 
@@ -1147,6 +1223,7 @@
 svn_fs_copy(svn_fs_root_t *from_root, const char *from_path,
             svn_fs_root_t *to_root, const char *to_path, apr_pool_t *pool)
 {
+  ENSURE_VTABLE(to_root, copy);
   SVN_ERR(svn_fs__path_valid(to_path, pool));
   return svn_error_trace(to_root->vtable->copy(from_root, from_path,
                                                to_root, to_path, pool));
@@ -1156,6 +1233,7 @@
 svn_fs_revision_link(svn_fs_root_t *from_root, svn_fs_root_t *to_root,
                      const char *path, apr_pool_t *pool)
 {
+  ENSURE_VTABLE(to_root, revision_link);
   return svn_error_trace(to_root->vtable->revision_link(from_root, to_root,
                                                         path, pool));
 }
@@ -1164,6 +1242,7 @@
 svn_fs_file_length(svn_filesize_t *length_p, svn_fs_root_t *root,
                    const char *path, apr_pool_t *pool)
 {
+  ENSURE_VTABLE(root, file_length);
   return svn_error_trace(root->vtable->file_length(length_p, root, path,
                                                    pool));
 }
@@ -1176,19 +1255,24 @@
                      svn_boolean_t force,
                      apr_pool_t *pool)
 {
+  ENSURE_VTABLE(root, file_checksum);
   SVN_ERR(root->vtable->file_checksum(checksum, kind, root, path, pool));
 
-  if (force && (*checksum == NULL || (*checksum)->kind != kind))
+  if (force)
     {
-      svn_stream_t *contents, *checksum_contents;
+      ENSURE(checksum);
+      if (*checksum == NULL || (*checksum)->kind != kind)
+        {
+          svn_stream_t *contents, *checksum_contents;
 
-      SVN_ERR(svn_fs_file_contents(&contents, root, path, pool));
-      checksum_contents = svn_stream_checksummed2(contents, checksum, NULL,
-                                                  kind, TRUE, pool);
+          SVN_ERR(svn_fs_file_contents(&contents, root, path, pool));
+          checksum_contents = svn_stream_checksummed2(contents, checksum, NULL,
+                                                      kind, TRUE, pool);
 
-      /* This will force a read of any remaining data (which is all of it in
-         this case) and dump the checksum into checksum->digest. */
-      SVN_ERR(svn_stream_close(checksum_contents));
+          /* This will force a read of any remaining data (which is all of it 
in
+             this case) and dump the checksum into checksum->digest. */
+          SVN_ERR(svn_stream_close(checksum_contents));
+        }
     }
 
   return SVN_NO_ERROR;
@@ -1202,6 +1286,7 @@
 {
   svn_checksum_t *md5sum;
 
+  ENSURE(digest);
   SVN_ERR(svn_fs_file_checksum(&md5sum, svn_checksum_md5, root, path, TRUE,
                                pool));
   memcpy(digest, md5sum->digest, APR_MD5_DIGESTSIZE);
@@ -1213,6 +1298,7 @@
 svn_fs_file_contents(svn_stream_t **contents, svn_fs_root_t *root,
                      const char *path, apr_pool_t *pool)
 {
+  ENSURE_VTABLE(root, file_contents);
   return svn_error_trace(root->vtable->file_contents(contents, root, path,
                                                      pool));
 }
@@ -1225,6 +1311,7 @@
                                  void* baton,
                                  apr_pool_t *pool)
 {
+  ENSURE(root && root->vtable);
   /* if the FS doesn't implement this function, report a "failed" attempt */
   if (root->vtable->try_process_file_contents == NULL)
     {
@@ -1241,6 +1328,7 @@
 svn_error_t *
 svn_fs_make_file(svn_fs_root_t *root, const char *path, apr_pool_t *pool)
 {
+  ENSURE_VTABLE(root, make_file);
   SVN_ERR(svn_fs__path_valid(path, pool));
   return svn_error_trace(root->vtable->make_file(root, path, pool));
 }
@@ -1253,6 +1341,8 @@
 {
   svn_checksum_t *base, *result;
 
+  ENSURE_VTABLE(root, apply_textdelta);
+
   /* TODO: If we ever rev this API, we should make the supplied checksums
      svn_checksum_t structs. */
   SVN_ERR(svn_checksum_parse_hex(&base, svn_checksum_md5, base_checksum,
@@ -1276,6 +1366,8 @@
 {
   svn_checksum_t *result;
 
+  ENSURE_VTABLE(root, apply_text);
+
   /* TODO: If we ever rev this API, we should make the supplied checksum an
      svn_checksum_t struct. */
   SVN_ERR(svn_checksum_parse_hex(&result, svn_checksum_md5, result_checksum,
@@ -1290,6 +1382,7 @@
                         const char *path1, svn_fs_root_t *root2,
                         const char *path2, apr_pool_t *pool)
 {
+  ENSURE_VTABLE(root1, contents_changed);
   return svn_error_trace(root1->vtable->contents_changed(changed_p,
                                                          root1, path1,
                                                          root2, path2,
@@ -1299,6 +1392,7 @@
 svn_error_t *
 svn_fs_youngest_rev(svn_revnum_t *youngest_p, svn_fs_t *fs, apr_pool_t *pool)
 {
+  ENSURE_VTABLE(fs, youngest_rev);
   return svn_error_trace(fs->vtable->youngest_rev(youngest_p, fs, pool));
 }
 
@@ -1305,6 +1399,7 @@
 svn_error_t *
 svn_fs_deltify_revision(svn_fs_t *fs, svn_revnum_t revision, apr_pool_t *pool)
 {
+  ENSURE_VTABLE(fs, deltify);
   return svn_error_trace(fs->vtable->deltify(fs, revision, pool));
 }
 
@@ -1312,6 +1407,7 @@
 svn_fs_revision_prop(svn_string_t **value_p, svn_fs_t *fs, svn_revnum_t rev,
                      const char *propname, apr_pool_t *pool)
 {
+  ENSURE_VTABLE(fs, revision_prop);
   return svn_error_trace(fs->vtable->revision_prop(value_p, fs, rev,
                                                    propname, pool));
 }
@@ -1320,6 +1416,7 @@
 svn_fs_revision_proplist(apr_hash_t **table_p, svn_fs_t *fs, svn_revnum_t rev,
                          apr_pool_t *pool)
 {
+  ENSURE_VTABLE(fs, revision_proplist);
   return svn_error_trace(fs->vtable->revision_proplist(table_p, fs, rev,
                                                        pool));
 }
@@ -1329,6 +1426,7 @@
                         const svn_string_t *const *old_value_p,
                         const svn_string_t *value, apr_pool_t *pool)
 {
+  ENSURE_VTABLE(fs, change_rev_prop);
   return svn_error_trace(fs->vtable->change_rev_prop(fs, rev, name,
                                                      old_value_p,
                                                      value, pool));
@@ -1349,6 +1447,7 @@
                              svn_fs_root_t *target_root,
                              const char *target_path, apr_pool_t *pool)
 {
+  ENSURE_VTABLE(target_root, get_file_delta_stream);
   return svn_error_trace(target_root->vtable->get_file_delta_stream(
                            stream_p,
                            source_root, source_path,
@@ -1358,6 +1457,7 @@
 svn_error_t *
 svn_fs_get_uuid(svn_fs_t *fs, const char **uuid, apr_pool_t *pool)
 {
+  ENSURE(fs);
   /* If you change this, consider changing svn_fs__identifier(). */
   *uuid = apr_pstrdup(pool, fs->uuid);
   return SVN_NO_ERROR;
@@ -1366,6 +1466,7 @@
 svn_error_t *
 svn_fs_set_uuid(svn_fs_t *fs, const char *uuid, apr_pool_t *pool)
 {
+  ENSURE_VTABLE(fs, set_uuid);
   if (! uuid)
     {
       uuid = svn_uuid_generate(pool);
@@ -1427,6 +1528,7 @@
           (SVN_ERR_INCORRECT_PARAMS, NULL,
            _("Negative expiration date passed to svn_fs_lock"));
 
+  ENSURE_VTABLE(fs, lock);
   return svn_error_trace(fs->vtable->lock(lock, fs, path, token, comment,
                                           is_dav_comment, expiration_date,
                                           current_rev, steal_lock, pool));
@@ -1435,6 +1537,7 @@
 svn_error_t *
 svn_fs_generate_lock_token(const char **token, svn_fs_t *fs, apr_pool_t *pool)
 {
+  ENSURE_VTABLE(fs, generate_lock_token);
   return svn_error_trace(fs->vtable->generate_lock_token(token, fs, pool));
 }
 
@@ -1442,6 +1545,7 @@
 svn_fs_unlock(svn_fs_t *fs, const char *path, const char *token,
               svn_boolean_t break_lock, apr_pool_t *pool)
 {
+  ENSURE_VTABLE(fs, unlock);
   return svn_error_trace(fs->vtable->unlock(fs, path, token, break_lock,
                                             pool));
 }
@@ -1450,6 +1554,7 @@
 svn_fs_get_lock(svn_lock_t **lock, svn_fs_t *fs, const char *path,
                 apr_pool_t *pool)
 {
+  ENSURE_VTABLE(fs, get_lock);
   return svn_error_trace(fs->vtable->get_lock(lock, fs, path, pool));
 }
 
@@ -1462,6 +1567,7 @@
                  (depth == svn_depth_files) ||
                  (depth == svn_depth_immediates) ||
                  (depth == svn_depth_infinity));
+  ENSURE_VTABLE(fs, get_locks);
   return svn_error_trace(fs->vtable->get_locks(fs, path, depth,
                                                get_locks_func,
                                                get_locks_baton, pool));
@@ -1485,6 +1591,7 @@
                     svn_fs_history_t *history, svn_boolean_t cross_copies,
                     apr_pool_t *pool)
 {
+  ENSURE_VTABLE(history, prev);
   return svn_error_trace(history->vtable->prev(prev_history_p, history,
                                                cross_copies, pool));
 }
@@ -1493,6 +1600,7 @@
 svn_fs_history_location(const char **path, svn_revnum_t *revision,
                         svn_fs_history_t *history, apr_pool_t *pool)
 {
+  ENSURE_VTABLE(history, location);
   return svn_error_trace(history->vtable->location(path, revision, history,
                                                    pool));
 }
@@ -1518,6 +1626,8 @@
 svn_string_t *
 svn_fs_unparse_id(const svn_fs_id_t *id, apr_pool_t *pool)
 {
+  if (!id || !id->vtable || !id->vtable->unparse)
+   return NULL; 
   return id->vtable->unparse(id, pool);
 }
 
@@ -1524,6 +1634,8 @@
 svn_boolean_t
 svn_fs_check_related(const svn_fs_id_t *a, const svn_fs_id_t *b)
 {
+  if (!a || !a->vtable || !a->vtable->compare)
+    return FALSE;
   return (a->vtable->compare(a, b) != -1);
 }
 
@@ -1530,6 +1642,8 @@
 int
 svn_fs_compare_ids(const svn_fs_id_t *a, const svn_fs_id_t *b)
 {
+  if (!a || !a->vtable || !a->vtable->compare)
+    return -1; 
   return a->vtable->compare(a, b);
 }
 

Reply via email to