diff --git a/core/modules/views/src/Exception/InvalidViewsDataException.php b/core/modules/views/src/Exception/InvalidViewsDataException.php
new file mode 100644
index 0000000000..b1fe45ed96
--- /dev/null
+++ b/core/modules/views/src/Exception/InvalidViewsDataException.php
@@ -0,0 +1,10 @@
+<?php
+
+namespace Drupal\views\Exception;
+
+/**
+ * Thrown when invalid views data is encountered.
+ */
+class InvalidViewsDataException extends \Exception {
+
+}
diff --git a/core/modules/views/src/ManyToOneHelper.php b/core/modules/views/src/ManyToOneHelper.php
index cb2e5754a8..582e27002b 100644
--- a/core/modules/views/src/ManyToOneHelper.php
+++ b/core/modules/views/src/ManyToOneHelper.php
@@ -5,6 +5,7 @@
 use Drupal\Core\Database\Query\Condition;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\views\Plugin\views\HandlerBase;
+use Drupal\views\Exception\InvalidViewsDataException;
 
 /**
  * This many to one helper object is used on both arguments and filters.
@@ -56,10 +57,19 @@ public function getField() {
   /**
    * Add a table to the query.
    *
-   * This is an advanced concept; not only does it add a new instance of the table,
-   * but it follows the relationship path all the way down to the relationship
-   * link point and adds *that* as a new relationship and then adds the table to
-   * the relationship, if necessary.
+   * This is an advanced concept; not only does it add a new instance of the
+   * table, but it follows the relationship path all the way down to the
+   * relationship link point and adds *that* as a new relationship and then
+   * adds the table to the relationship, if necessary.
+   *
+   * @param null $join
+   * @param null $alias
+   *
+   * @return string
+   *
+   * @throws \Drupal\views\Exception\InvalidViewsDataException
+   *   Thrown when invalid views data is found when trying to find a matching
+   *   relationship.
    */
   public function addTable($join = NULL, $alias = NULL) {
     // This is used for lookups in the many_to_one table.
@@ -84,11 +94,21 @@ public function addTable($join = NULL, $alias = NULL) {
     // Cycle through the joins. This isn't as error-safe as the normal
     // ensurePath logic. Perhaps it should be.
     $r_join = clone $join;
+    $traced = [];
     while ($r_join->leftTable != $base_table) {
+      if (isset($traced[$r_join->leftTable])) {
+        // We are in a loop, this means the views data is broken.
+        throw new InvalidViewsDataException('Invalid views data found while trying to find a relationship to ' . $base_table);
+      }
+      $traced[$r_join->leftTable] = TRUE;
       $r_join = HandlerBase::getTableJoin($r_join->leftTable, $base_table);
+      if (empty($r_join)) {
+        // No join was found, this means the views data is broken.
+        throw new InvalidViewsDataException('Invalid views data found while trying to find a relationship to ' . $base_table);
+      }
     }
     // If we found that there are tables in between, add the relationship.
-    if ($r_join->table != $join->table) {
+    if (!empty($r_join) && $r_join->table != $join->table) {
       $relationship = $this->handler->query->addRelationship($this->handler->table . '_' . $r_join->table, $r_join, $r_join->table, $this->handler->relationship);
     }
 
diff --git a/core/modules/views/tests/src/Unit/ManyToOneHelperTest.php b/core/modules/views/tests/src/Unit/ManyToOneHelperTest.php
new file mode 100644
index 0000000000..ccf0179bbb
--- /dev/null
+++ b/core/modules/views/tests/src/Unit/ManyToOneHelperTest.php
@@ -0,0 +1,148 @@
+<?php
+
+namespace Drupal\Tests\views\Unit;
+
+use Drupal\Tests\UnitTestCase;
+use Drupal\views\Exception\InvalidViewsDataException;
+use Drupal\views\ManyToOneHelper;
+use Drupal\views\Plugin\views\HandlerBase;
+use Drupal\views\Plugin\views\join\JoinPluginBase;
+use Drupal\views\Plugin\views\query\Sql;
+use Drupal\views\Plugin\ViewsHandlerManager;
+use Drupal\views\ViewExecutable;
+use Drupal\views\ViewsData;
+use Prophecy\Argument;
+use Symfony\Component\DependencyInjection\ContainerBuilder;
+
+/**
+ * @coversDefaultClass \Drupal\views\ManyToOneHelper
+ * @group views
+ */
+class ManyToOneHelperTest extends UnitTestCase {
+
+  /**
+   * @covers ::addTable
+   */
+  public function testAddTable() {
+    $handler = $this->prophesize(HandlerBase::class);
+    $view = $this->prophesize(ViewExecutable::class);
+    $join = $this->prophesize(JoinPluginBase::class);
+    $query = $this->prophesize(Sql::class);
+
+    $join->leftTable = 'base_table';
+    $join->table = 'base_table';
+
+    $query->addTable('table', 'relationship', Argument::any(), NULL)
+      ->willReturn('alias');
+
+    $query->relationships = [
+      'relationship' => [
+        'base' => 'base_table',
+      ],
+    ];
+
+    $handler->getJoin()->willReturn($join->reveal());
+    $handler->relationship = 'relationship';
+    $handler->table = 'table';
+    $handler->field = 'field';
+    $handler->value = 'value';
+    $handler->view = $view->reveal();
+    $handler->query = $query->reveal();
+
+    $many_to_one_helper = new ManyToOneHelper($handler->reveal());
+    $this->assertEquals('alias', $many_to_one_helper->addTable());
+  }
+
+  /**
+   * @covers ::addTable
+   */
+  public function testAddTableWithNonExistingTable() {
+    $container = new ContainerBuilder();
+    $views_data = $this->prophesize(ViewsData::class);
+    // Test a non-existent table.
+    $views_data->get('non_existing_left_table')->willReturn('');
+    $container->set('views.views_data', $views_data->reveal());
+    \Drupal::setContainer($container);
+
+    $handler = $this->prophesize(HandlerBase::class);
+    $view = $this->prophesize(ViewExecutable::class);
+    $join = $this->prophesize(JoinPluginBase::class);
+    $query = $this->prophesize(Sql::class);
+
+    $join->leftTable = 'non_existing_left_table';
+    $join->table = 'base_table';
+
+    $query->addTable('table', 'relationship', Argument::any(), NULL)
+      ->willReturn('alias');
+
+    $query->relationships = [
+      'relationship' => [
+        'base' => 'base_table',
+      ],
+    ];
+
+    $handler->getJoin()->willReturn($join->reveal());
+    $handler->relationship = 'relationship';
+    $handler->table = 'table';
+    $handler->field = 'field';
+    $handler->value = 'value';
+    $handler->view = $view->reveal();
+    $handler->query = $query->reveal();
+
+    $this->setExpectedException(InvalidViewsDataException::class);
+    $many_to_one_helper = new ManyToOneHelper($handler->reveal());
+
+    // Test that an exception is thrown when using a non existing table.
+    $many_to_one_helper->addTable();
+  }
+
+  /**
+   * @covers ::addTable
+   */
+  public function testAddTableWithCorruptData() {
+    $join = $this->prophesize(JoinPluginBase::class);
+    $join->leftTable = 'corrupt_left_table';
+    $join->table = 'corrupt_left_table';
+
+    $container = new ContainerBuilder();
+    $views_data = $this->prophesize(ViewsData::class);
+    // Test a non-existent table.
+    $views_data->get('corrupt_left_table')->willReturn(['table' => ['join' => ['base_table' => []]]]);
+
+    $views_join_plugin_manager = $this->prophesize(ViewsHandlerManager::class);
+    $views_join_plugin_manager->createInstance(Argument::any(), Argument::any())->willReturn($join->reveal());
+
+    $container->set('views.views_data', $views_data->reveal());
+    $container->set('plugin.manager.views.join', $views_join_plugin_manager->reveal());
+
+    \Drupal::setContainer($container);
+
+    $handler = $this->prophesize(HandlerBase::class);
+    $view = $this->prophesize(ViewExecutable::class);
+    $query = $this->prophesize(Sql::class);
+
+    $query->addTable('table', 'relationship', Argument::any(), NULL)
+      ->willReturn('alias');
+
+    $query->relationships = [
+      'relationship' => [
+        'base' => 'base_table',
+      ],
+    ];
+
+    $handler->getJoin()->willReturn($join->reveal());
+    $handler->relationship = 'relationship';
+    $handler->table = 'table';
+    $handler->field = 'field';
+    $handler->value = 'value';
+    $handler->view = $view->reveal();
+    $handler->query = $query->reveal();
+
+    $this->setExpectedException(InvalidViewsDataException::class);
+    $many_to_one_helper = new ManyToOneHelper($handler->reveal());
+
+    // Test that an exception is thrown when an infinite loop is caused.
+    $many_to_one_helper->addTable();
+  }
+
+}
