a499c9cc5cfd78b13dd20b9e558f31466a3a7ab9
[com/asn1c.git] / tests / tests-c-compiler / check-src / check-70.c
1 /*
2  * Mode of operation:
3  * Each of the *.in files is XER-decoded, then converted into DER,
4  * then decoded from DER and encoded into XER again. The resulting
5  * stream is compared with the corresponding .out file.
6  */
7 #undef  NDEBUG
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <sys/types.h>
11 #include <unistd.h>     /* for chdir(2), getcwd(3) */
12 #include <string.h>
13 #include <dirent.h>
14 #include <ctype.h>      /* for isspace(3) */
15 #include <assert.h>
16 #include <errno.h>
17
18 #include <PDU.h>
19
20 #ifndef SRCDIR
21 #define SRCDIR_S ".."
22 #else
23 #define STRINGIFY_MACRO2(x) #x
24 #define STRINGIFY_MACRO(x)  STRINGIFY_MACRO2(x)
25 #define SRCDIR_S    STRINGIFY_MACRO(SRCDIR)
26 #endif
27
28 #ifdef ENABLE_LIBFUZZER
29
30 int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
31 int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
32     PDU_t *st = 0;
33     asn_dec_rval_t rval;
34     rval = asn_decode(0, ATS_BASIC_XER, &asn_DEF_PDU, (void **)&st, Data, Size);
35     assert(rval.consumed <= Size);
36     ASN_STRUCT_FREE(asn_DEF_PDU, st);
37     return 0;
38 }
39
40 #else
41
42 enum expectation {
43         EXP_OK,         /* Encoding/decoding must succeed */
44         EXP_BROKEN,     /* Decoding must fail */
45         EXP_DIFFERENT,  /* Reconstruction will yield different encoding */
46 };
47
48 static unsigned char buf[4096];
49 static int buf_offset;
50
51 static int
52 _buf_writer(const void *buffer, size_t size, void *app_key) {
53         unsigned char *b, *bend;
54         (void)app_key;
55         assert(buf_offset + size < sizeof(buf));
56         memcpy(buf + buf_offset, buffer, size);
57         b = buf + buf_offset;
58         bend = b + size;
59         fprintf(stderr, "=> [");
60         for(; b < bend; b++)
61                 fprintf(stderr, "%c", *b);
62         fprintf(stderr, "]:%zd\n", size);
63         buf_offset += size;
64         return 0;
65 }
66
67 static void
68 save_object_as(PDU_t *st, enum asn_transfer_syntax syntax) {
69     asn_enc_rval_t rval; /* Return value */
70
71     buf_offset = 0;
72
73     rval = asn_encode(0, syntax, &asn_DEF_PDU, st, _buf_writer, 0);
74
75     if (rval.encoded == -1) {
76                 fprintf(stderr,
77                         "Cannot encode %s: %s\n",
78                         rval.failed_type->name, strerror(errno));
79                 assert(rval.encoded != -1);
80                 return;
81     }
82
83     fprintf(stderr, "SAVED OBJECT IN SIZE %d/%zu\n", buf_offset, rval.encoded);
84
85     assert(buf_offset == rval.encoded);
86 }
87
88 static PDU_t *
89 load_object_from(enum expectation expectation, unsigned char *fbuf, size_t size, enum asn_transfer_syntax syntax) {
90         asn_dec_rval_t rval;
91         PDU_t *st = 0;
92         size_t csize = 1;
93
94         if(getenv("INITIAL_CHUNK_SIZE"))
95                 csize = atoi(getenv("INITIAL_CHUNK_SIZE"));
96
97         /* Perform multiple iterations with multiple chunks sizes */
98         for(; csize < 20; csize += 1) {
99                 int fbuf_offset = 0;
100                 int fbuf_left = size;
101                 int fbuf_chunk = csize;
102
103                 fprintf(stderr, "LOADING OBJECT OF SIZE %zd, chunks %zd\n",
104                         size, csize);
105
106                 if(st) ASN_STRUCT_FREE(asn_DEF_PDU, st);
107                 st = 0;
108
109                 do {
110                         ASN_DEBUG("Decoding bytes %d..%d (left %d)",
111                                 fbuf_offset,
112                                         fbuf_chunk < fbuf_left
113                                                 ? fbuf_chunk : fbuf_left,
114                                         fbuf_left);
115 #ifdef  ASN_EMIT_DEBUG
116                         if(st) {
117                                 fprintf(stderr, "=== currently ===\n");
118                                 asn_fprint(stderr, &asn_DEF_PDU, st);
119                                 fprintf(stderr, "=== end ===\n");
120                         }
121 #endif
122                         rval = asn_decode(0, syntax, &asn_DEF_PDU, (void **)&st,
123                                 fbuf + fbuf_offset,
124                                         fbuf_chunk < fbuf_left 
125                                         ? fbuf_chunk : fbuf_left);
126                         fbuf_offset += rval.consumed;
127                         fbuf_left -= rval.consumed;
128                         if(rval.code == RC_WMORE)
129                                 fbuf_chunk += 1;        /* Give little more */
130                         else
131                                 fbuf_chunk = csize;     /* Back off */
132                 } while(fbuf_left && rval.code == RC_WMORE);
133
134                 if(expectation != EXP_BROKEN) {
135                         assert(rval.code == RC_OK);
136                         if(syntax == ATS_BER) {
137                                 assert(fbuf_offset == (ssize_t)size);
138                         } else {
139                                 assert((fbuf_offset + 1 /* "\n" */  == (ssize_t)size
140                                         && fbuf[size - 1] == '\n')
141                                 || (fbuf_offset + 2 /* "\r\n" */  == (ssize_t)size
142                                         && fbuf[size - 2] == '\r'
143                                         && fbuf[size - 1] == '\n')
144                                 );
145                         }
146                 } else {
147                         assert(rval.code != RC_OK);
148                         fprintf(stderr, "Failed, but this was expected\n");
149                         ASN_STRUCT_FREE(asn_DEF_PDU, st);
150                         st = 0; /* ignore leak for now */
151                 }
152         }
153
154         if(st) asn_fprint(stderr, &asn_DEF_PDU, st);
155         return st;
156 }
157
158 static int
159 xer_encoding_equal(void *obufp, size_t osize, void *nbufp, size_t nsize) {
160     char *obuf = obufp;
161     char *nbuf = nbufp;
162         char *oend = obuf + osize;
163         char *nend = nbuf + nsize;
164
165         if((osize && !nsize) || (!osize && nsize))
166                 return 0;       /* not equal apriori */
167
168         while(1) {
169                 while(obuf < oend && isspace(*obuf)) obuf++;
170                 while(nbuf < nend && isspace(*nbuf)) nbuf++;
171
172                 if(obuf == oend || nbuf == nend) {
173                         if(obuf == oend && nbuf == nend)
174                                 break;
175                         fprintf(stderr, "%s data in reconstructed encoding\n",
176                                 (obuf == oend) ? "More" : "Less");
177                         return 0;
178                 }
179
180                 if(*obuf != *nbuf) {
181                         printf("%c%c != %c%c\n",
182                                 obuf[0], obuf[1],
183                                 nbuf[0], nbuf[1]);
184                         return 0;
185                 }
186                 obuf++, nbuf++;
187         }
188
189         return 1;
190 }
191
192 static void
193 process_XER_data(enum expectation expectation, unsigned char *fbuf, size_t size) {
194         PDU_t *st;
195
196         st = load_object_from(expectation, fbuf, size, ATS_BASIC_XER);
197         if(!st) return;
198
199         /* Save and re-load as DER */
200         save_object_as(st, ATS_DER);
201         ASN_STRUCT_FREE(asn_DEF_PDU, st);
202         st = load_object_from(expectation, buf, buf_offset, ATS_BER);
203         assert(st);
204
205         save_object_as(st, ATS_BASIC_XER);
206         fprintf(stderr, "=== original ===\n");
207         fwrite(fbuf, 1, size, stderr);
208         fprintf(stderr, "=== re-encoded ===\n");
209         fwrite(buf, 1, buf_offset, stderr);
210         fprintf(stderr, "=== end ===\n");
211
212         switch(expectation) {
213         case EXP_DIFFERENT:
214                 assert(!xer_encoding_equal(fbuf, size, buf, buf_offset));
215                 break;
216         case EXP_BROKEN:
217                 assert(!xer_encoding_equal(fbuf, size, buf, buf_offset));
218                 break;
219         case EXP_OK:
220                 assert(xer_encoding_equal(fbuf, size, buf, buf_offset));
221                 break;
222         }
223
224         ASN_STRUCT_FREE(asn_DEF_PDU, st);
225 }
226
227 /*
228  * Decode the .der files and try to regenerate them.
229  */
230 static int
231 process(const char *fname) {
232         char prevdir[256];
233         unsigned char fbuf[4096];
234         char *ext = strrchr(fname, '.');
235         enum expectation expectation;
236         char *cwd;
237         int ret;
238         int rd;
239         FILE *fp;
240
241         if(ext == 0 || strcmp(ext, ".in"))
242                 return 0;
243
244         switch(ext[-1]) {
245         case 'B':       /* The file is intentionally broken */
246                 expectation = EXP_BROKEN; break;
247         case 'X':
248         case 'D':       /* Reconstructing should yield different data */
249                 expectation = EXP_DIFFERENT; break;
250         case 'E':
251         default:
252                 expectation = EXP_OK; break;
253         }
254
255         fprintf(stderr, "\nProcessing file [../%s]\n", fname);
256
257         cwd = getcwd(prevdir, sizeof(prevdir));
258         assert(cwd != NULL);
259         ret = chdir(SRCDIR_S "/data-70");
260         assert(ret == 0);
261         fp = fopen(fname, "r");
262         ret = chdir(prevdir);
263         assert(ret == 0);
264         assert(fp);
265
266         rd = fread(fbuf, 1, sizeof(fbuf), fp);
267         fclose(fp);
268
269         assert(rd > 0 && (size_t)rd < sizeof(fbuf));    /* expect small files */
270
271         process_XER_data(expectation, fbuf, rd);
272
273         return 1;
274 }
275
276 int
277 main() {
278         DIR *dir;
279         struct dirent *dent;
280         int processed_files = 0;
281         char *str;
282
283         /* Process a specific test file */
284         str = getenv("DATA_70_FILE");
285         if(str && strncmp(str, "data-70-", 8) == 0)
286                 process(str);
287
288         dir = opendir(SRCDIR_S "/data-70");
289         assert(dir);
290
291         /*
292          * Process each file in that directory.
293          */
294         while((dent = readdir(dir))) {
295                 if(strncmp(dent->d_name, "data-70-", 8) == 0)
296                         if(process(dent->d_name))
297                                 processed_files++;
298         }
299
300         assert(processed_files);
301         closedir(dir);
302
303         return 0;
304 }
305
306 #endif