I'm working on a large website and am often getting this warning:

Warning: preg_match(): Compilation failed: regular expression is too large at offset 39102 in drupal_match_path() (row 331 of includes/path.inc).

This is caused by the memory limit that is imposed on regexes by the pcre.backtrack_limit setting in php.ini. By default this is set to 1MB, and if this limit is exceeded while the regex is being processed, the warning is given and the function returns FALSE. Apart from the warning this causes unexpected behaviour since the paths are not being matched correctly.

A good solution would be to split large regexes into smaller chunks so this memory limit is never exceeded.

Comments

pfrenssen’s picture

Status: Active » Needs review
StatusFileSize
new2.76 KB
new1.36 KB

Here is a test that exposes the problem on a vanilla PHP 5.4.6 install, and a patch that fixes the problem.

pfrenssen’s picture

Version: 7.x-dev » 8.x-dev
StatusFileSize
new2.91 KB
new1.48 KB

Drupal 8-versions of the patch and test. These also contain some small improvements to the patch which should be backported to the D7 version above.

domidc’s picture

Status: Needs review » Reviewed & tested by the community

Patch reviewed. Looks good.

catch’s picture

Status: Reviewed & tested by the community » Needs work

I'm not sure why we need to support such a massive string in drupal_match_path(). Could you post the real-life string that this is breaking on?

pfrenssen’s picture

StatusFileSize
new26.33 KB

The test uses a truly gigantic string but this was just to make sure the test fails on the test bot regardless of the settings of pcre.backtrack_limit. In real life I'm seeing this fail on much smaller strings.

I have included an example pattern string that causes my website to break. The site is using Spaces with the PURL module. To be able to show all admin paths in the admin theme all admin paths are duplicated for every Space, and this causes the patterns list to grow dramatically. At first we increased the pcre.backtrack_limit but this is not a sustainable situation as the number of Spaces will continue to grow and we will eventually hit this limit again.

I think drupal_match_path() should always return a valid result, regardless of pattern size and PHP settings.

pfrenssen’s picture

Title: drupal_match_path() fails on large matching patterns with stock PHP settings » drupal_match_path() fails on large matching patterns
Status: Needs work » Needs review

Setting back to needs review, also changing title because this will always break at some point regardless of PHP settings.

catch’s picture

Status: Needs review » Closed (works as designed)

OK thanks for posting the example. I'm afraid I don't think this is a good use-case at all for drupal_match_path(). You could implement hook_block_list_alter() and affect visibility that way without running into the pcre limit. Moving this to 'works as designed'.

pfrenssen’s picture

The admin paths are determined with path_is_admin(), this has not much to do with block visibility settings or hook_block_list_alter().

I think at least that if it is intentional that drupal_match_path() breaks on large patterns that this should be documented.

catch’s picture

So if the use case is to only show a block on path_is_admin(), then it should be entirely possible to add a checkbox to block configuration to only show on admin paths, then in hook_block_list_alter() just check the value of that checkbox vs. path_is_admin() - then you're not copying a vast list of paths into the block visibility.

pfrenssen’s picture

@catch, Sorry I missed you on IRC, I had changed nicks and didn't get your ping.

I'm really not trying to do anything with blocks :) My use case is to show all admin screens (for example /admin/config, /node/add) in the admin theme (Seven). To support this in Spaces and PURL all admin paths need to be prefixed with the names of the Spaces (/space1/admin/config, /space2/admin/config etc) using hook_admin_path(). See issue #1693984: Admin theme is not applied when using path prefix.

I can understand your hesitation though as this is not terribly clean. Maybe I can take a look at how this is handled in the i18n modules since these also deal with path prefixes.

pfrenssen’s picture

Just a followup for people that might hit this error message. The actual problem I was dealing with was that path_is_admin() was being called early in the bootstrap, before hook_init() was invoked. During purl_init() the current path is rewritten to the normal Drupal paths so from this point onwards path_is_admin() would return correct results.

I just had to address this one instance where path_is_admin() is called before hook_init(): in system_custom_theme(), invoked by menu_set_custom_theme(). I implemented my own hook_custom_theme() and the problem was solved.

xmacinfo’s picture

I also get this problem. We have a large site where publishers use block visibility on a lot of paths. Between 31000 and 32000 characters, the visibility will return false without warning.

Any chance we see that 1783704-1-drupal_match_path_memory.patch commited? Or at least reviewed?

ajay gadhavana’s picture

Issue summary: View changes

Same here I have more than 600 URLs in which I wanted to hide particular block but its giving error in dblog
Warning: preg_match(): Compilation failed: regular expression is too large at offset **** in drupal_match_path() (line 331 of /var/www/html/sitename/includes/path.inc) any chance to solve this ?

ajay gadhavana’s picture

Finally I found solution, Might be its not solution but its working fine for me.
When you are adding URLS in block, in backend its matching urls using preg_match so if you are adding lots of URL this is giving error. Solution is instead of adding URL add node id like "node/1212"
Logic is url length is bigger than "node/1231" so its reduce preg_match content

xmacinfo’s picture

This is a good workaround, but we'd still need a better fix.