Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/private/Config/UserConfig.php
Original file line number Diff line number Diff line change
Expand Up @@ -686,7 +686,7 @@ public function getValueBool(
bool $default = false,
bool $lazy = false,
): bool {
$b = strtolower($this->getTypedValue($userId, $app, $key, $default ? 'true' : 'false', $lazy, ValueType::BOOL));
$b = strtolower((string)$this->getTypedValue($userId, $app, $key, $default ? 'true' : 'false', $lazy, ValueType::BOOL));
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I don't get how getTypedValue can return something which is not a string

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Empty string on oracle is null?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

See stack trace in linked issue. It is a string. Php would throw if it is not a string due to strict types.

I suspect a faulty PHP build being used on that machine.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Not Oracle, it's pgsql (as in the issue). The ): string hint is correct in the happy path, but the values returned come directly from $fastCache/$lazyCache, which are populated from PDO row data. The ?? '' in loadConfig guards against null, but doesn't cover all non-string cases that can end up in the cache from other write paths. The specific case here is user_ldap calling getValueBool($uid, 'user_ldap', 'isDeleted') on users who never had that key written, where a type mismatch in the stored metadata is enough to trigger it. PHP 8.4 made strtolower() fatal for non-strings (before that it was a silent deprecation), which is why this is only surfacing now. The stack trace in #59629 is from a stock PHP 8.4 build, reproduced by multiple people.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

  {"file": "lib/private/Config/UserConfig.php", "line": 688, "function": "strtolower", "args": ["false"]},

It gets passed a string, so the error makes no sense.
Also if like you describe a non-string would be returned by getTypedValue, then the error message would be:

TypeError: getTypedValue(): Return value must be of type string, false returned

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The stack trace in #59629 is from a stock PHP 8.4 build, reproduced by multiple people.

Not sure what a "stock php 8.4" is, as every distribution could compile PHP in a different way.
I tried to reproduce this but it simply cannot be reproduced the way it is reported.

Setup: I use PHP 8.4.20

Try 1: Call the getValueBool where no value was ever written to user_ldap. ➡️ works as expected no error.

Try 2: Manipulate the caches to return invalid value ➡️ throws different exception because caches are already used before.

Try 3: Manipulate method to return false ➡️ different error:

OC\Config\UserConfig::getTypedValue(): Return value must be of type string, false returned in file '/var/www/html/lib/private/Config/UserConfig.php' line 745


So maybe just try to update PHP to 8.4.20

return in_array($b, ['1', 'true', 'yes', 'on']);
}

Expand Down