hercules-team / augeas

A configuration editing tool and API
http://augeas.net/
GNU Lesser General Public License v2.1
486 stars 199 forks source link

double free when deleting nested XML elements using // (descendant-or-self) #319

Closed GeoffWilliams closed 8 years ago

GeoffWilliams commented 8 years ago

Overview

Double free from libaugeas with lens Xml.lns when deleting nested XML elements collected using // (descendant-or-self).

Software versions

Augeas is being used to remove all Realm elements from Tomcat's server.xml file using the ruby-augeas API like this:

@aug.rm("/files/opt/apache-tomcat/tomcat6/conf/server.xml/Server//Realm")

The operation itself seems to succeed but there is an error from libaugeas when the library attempts to free the memory being used.

Originally this problem was encountered invoking augeas through Puppet but I was able to reproduce the problem using augtool, see testcase.

External bug report: https://tickets.puppetlabs.com/browse/MODULES-1721

Error details

The above Ruby function enters libaugeas in aug_rm() and results in the following backtrace when running under puppet:

#0  __lll_lock_wait_private () at ../nptl/sysdeps/unix/sysv/linux/x86_64/lowlevellock.S:95
#1  0x00007f0edd206f66 in _L_lock_12192 () at malloc.c:5200
#2  0x00007f0edd2044e1 in __GI___libc_malloc (bytes=56) at malloc.c:2866
#3  0x00007f0ede388388 in _dl_map_object_deps (map=map@entry=0x4593280,
    preloads=preloads@entry=0x0, npreloads=npreloads@entry=0, trace_mode=trace_mode@entry=0,
    open_mode=open_mode@entry=-2147483648) at dl-deps.c:515
#4  0x00007f0ede38e92c in dl_open_worker (a=a@entry=0x12f2408) at dl-open.c:265
#5  0x00007f0ede38a314 in _dl_catch_error (objname=objname@entry=0x12f23f8,
    errstring=errstring@entry=0x12f2400, mallocedp=mallocedp@entry=0x12f23f0,
    operate=operate@entry=0x7f0ede38e7b0 <dl_open_worker>, args=args@entry=0x12f2408)
    at dl-error.c:177
#6  0x00007f0ede38e25b in _dl_open (file=0x7f0edd2ff0c6 "libgcc_s.so.1", mode=-2147483647,
    caller_dlopen=<optimized out>, nsid=-2, argc=6, argv=0x7fff2bb985a8, env=0x4869f90)
    at dl-open.c:656
#7  0x00007f0edd2b4be2 in do_dlopen (ptr=ptr@entry=0x12f2610) at dl-libc.c:87
#8  0x00007f0ede38a314 in _dl_catch_error (objname=0x12f25f0, errstring=0x12f2600,
    mallocedp=0x12f25e0, operate=0x7f0edd2b4ba0 <do_dlopen>, args=0x12f2610) at dl-error.c:177
#9  0x00007f0edd2b4ca2 in dlerror_run (args=0x12f2610, operate=0x7f0edd2b4ba0 <do_dlopen>)
    at dl-libc.c:46
#10 __GI___libc_dlopen_mode (name=name@entry=0x7f0edd2ff0c6 "libgcc_s.so.1",
    mode=mode@entry=-2147483647) at dl-libc.c:163
#11 0x00007f0edd28e265 in init () at ../sysdeps/x86_64/backtrace.c:52
#12 0x00007f0eddc8ebe0 in pthread_once ()
---Type <return> to continue, or q <return> to quit---
    at ../nptl/sysdeps/unix/sysv/linux/x86_64/pthread_once.S:103
#13 0x00007f0edd28e37c in __GI___backtrace (array=array@entry=0x7f0ede377240 <trace.11803>,
    size=size@entry=1024) at ../sysdeps/x86_64/backtrace.c:103
#14 0x00007f0ede080d1c in rb_print_backtrace () at vm_dump.c:690
#15 rb_vm_bugreport () at vm_dump.c:746
#16 0x00007f0eddf156c3 in report_bug (
    file=file@entry=0x4588f70 "/opt/puppetlabs/puppet/lib/ruby/vendor_ruby/puppet/provider/augeas/augeas.rb", line=<optimized out>, fmt=fmt@entry=0x7f0ede0c091c "Segmentation fault at %p",
    args=args@entry=0x12f2958) at error.c:312
#17 0x00007f0eddf16313 in rb_bug (fmt=fmt@entry=0x7f0ede0c091c "Segmentation fault at %p")
    at error.c:339
#18 0x00007f0eddff8983 in sigsegv (sig=<optimized out>, info=0x12f2bb0, ctx=<optimized out>)
    at signal.c:824
#19 <signal handler called>
#20 malloc_consolidate (av=av@entry=0x7f0edd53e760 <main_arena>) at malloc.c:4115
#21 0x00007f0edd202429 in _int_malloc (av=av@entry=0x7f0edd53e760 <main_arena>,
    bytes=bytes@entry=8192) at malloc.c:3400
#22 0x00007f0edd204f0a in __libc_calloc (n=<optimized out>, elem_size=<optimized out>)
    at malloc.c:3208
#23 0x00007f0edd1f8d63 in __GI_open_memstream (bufloc=bufloc@entry=0x7fff2bb96290,
    sizeloc=sizeloc@entry=0x7fff2bb962a0) at memstream.c:85
#24 0x00007f0edd2743ea in __GI___vsyslog_chk (pri=11, pri@entry=3, flag=flag@entry=-1,
    fmt=fmt@entry=0x7f0edd302b88 "*** Error in `%s': %s: 0x%s ***\n",
---Type <return> to continue, or q <return> to quit---
    ap=ap@entry=0x7fff2bb96578) at ../misc/syslog.c:167
#25 0x00007f0edd274a00 in __vsyslog (pri=pri@entry=3,
    fmt=fmt@entry=0x7f0edd302b88 "*** Error in `%s': %s: 0x%s ***\n",
    ap=ap@entry=0x7fff2bb96578) at ../misc/syslog.c:324
#26 0x00007f0edd1fa0f6 in __libc_message (do_abort=do_abort@entry=2,
    fmt=fmt@entry=0x7f0edd302b88 "*** Error in `%s': %s: 0x%s ***\n")
    at ../sysdeps/unix/sysv/linux/libc_fatal.c:166
#27 0x00007f0edd20156d in malloc_printerr (ptr=<optimized out>,
    str=0x7f0edd302bf8 "double free or corruption (fasttop)", action=3) at malloc.c:4972
#28 _int_free (av=0x7f0edd53e760 <main_arena>, p=<optimized out>, have_lock=0)
    at malloc.c:3804
#29 0x00007f0ed10d15d9 in free_tree_node (tree=tree@entry=0x4cdac50) at augeas.c:651
#30 0x00007f0ed10d2df6 in free_tree (tree=0x4cefae0) at augeas.c:1134
#31 0x00007f0ed10d2de7 in free_tree (tree=0x4cdac40) at augeas.c:1133
#32 0x00007f0ed10d2de7 in free_tree (tree=0xc0) at augeas.c:1133
#33 0x00007f0ed10d2e95 in tree_unlink_raw (tree=0x4cdab50) at augeas.c:662
#34 0x00007f0ed10d3752 in tree_rm (p=p@entry=0x49d5970) at augeas.c:1167
#35 0x00007f0ed10d37d3 in aug_rm (aug=aug@entry=0x476c160, path=<optimized out>)
    at augeas.c:1182
#36 0x00007f0ed1318e45 in augeas_rm (s=<optimized out>, path=61564760,
    sibling=<optimized out>) at ext/augeas/_augeas.c:165
#37 0x00007f0ede0781d1 in vm_call_cfunc_with_frame (ci=<optimized out>,
    reg_cfp=0x7f0ede58a110, th=0x12845b0) at vm_insnhelper.c:1510
---Type <return> to continue, or q <return> to quit---
#38 vm_call_cfunc (ci=<optimized out>, reg_cfp=0x7f0ede58a110, th=0x12845b0)
    at vm_insnhelper.c:1600
#39 vm_call_method (th=0x12845b0, cfp=0x7f0ede58a110, ci=<optimized out>)
    at vm_insnhelper.c:1788
#40 0x00007f0ede06f284 in vm_exec_core (th=th@entry=0x12845b0, initial=initial@entry=0)
    at insns.def:1028
#41 0x00007f0ede07314f in vm_exec (th=th@entry=0x12845b0) at vm.c:1421
#42 0x00007f0ede0762ba in invoke_block_from_c (th=0x12845b0, block=<optimized out>,
    self=<optimized out>, argc=<optimized out>, argv=<optimized out>,
    blockptr=<optimized out>, cref=0x0, defined_class=63658160) at vm.c:817
#43 0x00007f0ede077359 in vm_yield (argv=<optimized out>, argc=<optimized out>,
    th=<optimized out>) at vm.c:856
#44 rb_yield_0 (argv=<optimized out>, argc=<optimized out>) at vm_eval.c:944
#45 rb_yield (val=61566480) at vm_eval.c:954
#46 0x00007f0eddecc042 in rb_ary_each (array=61566520) at array.c:1796
#47 0x00007f0ede0781d1 in vm_call_cfunc_with_frame (ci=<optimized out>,
    reg_cfp=0x7f0ede58a1b0, th=0x12845b0) at vm_insnhelper.c:1510
#48 vm_call_cfunc (ci=<optimized out>, reg_cfp=0x7f0ede58a1b0, th=0x12845b0)
    at vm_insnhelper.c:1600
#49 vm_call_method (th=0x12845b0, cfp=0x7f0ede58a1b0, ci=<optimized out>)
    at vm_insnhelper.c:1788
#50 0x00007f0ede06fd45 in vm_exec_core (th=th@entry=0x12845b0, initial=initial@entry=0)
    at insns.def:999
---Type <return> to continue, or q <return> to quit---
#51 0x00007f0ede07314f in vm_exec (th=th@entry=0x12845b0) at vm.c:1421
#52 0x00007f0ede0762ba in invoke_block_from_c (th=0x12845b0, block=<optimized out>,
    self=<optimized out>, argc=<optimized out>, argv=<optimized out>,
    blockptr=<optimized out>, cref=0x0, defined_class=38025000) at vm.c:817
#53 0x00007f0ede077359 in vm_yield (argv=<optimized out>, argc=<optimized out>,
    th=<optimized out>) at vm.c:856
#54 rb_yield_0 (argv=<optimized out>, argc=<optimized out>) at vm_eval.c:944
#55 rb_yield (val=61557360) at vm_eval.c:954
#56 0x00007f0eddecc042 in rb_ary_each (array=64397600) at array.c:1796
#57 0x00007f0ede06a514 in vm_call_cfunc_with_frame (ci=<optimized out>,
    reg_cfp=0x7f0ede58a340, th=0x12845b0) at vm_insnhelper.c:1510
#58 vm_call_cfunc (th=0x12845b0, reg_cfp=0x7f0ede58a340, ci=<optimized out>)
    at vm_insnhelper.c:1600
#59 0x00007f0ede06fd45 in vm_exec_core (th=th@entry=0x12845b0, initial=initial@entry=0)
    at insns.def:999
#60 0x00007f0ede07314f in vm_exec (th=th@entry=0x12845b0) at vm.c:1421
#61 0x00007f0ede074434 in vm_call0_body (th=0x12845b0, ci=ci@entry=0x7fff2bb97d40,
    argv=0x7f0ede48b578, argv@entry=0x7fff2bb97d80) at vm_eval.c:171
#62 0x00007f0ede075017 in vm_call0 (defined_class=41544480, me=<optimized out>,
    argv=argv@entry=0x7fff2bb97d80, argc=argc@entry=32526, id=<optimized out>,
    recv=<optimized out>, th=<optimized out>) at vm_eval.c:50
#63 rb_vm_call (th=<optimized out>, recv=<optimized out>, id=<optimized out>,
    argc=argc@entry=1, argv=argv@entry=0x7f0ede48b578, me=<optimized out>,
---Type <return> to continue, or q <return> to quit---
    defined_class=41544480) at vm_eval.c:247
#64 0x00007f0eddf26f66 in rb_method_call_with_block (argc=1, argv=0x7f0ede48b578,
    method=<optimized out>, pass_procval=8) at proc.c:1820
#65 0x00007f0ede06a514 in vm_call_cfunc_with_frame (ci=<optimized out>,
    reg_cfp=0x7f0ede58a570, th=0x12845b0) at vm_insnhelper.c:1510
#66 vm_call_cfunc (th=0x12845b0, reg_cfp=0x7f0ede58a570, ci=<optimized out>)
    at vm_insnhelper.c:1600
#67 0x00007f0ede06f284 in vm_exec_core (th=th@entry=0x12845b0, initial=initial@entry=0)
    at insns.def:1028
#68 0x00007f0ede07314f in vm_exec (th=th@entry=0x12845b0) at vm.c:1421
#69 0x00007f0ede07b396 in rb_iseq_eval_main (iseqval=iseqval@entry=23662040) at vm.c:1660
#70 0x00007f0eddf1b88f in ruby_exec_internal (n=0x1690dd8) at eval.c:253
#71 0x00007f0eddf1d9ad in ruby_exec_node (n=n@entry=0x1690dd8) at eval.c:318
#72 0x00007f0eddf2017c in ruby_run_node (n=0x1690dd8) at eval.c:310
#73 0x00000000004008bb in main ()

Once I'd developed a stand-alone testcase I was able to add some print statements and step through the code with GDB and I found that:

ENTERING aug_rm(), path is /files/opt/apache-tomcat/tomcat6/conf/server.xml/Server//Realm
entering tree_rm()**** tree count: 4
================= delete tree 0 ==========
tree_unlink_raw(0x2740920)
free_tree(0x273fb30)
free_tree(0x273ff00)
free_tree(0x273dcc0)
free_tree((nil))
free_tree_node(0x273dcc0) == org.apache.catalina.realm.JNDIRealm
free_tree_node(0x273ff00) == (null)           ^
free_tree_node(0x273fb30) == (null)           |
free_tree_node(0x2740920) == (null)           |
================= delete tree 1 ==========    |
tree_unlink_raw(0x273ead0)                    |
free_tree(0x273ef40)                          |
free_tree(0x273e960)                          | already freed here
free_tree(0x273d7b0)                          |
free_tree((nil))                              |
free_tree_node(0x273d7b0) == ldap://localhost |
free_tree_node(0x273e960) == (null)           |
free_tree_node(0x273ef40) == (null)           |
free_tree_node(0x273ead0) == (null)           |
================= delete tree 2 ==========    |
tree_unlink_raw(0x273fb30)                    |
free_tree(0x273ff00)                          |
free_tree(0x273dcc0)                          |
free_tree((nil))                              |
free_tree_node(0x273dcc0) ==                  |
free_tree_node(0x273ff00) == (null)           |
free_tree(0x273ff00)                          |
free_tree(0x273dcc0)                          |
free_tree((nil))                              |
free_tree_node(0x273dcc0) == p?s         <------- garbage at dangling pointer
*** Error in `/opt/puppetlabs/puppet/bin/ruby': double free or corruption (fasttop): 0x000000000273fc00 ***

Root cause

Inside the XML file, I see the following Realm elements:

    <Realm><Realm className="org.apache.catalina.realm.JNDIRealm"></Realm>
</Realm>
<Realm><Realm connectionURL="ldap://localhost"></Realm>
</Realm>

It seems the parser has mapped the exact same memory for elements of the struct tree member being passed to tree_unlink_raw() which makes sense because the elements are nested

Testcase

assuming testcase.xml present on system at /vagrant/testcase.xml and with a freshly compiled libaugeas from git, free of any source modifications:

[root@localhost vagrant]# augtool
augtool> set /augeas/load/Xfm/lens Xml.lns
augtool> set /augeas/load/Xfm/incl /vagrant/testcase.xml
augtool> load
augtool> rm /files/vagrant/testcase.xml/Server//Realm
*** Error in `augtool': double free or corruption (fasttop): 0x00000000038790d0 ***
======= Backtrace: =========
/lib64/libc.so.6(+0x7d56d)[0x7f288a46e56d]
/usr/local/lib/libaugeas.so.0(+0x63f9)[0x7f288af7a3f9]
/usr/local/lib/libaugeas.so.0(+0x7c16)[0x7f288af7bc16]
/usr/local/lib/libaugeas.so.0(+0x7c07)[0x7f288af7bc07]
/usr/local/lib/libaugeas.so.0(+0x7cb5)[0x7f288af7bcb5]
/usr/local/lib/libaugeas.so.0(+0x8572)[0x7f288af7c572]
/usr/local/lib/libaugeas.so.0(aug_rm+0x43)[0x7f288af7c5f3]
/usr/local/lib/libaugeas.so.0(+0xadaa)[0x7f288af7edaa]
/usr/local/lib/libaugeas.so.0(aug_srun+0x2c2)[0x7f288af80412]
augtool[0x402a0f]
augtool[0x402d24]
augtool[0x401f5d]
/lib64/libc.so.6(__libc_start_main+0xf5)[0x7f288a412af5]
augtool[0x402131]
======= Memory map: ========
00400000-00405000 r-xp 00000000 fd:01 101854467                          /usr/local/bin/augtool
00604000-00605000 r--p 00004000 fd:01 101854467                          /usr/local/bin/augtool
00605000-00606000 rw-p 00005000 fd:01 101854467                          /usr/local/bin/augtool
01b4b000-07b57000 rw-p 00000000 00:00 0                                  [heap]
7f2882a5e000-7f2882a69000 r-xp 00000000 fd:01 67591521                   /usr/lib64/libnss_files-2.17.so
7f2882a69000-7f2882c68000 ---p 0000b000 fd:01 67591521                   /usr/lib64/libnss_files-2.17.so
7f2882c68000-7f2882c69000 r--p 0000a000 fd:01 67591521                   /usr/lib64/libnss_files-2.17.so
7f2882c69000-7f2882c6a000 rw-p 0000b000 fd:01 67591521                   /usr/lib64/libnss_files-2.17.so
7f2882c6a000-7f2882d68000 rw-p 00000000 00:00 0
7f2882d89000-7f2882f2d000 rw-p 00000000 00:00 0
7f2882f2d000-7f2889454000 r--p 00000000 fd:01 67591550                   /usr/lib/locale/locale-archive
7f2889454000-7f288946a000 r-xp 00000000 fd:01 67591529                   /usr/lib64/libpthread-2.17.so
7f288946a000-7f288966a000 ---p 00016000 fd:01 67591529                   /usr/lib64/libpthread-2.17.so
7f288966a000-7f288966b000 r--p 00016000 fd:01 67591529                   /usr/lib64/libpthread-2.17.so
7f288966b000-7f288966c000 rw-p 00017000 fd:01 67591529                   /usr/lib64/libpthread-2.17.so
7f288966c000-7f2889670000 rw-p 00000000 00:00 0
7f2889670000-7f2889771000 r-xp 00000000 fd:01 67591511                   /usr/lib64/libm-2.17.so
7f2889771000-7f2889970000 ---p 00101000 fd:01 67591511                   /usr/lib64/libm-2.17.so
7f2889970000-7f2889971000 r--p 00100000 fd:01 67591511                   /usr/lib64/libm-2.17.so
7f2889971000-7f2889972000 rw-p 00101000 fd:01 67591511                   /usr/lib64/libm-2.17.so
7f2889972000-7f2889996000 r-xp 00000000 fd:01 68828937                   /usr/lib64/liblzma.so.5.0.99
7f2889996000-7f2889b95000 ---p 00024000 fd:01 68828937                   /usr/lib64/liblzma.so.5.0.99
7f2889b95000-7f2889b96000 r--p 00023000 fd:01 68828937                   /usr/lib64/liblzma.so.5.0.99
7f2889b96000-7f2889b97000 rw-p 00024000 fd:01 68828937                   /usr/lib64/liblzma.so.5.0.99
7f2889b97000-7f2889bac000 r-xp 00000000 fd:01 67177068                   /usr/lib64/libz.so.1.2.7
7f2889bac000-7f2889dab000 ---p 00015000 fd:01 67177068                   /usr/lib64/libz.so.1.2.7
7f2889dab000-7f2889dac000 r--p 00014000 fd:01 67177068                   /usr/lib64/libz.so.1.2.7
7f2889dac000-7f2889dad000 rw-p 00015000 fd:01 67177068                   /usr/lib64/libz.so.1.2.7
7f2889dad000-7f2889db0000 r-xp 00000000 fd:01 67591509                   /usr/lib64/libdl-2.17.so
7f2889db0000-7f2889faf000 ---p 00003000 fd:01 67591509                   /usr/lib64/libdl-2.17.so
7f2889faf000-7f2889fb0000 r--p 00002000 fd:01 67591509                   /usr/lib64/libdl-2.17.so
7f2889fb0000-7f2889fb1000 rw-p 00003000 fd:01 67591509                   /usr/lib64/libdl-2.17.so
7f2889fb1000-7f2889fd6000 r-xp 00000000 fd:01 67176957                   /usr/lib64/libtinfo.so.5.9
7f2889fd6000-7f288a1d6000 ---p 00025000 fd:01 67176957                   /usr/lib64/libtinfo.so.5.9
7f288a1d6000-7f288a1da000 r--p 00025000 fd:01 67176957                   /usr/lib64/libtinfo.so.5.9
7f288a1da000-7f288a1db000 rw-p 00029000 fd:01 67176957                   /usr/lib64/libtinfo.so.5.9
7f288a1db000-7f288a1f0000 r-xp 00000000 fd:01 68621177                   /usr/lib64/libgcc_s-4.8.3-20140911.so.1
7f288a1f0000-7f288a3ef000 ---p 00015000 fd:01 68621177                   /usr/lib64/libgcc_s-4.8.3-20140911.so.1
7f288a3ef000-7f288a3f0000 r--p 00014000 fd:01 68621177                   /usr/lib64/libgcc_s-4.8.3-20140911.so.1
7f288a3f0000-7f288a3f1000 rw-p 00015000 fd:01 68621177                   /usr/lib64/libgcc_s-4.8.3-20140911.so.1
7f288a3f1000-7f288a5a7000 r-xp 00000000 fd:01 67591503                   /usr/lib64/libc-2.17.so
7f288a5a7000-7f288a7a7000 ---p 001b6000 fd:01 67591503                   /usr/lib64/libc-2.17.so
7f288a7a7000-7f288a7ab000 r--p 001b6000 fd:01 67591503                   /usr/lib64/libc-2.17.so
7f288a7ab000-7f288a7ad000 rw-p 001ba000 fd:01 67591503                   /usr/lib64/libc-2.17.so
7f288a7ad000-7f288a7b2000 rw-p 00000000 00:00 0
7f288a7b2000-7f288a910000 r-xp 00000000 fd:01 68828939                   /usr/lib64/libxml2.so.2.9.1
7f288a910000-7f288ab0f000 ---p 0015e000 fd:01 68828939                   /usr/lib64/libxml2.so.2.9.1
7f288ab0f000-7f288ab17000 r--p 0015d000 fd:01 68828939                   /usr/lib64/libxml2.so.2.9.1
7f288ab17000-7f288ab19000 rw-p 00165000 fd:01 68828939                   /usr/lib64/libxml2.so.2.9.1
7f288ab19000-7f288ab1b000 rw-p 00000000 00:00 0
7f288ab1b000-7f288ab57000 r-xp 00000000 fd:01 67177123                   /usr/lib64/libreadline.so.6.2
7f288ab57000-7f288ad57000 ---p 0003c000 fd:01 67177123                   /usr/lib64/libreadline.so.6.2
7f288ad57000-7f288ad59000 r--p 0003c000 fd:01 67177123                   /usr/lib64/libreadline.so.6.2
7f288ad59000-7f288ad5f000 rw-p 0003e000 fd:01 67177123                   /usr/lib64/libreadline.so.6.2
7f288ad5f000-7f288ad61000 rw-p 00000000 00:00 0
7f288ad61000-7f288ad73000 r-xp 00000000 fd:01 101261092                  /usr/local/lib/libfa.so.1.4.1
7f288ad73000-7f288af72000 ---p 00012000 fd:01 101261092                  /usr/local/lib/libfa.so.1.4.1
7f288af72000-7f288af73000 r--p 00011000 fd:01 101261092                  /usr/local/lib/libfa.so.1.4.1
7f288af73000-7f288af74000 rw-p 00012000 fd:01 101261092                  /usr/local/lib/libfa.so.1.4.1
7f288af74000-7f288afbd000 r-xp 00000000 fd:01 101844511                  /usr/local/lib/libaugeas.so.0.20.0Aborted

In the second testcase, I've un-nested the elements and Augeas is able to remove them with no problems:

[root@localhost vagrant]# augtool
augtool> set /augeas/load/Xfm/lens Xml.lns
augtool> set /augeas/load/Xfm/incl /vagrant/testcase2.xml
augtool> load
augtool> rm /files/vagrant/testcase2.xml/Server//Realm
rm : /files/vagrant/testcase2.xml/Server//Realm 8

How to fix this?

I'm not immediately clear on how this can be fixed being new to the internals of Augeas.

Looking at the nesting of the elements I'm trying to delete, the pointer structure I'm seeing makes sense since its the exact same XML nodes inside one another. I had been working under the assumption that the code was copying an object by reference instead of cloning it but clearly the parsing code is correct and not at fault.

It looks like the trees passed for deletion in tree_rm() need to be de-duplicated somehow, so that we don't try to delete nodes that are contained within a parent tree that has already been deleted - but I'm not sure of the best way to do this, can anyone help?

Thanks! testcase.xml.txt testcase2.xml.txt

lutter commented 8 years ago

Thanks for the excellent and thorough bug report. Having that made fixing this bug really easy. I'll leave the PR open for a couple days to give you chance to test it - if you do, lmk if it really does fix the issue.

GeoffWilliams commented 8 years ago

NP! PR fixes issue