WIP MachO binutils port assisted by AI I may consider upstreaming this in the future.
0

Configure Feed

Select the types of activity you want to include in your feed.

libctf: fix creation-time parent/child dict confusions

The fixes applied a few years ago to resolve confusions between parent and
child dicts at lookup time also apply in various forms to creation. In
general, if you have a type in a parent dict ctf_imported into a child and
you do something to it, and the parent dict is writable (created via
ctf_create, not opened via ctf_open*) it should work just the same to make
changes to that type via a child dict as it does to make the change
to the parent dict directly -- and nothing you're prohibited from doing
to the parent dict when done directly should be allowed just because
you're doing it via a child.

Specifically, the following don't work when doing things from the child, but
should:

- adding a member of a type in the parent to a struct or union in the
parent via ctf_add_member or ctf_add_member_offset: this yields
ECTF_BADID

- adding a member of a type in the parent to a struct or union in the
parent via ctf_add_member_encoded: this dumps core (!).

- adding an enumerand to an enumerator in the parent: this yields
ECTF_BADID

- setting the properties of an array in the parent via ctf_set_array;
this yields ECTF_BADID

Relatedly, some things work when doing things via a child that should fail,
yielding a CTF dictionary with invalid content (readable, but meaningless):
in particular, you can add a child type to a struct in the parent via
any of the ctf_add_member* family and nothing complains at all, even though
you should never be able to add references to children to parents (since any
given parent can be associated with many different children).

A family of tests is added to check each of these cases independently, since
some can result in coredumps and it would be nice to test the other cases
even if some dump core. They use a common library to do all the actual
work. The set of affected API calls was determined by code inspection
(auditing all calls to ctf_dtd_lookup): it's possible that I missed a few,
but I doubt it, since other cases use ctf_lookup* functions, which already
climb to the parent where appropriate.

libctf/ChangeLog:

PR libctf/30985
* ctf-create.c (ctf_dtd_lookup): Traverse to parents if necessary.
(ctf_set_array): Likewise. Report errors on the child; require
both parent and child to be writable.
(ctf_add_enumerator): Likewise.
(ctf_add_member_offset): Likewise. Prohibit addition of child types
to structs in the parent.
(ctf_add_member_encoded): Do not dereference a NULL dtd: report
ECTF_BADID instead.
* ctf-string.c (ctf_str_add_ref_internal): Report ENOMEM on the
dict if addition of a string ref fails.
* testsuite/libctf-writable/parent-child-dtd-crash-lib.c: New library.
* testsuite/libctf-writable/parent-child-dtd-enum.*: New test.
* testsuite/libctf-writable/parent-child-dtd-enumerator.*: New test.
* testsuite/libctf-writable/parent-child-dtd-member-encoded.*: New test.
* testsuite/libctf-writable/parent-child-dtd-member-offset.*: New test.
* testsuite/libctf-writable/parent-child-dtd-set-array.*: New test.
* testsuite/libctf-writable/parent-child-dtd-struct.*: New test.
* testsuite/libctf-writable/parent-child-dtd-union.*: New test.

Nick Alcock (Oct 20, 2023, 6:09 PM +0100) cd4a8fc4 d6053747

+322 -20
+56 -19
libctf/ctf-create.c
··· 299 299 ctf_dtdef_t * 300 300 ctf_dtd_lookup (const ctf_dict_t *fp, ctf_id_t type) 301 301 { 302 + if ((fp->ctf_flags & LCTF_CHILD) && LCTF_TYPE_ISPARENT (fp, type)) 303 + fp = fp->ctf_parent; 304 + 302 305 return (ctf_dtdef_t *) 303 306 ctf_dynhash_lookup (fp->ctf_dthash, (void *) (uintptr_t) type); 304 307 } ··· 712 715 int 713 716 ctf_set_array (ctf_dict_t *fp, ctf_id_t type, const ctf_arinfo_t *arp) 714 717 { 718 + ctf_dict_t *ofp = fp; 715 719 ctf_dtdef_t *dtd = ctf_dtd_lookup (fp, type); 716 720 ctf_array_t *vlen; 717 721 722 + if ((fp->ctf_flags & LCTF_CHILD) && LCTF_TYPE_ISPARENT (fp, type)) 723 + fp = fp->ctf_parent; 724 + 725 + if (!(ofp->ctf_flags & LCTF_RDWR)) 726 + return (ctf_set_errno (ofp, ECTF_RDONLY)); 727 + 718 728 if (!(fp->ctf_flags & LCTF_RDWR)) 719 - return (ctf_set_errno (fp, ECTF_RDONLY)); 729 + return (ctf_set_errno (ofp, ECTF_RDONLY)); 720 730 721 731 if (dtd == NULL 722 732 || LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info) != CTF_K_ARRAY) 723 - return (ctf_set_errno (fp, ECTF_BADID)); 733 + return (ctf_set_errno (ofp, ECTF_BADID)); 724 734 725 735 vlen = (ctf_array_t *) dtd->dtd_vlen; 726 736 fp->ctf_flags |= LCTF_DIRTY; ··· 1040 1050 ctf_add_enumerator (ctf_dict_t *fp, ctf_id_t enid, const char *name, 1041 1051 int value) 1042 1052 { 1053 + ctf_dict_t *ofp = fp; 1043 1054 ctf_dtdef_t *dtd = ctf_dtd_lookup (fp, enid); 1044 1055 unsigned char *old_vlen; 1045 1056 ctf_enum_t *en; ··· 1050 1061 if (name == NULL) 1051 1062 return (ctf_set_errno (fp, EINVAL)); 1052 1063 1064 + if ((fp->ctf_flags & LCTF_CHILD) && LCTF_TYPE_ISPARENT (fp, enid)) 1065 + fp = fp->ctf_parent; 1066 + 1067 + if (!(ofp->ctf_flags & LCTF_RDWR)) 1068 + return (ctf_set_errno (ofp, ECTF_RDONLY)); 1069 + 1053 1070 if (!(fp->ctf_flags & LCTF_RDWR)) 1054 - return (ctf_set_errno (fp, ECTF_RDONLY)); 1071 + return (ctf_set_errno (ofp, ECTF_RDONLY)); 1055 1072 1056 1073 if (dtd == NULL) 1057 - return (ctf_set_errno (fp, ECTF_BADID)); 1074 + return (ctf_set_errno (ofp, ECTF_BADID)); 1058 1075 1059 1076 kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info); 1060 1077 root = LCTF_INFO_ISROOT (fp, dtd->dtd_data.ctt_info); 1061 1078 vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info); 1062 1079 1063 1080 if (kind != CTF_K_ENUM) 1064 - return (ctf_set_errno (fp, ECTF_NOTENUM)); 1081 + return (ctf_set_errno (ofp, ECTF_NOTENUM)); 1065 1082 1066 1083 if (vlen == CTF_MAX_VLEN) 1067 - return (ctf_set_errno (fp, ECTF_DTFULL)); 1084 + return (ctf_set_errno (ofp, ECTF_DTFULL)); 1068 1085 1069 1086 old_vlen = dtd->dtd_vlen; 1070 1087 if (ctf_grow_vlen (fp, dtd, sizeof (ctf_enum_t) * (vlen + 1)) < 0) ··· 1083 1100 1084 1101 for (i = 0; i < vlen; i++) 1085 1102 if (strcmp (ctf_strptr (fp, en[i].cte_name), name) == 0) 1086 - return (ctf_set_errno (fp, ECTF_DUPLICATE)); 1103 + return (ctf_set_errno (ofp, ECTF_DUPLICATE)); 1087 1104 1088 1105 en[i].cte_name = ctf_str_add_pending (fp, name, &en[i].cte_name); 1089 1106 en[i].cte_value = value; 1090 1107 1091 1108 if (en[i].cte_name == 0 && name != NULL && name[0] != '\0') 1092 - return -1; /* errno is set for us. */ 1109 + return (ctf_set_errno (ofp, ctf_errno (fp))); 1093 1110 1094 1111 dtd->dtd_data.ctt_info = CTF_TYPE_INFO (kind, root, vlen + 1); 1095 1112 ··· 1102 1119 ctf_add_member_offset (ctf_dict_t *fp, ctf_id_t souid, const char *name, 1103 1120 ctf_id_t type, unsigned long bit_offset) 1104 1121 { 1122 + ctf_dict_t *ofp = fp; 1105 1123 ctf_dtdef_t *dtd = ctf_dtd_lookup (fp, souid); 1106 1124 1107 1125 ssize_t msize, malign, ssize; ··· 1111 1129 unsigned char *old_vlen; 1112 1130 ctf_lmember_t *memb; 1113 1131 1132 + if ((fp->ctf_flags & LCTF_CHILD) && LCTF_TYPE_ISPARENT (fp, souid)) 1133 + { 1134 + /* Adding a child type to a parent, even via the child, is prohibited. 1135 + Otherwise, climb to the parent and do all work there. */ 1136 + 1137 + if (LCTF_TYPE_ISCHILD (fp, type)) 1138 + return (ctf_set_errno (ofp, ECTF_BADID)); 1139 + 1140 + fp = fp->ctf_parent; 1141 + } 1142 + 1143 + if (!(ofp->ctf_flags & LCTF_RDWR)) 1144 + return (ctf_set_errno (ofp, ECTF_RDONLY)); 1145 + 1114 1146 if (!(fp->ctf_flags & LCTF_RDWR)) 1115 - return (ctf_set_errno (fp, ECTF_RDONLY)); 1147 + return (ctf_set_errno (ofp, ECTF_RDONLY)); 1116 1148 1117 1149 if (dtd == NULL) 1118 - return (ctf_set_errno (fp, ECTF_BADID)); 1150 + return (ctf_set_errno (ofp, ECTF_BADID)); 1119 1151 1120 1152 if (name != NULL && name[0] == '\0') 1121 1153 name = NULL; ··· 1125 1157 vlen = LCTF_INFO_VLEN (fp, dtd->dtd_data.ctt_info); 1126 1158 1127 1159 if (kind != CTF_K_STRUCT && kind != CTF_K_UNION) 1128 - return (ctf_set_errno (fp, ECTF_NOTSOU)); 1160 + return (ctf_set_errno (ofp, ECTF_NOTSOU)); 1129 1161 1130 1162 if (vlen == CTF_MAX_VLEN) 1131 - return (ctf_set_errno (fp, ECTF_DTFULL)); 1163 + return (ctf_set_errno (ofp, ECTF_DTFULL)); 1132 1164 1133 1165 old_vlen = dtd->dtd_vlen; 1134 1166 if (ctf_grow_vlen (fp, dtd, sizeof (ctf_lmember_t) * (vlen + 1)) < 0) 1135 - return -1; /* errno is set for us. */ 1167 + return (ctf_set_errno (ofp, ctf_errno (fp))); 1136 1168 memb = (ctf_lmember_t *) dtd->dtd_vlen; 1137 1169 1138 1170 if (dtd->dtd_vlen != old_vlen) ··· 1149 1181 { 1150 1182 for (i = 0; i < vlen; i++) 1151 1183 if (strcmp (ctf_strptr (fp, memb[i].ctlm_name), name) == 0) 1152 - return (ctf_set_errno (fp, ECTF_DUPLICATE)); 1184 + return (ctf_set_errno (ofp, ECTF_DUPLICATE)); 1153 1185 } 1154 1186 1155 1187 if ((msize = ctf_type_size (fp, type)) < 0 || ··· 1200 1232 1201 1233 if (is_incomplete) 1202 1234 { 1203 - ctf_err_warn (fp, 1, ECTF_INCOMPLETE, 1235 + ctf_err_warn (ofp, 1, ECTF_INCOMPLETE, 1204 1236 _("ctf_add_member_offset: cannot add member %s of " 1205 1237 "incomplete type %lx to struct %lx without " 1206 1238 "specifying explicit offset\n"), 1207 1239 name ? name : _("(unnamed member)"), type, souid); 1208 - return (ctf_set_errno (fp, ECTF_INCOMPLETE)); 1240 + return (ctf_set_errno (ofp, ECTF_INCOMPLETE)); 1209 1241 } 1210 1242 1211 1243 if (ctf_type_encoding (fp, ltype, &linfo) == 0) ··· 1216 1248 { 1217 1249 const char *lname = ctf_strraw (fp, memb[vlen - 1].ctlm_name); 1218 1250 1219 - ctf_err_warn (fp, 1, ECTF_INCOMPLETE, 1251 + ctf_err_warn (ofp, 1, ECTF_INCOMPLETE, 1220 1252 _("ctf_add_member_offset: cannot add member %s of " 1221 1253 "type %lx to struct %lx without specifying " 1222 1254 "explicit offset after member %s of type %lx, " 1223 1255 "which is an incomplete type\n"), 1224 1256 name ? name : _("(unnamed member)"), type, souid, 1225 1257 lname ? lname : _("(unnamed member)"), ltype); 1226 - return -1; /* errno is set for us. */ 1258 + return (ctf_set_errno (ofp, ECTF_INCOMPLETE)); 1227 1259 } 1228 1260 1229 1261 /* Round up the offset of the end of the last member to ··· 1274 1306 const ctf_encoding_t encoding) 1275 1307 { 1276 1308 ctf_dtdef_t *dtd = ctf_dtd_lookup (fp, type); 1277 - int kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info); 1309 + int kind; 1278 1310 int otype = type; 1311 + 1312 + if (dtd == NULL) 1313 + return (ctf_set_errno (fp, ECTF_BADID)); 1314 + 1315 + kind = LCTF_INFO_KIND (fp, dtd->dtd_data.ctt_info); 1279 1316 1280 1317 if ((kind != CTF_K_INTEGER) && (kind != CTF_K_FLOAT) && (kind != CTF_K_ENUM)) 1281 1318 return (ctf_set_errno (fp, ECTF_NOTINTFP));
+3 -1
libctf/ctf-string.c
··· 170 170 171 171 if (flags & CTF_STR_ADD_REF) 172 172 { 173 - if ((aref = malloc (sizeof (struct ctf_str_atom_ref))) == NULL) 173 + if ((aref = malloc (sizeof (struct ctf_str_atom_ref))) == NULL) { 174 + ctf_set_errno (fp, ENOMEM); 174 175 return NULL; 176 + } 175 177 aref->caf_ref = ref; 176 178 } 177 179
+179
libctf/testsuite/libctf-writable/parent-child-dtd-crash-lib.c
··· 1 + /* Make sure we do various things right that involve DTD lookups of parents 2 + from the perspective of children. */ 3 + 4 + #include <ctf-api.h> 5 + #include <stdio.h> 6 + #include <stdlib.h> 7 + #include <string.h> 8 + 9 + enum crash_method { ADD_STRUCT, ADD_UNION, ADD_MEMBER_OFFSET, ADD_MEMBER_ENCODED, ADD_ENUM, ADD_ENUMERATOR, SET_ARRAY }; 10 + 11 + void 12 + dtd_crash (enum crash_method method, int parent_bigger) 13 + { 14 + ctf_dict_t *pfp, *cfp; 15 + ctf_encoding_t e = { CTF_INT_SIGNED, 0, sizeof (long) }; 16 + ctf_id_t ptype, ftype, stype, foo; 17 + int forward_kind = CTF_K_STRUCT; 18 + size_t i; 19 + int err; 20 + 21 + /* Maybe make the relevant type IDs in the parent much bigger than those 22 + in the child, or maybe vice versa. */ 23 + 24 + if ((pfp = ctf_create (&err)) == NULL) 25 + goto create_err; 26 + 27 + if (parent_bigger) 28 + { 29 + if ((foo = ctf_add_integer (pfp, CTF_ADD_NONROOT, "blah", &e)) == CTF_ERR) 30 + goto create_parent; 31 + 32 + for (i = 0; i < 4096; i++) 33 + if (ctf_add_pointer (pfp, CTF_ADD_NONROOT, foo) == CTF_ERR) 34 + goto create_parent; 35 + } 36 + 37 + if ((ptype = ctf_add_integer (pfp, CTF_ADD_NONROOT, "int", &e)) == CTF_ERR) 38 + goto create_parent; 39 + 40 + /* Add a forward to a struct, union, or enum (depending on the method) in 41 + the parent, so we can try to replace it in the child and see what 42 + happens. (Most of them are structs, or it doesn't matter, as for 43 + SET_ARRAY; so we do that by default.) */ 44 + 45 + switch (method) 46 + { 47 + case ADD_UNION: 48 + forward_kind = CTF_K_UNION; 49 + break; 50 + case ADD_ENUM: 51 + case ADD_ENUMERATOR: 52 + forward_kind = CTF_K_ENUM; 53 + break; 54 + /* Placate clang. */ 55 + default: 56 + break; 57 + } 58 + 59 + if ((ftype = ctf_add_forward (pfp, CTF_ADD_ROOT, "foo", forward_kind)) == CTF_ERR) 60 + goto create_parent; 61 + 62 + if ((cfp = ctf_create (&err)) == NULL) 63 + goto create_err; 64 + 65 + if (ctf_import (cfp, pfp) < 0) 66 + goto create_child; 67 + 68 + if (!parent_bigger) 69 + { 70 + if ((foo = ctf_add_integer (pfp, CTF_ADD_NONROOT, "blah", &e)) == CTF_ERR) 71 + goto create_parent; 72 + 73 + for (i = 0; i < 4096; i++) 74 + if (ctf_add_pointer (pfp, CTF_ADD_NONROOT, foo) == CTF_ERR) 75 + goto create_parent; 76 + } 77 + 78 + switch (method) 79 + { 80 + /* These try to replace a forward, and should not do so if we're 81 + adding in the child and it's in the parent. */ 82 + case ADD_STRUCT: 83 + if ((stype = ctf_add_struct_sized (cfp, CTF_ADD_ROOT, "foo", 1024)) == CTF_ERR) 84 + goto create_child; 85 + if (stype == ftype) 86 + fprintf (stderr, "Forward-promotion spotted!\n"); 87 + break; 88 + 89 + case ADD_UNION: 90 + if ((stype = ctf_add_union_sized (cfp, CTF_ADD_ROOT, "foo", 1024)) == CTF_ERR) 91 + goto create_child; 92 + if (stype == ftype) 93 + fprintf (stderr, "Forward-promotion spotted!\n"); 94 + break; 95 + 96 + case ADD_ENUM: 97 + if ((stype = ctf_add_enum (cfp, CTF_ADD_ROOT, "foo")) == CTF_ERR) 98 + goto create_child; 99 + if (stype == ftype) 100 + fprintf (stderr, "Forward-promotion spotted!\n"); 101 + break; 102 + 103 + /* These try to look up the struct/union/enum we're adding to: make 104 + sure this works from the perspective of the child if the type is in 105 + the parent. Also make sure that addition of child types to parent 106 + types this way is prohibited, and that addition of parent types to 107 + parent types is allowed. */ 108 + case ADD_MEMBER_OFFSET: 109 + { 110 + ctf_id_t ctype; 111 + 112 + if ((stype = ctf_add_struct (pfp, CTF_ADD_ROOT, "bar")) == CTF_ERR) 113 + goto create_child; 114 + 115 + if ((ctype = ctf_add_integer (cfp, CTF_ADD_NONROOT, "xyzzy", &e)) == CTF_ERR) 116 + goto create_child; 117 + 118 + if (ctf_add_member_offset (cfp, stype, "member", ptype, 5) == CTF_ERR) 119 + goto create_child; 120 + 121 + if (ctf_add_member_offset (cfp, stype, "xyzzy", ctype, 4) != CTF_ERR) 122 + fprintf (stderr, "Addition of child type to parent via child unexpectedly succeeded\n"); 123 + else if (ctf_errno (cfp) == 0) 124 + fprintf (stderr, "got error from ctype addition to parent struct, but no error found on child\n"); 125 + 126 + break; 127 + } 128 + 129 + case ADD_ENUMERATOR: 130 + if ((stype = ctf_add_enum (pfp, CTF_ADD_ROOT, "bar")) == CTF_ERR) 131 + goto create_parent; 132 + 133 + if (ctf_add_enumerator (cfp, stype, "FOO", 0) == CTF_ERR) 134 + goto create_child; 135 + break; 136 + 137 + /* This tries to look up the member type we're adding, and goes wrong 138 + if the struct is in the child and the member type is in the parent. */ 139 + case ADD_MEMBER_ENCODED: 140 + if ((stype = ctf_add_struct (cfp, CTF_ADD_ROOT, "foo")) == CTF_ERR) 141 + goto create_child; 142 + 143 + if (ctf_add_member_encoded (cfp, stype, "cmember", ptype, 5, e) == CTF_ERR) 144 + goto create_child; 145 + break; 146 + 147 + /* This tries to look up the array we're resetting the state of. */ 148 + case SET_ARRAY: 149 + { 150 + ctf_arinfo_t ar; 151 + 152 + ar.ctr_contents = ptype; 153 + ar.ctr_index = ptype; 154 + ar.ctr_nelems = 5; 155 + 156 + if ((stype = ctf_add_array (pfp, CTF_ADD_ROOT, &ar)) == CTF_ERR) 157 + goto create_child; 158 + 159 + if (ctf_set_array (cfp, stype, &ar) == CTF_ERR) 160 + goto create_child; 161 + break; 162 + } 163 + } 164 + 165 + ctf_dict_close (cfp); 166 + ctf_dict_close (pfp); 167 + 168 + return; 169 + 170 + create_err: 171 + fprintf (stderr, "Creation failed: %s\n", ctf_errmsg (err)); 172 + exit (1); 173 + create_parent: 174 + fprintf (stderr, "Cannot create parent type: %s\n", ctf_errmsg (ctf_errno (pfp))); 175 + exit (1); 176 + create_child: 177 + fprintf (stderr, "Cannot create child type: %s\n", ctf_errmsg (ctf_errno (cfp))); 178 + exit (1); 179 + }
+11
libctf/testsuite/libctf-writable/parent-child-dtd-enum.c
··· 1 + #include "parent-child-dtd-crash-lib.c" 2 + 3 + int main (void) 4 + { 5 + dtd_crash(ADD_ENUM, 0); 6 + dtd_crash(ADD_ENUM, 1); 7 + 8 + printf("Creation successful.\n"); 9 + 10 + return 0; 11 + }
+1
libctf/testsuite/libctf-writable/parent-child-dtd-enum.lk
··· 1 + Creation successful.
+11
libctf/testsuite/libctf-writable/parent-child-dtd-enumerator.c
··· 1 + #include "parent-child-dtd-crash-lib.c" 2 + 3 + int main (void) 4 + { 5 + dtd_crash(ADD_ENUMERATOR, 0); 6 + dtd_crash(ADD_ENUMERATOR, 1); 7 + 8 + printf("Creation successful.\n"); 9 + 10 + return 0; 11 + }
+1
libctf/testsuite/libctf-writable/parent-child-dtd-enumerator.lk
··· 1 + Creation successful.
+11
libctf/testsuite/libctf-writable/parent-child-dtd-member-encoded.c
··· 1 + #include "parent-child-dtd-crash-lib.c" 2 + 3 + int main (void) 4 + { 5 + dtd_crash(ADD_MEMBER_ENCODED, 0); 6 + dtd_crash(ADD_MEMBER_ENCODED, 1); 7 + 8 + printf("Creation successful.\n"); 9 + 10 + return 0; 11 + }
+1
libctf/testsuite/libctf-writable/parent-child-dtd-member-encoded.lk
··· 1 + Creation successful.
+11
libctf/testsuite/libctf-writable/parent-child-dtd-member-offset.c
··· 1 + #include "parent-child-dtd-crash-lib.c" 2 + 3 + int main (void) 4 + { 5 + dtd_crash(ADD_MEMBER_OFFSET, 0); 6 + dtd_crash(ADD_MEMBER_OFFSET, 1); 7 + 8 + printf("Creation successful.\n"); 9 + 10 + return 0; 11 + }
+1
libctf/testsuite/libctf-writable/parent-child-dtd-member-offset.lk
··· 1 + Creation successful.
+11
libctf/testsuite/libctf-writable/parent-child-dtd-set-array.c
··· 1 + #include "parent-child-dtd-crash-lib.c" 2 + 3 + int main (void) 4 + { 5 + dtd_crash(SET_ARRAY, 0); 6 + dtd_crash(SET_ARRAY, 1); 7 + 8 + printf("Creation successful.\n"); 9 + 10 + return 0; 11 + }
+1
libctf/testsuite/libctf-writable/parent-child-dtd-set-array.lk
··· 1 + Creation successful.
+11
libctf/testsuite/libctf-writable/parent-child-dtd-struct.c
··· 1 + #include "parent-child-dtd-crash-lib.c" 2 + 3 + int main (void) 4 + { 5 + dtd_crash(ADD_STRUCT, 0); 6 + dtd_crash(ADD_STRUCT, 1); 7 + 8 + printf("Creation successful.\n"); 9 + 10 + return 0; 11 + }
+1
libctf/testsuite/libctf-writable/parent-child-dtd-struct.lk
··· 1 + Creation successful.
+11
libctf/testsuite/libctf-writable/parent-child-dtd-union.c
··· 1 + #include "parent-child-dtd-crash-lib.c" 2 + 3 + int main (void) 4 + { 5 + dtd_crash(ADD_UNION, 0); 6 + dtd_crash(ADD_UNION, 1); 7 + 8 + printf("Creation successful.\n"); 9 + 10 + return 0; 11 + }
+1
libctf/testsuite/libctf-writable/parent-child-dtd-union.lk
··· 1 + Creation successful.