0
strlcpy (char *dst, const char *src, size_t dst_sz)
0
strlcpy(&name_buf[1], spec->name, sizeof(name_buf) - 1);
0
- // TODO(kevinclark): Replace with the strlcpy method used in read
0
VALUE value = rb_ivar_get(obj, rb_intern(name_buf));
0
#define read_struct_begin(buf)
0
#define read_struct_end(buf)
0
-static void consume(decode_buffer* buf, int32_t size) {
0
+// This prototype is required to be able to run a call through rb_protect
0
+// which rescues from ruby exceptions
0
+static VALUE protectable_consume(VALUE args) {
0
+ VALUE trans = rb_ary_entry(args, 0);
0
+ VALUE size = rb_ary_entry(args, 1);
0
+ return rb_funcall(trans, consume_bang_id, 1, size);
0
+// Clears size bytes from the transport's string buffer
0
+static bool consume(decode_buffer* buf, int32_t size) {
0
- rb_funcall(buf->trans, consume_bang_id, 1, INT2FIX(size));
0
+ VALUE args = rb_ary_new3(2, buf->trans, INT2FIX(size));
0
+ ret = rb_protect(protectable_consume, args, &status);
0
+ // Nothing to consume, we're all good
0
-static VALUE borrow(decode_buffer* buf, int32_t size) {
0
+// This prototype is required to be able to run a call through rb_protect
0
+// which rescues from ruby exceptions
0
+static VALUE protectable_borrow(VALUE args) {
0
+ VALUE trans = rb_ary_entry(args, 0);
0
+ switch(RARRAY(args)->len) {
0
+ return rb_funcall(trans, borrow_id, 0);
0
+ VALUE size = rb_ary_entry(args, 1);
0
+ return rb_funcall(trans, borrow_id, 1, size);
0
+// Calls into the transport to get the available string buffer
0
+static bool borrow(decode_buffer* buf, int32_t size, VALUE* dst) {
0
-
return rb_funcall(buf->trans, borrow_id, 0);
0
+
args = rb_ary_new3(1, buf->trans);
0
-
return rb_funcall(buf->trans, borrow_id, 1, INT2FIX(size));
0
+
args = rb_ary_new3(2, buf->trans, INT2FIX(size));
0
+ *dst = rb_protect(protectable_borrow, args, &status);
0
// Refills the buffer by calling borrow. If buf->pos is nonzero that number of bytes
0
-// is cleared through consume
0
-static void fill_buffer(decode_buffer* buf, int32_t req_len) {
0
- consume(buf, buf->pos);
0
- VALUE refill = borrow(buf, req_len);
0
+// is cleared through consume.
0
+// returns: 0 on success, non-zero on failure. On error buf is unchanged.
0
+static int fill_buffer(decode_buffer* buf, int32_t req_len) {
0
+ if (!consume(buf, buf->pos)) {
0
+ if (!borrow(buf, req_len, &refill)) {
0
buf->data = StringValuePtr(refill);
0
buf->len = RSTRING(refill)->len;
0
- fill_buffer(buf, size);
0
+ if (fill_buffer(buf, size - avail) < 0) {
0
memcpy(dst + avail, buf->data, size - avail);
0
buf->pos += size - avail;
0
// Helpers for grabbing specific types from the buffer
0
// -----------------------------------------------------------------------------
0
-static int8_t read_byte(decode_buffer* buf) {
0
- read_bytes(buf, &data, sizeof(int8_t));
0
+static bool read_byte(decode_buffer* buf, int8_t* data) {
0
+ return read_bytes(buf, data, sizeof(int8_t));
0
-static int16_t read_int16(decode_buffer* buf) {
0
- read_bytes(buf, &data, sizeof(int16_t));
0
+static bool read_int16(decode_buffer* buf, int16_t* data) {
0
+ bool success = read_bytes(buf, data, sizeof(int16_t));
0
-static int32_t read_int32(decode_buffer* buf) {
0
- read_bytes(buf, &data, sizeof(int32_t));
0
+static bool read_int32(decode_buffer* buf, int32_t* data) {
0
+ bool success = read_bytes(buf, data, sizeof(int32_t));
0
-static int64_t read_int64(decode_buffer* buf) {
0
- read_bytes(buf, &data, sizeof(int64_t));
0
+static bool read_int64(decode_buffer* buf, int64_t* data) {
0
+ bool success = read_bytes(buf, data, sizeof(int64_t));
0
+ *data = ntohll(*data);
0
-static double read_double(decode_buffer* buf) {
0
- transfer.t = read_int64(buf);
0
+static bool read_double(decode_buffer* buf, double* data) {
0
+ return read_int64(buf, (int64_t*)data);
0
-static VALUE read_string(decode_buffer* buf) {
0
- int len = read_int32(buf);
0
+static bool read_string(decode_buffer* buf, VALUE* data) {
0
+ if (!read_int32(buf, &len)) {
0
if (buf->len - buf->pos >= len) {
0
-
ret_str = rb_str_new(buf->data + buf->pos, len);
0
+
*data = rb_str_new(buf->data + buf->pos, len);
0
- str = (char*) malloc(len);
0
+ if ((str = (char*) malloc(len)) == NULL) {
0
- read_bytes(buf, str, len);
0
- ret_str = rb_str_new(str, len);
0
+ if (!read_bytes(buf, str, len)) {
0
+ *data = rb_str_new(str, len);
0
-static
void read_field_begin(decode_buffer* buf, field_header* header) {
0
+static
bool read_field_begin(decode_buffer* buf, field_header* header) {
0
#ifdef __DEBUG__ // No need for this in prod since I set all the fields
0
bzero(header, sizeof(field_header));
0
- header->type = read_byte(buf);
0
+ if (!read_byte(buf, &header->type)) {
0
if (header->type == T_STOP) {
0
- header->id = read_int16(buf);
0
+ if (!read_int16(buf, &header->id)) {
0
#define read_field_end(buf)
0
-static
void read_map_begin(decode_buffer* buf, map_header* header) {
0
+static
bool read_map_begin(decode_buffer* buf, map_header* header) {
0
#ifdef __DEBUG__ // No need for this in prod since I set all the fields
0
bzero(header, sizeof(map_header));
0
- header->key_type = read_byte(buf);
0
- header->val_type = read_byte(buf);
0
- header->num_entries = read_int32(buf);
0
+ return (read_byte(buf, &header->key_type) &&
0
+ read_byte(buf, &header->val_type) &&
0
+ read_int32(buf, &header->num_entries));
0
#define read_map_end(buf)
0
-static
void read_list_begin(decode_buffer* buf, list_header* header) {
0
+static
bool read_list_begin(decode_buffer* buf, list_header* header) {
0
#ifdef __DEBUG__ // No need for this in prod since I set all the fields
0
bzero(header, sizeof(list_header));
0
- header->type = read_byte(buf);
0
- header->num_elements = read_int32(buf);
0
+ if (!read_byte(buf, &header->type) || !read_int32(buf, &header->num_elements)) {
0
#define read_list_end(buf)
0
// High level reader function with ruby type coercion
0
-static
VALUE read_type(int type, decode_buffer* buf) {
0
+static
bool read_type(int type, decode_buffer* buf, VALUE* dst) {
0
- int8_t byte = read_byte(buf);
0
+ if (!read_byte(buf, &byte)) {
0
- return INT2FIX(read_byte(buf));
0
+ if (!read_byte(buf, &byte)) {
0
- return INT2FIX(read_int16(buf));
0
+ if (!read_int16(buf, &i16)) {
0
- return INT2NUM(read_int32(buf));
0
+ if (!read_int32(buf, &i32)) {
0
- return rb_ll2inum(read_int64(buf));
0
+ if (!read_int64(buf, &i64)) {
0
+ *dst = rb_ll2inum(i64);
0
- return rb_float_new(read_double(buf));
0
+ if (!read_double(buf, &dbl)) {
0
+ *dst = rb_float_new(dbl);
0
- return read_string(buf);
0
+ if (!read_string(buf, &str)) {
0
// TODO(kevinclark): Now that read_string does a malloc,
0
// This maybe could be modified to avoid that, and the type coercion
0
// Read the bytes but don't do anything with the value
0
-static void skip_type(int type, decode_buffer* buf) {
0
+static bool skip_type(int type, decode_buffer* buf) {
0
+ return read_type(type, buf, &v);
0
// Read the right thing from the buffer given the field spec
0
// and return the ruby object
0
-static
VALUE read_field(decode_buffer* buf, field_spec* spec) {
0
+static
bool read_field(decode_buffer* buf, field_spec* spec, VALUE* dst) {
0
VALUE obj = rb_class_new_instance(0, NULL, spec->data.class);
0
- return read_struct(obj, buf);
0
+ *dst = read_struct(obj, buf);
0
for (i = 0; i < hdr.num_entries; ++i) {
0
- VALUE key = read_field(buf, spec->data.map->key);
0
- VALUE val = read_field(buf, spec->data.map->value);
0
+ if (!read_field(buf, spec->data.map->key, &key)) {
0
+ if (!read_field(buf, spec->data.map->value, &val)) {
0
rb_hash_aset(hsh, key, val);
0
read_list_begin(buf, &hdr);
0
arr = rb_ary_new2(hdr.num_elements);
0
for (i = 0; i < hdr.num_elements; ++i) {
0
- rb_ary_push(arr, read_field(buf, spec->data.element));
0
+ if (!read_field(buf, spec->data.element, &element)) {
0
+ rb_ary_push(arr, element);
0
for (i = 0; i < hdr.num_elements; ++i) {
0
- rb_hash_aset(set, read_field(buf, spec->data.element), Qtrue);
0
+ if (!read_field(buf, spec->data.element, &item)) {
0
+ rb_hash_aset(set, item, Qtrue);
0
- return read_type(spec->type, buf
);
0
+ return read_type(spec->type, buf
, dst);
0
+static void handle_read_error() {
0
+ // If it was an exception, reraise
0
+ if (!NIL_P(ruby_errinfo)) {
0
+ rb_exc_raise(ruby_errinfo);
0
+ // Something else went wrong, no idea what would call this yet
0
+ // So far, the only thing to cause failures underneath is ruby
0
+ // exceptions. Follow up on this regularly -- Kevin Clark (TODO)
0
+ rb_raise(rb_eStandardError, "[BUG] Something went wrong in the field reading, but not a ruby exception");
0
// Fill in the instance variables in an object (thrift struct)
0
// from the decode buffer
0
read_struct_begin(buf);
0
- read_field_begin(buf, &f_header);
0
+ if (!read_field_begin(buf, &f_header)) {
0
if (T_STOP == f_header.type) {
0
field = rb_hash_aref(fields, INT2FIX(f_header.id));
0
- skip_type(f_header.type, buf);
0
+ if (!skip_type(f_header.type, buf)) {
0
spec = parse_field_spec(field);
0
if (spec->type != f_header.type) {
0
- skip_type(spec->type, buf);
0
+ if (!skip_type(spec->type, buf)) {
0
+ free_field_spec(spec);
0
- value = read_field(buf, spec);
0
+ // Read busted somewhere (probably borrow/consume), bail
0
+ if (!read_field(buf, spec, &value)) {
0
+ free_field_spec(spec);
0
strlcpy(&name_buf[1], spec->name, sizeof(name_buf) - 1);
0
buf.pos = 0; // This needs to be set so an arbitrary number of bytes isn't consumed
0
buf.trans = transport; // We need to hold this so the buffer can be refilled
0
+ if (fill_buffer(&buf, 0) < 0) {
0
rb_p(rb_str_new2("Running decode binary with data:"));
0
buf.pos = 0; // This needs to be set so fill_buffer doesn't consume
0
buf.trans = trans; // We need to hold this so the buffer can be refilled
0
- version = read_int32(&buf);
0
+ if (fill_buffer(&buf, 0) < 0 || !read_int32(&buf, &version)) {
0
+ // Consume whatever was read
0
+ consume(&buf, buf.pos);
0
if ((version & VERSION_MASK) != VERSION_1) {
0
-
ID tprotocol_exception = rb_intern("TProtocolException");
0
+
VALUE tprotocol_exception = rb_const_get(rb_cObject, rb_intern("TProtocolException"));
0
VALUE exception = rb_funcall(tprotocol_exception, rb_intern("new"), 2, rb_const_get(tprotocol_exception, rb_intern("BAD_VERSION")), rb_str_new2("Missing version identifier"));
0
rb_raise(exception, "");
0
type = version & 0x000000ff;
0
- name = read_string(&buf);
0
- seqid = read_int32(&buf);
0
- consume(&buf, buf.pos);
0
+ if (!read_string(&buf, &name) || !read_int32(&buf, &seqid)) {
0
+ // Consume whatever was read
0
+ consume(&buf, buf.pos);
0
+ // Consume whatever was read
0
+ if (consume(&buf, buf.pos) < 0) {
0
return rb_ary_new3(3, name, INT2FIX(type), INT2FIX(seqid));
Comments
No one has commented yet.