diff --git a/core/includes/menu.inc b/core/includes/menu.inc
index f2da288f70a68ae7006f84f6fb8b648ae0d82841..511c5d09dfc5c86668f5bbca8de3e2b2c0525a29 100644
--- a/core/includes/menu.inc
+++ b/core/includes/menu.inc
@@ -2292,6 +2292,9 @@ function menu_get_active_menu_names() {
  */
 function menu_set_active_item($path) {
   $_GET['q'] = $path;
+  // Since the active item has changed, the active menu trail may also be out
+  // of date.
+  drupal_static_reset('menu_set_active_trail');
 }
 
 /**
@@ -2377,7 +2380,7 @@ function menu_set_active_trail($new_trail = NULL) {
     // appending either the preferred link or the menu router item for the
     // current page. Exclude it if we are on the front page.
     $last = end($trail);
-    if ($last['href'] != $preferred_link['href'] && !drupal_is_front_page()) {
+    if ($preferred_link && $last['href'] != $preferred_link['href'] && !drupal_is_front_page()) {
       $trail[] = $preferred_link;
     }
   }
diff --git a/core/modules/simpletest/tests/menu.test b/core/modules/simpletest/tests/menu.test
index fbc0e177bf879c3d50b73df4f2957c1a0fc0d10a..8d1d6516118075a07674b9b3e833cec469909de9 100644
--- a/core/modules/simpletest/tests/menu.test
+++ b/core/modules/simpletest/tests/menu.test
@@ -1627,4 +1627,97 @@ class MenuTrailTestCase extends MenuWebTestCase {
     variable_set('menu_test_menu_tree_set_path', $test_menu_path);
     $this->assertBreadcrumb('admin/config/development/menu-trail', $override_breadcrumb, t('Menu trail - Case 2'), $override_tree);
   }
+
+  /**
+   * Tests that the active trail works correctly on custom 403 and 404 pages.
+   */
+  function testCustom403And404Pages() {
+    // Set the custom 403 and 404 pages we will use.
+    variable_set('site_403', 'menu-test/custom-403-page');
+    variable_set('site_404', 'menu-test/custom-404-page');
+
+    // Define the paths we'll visit to trigger 403 and 404 responses during
+    // this test, and the expected active trail for each case.
+    $paths = array(
+      403 => 'admin/config',
+      404 => $this->randomName(),
+    );
+    // For the 403 page, the initial trail during the Drupal bootstrap should
+    // include the page that the user is trying to visit, while the final trail
+    // should reflect the custom 403 page that the user was redirected to.
+    $expected_trail[403]['initial'] = array(
+      '<front>' => 'Home',
+      'admin/config' => 'Configuration',
+    );
+    $expected_trail[403]['final'] = array(
+      '<front>' => 'Home',
+      'menu-test' => 'Menu test root',
+      'menu-test/custom-403-page' => 'Custom 403 page',
+    );
+    // For the 404 page, the initial trail during the Drupal bootstrap should
+    // only contain the link back to "Home" (since the page the user is trying
+    // to visit doesn't have any menu items associated with it), while the
+    // final trail should reflect the custom 404 page that the user was
+    // redirected to.
+    $expected_trail[404]['initial'] = array(
+      '<front>' => 'Home',
+    );
+    $expected_trail[404]['final'] = array(
+      '<front>' => 'Home',
+      'menu-test' => 'Menu test root',
+      'menu-test/custom-404-page' => 'Custom 404 page',
+    );
+
+    // Visit each path as an anonymous user so that we will actually get a 403
+    // on admin/config.
+    $this->drupalLogout();
+    foreach (array(403, 404) as $status_code) {
+      // Before visiting the page, trigger the code in the menu_test module
+      // that will record the active trail (so we can check it in this test).
+      variable_set('menu_test_record_active_trail', TRUE);
+      $this->drupalGet($paths[$status_code]);
+      $this->assertResponse($status_code);
+
+      // Check that the initial trail (during the Drupal bootstrap) matches
+      // what we expect.
+      $initial_trail = variable_get('menu_test_active_trail_initial', array());
+      $this->assertEqual(count($initial_trail), count($expected_trail[$status_code]['initial']), t('The initial active trail for a @status_code page contains the expected number of items (expected: @expected, found: @found).', array(
+        '@status_code' => $status_code,
+        '@expected' => count($expected_trail[$status_code]['initial']),
+        '@found' => count($initial_trail),
+      )));
+      foreach (array_keys($expected_trail[$status_code]['initial']) as $index => $path) {
+        $this->assertEqual($initial_trail[$index]['href'], $path, t('Element number @number of the initial active trail for a @status_code page contains the correct path (expected: @expected, found: @found)', array(
+          '@number' => $index + 1,
+          '@status_code' => $status_code,
+          '@expected' => $path,
+          '@found' => $initial_trail[$index]['href'],
+        )));
+      }
+
+      // Check that the final trail (after the user has been redirected to the
+      // custom 403/404 page) matches what we expect.
+      $final_trail = variable_get('menu_test_active_trail_final', array());
+      $this->assertEqual(count($final_trail), count($expected_trail[$status_code]['final']), t('The final active trail for a @status_code page contains the expected number of items (expected: @expected, found: @found).', array(
+        '@status_code' => $status_code,
+        '@expected' => count($expected_trail[$status_code]['final']),
+        '@found' => count($final_trail),
+      )));
+      foreach (array_keys($expected_trail[$status_code]['final']) as $index => $path) {
+        $this->assertEqual($final_trail[$index]['href'], $path, t('Element number @number of the final active trail for a @status_code page contains the correct path (expected: @expected, found: @found)', array(
+          '@number' => $index + 1,
+          '@status_code' => $status_code,
+          '@expected' => $path,
+          '@found' => $final_trail[$index]['href'],
+        )));
+      }
+
+      // Check that the breadcrumb displayed on the final custom 403/404 page
+      // matches what we expect. (The last item of the active trail represents
+      // the current page, which is not supposed to appear in the breadcrumb,
+      // so we need to remove it from the array before checking.)
+      array_pop($expected_trail[$status_code]['final']);
+      $this->assertBreadcrumb(NULL, $expected_trail[$status_code]['final']);
+    }
+  }
 }
diff --git a/core/modules/simpletest/tests/menu_test.module b/core/modules/simpletest/tests/menu_test.module
index c42aca60fe67a0851d5177ebbd6e8c97b31b8781..0b954ae1cbadeef629a9bf451025dd1aac6b0361 100644
--- a/core/modules/simpletest/tests/menu_test.module
+++ b/core/modules/simpletest/tests/menu_test.module
@@ -230,6 +230,16 @@ function menu_test_menu() {
     'page callback' => 'menu_test_menu_trail_callback',
     'access arguments' => array('access administration pages'),
   );
+  $items['menu-test/custom-403-page'] = array(
+    'title' => 'Custom 403 page',
+    'page callback' => 'menu_test_custom_403_404_callback',
+    'access arguments' => array('access content'),
+  );
+  $items['menu-test/custom-404-page'] = array(
+    'title' => 'Custom 404 page',
+    'page callback' => 'menu_test_custom_403_404_callback',
+    'access arguments' => array('access content'),
+  );
 
   // File inheritance tests. This menu item should inherit the page callback
   // system_admin_menu_block_page() and therefore render its children as links
@@ -369,6 +379,32 @@ function menu_test_menu_trail_callback() {
   return 'This is menu_test_menu_trail_callback().';
 }
 
+/**
+ * Implements hook_init().
+ */
+function menu_test_init() {
+  // When requested by one of the MenuTrailTestCase tests, record the initial
+  // active trail during Drupal's bootstrap (before the user is redirected to a
+  // custom 403 or 404 page). See menu_test_custom_403_404_callback().
+  if (variable_get('menu_test_record_active_trail', FALSE)) {
+    variable_set('menu_test_active_trail_initial', menu_get_active_trail());
+  }
+}
+
+/**
+ * Callback for our custom 403 and 404 pages.
+ */
+function menu_test_custom_403_404_callback() {
+  // When requested by one of the MenuTrailTestCase tests, record the final
+  // active trail now that the user has been redirected to the custom 403 or
+  // 404 page. See menu_test_init().
+  if (variable_get('menu_test_record_active_trail', FALSE)) {
+    variable_set('menu_test_active_trail_final', menu_get_active_trail());
+  }
+
+  return 'This is menu_test_custom_403_404_callback().';
+}
+
 /**
  * Page callback to use when testing the theme callback functionality.
  *