aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/protobuf-mutator/src/libfuzzer
diff options
context:
space:
mode:
authormonster <monster@ydb.tech>2022-07-07 14:41:37 +0300
committermonster <monster@ydb.tech>2022-07-07 14:41:37 +0300
commit06e5c21a835c0e923506c4ff27929f34e00761c2 (patch)
tree75efcbc6854ef9bd476eb8bf00cc5c900da436a2 /contrib/libs/protobuf-mutator/src/libfuzzer
parent03f024c4412e3aa613bb543cf1660176320ba8f4 (diff)
downloadydb-06e5c21a835c0e923506c4ff27929f34e00761c2.tar.gz
fix ya.make
Diffstat (limited to 'contrib/libs/protobuf-mutator/src/libfuzzer')
-rw-r--r--contrib/libs/protobuf-mutator/src/libfuzzer/libfuzzer_macro.cc242
-rw-r--r--contrib/libs/protobuf-mutator/src/libfuzzer/libfuzzer_macro.h129
-rw-r--r--contrib/libs/protobuf-mutator/src/libfuzzer/libfuzzer_mutator.cc100
-rw-r--r--contrib/libs/protobuf-mutator/src/libfuzzer/libfuzzer_mutator.h46
4 files changed, 517 insertions, 0 deletions
diff --git a/contrib/libs/protobuf-mutator/src/libfuzzer/libfuzzer_macro.cc b/contrib/libs/protobuf-mutator/src/libfuzzer/libfuzzer_macro.cc
new file mode 100644
index 0000000000..4e506cbe94
--- /dev/null
+++ b/contrib/libs/protobuf-mutator/src/libfuzzer/libfuzzer_macro.cc
@@ -0,0 +1,242 @@
+// Copyright 2017 Google Inc. All rights reserved.
+//
+// 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
+//
+// http://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.
+
+#include "src/libfuzzer/libfuzzer_macro.h"
+
+#include <algorithm>
+#include <memory>
+#include <vector>
+
+#include "src/binary_format.h"
+#include "src/libfuzzer/libfuzzer_mutator.h"
+#include "src/text_format.h"
+
+namespace protobuf_mutator {
+namespace libfuzzer {
+
+namespace {
+
+class InputReader {
+ public:
+ InputReader(const uint8_t* data, size_t size) : data_(data), size_(size) {}
+ virtual ~InputReader() = default;
+
+ virtual bool Read(protobuf::Message* message) const = 0;
+
+ const uint8_t* data() const { return data_; }
+ size_t size() const { return size_; }
+
+ private:
+ const uint8_t* data_;
+ size_t size_;
+};
+
+class OutputWriter {
+ public:
+ OutputWriter(uint8_t* data, size_t size) : data_(data), size_(size) {}
+ virtual ~OutputWriter() = default;
+
+ virtual size_t Write(const protobuf::Message& message) = 0;
+
+ uint8_t* data() const { return data_; }
+ size_t size() const { return size_; }
+
+ private:
+ uint8_t* data_;
+ size_t size_;
+};
+
+class TextInputReader : public InputReader {
+ public:
+ using InputReader::InputReader;
+
+ bool Read(protobuf::Message* message) const override {
+ return ParseTextMessage(data(), size(), message);
+ }
+};
+
+class TextOutputWriter : public OutputWriter {
+ public:
+ using OutputWriter::OutputWriter;
+
+ size_t Write(const protobuf::Message& message) override {
+ return SaveMessageAsText(message, data(), size());
+ }
+};
+
+class BinaryInputReader : public InputReader {
+ public:
+ using InputReader::InputReader;
+
+ bool Read(protobuf::Message* message) const override {
+ return ParseBinaryMessage(data(), size(), message);
+ }
+};
+
+class BinaryOutputWriter : public OutputWriter {
+ public:
+ using OutputWriter::OutputWriter;
+
+ size_t Write(const protobuf::Message& message) override {
+ return SaveMessageAsBinary(message, data(), size());
+ }
+};
+
+class LastMutationCache {
+ public:
+ void Store(const uint8_t* data, size_t size, protobuf::Message* message) {
+ if (!message_) message_.reset(message->New());
+ message->GetReflection()->Swap(message, message_.get());
+ data_.assign(data, data + size);
+ }
+
+ bool LoadIfSame(const uint8_t* data, size_t size,
+ protobuf::Message* message) {
+ if (!message_ || size != data_.size() ||
+ !std::equal(data_.begin(), data_.end(), data))
+ return false;
+
+ message->GetReflection()->Swap(message, message_.get());
+ message_.reset();
+ return true;
+ }
+
+ private:
+ std::vector<uint8_t> data_;
+ std::unique_ptr<protobuf::Message> message_;
+};
+
+LastMutationCache* GetCache() {
+ static LastMutationCache cache;
+ return &cache;
+}
+
+Mutator* GetMutator() {
+ static Mutator mutator;
+ return &mutator;
+}
+
+size_t GetMaxSize(const InputReader& input, const OutputWriter& output,
+ const protobuf::Message& message) {
+ size_t max_size = message.ByteSizeLong() + output.size();
+ max_size -= std::min(max_size, input.size());
+ return max_size;
+}
+
+size_t MutateMessage(unsigned int seed, const InputReader& input,
+ OutputWriter* output, protobuf::Message* message) {
+ GetMutator()->Seed(seed);
+ input.Read(message);
+ size_t max_size = GetMaxSize(input, *output, *message);
+ GetMutator()->Mutate(message, max_size);
+ if (size_t new_size = output->Write(*message)) {
+ assert(new_size <= output->size());
+ GetCache()->Store(output->data(), new_size, message);
+ return new_size;
+ }
+ return 0;
+}
+
+size_t CrossOverMessages(unsigned int seed, const InputReader& input1,
+ const InputReader& input2, OutputWriter* output,
+ protobuf::Message* message1,
+ protobuf::Message* message2) {
+ GetMutator()->Seed(seed);
+ input1.Read(message1);
+ input2.Read(message2);
+ size_t max_size = GetMaxSize(input1, *output, *message1);
+ GetMutator()->CrossOver(*message2, message1, max_size);
+ if (size_t new_size = output->Write(*message1)) {
+ assert(new_size <= output->size());
+ GetCache()->Store(output->data(), new_size, message1);
+ return new_size;
+ }
+ return 0;
+}
+
+size_t MutateTextMessage(uint8_t* data, size_t size, size_t max_size,
+ unsigned int seed, protobuf::Message* message) {
+ TextInputReader input(data, size);
+ TextOutputWriter output(data, max_size);
+ return MutateMessage(seed, input, &output, message);
+}
+
+size_t CrossOverTextMessages(const uint8_t* data1, size_t size1,
+ const uint8_t* data2, size_t size2, uint8_t* out,
+ size_t max_out_size, unsigned int seed,
+ protobuf::Message* message1,
+ protobuf::Message* message2) {
+ TextInputReader input1(data1, size1);
+ TextInputReader input2(data2, size2);
+ TextOutputWriter output(out, max_out_size);
+ return CrossOverMessages(seed, input1, input2, &output, message1, message2);
+}
+
+size_t MutateBinaryMessage(uint8_t* data, size_t size, size_t max_size,
+ unsigned int seed, protobuf::Message* message) {
+ BinaryInputReader input(data, size);
+ BinaryOutputWriter output(data, max_size);
+ return MutateMessage(seed, input, &output, message);
+}
+
+size_t CrossOverBinaryMessages(const uint8_t* data1, size_t size1,
+ const uint8_t* data2, size_t size2, uint8_t* out,
+ size_t max_out_size, unsigned int seed,
+ protobuf::Message* message1,
+ protobuf::Message* message2) {
+ BinaryInputReader input1(data1, size1);
+ BinaryInputReader input2(data2, size2);
+ BinaryOutputWriter output(out, max_out_size);
+ return CrossOverMessages(seed, input1, input2, &output, message1, message2);
+}
+
+} // namespace
+
+size_t CustomProtoMutator(bool binary, uint8_t* data, size_t size,
+ size_t max_size, unsigned int seed,
+ protobuf::Message* input) {
+ auto mutate = binary ? &MutateBinaryMessage : &MutateTextMessage;
+ return mutate(data, size, max_size, seed, input);
+}
+
+size_t CustomProtoCrossOver(bool binary, const uint8_t* data1, size_t size1,
+ const uint8_t* data2, size_t size2, uint8_t* out,
+ size_t max_out_size, unsigned int seed,
+ protobuf::Message* input1,
+ protobuf::Message* input2) {
+ auto cross = binary ? &CrossOverBinaryMessages : &CrossOverTextMessages;
+ return cross(data1, size1, data2, size2, out, max_out_size, seed, input1,
+ input2);
+}
+
+bool LoadProtoInput(bool binary, const uint8_t* data, size_t size,
+ protobuf::Message* input) {
+ if (GetCache()->LoadIfSame(data, size, input)) return true;
+ auto result = binary ? ParseBinaryMessage(data, size, input)
+ : ParseTextMessage(data, size, input);
+ if (!result) return false;
+ GetMutator()->Seed(size);
+ GetMutator()->Fix(input);
+ return true;
+}
+
+void RegisterPostProcessor(
+ const protobuf::Descriptor* desc,
+ std::function<void(protobuf::Message* message, unsigned int seed)>
+ callback) {
+ GetMutator()->RegisterPostProcessor(desc, callback);
+}
+
+} // namespace libfuzzer
+} // namespace protobuf_mutator
diff --git a/contrib/libs/protobuf-mutator/src/libfuzzer/libfuzzer_macro.h b/contrib/libs/protobuf-mutator/src/libfuzzer/libfuzzer_macro.h
new file mode 100644
index 0000000000..1a1fe0a297
--- /dev/null
+++ b/contrib/libs/protobuf-mutator/src/libfuzzer/libfuzzer_macro.h
@@ -0,0 +1,129 @@
+// Copyright 2017 Google Inc. All rights reserved.
+//
+// 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
+//
+// http://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.
+
+#ifndef SRC_LIBFUZZER_LIBFUZZER_MACRO_H_
+#define SRC_LIBFUZZER_LIBFUZZER_MACRO_H_
+
+#include <stddef.h>
+
+#include <cstdint>
+#include <functional>
+#include <type_traits>
+
+#include "port/protobuf.h"
+
+// Defines custom mutator, crossover and test functions using default
+// serialization format. Default is text.
+#define DEFINE_PROTO_FUZZER(arg) DEFINE_TEXT_PROTO_FUZZER(arg)
+// Defines custom mutator, crossover and test functions using text
+// serialization. This format is more convenient to read.
+#define DEFINE_TEXT_PROTO_FUZZER(arg) DEFINE_PROTO_FUZZER_IMPL(false, arg)
+// Defines custom mutator, crossover and test functions using binary
+// serialization. This makes mutations faster. However often test function is
+// significantly slower than mutator, so fuzzing rate may stay unchanged.
+#define DEFINE_BINARY_PROTO_FUZZER(arg) DEFINE_PROTO_FUZZER_IMPL(true, arg)
+
+// Registers the callback as a potential mutation performed on the parent
+// message of a field. This must be called inside an initialization code block.
+// libFuzzer suggests putting one-time-initialization in a function used to
+// initialize a static variable inside the fuzzer target. For example:
+//
+// static bool Modify(
+// SomeMessage* message /* Fix or additionally modify the message */,
+// unsigned int seed /* If random generator is needed use this seed */) {
+// ...
+// }
+//
+// DEFINE_PROTO_FUZZER(const SomeMessage& msg) {
+// static PostProcessorRegistration reg(&Modify);
+// }
+
+// Implementation of macros above.
+#define DEFINE_CUSTOM_PROTO_MUTATOR_IMPL(use_binary, Proto) \
+ extern "C" size_t LLVMFuzzerCustomMutator( \
+ uint8_t* data, size_t size, size_t max_size, unsigned int seed) { \
+ using protobuf_mutator::libfuzzer::CustomProtoMutator; \
+ Proto input; \
+ return CustomProtoMutator(use_binary, data, size, max_size, seed, &input); \
+ }
+
+#define DEFINE_CUSTOM_PROTO_CROSSOVER_IMPL(use_binary, Proto) \
+ extern "C" size_t LLVMFuzzerCustomCrossOver( \
+ const uint8_t* data1, size_t size1, const uint8_t* data2, size_t size2, \
+ uint8_t* out, size_t max_out_size, unsigned int seed) { \
+ using protobuf_mutator::libfuzzer::CustomProtoCrossOver; \
+ Proto input1; \
+ Proto input2; \
+ return CustomProtoCrossOver(use_binary, data1, size1, data2, size2, out, \
+ max_out_size, seed, &input1, &input2); \
+ }
+
+#define DEFINE_TEST_ONE_PROTO_INPUT_IMPL(use_binary, Proto) \
+ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { \
+ using protobuf_mutator::libfuzzer::LoadProtoInput; \
+ Proto input; \
+ if (LoadProtoInput(use_binary, data, size, &input)) \
+ TestOneProtoInput(input); \
+ return 0; \
+ }
+
+#define DEFINE_POST_PROCESS_PROTO_MUTATION_IMPL(Proto) \
+ using PostProcessorRegistration = \
+ protobuf_mutator::libfuzzer::PostProcessorRegistration<Proto>;
+
+#define DEFINE_PROTO_FUZZER_IMPL(use_binary, arg) \
+ static void TestOneProtoInput(arg); \
+ using FuzzerProtoType = std::remove_const<std::remove_reference< \
+ std::function<decltype(TestOneProtoInput)>::argument_type>::type>::type; \
+ DEFINE_CUSTOM_PROTO_MUTATOR_IMPL(use_binary, FuzzerProtoType) \
+ DEFINE_CUSTOM_PROTO_CROSSOVER_IMPL(use_binary, FuzzerProtoType) \
+ DEFINE_TEST_ONE_PROTO_INPUT_IMPL(use_binary, FuzzerProtoType) \
+ DEFINE_POST_PROCESS_PROTO_MUTATION_IMPL(FuzzerProtoType) \
+ static void TestOneProtoInput(arg)
+
+namespace protobuf_mutator {
+namespace libfuzzer {
+
+size_t CustomProtoMutator(bool binary, uint8_t* data, size_t size,
+ size_t max_size, unsigned int seed,
+ protobuf::Message* input);
+size_t CustomProtoCrossOver(bool binary, const uint8_t* data1, size_t size1,
+ const uint8_t* data2, size_t size2, uint8_t* out,
+ size_t max_out_size, unsigned int seed,
+ protobuf::Message* input1,
+ protobuf::Message* input2);
+bool LoadProtoInput(bool binary, const uint8_t* data, size_t size,
+ protobuf::Message* input);
+
+void RegisterPostProcessor(
+ const protobuf::Descriptor* desc,
+ std::function<void(protobuf::Message* message, unsigned int seed)>
+ callback);
+
+template <class Proto>
+struct PostProcessorRegistration {
+ PostProcessorRegistration(
+ const std::function<void(Proto* message, unsigned int seed)>& callback) {
+ RegisterPostProcessor(
+ Proto::descriptor(),
+ [callback](protobuf::Message* message, unsigned int seed) {
+ callback(static_cast<Proto*>(message), seed);
+ });
+ }
+};
+
+} // namespace libfuzzer
+} // namespace protobuf_mutator
+
+#endif // SRC_LIBFUZZER_LIBFUZZER_MACRO_H_
diff --git a/contrib/libs/protobuf-mutator/src/libfuzzer/libfuzzer_mutator.cc b/contrib/libs/protobuf-mutator/src/libfuzzer/libfuzzer_mutator.cc
new file mode 100644
index 0000000000..9c3be921e6
--- /dev/null
+++ b/contrib/libs/protobuf-mutator/src/libfuzzer/libfuzzer_mutator.cc
@@ -0,0 +1,100 @@
+// Copyright 2017 Google Inc. All rights reserved.
+//
+// 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
+//
+// http://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.
+
+#include "src/libfuzzer/libfuzzer_mutator.h"
+
+#include <string.h>
+
+#include <algorithm>
+#include <cassert>
+#include <memory>
+#include <string>
+
+#include "port/protobuf.h"
+#include "src/mutator.h"
+
+// see compiler-rt/lib/sanitizer-common/sanitizer_internal_defs.h; usage same as
+// SANITIZER_INTERFACE_WEAK_DEF with some functionality removed
+#ifdef _MSC_VER
+#if defined(_M_IX86) || defined(__i386__)
+#define WIN_SYM_PREFIX "_"
+#else
+#define WIN_SYM_PREFIX
+#endif
+
+#define STRINGIFY_(A) #A
+#define STRINGIFY(A) STRINGIFY_(A)
+
+#define WEAK_DEFAULT_NAME(Name) Name##__def
+
+// clang-format off
+#define LIB_PROTO_MUTATOR_WEAK_DEF(ReturnType, Name, ...) \
+ __pragma(comment(linker, "/alternatename:" \
+ WIN_SYM_PREFIX STRINGIFY(Name) "=" \
+ WIN_SYM_PREFIX STRINGIFY(WEAK_DEFAULT_NAME(Name))))\
+ extern "C" ReturnType Name(__VA_ARGS__); \
+ extern "C" ReturnType WEAK_DEFAULT_NAME(Name)(__VA_ARGS__)
+// clang-format on
+#else
+#define LIB_PROTO_MUTATOR_WEAK_DEF(ReturnType, Name, ...) \
+ extern "C" __attribute__((weak)) ReturnType Name(__VA_ARGS__)
+#endif
+
+LIB_PROTO_MUTATOR_WEAK_DEF(size_t, LLVMFuzzerMutate, uint8_t*, size_t, size_t) {
+ return 0;
+}
+
+namespace protobuf_mutator {
+namespace libfuzzer {
+
+namespace {
+
+template <class T>
+T MutateValue(T v) {
+ size_t size =
+ LLVMFuzzerMutate(reinterpret_cast<uint8_t*>(&v), sizeof(v), sizeof(v));
+ memset(reinterpret_cast<uint8_t*>(&v) + size, 0, sizeof(v) - size);
+ return v;
+}
+
+} // namespace
+
+int32_t Mutator::MutateInt32(int32_t value) { return MutateValue(value); }
+
+int64_t Mutator::MutateInt64(int64_t value) { return MutateValue(value); }
+
+uint32_t Mutator::MutateUInt32(uint32_t value) { return MutateValue(value); }
+
+uint64_t Mutator::MutateUInt64(uint64_t value) { return MutateValue(value); }
+
+float Mutator::MutateFloat(float value) { return MutateValue(value); }
+
+double Mutator::MutateDouble(double value) { return MutateValue(value); }
+
+TProtoStringType Mutator::MutateString(const TProtoStringType& value,
+ int size_increase_hint) {
+ // Randomly return empty strings as LLVMFuzzerMutate does not produce them.
+ // Use uint16_t because on Windows, uniform_int_distribution does not support
+ // any 8 bit types.
+ if (!std::uniform_int_distribution<uint16_t>(0, 20)(*random())) return {};
+ TProtoStringType result = value;
+ int new_size = value.size() + size_increase_hint;
+ result.resize(std::max(1, new_size));
+ result.resize(LLVMFuzzerMutate(reinterpret_cast<uint8_t*>(&result[0]),
+ value.size(), result.size()));
+ return result;
+}
+
+} // namespace libfuzzer
+} // namespace protobuf_mutator
diff --git a/contrib/libs/protobuf-mutator/src/libfuzzer/libfuzzer_mutator.h b/contrib/libs/protobuf-mutator/src/libfuzzer/libfuzzer_mutator.h
new file mode 100644
index 0000000000..722993efe8
--- /dev/null
+++ b/contrib/libs/protobuf-mutator/src/libfuzzer/libfuzzer_mutator.h
@@ -0,0 +1,46 @@
+// Copyright 2017 Google Inc. All rights reserved.
+//
+// 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
+//
+// http://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.
+
+#ifndef SRC_LIBFUZZER_LIBFUZZER_MUTATOR_H_
+#define SRC_LIBFUZZER_LIBFUZZER_MUTATOR_H_
+
+#include <string>
+
+#include "src/mutator.h"
+
+namespace protobuf_mutator {
+namespace libfuzzer {
+
+// Overrides protobuf_mutator::Mutator::Mutate* methods with implementation
+// which uses libFuzzer library. protobuf_mutator::Mutator has very basic
+// implementation of this methods.
+class Mutator : public protobuf_mutator::Mutator {
+ public:
+ using protobuf_mutator::Mutator::Mutator;
+
+ protected:
+ int32_t MutateInt32(int32_t value) override;
+ int64_t MutateInt64(int64_t value) override;
+ uint32_t MutateUInt32(uint32_t value) override;
+ uint64_t MutateUInt64(uint64_t value) override;
+ float MutateFloat(float value) override;
+ double MutateDouble(double value) override;
+ TProtoStringType MutateString(const TProtoStringType& value,
+ int size_increase_hint) override;
+};
+
+} // namespace libfuzzer
+} // namespace protobuf_mutator
+
+#endif // SRC_LIBFUZZER_LIBFUZZER_MUTATOR_H_