Opened 16 months ago
Last modified 8 months ago
#59246 new defect (bug)
update_option returns true, even when the value didn't change, potentially adding back old data
Reported by: | malthert | Owned by: | |
---|---|---|---|
Milestone: | Awaiting Review | Priority: | normal |
Severity: | normal | Version: | |
Component: | Options, Meta APIs | Keywords: | has-patch has-unit-tests |
Focuses: | Cc: |
Description
update_option
will inconsistently return true/false, depending on whether another update option call is made in the meantime.
While this isn't a problem per se, it creates inconsistent and unexpected behavior.
`
$a = get_option( 'a' );
$b = get_option( 'b' );
sleep( 5 ); placeholder for code that takes some time
$b = '2';
update_option( 'b', $b );
update_option( 'a', $a ); $a didn't change, so it shouldn't update but return false - but it will update and return true
`
Request 2:
`
$a = get_option( 'a' );
$b = get_option( 'b' );
$a = '7';
$b = '3';
update_option( 'b', $b );
update_option( 'a', $a );
`
Result:
Option 'a' will have a value of 1 instead of 7.
Why does this happen?
update_option
uses get_option
to get the $old_value - however the $old_value might in fact be a NEW value that was added in the meantime by another request.
This leads to unexpected behavior of update_option
if called with unmodified data - since update_option
sometimes behaves seemingly atomically, while in reality it doesn't - but most devs are not aware of this.
These are extremely hard to track down bugs for most developers.
Possible solution(s):
- ignore this issue, and improve documentation to make it clear that
update_option
might update an option even if the value didn't change - if the option was modified in the meantime - add an additional parameter to
update_option
for$old_value
to have people pass it in for comparison
Change History (4)
This ticket was mentioned in PR #6057 on WordPress/wordpress-develop by @kkmuffme.
10 months ago
#1
- Keywords has-patch has-unit-tests added
We encountered this issue also within the same request in cases where an apply filters/do action callback modified an option value, which it turned out is an extremely common issue and requires manual mitigation at the moment.
Simple reproduction case:
I created a PR that adds a 4th optional argument as well as a specific function for update_option to require the old value for atomic updates.