Opened 9 years ago
Last modified 9 years ago
#40685 new defect (bug)
/wp-includes/class-wp-hook.php function resort_active_iterations not working correct
| Reported by: |
|
Owned by: | |
|---|---|---|---|
| Milestone: | Awaiting Review | Priority: | normal |
| Severity: | normal | Version: | 4.7.4 |
| Component: | General | Keywords: | |
| Focuses: | Cc: |
Description
if you have current priority of 5, whose only hook is cancelling itself (remove_filter) and the new priority list is for example (2,7,12), then this part
while ( current( $iteration ) < $current ) {
if ( false === next( $iteration ) ) {
break;
}
}
sets the current pointer to 7, so the next priority worked on is the 12 in apply_filters function, while it should be 7.
Attachments (1)
Change History (4)
Note: See
TracTickets for help on using
tickets.
Nice bug!
At first I thought it might be possible to fix this by manipulating the internal array pointer of
iterationsto point to the previous element onremove_filter()so that thenext()inapply_filters()would work correctly - but a major flaw with this is that if the filter being removed is the first initerationsthen there's no previous element to go back to! So thenext()inapply_filters()will always skip an element.So just not calling
resort_active_iterations()onremove_filter()seems like a simple way to fix the issue. But this leaves theiterationsarray invalid, so its return needs to be checked before using it inapply_filters(), which affects the performance of the loop. (It might still be a good, more BC solution though.)The approach taken in the attached demo patch is to not call
resort_active_iterations()either, but also to not unset the callback priority entries at all but leave them empty, soiterationsis left pointing at a "zombie" entry, avoiding the need for a check.This has some behavioural issues - for instance to get the full unit tests working required changing some of them to not test for
isset( $hook->callbacks[ $priority ] )but! empty()instead, and also not doassertArrayNotHasKey( 'blah', $wp_filter )buthas_filter( 'blah' )- so it's very much a demo.The patch includes unit tests that fail appropriately.