Skip to content

Commit d757e77

Browse files
authored
fix Python buffers & C++ doc leaks, add modern Python support (fixes #7) (#9)
1 parent d0da6e6 commit d757e77

File tree

10 files changed

+117
-36
lines changed

10 files changed

+117
-36
lines changed

README.md

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,3 @@ git clone https://github.com/Arzaroth/python_rapidxml.git
5656
MIT license. See the LICENSE file.
5757

5858

59-
### Development status
60-
61-
[![Build Status](https://travis-ci.org/Arzaroth/python_rapidxml.svg?branch=master)](https://travis-ci.org/Arzaroth/python_rapidxml)
62-
63-
This project is currently under development.

rapidxml/c_ext/inc/common.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ extern PyObject* rapidxml_RapidXmlError;
7676
** Utility functions
7777
*/
7878

79-
int _parse_args_for_name(PyObject*, PyObject*, const char**);
79+
int _parse_args_for_name(PyObject*, PyObject*, Py_buffer*, const char**);
8080
PyObject* _bind_result(rapidxml_BaseObject*, rapidxml::xml_base<>*, PyTypeObject*);
8181

8282
/*

rapidxml/c_ext/src/attribute_object.cpp

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,18 +24,25 @@ static PyObject* rapidxml_AttributeObject_previous_attribute(rapidxml_AttributeO
2424
PyObject* args,
2525
PyObject* kwds) {
2626
const char* name = NULL;
27+
Py_buffer name_buff = {0};
2728
rapidxml::xml_attribute<>* attribute;
2829

29-
if (!_parse_args_for_name(args, kwds, &name)) {
30+
if (!_parse_args_for_name(args, kwds, &name_buff, &name)) {
3031
goto err;
3132
}
3233
attribute = static_cast<rapidxml::xml_attribute<>*>(self->base.underlying_obj)->previous_attribute(name);
3334
if (attribute == NULL) {
3435
goto err;
3536
}
37+
if (name_buff.buf) {
38+
PyBuffer_Release(&name_buff);
39+
}
3640
return _bind_result(reinterpret_cast<rapidxml_BaseObject*>(self),
3741
attribute, &rapidxml_AttributeType);
3842
err:
43+
if (name_buff.buf) {
44+
PyBuffer_Release(&name_buff);
45+
}
3946
Py_INCREF(Py_None);
4047
return Py_None;
4148
}
@@ -44,18 +51,25 @@ static PyObject* rapidxml_AttributeObject_next_attribute(rapidxml_AttributeObjec
4451
PyObject* args,
4552
PyObject* kwds) {
4653
const char* name = NULL;
54+
Py_buffer name_buff = {0};
4755
rapidxml::xml_attribute<>* attribute;
4856

49-
if (!_parse_args_for_name(args, kwds, &name)) {
57+
if (!_parse_args_for_name(args, kwds, &name_buff, &name)) {
5058
goto err;
5159
}
5260
attribute = static_cast<rapidxml::xml_attribute<>*>(self->base.underlying_obj)->next_attribute(name);
5361
if (attribute == NULL) {
5462
goto err;
5563
}
64+
if (name_buff.buf) {
65+
PyBuffer_Release(&name_buff);
66+
}
5667
return _bind_result(reinterpret_cast<rapidxml_BaseObject*>(self),
5768
attribute, &rapidxml_AttributeType);
5869
err:
70+
if (name_buff.buf) {
71+
PyBuffer_Release(&name_buff);
72+
}
5973
Py_INCREF(Py_None);
6074
return Py_None;
6175
}

rapidxml/c_ext/src/base_object.cpp

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ static PyObject* rapidxml_BaseObject_getname(rapidxml_BaseObject* self,
106106
static int rapidxml_BaseObject_setname(rapidxml_BaseObject* self,
107107
PyObject* arg,
108108
void* closure) {
109-
Py_buffer name;
109+
Py_buffer name = {0};
110110

111111
if (self->underlying_obj == NULL || self->document == NULL) {
112112
PyErr_SetString(rapidxml_RapidXmlError,
@@ -122,6 +122,7 @@ static int rapidxml_BaseObject_setname(rapidxml_BaseObject* self,
122122
return -1;
123123
}
124124
self->underlying_obj->name(self->document->allocate_string(static_cast<const char*>(name.buf)));
125+
PyBuffer_Release(&name);
125126
return 0;
126127
}
127128

@@ -147,7 +148,7 @@ static PyObject* rapidxml_BaseObject_getvalue(rapidxml_BaseObject* self,
147148
static int rapidxml_BaseObject_setvalue(rapidxml_BaseObject* self,
148149
PyObject* arg,
149150
void* closure) {
150-
Py_buffer value;
151+
Py_buffer value = {0};
151152

152153
if (self->underlying_obj == NULL || self->document == NULL) {
153154
PyErr_SetString(rapidxml_RapidXmlError,
@@ -163,6 +164,7 @@ static int rapidxml_BaseObject_setvalue(rapidxml_BaseObject* self,
163164
return -1;
164165
}
165166
self->underlying_obj->value(self->document->allocate_string(static_cast<const char*>(value.buf)));
167+
PyBuffer_Release(&value);
166168
return 0;
167169
}
168170

rapidxml/c_ext/src/common.cpp

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,21 @@
1515

1616
int _parse_args_for_name(PyObject* args,
1717
PyObject* kwds,
18+
Py_buffer* buf,
1819
const char** name) {
19-
Py_buffer buf = {0};
20+
*name = NULL;
21+
if (buf != NULL) {
22+
buf->buf = NULL;
23+
buf->obj = NULL;
24+
}
2025

2126
static char* kwlist[] = {"name", NULL};
2227
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|s*", kwlist,
23-
&buf)) {
28+
buf)) {
2429
return false;
2530
}
26-
if (buf.buf) {
27-
*name = static_cast<const char*>(buf.buf);
31+
if (buf != NULL && buf->buf) {
32+
*name = static_cast<const char*>(buf->buf);
2833
}
2934
return true;
3035
}

rapidxml/c_ext/src/document_object.cpp

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ static int _parse(rapidxml_DocumentObject* self,
6262
static PyObject* rapidxml_DocumentObject_parse(rapidxml_DocumentObject* self,
6363
PyObject* args,
6464
PyObject* kwds) {
65-
Py_buffer text_buff;
65+
Py_buffer text_buff = {0};
6666
PyObject* from_file_obj = NULL;
6767
PyObject* read_cdata = NULL;
6868

@@ -72,9 +72,13 @@ static PyObject* rapidxml_DocumentObject_parse(rapidxml_DocumentObject* self,
7272
return NULL;
7373
}
7474

75-
if (!_parse(self, &text_buff,
76-
(from_file_obj != NULL) && PyObject_IsTrue(from_file_obj),
77-
(read_cdata != NULL) && PyObject_IsTrue(read_cdata))) {
75+
int parsed = _parse(self, &text_buff,
76+
(from_file_obj != NULL) && PyObject_IsTrue(from_file_obj),
77+
(read_cdata != NULL) && PyObject_IsTrue(read_cdata));
78+
if (text_buff.buf) {
79+
PyBuffer_Release(&text_buff);
80+
}
81+
if (!parsed) {
7882
return NULL;
7983
}
8084
Py_INCREF(Py_None);
@@ -99,20 +103,21 @@ static int rapidxml_DocumentObject_init(rapidxml_DocumentObject* self,
99103
self->base.base.underlying_obj = new rapidxml::xml_document<>();
100104
self->base.base.document = static_cast<rapidxml::xml_document<>*>(self->base.base.underlying_obj);
101105
if (text_buff.buf) {
102-
return (_parse(self, &text_buff,
103-
(from_file_obj != NULL) && PyObject_IsTrue(from_file_obj),
104-
(read_cdata != NULL) && PyObject_IsTrue(read_cdata))
105-
- 1);
106+
int parsed = _parse(self, &text_buff,
107+
(from_file_obj != NULL) && PyObject_IsTrue(from_file_obj),
108+
(read_cdata != NULL) && PyObject_IsTrue(read_cdata));
109+
PyBuffer_Release(&text_buff);
110+
return parsed - 1;
106111
}
107112
return 0;
108113
}
109114

110115
static PyObject* rapidxml_DocumentObject_allocate_node(rapidxml_DocumentObject* self,
111116
PyObject* args,
112117
PyObject* kwds) {
113-
const char* name;
118+
const char* name = NULL;
114119
Py_buffer name_buff = {0};
115-
const char* value;
120+
const char* value = NULL;
116121
Py_buffer value_buff = {0};
117122
rapidxml::xml_node<>* node;
118123

@@ -131,16 +136,22 @@ static PyObject* rapidxml_DocumentObject_allocate_node(rapidxml_DocumentObject*
131136
value = self->base.base.document->allocate_string(value);
132137
}
133138
node = self->base.base.document->allocate_node(rapidxml::node_element, name, value);
139+
if (name_buff.buf) {
140+
PyBuffer_Release(&name_buff);
141+
}
142+
if (value_buff.buf) {
143+
PyBuffer_Release(&value_buff);
144+
}
134145
return _bind_result(reinterpret_cast<rapidxml_BaseObject*>(self),
135146
node, &rapidxml_NodeType);
136147
}
137148

138149
static PyObject* rapidxml_DocumentObject_allocate_attribute(rapidxml_DocumentObject* self,
139150
PyObject* args,
140151
PyObject* kwds) {
141-
const char* name;
152+
const char* name = NULL;
142153
Py_buffer name_buff = {0};
143-
const char* value;
154+
const char* value = NULL;
144155
Py_buffer value_buff = {0};
145156
rapidxml::xml_attribute<>* attribute;
146157

@@ -159,6 +170,12 @@ static PyObject* rapidxml_DocumentObject_allocate_attribute(rapidxml_DocumentObj
159170
value = self->base.base.document->allocate_string(value);
160171
}
161172
attribute = self->base.base.document->allocate_attribute(name, value);
173+
if (name_buff.buf) {
174+
PyBuffer_Release(&name_buff);
175+
}
176+
if (value_buff.buf) {
177+
PyBuffer_Release(&value_buff);
178+
}
162179
return _bind_result(reinterpret_cast<rapidxml_BaseObject*>(self),
163180
attribute, &rapidxml_AttributeType);
164181
}

rapidxml/c_ext/src/node_object.cpp

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,18 +42,25 @@ static PyObject* rapidxml_NodeObject_first_node(rapidxml_NodeObject* self,
4242
PyObject* args,
4343
PyObject* kwds) {
4444
const char* name = NULL;
45+
Py_buffer name_buff = {0};
4546
rapidxml::xml_node<>* node;
4647

47-
if (!_parse_args_for_name(args, kwds, &name)) {
48+
if (!_parse_args_for_name(args, kwds, &name_buff, &name)) {
4849
goto err;
4950
}
5051
node = static_cast<rapidxml::xml_node<>*>(self->base.underlying_obj)->first_node(name);
5152
if (node == NULL) {
5253
goto err;
5354
}
55+
if (name_buff.buf) {
56+
PyBuffer_Release(&name_buff);
57+
}
5458
return _bind_result(reinterpret_cast<rapidxml_BaseObject*>(self),
5559
node, &rapidxml_NodeType);
5660
err:
61+
if (name_buff.buf) {
62+
PyBuffer_Release(&name_buff);
63+
}
5764
Py_INCREF(Py_None);
5865
return Py_None;
5966
}
@@ -62,19 +69,26 @@ static PyObject* rapidxml_NodeObject_last_node(rapidxml_NodeObject* self,
6269
PyObject* args,
6370
PyObject* kwds) {
6471
const char* name = NULL;
72+
Py_buffer name_buff = {0};
6573
rapidxml::xml_node<>* node;
6674

67-
if (!(_parse_args_for_name(args, kwds, &name) &&
75+
if (!(_parse_args_for_name(args, kwds, &name_buff, &name) &&
6876
static_cast<rapidxml::xml_node<>*>(self->base.underlying_obj)->first_node())) {
6977
goto err;
7078
}
7179
node = static_cast<rapidxml::xml_node<>*>(self->base.underlying_obj)->last_node(name);
7280
if (node == NULL) {
7381
goto err;
7482
}
83+
if (name_buff.buf) {
84+
PyBuffer_Release(&name_buff);
85+
}
7586
return _bind_result(reinterpret_cast<rapidxml_BaseObject*>(self),
7687
node, &rapidxml_NodeType);
7788
err:
89+
if (name_buff.buf) {
90+
PyBuffer_Release(&name_buff);
91+
}
7892
Py_INCREF(Py_None);
7993
return Py_None;
8094
}
@@ -83,19 +97,26 @@ static PyObject* rapidxml_NodeObject_previous_sibling(rapidxml_NodeObject* self,
8397
PyObject* args,
8498
PyObject* kwds) {
8599
const char* name = NULL;
100+
Py_buffer name_buff = {0};
86101
rapidxml::xml_node<>* node;
87102

88-
if (!(_parse_args_for_name(args, kwds, &name) &&
103+
if (!(_parse_args_for_name(args, kwds, &name_buff, &name) &&
89104
static_cast<rapidxml::xml_node<>*>(self->base.underlying_obj)->parent())) {
90105
goto err;
91106
}
92107
node = static_cast<rapidxml::xml_node<>*>(self->base.underlying_obj)->previous_sibling(name);
93108
if (node == NULL) {
94109
goto err;
95110
}
111+
if (name_buff.buf) {
112+
PyBuffer_Release(&name_buff);
113+
}
96114
return _bind_result(reinterpret_cast<rapidxml_BaseObject*>(self),
97115
node, &rapidxml_NodeType);
98116
err:
117+
if (name_buff.buf) {
118+
PyBuffer_Release(&name_buff);
119+
}
99120
Py_INCREF(Py_None);
100121
return Py_None;
101122
}
@@ -104,19 +125,26 @@ static PyObject* rapidxml_NodeObject_next_sibling(rapidxml_NodeObject* self,
104125
PyObject* args,
105126
PyObject* kwds) {
106127
const char* name = NULL;
128+
Py_buffer name_buff = {0};
107129
rapidxml::xml_node<>* node;
108130

109-
if (!(_parse_args_for_name(args, kwds, &name) &&
131+
if (!(_parse_args_for_name(args, kwds, &name_buff, &name) &&
110132
static_cast<rapidxml::xml_node<>*>(self->base.underlying_obj)->parent())) {
111133
goto err;
112134
}
113135
node = static_cast<rapidxml::xml_node<>*>(self->base.underlying_obj)->next_sibling(name);
114136
if (node == NULL) {
115137
goto err;
116138
}
139+
if (name_buff.buf) {
140+
PyBuffer_Release(&name_buff);
141+
}
117142
return _bind_result(reinterpret_cast<rapidxml_BaseObject*>(self),
118143
node, &rapidxml_NodeType);
119144
err:
145+
if (name_buff.buf) {
146+
PyBuffer_Release(&name_buff);
147+
}
120148
Py_INCREF(Py_None);
121149
return Py_None;
122150
}
@@ -125,18 +153,25 @@ static PyObject* rapidxml_NodeObject_first_attribute(rapidxml_NodeObject* self,
125153
PyObject* args,
126154
PyObject* kwds) {
127155
const char* name = NULL;
156+
Py_buffer name_buff = {0};
128157
rapidxml::xml_attribute<>* attribute;
129158

130-
if (!_parse_args_for_name(args, kwds, &name)) {
159+
if (!_parse_args_for_name(args, kwds, &name_buff, &name)) {
131160
goto err;
132161
}
133162
attribute = static_cast<rapidxml::xml_node<>*>(self->base.underlying_obj)->first_attribute(name);
134163
if (attribute == NULL) {
135164
goto err;
136165
}
166+
if (name_buff.buf) {
167+
PyBuffer_Release(&name_buff);
168+
}
137169
return _bind_result(reinterpret_cast<rapidxml_BaseObject*>(self),
138170
attribute, &rapidxml_AttributeType);
139171
err:
172+
if (name_buff.buf) {
173+
PyBuffer_Release(&name_buff);
174+
}
140175
Py_INCREF(Py_None);
141176
return Py_None;
142177
}
@@ -145,18 +180,25 @@ static PyObject* rapidxml_NodeObject_last_attribute(rapidxml_NodeObject* self,
145180
PyObject* args,
146181
PyObject* kwds) {
147182
const char* name = NULL;
183+
Py_buffer name_buff = {0};
148184
rapidxml::xml_attribute<>* attribute;
149185

150-
if (!_parse_args_for_name(args, kwds, &name)) {
186+
if (!_parse_args_for_name(args, kwds, &name_buff, &name)) {
151187
goto err;
152188
}
153189
attribute = static_cast<rapidxml::xml_node<>*>(self->base.underlying_obj)->last_attribute(name);
154190
if (attribute == NULL) {
155191
goto err;
156192
}
193+
if (name_buff.buf) {
194+
PyBuffer_Release(&name_buff);
195+
}
157196
return _bind_result(reinterpret_cast<rapidxml_BaseObject*>(self),
158197
attribute, &rapidxml_AttributeType);
159198
err:
199+
if (name_buff.buf) {
200+
PyBuffer_Release(&name_buff);
201+
}
160202
Py_INCREF(Py_None);
161203
return Py_None;
162204
}

rapidxml/rapidxml.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ def __iter__(self):
9494
self.cdata_key,
9595
self.always_aslist)
9696

97-
class RapidXml(DictNode, rapidxml.c_ext.Document):
97+
class RapidXml(rapidxml.c_ext.Document, DictNode):
9898
def __init__(self,
9999
text="",
100100
from_file=False,

0 commit comments

Comments
 (0)