xref: /aosp_15_r20/external/pcre/src/pcre2_serialize.c (revision 22dc650d8ae982c6770746019a6f94af92b0f024)
1*22dc650dSSadaf Ebrahimi /*************************************************
2*22dc650dSSadaf Ebrahimi *      Perl-Compatible Regular Expressions       *
3*22dc650dSSadaf Ebrahimi *************************************************/
4*22dc650dSSadaf Ebrahimi 
5*22dc650dSSadaf Ebrahimi /* PCRE is a library of functions to support regular expressions whose syntax
6*22dc650dSSadaf Ebrahimi and semantics are as close as possible to those of the Perl 5 language.
7*22dc650dSSadaf Ebrahimi 
8*22dc650dSSadaf Ebrahimi                        Written by Philip Hazel
9*22dc650dSSadaf Ebrahimi      Original API code Copyright (c) 1997-2012 University of Cambridge
10*22dc650dSSadaf Ebrahimi           New API code Copyright (c) 2016-2020 University of Cambridge
11*22dc650dSSadaf Ebrahimi 
12*22dc650dSSadaf Ebrahimi -----------------------------------------------------------------------------
13*22dc650dSSadaf Ebrahimi Redistribution and use in source and binary forms, with or without
14*22dc650dSSadaf Ebrahimi modification, are permitted provided that the following conditions are met:
15*22dc650dSSadaf Ebrahimi 
16*22dc650dSSadaf Ebrahimi     * Redistributions of source code must retain the above copyright notice,
17*22dc650dSSadaf Ebrahimi       this list of conditions and the following disclaimer.
18*22dc650dSSadaf Ebrahimi 
19*22dc650dSSadaf Ebrahimi     * Redistributions in binary form must reproduce the above copyright
20*22dc650dSSadaf Ebrahimi       notice, this list of conditions and the following disclaimer in the
21*22dc650dSSadaf Ebrahimi       documentation and/or other materials provided with the distribution.
22*22dc650dSSadaf Ebrahimi 
23*22dc650dSSadaf Ebrahimi     * Neither the name of the University of Cambridge nor the names of its
24*22dc650dSSadaf Ebrahimi       contributors may be used to endorse or promote products derived from
25*22dc650dSSadaf Ebrahimi       this software without specific prior written permission.
26*22dc650dSSadaf Ebrahimi 
27*22dc650dSSadaf Ebrahimi THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
28*22dc650dSSadaf Ebrahimi AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
29*22dc650dSSadaf Ebrahimi IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
30*22dc650dSSadaf Ebrahimi ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
31*22dc650dSSadaf Ebrahimi LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32*22dc650dSSadaf Ebrahimi CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33*22dc650dSSadaf Ebrahimi SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34*22dc650dSSadaf Ebrahimi INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35*22dc650dSSadaf Ebrahimi CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36*22dc650dSSadaf Ebrahimi ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37*22dc650dSSadaf Ebrahimi POSSIBILITY OF SUCH DAMAGE.
38*22dc650dSSadaf Ebrahimi -----------------------------------------------------------------------------
39*22dc650dSSadaf Ebrahimi */
40*22dc650dSSadaf Ebrahimi 
41*22dc650dSSadaf Ebrahimi /* This module contains functions for serializing and deserializing
42*22dc650dSSadaf Ebrahimi a sequence of compiled codes. */
43*22dc650dSSadaf Ebrahimi 
44*22dc650dSSadaf Ebrahimi 
45*22dc650dSSadaf Ebrahimi #ifdef HAVE_CONFIG_H
46*22dc650dSSadaf Ebrahimi #include "config.h"
47*22dc650dSSadaf Ebrahimi #endif
48*22dc650dSSadaf Ebrahimi 
49*22dc650dSSadaf Ebrahimi 
50*22dc650dSSadaf Ebrahimi #include "pcre2_internal.h"
51*22dc650dSSadaf Ebrahimi 
52*22dc650dSSadaf Ebrahimi /* Magic number to provide a small check against being handed junk. */
53*22dc650dSSadaf Ebrahimi 
54*22dc650dSSadaf Ebrahimi #define SERIALIZED_DATA_MAGIC 0x50523253u
55*22dc650dSSadaf Ebrahimi 
56*22dc650dSSadaf Ebrahimi /* Deserialization is limited to the current PCRE version and
57*22dc650dSSadaf Ebrahimi character width. */
58*22dc650dSSadaf Ebrahimi 
59*22dc650dSSadaf Ebrahimi #define SERIALIZED_DATA_VERSION \
60*22dc650dSSadaf Ebrahimi   ((PCRE2_MAJOR) | ((PCRE2_MINOR) << 16))
61*22dc650dSSadaf Ebrahimi 
62*22dc650dSSadaf Ebrahimi #define SERIALIZED_DATA_CONFIG \
63*22dc650dSSadaf Ebrahimi   (sizeof(PCRE2_UCHAR) | ((sizeof(void*)) << 8) | ((sizeof(PCRE2_SIZE)) << 16))
64*22dc650dSSadaf Ebrahimi 
65*22dc650dSSadaf Ebrahimi 
66*22dc650dSSadaf Ebrahimi 
67*22dc650dSSadaf Ebrahimi /*************************************************
68*22dc650dSSadaf Ebrahimi *           Serialize compiled patterns          *
69*22dc650dSSadaf Ebrahimi *************************************************/
70*22dc650dSSadaf Ebrahimi 
71*22dc650dSSadaf Ebrahimi PCRE2_EXP_DEFN int32_t PCRE2_CALL_CONVENTION
pcre2_serialize_encode(const pcre2_code ** codes,int32_t number_of_codes,uint8_t ** serialized_bytes,PCRE2_SIZE * serialized_size,pcre2_general_context * gcontext)72*22dc650dSSadaf Ebrahimi pcre2_serialize_encode(const pcre2_code **codes, int32_t number_of_codes,
73*22dc650dSSadaf Ebrahimi    uint8_t **serialized_bytes, PCRE2_SIZE *serialized_size,
74*22dc650dSSadaf Ebrahimi    pcre2_general_context *gcontext)
75*22dc650dSSadaf Ebrahimi {
76*22dc650dSSadaf Ebrahimi uint8_t *bytes;
77*22dc650dSSadaf Ebrahimi uint8_t *dst_bytes;
78*22dc650dSSadaf Ebrahimi int32_t i;
79*22dc650dSSadaf Ebrahimi PCRE2_SIZE total_size;
80*22dc650dSSadaf Ebrahimi const pcre2_real_code *re;
81*22dc650dSSadaf Ebrahimi const uint8_t *tables;
82*22dc650dSSadaf Ebrahimi pcre2_serialized_data *data;
83*22dc650dSSadaf Ebrahimi 
84*22dc650dSSadaf Ebrahimi const pcre2_memctl *memctl = (gcontext != NULL) ?
85*22dc650dSSadaf Ebrahimi   &gcontext->memctl : &PRIV(default_compile_context).memctl;
86*22dc650dSSadaf Ebrahimi 
87*22dc650dSSadaf Ebrahimi if (codes == NULL || serialized_bytes == NULL || serialized_size == NULL)
88*22dc650dSSadaf Ebrahimi   return PCRE2_ERROR_NULL;
89*22dc650dSSadaf Ebrahimi 
90*22dc650dSSadaf Ebrahimi if (number_of_codes <= 0) return PCRE2_ERROR_BADDATA;
91*22dc650dSSadaf Ebrahimi 
92*22dc650dSSadaf Ebrahimi /* Compute total size. */
93*22dc650dSSadaf Ebrahimi total_size = sizeof(pcre2_serialized_data) + TABLES_LENGTH;
94*22dc650dSSadaf Ebrahimi tables = NULL;
95*22dc650dSSadaf Ebrahimi 
96*22dc650dSSadaf Ebrahimi for (i = 0; i < number_of_codes; i++)
97*22dc650dSSadaf Ebrahimi   {
98*22dc650dSSadaf Ebrahimi   if (codes[i] == NULL) return PCRE2_ERROR_NULL;
99*22dc650dSSadaf Ebrahimi   re = (const pcre2_real_code *)(codes[i]);
100*22dc650dSSadaf Ebrahimi   if (re->magic_number != MAGIC_NUMBER) return PCRE2_ERROR_BADMAGIC;
101*22dc650dSSadaf Ebrahimi   if (tables == NULL)
102*22dc650dSSadaf Ebrahimi     tables = re->tables;
103*22dc650dSSadaf Ebrahimi   else if (tables != re->tables)
104*22dc650dSSadaf Ebrahimi     return PCRE2_ERROR_MIXEDTABLES;
105*22dc650dSSadaf Ebrahimi   total_size += re->blocksize;
106*22dc650dSSadaf Ebrahimi   }
107*22dc650dSSadaf Ebrahimi 
108*22dc650dSSadaf Ebrahimi /* Initialize the byte stream. */
109*22dc650dSSadaf Ebrahimi bytes = memctl->malloc(total_size + sizeof(pcre2_memctl), memctl->memory_data);
110*22dc650dSSadaf Ebrahimi if (bytes == NULL) return PCRE2_ERROR_NOMEMORY;
111*22dc650dSSadaf Ebrahimi 
112*22dc650dSSadaf Ebrahimi /* The controller is stored as a hidden parameter. */
113*22dc650dSSadaf Ebrahimi memcpy(bytes, memctl, sizeof(pcre2_memctl));
114*22dc650dSSadaf Ebrahimi bytes += sizeof(pcre2_memctl);
115*22dc650dSSadaf Ebrahimi 
116*22dc650dSSadaf Ebrahimi data = (pcre2_serialized_data *)bytes;
117*22dc650dSSadaf Ebrahimi data->magic = SERIALIZED_DATA_MAGIC;
118*22dc650dSSadaf Ebrahimi data->version = SERIALIZED_DATA_VERSION;
119*22dc650dSSadaf Ebrahimi data->config = SERIALIZED_DATA_CONFIG;
120*22dc650dSSadaf Ebrahimi data->number_of_codes = number_of_codes;
121*22dc650dSSadaf Ebrahimi 
122*22dc650dSSadaf Ebrahimi /* Copy all compiled code data. */
123*22dc650dSSadaf Ebrahimi dst_bytes = bytes + sizeof(pcre2_serialized_data);
124*22dc650dSSadaf Ebrahimi memcpy(dst_bytes, tables, TABLES_LENGTH);
125*22dc650dSSadaf Ebrahimi dst_bytes += TABLES_LENGTH;
126*22dc650dSSadaf Ebrahimi 
127*22dc650dSSadaf Ebrahimi for (i = 0; i < number_of_codes; i++)
128*22dc650dSSadaf Ebrahimi   {
129*22dc650dSSadaf Ebrahimi   re = (const pcre2_real_code *)(codes[i]);
130*22dc650dSSadaf Ebrahimi   (void)memcpy(dst_bytes, (char *)re, re->blocksize);
131*22dc650dSSadaf Ebrahimi 
132*22dc650dSSadaf Ebrahimi   /* Certain fields in the compiled code block are re-set during
133*22dc650dSSadaf Ebrahimi   deserialization. In order to ensure that the serialized data stream is always
134*22dc650dSSadaf Ebrahimi   the same for the same pattern, set them to zero here. We can't assume the
135*22dc650dSSadaf Ebrahimi   copy of the pattern is correctly aligned for accessing the fields as part of
136*22dc650dSSadaf Ebrahimi   a structure. Note the use of sizeof(void *) in the second of these, to
137*22dc650dSSadaf Ebrahimi   specify the size of a pointer. If sizeof(uint8_t *) is used (tables is a
138*22dc650dSSadaf Ebrahimi   pointer to uint8_t), gcc gives a warning because the first argument is also a
139*22dc650dSSadaf Ebrahimi   pointer to uint8_t. Casting the first argument to (void *) can stop this, but
140*22dc650dSSadaf Ebrahimi   it didn't stop Coverity giving the same complaint. */
141*22dc650dSSadaf Ebrahimi 
142*22dc650dSSadaf Ebrahimi   (void)memset(dst_bytes + offsetof(pcre2_real_code, memctl), 0,
143*22dc650dSSadaf Ebrahimi     sizeof(pcre2_memctl));
144*22dc650dSSadaf Ebrahimi   (void)memset(dst_bytes + offsetof(pcre2_real_code, tables), 0,
145*22dc650dSSadaf Ebrahimi     sizeof(void *));
146*22dc650dSSadaf Ebrahimi   (void)memset(dst_bytes + offsetof(pcre2_real_code, executable_jit), 0,
147*22dc650dSSadaf Ebrahimi     sizeof(void *));
148*22dc650dSSadaf Ebrahimi 
149*22dc650dSSadaf Ebrahimi   dst_bytes += re->blocksize;
150*22dc650dSSadaf Ebrahimi   }
151*22dc650dSSadaf Ebrahimi 
152*22dc650dSSadaf Ebrahimi *serialized_bytes = bytes;
153*22dc650dSSadaf Ebrahimi *serialized_size = total_size;
154*22dc650dSSadaf Ebrahimi return number_of_codes;
155*22dc650dSSadaf Ebrahimi }
156*22dc650dSSadaf Ebrahimi 
157*22dc650dSSadaf Ebrahimi 
158*22dc650dSSadaf Ebrahimi /*************************************************
159*22dc650dSSadaf Ebrahimi *          Deserialize compiled patterns         *
160*22dc650dSSadaf Ebrahimi *************************************************/
161*22dc650dSSadaf Ebrahimi 
162*22dc650dSSadaf Ebrahimi PCRE2_EXP_DEFN int32_t PCRE2_CALL_CONVENTION
pcre2_serialize_decode(pcre2_code ** codes,int32_t number_of_codes,const uint8_t * bytes,pcre2_general_context * gcontext)163*22dc650dSSadaf Ebrahimi pcre2_serialize_decode(pcre2_code **codes, int32_t number_of_codes,
164*22dc650dSSadaf Ebrahimi    const uint8_t *bytes, pcre2_general_context *gcontext)
165*22dc650dSSadaf Ebrahimi {
166*22dc650dSSadaf Ebrahimi const pcre2_serialized_data *data = (const pcre2_serialized_data *)bytes;
167*22dc650dSSadaf Ebrahimi const pcre2_memctl *memctl = (gcontext != NULL) ?
168*22dc650dSSadaf Ebrahimi   &gcontext->memctl : &PRIV(default_compile_context).memctl;
169*22dc650dSSadaf Ebrahimi 
170*22dc650dSSadaf Ebrahimi const uint8_t *src_bytes;
171*22dc650dSSadaf Ebrahimi pcre2_real_code *dst_re;
172*22dc650dSSadaf Ebrahimi uint8_t *tables;
173*22dc650dSSadaf Ebrahimi int32_t i, j;
174*22dc650dSSadaf Ebrahimi 
175*22dc650dSSadaf Ebrahimi /* Sanity checks. */
176*22dc650dSSadaf Ebrahimi 
177*22dc650dSSadaf Ebrahimi if (data == NULL || codes == NULL) return PCRE2_ERROR_NULL;
178*22dc650dSSadaf Ebrahimi if (number_of_codes <= 0) return PCRE2_ERROR_BADDATA;
179*22dc650dSSadaf Ebrahimi if (data->number_of_codes <= 0) return PCRE2_ERROR_BADSERIALIZEDDATA;
180*22dc650dSSadaf Ebrahimi if (data->magic != SERIALIZED_DATA_MAGIC) return PCRE2_ERROR_BADMAGIC;
181*22dc650dSSadaf Ebrahimi if (data->version != SERIALIZED_DATA_VERSION) return PCRE2_ERROR_BADMODE;
182*22dc650dSSadaf Ebrahimi if (data->config != SERIALIZED_DATA_CONFIG) return PCRE2_ERROR_BADMODE;
183*22dc650dSSadaf Ebrahimi 
184*22dc650dSSadaf Ebrahimi if (number_of_codes > data->number_of_codes)
185*22dc650dSSadaf Ebrahimi   number_of_codes = data->number_of_codes;
186*22dc650dSSadaf Ebrahimi 
187*22dc650dSSadaf Ebrahimi src_bytes = bytes + sizeof(pcre2_serialized_data);
188*22dc650dSSadaf Ebrahimi 
189*22dc650dSSadaf Ebrahimi /* Decode tables. The reference count for the tables is stored immediately
190*22dc650dSSadaf Ebrahimi following them. */
191*22dc650dSSadaf Ebrahimi 
192*22dc650dSSadaf Ebrahimi tables = memctl->malloc(TABLES_LENGTH + sizeof(PCRE2_SIZE), memctl->memory_data);
193*22dc650dSSadaf Ebrahimi if (tables == NULL) return PCRE2_ERROR_NOMEMORY;
194*22dc650dSSadaf Ebrahimi 
195*22dc650dSSadaf Ebrahimi memcpy(tables, src_bytes, TABLES_LENGTH);
196*22dc650dSSadaf Ebrahimi *(PCRE2_SIZE *)(tables + TABLES_LENGTH) = number_of_codes;
197*22dc650dSSadaf Ebrahimi src_bytes += TABLES_LENGTH;
198*22dc650dSSadaf Ebrahimi 
199*22dc650dSSadaf Ebrahimi /* Decode the byte stream. We must not try to read the size from the compiled
200*22dc650dSSadaf Ebrahimi code block in the stream, because it might be unaligned, which causes errors on
201*22dc650dSSadaf Ebrahimi hardware such as Sparc-64 that doesn't like unaligned memory accesses. The type
202*22dc650dSSadaf Ebrahimi of the blocksize field is given its own name to ensure that it is the same here
203*22dc650dSSadaf Ebrahimi as in the block. */
204*22dc650dSSadaf Ebrahimi 
205*22dc650dSSadaf Ebrahimi for (i = 0; i < number_of_codes; i++)
206*22dc650dSSadaf Ebrahimi   {
207*22dc650dSSadaf Ebrahimi   CODE_BLOCKSIZE_TYPE blocksize;
208*22dc650dSSadaf Ebrahimi   memcpy(&blocksize, src_bytes + offsetof(pcre2_real_code, blocksize),
209*22dc650dSSadaf Ebrahimi     sizeof(CODE_BLOCKSIZE_TYPE));
210*22dc650dSSadaf Ebrahimi   if (blocksize <= sizeof(pcre2_real_code))
211*22dc650dSSadaf Ebrahimi     return PCRE2_ERROR_BADSERIALIZEDDATA;
212*22dc650dSSadaf Ebrahimi 
213*22dc650dSSadaf Ebrahimi   /* The allocator provided by gcontext replaces the original one. */
214*22dc650dSSadaf Ebrahimi 
215*22dc650dSSadaf Ebrahimi   dst_re = (pcre2_real_code *)PRIV(memctl_malloc)(blocksize,
216*22dc650dSSadaf Ebrahimi     (pcre2_memctl *)gcontext);
217*22dc650dSSadaf Ebrahimi   if (dst_re == NULL)
218*22dc650dSSadaf Ebrahimi     {
219*22dc650dSSadaf Ebrahimi     memctl->free(tables, memctl->memory_data);
220*22dc650dSSadaf Ebrahimi     for (j = 0; j < i; j++)
221*22dc650dSSadaf Ebrahimi       {
222*22dc650dSSadaf Ebrahimi       memctl->free(codes[j], memctl->memory_data);
223*22dc650dSSadaf Ebrahimi       codes[j] = NULL;
224*22dc650dSSadaf Ebrahimi       }
225*22dc650dSSadaf Ebrahimi     return PCRE2_ERROR_NOMEMORY;
226*22dc650dSSadaf Ebrahimi     }
227*22dc650dSSadaf Ebrahimi 
228*22dc650dSSadaf Ebrahimi   /* The new allocator must be preserved. */
229*22dc650dSSadaf Ebrahimi 
230*22dc650dSSadaf Ebrahimi   memcpy(((uint8_t *)dst_re) + sizeof(pcre2_memctl),
231*22dc650dSSadaf Ebrahimi     src_bytes + sizeof(pcre2_memctl), blocksize - sizeof(pcre2_memctl));
232*22dc650dSSadaf Ebrahimi   if (dst_re->magic_number != MAGIC_NUMBER ||
233*22dc650dSSadaf Ebrahimi       dst_re->name_entry_size > MAX_NAME_SIZE + IMM2_SIZE + 1 ||
234*22dc650dSSadaf Ebrahimi       dst_re->name_count > MAX_NAME_COUNT)
235*22dc650dSSadaf Ebrahimi     {
236*22dc650dSSadaf Ebrahimi     memctl->free(dst_re, memctl->memory_data);
237*22dc650dSSadaf Ebrahimi     return PCRE2_ERROR_BADSERIALIZEDDATA;
238*22dc650dSSadaf Ebrahimi     }
239*22dc650dSSadaf Ebrahimi 
240*22dc650dSSadaf Ebrahimi   /* At the moment only one table is supported. */
241*22dc650dSSadaf Ebrahimi 
242*22dc650dSSadaf Ebrahimi   dst_re->tables = tables;
243*22dc650dSSadaf Ebrahimi   dst_re->executable_jit = NULL;
244*22dc650dSSadaf Ebrahimi   dst_re->flags |= PCRE2_DEREF_TABLES;
245*22dc650dSSadaf Ebrahimi 
246*22dc650dSSadaf Ebrahimi   codes[i] = dst_re;
247*22dc650dSSadaf Ebrahimi   src_bytes += blocksize;
248*22dc650dSSadaf Ebrahimi   }
249*22dc650dSSadaf Ebrahimi 
250*22dc650dSSadaf Ebrahimi return number_of_codes;
251*22dc650dSSadaf Ebrahimi }
252*22dc650dSSadaf Ebrahimi 
253*22dc650dSSadaf Ebrahimi 
254*22dc650dSSadaf Ebrahimi /*************************************************
255*22dc650dSSadaf Ebrahimi *    Get the number of serialized patterns       *
256*22dc650dSSadaf Ebrahimi *************************************************/
257*22dc650dSSadaf Ebrahimi 
258*22dc650dSSadaf Ebrahimi PCRE2_EXP_DEFN int32_t PCRE2_CALL_CONVENTION
pcre2_serialize_get_number_of_codes(const uint8_t * bytes)259*22dc650dSSadaf Ebrahimi pcre2_serialize_get_number_of_codes(const uint8_t *bytes)
260*22dc650dSSadaf Ebrahimi {
261*22dc650dSSadaf Ebrahimi const pcre2_serialized_data *data = (const pcre2_serialized_data *)bytes;
262*22dc650dSSadaf Ebrahimi 
263*22dc650dSSadaf Ebrahimi if (data == NULL) return PCRE2_ERROR_NULL;
264*22dc650dSSadaf Ebrahimi if (data->magic != SERIALIZED_DATA_MAGIC) return PCRE2_ERROR_BADMAGIC;
265*22dc650dSSadaf Ebrahimi if (data->version != SERIALIZED_DATA_VERSION) return PCRE2_ERROR_BADMODE;
266*22dc650dSSadaf Ebrahimi if (data->config != SERIALIZED_DATA_CONFIG) return PCRE2_ERROR_BADMODE;
267*22dc650dSSadaf Ebrahimi 
268*22dc650dSSadaf Ebrahimi return data->number_of_codes;
269*22dc650dSSadaf Ebrahimi }
270*22dc650dSSadaf Ebrahimi 
271*22dc650dSSadaf Ebrahimi 
272*22dc650dSSadaf Ebrahimi /*************************************************
273*22dc650dSSadaf Ebrahimi *            Free the allocated stream           *
274*22dc650dSSadaf Ebrahimi *************************************************/
275*22dc650dSSadaf Ebrahimi 
276*22dc650dSSadaf Ebrahimi PCRE2_EXP_DEFN void PCRE2_CALL_CONVENTION
pcre2_serialize_free(uint8_t * bytes)277*22dc650dSSadaf Ebrahimi pcre2_serialize_free(uint8_t *bytes)
278*22dc650dSSadaf Ebrahimi {
279*22dc650dSSadaf Ebrahimi if (bytes != NULL)
280*22dc650dSSadaf Ebrahimi   {
281*22dc650dSSadaf Ebrahimi   pcre2_memctl *memctl = (pcre2_memctl *)(bytes - sizeof(pcre2_memctl));
282*22dc650dSSadaf Ebrahimi   memctl->free(memctl, memctl->memory_data);
283*22dc650dSSadaf Ebrahimi   }
284*22dc650dSSadaf Ebrahimi }
285*22dc650dSSadaf Ebrahimi 
286*22dc650dSSadaf Ebrahimi /* End of pcre2_serialize.c */
287