Detect large Jacobians and return failure instead of crashing.

Detect when the number of non-zeros overflows when constructing
BlockSparseMatrix and CompressedRowSparseMatrix and return
with an error message instead of crashing.

Change-Id: I45e102f7c0519eef441ce0586b7adf96e4a954a9
diff --git a/internal/ceres/block_jacobian_writer.cc b/internal/ceres/block_jacobian_writer.cc
index b009e96..adeaf41 100644
--- a/internal/ceres/block_jacobian_writer.cc
+++ b/internal/ceres/block_jacobian_writer.cc
@@ -63,7 +63,7 @@
 //
 // TODO(keir): Consider if we should use a boolean for each parameter block
 // instead of num_eliminate_blocks.
-void BuildJacobianLayout(const Program& program,
+bool BuildJacobianLayout(const Program& program,
                          int num_eliminate_blocks,
                          std::vector<int*>* jacobian_layout,
                          std::vector<int>* jacobian_layout_storage) {
@@ -73,8 +73,8 @@
   // Iterate over all the active residual blocks and determine how many E blocks
   // are there. This will determine where the F blocks start in the jacobian
   // matrix. Also compute the number of jacobian blocks.
-  int f_block_pos = 0;
-  int num_jacobian_blocks = 0;
+  unsigned int f_block_pos = 0;
+  unsigned int num_jacobian_blocks = 0;
   for (auto* residual_block : residual_blocks) {
     const int num_residuals = residual_block->NumResiduals();
     const int num_parameter_blocks = residual_block->NumParameterBlocks();
@@ -90,6 +90,11 @@
         }
       }
     }
+    if (num_jacobian_blocks > std::numeric_limits<int>::max()) {
+      LOG(ERROR) << "Overlow error. Too many blocks in the jacobian matrix : "
+                 << num_jacobian_blocks;
+      return false;
+    }
   }
 
   // We now know that the E blocks are laid out starting at zero, and the F
@@ -145,12 +150,18 @@
         jacobian_pos[k] = e_block_pos;
         e_block_pos += jacobian_block_size;
       } else {
-        jacobian_pos[k] = f_block_pos;
+        jacobian_pos[k] = static_cast<int>(f_block_pos);
         f_block_pos += jacobian_block_size;
+        if (f_block_pos > std::numeric_limits<int>::max()) {
+          LOG(ERROR)
+              << "Overlow error. Too many entries in the Jacobian matrix.";
+          return false;
+        }
       }
     }
     jacobian_pos += active_parameter_blocks.size();
   }
+  return true;
 }
 
 }  // namespace
@@ -161,10 +172,10 @@
   CHECK_GE(options.num_eliminate_blocks, 0)
       << "num_eliminate_blocks must be greater than 0.";
 
-  BuildJacobianLayout(*program,
-                      options.num_eliminate_blocks,
-                      &jacobian_layout_,
-                      &jacobian_layout_storage_);
+  jacobian_layout_is_valid_ = BuildJacobianLayout(*program,
+                                                  options.num_eliminate_blocks,
+                                                  &jacobian_layout_,
+                                                  &jacobian_layout_storage_);
 }
 
 // Create evaluate prepareres that point directly into the final jacobian. This
@@ -183,6 +194,12 @@
 }
 
 std::unique_ptr<SparseMatrix> BlockJacobianWriter::CreateJacobian() const {
+  if (!jacobian_layout_is_valid_) {
+    LOG(ERROR) << "Unable to create Jacobian matrix. Too many entries in the "
+                  "Jacobian matrix.";
+    return nullptr;
+  }
+
   auto* bs = new CompressedRowBlockStructure;
 
   const std::vector<ParameterBlock*>& parameter_blocks =