Exemplo n.º 1
0
static bool
decode_struct(DecodeBuffer* input, PyObject* output, PyObject* spec_seq) {
  int spec_seq_len = PyTuple_Size(spec_seq);
  if (spec_seq_len == -1) {
    return false;
  }

  while (true) {
    TType type;
    int16_t tag;
    PyObject* item_spec;
    PyObject* fieldval = NULL;
    StructItemSpec parsedspec;

    type = readByte(input);
    if (type == -1) {
      return false;
    }
    if (type == T_STOP) {
      break;
    }
    tag = readI16(input);
    if (INT_CONV_ERROR_OCCURRED(tag)) {
      return false;
    }
    if (tag >= 0 && tag < spec_seq_len) {
      item_spec = PyTuple_GET_ITEM(spec_seq, tag);
    } else {
      item_spec = Py_None;
    }

    if (item_spec == Py_None) {
      if (!skip(input, type)) {
        return false;
      } else {
        continue;
      }
    }

    if (!parse_struct_item_spec(&parsedspec, item_spec)) {
      return false;
    }
    if (parsedspec.type != type) {
      PyErr_SetString(PyExc_TypeError, "struct field had wrong type while reading");
      return false;
    }

    fieldval = decode_val(input, parsedspec.type, parsedspec.typeargs);
    if (fieldval == NULL) {
      return false;
    }

    if (PyObject_SetAttr(output, parsedspec.attrname, fieldval) == -1) {
      Py_DECREF(fieldval);
      return false;
    }
    Py_DECREF(fieldval);
  }
  return true;
}
Exemplo n.º 2
0
static PyObject*
decode_struct(DecodeBuffer* input, PyObject* output, PyObject* klass, PyObject* spec_seq, long string_limit, long container_limit) {
    int spec_seq_len = PyTuple_Size(spec_seq);
    bool immutable = output == Py_None;
    PyObject* kwargs = NULL;
    if (spec_seq_len == -1) {
        return NULL;
    }

    if (immutable) {
        kwargs = PyDict_New();
        if (!kwargs) {
            PyErr_SetString(PyExc_TypeError, "failed to prepare kwargument storage");
            return NULL;
        }
    }

    while (true) {
        TType type;
        int16_t tag;
        PyObject* item_spec;
        PyObject* fieldval = NULL;
        StructItemSpec parsedspec;

        type = readByte(input);
        if (type == -1) {
            goto error;
        }
        if (type == T_STOP) {
            break;
        }
        tag = readI16(input);
        if (INT_CONV_ERROR_OCCURRED(tag)) {
            goto error;
        }
        if (tag >= 0 && tag < spec_seq_len) {
            item_spec = PyTuple_GET_ITEM(spec_seq, tag);
        } else {
            item_spec = Py_None;
        }

        if (item_spec == Py_None) {
            if (!skip(input, type)) {
                goto error;
            } else {
                continue;
            }
        }

        if (!parse_struct_item_spec(&parsedspec, item_spec)) {
            goto error;
        }
        if (parsedspec.type != type) {
            if (!skip(input, type)) {
                PyErr_Format(PyExc_TypeError, "struct field had wrong type: expected %d but got %d", parsedspec.type, type);
                goto error;
            } else {
                continue;
            }
        }

        fieldval = decode_val(input, parsedspec.type, parsedspec.typeargs, string_limit, container_limit);
        if (fieldval == NULL) {
            goto error;
        }

        if ((immutable && PyDict_SetItem(kwargs, parsedspec.attrname, fieldval) == -1)
                || (!immutable && PyObject_SetAttr(output, parsedspec.attrname, fieldval) == -1)) {
            Py_DECREF(fieldval);
            goto error;
        }
        Py_DECREF(fieldval);
    }
    if (immutable) {
        PyObject* args = PyTuple_New(0);
        PyObject* ret = NULL;
        if (!args) {
            PyErr_SetString(PyExc_TypeError, "failed to prepare argument storage");
            goto error;
        }
        ret = PyObject_Call(klass, args, kwargs);
        Py_DECREF(kwargs);
        Py_DECREF(args);
        return ret;
    }
    Py_INCREF(output);
    return output;

error:
    Py_XDECREF(kwargs);
    return NULL;
}
Exemplo n.º 3
0
static bool
output_val(PyObject* output, PyObject* value, TType type, PyObject* typeargs) {
    /*
     * Refcounting Strategy:
     *
     * We assume that elements of the thrift_spec tuple are not going to be
     * mutated, so we don't ref count those at all. Other than that, we try to
     * keep a reference to all the user-created objects while we work with them.
     * output_val assumes that a reference is already held. The *caller* is
     * responsible for handling references
     */

    switch (type) {

    case T_BOOL: {
        int v = PyObject_IsTrue(value);
        if (v == -1) {
            return false;
        }

        writeByte(output, (int8_t) v);
        break;
    }
    case T_I08: {
        int32_t val;

        if (!parse_pyint(value, &val, INT8_MIN, INT8_MAX)) {
            return false;
        }

        writeByte(output, (int8_t) val);
        break;
    }
    case T_I16: {
        int32_t val;

        if (!parse_pyint(value, &val, INT16_MIN, INT16_MAX)) {
            return false;
        }

        writeI16(output, (int16_t) val);
        break;
    }
    case T_I32: {
        int32_t val;

        if (!parse_pyint(value, &val, INT32_MIN, INT32_MAX)) {
            return false;
        }

        writeI32(output, val);
        break;
    }
    case T_I64: {
        int64_t nval = PyLong_AsLongLong(value);

        if (INT_CONV_ERROR_OCCURRED(nval)) {
            return false;
        }

        if (!CHECK_RANGE(nval, INT64_MIN, INT64_MAX)) {
            PyErr_SetString(PyExc_OverflowError, "int out of range");
            return false;
        }

        writeI64(output, nval);
        break;
    }

    case T_DOUBLE: {
        double nval = PyFloat_AsDouble(value);
        if (nval == -1.0 && PyErr_Occurred()) {
            return false;
        }

        writeDouble(output, nval);
        break;
    }

    case T_STRING: {
        Py_ssize_t len = 0;
        if (is_utf8(typeargs) && PyUnicode_Check(value))
            value = PyUnicode_AsUTF8String(value);
        len = PyString_Size(value);

        if (!check_ssize_t_32(len)) {
            return false;
        }

        writeI32(output, (int32_t) len);
        PycStringIO->cwrite(output, PyString_AsString(value), (int32_t) len);
        break;
    }

    case T_LIST:
    case T_SET: {
        Py_ssize_t len;
        SetListTypeArgs parsedargs;
        PyObject *item;
        PyObject *iterator;

        if (!parse_set_list_args(&parsedargs, typeargs)) {
            return false;
        }

        len = PyObject_Length(value);

        if (!check_ssize_t_32(len)) {
            return false;
        }

        writeByte(output, parsedargs.element_type);
        writeI32(output, (int32_t) len);

        iterator =  PyObject_GetIter(value);
        if (iterator == NULL) {
            return false;
        }

        while ((item = PyIter_Next(iterator))) {
            if (!output_val(output, item, parsedargs.element_type, parsedargs.typeargs)) {
                Py_DECREF(item);
                Py_DECREF(iterator);
                return false;
            }
            Py_DECREF(item);
        }

        Py_DECREF(iterator);

        if (PyErr_Occurred()) {
            return false;
        }

        break;
    }

    case T_MAP: {
        PyObject *k, *v;
        Py_ssize_t pos = 0;
        Py_ssize_t len;

        MapTypeArgs parsedargs;

        len = PyDict_Size(value);
        if (!check_ssize_t_32(len)) {
            return false;
        }

        if (!parse_map_args(&parsedargs, typeargs)) {
            return false;
        }

        writeByte(output, parsedargs.ktag);
        writeByte(output, parsedargs.vtag);
        writeI32(output, len);

        // TODO(bmaurer): should support any mapping, not just dicts
        while (PyDict_Next(value, &pos, &k, &v)) {
            // TODO(dreiss): Think hard about whether these INCREFs actually
            //               turn any unsafe scenarios into safe scenarios.
            Py_INCREF(k);
            Py_INCREF(v);

            if (!output_val(output, k, parsedargs.ktag, parsedargs.ktypeargs)
                    || !output_val(output, v, parsedargs.vtag, parsedargs.vtypeargs)) {
                Py_DECREF(k);
                Py_DECREF(v);
                return false;
            }
            Py_DECREF(k);
            Py_DECREF(v);
        }
        break;
    }

    // TODO(dreiss): Consider breaking this out as a function
    //               the way we did for decode_struct.
    case T_STRUCT: {
        StructTypeArgs parsedargs;
        Py_ssize_t nspec;
        Py_ssize_t i;

        if (!parse_struct_args(&parsedargs, typeargs)) {
            return false;
        }

        nspec = PyTuple_Size(parsedargs.spec);

        if (nspec == -1) {
            return false;
        }

        for (i = 0; i < nspec; i++) {
            StructItemSpec parsedspec;
            PyObject* spec_tuple;
            PyObject* instval = NULL;

            spec_tuple = PyTuple_GET_ITEM(parsedargs.spec, i);
            if (spec_tuple == Py_None) {
                continue;
            }

            if (!parse_struct_item_spec (&parsedspec, spec_tuple)) {
                return false;
            }

            instval = PyObject_GetAttr(value, parsedspec.attrname);

            if (!instval) {
                return false;
            }

            if (instval == Py_None) {
                Py_DECREF(instval);
                continue;
            }

            writeByte(output, (int8_t) parsedspec.type);
            writeI16(output, parsedspec.tag);

            if (!output_val(output, instval, parsedspec.type, parsedspec.typeargs)) {
                Py_DECREF(instval);
                return false;
            }

            Py_DECREF(instval);
        }

        writeByte(output, (int8_t)T_STOP);
        break;
    }

    case T_STOP:
    case T_VOID:
    case T_UTF16:
    case T_UTF8:
    case T_U64:
    default:
        PyErr_SetString(PyExc_TypeError, "Unexpected TType");
        return false;

    }

    return true;
}