src/fuzzers/cpp/PatternLayoutFuzzer.cpp (80 lines of code) (raw):
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 <iostream> // for `cout`, `endl`
#include <cstdlib> // for `exit()`, `EXIT_FAILURE`
#include <unistd.h> // for `readlink`, `chdir`
#include <libgen.h> // for `dirname`
#include <limits.h> // for `PATH_MAX`
#include <iomanip> // for `put_time()`
#include <ctime> // for `time()`
#include <fuzzer/FuzzedDataProvider.h>
#include <log4cxx/propertyconfigurator.h>
#include <log4cxx/appenderskeleton.h>
using namespace LOG4CXX_NS;
namespace LOG4CXX_NS::fuzzer {
/**
* Appender encoding incoming log events using the provided layout.
* It is intended for appender-agnostic fuzzing.
*/
class EncodingAppender : public AppenderSkeleton {
public:
DECLARE_LOG4CXX_OBJECT(EncodingAppender)
BEGIN_LOG4CXX_CAST_MAP()
LOG4CXX_CAST_ENTRY(EncodingAppender)
LOG4CXX_CAST_ENTRY_CHAIN(AppenderSkeleton)
END_LOG4CXX_CAST_MAP()
EncodingAppender() : AppenderSkeleton() {}
EncodingAppender(const LayoutPtr& layout) : AppenderSkeleton(layout) {}
void close() override {}
bool requiresLayout() const override {
return true;
}
void append(const spi::LoggingEventPtr& event, helpers::Pool& pool) override {
LogString msg;
getLayout()->format(msg, event, pool);
}
void activateOptions(helpers::Pool& pool) override {}
void setOption(const LogString& option, const LogString& value) override {}
}; // class
IMPLEMENT_LOG4CXX_OBJECT(EncodingAppender)
LOG4CXX_PTR_DEF(EncodingAppender);
} // namespace
static std::time_t logTime;
static std::tm* logTimeBuffer;
#define LOG(stream) \
logTime = std::time(nullptr); \
logTimeBuffer = std::localtime(&logTime); \
stream << std::put_time(logTimeBuffer, "%Y-%m-%d %H:%M:%S") << " [" << __FILE_NAME__ << ":" << __LINE__ << "] "
static void findExecutablePath(char* buffer) {
ssize_t length = readlink("/proc/self/exe", buffer, PATH_MAX);
if (length == -1) {
LOG(std::cerr) << "ERROR: Failed to find the executable path" << std::endl;
exit(EXIT_FAILURE);
}
buffer[length] = '\0';
}
static void chdirExecutableHome() {
char executablePath[PATH_MAX];
findExecutablePath(executablePath);
char* executableHome = dirname(executablePath);
if (chdir(executableHome) != 0) {
LOG(std::cerr) << "DEBUG: Executable path: " << executablePath << std::endl;
LOG(std::cerr) << "DEBUG: Executable home: " << executableHome << std::endl;
LOG(std::cerr) << "ERROR: Failed to `chdir()` the executable path" << std::endl;
}
}
static int INITIALIZED = 0;
static void init() {
if (INITIALIZED != 0) {
return;
}
LOG(std::cout) << "INFO: Produced using the Git commit ID: " << GIT_COMMIT_ID << std::endl;
chdirExecutableHome();
PropertyConfigurator::configure("PatternLayoutFuzzer.properties");
INITIALIZED = 1;
}
#define MAX_STRING_LENGTH 512
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
init();
LoggerPtr logger = Logger::getRootLogger();
FuzzedDataProvider dataProvider(data, size);
while (dataProvider.remaining_bytes() > 0) {
std::string message = dataProvider.ConsumeRandomLengthString(MAX_STRING_LENGTH);
LOG4CXX_INFO(logger, message);
}
return 0;
}