• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..20-Dec-2021-

LICENCEH A D20-Dec-20213.1 KiB9465

README.pcre_update.mdH A D20-Dec-202131.4 KiB753587

dftables.cH A D20-Dec-20216.8 KiB213134

local_config.hH A D20-Dec-20214.4 KiB9015

pcre.hH A D20-Dec-202136 KiB842640

pcre.mkH A D20-Dec-20215 KiB138106

pcre_byte_order.cH A D20-Dec-20219.2 KiB325220

pcre_chartables.cH A D20-Dec-20217.7 KiB201141

pcre_compile.cH A D20-Dec-2021315.5 KiB9,8246,173

pcre_config.cH A D20-Dec-20215.1 KiB201119

pcre_dfa_exec.cH A D20-Dec-2021124.1 KiB3,6852,718

pcre_exec.cH A D20-Dec-2021232.4 KiB7,7455,763

pcre_fullinfo.cH A D20-Dec-20217.8 KiB253141

pcre_get.cH A D20-Dec-202125.3 KiB760457

pcre_globals.cH A D20-Dec-20213.8 KiB8927

pcre_internal.hH A D20-Dec-2021112.2 KiB2,8381,848

pcre_jit_compile.cH A D20-Dec-2021357 KiB11,95110,041

pcre_latin_1_table.cH A D20-Dec-20217.3 KiB195141

pcre_maketables.cH A D20-Dec-20215.8 KiB16362

pcre_newline.cH A D20-Dec-20216 KiB21299

pcre_ord2utf8.cH A D20-Dec-20213.2 KiB9727

pcre_refcount.cH A D20-Dec-20213.8 KiB9929

pcre_string_utils.cH A D20-Dec-20215.3 KiB212105

pcre_study.cH A D20-Dec-202148 KiB1,7081,158

pcre_tables.cH A D20-Dec-202128.1 KiB729577

pcre_ucd.cH A D20-Dec-2021203.7 KiB3,6453,135

pcre_valid_utf8.cH A D20-Dec-202111.4 KiB372201

pcre_version.cH A D20-Dec-20214.2 KiB10526

pcre_xclass.cH A D20-Dec-20218.1 KiB270149

ucp.hH A D20-Dec-20215.1 KiB227186

README.pcre_update.md

1# How to update the PCRE version used by Erlang
2
3## The basic changes to the PCRE library
4
5To work with the Erlang VM, PCRE has been changed in three important ways:
6
71. The main execution machine in pcre\_exec has been modified so that
8matching can be interrupted and restarted. This functionality utilizes
9the code that implements recursion by allocating explicit
10"stack-frames" in heap space, which basically means that all local
11variables in the loop are part of a struct which is kept in "malloced"
12memory on the heap and there are no real stack variables that need to
13be pushed on the C stack in the case of recursive calls. This is a
14technique we also use inside the VM to avoid building large C
15stacks. In PCRE this is enabled by the NO\_RECURSE define, so that is a
16prerequisite for the ERLANG\_INTEGRATION define which also adds labels
17at restart points and counts "reductions".
18
192. All visible symbols in PCRE gets the erts_ prefix, so that NIF's
20and such using a "real" pcre library does not get confused (or 're'
21gets confused when a "real" pcre library get's loaded into the VM
22process).
23
243. All irrelevant functionality has been stripped from the library,
25which means for example UTF16 support, jit, DFA execution
26etc. Basically the source files handling this are removed, together
27with any build support from the PCRE project. We have our own
28makefiles etc.
29
30## Setting up an environment for the work
31
32I work with four temporary directories when doing this (the examples
33are from the updating of pcre-7.6 to pcre-8.33);
34
35       ~/tmp/pcre> ls
36       epcre-7.6  epcre-8.33  pcre-7.6  pcre-8.33
37
38I've unpacked the plain pcre sources in pcre-* and will work with our
39patched sources in the epcre-* directories.
40
41Make sure your ERL_TOP contains a *built* version of Erlang (and you have made a branch)
42
43First unpack the pcre libraries (which will create the pcre-*
44directories) and then copy our code to the old epcre directory:
45
46      ~/tmp/pcre> tar jxf $ERL_TOP/erts/emulator/pcre/pcre-7.6.tar.bz2
47      ~/tmp/pcre> tar jxf ~/Downloads/pcre-8.33.tar.bz2
48      ~/tmp/pcre> mkdir epcre-7.6  epcre-8.33
49      ~/tmp/pcre> cd epcre-7.6/
50      ~/tmp/pcre/epcre-7.6> cp -r $ERL_TOP/erts/emulator/pcre/* .
51      ~/tmp/pcre/epcre-7.6> rm pcre-7.6.tar.bz2
52
53Leave the obj directory, you may need the libepcre.a file...
54
55If you find it easier, you can revert the commit in GIT that adds the
56erts_ prefix to the previous version before continuing work, but as
57that is a quite small diff in newer versions of PCRE, it is probably
58not worth it. Still, you will find the erts_ prefix being a separate
59commit when integrating 8.33, so if you're nice, you will do the same
60for the person coming after you...
61
62## Generating a diff for our changes to PCRE
63
64Before you generate a diff (that, in an ideal world, would be used to
65automatically patch the newer version of pcre, which will probably
66only work for minor PCRE updates), we need to configure the old pcre.
67
68       ~/tmp/pcre/epcre-7.6> cd ../pcre-7.6
69       ~/tmp/pcre/pcre-7.6> ./configure --enable-utf8 --enable-unicode-properties --disable-shared --disable-stack-for-recursion
70
71Note that for newer versions, the configure flag '--enable-utf8'
72should be replaced with '--enable-utf'
73
74So we now generate a diff:
75
76    ~/tmp/pcre/pcre-7.6> cd ../epcre-7.6
77   ~/tmp/pcre/epcre-7.6> (for x in *.[ch]; do if [ -f ../pcre-7.6/$x ]; then diff -c ../pcre-7.6/$x $x; fi; done ) > ../epcre-7.6_clean.diff
78
79### What the diff means
80
81Let's now walk through the relevant parts of the diff. Some of the
82differences might come from patches that probably are already in the
83new version, For example in out 7.6, we had a security patch which
84added the define WORK_SIZE_CHECK and used it in some places. Those can
85probably safely be ignored, but to be on the safe side, check what's
86already integrated in the new version.
87
88The interesting part is in pcre_exec.c. You will see things like
89
90    #ifdef ERLANG_INTEGRATION
91    ...
92    #endif
93
94or
95
96    #if defined(ERLANG_INTEGRATION)
97    ...
98    #endif
99
100and a lot of
101
102    COST_CHK(1);
103
104or
105
106    COST(min);
107
108and
109
110    /* LOOP_COUNT: Ok */
111    /* LOOP_COUNT: CHK */
112    /* LOOP_COUNT: COST */
113
114
115scattered over the main loop. Those mean the following:
116
117* COST(int x) - consume reductions proportional to the integer
118  parameter, but no need for interruption here (it's like
119  bump_reductions without trapping). The loop they apply to also has a
120  'LOOP_COUNT: COST' comment at it's head.
121
122* COST\_CHK(int x) - like COST(x), but also check that the reduction
123counter does not reach zero. If it does, leave the execution loop to
124be restarted at a later point. No real stack variables can be live
125here. Note that variables like 'max' and 'min' are *not* real stack
126variables, the NO\_RECURSION setting has taken care of that. 'i' is a
127stack variable that's explicitly saved when trapping, so that will
128also be correct when returning from a trap. So will 'c', 'rrc' and
129flags like 'utf8', 'minimize' and 'posessive'. Those can also be
130regarded as "non C-stack variables". The loop where they reside also
131has a 'LOOP\_COUNT: CHK' comment.
132
133* /* LOOP_COUNT: Ok */ - means that I have checked the loop and it
134  only runs a deterministic set of iterations regardless of input, or
135  it has a call to RRECURSE in it's body, why we need not add more
136  cost than the normal reduction counting that will occur for each
137  instruction demands.
138
139The thing is that each loop in the function 'match' should be marked
140with one of these comments. If no comment is present after you patched
141the new release (if you successfully manage to do it automatically),
142it may be a new regexp instruction that is added since the last
143release.
144
145You will need to manually go through the main 'match' loop after
146upgrading to verify that there are no unhandled loops in the regexp
147machine loop (!).
148
149The COST\_CHK macro works like this:
150
1511. Add to the loop count.
1522. If loop count > limit:
153    1. Store the line (+100) in the Xwhere member of the frame structure
154    2. Goto LOOP\_COUNT\_BREAK, which ultimately returns from the function
1553. Insert a label, which is named L\_LOOP\_COUNT\_<line number>
156
157LOOP\_COUNT\_BREAK code will create an extra "stack frame" on the heap
158allocated stack used if NO\_RECURSION is set, and will store the few
159locals that are not already in the ordinary stack frame there (like
160'c' and 'i').
161
162When we continue execution (after a trap up to the main Erlang
163scheduler), we will jump to LOOP\_COUNT\_RETURN, which will restore
164the local variables and will jump to the labels. The jump code looks
165like this in the C source:
166
167     	switch (frame->Xwhere)
168      	       {
169      #include "pcre_exec_loop_break_cases.inc"
170      	       default:
171		        DPRINTF(("jump error in pcre match: label %d non-existent\n", frame->Xwhere));
172        		return PCRE_ERROR_INTERNAL;
173      		}
174
175When building, pcre\_exec\_loop\_break\_cases.inc will be generated
176during build by pcre.mk, it will look like:
177
178     case 791: goto L_LOOP_COUNT_691;
179     case 1892: goto L_LOOP_COUNT_1792;
180     case 1999: goto L_LOOP_COUNT_1899;
181
182etc
183
184So, simply put, all C-stack variables are saved when we have consumed
185our reductions, we return from the function and, as there is no real
186recursion we immediately fall out into the re:run BIF, which with the
187help of a magic binary keeps track of the heap allocated stack for the
188regexp machine. When we return from trapping out to the scheduler, all
189vital data is restored and we continue from exactly the same state as
190we left. What's needed is to patch this into the new pcre_exec and
191check all new instructions to determine what might need updating in
192terms of COST, COST\_CHK etc.
193
194Well, that's *almost* everything, because there is of course more...
195
196The actual interface function, 'pcre\_exec', needs the same treatment
197as the actual regexp machine loop, that is we need to store all local
198variables between restarts. Unfortunately the NO\_RECURSE setting does
199not do this, we need to do it ourselves. So there's quite a diff in
200that function too, where a big struct is declared, containing every
201local variable in that function, together with either local copies
202that are swapped in and out, or macros that directly access the heap
203allocated struct. The struct is called `PcreExecContext`.
204
205If a context is present, we are restarting and therefore restore
206everything. If we are restarting we can also skip all initialization
207code in the function and jump more or less directly to the
208RESTART_INTERRUPTED label and the call to 'match', which is the actual
209regexp machine loop.
210
211There are a few places in the pcre_exec we need to do some housekeeping, you will see code like:
212
213 	if ((extra_data->flags & PCRE_EXTRA_LOOP_LIMIT) != 0)
214 	  {
215		*extra_data->loop_counter_return =
216 	    		(extra_data->loop_limit - md->loop_limit);
217          }
218
219Make sure, after updating, that this housekeeping is done whenever we
220do not reach the call to 'match'.
221
222So, now we in theory know what to do, so let's do it:
223
224But...
225
226## File changes in the new version of PCRE
227
228First we need to go through what's changed in the new library
229version. Files may have new names, functions may have moved and so on.
230
231Start by building the new library:
232
233      ~/tmp/pcre> cd pcre-8.33/
234      ~/tmp/pcre/pcre-8.33> ./configure --enable-utf --enable-unicode-properties --disable-shared --disable-stack-for-recursion
235      ~/tmp/pcre/pcre-8.33> make
236
237In the make process, you will probably notice most files that are
238used, but you can bet that's not all not all...
239
240To begin with you will need a default table for Latin-1 characters, so:
241
242   	 ~/tmp/pcre/pcre-8.33> cc -DHAVE_CONFIG_H -o dftables dftables.c
243	 ~/tmp/pcre/pcre-8.33> LANG=sv_SE ./dftables -L ../epcre-8.33/pcre_latin_1_table.c
244
245Compare it to the pcre\_latin\_1\_table.c in the old version, they
246should not differ in any significant way. If they do, it might be
247that you do not have the sv_SE locale installed on your machine.
248
249A good starting point is then to try to find all files in the new
250version of the library that have (probably) the same names as the
251one's in our distribution:
252
253	~/tmp/pcre/pcre-8.33> cd ../epcre-7.6/
254	~/tmp/pcre/epcre-7.6> for x in *.[ch]; do if [ '!' -f ../pcre-8.33/$x ]; then echo $x; else cp ../pcre-8.33/$x ../epcre-8.33/; fi; done
255
256This will output a list of files not found in the new distro. Let's
257look at the list from the example upgrade:
258
259     local_config.h
260     make_latin1_table.c
261     pcre_info.c
262     pcre_latin_1_table.c
263     pcre_make_latin1_default.c
264     pcre_try_flipped.c
265     pcre_ucp_searchfuncs.c
266     ucpinternal.h
267     ucptable.h
268
269* local\_config.h - OK, that's our child, it contains PCRE-specific
270  configure-results (i.e. the #defines that are results from out
271  parameters to configure, like NO\_RECURSE etc). Just copy it and
272  edit it according to what specific settings you can find in the
273  generated config.h from the real library build. In our example case,
274  the #define SUPPORT\_UTF8 should be renamed to #define SUPPORT\_UTF
275  and #define VERSION "7.6" should be changed to #define VERSION
276  "8.33"...
277
278* make\_latin1\_table.c - it was renamed to dftables.c, so we copy
279  that instead.
280
281* pcre\_info.c - It was simply removed from the library. Good, because
282  it was useless... So just ignore.
283
284* pcre\_latin\_1\_table.c - No problem, we generated a new one in the
285  earlier stage.
286
287* pcre\_make\_latin1\_default.c - No longer used, a hack that's not
288  needed with dftables. Ignored
289
290* pcre\_try\_flipped.c - This functionality has been removed from
291  pcre\_exec, you cannot compile on one endianess and execute on
292  another any more :( Ignored.
293
294* pcre\_ucp\_searchfuncs.c, ucpinternal.h, ucptable.h - this
295  functionality is moved to pcre\_ucd.c, copy that one instead.
296
297OK, now go the other way and look at what was actually built for the new version of pcre:
298
299    ~/tmp/pcre/epcre-7.6> cd ../pcre-8.33/
300    ~/tmp/pcre/pcre-8.33> nm ./.libs/libpcre.a | egrep 'lib.*.o:'
301
302The output for this release was:
303
304    libpcre_la-pcre_byte_order.o:
305    libpcre_la-pcre_compile.o:
306    libpcre_la-pcre_config.o:
307    libpcre_la-pcre_dfa_exec.o:
308    libpcre_la-pcre_exec.o:
309    libpcre_la-pcre_fullinfo.o:
310    libpcre_la-pcre_get.o:
311    libpcre_la-pcre_globals.o:
312    libpcre_la-pcre_jit_compile.o:
313    libpcre_la-pcre_maketables.o:
314    libpcre_la-pcre_newline.o:
315    libpcre_la-pcre_ord2utf8.o:
316    libpcre_la-pcre_refcount.o:
317    libpcre_la-pcre_string_utils.o:
318    libpcre_la-pcre_study.o:
319    libpcre_la-pcre_tables.o:
320    libpcre_la-pcre_ucd.o:
321    libpcre_la-pcre_valid_utf8.o:
322    libpcre_la-pcre_version.o:
323    libpcre_la-pcre_xclass.o:
324    libpcre_la-pcre_chartables.o:
325
326Libtool has changed the object names, but we can fix that and see what
327sources we have already decided should exist:
328
329	~/tmp/pcre/pcre-8.33> NAMES=`nm ./.libs/libpcre.a | egrep 'lib.*.o:'| sed 's,libpcre_la-,,' | sed 's,.o:$,,'`
330	~/tmp/pcre/pcre-8.33> for x in $NAMES; do if [ '!' -f ../epcre-8.33/$x.c ]; then echo $x; fi; done
331
332And the list contained:
333
334    pcre_byte_order
335    pcre_jit_compile
336    pcre_string_utils
337
338pcre\_jit\_compile is actually needed, even though we have not enabled
339jit, and the other two contain functionality needed, so just copy the
340sources...
341
342    ~/tmp/pcre/pcre-8.33> for x in $NAMES; do if [ '!' -f ../epcre-8.33/$x.c ]; then cp $x.c ../epcre-8.33/; fi; done
343
344## Test build of stripped down version of new PCRE
345
346Time to do a test build. Copy and edit the pcre.mk makefile and try to
347get something that builds...
348
349I made a wrapper Makefile, hacked pcre.mk a little and did a few
350changes to a few files, namely added:
351
352	#ifdef ERLANG_INTEGRATION
353	#include "local_config.h"
354	#endif
355
356to pcre\_config.c and pcre\_internal.h. Also pcre.mk needs to get the
357new files added and the old files removed, directory names need to be
358changed and the wrapper can define most. My wrapper Makefile looked
359like this:
360
361    EPCRE_LIB = ./obj/libepcre.a
362    PCRE_GENINC = ./pcre_exec_loop_break_cases.inc
363    PCRE_OBJDIR = ./obj
364    V_AR = ar
365    V_CC = gcc
366    CFLAGS = -g -O2 -DHAVE_CONFIG_H -I/ldisk/pan/git/otp/erts/x86_64-unknown-linux-gnu
367    gen_verbose =
368    PCRE_DIR=.
369    include pcre.mk
370
371And the according variables were removed together with dependencies
372from pcre.mk. Note that you will need to put things back in order in
373pcre.mk after all testing is done. Once a 'make' is successful, you
374can generate new dependencies:
375
376    ~/tmp/pcre/epcre-8.33> gcc -MM -c -g -O2 -DHAVE_CONFIG_H -I/ldisk/pan/git/otp/erts/x86_64-unknown-linux-gnu -DERLANG_INTEGRATION *.c | grep -v $ERL_TOP
377
378Well, then you have to add $(PCRE\_OBJDIR)/ to each object and
379$(PCRE\_DIR)/ to each header. I did it manually, it's just a couple of
380files. Now your pcre.mk is fairly up to date and it's time to start
381patching in the changes...
382
383## Actually patching in the changes to the C code
384
385### Fixing the functionality (interruptable pcre\_run etc)
386
387Begin with only pcre\_exec.c, that's the important part:
388
389    ~/tmp/pcre/epcre-8.33> cd ../epcre-7.6/
390    ~/tmp/pcre/epcre-7.6> diff -c ../pcre-7.6/pcre_exec.c ./pcre_exec.c > ../epcre_exec.c_7.6.diff
391    ~/tmp/pcre/epcre-7.6> cd ../epcre-8.33
392
393Now - if you are lucky, you can patch the new pcre\_exec with the
394patch command from the diff, but that may not be the case... Even if:
395
396    ~/tmp/pcre/epcre-8.33> patch -p0 < ../epcre_exec.c_7.6.diff
397
398works like a charm, you still have to go through the main loop and see
399that all do, while and for loops in the code contains COST\_CHK or at
400least COST, or, if it's a small loop (over, say one UTF character),
401mark it as OK with a comment.
402
403You should also check for other changes, like new local variables in
404the pcre\_exec code etc.
405
406What will probably happen, is that the majority of chunks
407fail. pcre\_exec is the main file for PCRE, one that is constantly
408optimized and where every new feature ends up. You will probably see
409so many failed HUNK's that you feel like giving up, but do not
410despair, it's just a matter of patience and hard work:
411
412* First, fix the 'pcre\_exec' function.
413
414    * Change the struct PcreExecContext to reflect the local variables
415      in this version of the code.
416
417    * Add/update the defines that makes local variables in the code
418      actually stay in an allocated "exec\_context" and be sure to
419      initialize the "pseudo-stack-variables" in the same way as in
420      the declarations for the original version of the code.
421
422    * The macros SWAPIN and SWAPOUT should be for variables that are
423      used a lot and we do not want to always access through the
424      struct. Also a few parameters are saved by SWAPIN and SWAPOUT.
425
426    * What might be tricky is to get things deallocated in a proper
427      way, there is a function that's called from the BIF code to
428      clean up an exec\_context, be especially observant about how the
429      stack in the 'match' function is allocated! The first frame is
430      supposed to be on the C stack, but in our case is allocated in
431      the exec\_context. The rest of the frames are allocated but
432      never freed, not until the match is done.
433
434      The variable 'frame' in the 'match' function is stored in our
435      additional field of the 'md' structure, that is the stack top,
436      but not necessarily the uppermost frame (due to reuse of old
437      frames, which is supposed to be an optimization...).
438
439    * The housekeeping of the "reduction counter" in the extra\_data
440      struct needs to be added to all places where we break out of the
441      main loop of pcre\_exec. Look for 'break' and you will see the
442      places. Make sure to update
443      '*extra\_data->loop\_counter\_return' whenever you leave this
444      function. It all boils down to some code that loops over the
445      call for match and returns PCRE\_ERROR\_LOOP\_LIMIT and get's
446      jumped back to when the BIF is restarted. You will see it in
447      your diff and you will find a similar place in the new version
448      where you put basically the same code.
449
450    * Fixing pcre\_exec takes about an hour of concentrated work, it
451      could be worse...
452
453* Next, go for the match function. It's simpler in some ways but
454  harder in other. The elimination of the C stack is already there,
455  you just need to modify it a little:
456
457    * In the RRETURN macro for NO\_RECURSE, add updating of
458      md->loop\_limit before returning. You can see how it's done in
459      the diff.
460
461    * RMATCH can be left as it is, at least it could in earlier
462      versions. Note however that you should mimic the allocation
463      strategies of RMATCH and RRETURN in the code at another place
464      later... The principle of the labels HEAP\_RECURSE and
465      HEAP\_RETURN are mimicked by our code in LOOP\_COUNT\_BREAK and
466      LOOP\_COUNT\_RETURN. You'll see later...
467
468    * COST and COST\_CHK, together with the jump to
469      LOOP\_COUNT\_RETURN label are in the beginning of the function
470      'match'. It's a block of macros and declaration of our local
471      variables loop\_count and loop\_limit. We patch in the code for
472      that, but may need to adopt it to new variable names etc. It's
473      important to handle the 'frames' variable correctly, dig it out
474      of the 'md' struct when we are restarting, but initialize it as
475      is done in normal NO\_RECURSE code otherwise. Note that the
476      COST\_CHK macro reuses the Xwhere field of the frame struct, it
477      is not needed when trapping.
478
479    * The LOOP\_COUNT\_BREAK and the LOOP\_COUNT\_RETURN code can now
480      be added. Make sure to check both how a new stack frame should be
481      properly allocated by mimicking the code in RMATCH, and how (if)
482      it should be freed by mimicking RRETURN. Also check which
483      variables need to be saved. They are properly pointed out in
484      8.33 with the comment 'These variables do not need to be
485      preserved over recursion' and appear in the beginning of the
486      function. Find variables of similar type in the frame structure
487      and reuse them. In 8.33 there are eight such variables. They are
488      placed at the end of the function 'match'. If You are reading
489      the diff, you need to scroll past all the COST\_CHK calls,
490      i.e. past the whole regexp machine loop.
491
492    * Now take the time to add things like debug macros to the top of
493      the file and one single COST\_CHK (preferably the one right
494      after for(;;) in 'match'), and see if you can compile. You will
495      probably need to add some fields in the structures in pcre.h,
496      see from a larger diff what you need there and iterate until you
497      can compile.
498
499    * So, what's left is to add all the COST and COST\_CHK macros,
500      plus marking all harmless loops as OK. There are a few rules
501      here:
502
503        * Mark *every* loop with the comment 'LOOP\_COUNT: xxxx',
504          where xxxx is either 'Ok', 'COST' or 'CHK'. There are 175
505          'LOOP\_COUNT:' comments in 8.33.
506
507        * Loops marked 'Ok' need no macro, either because they are so
508          short (like over an UTF character) or because they contain
509          an RMATCH macro, in which case they will be accounted for
510          anyway.
511
512        * Loops marked 'COST' will have an associated 'COST(N)' macro,
513          either before, if we know the amount of iterations, or
514          within. Reductions are counted, but we will not
515          interrupt. This is typically in what is expected to be
516          medium long loops or at places where interruption is hard
517          (like where we have local variables that are alive. The
518          selection between 'COST' and 'COST\_CHK' is hard. 'COST' is
519          much cheaper and usually enough, but when in doubt about the
520          loop length, try to use 'COST\_CHK', while making very sure
521          there are no live block-local variables that need to be
522          saved over the trap. There are 49 'COST' macros in 8.33.
523
524        * Loops marked 'CHK' shall contain a 'COST\_CHK(N)'
525          macro. This macro both counts reductions and may result in
526          an interrupt and a return to Erlang space. It is expensive
527          and it is vital to ensure that there are no unexpected local
528          variables that live past the macro. Most variables are in
529          the pseudo stack frame, but some regexp instructions declare
530          temporaries inside blocks. Make sure they are not expected
531          to be alive after a COST\_CHK if they are not in the
532          'heapframe' structure. If they are, you need to
533          conditionally move them to the 'heapframe' #if
534          defined(ERLANG\_INTEGRATION). in 8.33 the variables 'lgb'
535          and 'rgb' are preserved in this way. There are 54
536          'COST\_CHK's in 8.33.
537
538        * I've marked a few block-local variables with warnings, but
539          look thoroughly through the main loop to detect any new
540          ones.
541
542        * Be careful when it comes to freeing the context from Erlang
543          (the function erts\_pcre\_free\_restart\_data), Whatever is
544          done there has to work *both* when the context is freed in
545          the middle of an operation (because of trapping) and when
546          some things have been freed by a successful
547          return. Specifically, make sure to set md->offset\_vector to
548          NULL whenever it's freed (in the rest of the code) and
549          construct release\_match\_heapframes so that it can be
550          called multiple times for the same heapframe (set the next
551          pointer in the "static" frame, i.e. the one allocated in the
552          md to NULL after freeing).
553
554    * To add the costs to the main loop takes less than one work day,
555      keep calm and continue...
556
557OK, now you are done with the pcre\_exec (or at least, you think
558so). The rest is simpler. You have probably already handled 'pcre.h'
559and 'pcre\_internal.h' to add fields to the structures etc. Looking at
560a diff from an earlier version, you will see what's left. In upgrading
561to 8.33, the following things was left to do after pcre\_exec was
562fixed, remember you could generate a diff with:
563
564    ~/tmp/pcre/epcre-8.33> cd ../epcre-7.6/
565    ~/tmp/pcre/epcre-7.6> (for x in *.[ch]; do if [ -f ../pcre-7.6/$x ]; then diff -c ../pcre-7.6/$x $x; fi; done) > ../epcre-7.6.diff
566
567Open the diff in your favorite editor and remove whatever changes you
568have already made, like everything that has to do with pcre\_exec.c
569and probably a large part of pcre.h/pcre\_internal.h.
570
571The expected result is a diff that either contains only the
572'%ExternalCopyright%' comments or contains them and the addition of
573the erts\_ prefix, depending on if you reverted the prefix change
574(using 'git revert') before starting to work. With a little luck, the
575patch of the remaining stuff should be possible to apply
576automatically. If anything fails, just add it manually.
577
578### Fixing the erts\_prefix
579
580The erts\_ prefix is mostly implemented by adding '#if
581defined(ERLANG\_INTEGRATION)' to a lot of function headers, inside the
582COMPILE\_UTF8 part. If you then also change the PRIV and PUBL macros
583in pcre\_internal.h. Typical diffs look like:
584
585        #if defined COMPILE_PCRE8
586      + #if defined(ERLANG_INTEGRATION)
587      + #ifndef PUBL
588      + #define PUBL(name) erts_pcre_##name
589      + #endif
590      + #ifndef PRIV
591      + #define PRIV(name) _erts_pcre_##name
592      + #endif
593      + #else
594        #ifndef PUBL
595        #define PUBL(name) pcre_##name
596        #endif
597        #ifndef PRIV
598        #define PRIV(name) _pcre_##name
599        #endif
600      + #endif
601
602and
603
604	    #if defined COMPILE_PCRE8
605	  + #if defined(ERLANG_INTEGRATION)
606	  + PCRE_EXP_DECL int erts_pcre_pattern_to_host_byte_order(pcre *argument_re,
607	  +   erts_pcre_extra *extra_data, const unsigned char *tables)
608	  + #else
609  	    PCRE_EXP_DECL int pcre_pattern_to_host_byte_order(pcre *argument_re,
610    	      pcre_extra *extra_data, const unsigned char *tables)
611	  + #endif
612
613Note that some data types, like pcre\_extra are accessed with the PUBL
614macro, so they need to explicitly get the prefix added. pcre.h is a
615pig, as it declares prototypes for all functions regardless of
616compilation ode, so there is quite a lot of '#if
617defined(ERLANG\_INTEGRATION)' to add there.
618
619Anyway, now try to patch, using a diff where you have removed the
620changes you made manually (probably to pcre\_exec.c) but make sure to
621save your work (temporary git repository?) before, so you can revert
622any disasters...
623
624    ~/tmp/pcre/epcre-7.6> cd ../epcre-8.33/
625    ~/tmp/pcre/epcre-8.33> patch -p0 < ../epcre-7.6_clean2.diff
626
627Some hunks may certainly still fail, read through the .rej file and fix it.
628
629### ExternalCopyright
630
631Now you should check that the 'ExternalCopyright' comment is present
632in all source files:
633
634    ~/tmp/pcre/epcre-8.33> for x in *.[ch]; do if grep ExternalCopyright $x > /dev/null; then true; else echo $x; fi; done
635
636In this upgrade (from 7.6 to 8.33) we certainly had some new and
637renamed files:
638
639    dftables.c
640    pcre_byte_order.c
641    pcre_chartables.c
642    pcre_jit_compile.c
643    pcre_latin_1_table.c
644    pcre_string_utils.c
645    pcre_ucd.c
646
647Go through them manually and add the 'ExternalCopyright' comment.
648
649## Integrate with Erlang
650
651Now you are done with most of the tedious work. It's time to move this
652into your branch of the Erlang source tree, remove old files and add
653new ones, plus add the tar file with the original pcre dist. Remember
654to fix your hacked version of pcre.mk and then try to build
655Erlang. You might need to update 'erl\_bif\_re.c' to reflect any
656changes in the PCRE library. When it builds, run the test suites.
657
658Make sure to rename any files that has new names and remove any files
659that are no longer present before copying in the new versions from
660your temporary directory. In our example we remove 'pcre\_info.c',
661'pcre\_make\_latin1\_default.c', 'pcre\_try\_flipped.c',
662'ucpinternal.h' and 'ucptable.h'. We rename 'make\_latin1\_table.c' to
663'dftables.c' and 'pcre\_ucp\_searchfuncs.c' to 'pcre\_ucd.c'.
664
665After copying in the sources, we can try to build. Do not forget to
666fix whatever you did in pcre.mk to make it build locally.
667
668## Update test suites
669
670The next step is to integrate the updated PCRE tests into our test suites.
671
672Copy testoutput[1-9] from the testdata directory of your new version
673of pcre, to the re\_SUITE\_data in stdlib's test suites. Run the
674test suites and remove any bugs. Usually the bugs come from the fact
675that the PCRE test suites get better and from our implementation of
676global matching, which may have bugs outside of the PCRE library. The
677test suite 'pcre' is the one that runs these tests. Also copy
678testoutput11-8 to testoutput10, the testoutput10 file in pcre is
679nowadays for the DFA, which we do not use.
680
681The next step is to regenerate re\_testoutput1\_replacement\_test. How
682to do that is in a comment in the beginning of the file. The key
683module is run\_pcre\_tests.erl, which both driver the pcre test and
684generate re\_testoutput1\_replacement\_test.erl. Watch during the
685generation that you do not get to many of the "Fishy character"
686messages, if they are more than, say 20, you will probably need to
687address the UTF8 issues in the Perl execution. As it is now, we skip
688non latin1 characters in this test. You will need to run iconv on the
689generated module to make it UTF-8 before running tests. Try to use a
690perl version that is as new as possible.
691
692The exact same procedure goes for the re\_testoutput1\_split\_test.erl.
693
694Make a note about perl version used in the commit updating the replace
695and split test files.
696
697Note that the perl version you are using may not be completely
698compatible with the PCRE version you are upgrading to. If this is the
699case you might get failures when running the replace and split tests.
700If you get failures, you need to inspect the failures and decide what
701to do. If there are only a small amount of failures you will probably
702end up preferring the behavior of PCRE, and manually changing these
703tests. Do these changes in a separate commit so it is easy to see
704what differed.
705
706Also add copyright headers to the files after converting them to UTF-8.
707
708After ironing out the rest of the bugs, you should be done with the
709code.
710
711## Update documentation
712
713Now it's time for the documentation, which is fairly
714straightforward. Diff the pcrepattern man pages from the old and new
715PCRE distros and update the re.xml file accordingly. It may help to
716have the generated HTML file from the new version to cut and paste
717from, but as you will notice, it's quite a few changes from HTML to
718XML. All lists are reformatted, the &lt;pre&gt; tags are made into
719either &lt;code&gt; or &lt;quite&gt; etc. Also the &lt;P&gt; tags are
720converted to lowercase and all mentioned options and function calls
721are converted to their Erlang counterpart. Really awesome work that
722requires thorough reading of all new text.  For the upgrade from 7.6
723to 8.33, the update of the pcrepattern part of our manual page took
724about eight hours.
725
726## Update Licence
727
728Copy the LICENCE file to `erts/emulator/pcre/LICENCE` and update
729the `[PCRE]` section in `system/COPYRIGHT` with the content of
730the `LICENCE` file.
731
732## Add new relevant options to re
733
734Then, when all this is done, you should add any new relevant options
735from the PCRE library to both the code (erl\_bif\_re.c), the specs and
736the Erlang function 'copt/1' (re.erl) and the manual page
737(re.xml). Make sure the options are really relevant to add to the
738Erlang API, check if they are compile or run-time options (or both) and
739add them to the 'parse\_options' function of erl\_bif\_re.c. Adding an
740option that is just passed through to PCRE is pretty simple, at least
741"code wise".
742
743Now you are done. Run all test suites on all machines and you will be happy.
744
745## Final notes
746
747To avoid the work of a major upgrade, it is probably worth it to keep
748in pace with the changes to PCRE. The upgrade from 7.6 to 8.33,
749including tracking down bugs etc, took me a total of two weeks. If
750smaller diffs from the PCRE development were integrated in a more
751incremental fashion, it will be much easier each time and you will
752have the PCRE library up to date. PCRE should probably be updated for
753each major release, instead of every five years...