+static void
+set_custom_attr_fmt_error (MonoError *error)
+{
+ error_init (error);
+ mono_error_set_generic_error (error, "System.Reflection", "CustomAttributeFormatException", "Binary format of the specified custom attribute was invalid.");
+}
+
+/**
+ * bcheck_blob:
+ * \param ptr a pointer into a blob
+ * \param bump how far we plan on reading past \p ptr.
+ * \param endp upper bound for \p ptr - one past the last valid value for \p ptr.
+ * \param error set on error
+ *
+ * Check that ptr+bump is below endp. Returns TRUE on success, or FALSE on
+ * failure and sets \p error.
+ */
+static gboolean
+bcheck_blob (const char *ptr, int bump, const char *endp, MonoError *error)
+{
+ error_init (error);
+ if (ADDP_IS_GREATER_OR_OVF (ptr, bump, endp - 1)) {
+ set_custom_attr_fmt_error (error);
+ return FALSE;
+ } else
+ return TRUE;
+}
+
+/**
+ * decode_blob_size_checked:
+ * \param ptr a pointer into a blob
+ * \param endp upper bound for \p ptr - one pas the last valid value for \p ptr
+ * \param size_out on success set to the decoded size
+ * \param retp on success set to the next byte after the encoded size
+ * \param error set on error
+ *
+ * Decode an encoded size value which takes 1, 2, or 4 bytes and set \p
+ * size_out to the decoded size and \p retp to the next byte after the encoded
+ * size. Returns TRUE on success, or FALASE on failure and sets \p error.
+ */
+static gboolean
+decode_blob_size_checked (const char *ptr, const char *endp, guint32 *size_out, const char **retp, MonoError *error)
+{
+ error_init (error);
+ if (endp && !bcheck_blob (ptr, 0, endp, error))
+ goto leave;
+ if ((*ptr & 0x80) != 0) {
+ if ((*ptr & 0x40) == 0 && !bcheck_blob (ptr, 1, endp, error))
+ goto leave;
+ else if (!bcheck_blob (ptr, 3, endp, error))
+ goto leave;
+ }
+ *size_out = mono_metadata_decode_blob_size (ptr, retp);
+leave:
+ return is_ok (error);
+}
+
+/**
+ * decode_blob_value_checked:
+ * \param ptr a pointer into a blob
+ * \param endp upper bound for \p ptr - one pas the last valid value for \p ptr
+ * \param value_out on success set to the decoded value
+ * \param retp on success set to the next byte after the encoded size
+ * \param error set on error
+ *
+ * Decode an encoded uint32 value which takes 1, 2, or 4 bytes and set \p
+ * value_out to the decoded value and \p retp to the next byte after the
+ * encoded value. Returns TRUE on success, or FALASE on failure and sets \p
+ * error.
+ */
+static gboolean
+decode_blob_value_checked (const char *ptr, const char *endp, guint32 *value_out, const char **retp, MonoError *error)
+{
+ /* This similar to decode_blob_size_checked, above but delegates to
+ * mono_metadata_decode_value which is semantically different. */
+ error_init (error);
+ if (!bcheck_blob (ptr, 0, endp, error))
+ goto leave;
+ if ((*ptr & 0x80) != 0) {
+ if ((*ptr & 0x40) == 0 && !bcheck_blob (ptr, 1, endp, error))
+ goto leave;
+ else if (!bcheck_blob (ptr, 3, endp, error))
+ goto leave;
+ }
+ *value_out = mono_metadata_decode_value (ptr, retp);
+leave:
+ return is_ok (error);
+}