Line | Count | Source |
1 | | // Copyright 2026 Google LLC |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // http://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | |
15 | | #include <fuzzer/FuzzedDataProvider.h> |
16 | | #include <Eigen/Sparse> |
17 | | #include <Eigen/SparseLU> |
18 | | #include <Eigen/SparseQR> |
19 | | #include <vector> |
20 | | |
21 | | namespace { |
22 | | |
23 | | static constexpr Eigen::Index kEigenTestMaxSize = 16; |
24 | | |
25 | | template <typename Scalar> |
26 | 0 | void fuzzSparse(FuzzedDataProvider* stream) { |
27 | 0 | Eigen::Index rows = stream->ConsumeIntegralInRange<Eigen::Index>(1, kEigenTestMaxSize); |
28 | 0 | Eigen::Index cols = stream->ConsumeIntegralInRange<Eigen::Index>(1, kEigenTestMaxSize); |
29 | 0 | size_t numTriplets = stream->ConsumeIntegralInRange<size_t>(0, rows * cols / 10 + 1); |
30 | |
|
31 | 0 | typedef Eigen::Triplet<Scalar> T; |
32 | 0 | std::vector<T> triplets; |
33 | 0 | for (size_t i = 0; i < numTriplets; ++i) { |
34 | 0 | Eigen::Index r = stream->ConsumeIntegralInRange<Eigen::Index>(0, rows - 1); |
35 | 0 | Eigen::Index c = stream->ConsumeIntegralInRange<Eigen::Index>(0, cols - 1); |
36 | 0 | Scalar v; |
37 | | if constexpr (std::is_integral_v<Scalar>) { |
38 | | v = stream->ConsumeIntegral<Scalar>(); |
39 | 0 | } else { |
40 | 0 | v = stream->ConsumeFloatingPoint<Scalar>(); |
41 | 0 | } |
42 | 0 | triplets.push_back(T(r, c, v)); |
43 | 0 | } |
44 | |
|
45 | 0 | Eigen::SparseMatrix<Scalar> mat(rows, cols); |
46 | 0 | mat.setFromTriplets(triplets.begin(), triplets.end()); |
47 | | |
48 | | // Basic operations |
49 | 0 | (void)mat.transpose(); |
50 | 0 | (void)mat.adjoint(); |
51 | 0 | (void)mat.norm(); |
52 | |
|
53 | 0 | if (rows == cols) { |
54 | | // SparseLU |
55 | 0 | Eigen::SparseLU<Eigen::SparseMatrix<Scalar>> lu; |
56 | 0 | lu.compute(mat); |
57 | 0 | if (lu.info() == Eigen::Success) { |
58 | 0 | Eigen::Matrix<Scalar, Eigen::Dynamic, 1> b = Eigen::Matrix<Scalar, Eigen::Dynamic, 1>::Random(rows); |
59 | 0 | (void)lu.solve(b); |
60 | 0 | } |
61 | 0 | } |
62 | | |
63 | | // SparseQR |
64 | 0 | Eigen::SparseQR<Eigen::SparseMatrix<Scalar>, Eigen::COLAMDOrdering<int>> qr; |
65 | 0 | qr.compute(mat); |
66 | 0 | if (qr.info() == Eigen::Success) { |
67 | 0 | Eigen::Matrix<Scalar, Eigen::Dynamic, 1> b = Eigen::Matrix<Scalar, Eigen::Dynamic, 1>::Random(rows); |
68 | 0 | (void)qr.solve(b); |
69 | 0 | } |
70 | 0 | } Unexecuted instantiation: sparse_fuzzer.cc:void (anonymous namespace)::fuzzSparse<float>(FuzzedDataProvider*) Unexecuted instantiation: sparse_fuzzer.cc:void (anonymous namespace)::fuzzSparse<double>(FuzzedDataProvider*) |
71 | | |
72 | | } // namespace |
73 | | |
74 | 349 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { |
75 | 349 | FuzzedDataProvider stream(data, size); |
76 | | |
77 | 349 | uint8_t type = stream.ConsumeIntegral<uint8_t>(); |
78 | 349 | switch (type % 2) { |
79 | 177 | case 0: |
80 | 177 | fuzzSparse<float>(&stream); |
81 | 177 | break; |
82 | 172 | case 1: |
83 | 172 | fuzzSparse<double>(&stream); |
84 | 172 | break; |
85 | 349 | } |
86 | | |
87 | 349 | return 0; |
88 | 349 | } |