menu_execute_active_handler() is smart enough to rebuild the menus if the menu_mask variable isn't already set due to some race condition.
// Rebuild if we know it's needed, or if the menu masks are missing which
// occurs rarely, likely due to a race condition of multiple rebuilds.
if (variable_get('menu_rebuild_needed', FALSE) || !variable_get('menu_masks', array())) {
menu_rebuild();
}
However, earlier in the page generation process we might have already died from the call chain
drupal_bootstrap(DRUPAL_BOOTSTRAP_FULL);
=> _drupal_bootstrap_full();
=> menu_set_custom_theme();
=> menu_get_custom_theme(TRUE);
=> menu_get_item();
This throws errors like
PDOException: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ')) ORDER BY fit DESC LIMIT 0, 1' at line 2: SELECT menu_router.* FROM {menu_router} menu_router WHERE (path IN ()) ORDER BY fit DESC LIMIT 0, 1; Array ( ) in menu_get_item() (line 404 of C:\wamp\www\drupal7\includes\menu.inc).
(as seen in #619542: Malformed theme .info files break menu_router generation from a different cause).
Comments
Comment #1
bfroehle commentedThe solution is likely to be adding something like
in the appropriate place which may be immediately before the
menu_get_item()call inmenu_get_custom_theme(), or perhaps inmenu_get_ancestors()(which is the only function that actually uses the 'menu_masks' variable).Comment #2
quartsize commentedIssues for historical perspective: #261148: menu_masks variable is empty (race condition) and #202955: Access denied after install - menu_rebuild() calls.
My inclination is toward menu_get_ancestors(), since this issue has has the potential to manifest itself in any situation where menu_get_ancestors() is called, either directly, as it is a public function, or via menu_get_item(), and the menu needs (re)built (see also #1069922: Boost installation fails when using installation profile to install). Moreover, as witnessed by menu_get_item(), callers do not seem to expect an empty array as a possible return value from menu_get_ancestors() (menu_get_item() will generate an invalid SQL query). The trouble with doing that is that menu_get_ancestors() may be called indirectly by menu_rebuild() itself, causing an infinite loop, and if stale data is okay in some situations, it's a waste of cycles.
I have a patch which tries to avoid the former by checking for the lock. I don't like it because I really want to know if menu_rebuild() is higher in the call stack, not if it's running in another thread, but in the interest of helping this issue along, I'm attaching it.
Comment #4
sunLacking clear steps to reproduce this issue, this is a task.
Comment #5
quartsize commentedsites/all/modules.dependencies[] = repro1026474toprofiles/minimal/minimal.info.when Drupal goes to enable
repro1026474.The Minimal profile is used because the Standard includes
menuas dependency, the first action of which when enabling is to callmenu_rebuild(). The fundamental issue is that it is possible formenu_get_item()to be called before themenu_masksare built, butmenu_get_item()assumes, viamenu_get_ancestors(), that the masks are not in need of building any time it is called.Comment #6
sunTo safe others from the hazzle of downloading and extracting, here's the actual and only code of that module:
Comment #7
catchThis is a duplicate of #898634: install_drupal(): call to install_display_output() results in SQL syntax error.