Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix memory leaks #17

Merged
merged 4 commits into from Feb 11, 2018
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
103 changes: 79 additions & 24 deletions ext/version_sorter/version_sorter.c
Expand Up @@ -171,43 +171,75 @@ parse_version_number(const char *string)
return version;
}

struct sort_context {
VALUE rb_self;
VALUE rb_version_array;
compare_callback_t *cmp;
struct version_number **versions;
};

static VALUE
rb_version_sort_1(VALUE rb_self, VALUE rb_version_array, compare_callback_t cmp)
rb_version_sort_1_cb(VALUE arg)
{
struct version_number **versions;
struct sort_context *context = (struct sort_context *)arg;
long length, i;
VALUE *rb_version_ptr;

Check_Type(rb_version_array, T_ARRAY);

length = RARRAY_LEN(rb_version_array);
if (!length)
return rb_ary_new();

versions = xcalloc(length, sizeof(struct version_number *));

length = RARRAY_LEN(context->rb_version_array);
for (i = 0; i < length; ++i) {
VALUE rb_version, rb_version_string;

rb_version = rb_ary_entry(rb_version_array, i);
rb_version = rb_ary_entry(context->rb_version_array, i);
if (rb_block_given_p())
rb_version_string = rb_yield(rb_version);
else
rb_version_string = rb_version;

versions[i] = parse_version_number(StringValueCStr(rb_version_string));
versions[i]->rb_version = rb_version;
context->versions[i] = parse_version_number(StringValueCStr(rb_version_string));
context->versions[i]->rb_version = rb_version;
}

qsort(context->versions, length, sizeof(struct version_number *), context->cmp);
rb_version_ptr = RARRAY_PTR(context->rb_version_array);

for (i = 0; i < length; ++i) {
rb_version_ptr[i] = context->versions[i]->rb_version;
}

qsort(versions, length, sizeof(struct version_number *), cmp);
rb_version_ptr = RARRAY_PTR(rb_version_array);
return context->rb_version_array;
}

static VALUE
rb_version_sort_1(VALUE rb_self, VALUE rb_version_array, compare_callback_t cmp)
{
long length, i;
int exception;

Check_Type(rb_version_array, T_ARRAY);

length = RARRAY_LEN(rb_version_array);
if (!length)
return rb_ary_new();

struct sort_context context = {
rb_self,
rb_version_array,
cmp,
xcalloc(length, sizeof(struct version_number *)),
};

VALUE result = rb_protect(rb_version_sort_1_cb, (VALUE)&context, &exception);

for (i = 0; i < length; ++i) {
rb_version_ptr[i] = versions[i]->rb_version;
xfree(versions[i]);
xfree(context.versions[i]);
}
xfree(versions);
return rb_version_array;
xfree(context.versions);

if (exception) {
rb_jump_tag(exception);
}

return result;
}

static VALUE
Expand All @@ -234,16 +266,39 @@ rb_version_sort_r_bang(VALUE rb_self, VALUE rb_versions)
return rb_version_sort_1(rb_self, rb_versions, version_compare_cb_r);
}

struct compare_context {
VALUE rb_version_a, rb_version_b;
struct version_number *version_a, *version_b;
};

static VALUE
rb_version_compare_cb(VALUE arg)
{
struct compare_context *context = (struct compare_context *)arg;

context->version_a = parse_version_number(StringValueCStr(context->rb_version_a));
context->version_b = parse_version_number(StringValueCStr(context->rb_version_b));

return INT2NUM(version_compare_cb(&context->version_a, &context->version_b));
}

static VALUE
rb_version_compare(VALUE rb_self, VALUE rb_version_a, VALUE rb_version_b)
{
struct version_number *version_a = parse_version_number(StringValueCStr(rb_version_a));
struct version_number *version_b = parse_version_number(StringValueCStr(rb_version_b));
int exception;
struct compare_context context = {
rb_version_a, rb_version_b,
NULL, NULL,
};

VALUE result = INT2NUM(version_compare_cb(&version_a, &version_b));
VALUE result = rb_protect(rb_version_compare_cb, (VALUE)&context, &exception);

xfree(version_a);
xfree(version_b);
xfree(context.version_a);
xfree(context.version_b);

if (exception) {
rb_jump_tag(exception);
}

return result;
}
Expand Down