capnproto

FORK: Cap'n Proto serialization/RPC system - core tools and C++ library
git clone https://git.neptards.moe/neptards/capnproto.git
Log | Files | Refs | README | LICENSE

afl-testcase.c++ (4814B)


      1 // Copyright (c) 2017 Cloudflare, Inc. and contributors
      2 // Licensed under the MIT License:
      3 //
      4 // Permission is hereby granted, free of charge, to any person obtaining a copy
      5 // of this software and associated documentation files (the "Software"), to deal
      6 // in the Software without restriction, including without limitation the rights
      7 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      8 // copies of the Software, and to permit persons to whom the Software is
      9 // furnished to do so, subject to the following conditions:
     10 //
     11 // The above copyright notice and this permission notice shall be included in
     12 // all copies or substantial portions of the Software.
     13 //
     14 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     17 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     18 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     19 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     20 // THE SOFTWARE.
     21 
     22 #include "test-util.h"
     23 #include <kj/main.h>
     24 #include "serialize.h"
     25 #include <capnp/test.capnp.h>
     26 #include <unistd.h>
     27 
     28 namespace capnp {
     29 namespace _ {
     30 namespace {
     31 
     32 class AflTestMain {
     33 public:
     34   explicit AflTestMain(kj::ProcessContext& context)
     35       : context(context) {}
     36 
     37   kj::MainFunc getMain() {
     38     return kj::MainBuilder(context, "(unknown version)",
     39         "American Fuzzy Lop test case. Pass input on stdin. Expects a binary "
     40         "message of type TestAllTypes.")
     41         .addOption({"lists"}, KJ_BIND_METHOD(*this, runLists),
     42             "Expect a message of type TestLists instead of TestAllTypes.")
     43         .addOption({"canonicalize"}, KJ_BIND_METHOD(*this, canonicalize),
     44             "Test canonicalization code.")
     45         .callAfterParsing(KJ_BIND_METHOD(*this, run))
     46         .build();
     47   }
     48 
     49   kj::MainBuilder::Validity run() {
     50     capnp::StreamFdMessageReader reader(STDIN_FILENO);
     51     KJ_IF_MAYBE(e, kj::runCatchingExceptions([&]() {
     52       checkTestMessage(reader.getRoot<TestAllTypes>());
     53     })) {
     54       KJ_LOG(ERROR, "threw");
     55     }
     56     KJ_IF_MAYBE(e, kj::runCatchingExceptions([&]() {
     57       checkDynamicTestMessage(reader.getRoot<DynamicStruct>(Schema::from<TestAllTypes>()));
     58     })) {
     59       KJ_LOG(ERROR, "dynamic threw");
     60     }
     61     KJ_IF_MAYBE(e, kj::runCatchingExceptions([&]() {
     62       kj::str(reader.getRoot<TestAllTypes>());
     63     })) {
     64       KJ_LOG(ERROR, "str threw");
     65     }
     66     return true;
     67   }
     68 
     69   kj::MainBuilder::Validity runLists() {
     70     capnp::StreamFdMessageReader reader(STDIN_FILENO);
     71     KJ_IF_MAYBE(e, kj::runCatchingExceptions([&]() {
     72       kj::str(reader.getRoot<test::TestLists>());
     73     })) {
     74       KJ_LOG(ERROR, "threw");
     75     }
     76     return true;
     77   }
     78 
     79   kj::MainBuilder::Validity canonicalize() {
     80     // (Test case contributed by David Renshaw.)
     81 
     82     kj::Array<capnp::word> canonical;
     83     bool equal = false;
     84     KJ_IF_MAYBE(e, kj::runCatchingExceptions([&]() {
     85       capnp::ReaderOptions options;
     86 
     87       // The default traversal limit of 8 * 1024 * 1024 causes
     88       // AFL to think that it has found "hang" bugs.
     89       options.traversalLimitInWords = 8 * 1024;
     90 
     91       capnp::StreamFdMessageReader message(0, options); // read from stdin
     92       TestAllTypes::Reader myStruct = message.getRoot<TestAllTypes>();
     93       canonical = capnp::canonicalize(myStruct);
     94 
     95       kj::ArrayPtr<const capnp::word> segments[1] = {canonical.asPtr()};
     96       capnp::SegmentArrayMessageReader reader(kj::arrayPtr(segments, 1));
     97 
     98       auto originalAny = message.getRoot<capnp::AnyPointer>();
     99 
    100       // Discard cases where the original message is null.
    101       KJ_ASSERT(!originalAny.isNull());
    102 
    103       equal = originalAny == reader.getRoot<capnp::AnyPointer>();
    104     })) {
    105       // Probably some kind of decoding exception.
    106       KJ_LOG(ERROR, "threw");
    107       context.exit();
    108     }
    109 
    110     KJ_ASSERT(equal);
    111 
    112     kj::ArrayPtr<const capnp::word> segments[1] = {canonical.asPtr()};
    113     capnp::SegmentArrayMessageReader reader(kj::arrayPtr(segments, 1));
    114     KJ_ASSERT(reader.isCanonical());
    115 
    116     kj::Array<capnp::word> canonical2;
    117     {
    118       capnp::ReaderOptions options;
    119       options.traversalLimitInWords = 8 * 1024;
    120 
    121       TestAllTypes::Reader myStruct = reader.getRoot<TestAllTypes>();
    122       canonical2 = capnp::canonicalize(myStruct);
    123     }
    124 
    125     KJ_ASSERT(canonical.size() == canonical2.size());
    126     auto b1 = canonical.asBytes();
    127     auto b2 = canonical2.asBytes();
    128     for (int idx = 0; idx < b1.size(); ++idx) {
    129       KJ_ASSERT(b1[idx] == b2[idx], idx, b1.size());
    130     }
    131 
    132     return true;
    133   }
    134 
    135 private:
    136   kj::ProcessContext& context;
    137 };
    138 
    139 }  // namespace
    140 }  // namespace _
    141 }  // namespace capnp
    142 
    143 KJ_MAIN(capnp::_::AflTestMain);