I posted about this to the devel list:
http://lists.drupal.org/pipermail/development/2006-September/019956.html
To summarize, under PHP5 the node object returned from node_load may not the
same during all stages of the page view. I'd attribute this to PHP 5's behavior where all objects are passed by reference. Assuming the behavior under PHP4 is the correct/desired behavior, then a solution seems to be to use drupal_clone in node_load to insure we preserve a pristine copy of the node object.
patch attached for Drupal 5.0 (HEAD), same patch to follow for 4.7.
for those who want to see the effect of the patch, here's a simple test. Create a node with a short body (e.g. "hello world!"). Find the nid. Create another node using PHP mode and put in the code below, substituting your nid for 12:
for ($i=1; $i < 5; $i++) {
$anode = node_load(12);
$anode->body .= " $i";
print $anode->body. "<br>";
}
on a an unpatched site under PHP5, the output will be:
hello word! 1
hello word! 1 2
hello word! 1 2 3
hello word! 1 2 3 4
on a site under PHP4 or with the patch, the output will be:
hello word! 1
hello word! 2
hello word! 3
hello word! 4
Comment | File | Size | Author |
---|---|---|---|
#17 | node_load_php5_fix2_5x-dev.txt | 1.02 KB | pwolanin |
#15 | drupal_node_load_warnings.patch.txt | 763 bytes | fago |
#14 | node_load_php5_fix2_47.txt | 769 bytes | pwolanin |
#1 | node_load_php5_fix1_47.diff.txt | 825 bytes | pwolanin |
node_load_php5_fix1.diff.txt | 824 bytes | pwolanin |
Comments
Comment #1
pwolanin CreditAttribution: pwolanin commentedpatch for 4.7
Comment #2
pwolanin CreditAttribution: pwolanin commentedI marked http://drupal.org/node/88503 as a duplicate of this issue
Comment #3
Arto CreditAttribution: Arto commented+1 as this seems to me, after some consideration, exactly the correct way to fix the issue on PHP5, and it doesn't have a negative impact on PHP4, either.
BTW, for anyone needing a refresher on PHP5 object references and the history of the
drupal_clone()
function, read Steven's 2004 writeup at http://www.acko.net/node/54.Comment #4
Arto CreditAttribution: Arto commentedVerified that both the 4.7 and 5.0 patches still apply cleanly against the respective CVS versions, so marking this as ready to be committed.
Comment #5
Dries CreditAttribution: Dries commentedAren't we cloning too much now? How about we clone when we take the node out of the cache? Looks like with this patch, we clone then node before we put it in the cache, and just before we take it out of the cache. I might be mistaken though.
Comment #6
pwolanin CreditAttribution: pwolanin commented@Dries- Yes, I really think you have to do both- otherwise, the the copy in the cache may be altered via the reference intially returned by node_load.
Comment #7
pwolanin CreditAttribution: pwolanin commentedFYI, if you leave off the 2nd drupal_clone at line 510, the output of the script above is:
If you leave off the 1st drupal_clone at line 469 the output is:
of course, you could put the 2nd drupal_clone at the return at line 513, but then you always incur the function call, rather than only when the node is cachable.
Comment #8
Arto CreditAttribution: Arto commentedDries: as Peter said, both clone calls are definitely necessary. I initially had the same concern but upon further consideration came to realize the patch is exactly right, including the fact that the second clone happens on the conditional case instead of the default case.
I believe this is ready to be committed.
Comment #9
drummCommitted to HEAD.
Comment #10
pwolanin CreditAttribution: pwolanin commentedchanging version to 4.7, RTBC to catch killes' attention
Comment #11
killes@www.drop.org CreditAttribution: killes@www.drop.org commentedapplied
Comment #12
fagoI've just upgraded my 4.7 installations. Now I get some warnings on "node/34" pages, where the nid is not valid!
I'm using php 5.2.0, so drupal_clone uses the clone() function which fails for boolean values (the node object is false!), when node_load() tries to cache the node.
Comment #13
pwolanin CreditAttribution: pwolanin commentedHmmm, I think I see the problem. $cachable may be TRUE, even if $node is NULL. I'm not sure about elsewhere in the core code, but in node_module there check for correctness of the returned object seem to take the form:
if ($node->nid)
ORif ($node->vid)
. This is bad in any case, since they should be using isset(). Some similarly bad code in poll module:if ($node = node_load($nid))
So- 3 possible ways to deal with this off the top of my head.
1) put a check for non-objects in drupal_clone (maybe a bad hack)
2) change node_load further to only clone non-NULL (or is_object) values.
3) change node_load so that calls with an invalid nid/vid result in saving an object with $node->nid == 0, $node->vid == 0.
Sorry for missing this in the original patch.
Comment #14
pwolanin CreditAttribution: pwolanin commentedHere's an attempt at a revised patch- not tested yet (I'm at work and shouldn't be doing this now). Note also the explicit setting of $cachable, for ALL_E compliance.
Comment #15
fagoyour patch fixes the problem!
I assume your patch is for HEAD so I change the version.
Further I've attached your patch for drupal 4.7.
Comment #16
pwolanin CreditAttribution: pwolanin commentedmy patch was for 4.7, but for HEAD would be the same except for an offset and the fact that the module is in a directory.
I'm glad to hear that this patch fixes the problem, but the question still remains whether it's the optimal solution.
Comment #17
pwolanin CreditAttribution: pwolanin commentedHmm, apparently the 4-7-CVS tarball didn't have the fix1 patch from above yet, so actually my patch wasn't good.
Your patch should work for 4.7.x (though next time use the -p flag for diff).
Attached patch is for 5.x
Comment #18
pwolanin CreditAttribution: pwolanin commentedtested patch from #17 with latest update of 5.x-dev on both PHP 5.1.2 and PHP 4.4.1 and seems to work as expected (no surprise). I'm inclined to stick with this approach, since it represents the smallest change.
Comment #19
pwolanin CreditAttribution: pwolanin commentedI think this must be fixed before RC
Comment #20
drummCommitted to HEAD.
Comment #21
pwolanin CreditAttribution: pwolanin commentedneeds to be backported too
Comment #22
pwolanin CreditAttribution: pwolanin commentedComment #23
RobRoy CreditAttribution: RobRoy commentedYeah, just ran across this is 4.7. Good call, changed status to the new "to be ported".
Comment #24
killes@www.drop.org CreditAttribution: killes@www.drop.org commented"to be ported" means to me: The patch should get into 4.7, but it doesn't apply due to soem changes between 4..7 and 5. This patch applied just fine, so "rtbc" would have been better.
applied
Comment #25
(not verified) CreditAttribution: commented