88 |
The same workspace is used during the second, actual compile phase for |
The same workspace is used during the second, actual compile phase for |
89 |
remembering forward references to groups so that they can be filled in at the |
remembering forward references to groups so that they can be filled in at the |
90 |
end. Each entry in this list occupies LINK_SIZE bytes, so even when LINK_SIZE |
end. Each entry in this list occupies LINK_SIZE bytes, so even when LINK_SIZE |
91 |
is 4 there is plenty of room. */ |
is 4 there is plenty of room for most patterns. However, the memory can get |
92 |
|
filled up by repetitions of forward references, for example patterns like |
93 |
|
/(?1){0,1999}(b)/, and one user did hit the limit. The code has been changed so |
94 |
|
that the workspace is expanded using malloc() in this situation. The value |
95 |
|
below is therefore a minimum, and we put a maximum on it for safety. The |
96 |
|
minimum is now also defined in terms of LINK_SIZE so that the use of malloc() |
97 |
|
kicks in at the same number of forward references in all cases. */ |
98 |
|
|
99 |
#define COMPILE_WORK_SIZE (4096) |
#define COMPILE_WORK_SIZE (2048*LINK_SIZE) |
100 |
|
#define COMPILE_WORK_SIZE_MAX (100*COMPILE_WORK_SIZE) |
101 |
|
|
102 |
/* The overrun tests check for a slightly smaller size so that they detect the |
/* The overrun tests check for a slightly smaller size so that they detect the |
103 |
overrun before it actually does run off the end of the data block. */ |
overrun before it actually does run off the end of the data block. */ |
104 |
|
|
105 |
#define WORK_SIZE_CHECK (COMPILE_WORK_SIZE - 100) |
#define WORK_SIZE_SAFETY_MARGIN (100) |
106 |
|
|
107 |
|
|
108 |
/* Table for handling escaped characters in the range '0'-'z'. Positive returns |
/* Table for handling escaped characters in the range '0'-'z'. Positive returns |
589 |
|
|
590 |
|
|
591 |
/************************************************* |
/************************************************* |
592 |
|
* Expand the workspace * |
593 |
|
*************************************************/ |
594 |
|
|
595 |
|
/* This function is called during the second compiling phase, if the number of |
596 |
|
forward references fills the existing workspace, which is originally a block on |
597 |
|
the stack. A larger block is obtained from malloc() unless the ultimate limit |
598 |
|
has been reached or the increase will be rather small. |
599 |
|
|
600 |
|
Argument: pointer to the compile data block |
601 |
|
Returns: 0 if all went well, else an error number |
602 |
|
*/ |
603 |
|
|
604 |
|
static int |
605 |
|
expand_workspace(compile_data *cd) |
606 |
|
{ |
607 |
|
uschar *newspace; |
608 |
|
int newsize = cd->workspace_size * 2; |
609 |
|
|
610 |
|
if (newsize > COMPILE_WORK_SIZE_MAX) newsize = COMPILE_WORK_SIZE_MAX; |
611 |
|
if (cd->workspace_size >= COMPILE_WORK_SIZE_MAX || |
612 |
|
newsize - cd->workspace_size < WORK_SIZE_SAFETY_MARGIN) |
613 |
|
return ERR72; |
614 |
|
|
615 |
|
newspace = (pcre_malloc)(newsize); |
616 |
|
if (newspace == NULL) return ERR21; |
617 |
|
|
618 |
|
memcpy(newspace, cd->start_workspace, cd->workspace_size); |
619 |
|
cd->hwm = (uschar *)newspace + (cd->hwm - cd->start_workspace); |
620 |
|
if (cd->workspace_size > COMPILE_WORK_SIZE) |
621 |
|
(pcre_free)((void *)cd->start_workspace); |
622 |
|
cd->start_workspace = newspace; |
623 |
|
cd->workspace_size = newsize; |
624 |
|
return 0; |
625 |
|
} |
626 |
|
|
627 |
|
|
628 |
|
|
629 |
|
/************************************************* |
630 |
* Check for counted repeat * |
* Check for counted repeat * |
631 |
*************************************************/ |
*************************************************/ |
632 |
|
|
3377 |
#ifdef PCRE_DEBUG |
#ifdef PCRE_DEBUG |
3378 |
if (code > cd->hwm) cd->hwm = code; /* High water info */ |
if (code > cd->hwm) cd->hwm = code; /* High water info */ |
3379 |
#endif |
#endif |
3380 |
if (code > cd->start_workspace + WORK_SIZE_CHECK) /* Check for overrun */ |
if (code > cd->start_workspace + cd->workspace_size - |
3381 |
|
WORK_SIZE_SAFETY_MARGIN) /* Check for overrun */ |
3382 |
{ |
{ |
3383 |
*errorcodeptr = ERR52; |
*errorcodeptr = ERR52; |
3384 |
goto FAILED; |
goto FAILED; |
3428 |
/* In the real compile phase, just check the workspace used by the forward |
/* In the real compile phase, just check the workspace used by the forward |
3429 |
reference list. */ |
reference list. */ |
3430 |
|
|
3431 |
else if (cd->hwm > cd->start_workspace + WORK_SIZE_CHECK) |
else if (cd->hwm > cd->start_workspace + cd->workspace_size - |
3432 |
|
WORK_SIZE_SAFETY_MARGIN) |
3433 |
{ |
{ |
3434 |
*errorcodeptr = ERR52; |
*errorcodeptr = ERR52; |
3435 |
goto FAILED; |
goto FAILED; |
4932 |
} |
} |
4933 |
|
|
4934 |
/* This is compiling for real. If there is a set first byte for |
/* This is compiling for real. If there is a set first byte for |
4935 |
the group, and we have not yet set a "required byte", set it. */ |
the group, and we have not yet set a "required byte", set it. Make |
4936 |
|
sure there is enough workspace for copying forward references before |
4937 |
|
doing the copy. */ |
4938 |
|
|
4939 |
else |
else |
4940 |
{ |
{ |
4941 |
if (groupsetfirstbyte && reqbyte < 0) reqbyte = firstbyte; |
if (groupsetfirstbyte && reqbyte < 0) reqbyte = firstbyte; |
4942 |
|
|
4943 |
for (i = 1; i < repeat_min; i++) |
for (i = 1; i < repeat_min; i++) |
4944 |
{ |
{ |
4945 |
uschar *hc; |
uschar *hc; |
4946 |
uschar *this_hwm = cd->hwm; |
uschar *this_hwm = cd->hwm; |
4947 |
memcpy(code, previous, len); |
memcpy(code, previous, len); |
4948 |
|
|
4949 |
|
while (cd->hwm > cd->start_workspace + cd->workspace_size - |
4950 |
|
WORK_SIZE_SAFETY_MARGIN - (this_hwm - save_hwm)) |
4951 |
|
{ |
4952 |
|
int save_offset = save_hwm - cd->start_workspace; |
4953 |
|
int this_offset = this_hwm - cd->start_workspace; |
4954 |
|
*errorcodeptr = expand_workspace(cd); |
4955 |
|
if (*errorcodeptr != 0) goto FAILED; |
4956 |
|
save_hwm = (uschar *)cd->start_workspace + save_offset; |
4957 |
|
this_hwm = (uschar *)cd->start_workspace + this_offset; |
4958 |
|
} |
4959 |
|
|
4960 |
for (hc = save_hwm; hc < this_hwm; hc += LINK_SIZE) |
for (hc = save_hwm; hc < this_hwm; hc += LINK_SIZE) |
4961 |
{ |
{ |
|
if (cd->hwm >= cd->start_workspace + WORK_SIZE_CHECK) |
|
|
{ |
|
|
*errorcodeptr = ERR72; |
|
|
goto FAILED; |
|
|
} |
|
4962 |
PUT(cd->hwm, 0, GET(hc, 0) + len); |
PUT(cd->hwm, 0, GET(hc, 0) + len); |
4963 |
cd->hwm += LINK_SIZE; |
cd->hwm += LINK_SIZE; |
4964 |
} |
} |
5024 |
} |
} |
5025 |
|
|
5026 |
memcpy(code, previous, len); |
memcpy(code, previous, len); |
5027 |
|
|
5028 |
|
/* Ensure there is enough workspace for forward references before |
5029 |
|
copying them. */ |
5030 |
|
|
5031 |
|
while (cd->hwm > cd->start_workspace + cd->workspace_size - |
5032 |
|
WORK_SIZE_SAFETY_MARGIN - (this_hwm - save_hwm)) |
5033 |
|
{ |
5034 |
|
int save_offset = save_hwm - cd->start_workspace; |
5035 |
|
int this_offset = this_hwm - cd->start_workspace; |
5036 |
|
*errorcodeptr = expand_workspace(cd); |
5037 |
|
if (*errorcodeptr != 0) goto FAILED; |
5038 |
|
save_hwm = (uschar *)cd->start_workspace + save_offset; |
5039 |
|
this_hwm = (uschar *)cd->start_workspace + this_offset; |
5040 |
|
} |
5041 |
|
|
5042 |
for (hc = save_hwm; hc < this_hwm; hc += LINK_SIZE) |
for (hc = save_hwm; hc < this_hwm; hc += LINK_SIZE) |
5043 |
{ |
{ |
|
if (cd->hwm >= cd->start_workspace + WORK_SIZE_CHECK) |
|
|
{ |
|
|
*errorcodeptr = ERR72; |
|
|
goto FAILED; |
|
|
} |
|
5044 |
PUT(cd->hwm, 0, GET(hc, 0) + len + ((i != 0)? 2+LINK_SIZE : 1)); |
PUT(cd->hwm, 0, GET(hc, 0) + len + ((i != 0)? 2+LINK_SIZE : 1)); |
5045 |
cd->hwm += LINK_SIZE; |
cd->hwm += LINK_SIZE; |
5046 |
} |
} |
6058 |
of the group. Then remember the forward reference. */ |
of the group. Then remember the forward reference. */ |
6059 |
|
|
6060 |
called = cd->start_code + recno; |
called = cd->start_code + recno; |
6061 |
if (cd->hwm >= cd->start_workspace + WORK_SIZE_CHECK) |
if (cd->hwm >= cd->start_workspace + cd->workspace_size - |
6062 |
|
WORK_SIZE_SAFETY_MARGIN) |
6063 |
{ |
{ |
6064 |
*errorcodeptr = ERR72; |
*errorcodeptr = expand_workspace(cd); |
6065 |
goto FAILED; |
if (*errorcodeptr != 0) goto FAILED; |
6066 |
} |
} |
6067 |
PUTINC(cd->hwm, 0, (int)(code + 1 - cd->start_code)); |
PUTINC(cd->hwm, 0, (int)(code + 1 - cd->start_code)); |
6068 |
} |
} |
7314 |
computing the amount of memory that is needed. Compiled items are thrown away |
computing the amount of memory that is needed. Compiled items are thrown away |
7315 |
as soon as possible, so that a fairly large buffer should be sufficient for |
as soon as possible, so that a fairly large buffer should be sufficient for |
7316 |
this purpose. The same space is used in the second phase for remembering where |
this purpose. The same space is used in the second phase for remembering where |
7317 |
to fill in forward references to subpatterns. */ |
to fill in forward references to subpatterns. That may overflow, in which case |
7318 |
|
new memory is obtained from malloc(). */ |
7319 |
|
|
7320 |
uschar cworkspace[COMPILE_WORK_SIZE]; |
uschar cworkspace[COMPILE_WORK_SIZE]; |
7321 |
|
|
7505 |
cd->names_found = 0; |
cd->names_found = 0; |
7506 |
cd->name_entry_size = 0; |
cd->name_entry_size = 0; |
7507 |
cd->name_table = NULL; |
cd->name_table = NULL; |
|
cd->start_workspace = cworkspace; |
|
7508 |
cd->start_code = cworkspace; |
cd->start_code = cworkspace; |
7509 |
cd->hwm = cworkspace; |
cd->hwm = cworkspace; |
7510 |
|
cd->start_workspace = cworkspace; |
7511 |
|
cd->workspace_size = COMPILE_WORK_SIZE; |
7512 |
cd->start_pattern = (const uschar *)pattern; |
cd->start_pattern = (const uschar *)pattern; |
7513 |
cd->end_pattern = (const uschar *)(pattern + strlen(pattern)); |
cd->end_pattern = (const uschar *)(pattern + strlen(pattern)); |
7514 |
cd->req_varyopt = 0; |
cd->req_varyopt = 0; |
7586 |
cd->name_table = (uschar *)re + re->name_table_offset; |
cd->name_table = (uschar *)re + re->name_table_offset; |
7587 |
codestart = cd->name_table + re->name_entry_size * re->name_count; |
codestart = cd->name_table + re->name_entry_size * re->name_count; |
7588 |
cd->start_code = codestart; |
cd->start_code = codestart; |
7589 |
cd->hwm = cworkspace; |
cd->hwm = (uschar *)(cd->start_workspace); |
7590 |
cd->req_varyopt = 0; |
cd->req_varyopt = 0; |
7591 |
cd->had_accept = FALSE; |
cd->had_accept = FALSE; |
7592 |
cd->check_lookbehind = FALSE; |
cd->check_lookbehind = FALSE; |
7620 |
if (code - codestart > length) errorcode = ERR23; |
if (code - codestart > length) errorcode = ERR23; |
7621 |
#endif |
#endif |
7622 |
|
|
7623 |
/* Fill in any forward references that are required. */ |
/* Fill in any forward references that are required. There may be repeated |
7624 |
|
references; optimize for them, as searching a large regex takes time. */ |
7625 |
|
|
7626 |
while (errorcode == 0 && cd->hwm > cworkspace) |
if (cd->hwm > cd->start_workspace) |
7627 |
{ |
{ |
7628 |
int offset, recno; |
int prev_recno = -1; |
7629 |
const uschar *groupptr; |
const uschar *groupptr = NULL; |
7630 |
cd->hwm -= LINK_SIZE; |
while (errorcode == 0 && cd->hwm > cd->start_workspace) |
7631 |
offset = GET(cd->hwm, 0); |
{ |
7632 |
recno = GET(codestart, offset); |
int offset, recno; |
7633 |
groupptr = _pcre_find_bracket(codestart, utf8, recno); |
cd->hwm -= LINK_SIZE; |
7634 |
if (groupptr == NULL) errorcode = ERR53; |
offset = GET(cd->hwm, 0); |
7635 |
else PUT(((uschar *)codestart), offset, (int)(groupptr - codestart)); |
recno = GET(codestart, offset); |
7636 |
} |
if (recno != prev_recno) |
7637 |
|
{ |
7638 |
|
groupptr = _pcre_find_bracket(codestart, utf8, recno); |
7639 |
|
prev_recno = recno; |
7640 |
|
} |
7641 |
|
if (groupptr == NULL) errorcode = ERR53; |
7642 |
|
else PUT(((uschar *)codestart), offset, (int)(groupptr - codestart)); |
7643 |
|
} |
7644 |
|
} |
7645 |
|
|
7646 |
|
/* If the workspace had to be expanded, free the new memory. */ |
7647 |
|
|
7648 |
|
if (cd->workspace_size > COMPILE_WORK_SIZE) |
7649 |
|
(pcre_free)((void *)cd->start_workspace); |
7650 |
|
|
7651 |
/* Give an error if there's back reference to a non-existent capturing |
/* Give an error if there's back reference to a non-existent capturing |
7652 |
subpattern. */ |
subpattern. */ |