1 #include "validation.h"
2 #include "malloc_wrappers.h"
3 #include <pb_common.h>
4 #include <assert.h>
5 
validate_static(pb_field_iter_t * iter)6 void validate_static(pb_field_iter_t *iter)
7 {
8     pb_size_t count = 1;
9     pb_size_t i;
10     bool truebool = true;
11     bool falsebool = false;
12 
13     if (PB_HTYPE(iter->type) == PB_HTYPE_REPEATED && iter->pSize)
14     {
15         /* Array count must be between 0 and statically allocated size */
16         count = *(pb_size_t*)iter->pSize;
17         assert(count <= iter->array_size);
18     }
19     else if (PB_HTYPE(iter->type) == PB_HTYPE_OPTIONAL && iter->pSize)
20     {
21         /* Boolean has_ field must have a valid value */
22         assert(memcmp(iter->pSize, &truebool, sizeof(bool)) == 0 ||
23                memcmp(iter->pSize, &falsebool, sizeof(bool)) == 0);
24     }
25     else if (PB_HTYPE(iter->type) == PB_HTYPE_ONEOF)
26     {
27         if (*(pb_size_t*)iter->pSize != iter->tag)
28         {
29             /* Some different field in oneof */
30             return;
31         }
32     }
33 
34     for (i = 0; i < count; i++)
35     {
36         void *pData = (char*)iter->pData + iter->data_size * i;
37 
38         if (PB_LTYPE(iter->type) == PB_LTYPE_STRING)
39         {
40             /* String length must be at most statically allocated size */
41             assert(strlen(pData) + 1 <= iter->data_size);
42         }
43         else if (PB_LTYPE(iter->type) == PB_LTYPE_BYTES)
44         {
45             /* Bytes length must be at most statically allocated size */
46             pb_bytes_array_t *bytes = pData;
47             assert(PB_BYTES_ARRAY_T_ALLOCSIZE(bytes->size) <= iter->data_size);
48         }
49         else if (PB_LTYPE(iter->type) == PB_LTYPE_BOOL)
50         {
51             /* Bool fields must have valid value */
52             assert(memcmp(pData, &truebool, sizeof(bool)) == 0 ||
53                    memcmp(pData, &falsebool, sizeof(bool)) == 0);
54         }
55         else if (PB_LTYPE_IS_SUBMSG(iter->type))
56         {
57             validate_message(pData, 0, iter->submsg_desc);
58         }
59     }
60 }
61 
validate_pointer(pb_field_iter_t * iter)62 void validate_pointer(pb_field_iter_t *iter)
63 {
64     pb_size_t count = 1;
65     pb_size_t i;
66     bool truebool = true;
67     bool falsebool = false;
68 
69     if (PB_HTYPE(iter->type) == PB_HTYPE_ONEOF)
70     {
71         if (*(pb_size_t*)iter->pSize != iter->tag)
72         {
73             /* Some different field in oneof */
74             return;
75         }
76     }
77     else if (!iter->pData)
78     {
79         /* Nothing allocated */
80         if (PB_HTYPE(iter->type) == PB_HTYPE_REPEATED && iter->pSize != &iter->array_size)
81         {
82             assert(*(pb_size_t*)iter->pSize == 0);
83         }
84         return;
85     }
86 
87     if (PB_HTYPE(iter->type) == PB_HTYPE_REPEATED)
88     {
89         /* Check that enough memory has been allocated for array */
90         size_t allocated_size = get_allocation_size(iter->pData);
91         count = *(pb_size_t*)iter->pSize;
92         assert(allocated_size >= count * iter->data_size);
93     }
94     else if (PB_LTYPE(iter->type) != PB_LTYPE_STRING && PB_LTYPE(iter->type) != PB_LTYPE_BYTES)
95     {
96         size_t allocated_size = get_allocation_size(iter->pData);
97         assert(allocated_size >= iter->data_size);
98     }
99 
100     for (i = 0; i < count; i++)
101     {
102         void *pData = (char*)iter->pData + iter->data_size * i;
103 
104         if (PB_LTYPE(iter->type) == PB_LTYPE_STRING)
105         {
106             /* Check that enough memory is allocated for string and that
107                the string is properly terminated. */
108             const char *str = pData;
109 
110             if (PB_HTYPE(iter->type) == PB_HTYPE_REPEATED)
111             {
112                 /* String arrays are stored as array of pointers */
113                 str = ((const char**)iter->pData)[i];
114             }
115 
116             assert(strlen(str) + 1 <= get_allocation_size(str));
117         }
118         else if (PB_LTYPE(iter->type) == PB_LTYPE_BYTES)
119         {
120             /* Bytes length must be at most statically allocated size */
121             const pb_bytes_array_t *bytes = pData;
122 
123             if (PB_HTYPE(iter->type) == PB_HTYPE_REPEATED)
124             {
125                 /* Bytes arrays are stored as array of pointers */
126                 bytes = ((const pb_bytes_array_t**)iter->pData)[i];
127             }
128 
129             assert(PB_BYTES_ARRAY_T_ALLOCSIZE(bytes->size) <= get_allocation_size(bytes));
130         }
131         else if (PB_LTYPE(iter->type) == PB_LTYPE_BOOL)
132         {
133             /* Bool fields must have valid value */
134             assert(memcmp(pData, &truebool, sizeof(bool)) == 0 ||
135                    memcmp(pData, &falsebool, sizeof(bool)) == 0);
136         }
137         else if (PB_LTYPE_IS_SUBMSG(iter->type))
138         {
139             validate_message(pData, 0, iter->submsg_desc);
140         }
141     }
142 }
143 
validate_message(const void * msg,size_t structsize,const pb_msgdesc_t * msgtype)144 void validate_message(const void *msg, size_t structsize, const pb_msgdesc_t *msgtype)
145 {
146     pb_field_iter_t iter;
147 
148     if (pb_field_iter_begin_const(&iter, msgtype, msg))
149     {
150         do
151         {
152             if (PB_ATYPE(iter.type) == PB_ATYPE_STATIC)
153             {
154                 validate_static(&iter);
155             }
156             else if (PB_ATYPE(iter.type) == PB_ATYPE_POINTER)
157             {
158                 validate_pointer(&iter);
159             }
160         } while (pb_field_iter_next(&iter));
161     }
162 }
163 
164