Skip to content
This repository was archived by the owner on Mar 8, 2020. It is now read-only.

Commit d363170

Browse files
authored
Merge pull request #102 from juanjux/fix/positions_leak
Fix leaks in HasPosition calls
2 parents 3a2bf50 + 1ca9bec commit d363170

File tree

3 files changed

+51
-12
lines changed

3 files changed

+51
-12
lines changed

bblfsh/pyuast.cc

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,33 @@
88
#include "memtracker.h"
99

1010

11-
MemTracker memTracker;
1211

1312
// Used to store references to the Pyobjects instanced in String() and
1413
// ItemAt() methods. Those can't be DECREF'ed to 0 because libuast uses them
1514
// so we pass ownership to these lists and free them at the end of filter()
15+
MemTracker memTracker;
1616

17+
// WARNING: calls to Attribute MUST Py_DECREF the returned value once
18+
// used (or add it to the memtracker)
1719
static PyObject *Attribute(const void *node, const char *prop) {
1820
PyObject *n = (PyObject *)node;
1921
return PyObject_GetAttrString(n, prop);
2022
}
2123

24+
// WARNING: calls to AttributeValue MUST Py_DECREF the returned value once
25+
// used (or add it to the memtracker)
2226
static PyObject *AttributeValue(const void *node, const char *prop) {
2327
PyObject *a = Attribute(node, prop);
2428
return a && a != Py_None ? a : NULL;
2529
}
2630

31+
static bool HasAttribute(const void *node, const char *prop) {
32+
PyObject *o = AttributeValue(node, prop);
33+
bool res = o != NULL;
34+
Py_DECREF(o);
35+
return res;
36+
}
37+
2738
static const char *String(const void *node, const char *prop) {
2839
const char *retval = NULL;
2940
PyObject *o = Attribute(node, prop);
@@ -163,47 +174,47 @@ static uint32_t PositionValue(const void* node, const char *prop, const char *fi
163174
extern "C"
164175
{
165176
static bool HasStartOffset(const void *node) {
166-
return AttributeValue(node, "start_position");
177+
return HasAttribute(node, "start_position");
167178
}
168179

169180
static uint32_t StartOffset(const void *node) {
170181
return PositionValue(node, "start_position", "offset");
171182
}
172183

173184
static bool HasStartLine(const void *node) {
174-
return AttributeValue(node, "start_position");
185+
return HasAttribute(node, "start_position");
175186
}
176187

177188
static uint32_t StartLine(const void *node) {
178189
return PositionValue(node, "start_position", "line");
179190
}
180191

181192
static bool HasStartCol(const void *node) {
182-
return AttributeValue(node, "start_position");
193+
return HasAttribute(node, "start_position");
183194
}
184195

185196
static uint32_t StartCol(const void *node) {
186197
return PositionValue(node, "start_position", "col");
187198
}
188199

189200
static bool HasEndOffset(const void *node) {
190-
return AttributeValue(node, "end_position");
201+
return HasAttribute(node, "end_position");
191202
}
192203

193204
static uint32_t EndOffset(const void *node) {
194205
return PositionValue(node, "end_position", "offset");
195206
}
196207

197208
static bool HasEndLine(const void *node) {
198-
return AttributeValue(node, "end_position");
209+
return HasAttribute(node, "end_position");
199210
}
200211

201212
static uint32_t EndLine(const void *node) {
202213
return PositionValue(node, "end_position", "line");
203214
}
204215

205216
static bool HasEndCol(const void *node) {
206-
return AttributeValue(node, "end_position");
217+
return HasAttribute(node, "end_position");
207218
}
208219

209220
static uint32_t EndCol(const void *node) {

bblfsh/test.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import os
2+
import resource
23
import unittest
34

45
import docker
@@ -250,18 +251,45 @@ def testManyFilters(self):
250251
root.properties['k1'] = 'v2'
251252
root.properties['k2'] = 'v1'
252253

253-
import resource
254254
before = resource.getrusage(resource.RUSAGE_SELF)
255255
for _ in range(500):
256256
filter(root, "//*[@roleIdentifier]")
257+
257258
after = resource.getrusage(resource.RUSAGE_SELF)
258259

259260
# Check that memory usage has not doubled after running the filter
260261
self.assertLess(after[2] / before[2], 2.0)
261262

263+
def testManyParses(self):
264+
before = resource.getrusage(resource.RUSAGE_SELF)
265+
for _ in range(100):
266+
root = self.client.parse(__file__).uast
267+
root.properties['k1'] = 'v2'
268+
root.properties['k2'] = 'v1'
269+
270+
after = resource.getrusage(resource.RUSAGE_SELF)
271+
272+
# Check that memory usage has not doubled after running the parse+filter
273+
self.assertLess(after[2] / before[2], 2.0)
274+
275+
def testManyParsersAndFilters(self):
276+
before = resource.getrusage(resource.RUSAGE_SELF)
277+
for _ in range(100):
278+
root = self.client.parse(__file__).uast
279+
root.properties['k1'] = 'v2'
280+
root.properties['k2'] = 'v1'
281+
282+
filter(root, "//*[@roleIdentifier]")
283+
284+
after = resource.getrusage(resource.RUSAGE_SELF)
285+
286+
# Check that memory usage has not doubled after running the parse+filter
287+
self.assertLess(after[2] / before[2], 2.0)
288+
262289
def _validate_filter(self, resp):
263290
results = filter(resp.uast, "//Import[@roleImport and @roleDeclaration]//alias")
264291
self.assertEqual(next(results).token, "os")
292+
self.assertEqual(next(results).token, "resource")
265293
self.assertEqual(next(results).token, "unittest")
266294
self.assertEqual(next(results).token, "docker")
267295

setup.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from setuptools import setup, find_packages, Extension
55
from setuptools.command.build_ext import build_ext
66

7-
VERSION = "2.9.11"
7+
VERSION = "2.9.12"
88
LIBUAST_VERSION = "v1.9.1"
99
SDK_VERSION = "v1.8.0"
1010
SDK_MAJOR = SDK_VERSION.split('.')[0]
@@ -76,9 +76,9 @@ def getLibuast():
7676
if not GET_LIBUAST:
7777
return
7878

79-
runc("curl -SL https://github.com/bblfsh/libuast/releases/download/{LIBUAST_VERSION}/"
80-
"libuast-{LIBUAST_VERSION}.tar.gz | tar xz")
81-
runc("mv libuast-{LIBUAST_VERSION} libuast")
79+
runc("curl -SL https://github.com/bblfsh/libuast/archive/{LIBUAST_VERSION}/"
80+
"{LIBUAST_VERSION}.tar.gz | tar xz")
81+
runc("mv {} libuast".format('libuast-' + LIBUAST_VERSION.replace('v', '')))
8282
runc("cp -a libuast/src bblfsh/libuast")
8383
runc("rm -rf libuast")
8484

0 commit comments

Comments
 (0)