| // Copyright 2022 The Centipede Authors. | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // https://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| // Centipede puzzle: almost no control flow, needs paths to find the goal. | |
| // We disable use_dataflow_features because on this puzzle | |
| // it is also effective. | |
| // RUN: Run --use_dataflow_features=0 --path_level=10 | |
| // RUN: ExpectInLog "Input bytes.*: .x1.x2.x3" | |
| // This puzzle aborts on input "\x1\x2\x3" | |
| // The code here has very little control flow, but an exponential number of | |
| // call paths. The input above triggers a call sequence F1->F2->F3. | |
| // The value `sink` generated by these functions represents the call sequence. | |
| // The goal of this test is to verify that "bounded-path" features work. | |
| #include <cstddef> | |
| #include <cstdint> | |
| static volatile uint64_t sink; | |
| using Func = void (*)(); | |
| template <size_t kIdx> | |
| static void F() { | |
| sink = sink * 16 + kIdx; | |
| } | |
| void FN() {} | |
| // All functions in an array. | |
| static Func table[256] = { | |
| F<0>, F<1>, F<2>, F<3>, F<4>, F<5>, F<6>, F<7>, | |
| F<8>, F<9>, F<10>, F<11>, F<12>, F<13>, F<14>, F<15>, | |
| // The rest are set to FN below. | |
| }; | |
| // Set table[16:256] to FN. | |
| struct TableCtor { | |
| TableCtor() { | |
| for (size_t i = 16; i < 256; ++i) table[i] = FN; | |
| } | |
| }; | |
| [[maybe_unused]] static TableCtor table_ctor; | |
| extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { | |
| if (size != 3) return -1; | |
| sink = 0; | |
| table[data[0]](); | |
| table[data[1]](); | |
| table[data[2]](); | |
| sink /= 0x123 - sink; // Generates a crash (div by zero) w/o a control flow. | |
| return 0; | |
| } |