Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wide integer fuzzing #424

Merged
merged 4 commits into from
Sep 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions .github/workflows/wide_integer_fuzzing.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# ------------------------------------------------------------------------------
# Copyright Christopher Kormanyos 2024.
# Distributed under the Boost Software License,
# Version 1.0. (See accompanying file LICENSE_1_0.txt
# or copy at http://www.boost.org/LICENSE_1_0.txt)
# ------------------------------------------------------------------------------

name: wide_integer_fuzzing
on:
push:
branches:
- '**'
pull_request:
schedule:
- cron: '15 2 * * *' # run at 2:15 AM UTC
jobs:
clang-fuzzing:
runs-on: ubuntu-latest
defaults:
run:
shell: bash
strategy:
fail-fast: false
matrix:
tcase: [ add, sub, mul, div ]
steps:
- uses: actions/checkout@v4
with:
fetch-depth: '0'
- name: update-tools
run: sudo apt install llvm lld
- name: clone-submods-bootstrap-headers-boost-develop
run: |
git clone -b develop --depth 1 https://github.com/boostorg/boost.git ../boost-root
cd ../boost-root
git submodule update --init tools
git submodule update --init libs/config
git submodule update --init libs/multiprecision
./bootstrap.sh
./b2 headers
- name: clang-fuzzing
run: |
grep BOOST_VERSION ../boost-root/boost/version.hpp
echo "compile and instrument fuzzing test"
clang++ -v
clang++ -g -O2 -fsanitize=fuzzer,address,undefined -I. -I../boost-root test/fuzzing/test_fuzzing_${{ matrix.tcase }}.cpp -o test_fuzzing_${{ matrix.tcase }}
echo "ls test_fuzzing_${{ matrix.tcase }}"
ls -la test_fuzzing_${{ matrix.tcase }}
./test_fuzzing_${{ matrix.tcase }} -max_total_time=240
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
<p align="center">
<a href="https://github.com/ckormanyos/wide-integer/actions">
<img src="https://github.com/ckormanyos/wide-integer/actions/workflows/wide_integer.yml/badge.svg" alt="Build Status"></a>
<a href="https://github.com/ckormanyos/wide-integer/actions">
<img src="https://github.com/ckormanyos/wide-integer/actions/workflows/wide_integer_fuzzing.yml/badge.svg" alt="Build Status"></a>
<a href="https://github.com/ckormanyos/wide-integer/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc">
<img src="https://custom-icon-badges.herokuapp.com/github/issues-raw/ckormanyos/wide-integer?logo=github" alt="Issues" /></a>
<a href="https://github.com/ckormanyos/wide-integer/actions?query=workflow%3ACodeQL">
Expand Down Expand Up @@ -340,6 +342,8 @@ as well as in offline checks to improve static code quality.
GCC's run-time
[sanitizers](https://gcc.gnu.org/onlinedocs/gcc/Instrumentation-Options.html)
are used in CI in order to help assure dynamic quality.
This effort also includes _fuzzing_ with
[libFuzzer](https://llvm.org/docs/LibFuzzer.html).

Additional quality checks are performed on pull-request
and merge to master using modern third party open-source services.
Expand Down
127 changes: 127 additions & 0 deletions test/fuzzing/test_fuzzing_add.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright Christopher Kormanyos 2024.
// Distributed under the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
//

// cd /mnt/c/Users/ckorm/Documents/Ks/PC_Software/NumericalPrograms/ExtendedNumberTypes/wide_integer
// clang++ -g -O2 -fsanitize=fuzzer,address,undefined -I. -I/mnt/c/boost/boost_1_85_0 test/fuzzing/test_fuzzing_add.cpp -o test_fuzzing_add
// ./test_fuzzing_add -max_total_time=180

#include <math/wide_integer/uintwide_t.h>

#include <boost/multiprecision/cpp_int.hpp>

#include <algorithm>
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <vector>

namespace fuzzing
{
using boost_uint_backend_type =
boost::multiprecision::cpp_int_backend<static_cast<unsigned>(UINT32_C(256)),
static_cast<unsigned>(UINT32_C(256)),
boost::multiprecision::unsigned_magnitude>;

using boost_uint_type = boost::multiprecision::number<boost_uint_backend_type,
boost::multiprecision::et_off>;

using local_uint_type = ::math::wide_integer::uint256_t;

auto eval_add(const std::uint8_t* data, std::size_t size) -> bool;
}

auto fuzzing::eval_add(const std::uint8_t* data, std::size_t size) -> bool
{
const std::size_t
max_size
{
static_cast<std::size_t>
(
std::numeric_limits<fuzzing::local_uint_type>::digits / 8
)
};

bool result_is_ok { true };

if((size > std::size_t { UINT8_C(1) }) && (size <= std::size_t { max_size * 2U }))
{
local_uint_type a_local { };
local_uint_type b_local { };

boost_uint_type a_boost { };
boost_uint_type b_boost { };

// Import data into their respective uintwide_t a and b values.
import_bits
(
a_local,
data,
data + std::size_t { size / 2U },
8U
);

import_bits
(
b_local,
data + std::size_t { size / 2U },
data + size,
8U
);

// Import data into their respective boost-based a and b values.
import_bits
(
a_boost,
data,
data + std::size_t { size / 2U },
8U
);

import_bits
(
b_boost,
data + std::size_t { size / 2U },
data + size,
8U
);

local_uint_type result_local { a_local + b_local };
boost_uint_type result_boost { a_boost + b_boost };

std::vector<std::uint8_t> result_data_local(max_size, UINT8_C(0));
std::vector<std::uint8_t> result_data_boost(result_data_local.size(), UINT8_C(0));

export_bits(result_local, result_data_local.data(), 8U);
export_bits(result_boost, result_data_boost.data(), 8U);

// Verify that both uintwide_t as well as boost obtain the same result.
const bool result_add_is_ok =
std::equal
(
result_data_local.cbegin(),
result_data_local.cend(),
result_data_boost.cbegin(),
result_data_boost.cend()
);

result_is_ok = (result_add_is_ok && result_is_ok);
}

// Assert the correct result.
assert(result_is_ok);

return result_is_ok;
}

// The fuzzing entry point.
extern "C"
int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
{
const bool result_one_add_is_ok { fuzzing::eval_add(data, size) };

return (result_one_add_is_ok ? 0 : -1);
}
136 changes: 136 additions & 0 deletions test/fuzzing/test_fuzzing_div.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
///////////////////////////////////////////////////////////////////////////////
// Copyright Christopher Kormanyos 2024.
// Distributed under the Boost Software License,
// Version 1.0. (See accompanying file LICENSE_1_0.txt
// or copy at http://www.boost.org/LICENSE_1_0.txt)
//

// cd /mnt/c/Users/ckorm/Documents/Ks/PC_Software/NumericalPrograms/ExtendedNumberTypes/wide_integer
// clang++ -g -O2 -fsanitize=fuzzer,address,undefined -I. -I/mnt/c/boost/boost_1_85_0 test/fuzzing/test_fuzzing_div.cpp -o test_fuzzing_div
// ./test_fuzzing_div -max_total_time=180

#include <math/wide_integer/uintwide_t.h>

#include <boost/multiprecision/cpp_int.hpp>

#include <algorithm>
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <vector>

namespace fuzzing
{
using boost_uint_backend_type =
boost::multiprecision::cpp_int_backend<static_cast<unsigned>(UINT32_C(256)),
static_cast<unsigned>(UINT32_C(256)),
boost::multiprecision::unsigned_magnitude>;

using boost_uint_type = boost::multiprecision::number<boost_uint_backend_type,
boost::multiprecision::et_off>;

using local_uint_type = ::math::wide_integer::uint256_t;

auto eval_div(const std::uint8_t* data, std::size_t size) -> bool;
}

auto fuzzing::eval_div(const std::uint8_t* data, std::size_t size) -> bool
{
const std::size_t
max_size
{
static_cast<std::size_t>
(
std::numeric_limits<fuzzing::local_uint_type>::digits / 8
)
};

bool result_is_ok { true };

if((size > std::size_t { UINT8_C(1) }) && (size <= std::size_t { max_size * 2U }))
{
local_uint_type a_local { };
local_uint_type b_local { };

boost_uint_type a_boost { };
boost_uint_type b_boost { };

// Import data into their respective uintwide_t a and b values.
import_bits
(
a_local,
data,
data + std::size_t { size / 2U },
8U
);

import_bits
(
b_local,
data + std::size_t { size / 2U },
data + size,
8U
);

// Import data into their respective boost-based a and b values.
import_bits
(
a_boost,
data,
data + std::size_t { size / 2U },
8U
);

import_bits
(
b_boost,
data + std::size_t { size / 2U },
data + size,
8U
);

if(a_local < b_local)
{
std::swap(a_local, b_local);
std::swap(a_boost, b_boost);
}

if(b_local != 0U)
{
local_uint_type result_local { a_local / b_local };
boost_uint_type result_boost { a_boost / b_boost };

std::vector<std::uint8_t> result_data_local(max_size, UINT8_C(0));
std::vector<std::uint8_t> result_data_boost(result_data_local.size(), UINT8_C(0));

export_bits(result_local, result_data_local.data(), 8U);
export_bits(result_boost, result_data_boost.data(), 8U);

// Verify that both uintwide_t as well as boost obtain the same result.
const bool result_div_is_ok =
std::equal
(
result_data_local.cbegin(),
result_data_local.cend(),
result_data_boost.cbegin(),
result_data_boost.cend()
);

result_is_ok = (result_div_is_ok && result_is_ok);
}
}

// Assert the correct result.
assert(result_is_ok);

return result_is_ok;
}

// The fuzzing entry point.
extern "C"
int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
{
const bool result_one_div_is_ok { fuzzing::eval_div(data, size) };

return (result_one_div_is_ok ? 0 : -1);
}
Loading