aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/ruby/ext
diff options
context:
space:
mode:
authorGravatar Alexander Polcyn <apolcyn@google.com>2017-07-14 16:36:51 -0700
committerGravatar Alexander Polcyn <apolcyn@google.com>2017-07-21 15:47:37 -0700
commit85cc143a7f90c33453c3c822a1da514664f7baea (patch)
tree24d89f3b18bd53e7d613b4bdee3d123dae44bf61 /src/ruby/ext
parenta5b7a8e8c20e867c8ae66497dc785ff25be4d6a4 (diff)
fix memory leak with large metadata keys or values
Diffstat (limited to 'src/ruby/ext')
-rw-r--r--src/ruby/ext/grpc/rb_call.c33
-rw-r--r--src/ruby/ext/grpc/rb_call.h3
-rw-r--r--src/ruby/ext/grpc/rb_call_credentials.c2
3 files changed, 27 insertions, 11 deletions
diff --git a/src/ruby/ext/grpc/rb_call.c b/src/ruby/ext/grpc/rb_call.c
index 67425a68e6..b99954883f 100644
--- a/src/ruby/ext/grpc/rb_call.c
+++ b/src/ruby/ext/grpc/rb_call.c
@@ -24,6 +24,8 @@
#include <grpc/grpc.h>
#include <grpc/impl/codegen/compression_types.h>
#include <grpc/support/alloc.h>
+#include <grpc/support/alloc.h>
+#include <grpc/support/log.h>
#include "rb_byte_buffer.h"
#include "rb_call_credentials.h"
@@ -368,7 +370,7 @@ static VALUE grpc_rb_call_set_credentials(VALUE self, VALUE credentials) {
to fill grpc_metadata_array.
it's capacity should have been computed via a prior call to
- grpc_rb_md_ary_fill_hash_cb
+ grpc_rb_md_ary_capacity_hash_cb
*/
static int grpc_rb_md_ary_fill_hash_cb(VALUE key, VALUE val, VALUE md_ary_obj) {
grpc_metadata_array *md_ary = NULL;
@@ -376,7 +378,7 @@ static int grpc_rb_md_ary_fill_hash_cb(VALUE key, VALUE val, VALUE md_ary_obj) {
long i;
grpc_slice key_slice;
grpc_slice value_slice;
- char *tmp_str;
+ char *tmp_str = NULL;
if (TYPE(key) == T_SYMBOL) {
key_slice = grpc_slice_from_static_string(rb_id2name(SYM2ID(key)));
@@ -386,6 +388,7 @@ static int grpc_rb_md_ary_fill_hash_cb(VALUE key, VALUE val, VALUE md_ary_obj) {
} else {
rb_raise(rb_eTypeError,
"grpc_rb_md_ary_fill_hash_cb: bad type for key parameter");
+ return ST_STOP;
}
if (!grpc_header_key_is_legal(key_slice)) {
@@ -413,6 +416,7 @@ static int grpc_rb_md_ary_fill_hash_cb(VALUE key, VALUE val, VALUE md_ary_obj) {
tmp_str);
return ST_STOP;
}
+ GPR_ASSERT(md_ary->count < md_ary->capacity);
md_ary->metadata[md_ary->count].key = key_slice;
md_ary->metadata[md_ary->count].value = value_slice;
md_ary->count += 1;
@@ -428,6 +432,7 @@ static int grpc_rb_md_ary_fill_hash_cb(VALUE key, VALUE val, VALUE md_ary_obj) {
tmp_str);
return ST_STOP;
}
+ GPR_ASSERT(md_ary->count < md_ary->capacity);
md_ary->metadata[md_ary->count].key = key_slice;
md_ary->metadata[md_ary->count].value = value_slice;
md_ary->count += 1;
@@ -435,7 +440,6 @@ static int grpc_rb_md_ary_fill_hash_cb(VALUE key, VALUE val, VALUE md_ary_obj) {
rb_raise(rb_eArgError, "Header values must be of type string or array");
return ST_STOP;
}
-
return ST_CONTINUE;
}
@@ -458,6 +462,7 @@ static int grpc_rb_md_ary_capacity_hash_cb(VALUE key, VALUE val,
} else {
md_ary->capacity += 1;
}
+
return ST_CONTINUE;
}
@@ -480,7 +485,7 @@ void grpc_rb_md_ary_convert(VALUE md_ary_hash, grpc_metadata_array *md_ary) {
md_ary_obj =
TypedData_Wrap_Struct(grpc_rb_cMdAry, &grpc_rb_md_ary_data_type, md_ary);
rb_hash_foreach(md_ary_hash, grpc_rb_md_ary_capacity_hash_cb, md_ary_obj);
- md_ary->metadata = gpr_malloc(md_ary->capacity * sizeof(grpc_metadata));
+ md_ary->metadata = gpr_zalloc(md_ary->capacity * sizeof(grpc_metadata));
rb_hash_foreach(md_ary_hash, grpc_rb_md_ary_fill_hash_cb, md_ary_obj);
}
@@ -611,13 +616,25 @@ static void grpc_run_batch_stack_init(run_batch_stack *st,
st->write_flag = write_flag;
}
+void grpc_rb_metadata_array_destroy_including_entries(
+ grpc_metadata_array *array) {
+ size_t i;
+ if (array->metadata) {
+ for (i = 0; i < array->count; i++) {
+ grpc_slice_unref(array->metadata[i].key);
+ grpc_slice_unref(array->metadata[i].value);
+ }
+ }
+ grpc_metadata_array_destroy(array);
+}
+
/* grpc_run_batch_stack_cleanup ensures the run_batch_stack is properly
* cleaned up */
static void grpc_run_batch_stack_cleanup(run_batch_stack *st) {
size_t i = 0;
- grpc_metadata_array_destroy(&st->send_metadata);
- grpc_metadata_array_destroy(&st->send_trailing_metadata);
+ grpc_rb_metadata_array_destroy_including_entries(&st->send_metadata);
+ grpc_rb_metadata_array_destroy_including_entries(&st->send_trailing_metadata);
grpc_metadata_array_destroy(&st->recv_metadata);
grpc_metadata_array_destroy(&st->recv_trailing_metadata);
@@ -658,8 +675,6 @@ static void grpc_run_batch_stack_fill_ops(run_batch_stack *st, VALUE ops_hash) {
st->ops[st->op_num].flags = 0;
switch (NUM2INT(this_op)) {
case GRPC_OP_SEND_INITIAL_METADATA:
- /* N.B. later there is no need to explicitly delete the metadata keys
- * and values, they are references to data in ruby objects. */
grpc_rb_md_ary_convert(this_value, &st->send_metadata);
st->ops[st->op_num].data.send_initial_metadata.count =
st->send_metadata.count;
@@ -675,8 +690,6 @@ static void grpc_run_batch_stack_fill_ops(run_batch_stack *st, VALUE ops_hash) {
case GRPC_OP_SEND_CLOSE_FROM_CLIENT:
break;
case GRPC_OP_SEND_STATUS_FROM_SERVER:
- /* N.B. later there is no need to explicitly delete the metadata keys
- * and values, they are references to data in ruby objects. */
grpc_rb_op_update_status_from_server(
&st->ops[st->op_num], &st->send_trailing_metadata,
&st->send_status_details, this_value);
diff --git a/src/ruby/ext/grpc/rb_call.h b/src/ruby/ext/grpc/rb_call.h
index be791cf972..bfe8035e0f 100644
--- a/src/ruby/ext/grpc/rb_call.h
+++ b/src/ruby/ext/grpc/rb_call.h
@@ -40,6 +40,9 @@ VALUE grpc_rb_md_ary_to_h(grpc_metadata_array *md_ary);
*/
void grpc_rb_md_ary_convert(VALUE md_ary_hash, grpc_metadata_array *md_ary);
+void grpc_rb_metadata_array_destroy_including_entries(
+ grpc_metadata_array *md_ary);
+
/* grpc_rb_eCallError is the ruby class of the exception thrown during call
operations. */
extern VALUE grpc_rb_eCallError;
diff --git a/src/ruby/ext/grpc/rb_call_credentials.c b/src/ruby/ext/grpc/rb_call_credentials.c
index 17083dd414..049a869bdc 100644
--- a/src/ruby/ext/grpc/rb_call_credentials.c
+++ b/src/ruby/ext/grpc/rb_call_credentials.c
@@ -108,7 +108,7 @@ static void grpc_rb_call_credentials_callback_with_gil(void *param) {
error_details = StringValueCStr(details);
params->callback(params->user_data, md_ary.metadata, md_ary.count, status,
error_details);
- grpc_metadata_array_destroy(&md_ary);
+ grpc_rb_metadata_array_destroy_including_entries(&md_ary);
gpr_free(params);
}