Skip Menu |

This queue is for tickets about the XML-Bare CPAN distribution.

Report information
The Basics
Id: 52832
Status: resolved
Priority: 0/
Queue: XML-Bare

People
Owner: cpan [...] codechild.com
Requestors: mar.kolya [...] gmail.com
Cc:
AdminCc:

Bug Information
Severity: Normal
Broken in: 0.45
Fixed in: 0.48



Subject: Several memory leaks
In case parse() is not called after call to new memory allocated by 'new' for the xml tree is never freed. 'parser' and 'data' variables are not freed in c_parse() and c_parsefile() Please see patch attached with fixes for this. This patch also includes changes for 52762.
Subject: patch.diff
diff -ru XML-Bare-0.45/Bare.pm XML-Bare-0.45.new/Bare.pm --- XML-Bare-0.45/Bare.pm 2009-08-02 17:09:54.000000000 -0400 +++ XML-Bare-0.45.new/Bare.pm 2009-12-16 10:19:03.585038611 -0500 @@ -38,6 +38,7 @@ if( $self->{ 'text' } ) { XML::Bare::c_parse( $self->{'text'} ); + $self->{'structroot'} = XML::Bare::get_root(); } else { my $res = open( XML, $self->{ 'file' } ); @@ -51,6 +52,7 @@ } close( XML ); XML::Bare::c_parse( $self->{'text'} ); + $self->{'structroot'} = XML::Bare::get_root(); } bless $self, $class; return $self if( !wantarray ); @@ -59,6 +61,7 @@ sub DESTROY { my $self = shift; + $self->free_tree(); undef $self->{'xml'}; } @@ -779,7 +782,13 @@ return ''; } -sub free_tree { my $self = shift; XML::Bare::free_tree_c( $self->{'structroot'} ); } +sub free_tree { + my $self = shift; + if($self->{'structroot'}) { + XML::Bare::free_tree_c($self->{'structroot'}); + delete($self->{'structroot'}); + } +} 1; diff -ru XML-Bare-0.45/Bare.xs XML-Bare-0.45.new/Bare.xs --- XML-Bare-0.45/Bare.xs 2009-08-02 17:12:19.000000000 -0400 +++ XML-Bare-0.45.new/Bare.xs 2009-12-16 11:28:17.879011654 -0500 @@ -227,6 +227,10 @@ if( i != ( length - 1 ) ) curnode = curnode->next; } curnode = curnode->parent; + } else { + SV * sv = newSVpvn( curnode->value, curnode->vallen ); + SvUTF8_on(sv); + hv_store( output, "content", 7, sv, vhash ); } if( numatts ) { @@ -242,23 +246,24 @@ return outputref; } -struct parserc *parser = 0; - MODULE = XML::Bare PACKAGE = XML::Bare SV * xml2obj() CODE: - curnode = parser->pcurnode; - if( curnode->err ) RETVAL = newSViv( curnode->err ); - else RETVAL = cxml2obj(); + if( root->err ) RETVAL = newSViv( root->err ); + else { + curnode = root; + RETVAL = cxml2obj(); + } OUTPUT: RETVAL SV * xml2obj_simple() CODE: - curnode = parser->pcurnode; + PERL_HASH(vhash, "content", 7); + curnode = root; RETVAL = cxml2obj_simple(); OUTPUT: RETVAL @@ -275,9 +280,8 @@ PERL_HASH(ihash, "_i", 2 ); PERL_HASH(zhash, "_z", 2 ); PERL_HASH(cdhash, "_cdata", 6 ); - parser = (struct parserc *) malloc( sizeof( struct parserc ) ); - root = parserc_parse( parser, text ); - + root = parserc_parse( text ); + void c_parsefile(filename) char * filename @@ -305,8 +309,8 @@ rootpos = data; fread( data, 1, len, handle ); fclose( handle ); - parser = (struct parserc *) malloc( sizeof( struct parserc ) ); - root = parserc_parse( parser, data ); + root = parserc_parse( data ); + free( data ); SV * get_root() @@ -321,4 +325,4 @@ CODE: struct nodec *rootnode; rootnode = INT2PTR( struct nodec *, SvUV( rootsv ) ); - del_nodec( rootnode ); \ No newline at end of file + del_nodec( rootnode ); Only in XML-Bare-0.45.new: Makefile.old diff -ru XML-Bare-0.45/parser.c XML-Bare-0.45.new/parser.c --- XML-Bare-0.45/parser.c 2009-08-02 17:09:54.000000000 -0400 +++ XML-Bare-0.45.new/parser.c 2009-12-16 11:15:11.398014171 -0500 @@ -1,5 +1,6 @@ #include "parser.h" -#include<stdio.h> +#include <stdlib.h> +#include <stdio.h> #ifdef DARWIN #include "stdlib.h" #endif @@ -69,7 +70,7 @@ //#define DEBUG -struct nodec* parserc_parse( struct parserc *self, char *xmlin ) { +struct nodec* parserc_parse( char *xmlin ) { char *tagname, *attname, *attval, *val; struct nodec *root = new_nodec(); int tagname_len = 0; @@ -582,15 +583,12 @@ goto ename_x; error: root->err = - ( int ) ( cpos - &xmlin[0] ); - self->pcurnode = root; //root->err = 1; return root; done: #ifdef DEBUG printf("done\n", *cpos); #endif - self->pcurnode = root; - self->pcurnode->curchild = self->pcurnode->firstchild; #ifdef DEBUG printf("returning\n", *cpos); #endif diff -ru XML-Bare-0.45/parser.h XML-Bare-0.45.new/parser.h --- XML-Bare-0.45/parser.h 2009-08-02 17:09:54.000000000 -0400 +++ XML-Bare-0.45.new/parser.h 2009-12-16 11:22:14.918523469 -0500 @@ -50,9 +50,4 @@ struct attc* new_attc( struct nodec *newparent ); -struct parserc { - struct nodec *pcurnode; - struct attc *curatt; -}; - -struct nodec* parserc_parse( struct parserc *self, char *newbuf ); +struct nodec* parserc_parse( char *newbuf ); diff -ru XML-Bare-0.45/t/Basic.t XML-Bare-0.45.new/t/Basic.t --- XML-Bare-0.45/t/Basic.t 2009-08-02 17:10:02.000000000 -0400 +++ XML-Bare-0.45.new/t/Basic.t 2009-12-16 10:41:51.429041159 -0500 @@ -1,7 +1,6 @@ #!/usr/bin/perl -w use strict; - use Test::More qw(no_plan); use_ok( 'XML::Bare', qw/xmlin/ ); @@ -30,6 +29,10 @@ is( $root->{xml}->{node}->{value}, '<cval>', 'reading of cdata' ); is( $simple->{node}, '<cval>', 'simple - reading of cdata' ); +( $xml, $root, $simple ) = reparse( "<xml><node att=\"12\"><![CDATA[<cval>]]></node></xml>" ); +is( $root->{xml}->{node}->{value}, '<cval>', 'reading of cdata' ); +is( $simple->{node}->{content}, '<cval>', 'simple - reading of cdata' ); + ( $xml, $root, $simple ) = reparse( "<xml><node>a</node><node>b</node></xml>" ); is( $root->{xml}->{node}->[1]->{value}, 'b', 'multiple node array creation' ); is( $simple->{node}[1], 'b', 'simple - multiple node array creation' );
The module has been changed to work in a multi-threaded environment in version 0.48. Note that the patch you provided was included in the 0.46 and 0.47 versions of the module, but the changes are no longer included, for specific reasons. The parser should be freed immediately in all cases. It is done whenever a parser is allocated, not on destruction of the objection. The parser does not need to live for the life of the object the way the module works. More changes still need to be made to ensure error handling is still done properly. The get_root function has been removed entirely because it is not needed. The patch seems to arbitrarily include "stdlib.h" even when it is not needed. Is there some purpose to this? The patch removes 'pcurnode' references within the module. In fact, it removes all references to the parser object entirely. This is unacceptable; while the parser object is not used to potential right now, it is there intentionally so that it can be extended to allow error checking to be more advanced and pass state of the parser back to perl. I believe it is true that there are additional memory leaks in the system, but I don't believe these patches address those additional problems. ( nor is it described here when those occur ) In summary, the issue described by this ticket should be fixed in 0.48 and 0.49. It was also "fixed" in 0.46 and 0.47, but not in an appropriate fashion.