1 /* Make sure that all fields are freed in various scenarios. */
2 
3 #include <pb_decode.h>
4 #include <pb_encode.h>
5 #include <malloc_wrappers.h>
6 #include <stdio.h>
7 #include <test_helpers.h>
8 #include "mem_release.pb.h"
9 
10 #define TEST(x) if (!(x)) { \
11     fprintf(stderr, "Test %s on line %d failed.\n", #x, __LINE__); \
12     return false; \
13     }
14 
15 static char *test_str_arr[] = {"1", "2", ""};
16 static SubMessage test_msg_arr[] = {SubMessage_init_zero, SubMessage_init_zero};
17 static pb_extension_t ext1, ext2;
18 
fill_TestMessage(TestMessage * msg)19 static void fill_TestMessage(TestMessage *msg)
20 {
21     msg->static_req_submsg.dynamic_str = "12345";
22     msg->static_req_submsg.dynamic_str_arr_count = 3;
23     msg->static_req_submsg.dynamic_str_arr = test_str_arr;
24     msg->static_req_submsg.dynamic_submsg_count = 2;
25     msg->static_req_submsg.dynamic_submsg = test_msg_arr;
26     msg->static_req_submsg.dynamic_submsg[1].dynamic_str = "abc";
27     msg->static_opt_submsg.dynamic_str = "abc";
28     msg->static_rep_submsg_count = 2;
29     msg->static_rep_submsg[1].dynamic_str = "abc";
30     msg->has_static_opt_submsg = true;
31     msg->dynamic_submsg = &msg->static_req_submsg;
32 
33     msg->extensions = &ext1;
34     ext1.type = &dynamic_ext;
35     ext1.dest = &msg->static_req_submsg;
36     ext1.next = &ext2;
37     ext2.type = &static_ext;
38     ext2.dest = &msg->static_req_submsg;
39     ext2.next = NULL;
40 }
41 
42 /* Basic fields, nested submessages, extensions */
test_TestMessage()43 static bool test_TestMessage()
44 {
45     uint8_t buffer[256];
46     size_t msgsize;
47 
48     /* Construct a message with various fields filled in */
49     {
50         TestMessage msg = TestMessage_init_zero;
51         pb_ostream_t stream;
52 
53         fill_TestMessage(&msg);
54 
55         stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
56         if (!pb_encode(&stream, TestMessage_fields, &msg))
57         {
58             fprintf(stderr, "Encode failed: %s\n", PB_GET_ERROR(&stream));
59             return false;
60         }
61         msgsize = stream.bytes_written;
62     }
63 
64     /* Output encoded message for debug */
65     SET_BINARY_MODE(stdout);
66     fwrite(buffer, 1, msgsize, stdout);
67 
68     /* Decode memory using dynamic allocation */
69     {
70         TestMessage msg = TestMessage_init_zero;
71         pb_istream_t stream;
72         SubMessage ext2_dest;
73 
74         msg.extensions = &ext1;
75         ext1.type = &dynamic_ext;
76         ext1.dest = NULL;
77         ext1.next = &ext2;
78         ext2.type = &static_ext;
79         ext2.dest = &ext2_dest;
80         ext2.next = NULL;
81 
82         stream = pb_istream_from_buffer(buffer, msgsize);
83         if (!pb_decode(&stream, TestMessage_fields, &msg))
84         {
85             fprintf(stderr, "Decode failed: %s\n", PB_GET_ERROR(&stream));
86             return false;
87         }
88 
89         /* Make sure it encodes back to same data */
90         {
91             uint8_t buffer2[256];
92             pb_ostream_t ostream = pb_ostream_from_buffer(buffer2, sizeof(buffer2));
93             TEST(pb_encode(&ostream, TestMessage_fields, &msg));
94             TEST(ostream.bytes_written == msgsize);
95             TEST(memcmp(buffer, buffer2, msgsize) == 0);
96         }
97 
98         /* Make sure that malloc counters work */
99         TEST(get_alloc_count() > 0);
100 
101         /* Make sure that pb_release releases everything */
102         pb_release(TestMessage_fields, &msg);
103         TEST(get_alloc_count() == 0);
104 
105         /* Check that double-free is a no-op */
106         pb_release(TestMessage_fields, &msg);
107         TEST(get_alloc_count() == 0);
108     }
109 
110     return true;
111 }
112 
113 /* Oneofs */
test_OneofMessage()114 static bool test_OneofMessage()
115 {
116     uint8_t buffer[256];
117     size_t msgsize;
118 
119     {
120         pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
121 
122         /* Encode first with TestMessage */
123         {
124             OneofMessage msg = OneofMessage_init_zero;
125             msg.which_msgs = OneofMessage_msg1_tag;
126 
127             fill_TestMessage(&msg.msgs.msg1);
128 
129             if (!pb_encode(&stream, OneofMessage_fields, &msg))
130             {
131                 fprintf(stderr, "Encode failed: %s\n", PB_GET_ERROR(&stream));
132                 return false;
133             }
134         }
135 
136         /* Encode second with SubMessage, replacing the oneof item */
137         {
138             OneofMessage msg = OneofMessage_init_zero;
139             char *teststr = "1";
140             msg.which_msgs = OneofMessage_msg2_tag;
141 
142             msg.first = 999;
143             msg.msgs.msg2.dynamic_str = "ABCD";
144             msg.msgs.msg2.dynamic_str_arr_count = 1;
145             msg.msgs.msg2.dynamic_str_arr = &teststr;
146             msg.last = 888;
147 
148             if (!pb_encode(&stream, OneofMessage_fields, &msg))
149             {
150                 fprintf(stderr, "Encode failed: %s\n", PB_GET_ERROR(&stream));
151                 return false;
152             }
153         }
154 
155         /* Encode second SubMessage, invoking submessage merge behavior */
156         {
157             OneofMessage msg = OneofMessage_init_zero;
158             char *teststr = "2";
159             msg.which_msgs = OneofMessage_msg2_tag;
160 
161             msg.first = 99;
162             msg.msgs.msg2.dynamic_str = "EFGH";
163             msg.msgs.msg2.dynamic_str_arr_count = 1;
164             msg.msgs.msg2.dynamic_str_arr = &teststr;
165             msg.last = 88;
166 
167             if (!pb_encode(&stream, OneofMessage_fields, &msg))
168             {
169                 fprintf(stderr, "Encode failed: %s\n", PB_GET_ERROR(&stream));
170                 return false;
171             }
172         }
173         msgsize = stream.bytes_written;
174     }
175 
176     {
177         OneofMessage msg = OneofMessage_init_zero;
178         pb_istream_t stream = pb_istream_from_buffer(buffer, msgsize);
179         if (!pb_decode(&stream, OneofMessage_fields, &msg))
180         {
181             fprintf(stderr, "Decode failed: %s\n", PB_GET_ERROR(&stream));
182             return false;
183         }
184 
185         TEST(msg.first == 99);
186         TEST(msg.which_msgs == OneofMessage_msg2_tag);
187         TEST(msg.msgs.msg2.dynamic_str);
188         TEST(strcmp(msg.msgs.msg2.dynamic_str, "EFGH") == 0);
189         TEST(msg.msgs.msg2.dynamic_str_arr != NULL);
190         TEST(msg.msgs.msg2.dynamic_str_arr_count == 2);
191         TEST(strcmp(msg.msgs.msg2.dynamic_str_arr[0], "1") == 0);
192         TEST(strcmp(msg.msgs.msg2.dynamic_str_arr[1], "2") == 0);
193         TEST(msg.msgs.msg2.dynamic_submsg == NULL);
194         TEST(msg.last == 88);
195 
196         pb_release(OneofMessage_fields, &msg);
197         TEST(get_alloc_count() == 0);
198         pb_release(OneofMessage_fields, &msg);
199         TEST(get_alloc_count() == 0);
200     }
201 
202     return true;
203 }
204 
dummy_decode_cb(pb_istream_t * stream,const pb_field_t * field,void ** arg)205 static bool dummy_decode_cb(pb_istream_t *stream, const pb_field_t *field, void **arg)
206 {
207     return false;
208 }
209 
210 /* Garbage input */
test_Garbage()211 static bool test_Garbage()
212 {
213     const uint8_t buffer[] = "I'm only happy when it rains";
214     const size_t msgsize = sizeof(buffer);
215 
216     {
217         OneofMessage msg = OneofMessage_init_zero;
218         pb_istream_t stream = pb_istream_from_buffer(buffer, msgsize);
219         TEST(!pb_decode(&stream, OneofMessage_fields, &msg));
220     }
221 
222     {
223         TestMessage msg = TestMessage_init_zero;
224         pb_istream_t stream = pb_istream_from_buffer(buffer, msgsize);
225         TEST(!pb_decode(&stream, TestMessage_fields, &msg));
226     }
227 
228     {
229         RepeatedMessage msg = RepeatedMessage_init_zero;
230         pb_istream_t stream = pb_istream_from_buffer(buffer, msgsize);
231         msg.subs.arg = NULL;
232         msg.subs.funcs.decode = dummy_decode_cb;
233         TEST(!pb_decode(&stream, RepeatedMessage_fields, &msg));
234     }
235 
236     return true;
237 }
238 
main()239 int main()
240 {
241     if (test_TestMessage() && test_OneofMessage() && test_Garbage())
242         return 0;
243     else
244         return 1;
245 }
246 
247