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 " #x " on line %d failed.\n", __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, invoking 'merge' behaviour */
137         {
138             OneofMessage msg = OneofMessage_init_zero;
139             msg.which_msgs = OneofMessage_msg2_tag;
140 
141             msg.first = 999;
142             msg.msgs.msg2.dynamic_str = "ABCD";
143             msg.last = 888;
144 
145             if (!pb_encode(&stream, OneofMessage_fields, &msg))
146             {
147                 fprintf(stderr, "Encode failed: %s\n", PB_GET_ERROR(&stream));
148                 return false;
149             }
150         }
151         msgsize = stream.bytes_written;
152     }
153 
154     {
155         OneofMessage msg = OneofMessage_init_zero;
156         pb_istream_t stream = pb_istream_from_buffer(buffer, msgsize);
157         if (!pb_decode(&stream, OneofMessage_fields, &msg))
158         {
159             fprintf(stderr, "Decode failed: %s\n", PB_GET_ERROR(&stream));
160             return false;
161         }
162 
163         TEST(msg.first == 999);
164         TEST(msg.which_msgs == OneofMessage_msg2_tag);
165         TEST(msg.msgs.msg2.dynamic_str);
166         TEST(strcmp(msg.msgs.msg2.dynamic_str, "ABCD") == 0);
167         TEST(msg.msgs.msg2.dynamic_str_arr == NULL);
168         TEST(msg.msgs.msg2.dynamic_submsg == NULL);
169         TEST(msg.last == 888);
170 
171         pb_release(OneofMessage_fields, &msg);
172         TEST(get_alloc_count() == 0);
173         pb_release(OneofMessage_fields, &msg);
174         TEST(get_alloc_count() == 0);
175     }
176 
177     return true;
178 }
179 
main()180 int main()
181 {
182     if (test_TestMessage() && test_OneofMessage())
183         return 0;
184     else
185         return 1;
186 }
187 
188