Skip to content

Commit

Permalink
Add more testing in node port in order to catch the callback bug.
Browse files Browse the repository at this point in the history
  • Loading branch information
viferga committed Mar 25, 2020
1 parent 09f3a4b commit 63300b6
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 14 deletions.
25 changes: 17 additions & 8 deletions source/loaders/py_loader/source/py_loader_impl.c
Original file line number Diff line number Diff line change
Expand Up @@ -801,21 +801,30 @@ PyObject * py_loader_impl_function_type_invoke(PyObject * self, PyObject * args)

loader_impl_py_function_type_invoke_state invoke_state = (loader_impl_py_function_type_invoke_state)PyModule_GetState(self);

signature s = function_signature(invoke_state->callback);
signature s;

const size_t args_size = signature_count(s);
size_t args_size, args_count, min_args_size;

size_t args_count;
Py_ssize_t callee_args_size;

/* type ret_type = signature_get_return(s); */
void ** value_args;

Py_ssize_t callee_args_size = PyTuple_Size(args);
value ret;

const size_t min_args_size = args_size < (size_t)callee_args_size ? args_size : (size_t)callee_args_size;
if (invoke_state == NULL)
{
log_write("metacall", LOG_LEVEL_ERROR, "Fatal error when invoking a function, state cannot be recovered, avoiding the function call");

void ** value_args;
return Py_None;
}

value ret;
s = function_signature(invoke_state->callback);

args_size = signature_count(s);

callee_args_size = PyTuple_Size(args);

min_args_size = args_size < (size_t)callee_args_size ? args_size : (size_t)callee_args_size;

if (args_size != (size_t)callee_args_size)
{
Expand Down
7 changes: 7 additions & 0 deletions source/ports/node_port/test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,13 @@ describe('metacall', () => {
// Receiving undefined from a function that returns nothing in Python
assert.strictEqual(f.function_pass(), undefined);

// Double recursion
/*
const sum = (value, f) => value <= 0 ? 0 : value + f(value - 1, sum);
assert.strictEqual(sum(5, f.function_sum), 15);
assert.strictEqual(f.function_sum(5, sum), 15);
*/

// Factorial composition (@trgwii)
/*
const fact = f.function_factorial(c => v => v);
Expand Down
16 changes: 10 additions & 6 deletions source/scripts/python/function/source/function.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,20 @@ def function_ret_lambda(y):
return lambda x: function_print_and_return(x) * y

def function_currying(y):
return lambda x: lambda z: x * z * y
return lambda x: lambda z: x * z * y;

def function_currying_more(y):
return lambda x: lambda z: lambda w: lambda n: x * z * w * n * y
return lambda x: lambda z: lambda w: lambda n: x * z * w * n * y;

def function_pass():
pass;

def function_sum(value, f):
return 0 if value <= 0 else value + f(value - 1, function_sum);

def function_chain(x):
return lambda n: x(x)(n)
return lambda n: x(x)(n);

def function_factorial(x):
return lambda n: 1 if n == 0 else n * x(x)(n - 1)
return lambda n: 1 if n == 0 else n * x(x)(n - 1);

def function_pass():
pass
56 changes: 56 additions & 0 deletions source/tests/memcheck/valgrind-suppressions.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
#! /usr/bin/awk -f
# A script to extract the actual suppression info from the output of (for example) valgrind --leak-check=full --show-reachable=yes --error-limit=no --gen-suppressions=all ./minimal
# The desired bits are between ^{ and ^} (including the braces themselves).
# The combined output should either be appended to /usr/lib/valgrind/default.supp, or placed in a .supp of its own
# If the latter, either tell valgrind about it each time with --suppressions=<filename>, or add that line to ~/.valgrindrc

# NB This script uses the |& operator, which I believe is gawk-specific. In case of failure, check that you're using gawk rather than some other awk

# The script looks for suppressions. When it finds one it stores it temporarily in an array,
# and also feeds it line by line to the external app 'md5sum' which generates a unique checksum for it.
# The checksum is used as an index in a different array. If an item with that index already exists the suppression must be a duplicate and is discarded.

BEGIN { suppression=0; md5sum = "md5sum" }
# If the line begins with '{', it's the start of a supression; so set the var and initialise things
/^{/ {
suppression=1; i=0; next
}
# If the line begins with '}' its the end of a suppression
/^}/ {
if (suppression)
{ suppression=0;
close(md5sum, "to") # We've finished sending data to md5sum, so close that part of the pipe
ProcessInput() # Do the slightly-complicated stuff in functions
delete supparray # We don't want subsequent suppressions to append to it!
}
}
# Otherwise, it's a normal line. If we're inside a supression, store it, and pipe it to md5sum. Otherwise it's cruft, so ignore it
{ if (suppression)
{
supparray[++i] = $0
print |& md5sum
}
}

function ProcessInput()
{
# Pipe the result from md5sum, then close it
md5sum |& getline result
close(md5sum)
# gawk can't cope with enormous ints like $result would be, so stringify it first by prefixing a definite string
resultstring = "prefix"result

if (! (resultstring in chksum_array) )
{ chksum_array[resultstring] = 0; # This checksum hasn't been seen before, so add it to the array
OutputSuppression() # and output the contents of the suppression
}
}

function OutputSuppression()
{
# A suppression is surrounded by '{' and '}'. Its data was stored line by line in the array
print "{"
for (n=1; n <= i; ++n)
{ print supparray[n] }
print "}"
}

0 comments on commit 63300b6

Please sign in to comment.