After I have enabled the module and try to select a menu to use for access contol in the settings I recieve the following error. After the error shows up I need to restore from a database backup to restore the site.

Fatal error: Maximum function nesting level of '100' reached, aborting! in /Users/mirzu/Sites/sdge/includes/database/database.inc on line 308

Comments

mirzu’s picture

Status: Active » Fixed

fixed this was due to having xdebug enabled locally and had nothing to do with this module.

Anonymous’s picture

StatusFileSize
new396.05 KB

I have the same issue with the "nesting level of '100' reched" error. But disabling or enabling xdebug has no impact. It occured the first time after I changed some Workbench Access related permission settings.

The error is somewhere in the callstack of the "menu_workbench_access_tree" Function. If I prevent drupal from executing that function the error is gone. (see a screenshot of the callstack attached).

When I'm logged in as user 1, the error doesn't occur.

Anonymous’s picture

Status: Fixed » Active
agentrickard’s picture

Status: Active » Needs review
StatusFileSize
new485 bytes

workbench_access_get_active_tree() should only be called once per page request, unless you are saving data or calling workbench_access_reset_tree().

There is a very dumb typo in the static check.

agentrickard’s picture

Priority: Major » Critical

Bumping to critical. This is rare but showstopping.

Anonymous’s picture

The patch doesn't solve the problem yet.

During the first call $active is null, so isset($active['access_scheme']) is false --> correct so far. Now the second time when the function is executed, $active has the following structure:

$active = array(
  [405] => array(
     'access_id' => ....,
     (...)
     'access_scheme' => ...
  ),
  (...)
);

So isset($active['access_scheme']) is still false. I guess the condition should be something like:

$active = &drupal_static(__FUNCTION__);
  if (!empty($active)) {
    return $active;
  }

That actually works out for me... but I'm not sure if the availability of 'access_scheme' should be explicitly checked.

agentrickard’s picture

StatusFileSize
new1.79 KB

That doesn't make sense to me. $active should never return a numeric keyed array. The structure should be:

$active = array(
  'access_scheme' => array(), // with stuff in the array.
  'tree' => array(), // with stuff in the array.
  'active' => array(), // with stuff in the array.
)

So the question is this:

1) Why is your structure different?
2) Why can I not reproduce that structure?

I wonder if it's because the call is erroring out. That's what it looks like. I can only replicate that data structure if I do this:

/**
 * Load the active tree.
 */
function workbench_access_get_active_tree() {
  $active = &drupal_static(__FUNCTION__);
  if (isset($active['access_scheme'])) {
    return $active;
  }
  $scheme = variable_get('workbench_access', 'taxonomy');
  workbench_access_load_include($scheme);
  $func = $scheme . '_workbench_access_info';
  $info = $func();
  $data = $info[$scheme];
  $active = workbench_access_get_ids_by_scheme($data);
 /* $tree = workbench_access_tree($data);
  workbench_access_build_tree($tree);
  $active = array(
    'access_scheme' => $data,
    'tree' => $tree,
    'active' => $active,
  );*/
  return $active;
}

There may be an issue with the re-assignment of the $active variable, so let's try changing that.

Tests pass for this patch, so if it fails fo you, we really need to dig in to what's wrong with your install.

Anonymous’s picture

StatusFileSize
new110.33 KB

What I found out is that the numeric keyed array for $active is only returned as anonymous user. As soon as I log in as user 1, the array has the structure as you are expecting it.

Renaming the variable from $active to $access_tree didn't help.

I use the module for a prototype so my drupal installation is quite clean --> only workbench and modules like panels or views are installed.

The error happened the first time, when I manipulated the permissions for the workbench module (right after saving). You find the permissions I've set in the attachment. Maybe you can reproduce it with that.

agentrickard’s picture

Thanks!

agentrickard’s picture

Status: Needs review » Needs work
agentrickard’s picture

Nope. Cannot replicate. I wonder if it has to do with how Panels is calling the page.

Your original stack trace looked like a Panels page call. Does it occur on all pages or just Panels pages?

Can you export and attach the panels page?

agentrickard’s picture

Status: Needs work » Postponed (maintainer needs more info)

Needs more info, actually, since I cannot replicate without hacking the code.

agentrickard’s picture

I'm going to commit the obvious fix. Then we can dig into your issue.

Anonymous’s picture

Ok, I tried to replicate the problem on a clean new drupal 7.4 installation with the latest versions of panels, views, workbench, workbench access, etc...!

The error did not occur (not with panel pages, not with contexts or anything ...). So I think we mark this as fixed until someone else has a similar problem and is able to replicate it.

Thanks for your help!!

agentrickard’s picture

Status: Postponed (maintainer needs more info) » Fixed

Sure. We did find a nasty and dumb bug!

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.

jhedstrom’s picture

Status: Postponed (maintainer needs more info) » Active
StatusFileSize
new115.31 KB

I'm seeing this on a site running 1.0 (and changing to latest dev doesn't resolve). Attached is relevant portion of the stack trace. Basically, workbench_access_get_active_tree() is recursively calling itself when there is no cache. The issue first started when somebody was saving a node. Specifically, the call to workbench_access_tree() from within workbench_access_get_active_tree() is causing the recursion.

Selection_053.png

agentrickard’s picture

Version: 7.x-1.0-beta6 » 7.x-1.x-dev
Status: Closed (fixed) » Postponed (maintainer needs more info)

Exact steps to replicate, please.

jhedstrom’s picture

I still haven't yet figured out how the system got into this state, but I've traced the issue to calls to workbench_access_tree() from within workbench_access_get_active_tree(). The site is using the menu scheme for access, so this function then calls menu_workbench_access_tree(), which in turn calls menu_tree_all_data(), which calls menu_build_tree(), which then calls back to workbench_access_get_active_tree().

I'll provide more information as I find it.

agentrickard’s picture

What are you doing when this happens?

jhedstrom’s picture

Ok, I've traced this back to an essentially recursive link placed in the menu system.

There was a top-level main menu link to node/11, and another link under that pointing to node/11/1. Removing the latter resolved the issue.

I can reproduce this on a stock D7 site running workbench access by putting such a recursive node link into the main menu.

agentrickard’s picture

Eek. Not sure we can do much about that.

jhedstrom’s picture

Yeah, I don't have any immediate ideas on how to get around that, which is unfortunate since this user-error has the power to take down the entire site, with the only fix being some forensics work and the manual removal of the offending link.

agentrickard’s picture

We might be able to do some checking in _workbench_menu_build_tree() to ensure that we don't load the same data twice. Perhaps something like so?

/**
 * Recursive helper function to build menus.
 *
 * @param &$tree
 *   The workbench access tree being built.
 * @param $link
 *   The menu link being inspected.
 */
function _workbench_access_menu_build_tree(&$tree, $link) {
  $item = (object) $link['link'];
  if (isset($tree[$item->mlid])) {
    return;
  }
  $tree[$item->mlid] = array(
    'access_id' => $item->mlid,
    'access_type_id' => $item->menu_name,
    'name' => $item->link_title,
    'description' => isset($item->options['attributes']['title']) ? $item->options['attributes']['title'] : '',
    'weight' => $item->weight,
    'depth' => $item->depth,
    'parent' => ($item->plid == 0) ? $item->menu_name : $item->plid,
  );
  if (!empty($link['below'])) {
    foreach ($link['below'] as $below) {
      _workbench_access_menu_build_tree($tree, $below);
    }
  }
}

But that shouldn't be the issue, since node/11 and node/11/1 should have different mlids. I don't really see how this loop occurs.

agentrickard’s picture

Does your fatal error call stack ever get to that function?

jhedstrom’s picture

It doesn't appear to ever reach _workbench_access_menu_build_tree().

larowlan’s picture

We experienced this issue and traced it down to an additional trailing / on a menu entry.

mysql> select * from menu_links where substr(link_path, -1, 1) = '/';
+-----------+------+------+----------------------------------+-------------+------------+-------------------------------------------------------------------+--------+--------+----------+--------------+----------+--------+-------+------------+------+------+----+----+----+----+----+----+----+---------+
| menu_name | mlid | plid | link_path                        | router_path | link_title | options                                                           | module | hidden | external | has_children | expanded | weight | depth | customized | p1   | p2   | p3 | p4 | p5 | p6 | p7 | p8 | p9 | updated |
+-----------+------+------+----------------------------------+-------------+------------+-------------------------------------------------------------------+--------+--------+----------+--------------+----------+--------+-------+------------+------+------+----+----+----+----+----+----+----+---------+
| main-menu | 6389 | 6388 | node/586/                        | node/%      | Overview   | a:1:{s:10:"attributes";a:1:{s:5:"title";s:0:"";}}                 | menu   |      0 |        0 |            0 |        0 |    -50 |     2 |          1 | 6388 | 6389 |  0 |  0 |  0 |  0 |  0 |  0 |  0 |       0 |
+-----------+------+------+----------------------------------+-------------+------------+-------------------------------------------------------------------+--------+--------+----------+--------------+----------+--------+-------+------------+------+------+----+----+----+----+----+----+----+---------+
2 rows in set (0.05 sec)

Fixed with:

update menu_links set link_path = 'node/586' where mlid = 6389;
delete from cache_menu;
larowlan’s picture

I can confirm that editing a menu link and adding a / to the end of it causes this issue.

agentrickard’s picture

Well, adding a '/' is user error.

larowlan’s picture

Yes agreed, pity menu system doesn't catch it as an invalid path :(

agentrickard’s picture

You should file (or find) an issue for that. That's a UX fail.

larowlan’s picture

imo it's a feature, not a fail.
I've always used trailing args on menu items to facilitate alternate page tpls.

Eg page-node-lightbox.tpl.php has no sidebars etc.

Then links to /node/3/lightbox load with a different page tpl to /node/3

But I agree, the issue is not with workbench_access

jhedstrom’s picture

But I agree, the issue is not with workbench_access

The problem though is that with just core, the user error can be fixed easily, or ignored. With workbench access enabled, the site fatal errors until the offending path is manually removed from the db.

agentrickard’s picture

I am open to fixing this loophole here, if we can figure out how.

leszek.stachowski’s picture

This is how I manage to reproduce this error:

  1. Enable all workbench* modules.
  2. Create a menu with links to administration pages (for me it was just "node/add") and assign this menu to a block visible for all users (even anonymous).
  3. Enable workbench moderation & access for nodes with menu access scheme (of course now we have to assign some user to some sections, for me - again - it was section linked with menu item with path "node/add").
  4. Access site as anonymous user.
agentrickard’s picture

When I follow those steps and clear the cache, if the first page load comes from an anon user, I am getting a page timeout.

agentrickard’s picture

There is a race condition in menu_workbench_access_tree() that only appears when certain types of items are placed in the menu. If menu_tree_all_data() has not yet primed the cache, we hit an infinite loop.

agentrickard’s picture

Status: Active » Needs review
StatusFileSize
new950 bytes

Tracked it down.

Two changes in this patch, which tests cleanly with both "node/1/" and "node/add" as "bad" menu items.

  • Check to ensure that $name is a valid menu.
  • Use _menu_build_tree() directly, which bypasses access checks and eliminates the mystery errors.

I'm not crazy about using a "private" function, but it seems to be stable.

agentrickard’s picture

I suspect that this works by bypassing the access check in menu_tree_build(). My concern is that we also bypass translation and may need to call _menu_link_translate().

agentrickard’s picture

With menu testing in, this can be reproduced, I believe, by adding 'node/add' into the menu structure test.

The remaining question is whether the solution is proper.

Sean Buscay’s picture

Assigned: Unassigned » Sean Buscay

I have tested the latest patch by first reproducing the error and then applying the patch to fix the error.

The error is fixed correctly.

I confirmed the menu items continue to follow the correct access scheme based on permissions.

I will test the translation issue and then this should be ready to be committed.

agentrickard’s picture

Assigned: Sean Buscay » Unassigned
StatusFileSize
new1.77 KB

Status: Needs review » Needs work

The last submitted patch, 1203260-make-thefail.patch, failed testing.

agentrickard’s picture

Status: Needs work » Needs review
StatusFileSize
new982 bytes

Re-roll of original patch.

agentrickard’s picture

StatusFileSize
new2.73 KB

Interesting. The patch in #42 fails without the patch in #44, and perhaps that is a sufficient test condition.

I am replicating the steps in #35.

This patch, which combines #42 and #44 passes.

So the remaining question is simply: Can we safely call the "private" function here?

agentrickard’s picture

StatusFileSize
new2.79 KB

OK, thanks to @stevector and @Sean Buscay, we were able to replicate this in the test.

agentrickard’s picture

Status: Needs review » Reviewed & tested by the community

Testbot is stalled. This patch is green. Committing.

agentrickard’s picture

Status: Reviewed & tested by the community » Fixed
   7961799..c7e3753  7.x-1.x -> 7.x-1.x

Status: Fixed » Closed (fixed)

Automatically closed -- issue fixed for 2 weeks with no activity.