diff --git a/core/includes/menu.inc b/core/includes/menu.inc
index 0c18a60..2386e29 100644
--- a/core/includes/menu.inc
+++ b/core/includes/menu.inc
@@ -508,7 +508,12 @@ function menu_execute_active_handler($path = NULL, $deliver = TRUE) {
         if ($router_item['include_file']) {
           require_once DRUPAL_ROOT . '/' . $router_item['include_file'];
         }
-        $page_callback_result = call_user_func_array($router_item['page_callback'], $router_item['page_arguments']);
+        if (function_exists($router_item['page_callback'])) {
+          $page_callback_result = call_user_func_array($router_item['page_callback'], $router_item['page_arguments']);
+        }
+        else {
+          $page_callback_result = MENU_NOT_FOUND;
+        }
       }
       else {
         $page_callback_result = MENU_ACCESS_DENIED;
@@ -627,7 +632,10 @@ function _menu_check_access(&$item, $map) {
       $item['access'] = (count($arguments) == 1) ? user_access($arguments[0]) : user_access($arguments[0], $arguments[1]);
     }
     else {
-      $item['access'] = call_user_func_array($callback, $arguments);
+      // If the callback function does not exist, do not set $item['access'] to
+      // TRUE. This prevents giving access to any functionality that is not
+      // explicity allowed by a callback function.
+      $item['access'] = function_exists($callback) ? call_user_func_array($callback, $arguments) : NULL;
     }
   }
 }
diff --git a/core/modules/menu/menu.admin.inc b/core/modules/menu/menu.admin.inc
index 2e1725d..9746433 100644
--- a/core/modules/menu/menu.admin.inc
+++ b/core/modules/menu/menu.admin.inc
@@ -476,6 +476,32 @@ function menu_edit_menu($form, &$form_state, $type, $menu = array()) {
     '#title' => t('Description'),
     '#default_value' => $menu['description'],
   );
+
+  // Add the option to add custom menus to a content type when creating or
+  // updating a menu.
+  if (module_exists('node')) {
+    $node_types = node_type_get_names();
+    $default_value = array();
+    // Ignore the add form case because there are no default values available.
+    if ($type == 'edit') {
+      // When editing a menu we need to collect all the node types that have
+      // this menu enabled.
+      foreach ($node_types as $node_type => $name) {
+        $menu_options = variable_get('menu_options_' . $node_type, array('main-menu'));
+        if (in_array($menu['menu_name'], $menu_options)) {
+          $default_value[] = $node_type;
+        }
+      }
+    }
+    // Add checkboxes to the form for each content type.
+    $form['menu_node_types'] = array(
+      '#type' => 'checkboxes',
+      '#title' => t('Available for these content types'),
+      '#default_value' => $default_value,
+      '#options' => $node_types,
+    );
+  }
+
   $form['actions'] = array('#type' => 'actions');
   $form['actions']['submit'] = array(
     '#type' => 'submit',
@@ -580,6 +606,11 @@ function menu_edit_menu_name_exists($value) {
 function menu_edit_menu_submit($form, &$form_state) {
   $menu = $form_state['values'];
   $path = 'admin/structure/menu/manage/';
+  // Abort if the menu values do not exist.
+  if (!isset($menu['menu_name']) || !isset($menu['title'])) {
+    drupal_set_message(t('The menu name or title is undefined. Your configuration was not saved.'));
+    $form_state['redirect'] = $path;
+  }
   if ($form['#insert']) {
     // Add 'menu-' to the menu name to help avoid name-space conflicts.
     $menu['menu_name'] = 'menu-' . $menu['menu_name'];
@@ -605,6 +636,23 @@ function menu_edit_menu_submit($form, &$form_state) {
       menu_link_save($link);
     }
   }
+
+  // Add or remove this menu from each available node type.
+  if (isset($menu['menu_node_types'])) {
+    $node_types = $menu['menu_node_types'];
+    foreach ($node_types as $node_type => $value) {
+      $menu_options = variable_get('menu_options_' . $node_type, array('main-menu'));
+      if (empty($value)) {
+        // Remove this menu from the content type.
+        $menu_options = array_diff($menu_options, array($menu['menu_name']));
+      }
+      elseif (!empty($value) && !in_array($menu['menu_name'], $menu_options)) {
+        // Add this menu to the content type.
+        $menu_options[] = $menu['menu_name'];
+      }
+      variable_set('menu_options_' . $node_type, $menu_options);
+    }
+  }
   drupal_set_message(t('Your configuration has been saved.'));
   $form_state['redirect'] = $path . $menu['menu_name'];
 }
diff --git a/core/modules/menu/menu.test b/core/modules/menu/menu.test
index 14fe96b..8fd481b 100644
--- a/core/modules/menu/menu.test
+++ b/core/modules/menu/menu.test
@@ -31,7 +31,10 @@ class MenuTestCase extends WebTestBase {
   }
 
   /**
-   * Login users, add menus and menu links, and test menu functionality through the admin and user interfaces.
+   * Tests the standard menu functionality.
+   *
+   * Logs in users, adds menus and menu links, and tests menu functionality
+   * through the admin and user interfaces.
    */
   function testMenu() {
     // Login the user.
@@ -129,8 +132,6 @@ class MenuTestCase extends WebTestBase {
    * Add custom menu.
    */
   function addCustomMenu() {
-    // Add custom menu.
-
     // Try adding a menu using a menu_name that is too long.
     $this->drupalGet('admin/structure/menu/add');
     $menu_name = substr(hash('sha256', $this->randomName(16)), 0, MENU_MAX_MENU_NAME_LENGTH_UI + 1);
@@ -246,8 +247,8 @@ class MenuTestCase extends WebTestBase {
     $this->disableMenuLink($item1);
     $edit = array();
 
-    // Note in the UI the 'mlid:x[hidden]' form element maps to enabled, or
-    // NOT hidden.
+    // Test a hidden menu link. Note in the UI the 'mlid:x[hidden]' form element
+    // defaults to enabled, or NOT hidden.
     $edit['mlid:' . $item1['mlid'] . '[hidden]'] = TRUE;
     $this->drupalPost('admin/structure/menu/manage/' . $item1['menu_name'], $edit, t('Save configuration'));
 
@@ -336,25 +337,27 @@ class MenuTestCase extends WebTestBase {
    * Verify a menu link using the menu module UI.
    *
    * @param array $item Menu link.
-   * @param object $item_node Menu link content node.
+   * @param object $item_node (optional) Menu link content node.
    * @param array $parent Parent menu link.
    * @param object $parent_node Parent menu link content node.
    */
-  function verifyMenuLink($item, $item_node, $parent = NULL, $parent_node = NULL) {
+  function verifyMenuLink($item, $item_node = NULL, $parent = NULL, $parent_node = NULL) {
     // View home page.
-    $this->drupalGet('');
+    $this->drupalGet('user');
     $this->assertResponse(200);
 
     // Verify parent menu link.
     if (isset($parent)) {
       // Verify menu link.
       $title = $parent['link_title'];
-      $this->assertLink($title, 0, 'Parent menu link was displayed');
+      $this->assertLink($title, 0, 'Parent menu link was displayed.');
 
       // Verify menu link link.
-      $this->clickLink($title);
-      $title = $parent_node->title;
-      $this->assertTitle(t("@title | Drupal", array('@title' => $title)), t('Parent menu link link target was correct'));
+      if (isset($parent_node)) {
+        $this->clickLink($title);
+        $title = $parent_node->title;
+        $this->assertTitle(t("@title | Drupal", array('@title' => $title)), 'Parent menu link link target was correct.');
+      }
     }
 
     // Verify menu link.
@@ -362,9 +365,11 @@ class MenuTestCase extends WebTestBase {
     $this->assertLink($title, 0, 'Menu link was displayed');
 
     // Verify menu link link.
-    $this->clickLink($title);
-    $title = $item_node->title;
-    $this->assertTitle(t("@title | Drupal", array('@title' => $title)), t('Menu link link target was correct'));
+    if (isset($item_node)) {
+      $this->clickLink($title);
+      $title = $item_node->title;
+      $this->assertTitle(t("@title | Drupal", array('@title' => $title)), t('Menu link link target was correct'));
+    }
   }
 
   /**
@@ -419,7 +424,7 @@ class MenuTestCase extends WebTestBase {
     $this->assertRaw(t('The menu link was reset to its default settings.'), t('Menu link was reset'));
 
     // Verify menu link.
-    $this->drupalGet('');
+    $this->drupalGet('user');
     $this->assertNoText($title, 'Menu link was reset');
     $this->assertText($old_title, 'Menu link was reset');
   }
@@ -453,12 +458,12 @@ class MenuTestCase extends WebTestBase {
     $this->disableMenuLink($item);
 
     // Verify menu link is absent.
-    $this->drupalGet('');
+    $this->drupalGet('user');
     $this->assertNoText($item['link_title'], 'Menu link was not displayed');
     $this->enableMenuLink($item);
 
     // Verify menu link is displayed.
-    $this->drupalGet('');
+    $this->drupalGet('user');
     $this->assertText($item['link_title'], 'Menu link was displayed');
   }
 
@@ -580,6 +585,128 @@ class MenuTestCase extends WebTestBase {
       $this->assertText(t('Menus'), t('Add menu node was displayed'));
     }
   }
+
+  /**
+   * Tests the standard menu functionality with the Node module disabled.
+   *
+   * With node module disabled, this test logs in users, adds menus and menu
+   * links, and tests menu functionality through the admin and user interfaces.
+   */
+  function testMenuWithoutNode() {
+    // Disable node module to test menus.
+    module_disable(array('node'));
+
+    // Login the user.
+    $this->drupalLogin($this->big_user);
+    $this->items = array();
+
+    // Do standard menu tests.
+    $this->doStandardMenuTestsWithoutNode();
+
+    // Do custom menu tests.
+    $this->doCustomMenuTestsWithoutNode();
+
+    // No standard user tests because there are no accessible menu links to
+    // $std_user.
+
+    // Delete menu links.
+    foreach ($this->items as $item) {
+      $this->deleteMenuLink($item);
+    }
+
+    // Delete custom menu.
+    $this->deleteCustomMenu($this->menu);
+
+    // Modify and reset a standard menu link.
+    $item = $this->getStandardMenuLink();
+    $old_title = $item['link_title'];
+    $this->modifyMenuLink($item);
+    $item = menu_link_load($item['mlid']);
+
+    // Verify that a change to the description is saved.
+    $description = $this->randomName(16);
+    $item['options']['attributes']['title']  = $description;
+    menu_link_save($item);
+    $saved_item = menu_link_load($item['mlid']);
+    $this->assertEqual($description, $saved_item['options']['attributes']['title'], t('Saving an existing link updates the description (title attribute)'));
+    $this->resetMenuLink($item, $old_title);
+  }
+
+  /**
+   * Tests standard menu functionality using navigation menu.
+   */
+  function doStandardMenuTestsWithoutNode() {
+    $this->doMenuTestsWithoutNode();
+    $this->addInvalidMenuLink();
+  }
+
+  /**
+   * Tests custom menu functionality using navigation menu.
+   */
+  function doCustomMenuTestsWithoutNode() {
+    $this->menu = $this->addCustomMenu();
+    $this->doMenuTestsWithoutNode($this->menu['menu_name']);
+    $this->addInvalidMenuLink($this->menu['menu_name']);
+    $this->addCustomMenuCRUD();
+  }
+
+
+  /**
+   * Tests menu functionality using navigation menu.
+   */
+  function doMenuTestsWithoutNode($menu_name = 'navigation') {
+
+    // Add menu links.
+    $item1 = $this->addMenuLink(0, 'admin', $menu_name);
+    $item2 = $this->addMenuLink($item1['mlid'], 'admin/structure', $menu_name);
+    $item3 = $this->addMenuLink($item2['mlid'], 'admin/structure/block', $menu_name);
+    $this->assertMenuLink($item1['mlid'], array('depth' => 1, 'has_children' => 1, 'p1' => $item1['mlid'], 'p2' => 0));
+    $this->assertMenuLink($item2['mlid'], array('depth' => 2, 'has_children' => 1, 'p1' => $item1['mlid'], 'p2' => $item2['mlid'], 'p3' => 0));
+    $this->assertMenuLink($item3['mlid'], array('depth' => 3, 'has_children' => 0, 'p1' => $item1['mlid'], 'p2' => $item2['mlid'], 'p3' => $item3['mlid'], 'p4' => 0));
+
+    // Verify menu links.
+    $this->verifyMenuLink($item1);
+    $this->verifyMenuLink($item2, NULL, $item1, NULL);
+    $this->verifyMenuLink($item3, NULL, $item2, NULL);
+
+    // Add more menu links.
+    $item4 = $this->addMenuLink(0, 'admin/config', $menu_name);
+    $item5 = $this->addMenuLink($item4['mlid'], 'admin/config/system', $menu_name);
+    $this->assertMenuLink($item4['mlid'], array('depth' => 1, 'has_children' => 1, 'p1' => $item4['mlid'], 'p2' => 0));
+    $this->assertMenuLink($item5['mlid'], array('depth' => 2, 'has_children' => 0, 'p1' => $item4['mlid'], 'p2' => $item5['mlid'], 'p3' => 0));
+
+    // Modify menu links.
+    $this->modifyMenuLink($item1);
+    $this->modifyMenuLink($item2);
+
+    // Toggle menu links.
+    $this->toggleMenuLink($item1);
+    $this->toggleMenuLink($item2);
+
+    // Move link and verify that descendants are updated.
+    $this->moveMenuLink($item2, $item5['mlid'], $menu_name);
+    $this->assertMenuLink($item1['mlid'], array('depth' => 1, 'has_children' => 0, 'p1' => $item1['mlid'], 'p2' => 0));
+    $this->assertMenuLink($item4['mlid'], array('depth' => 1, 'has_children' => 1, 'p1' => $item4['mlid'], 'p2' => 0));
+    $this->assertMenuLink($item5['mlid'], array('depth' => 2, 'has_children' => 1, 'p1' => $item4['mlid'], 'p2' => $item5['mlid'], 'p3' => 0));
+    $this->assertMenuLink($item2['mlid'], array('depth' => 3, 'has_children' => 1, 'p1' => $item4['mlid'], 'p2' => $item5['mlid'], 'p3' => $item2['mlid'], 'p4' => 0));
+    $this->assertMenuLink($item3['mlid'], array('depth' => 4, 'has_children' => 0, 'p1' => $item4['mlid'], 'p2' => $item5['mlid'], 'p3' => $item2['mlid'], 'p4' => $item3['mlid'], 'p5' => 0));
+
+    // Enable a link via the overview form.
+    $this->disableMenuLink($item1);
+    $edit = array();
+
+    // Test a hidden menu link. Note in the UI the 'mlid:x[hidden]' form element
+    // defaults to enabled, or NOT hidden.
+    $edit['mlid:' . $item1['mlid'] . '[hidden]'] = TRUE;
+    $this->drupalPost('admin/structure/menu/manage/' . $item1['menu_name'], $edit, t('Save configuration'));
+
+    // Verify in the database.
+    $this->assertMenuLink($item1['mlid'], array('hidden' => 0));
+
+    // Save menu links for later tests.
+    $this->items[] = $item1;
+    $this->items[] = $item2;
+  }
 }
 
 /**
