Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CRM-19013 - Smarty - Do not truncate compiled templates #158

Closed
wants to merge 1 commit into from

Conversation

mfb
Copy link
Contributor

@mfb mfb commented Jun 27, 2016

Truncating a compiled template leads to concurrency issues if another process is including the same file. See also CRM-11189 for a description of the "bus error" encountered when one of the concurrent processes dies.


@@ -1543,7 +1543,8 @@ function validateCompilePath( $compilePath ) {
}

$isValid = false;
if ( $fd = @fopen( $compilePath, 'wb') ) {
// Open file for writing but do not truncate.
if ( $fd = @fopen( $compilePath, 'c') ) {
$isValid = true;
@fclose( $fd );
@unlink($compilePath);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't an issue with your patch, but a surprising observation about this section of code -- it looks like validateCompilePath() ("do check can smarty create a file w/ given path" [sic]) would effectively disable caching. If I'm reading correctly, every call to Smarty::fetch() calls Smarty::_get_compile_path(); as long as the resource uses string: notation, it will then call Smarty::validateCompilePath() which then @fopens and @unlinks the file... which means that cache file is always deleted before you get a chance to use it.

(Hrm... this whole scenario for caching string: seems overwrought... as in... it's not sure what to name the cache-file, so it does @fopen+@fclose+@unlink to see if the filename produces a syntax error; and if there is an error, then it makes a uniqueish-but-not-reusable name with time()+rand(). Wouldn't it be simpler to have a more robust naming pattern like $this->compile_dir . sha1($resource_name) . '.php'?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That does sound more robust (I have no idea why it works this way :) Oh and the other weird thing here is that it opens the file for writing. And for a short period of time this compiled template is now on disk, completely empty, if it didn't already exist. That's not safe for concurrent processes either. For reference this was added in https://issues.civicrm.org/jira/browse/CRM-5890

Copy link
Contributor Author

@mfb mfb Jun 28, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like even if you remove these lines, templates are still recompiled (at least for mailings), because $smarty->compile_check is enabled.

@tttp
Copy link

tttp commented Mar 7, 2017

Oh my,
I've hit that bug too (php 7).
So it's a huge pile of weird, from how the template file names are managed to "why are we even using that for civimail?"

The problem I have needs to run two cronjobs (needed if you want to have meaningful AB tests), but, for some reasons, it does not happen if the mailings are small (ie. it needs to run long enough)

So beside code review, not sure how to reliably test. Any suggestion?

I'm thinking of either going the custom cache road http://www.smarty.net/docs/en/caching.custom.tpl (so we can see better what is happening... or skip the caching altogether for civimail)

... or consider it fubar and jump into flexmail.

@totten
Copy link
Member

totten commented Mar 9, 2017

...not sure how to reliably test...

This.

I think if a couple folks like @mfb and @tttp have been using it in production for a while, then that's the best we can really do. Have you guys been using it?

@tttp
Copy link

tttp commented May 8, 2017

Yes we have been using it since a month ago in production, and sent 5M emails since the change.

@totten on our side: does work
@mfb did you try it?

@mfb
Copy link
Contributor Author

mfb commented May 8, 2017

Yes we have to use this in production, otherwise we get the dreaded "bus error" and the process dies. This resolves that issue, but occasionally (haven't checked stats, but it's rare) an individual mailing message is empty and CiviCRM therefore won't send it - this is a related concurrency issue due to template files being deleted and empty template files being created by multiple processes sharing the same templates.

@mfb
Copy link
Contributor Author

mfb commented Jun 15, 2017

...This wasn't getting any traction, so I tried reworking it into something more robust: Using SHA-256 hash as the filename (rather than CRC-32 plus the string itself, which could be too long to be a valid filename, thus the weird creating and unlinking of compiled templates).

@seamuslee001
Copy link
Contributor

hmm I certainly haven't hit this before @totten This makes sense i think to me Tim, its also evident its in production in 2 separate sites and no errors found I think it should be merged on the basis of probabilities that its an improvement

@mfb
Copy link
Contributor Author

mfb commented Jun 21, 2017

The current version of this PR might only be in use on one site, since I completely rewrote it a week ago. Would be great to get a bit more testing. Maybe it's possible to run the test suite on a civicrm-packages PR?

@seamuslee001
Copy link
Contributor

@mfb i have just checked it out onto a local buildkit build of master and now going to try and run the unit tests on it locally. tho @totten maybe able to get it to run on Jenkins

@seamuslee001
Copy link
Contributor

@mfb i have just kicked off a Jenkins run based on this PR

@seamuslee001
Copy link
Contributor

@totten @mfb unit tests passed on pr-158-1

@mfb
Copy link
Contributor Author

mfb commented Jun 22, 2017

great! I can't think of a possible regression since the code is mostly just simplified, but if there are any more volunteers willing to test that couldn't hurt..

@mfb
Copy link
Contributor Author

mfb commented Jul 14, 2017

We've been using this in production so I think it's ready to be scheduled for next release.

@seamuslee001
Copy link
Contributor

@totten I would be a +1 on merging this, it has passed unit tests and appears to have been in production in one environment at least so i think it would be fairly stable

@mfb
Copy link
Contributor Author

mfb commented Jul 29, 2017

I was looking at how Smarty generates keys for cached templates these days - looks like it uses sha1. However that was implemented some time ago, and given the SHAttered attack and general migration from sha1, sha256 seems reasonable to me.

@xurizaemon
Copy link
Member

Would SHA1 vs SHA256 make any difference? AFAICT we only use a small chunk of the hash anyway and they need to be predictable for use as a cache key. If we're seeing duplicate attempts to open the same file simultaneously, it's not the hash that's at fault MO.

(Not 100% but at a glance it seems like Smarty is using CRC32?)

I've wondered about speed-testing $smarty->setCompileDir('/dev/null'); against compile to disk, and I believe there is functionality or patches around to put templates_c in Redis etc. (Should also nicely address things like CRM-15632.)

@mfb
Copy link
Contributor Author

mfb commented Jul 30, 2017

I used sha256 given that sha1 is generally deprecated (Twig and Drupal 8 for example use sha256)

@seamuslee001
Copy link
Contributor

Jenkins test this please

@mfb
Copy link
Contributor Author

mfb commented Nov 20, 2017

We decided to disable CIVICRM_MAIL_SMARTY - doing so works around most instances of this bug (unless your site is really busy, I guess). I wasn't planning to keep maintaining this PR since it's not critical for our instance, but this code is still "wrong" and should be fixed.. :)

@mfb
Copy link
Contributor Author

mfb commented Aug 13, 2019

EFF folks are interested in re-enabling Smarty so that they can add more complex logic to email templates. So there's a good chance I may resume work on this PR.

@tttp
Copy link

tttp commented Aug 13, 2019 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
7 participants