I encountered a bug caused by menu_get_active_breadcrumb in D6.
This is what I found (after digging in the code):
- menu_get_active_breadcrumb calls menu_get_active_trail
- some items don't have access, and so _menu_item_localize is not called, resulting in the item having no ['localized_options']
- the l() function is called with NULL for its $options argument, resulting in an error.

I don't even have breadcrumbs activated on my site, but it is called nevertheless.

Relevant stack trace / tree:

drupal_access_denied
  theme
    call_user_func_array
      template_preprocess_page
        drupal_get_breadcrumb
          menu_get_active_breadcrumb
          . menu_get_active_trail
          .   menu_set_active_trail
          .     menu_get_item
          .       _menu_translate
          .         // _menu_item_localize not called, because item has no ['access']
          .         // effect: no ['localized_options']
          . // $active_trail contains items without ['localized_options']
          . l
          .   // error, because $options is not an array

This bug seems to show up very rarely (didn't find any other issues).
However, I think it is a typical example of non-robust code, which does not check if variables what they are supposed to be.
So, even if you can't reproduce the error, would be good to have a look into the code and see if some sanity checks should be added here and there.

Some info that could help:
- I use the 'me' aliases module. I didn't get the error without this module (or maybe I just didn't check).
- I run PHP 5.3 (with a few patches to get around the errors)
- The path was user/1 (but user/2 will do as well)

I will update this issue when I have more info.

Comments

donquixote’s picture

I should clarify my stack trace diagram.

drupal_access_denied
  theme
    call_user_func_array
      template_preprocess_page
        drupal_get_breadcrumb
          menu_get_active_breadcrumb()
          . menu_get_active_trail()
          .   menu_set_active_trail(NULL)
          .     menu_get_item(NULL, NULL)
          .       _menu_translate($router_item, $original_map, FALSE)
          .         // _menu_item_localize not called, because item has no ['access']
          .         // effect: no ['localized_options']
          . // $active_trail contains items without ['localized_options']
          . l
          .   // error, because $options is not an array

----------

Furthermore, I found that the problem can be fixed by changing the 403 (access denied) page. I had this page set to "user", with the intention to show a login box (which does work on some other pages). I changed it to user/login, now it works.

I'm not sure if this is a sufficient solution, or if it needs further investigation.

sbozhko’s picture

Have the same issue with custom 403 page.

After some investigation, here is what i've found:

Function _menu_translate calls _menu_item_localize which adds "localized_options" element to array only if user has access to this menu item.

In my case, user don't have access to it (as i am trying to display 403 page). Therefore this element is NULL, and l() throws an error.

sbozhko’s picture

Version: 6.x-dev » 6.14
Priority: Normal » Critical
Anonymous’s picture

I had this issue once in combination with Search404 and Page Title module.

The problem was, that the menu_get_active_breadcrumb() eventually called an l() function with an nulled $options. Leading to a crash in common.inc, because $options (localized_options) must be an array.

function l($text, $path, $options = array()) {
  global $language;

  // Merge in defaults.
  $options += array(
      'attributes' => array(),
      'html' => FALSE,
    );

The $options was set and empty, but was not an array. So common.inc crashed in the l() function called by a menu_get_breadcrumb.

Indeed somewhere a check for $options is missing. It should also check if $options is really an array or an empty string.

pepe84’s picture

I fix a similar bug redirecting to "Not found" page using hook_menu_alter:

/**
 * Implementation of hook_menu_alter()
 *
 * @param array $items
 */
function mymodule_menu_alter(&$items) {
    if (isset($items['user/%user_uid_optional'])) {
        // Hack to avoid discovering user nicknames...
        $items['user/%user_uid_optional']['access callback'] = TRUE;
        $items['user/%user_uid_optional']['page callback'] = 'mymodule_user_view';
        if (isset($items['user/%user_uid_optional']['file'])) {
            unset($items['user/%user_uid_optional']['file']);
        }
    }
}

/**
 * Anyone can check if an user exists using profile path (users/{nickname})
 * even if you disable "access user profile" permission:
 * - If exists and has no permission redirects to drupal_access_denied()
 * - If not exists redirects to drupal_not_found()
 * The solution is redirecting both to drupal_not_found() so there is no way
 * to differentiate each case.
 */
function mymodule_user_view($account) {
    if (user_view_access($account)) {
        // Drupal core
        require_once drupal_get_path('module', 'user') . '/user.pages.inc';
        return user_view($account);
    } else {
        // Not found page
        drupal_not_found();
    }
}
ttkaminski’s picture

Version: 6.14 » 6.22
Status: Active » Needs review
StatusFileSize
new654 bytes

Please see #899508-19: l() function - Unsupported operand types in common.inc for a description of the problem. It turns out to be, in my option, a bug in drupal due to an optimization within drupal core. I posted a patch, attached here again for convenience. Hopefully the patch will not break anything so please review and hopefully we can get it into the core.

Status: Needs review » Needs work

The last submitted patch, localized_options_menu.patch, failed testing.

ttkaminski’s picture

Status: Needs work » Needs review
StatusFileSize
new755 bytes

Resubmitted after generating patch using git diff against drupal 6.22

David_Rothstein’s picture

Title: menu_get_active_breadcrumb does not check if items have ['localized_options'] » Occasional fatal error on custom 403 pages due to missing menu item 'localized_options' when generating breadcrumbs
Priority: Critical » Major

Not sure, but I think this may be the same issue as #918356: WSOD when drupal_get_title called during hook_init and custom 403 or 404 pages are being used and therefore fixed by the patch there (at least for D7 and D8)?

Looking at the patch here, I don't think it makes sense to pretend that a menu item is localized when it's not... If it hasn't been localized, then the title hasn't been translated/etc, so it doesn't make any sense to try to generate a link to it. I think we need a fix that comes closer to addressing the root cause and avoids trying to generate such a link in the first place.

kenorb’s picture

I've the same fatal error at /users/admin.
I'm using me module as well.
The patch fix the problem.

Index: menu.inc
===================================================================
--- menu.inc	(revision 252)
+++ menu.inc	(working copy)
@@ -578,6 +578,7 @@
   }
   $router_item['href'] = implode('/', $link_map);
   $router_item['options'] = array();
+  $router_item['localized_options'] = array();
   _menu_check_access($router_item, $map);
   
   // For performance, don't localize an item the user can't access.
kenorb’s picture

Status: Needs review » Reviewed & tested by the community
David_Rothstein’s picture

Status: Reviewed & tested by the community » Needs work

Needs work and further investigation, per #9.

q2_faith’s picture

#10 works for me(D7)

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.