As the title says, user_load(0) gets called on every page when not logged in (clean install). According to this comment by chx, user_load() should not be called with the anonymous user id, so this can be considered a bug.

Adding the PHP5 function debug_print_backtrace() to user_load() gave me this result (arguments trimmed down for readability):

#0  user_load(0) called at [/Users/joakim/Sites/drupal/modules/user/user.module:1112]
#1  user_current_load(0) called at [/Users/joakim/Sites/drupal/includes/menu.inc:405]
#2  _menu_load_objects(...) called at [/Users/joakim/Sites/drupal/includes/menu.inc:630]
#3  _menu_link_translate(...) called at [/Users/joakim/Sites/drupal/includes/menu.inc:942]
#4  _menu_tree_check_access(...) called at [/Users/joakim/Sites/drupal/includes/menu.inc:931]
#5  menu_tree_check_access(...) called at [/Users/joakim/Sites/drupal/includes/menu.inc:887]
#6  menu_tree_page_data(navigation) called at [/Users/joakim/Sites/drupal/includes/menu.inc:686]
#7  menu_tree() called at [/Users/joakim/Sites/drupal/modules/user/user.module:732]
#8  user_block(view, 1) called at [(null):0]
#9  call_user_func_array(user_block, Array ([2] => view,[3] => 1)) called at [/Users/joakim/Sites/drupal/includes/module.inc:450]
#10 module_invoke(user, block, view, 1) called at [/Users/joakim/Sites/drupal/modules/block/block.module:455]
#11 block_list(left) called at [/Users/joakim/Sites/drupal/includes/theme.inc:1515]
#12 theme_blocks(left) called at [(null):0]
#13 call_user_func_array(theme_blocks, Array ([0] => left)) called at [/Users/joakim/Sites/drupal/includes/theme.inc:591]
#14 theme(blocks, left) called at [/Users/joakim/Sites/drupal/includes/theme.inc:1709]
#15 template_preprocess_page(...) called at [(null):0]
#16 call_user_func_array(template_preprocess_page, ...) called at [/Users/joakim/Sites/drupal/includes/theme.inc:632]
#17 theme(page, ...) called at [/Users/joakim/Sites/drupal/index.php:36]

With user.module's blocks disabled (User login and Navigation), menu_tree_page_data(navigation) will still get called from menu_set_active_trail() (arguments trimmed):

#0  user_load(0) called at [/Users/joakim/Sites/drupal/modules/user/user.module:1112]
#1  user_current_load(0) called at [/Users/joakim/Sites/drupal/includes/menu.inc:405]
#2  _menu_load_objects(...) called at [/Users/joakim/Sites/drupal/includes/menu.inc:630]
#3  _menu_link_translate(...) called at [/Users/joakim/Sites/drupal/includes/menu.inc:942]
#4  _menu_tree_check_access(...) called at [/Users/joakim/Sites/drupal/includes/menu.inc:931]
#5  menu_tree_check_access(...) called at [/Users/joakim/Sites/drupal/includes/menu.inc:887]
#6  menu_tree_page_data(navigation) called at [/Users/joakim/Sites/drupal/includes/menu.inc:1449]
#7  menu_set_active_trail() called at [/Users/joakim/Sites/drupal/includes/menu.inc:1481]
#8  menu_get_active_trail() called at [/Users/joakim/Sites/drupal/includes/menu.inc:1491]
#9  menu_get_active_breadcrumb() called at [/Users/joakim/Sites/drupal/includes/common.inc:93]
#10 drupal_get_breadcrumb() called at [/Users/joakim/Sites/drupal/includes/theme.inc:1745]
#11 template_preprocess_page(...) called at [(null):0]
#12 call_user_func_array(template_preprocess_page, ...) called at [/Users/joakim/Sites/drupal/includes/theme.inc:632]
#13 theme(page, ...) called at [/Users/joakim/Sites/drupal/index.php:36]

One quick and easy way to fix this, is to in user_load_current() check if the current uid is 0, and if it is pass the anonymous user object with drupal_anonymous_user() instead of calling user_load(). See attached patch.

And I'm curious, why can't user_load() also deal with the anonymous uid? A simple if clause can return the anonymous user object before any db queries are made. I guess there's a perfectly good reason for this, but I would like to know what it is :)

Comments

ximo’s picture

Assigned: Unassigned » ximo
Status: Postponed (maintainer needs more info) » Needs review
StatusFileSize
new913 bytes

user_load_self() also calls user_load($GLOBALS['user']->uid), which is bad practice considering the user may be anonymous. I've ammended a fix for this to the previous patch..

BTW, the function is never used in core and it's not documented. Leftover from an earlier version?

gábor hojtsy’s picture

Status: Needs review » Needs work

Why not return drupal_anonymous_user() in user load() (which avoid DB requests for user_load()), so all callers are covered?

ximo’s picture

Status: Needs work » Needs review

Duh :) I was hooked up on not using user_load() for anon user, forgot to think about all contrib modules who might be doing it wrong.

isset($array['uid']) is because user_load() is called with no uid during installation.

ximo’s picture

StatusFileSize
new688 bytes

Sorry, I forgot to attach the new patch. Time to take my coffee.

Edit: Seems the file didn't want to upload, not my fault :) Trying again...

killes@www.drop.org’s picture

Title: user_load(0) gets called once every page for anon users » user_current_load and user_load_self should be made more forgiving and be documented.
Status: Needs review » Needs work

The title is no longer true. Actualy, user_current_load is no longer called from any place in core.

I am changing the title.

The patch in #4 should IMO not be applied, we try to not check every argument in a function, we try to educate the caller.

ximo’s picture

StatusFileSize
new571 bytes

According to the backtrace, user_current_load() is called programmatically by _menu_load_objects() in menu.inc (HEAD), so the old title was still valid. See the patch below to review the backtrace on your install. The function will also get called for anonymous users, which as I understand it, shouldn't happen.

I agree with your point on educating the caller though. _menu_load_objects() is the only caller in core AFAIK. And some documentation would be helpful for user_current_load() and user_load_self().

mr.baileys’s picture

In D7, user_load_self has been removed. Even in D6, I don't think there is a genuine need for that function.

Status: Needs work » Closed (outdated)

Automatically closed because Drupal 6 is no longer supported. If the issue verifiably applies to later versions, please reopen with details and update the version.