forked from OSchip/llvm-project
[clang-fuzzer] Add new fuzzer target for Objective-C
Summary: - Similar to that of `clang-fuzzer` itself but instead only targets Objective-C source files via cc1 - Also adds an example corpus directory containing some input for Objective-C Subscribers: mgorny, jfb, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D69171 llvm-svn: 375453
This commit is contained in:
parent
6f0ae81512
commit
e5ecba4f53
|
@ -12,6 +12,7 @@ endif()
|
|||
# Needed by LLVM's CMake checks because this file defines multiple targets.
|
||||
set(LLVM_OPTIONAL_SOURCES
|
||||
ClangFuzzer.cpp
|
||||
ClangObjectiveCFuzzer.cpp
|
||||
DummyClangFuzzer.cpp
|
||||
ExampleClangProtoFuzzer.cpp
|
||||
ExampleClangLoopProtoFuzzer.cpp
|
||||
|
@ -120,3 +121,15 @@ target_link_libraries(clang-fuzzer
|
|||
${LLVM_LIB_FUZZING_ENGINE}
|
||||
clangHandleCXX
|
||||
)
|
||||
|
||||
add_clang_executable(clang-objc-fuzzer
|
||||
EXCLUDE_FROM_ALL
|
||||
${DUMMY_MAIN}
|
||||
ClangObjectiveCFuzzer.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(clang-objc-fuzzer
|
||||
PRIVATE
|
||||
${LLVM_LIB_FUZZING_ENGINE}
|
||||
clangHandleCXX
|
||||
)
|
||||
|
|
|
@ -20,6 +20,6 @@ extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) { return 0; }
|
|||
|
||||
extern "C" int LLVMFuzzerTestOneInput(uint8_t *data, size_t size) {
|
||||
std::string s((const char *)data, size);
|
||||
HandleCXX(s, {"-O2"});
|
||||
HandleCXX(s, "./test.cc", {"-O2"});
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
//===-- ClangObjectiveCFuzzer.cpp - Fuzz Clang ----------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
///
|
||||
/// \file
|
||||
/// This file implements a function that runs Clang on a single Objective-C
|
||||
/// input. This function is then linked into the Fuzzer library.
|
||||
///
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "handle-cxx/handle_cxx.h"
|
||||
|
||||
using namespace clang_fuzzer;
|
||||
|
||||
extern "C" int LLVMFuzzerTestOneInput(uint8_t *data, size_t size) {
|
||||
std::string s(reinterpret_cast<const char *>(data), size);
|
||||
HandleCXX(s, "./test.m", {"-O2"});
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -32,6 +32,7 @@ RUN mkdir build1 && cd build1 && cmake -GNinja -DCMAKE_BUILD_TYPE=Release ../llv
|
|||
-DLLVM_USE_SANITIZER=Address -DCLANG_ENABLE_PROTO_FUZZER=ON
|
||||
# Build the fuzzers
|
||||
RUN cd build1 && ninja clang-fuzzer
|
||||
RUN cd build1 && ninja clang-objc-fuzzer
|
||||
RUN cd build1 && ninja clang-proto-fuzzer
|
||||
RUN cd build1 && ninja clang-proto-to-cxx
|
||||
RUN cd build1 && ninja clang-loop-proto-to-cxx
|
||||
|
|
|
@ -1,15 +1,21 @@
|
|||
This directory contains two utilities for fuzzing Clang: clang-fuzzer and
|
||||
clang-proto-fuzzer. Both use libFuzzer to generate inputs to clang via
|
||||
coverage-guided mutation.
|
||||
This directory contains three utilities for fuzzing Clang: clang-fuzzer,
|
||||
clang-objc-fuzzer, and clang-proto-fuzzer. All use libFuzzer to generate inputs
|
||||
to clang via coverage-guided mutation.
|
||||
|
||||
The two utilities differ, however, in how they structure inputs to Clang.
|
||||
The three utilities differ, however, in how they structure inputs to Clang.
|
||||
clang-fuzzer makes no attempt to generate valid C++ programs and is therefore
|
||||
primarily useful for stressing the surface layers of Clang (i.e. lexer, parser).
|
||||
|
||||
clang-objc-fuzzer is similar but for Objective-C: it makes no attempt to
|
||||
generate a valid Objective-C program.
|
||||
|
||||
clang-proto-fuzzer uses a protobuf class to describe a subset of the C++
|
||||
language and then uses libprotobuf-mutator to mutate instantiations of that
|
||||
class, producing valid C++ programs in the process. As a result,
|
||||
clang-proto-fuzzer is better at stressing deeper layers of Clang and LLVM.
|
||||
|
||||
Some of the fuzzers have example corpuses inside the corpus_examples directory.
|
||||
|
||||
===================================
|
||||
Building clang-fuzzer
|
||||
===================================
|
||||
|
@ -35,6 +41,35 @@ Example:
|
|||
bin/clang-fuzzer CORPUS_DIR
|
||||
|
||||
|
||||
===================================
|
||||
Building clang-objc-fuzzer
|
||||
===================================
|
||||
Within your LLVM build directory, run CMake with the following variable
|
||||
definitions:
|
||||
- CMAKE_C_COMPILER=clang
|
||||
- CMAKE_CXX_COMPILER=clang++
|
||||
- LLVM_USE_SANITIZE_COVERAGE=YES
|
||||
- LLVM_USE_SANITIZER=Address
|
||||
|
||||
Then build the clang-objc-fuzzer target.
|
||||
|
||||
Example:
|
||||
cd $LLVM_SOURCE_DIR
|
||||
mkdir build && cd build
|
||||
cmake .. -GNinja -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ \
|
||||
-DLLVM_USE_SANITIZE_COVERAGE=YES -DLLVM_USE_SANITIZER=Address
|
||||
ninja clang-objc-fuzzer
|
||||
|
||||
======================
|
||||
Running clang-objc-fuzzer
|
||||
======================
|
||||
bin/clang-objc-fuzzer CORPUS_DIR
|
||||
|
||||
e.g. using the example objc corpus,
|
||||
|
||||
bin/clang-objc-fuzzer <path to corpus_examples/objc> <path to new directory to store corpus findings>
|
||||
|
||||
|
||||
=======================================================
|
||||
Building clang-proto-fuzzer (Linux-only instructions)
|
||||
=======================================================
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
@interface RootObject
|
||||
@end
|
||||
|
||||
@interface BasicClass : RootObject {
|
||||
int _foo;
|
||||
char _boolean;
|
||||
}
|
||||
|
||||
@property(nonatomic, assign) int bar;
|
||||
@property(atomic, retain) id objectField;
|
||||
@property(nonatomic, assign) id delegate;
|
||||
|
||||
- (void)someMethod;
|
||||
@end
|
||||
|
||||
@implementation BasicClass
|
||||
|
||||
@synthesize bar = _bar;
|
||||
@synthesize objectField = _objectField;
|
||||
@synthesize delegate = _delegate;
|
||||
|
||||
- (void)someMethod {
|
||||
int value = self.bar;
|
||||
_foo = (_boolean != 0) ? self.bar : [self.objectField bar];
|
||||
[self setBar:value];
|
||||
id obj = self.objectField;
|
||||
}
|
||||
@end
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
@interface RootObject
|
||||
@end
|
||||
|
||||
@interface BaseClass : RootObject
|
||||
@property(atomic, assign, readonly) int field;
|
||||
@end
|
||||
|
||||
@interface BaseClass(Private)
|
||||
@property(atomic, assign, readwrite) int field;
|
||||
|
||||
- (int)something;
|
||||
@end
|
||||
|
||||
@implementation BaseClass
|
||||
- (int)something {
|
||||
self.field = self.field + 1;
|
||||
return self.field;
|
||||
}
|
||||
@end
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
@interface RootObject
|
||||
@end
|
||||
|
||||
@interface BaseClass : RootObject
|
||||
@end
|
||||
|
||||
@interface BaseClass() {
|
||||
int _field1;
|
||||
}
|
||||
@property(atomic, assign, readonly) int field2;
|
||||
|
||||
- (int)addFields;
|
||||
@end
|
||||
|
||||
@implementation BaseClass
|
||||
- (int)addFields {
|
||||
return self->_field1 + [self field2];
|
||||
}
|
||||
@end
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
@interface RootObject
|
||||
+ (instancetype)alloc;
|
||||
|
||||
- (instancetype)init;
|
||||
@end
|
||||
|
||||
@interface BaseClass : RootObject
|
||||
+ (instancetype)sharedInstance;
|
||||
|
||||
- (instancetype)initWithFoo:(int)foo;
|
||||
@end
|
||||
|
||||
static BaseClass *sharedInstance = (void *)0;
|
||||
static int counter = 0;
|
||||
|
||||
@implementation BaseClass
|
||||
+ (instancetype)sharedInstance {
|
||||
if (sharedInstance) {
|
||||
return sharedInstance;
|
||||
}
|
||||
sharedInstance = [[BaseClass alloc] initWithFoo:3];
|
||||
return sharedInstance;
|
||||
}
|
||||
|
||||
|
||||
- (instancetype)initWithFoo:(int)foo {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
counter += foo;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@end
|
||||
|
|
@ -21,12 +21,13 @@
|
|||
using namespace clang;
|
||||
|
||||
void clang_fuzzer::HandleCXX(const std::string &S,
|
||||
const char *FileName,
|
||||
const std::vector<const char *> &ExtraArgs) {
|
||||
llvm::opt::ArgStringList CC1Args;
|
||||
CC1Args.push_back("-cc1");
|
||||
for (auto &A : ExtraArgs)
|
||||
CC1Args.push_back(A);
|
||||
CC1Args.push_back("./test.cc");
|
||||
CC1Args.push_back(FileName);
|
||||
|
||||
llvm::IntrusiveRefCntPtr<FileManager> Files(
|
||||
new FileManager(FileSystemOptions()));
|
||||
|
@ -39,7 +40,7 @@ void clang_fuzzer::HandleCXX(const std::string &S,
|
|||
tooling::newInvocation(&Diagnostics, CC1Args));
|
||||
std::unique_ptr<llvm::MemoryBuffer> Input =
|
||||
llvm::MemoryBuffer::getMemBuffer(S);
|
||||
Invocation->getPreprocessorOpts().addRemappedFile("./test.cc",
|
||||
Invocation->getPreprocessorOpts().addRemappedFile(FileName,
|
||||
Input.release());
|
||||
std::unique_ptr<tooling::ToolAction> action(
|
||||
tooling::newFrontendActionFactory<clang::EmitObjAction>());
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
|
||||
namespace clang_fuzzer {
|
||||
void HandleCXX(const std::string &S,
|
||||
const char *FileName,
|
||||
const std::vector<const char *> &ExtraArgs);
|
||||
} // namespace clang_fuzzer
|
||||
|
||||
|
|
Loading…
Reference in New Issue