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: