Opened 8 years ago
Last modified 8 years ago
#40685 new defect (bug)
/wp-includes/class-wp-hook.php function resort_active_iterations not working correct
Reported by: | tim2017 | 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
iterations
to 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 initerations
then 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 theiterations
array 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, soiterations
is 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.