[svn.haxx.se] · SVN Dev · SVN Users · SVN Org · TSVN Dev · TSVN Users · Subclipse Dev · Subclipse Users · this month's index

[PATCH] possible crash on svn revert

From: Benjamin Pflugmann <benjamin-svn-dev_at_pflugmann.de>
Date: 2002-09-21 18:48:11 CEST

Hello.

Well, it is week-end and so I thougth it is the right time to assure
you have something to read on Monday... ;-)

Seriously, while browsing through bite-sized tasks, namely
http://subversion.tigris.org/issues/show_bug.cgi?id=714, I got a bit
side-tracked and stumbled upon crash bug.

Recipe:

  nora:~> cd /usr/local/src/phi/test
  nora:src/phi/test> svnadmin create repos2
  nora:src/phi/test> svn co file:///usr/local/src/phi/test/repos2 wc
  Checked out revision 0.
  nora:src/phi/test> cd wc
  nora:phi/test/wc> mkdir foo
  nora:phi/test/wc> svn add foo
  A foo
  nora:phi/test/wc> rm -rf foo
  nora:phi/test/wc> svn revert foo
  Segmentation fault (core dumped)
  Exit 139
  nora:phi/test/wc>

The problem is that libsvn_wc/adm_ops.c:svn_wc_revert() calls
svn_wc_remove_from_revision_control() with svn_wc_adm_access_t* set to
NULL, which is later (indirectly) dereferenced therein, therefore the
crash.

The bug is not easily fixed, because it is a new use case which is not
supported by the interface yet:

svn_error_t *
svn_wc_remove_from_revision_control (svn_wc_adm_access_t *adm_access,
                                     const char *name,
                                     svn_boolean_t destroy_wf,
                                     apr_pool_t *pool)

ADM_ACCESS is expected to be a valid write lock. The only valid
svn_wc_adm_access_t, which can be obtained is the one to the parent
directory of "foo", e.g. the root "". Then

  svn_wc_adm_access_path(ADM_ACCESS)

gives back the path to the root dir. Therefore somehow the name of
"foo" had to be passed to the function. But passing anything else than
SVN_WC_ENTRY_THIS_DIR for NAME is interpreted as the paramater being a
_file_. And of course the belonging functionality does not fit,
neither does the handling for directories (tries to delete the
directory given by ADM_ACCESS, here: the *root*).

A simply fix, which prevents the crash, but does not provide the
wished functionality would be:

Index: subversion/libsvn_wc/adm_ops.c
===================================================================
--- subversion/libsvn_wc/adm_ops.c
+++ subversion/libsvn_wc/adm_ops.c 2002-09-21 18:22:01.000000000 +0200
@@ -1205,7 +1205,7 @@
         {
           SVN_ERR (svn_wc_adm_open (&parent_access, NULL, p_dir, TRUE, TRUE,
                                     pool));
- if (kind == svn_node_dir)
+ if (entry->kind == svn_node_dir)
             SVN_ERR (svn_wc_adm_retrieve (&dir_access, parent_access, path,
                                           pool));
           else

With this patch one gets:

  nora:phi/test/wc> svn revert foo
  subversion/libsvn_wc/lock.c:360: (apr_err=155005, src_err=0)
  svn: Working copy not locked
  svn: directory not locked (foo)
  Exit 1

The least intrusive way to get the it working, which I found found by
now, is to put the 3 required function calls into svn_wc_revert()
itself, instead of calling svn_wc_remove_from_revision_control(). No
need to say that I am not really happy with that solution.

But since I do not see a better fix at the moment, the patch below
will prevent the crash and make svn revert work as supposed in the
discussed case. It works for me and passed "make check".

Regards,

        Benjamin.

2002-09-21 Benjamin Pflugmann <benjamin-svn-cvs@pflugmann.de>

        * libsvn_wc/adm_ops.c:
        (svn_wc_delete): minor style change
        (svn_wc_revert): Fixed a crash.
        svn_wc_remove_from_revision_control may not be called without a
        valid lock. When trying to revert an added, but manually deleted
        directory, only the parent lock would be valid. But passing the
        parent lock would be interpreted as request to remove the parent.
        Therefore do remove the revision control entry without calling
        svn_wc_remove_from_revision_control at all.

Index: subversion/libsvn_wc/adm_ops.c
===================================================================
--- subversion/libsvn_wc/adm_ops.c
+++ subversion/libsvn_wc/adm_ops.c 2002-09-21 18:30:47.000000000 +0200
@@ -617,7 +617,7 @@
   if (!entry)
     return erase_unversioned_from_wc (path, pool);
     
- was_schedule_add = entry->schedule == svn_wc_schedule_add;
+ was_schedule_add = (entry->schedule == svn_wc_schedule_add);
 
   if (entry->kind == svn_node_dir)
     {
@@ -1230,13 +1230,15 @@
          entry. */
       svn_boolean_t was_deleted = FALSE;
       const char *parent, *basey;
- svn_wc_adm_access_t *adm_access;
 
       svn_path_split_nts (path, &parent, &basey, pool);
       if (entry->kind == svn_node_file)
         {
           was_deleted = entry->deleted;
- adm_access = parent_access;
+
+ /* Remove the item from revision control. */
+ SVN_ERR (svn_wc_remove_from_revision_control
+ (parent_access, bname, FALSE, pool));
         }
       else if (entry->kind == svn_node_dir)
         {
@@ -1246,21 +1248,27 @@
           parents_entry = apr_hash_get (entries, basey, APR_HASH_KEY_STRING);
           if (parents_entry)
             was_deleted = parents_entry->deleted;
- adm_access = dir_access;
+
+ /* Remove the item from revision control. */
+ if( kind == svn_node_dir )
+ {
+ SVN_ERR (svn_wc_remove_from_revision_control
+ (dir_access, SVN_WC_ENTRY_THIS_DIR, FALSE, pool));
+ }
+ else
+ {
+ /* directory in WC does not exist (anymore), therefore
+ only remove revision information. */
+ SVN_ERR (svn_wc_adm_write_check (parent_access));
+ svn_wc__entry_remove (entries, basey);
+ SVN_ERR (svn_wc__entries_write (entries, parent, pool));
+ }
         }
       else /* Else it's `none', or something exotic like a symlink... */
         return svn_error_createf
           (SVN_ERR_NODE_UNKNOWN_KIND, 0, NULL, pool,
            "Unknown or unexpected kind for path %s", path);
 
- /* Remove the item from revision control. */
- if (entry->kind == svn_node_dir)
- SVN_ERR (svn_wc_remove_from_revision_control
- (adm_access, SVN_WC_ENTRY_THIS_DIR, FALSE, pool));
- else
- SVN_ERR (svn_wc_remove_from_revision_control (adm_access, bname,
- FALSE, pool));
-
       /* Recursivity is taken care of by svn_wc_remove_from_revision_control,
          and we've definitely reverted PATH at this point. */
       recursive = FALSE;

  • application/pgp-signature attachment: stored
Received on Sat Sep 21 18:48:58 2002

This is an archived mail posted to the Subversion Dev mailing list.