asn1c: segfault on reusing a structure after ASN_STRUCT_FREE_CONTENTS_ONLY().

I’m not sure if this is a bug or working as intended. I didn’t encounter this problem with v0.9.24, and am seeing it now with 0.9.27, but maybe I just got lucky before. I also switched from native-types to wide-types which may have contributed.

When trying to reuse a message structure after using and then “emptying” it, setting attributes using things like OCTET_STRING_fromBuf() can segfault. An example LDAP code fragment looks like this;

msg = calloc(1,sizeof(LDAPMessage_t))
msg->messageID = msgid;
res->protocolOp.present = LDAPMessage__protocolOp_PR_searchResEntry;
SearchResultEntry_t *searchResEntry = &res->protocolOp.choice.searchResEntry;
/* Populate the msg searchResEntry attributes here... */
...
/* Now empty the msg and reuse it for a searchResDone response. */
ASN_STRUCT_FREE_CONTENTS_ONLY(asn_DEF_LDAPMessage, msg);
msg->protocolOp.present = LDAPMessage__protocolOp_PR_searchResDone;
SearchResultDone_t *searchResDone = &res->protocolOp.choice.searchResDone;
/* And now this will segfault... */
OCTET_STRING_fromString(&searchResDone->matchedDN, basedn);

The problem is that OCTET_STRING_fromString() tries to free the existing matchedDN attribute before alloc/set the new one. However, the existing matchedDN attribute contains a garbage pointer left over from the previous searchResEntry message.

I realize this is pretty normal C behavior; freeing things doesn’t re-initialize/zero the pointers, and it’s up to the caller to do that. However, there appears to be some effort in things like OCTET_STRING_free() to leave the free’d structure in a valid initialized state, doing things like zeroing the pointer after free. Digging around other *_free() functions it looks like most others don’t do this.

I think the right thing here is to adhere to C conventions and have ASN_STRUCT_FREE_CONTENTS_ONLY() offer no guarantees that the structure is left in a valid initialized/zeroed state. In that case I think *_free() functions should never expend effort on things like zeroing pointers after free(), because that just masks that this cannot be relied on.

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Comments: 15 (6 by maintainers)

Commits related to this issue

Most upvoted comments

I was reluctant to merge https://github.com/mouse07410/asn1c/pull/12, because it introduces recursive memory resetting behavior when contents_only option is present. Consider the hierarchical structures. Freeing them would memset() each of the inner structures, then memset() the outer structure, and so on. This essentially resets each byte of the structure as many times as the number of layers in the hierarchy. This is wasteful and unnecessary.

Therefore I introduced ASN_STRUCT_RESET() macro which does clear the contents, and discouraged using ASN_STRUCT_FREE_CONTENTS_ONLY() in the application code.

https://github.com/vlm/asn1c/commit/8d99d7b5c87d5a805472a51007d5f640932d435e