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);