Reduce type-punning in ASN1_TYPE ASN1_TYPE is a union of a bunch of pointer types. Often it takes a shorthand and accesses a->value.ptr directly. This is allowed in C, but not C++. Writing the switch/case barely takes more code, so just write it that way. Along the way, extract the code for cleaning up an ASN1_TYPE from tasn_fre.c. This is a small step towards being able to use crypto/asn1's types without depending on the templates. ASN1_TYPE_free still, for now, calls into the templates. That will be fixable once tasn_*.c are rewritten a bit further. This also removes the weird hack here ASN1_primitive_free (an internal function) with NULL ASN1_ITEM secretly meant to partially clean up the ASN1_TYPE. We can just call the function directly now. Bug: 574 Change-Id: Ie2ba41418801a366ab2f12eccc01e8dadf82c33e Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/58126 Reviewed-by: Bob Beck <bbe@google.com> Commit-Queue: David Benjamin <davidben@google.com>
diff --git a/crypto/asn1/a_type.c b/crypto/asn1/a_type.c index d59fdba..0c2fd13 100644 --- a/crypto/asn1/a_type.c +++ b/crypto/asn1/a_type.c
@@ -65,31 +65,65 @@ int ASN1_TYPE_get(const ASN1_TYPE *a) { - if (a->type == V_ASN1_BOOLEAN || a->type == V_ASN1_NULL || - a->value.ptr != NULL) { - return a->type; + switch (a->type) { + case V_ASN1_NULL: + case V_ASN1_BOOLEAN: + return a->type; + case V_ASN1_OBJECT: + return a->value.object != NULL ? a->type : 0; + default: + return a->value.asn1_string != NULL ? a->type : 0; } - return 0; } const void *asn1_type_value_as_pointer(const ASN1_TYPE *a) { - if (a->type == V_ASN1_BOOLEAN) { - return a->value.boolean ? (void *)0xff : NULL; + switch (a->type) { + case V_ASN1_NULL: + return NULL; + case V_ASN1_BOOLEAN: + return a->value.boolean ? (void *)0xff : NULL; + case V_ASN1_OBJECT: + return a->value.object; + default: + return a->value.asn1_string; } - if (a->type == V_ASN1_NULL) { - return NULL; +} + +void asn1_type_cleanup(ASN1_TYPE *a) { + switch (a->type) { + case V_ASN1_NULL: + a->value.ptr = NULL; + break; + case V_ASN1_BOOLEAN: + a->value.boolean = ASN1_BOOLEAN_NONE; + break; + case V_ASN1_OBJECT: + ASN1_OBJECT_free(a->value.object); + a->value.object = NULL; + break; + default: + ASN1_STRING_free(a->value.asn1_string); + a->value.asn1_string = NULL; + break; } - return a->value.ptr; } void ASN1_TYPE_set(ASN1_TYPE *a, int type, void *value) { - ASN1_TYPE **tmp_a = &a; - ASN1_primitive_free((ASN1_VALUE **)tmp_a, NULL); + asn1_type_cleanup(a); a->type = type; - if (type == V_ASN1_BOOLEAN) { - a->value.boolean = value ? 0xff : 0; - } else { - a->value.ptr = value; + switch (type) { + case V_ASN1_NULL: + a->value.ptr = NULL; + break; + case V_ASN1_BOOLEAN: + a->value.boolean = value ? ASN1_BOOLEAN_TRUE : ASN1_BOOLEAN_FALSE; + break; + case V_ASN1_OBJECT: + a->value.object = value; + break; + default: + a->value.asn1_string = value; + break; } }
diff --git a/crypto/asn1/internal.h b/crypto/asn1/internal.h index a60a037..64e1e6b 100644 --- a/crypto/asn1/internal.h +++ b/crypto/asn1/internal.h
@@ -210,6 +210,10 @@ // a pointer. const void *asn1_type_value_as_pointer(const ASN1_TYPE *a); +// asn1_type_cleanup releases memory associated with |a|'s value, without +// freeing |a| itself. +void asn1_type_cleanup(ASN1_TYPE *a); + // asn1_is_printable returns one if |value| is a valid Unicode codepoint for an // ASN.1 PrintableString, and zero otherwise. int asn1_is_printable(uint32_t value);
diff --git a/crypto/asn1/tasn_fre.c b/crypto/asn1/tasn_fre.c index ebfd3d6..add46f5 100644 --- a/crypto/asn1/tasn_fre.c +++ b/crypto/asn1/tasn_fre.c
@@ -161,12 +161,10 @@ } void ASN1_template_free(ASN1_VALUE **pval, const ASN1_TEMPLATE *tt) { - size_t i; if (tt->flags & ASN1_TFLG_SK_MASK) { STACK_OF(ASN1_VALUE) *sk = (STACK_OF(ASN1_VALUE) *)*pval; - for (i = 0; i < sk_ASN1_VALUE_num(sk); i++) { - ASN1_VALUE *vtmp; - vtmp = sk_ASN1_VALUE_value(sk, i); + for (size_t i = 0; i < sk_ASN1_VALUE_num(sk); i++) { + ASN1_VALUE *vtmp = sk_ASN1_VALUE_value(sk, i); ASN1_item_ex_free(&vtmp, ASN1_ITEM_ptr(tt->item)); } sk_ASN1_VALUE_free(sk); @@ -177,30 +175,11 @@ } void ASN1_primitive_free(ASN1_VALUE **pval, const ASN1_ITEM *it) { - int utype; // Historically, |it->funcs| for primitive types contained an // |ASN1_PRIMITIVE_FUNCS| table of calbacks. - assert(it == NULL || it->funcs == NULL); - // Special case: if 'it' is NULL free contents of ASN1_TYPE - if (!it) { - ASN1_TYPE *typ = (ASN1_TYPE *)*pval; - utype = typ->type; - pval = &typ->value.asn1_value; - if (utype != V_ASN1_BOOLEAN && !*pval) { - return; - } - } else if (it->itype == ASN1_ITYPE_MSTRING) { - utype = -1; - if (!*pval) { - return; - } - } else { - utype = it->utype; - if ((utype != V_ASN1_BOOLEAN) && !*pval) { - return; - } - } + assert(it->funcs == NULL); + int utype = it->itype == ASN1_ITYPE_MSTRING ? -1 : it->utype; switch (utype) { case V_ASN1_OBJECT: ASN1_OBJECT_free((ASN1_OBJECT *)*pval); @@ -210,7 +189,7 @@ if (it) { *(ASN1_BOOLEAN *)pval = (ASN1_BOOLEAN)it->size; } else { - *(ASN1_BOOLEAN *)pval = -1; + *(ASN1_BOOLEAN *)pval = ASN1_BOOLEAN_NONE; } return; @@ -218,8 +197,10 @@ break; case V_ASN1_ANY: - ASN1_primitive_free(pval, NULL); - OPENSSL_free(*pval); + if (*pval != NULL) { + asn1_type_cleanup((ASN1_TYPE *)*pval); + OPENSSL_free(*pval); + } break; default: