Skip to content

Commit 1908f17

Browse files
committedJun 19, 2022
Tests passing once we let memory leak. Fix for memory leaks to be carefully enabled.
1 parent 794be8f commit 1908f17

File tree

5 files changed

+74
-46
lines changed

5 files changed

+74
-46
lines changed
 

‎_examples/multireturn/multireturn.go

+4-1
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,12 @@ func SingleWithErrorFunc(throwError bool) error {
2828
}
2929

3030
/////////////// Double WithoutError Return //////////////
31-
func DoubleWithoutErrorFunc() (int, int) {
31+
func DoubleWithoutErrorFunc1() (int, int) {
3232
return 200, 300
3333
}
34+
func DoubleWithoutErrorFunc2() (string, string) {
35+
return "200", "300"
36+
}
3437

3538
/////////////// Double WithError Return //////////////
3639
func DoubleWithErrorFunc(throwError bool) (string, error) {

‎_examples/multireturn/test.py

+21-14
Original file line numberDiff line numberDiff line change
@@ -16,25 +16,28 @@
1616
print("Single Str WithoutError Return %r" % oneStrResult)
1717

1818
############### Single WithError Return ##############
19-
errorFalseResult = multireturn.SingleWithErrorFunc(False)
20-
print("Single WithError(False) Return %r" % errorFalseResult)
19+
errorFalseResult1 = multireturn.SingleWithErrorFunc(False)
20+
print("Single WithError(False) Return %r" % errorFalseResult1)
2121

2222
try:
23-
errorTrueResult = multireturn.SingleWithErrorFunc(True)
23+
errorTrueResult1 = multireturn.SingleWithErrorFunc(True)
2424
print("Failed to throw an exception")
2525
except RuntimeError as ex:
26-
print("Single WithError(True). Exception:%r" % ex)
26+
print("Single WithError(True). Exception: %r" % ex)
2727

2828
############### Double WithoutError Return ##############
29-
twoResults = multireturn.DoubleWithoutErrorFunc()
30-
print("Double WithoutError Return (%r, %r)" % twoResults)
29+
twoResults = multireturn.DoubleWithoutErrorFunc1()
30+
print("Double WithoutError(Without String) Return (%r, %r)" % twoResults)
31+
32+
twoResults = multireturn.DoubleWithoutErrorFunc2()
33+
print("Double WithoutError(With String) Return (%r, %r)" % twoResults)
3134

3235
############### Double WithError Return ##############
3336
try:
3437
value400 = multireturn.DoubleWithErrorFunc(True)
3538
print("Failed to throw an exception. Return (%r, %r)." % value400)
3639
except RuntimeError as ex:
37-
print("Double WithError(True). exception Return %r" % ex)
40+
print("Double WithError(True). Exception: %r" % ex)
3841

3942
value500 = multireturn.DoubleWithErrorFunc(False)
4043
print("Double WithError(False) Return %r" % value500)
@@ -48,20 +51,24 @@
4851

4952
############### Triple With Error Return ##############
5053
try:
51-
(value900, value1000, errorTrueResult) = multireturn.TripleWithErrorFunc(True)
54+
(value900, value1000) = multireturn.TripleWithErrorFunc(True)
55+
print("Triple WithError(True) Return (%r, %r, %r)" % (value900, value1000))
5256
except RuntimeError as ex:
53-
print("Triple WithError(True). exception Return %r" % ex)
57+
print("Triple WithError(True) Exception: %r" % ex)
5458

5559
(value1100, value1200) = multireturn.TripleWithErrorFunc(False)
5660
print("Triple WithError(False) Return (%r, %r)" % (value1100, value1200))
5761

5862
############### Triple Struct Return With Error ##############
59-
(ptr1300, struct1400, errorTrueResult) = multireturn.TripleWithStructWithErrorFunc(True)
60-
print("Triple WithError(True) Return (%r, %r, %r)" % (ptr1300.P, struct1400.P, errorFalseResult))
63+
try:
64+
(ptr1300, struct1400) = multireturn.TripleWithStructWithErrorFunc(True)
65+
print("Triple WithError(True) Return (%r, %r)" % (ptr1300.P, struct1400.P))
66+
except RuntimeError as ex:
67+
print("Triple WithError(True) Exception: %r" % ex)
6168

62-
(value1500, value1600, errorFalseResult) = multireturn.TripleWithStructWithErrorFunc(False)
63-
print("Triple WithError(False) Return (%r, %r, %r)" % (value1500.P, value1600.P, errorFalseResult))
69+
(value1500, value1600) = multireturn.TripleWithStructWithErrorFunc(False)
70+
print("Triple WithError(False) Return (%r, %r)" % (value1500.P, value1600.P))
6471

6572
############### Triple Interface Return Without Error ##############
6673
(interface1700, struct1800, ptr1900) = multireturn.TripleWithInterfaceWithoutErrorFunc()
67-
print("Triple WithError(True) Return (%r, %r, %r)" % (interface1700.P, struct1800.P, ptr1900))
74+
print("Triple WithoutError() Return (%r, %r, %r)" % (interface1700.Number(), struct1800.P, ptr1900.P))

‎bind/gen.go

+28-17
Original file line numberDiff line numberDiff line change
@@ -86,13 +86,17 @@ static inline void gopy_err_handle() {
8686
PyErr_Print();
8787
}
8888
}
89-
static PyObject* Py_BuildValue1(const char *format, void* arg0)
89+
static PyObject* Py_BuildValue1(char *format, void* arg0)
9090
{
91-
return Py_BuildValue(format, arg0);
91+
PyObject *retval = Py_BuildValue(format, arg0);
92+
free(format);
93+
return retval;
9294
}
93-
static PyObject* Py_BuildValue2(const char *format, long long arg0)
95+
static PyObject* Py_BuildValue2(char *format, long long arg0)
9496
{
95-
return Py_BuildValue(format, arg0);
97+
PyObject *retval = Py_BuildValue(format, arg0);
98+
free(format);
99+
return retval;
96100
}
97101
98102
%[9]s
@@ -241,19 +245,22 @@ class CheckedFunction(Function):
241245
failure_cleanup = self._failure_cleanup or None
242246
self.before_call.write_error_check(check, failure_cleanup)
243247
244-
def add_checked_function(mod, name, retval, params, failure_expression='', *a, **kw):
245-
fn = CheckedFunction(name, retval, params, *a, **kw)
246-
fn.set_failure_expression(failure_expression)
247-
mod._add_function_obj(fn)
248-
return fn
249-
250-
def add_checked_string_function(mod, name, retval, params, failure_expression='', *a, **kw):
251-
fn = CheckedFunction(name, retval, params, *a, **kw)
252-
fn.set_failure_cleanup('if (retval != NULL) free(retval);')
253-
fn.after_call.add_cleanup_code('free(retval);')
254-
fn.set_failure_expression(failure_expression)
255-
mod._add_function_obj(fn)
256-
return fn
248+
def add_checked_function_generator(pyTupleBuilt, retvals_to_free):
249+
if not pyTupleBuilt:
250+
if retvals_to_free:
251+
assert(len(retvals_to_free) == 1)
252+
assert(retvals_to_free[0] == 0)
253+
def rv_format(format_str, rv):
254+
return format_str.format("PyTuple_GetItem(retval, {0})".format(rv))
255+
def add_checked_function(mod, name, retval, params, failure_expression='', *a, **kw):
256+
fn = CheckedFunction(name, retval, params, *a, **kw)
257+
#TODO: Figure out how to free allocated variables. Stop leaking memory.
258+
#fn.set_failure_cleanup('\n'.join([rv_format('if ({0} != NULL) free({0});', rv) for rv in retvals_to_free]))
259+
#fn.after_call.add_cleanup_code('\n'.join([rv_format('free({0});', rv) for rv in retvals_to_free]))
260+
fn.set_failure_expression(failure_expression)
261+
mod._add_function_obj(fn)
262+
return fn
263+
return add_checked_function
257264
258265
mod = Module('_%[1]s')
259266
mod.add_include('"%[1]s_go.h"')
@@ -384,6 +391,10 @@ build:
384391
# generated %[1]s.py python wrapper imports this c-code package
385392
%[9]s
386393
$(GCC) %[1]s.c %[6]s %[1]s_go$(LIBEXT) -o _%[1]s$(LIBEXT) $(CFLAGS) $(LDFLAGS) -fPIC --shared -w
394+
395+
halfbuild:
396+
$(GOBUILD) -buildmode=c-shared -o %[1]s_go$(LIBEXT) %[1]s.go
397+
$(GCC) %[1]s.c %[6]s %[1]s_go$(LIBEXT) -o _%[1]s$(LIBEXT) $(CFLAGS) $(LDFLAGS) -fPIC --shared -w
387398
388399
`
389400

‎bind/gen_func.go

+8-2
Original file line numberDiff line numberDiff line change
@@ -132,19 +132,24 @@ func (g *pyGen) genFuncSig(sym *symbol, fsym *Func) bool {
132132
// a function that adds function calls with exception checking.
133133
// But given specific return types, we may want to add more
134134
// behavior to the wrapped function code gen.
135-
addFuncName := "add_checked_function"
135+
retvalsToFree := make([]string, 0, npyres)
136136
if npyres > 0 {
137137
for i := 0; i < npyres; i++ {
138138
switch t := res[i].GoType().(type) {
139139
case *types.Basic:
140140
// string return types need special memory leak patches
141141
// to free the allocated char*
142142
if t.Kind() == types.String {
143-
addFuncName = "add_checked_string_function"
143+
retvalsToFree = append(retvalsToFree, strconv.Itoa(i))
144144
}
145145
}
146146
}
147147
}
148+
pyTupleBuilt := "True"
149+
if !buildPyTuple(fsym) {
150+
pyTupleBuilt = "False"
151+
}
152+
addFuncName := "add_checked_function_generator(" + pyTupleBuilt + ", [" + strings.Join(retvalsToFree, ", ") + "])"
148153

149154
switch {
150155
case isMethod:
@@ -506,6 +511,7 @@ if __err != nil {
506511
if !isPointer(formatStr) {
507512
buildValueFunc = "C.Py_BuildValue2"
508513
typeCast = "C.longlong"
514+
formatStr = "L"
509515
}
510516
valueCall := fmt.Sprintf("%s(C.CString(\"%s\"), %s(%s))",
511517
buildValueFunc,

‎main_test.go

+13-12
Original file line numberDiff line numberDiff line change
@@ -840,19 +840,20 @@ func TestBindMultiReturn(t *testing.T) {
840840
extras: nil,
841841
want: []byte(`No Return None
842842
Single WithoutError Return 100
843-
Single Str WithoutError Return 150
844-
Single WithError(False) Return nil
845-
Single WithError(True). Exception: 'Error'
846-
Double WithoutError Return (200,300)
847-
Double WithError(True). Return (400, Error)
848-
Double WithError(False) Return (500, nil)
843+
Single Str WithoutError Return '150'
844+
Single WithError(False) Return None
845+
Single WithError(True). Exception: RuntimeError('Error')
846+
Double WithoutError(Without String) Return (200, 300)
847+
Double WithoutError(With String) Return ('200', '300')
848+
Double WithError(True). Exception: RuntimeError('Error')
849+
Double WithError(False) Return '500'
849850
Triple WithoutError(Without String) Return (600, 700, 800)
850-
Triple WithoutError(With String) Return (600, 700, 800)
851-
Triple WithError(True) Return (900, 1000, Error)
852-
Triple WithError(False) Return (1100, 1200, nil)
853-
Triple WithError(True) Return (1300, 1400, Error)
854-
Triple WithError(False) Return (1500, 1600, nil)
855-
Triple WithError(True) Return (1700, 1800, 1900)
851+
Triple WithoutError(With String) Return (600, '700', 800)
852+
Triple WithError(True) Exception: RuntimeError('Error')
853+
Triple WithError(False) Return (1100, 1200)
854+
Triple WithError(True) Exception: RuntimeError('Error')
855+
Triple WithError(False) Return (1500, 1600)
856+
Triple WithoutError() Return (1700, 1800, 1900)
856857
`),
857858
})
858859
}

0 commit comments

Comments
 (0)
Failed to load comments.