Skip to content

Commit

Permalink
Rename read to exec, add better tests, and fix memory leak
Browse files Browse the repository at this point in the history
  • Loading branch information
ColdHeat committed Dec 13, 2020
1 parent 16740d4 commit 13667bc
Show file tree
Hide file tree
Showing 13 changed files with 119 additions and 44 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ pystarlark.egg-info/
starlark.o
starlark.so
.eggs
pystarlark/*.so
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
0.0.2 / unreleased
==================

* Rename `Starlark.read` to `Starlark.exec`
* Fix memory leak from not freeing C.CString

0.0.1 / 2020-11-22
==================

Expand Down
15 changes: 10 additions & 5 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
build:
so:
go build -buildmode=c-shared -o starlark.so .

ffi:
python build_ffi.py

clean:
rm starlark.c
rm starlark.h
rm starlark.o
rm starlark.so
rm -rf starlark.c
rm -rf starlark.h
rm -rf starlark.o
rm -rf starlark.so

test:
python -m pytest
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def fibonacci(n=10):
res[i] = res[i-2] + res[i-1]
return res
"""
s.read(fibonacci)
s.exec(fibonacci)
s.eval("fibonacci(5)") # [0, 1, 1, 2, 3]
```

Expand Down
10 changes: 6 additions & 4 deletions build_ffi.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,15 @@

ffibuilder.cdef(
"""
extern long unsigned int NewThread();
extern long unsigned int NewThread();
extern void DestroyThread(long unsigned int p0);
extern void DestroyThread(long unsigned int p0);
extern char* Eval(long unsigned int p0, char* p1);
extern char* Eval(long unsigned int p0, char* p1);
extern void ExecFile(long unsigned int p0, char* p1);
extern void ExecFile(long unsigned int p0, char* p1);
extern void FreeCString(char* p0);
"""
)

Expand Down
5 changes: 5 additions & 0 deletions development.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,7 @@
cffi==1.14.3
setuptools-golang==2.3.0
wheel==0.36.1
black==20.8b1
isort==5.6.4
twine==3.1.1
pytest==6.1.2
6 changes: 4 additions & 2 deletions pystarlark/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class Starlark:
def __init__(self):
self._id = lib.NewThread()

def read(self, code):
def exec(self, code):
if isinstance(code, str):
code = code.encode()
lib.ExecFile(self._id, code)
Expand All @@ -17,7 +17,9 @@ def eval(self, statement, _raw=False):
if isinstance(statement, str):
statement = statement.encode()

response = ffi.string(lib.Eval(self._id, statement))
output = lib.Eval(self._id, statement)
response = ffi.string(output)
lib.FreeCString(output)
if _raw:
return response
value = json.loads(response)["value"]
Expand Down
64 changes: 52 additions & 12 deletions starlark.c
Original file line number Diff line number Diff line change
Expand Up @@ -575,19 +575,22 @@ static void (*_cffi_call_python_org)(struct _cffi_externpy_s *, char *);
static void *_cffi_types[] = {
/* 0 */ _CFFI_OP(_CFFI_OP_FUNCTION, 2), // char *()(unsigned long, char *)
/* 1 */ _CFFI_OP(_CFFI_OP_PRIMITIVE, 10), // unsigned long
/* 2 */ _CFFI_OP(_CFFI_OP_POINTER, 13), // char *
/* 2 */ _CFFI_OP(_CFFI_OP_POINTER, 16), // char *
/* 3 */ _CFFI_OP(_CFFI_OP_FUNCTION_END, 0),
/* 4 */ _CFFI_OP(_CFFI_OP_FUNCTION, 1), // unsigned long()(void)
/* 5 */ _CFFI_OP(_CFFI_OP_FUNCTION_END, 0),
/* 6 */ _CFFI_OP(_CFFI_OP_FUNCTION, 14), // void()(unsigned long)
/* 7 */ _CFFI_OP(_CFFI_OP_PRIMITIVE, 10),
/* 6 */ _CFFI_OP(_CFFI_OP_FUNCTION, 17), // void()(char *)
/* 7 */ _CFFI_OP(_CFFI_OP_NOOP, 2),
/* 8 */ _CFFI_OP(_CFFI_OP_FUNCTION_END, 0),
/* 9 */ _CFFI_OP(_CFFI_OP_FUNCTION, 14), // void()(unsigned long, char *)
/* 9 */ _CFFI_OP(_CFFI_OP_FUNCTION, 17), // void()(unsigned long)
/* 10 */ _CFFI_OP(_CFFI_OP_PRIMITIVE, 10),
/* 11 */ _CFFI_OP(_CFFI_OP_NOOP, 2),
/* 12 */ _CFFI_OP(_CFFI_OP_FUNCTION_END, 0),
/* 13 */ _CFFI_OP(_CFFI_OP_PRIMITIVE, 2), // char
/* 14 */ _CFFI_OP(_CFFI_OP_PRIMITIVE, 0), // void
/* 11 */ _CFFI_OP(_CFFI_OP_FUNCTION_END, 0),
/* 12 */ _CFFI_OP(_CFFI_OP_FUNCTION, 17), // void()(unsigned long, char *)
/* 13 */ _CFFI_OP(_CFFI_OP_PRIMITIVE, 10),
/* 14 */ _CFFI_OP(_CFFI_OP_NOOP, 2),
/* 15 */ _CFFI_OP(_CFFI_OP_FUNCTION_END, 0),
/* 16 */ _CFFI_OP(_CFFI_OP_PRIMITIVE, 2), // char
/* 17 */ _CFFI_OP(_CFFI_OP_PRIMITIVE, 0), // void
};

static void _cffi_d_DestroyThread(unsigned long x0)
Expand Down Expand Up @@ -712,6 +715,42 @@ _cffi_f_ExecFile(PyObject *self, PyObject *args)
# define _cffi_f_ExecFile _cffi_d_ExecFile
#endif

static void _cffi_d_FreeCString(char * x0)
{
FreeCString(x0);
}
#ifndef PYPY_VERSION
static PyObject *
_cffi_f_FreeCString(PyObject *self, PyObject *arg0)
{
char * x0;
Py_ssize_t datasize;
struct _cffi_freeme_s *large_args_free = NULL;

datasize = _cffi_prepare_pointer_call_argument(
_cffi_type(2), arg0, (char **)&x0);
if (datasize != 0) {
x0 = ((size_t)datasize) <= 640 ? (char *)alloca((size_t)datasize) : NULL;
if (_cffi_convert_array_argument(_cffi_type(2), arg0, (char **)&x0,
datasize, &large_args_free) < 0)
return NULL;
}

Py_BEGIN_ALLOW_THREADS
_cffi_restore_errno();
{ FreeCString(x0); }
_cffi_save_errno();
Py_END_ALLOW_THREADS

(void)self; /* unused */
if (large_args_free != NULL) _cffi_free_array_arguments(large_args_free);
Py_INCREF(Py_None);
return Py_None;
}
#else
# define _cffi_f_FreeCString _cffi_d_FreeCString
#endif

static unsigned long _cffi_d_NewThread(void)
{
return NewThread();
Expand Down Expand Up @@ -739,9 +778,10 @@ _cffi_f_NewThread(PyObject *self, PyObject *noarg)
#endif

static const struct _cffi_global_s _cffi_globals[] = {
{ "DestroyThread", (void *)_cffi_f_DestroyThread, _CFFI_OP(_CFFI_OP_CPYTHON_BLTN_O, 6), (void *)_cffi_d_DestroyThread },
{ "DestroyThread", (void *)_cffi_f_DestroyThread, _CFFI_OP(_CFFI_OP_CPYTHON_BLTN_O, 9), (void *)_cffi_d_DestroyThread },
{ "Eval", (void *)_cffi_f_Eval, _CFFI_OP(_CFFI_OP_CPYTHON_BLTN_V, 0), (void *)_cffi_d_Eval },
{ "ExecFile", (void *)_cffi_f_ExecFile, _CFFI_OP(_CFFI_OP_CPYTHON_BLTN_V, 9), (void *)_cffi_d_ExecFile },
{ "ExecFile", (void *)_cffi_f_ExecFile, _CFFI_OP(_CFFI_OP_CPYTHON_BLTN_V, 12), (void *)_cffi_d_ExecFile },
{ "FreeCString", (void *)_cffi_f_FreeCString, _CFFI_OP(_CFFI_OP_CPYTHON_BLTN_O, 6), (void *)_cffi_d_FreeCString },
{ "NewThread", (void *)_cffi_f_NewThread, _CFFI_OP(_CFFI_OP_CPYTHON_BLTN_N, 4), (void *)_cffi_d_NewThread },
};

Expand All @@ -752,12 +792,12 @@ static const struct _cffi_type_context_s _cffi_type_context = {
NULL, /* no struct_unions */
NULL, /* no enums */
NULL, /* no typenames */
4, /* num_globals */
5, /* num_globals */
0, /* num_struct_unions */
0, /* num_enums */
0, /* num_typenames */
NULL, /* no includes */
15, /* num_types */
18, /* num_types */
0, /* flags */
};

Expand Down
20 changes: 12 additions & 8 deletions starlark.go
Original file line number Diff line number Diff line change
@@ -1,24 +1,23 @@
package main

/*
#include <stdlib.h>
*/
import "C"
import (
"C"
"encoding/json"
"fmt"
"go.starlark.net/starlark"
"math/rand"
"time"
"unsafe"

"go.starlark.net/starlark"
)

var THREADS = map[uint64]*starlark.Thread{}
var GLOBALS = map[uint64]starlark.StringDict{}
var RAND = false

//export NewThread
func NewThread() C.ulong {
if RAND == false {
rand.Seed(time.Now().UnixNano())
RAND = true
}
threadId := rand.Uint64()
thread := &starlark.Thread{}
THREADS[threadId] = thread
Expand Down Expand Up @@ -74,6 +73,11 @@ func ExecFile(threadId C.ulong, data *C.char) {
return
}

//export FreeCString
func FreeCString(s *C.char) {
C.free(unsafe.Pointer(s))
}

func main() {
const data = `
def fibonacci(n=10):
Expand Down
7 changes: 7 additions & 0 deletions starlark.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@ typedef struct { const char *p; ptrdiff_t n; } _GoString_;
/* Start of preamble from import "C" comments. */


#line 3 "starlark.go"

#include <stdlib.h>

#line 1 "cgo-generated-wrapper"


/* End of preamble from import "C" comments. */
Expand Down Expand Up @@ -77,6 +82,8 @@ extern char* Eval(long unsigned int p0, char* p1);

extern void ExecFile(long unsigned int p0, char* p1);

extern void FreeCString(char* p0);

#ifdef __cplusplus
}
#endif
Empty file added tests/__init__.py
Empty file.
12 changes: 0 additions & 12 deletions tests/test.py

This file was deleted.

15 changes: 15 additions & 0 deletions tests/test_fibonacci.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
from pystarlark import Starlark


def test_fibonacci():
s = Starlark()
fibonacci = """
def fibonacci(n=10):
res = list(range(n))
for i in res[2:]:
res[i] = res[i-2] + res[i-1]
return res
"""
s.exec(fibonacci)
assert s.eval("fibonacci(5)") == [0, 1, 1, 2, 3]
assert s.eval("fibonacci(10)") == [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

0 comments on commit 13667bc

Please sign in to comment.