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 =