Index: subversion/libsvn_wc/adm_ops.c =================================================================== --- subversion/libsvn_wc/adm_ops.c (revision 37912) +++ subversion/libsvn_wc/adm_ops.c (working copy) @@ -2653,7 +2653,8 @@ function is called by svn_wc_crop_tree(). */ dir_entry = apr_hash_get(parent_entries, base_name, APR_HASH_KEY_STRING); - if (dir_entry->depth != svn_depth_exclude) + if (dir_entry + && dir_entry->depth != svn_depth_exclude) { SVN_ERR(svn_wc__entry_remove(db, local_abspath, pool)); apr_hash_set(parent_entries, base_name, APR_HASH_KEY_STRING, Index: subversion/tests/cmdline/update_tests.py =================================================================== --- subversion/tests/cmdline/update_tests.py (revision 37912) +++ subversion/tests/cmdline/update_tests.py (working copy) @@ -4779,6 +4779,65 @@ "svn: Target path '/A' does not exist", "up", other_wc_dir) +#---------------------------------------------------------------------- + +def keep_local_delete_of_tree_conflicted_dir(sbox): + "--keep-local del of tree conflicted dir segfaults" + + # A convoluted combination of deletes with --keep-local on + # a tree conflicted working copy can segfault, see + # http://svn.haxx.se/dev/archive-2009-05/0410.shtml + + sbox.build() + wc_dir = sbox.wc_dir + + # Some paths we'll care about + C_path = os.path.join(wc_dir, "A", "C") + C_C_path = os.path.join(wc_dir, "A", "C", "C") + + # Add a directory A/C/C as r2. + svntest.main.run_svn(None, 'mkdir', C_C_path) + svntest.main.run_svn(None, 'commit', + '-m', 'Add directory A/C/C', + wc_dir) + + # Set a meaningless prop on A/C/C + svntest.actions.run_and_verify_svn(None, + ["property 'propname' set on '" + + C_C_path + "'\n"], [], 'ps', + 'propname', 'propval', C_C_path) + + # Update WC to r1, a tree conflict results on A/C because of the + # working prop on A/C/C. + expected_output = svntest.wc.State(wc_dir, { + 'A/C/C' : Item(status=' ', treeconflict='C'), + }) + expected_disk = svntest.main.greek_state.copy() + expected_disk.add({'A/C/C' : Item(props={'propname' : 'propval'})}) + expected_status = svntest.actions.get_virginal_state(wc_dir, 1) + expected_status.add({'A/C/C' : Item(status='A ', + wc_rev='-', + copied='+', + treeconflict='C')}) + svntest.actions.run_and_verify_update(wc_dir, + expected_output, + expected_disk, + expected_status, + None, None, None, None, None, 1, + '-r', '1', wc_dir) + + # Delete A/C --keep-local. + svntest.actions.run_and_verify_svn(None, + ['D ' + C_C_path + '\n', + 'D ' + C_path + '\n'], + [], 'delete', C_path, '--keep-local') + + # Delete A/C/C with --keep-local (--force would also work), + # here we see a segfault. + svntest.actions.run_and_verify_svn(None, + ['D ' + C_C_path + '\n'], + [], 'delete', C_C_path, '--keep-local') + ####################################################################### # Run the tests @@ -4844,6 +4903,7 @@ tree_conflict_uc2_schedule_re_add, set_deep_depth_on_target_with_shallow_children, update_wc_of_dir_to_rev_not_containing_this_dir, + keep_local_delete_of_tree_conflicted_dir, ] if __name__ == '__main__':