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

Add clang sanitizers #20

Merged
merged 13 commits into from
Nov 27, 2024
38 changes: 38 additions & 0 deletions .github/workflows/clang-sanitizers-linux-nix-check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
name: Build and Test sanitizers on Linux with clang

on:
workflow_call:

jobs:
build-and-test:
name: "Build and test Linux with clang"
runs-on: [self-hosted, Linux, X64, aws_autoscaling]
continue-on-error: true
steps:
# https://github.com/actions/checkout/issues/1552
- name: Clean up after previous checkout
run: chmod +w -R ${GITHUB_WORKSPACE}; rm -rf ${GITHUB_WORKSPACE}/*;

- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0

- name: Run checks
run: |
nix build -L .?#checks.x86_64-linux.all-clang-sanitize
mkdir results
cp result/test-logs/*_test.xml results/
continue-on-error: true
env:
NIX_CONFIG: |
cores = 4

- name: Publish Test Results
uses: EnricoMi/publish-unit-test-result-action/linux@v2
with:
check_name: "Sanitizers Test Results"
files: "results/*.xml"
comment_mode: ${{ github.event.pull_request.head.repo.fork && 'off' || 'always' }} # Don't create PR comment from fork runs
action_fail_on_inconclusive: true # fail, if no reports

45 changes: 45 additions & 0 deletions .github/workflows/nightly.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
name: Nightly Testing

on:
schedule:
- cron: '0 0 * * *'

jobs:
test-linux-sanitizers:
name: Linux placeholder testing and sanitize with clang
uses: ./.github/workflows/clang-sanitizers-linux-nix-check.yml
if: |
always() && !cancelled()
secrets: inherit

post-telemetry:
name: Post test results in Open Telemetry format
runs-on: [self-hosted, Linux, X64, aws_autoscaling]
needs:
- test-linux-sanitizers
steps:
- name: Checkout
uses: actions/checkout@v3
with:
fetch-depth: 0

- name: Post logs to Sig Noz
run: |
ls -l -a
nix build -L .?#checks.x86_64-linux.all-clang-sanitize
cat ./result/test-logs/test_errors.txt
export UndefinedBehaviorSanitizer=$(grep UndefinedBehaviorSanitizer result/test-logs/test_errors.txt | wc -l)
export AddressSanitizer=$(grep AddressSanitizer result/test-logs/test_errors.txt | wc -l)
export LeakSanitizer=$(grep LeakSanitizer result/test-logs/test_errors.txt | wc -l)
export OTEL_PYTHON_LOGGING_AUTO_INSTRUMENTATION_ENABLED=true
python3 --version
sudo yum update -y
sudo yum install -y python3-pip
pip3 install -r requirements.txt
/home/ec2-user/.local/bin/opentelemetry-instrument \
--traces_exporter console,otlp \
--metrics_exporter console,otlp \
--logs_exporter console,otlp \
--service_name nightly-build \
python3 ./parse_tests.py

1 change: 0 additions & 1 deletion .github/workflows/pull-request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,4 +43,3 @@ jobs:
if: |
always() && !cancelled()
secrets: inherit

1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -626,7 +626,6 @@ callgrind.*
/*.c
/*.cpp
/*.h
/*.py
/*.key
/*.pem
/*.der
Expand Down
4 changes: 3 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
add_compile_options (-fcolor-diagnostics)
endif ()

if(DEFINED CMAKE_BUILD_TYPE AND ${CMAKE_BUILD_TYPE} STREQUAL "Debug")
if(DEFINED CMAKE_BUILD_TYPE)
if(${CMAKE_BUILD_TYPE} STREQUAL "Debug")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0 -ggdb")
set(BOOST_FORCEINLINE "OFF") # improves debugging traces
endif()
endif()

option(SANITIZE "Build sanitizers" FALSE)
Expand Down
8 changes: 7 additions & 1 deletion crypto3.nix
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
enableDebug ? false,
runTests ? false,
sanitize ? false,
benchmarkTests ? false,
}:
let
inherit (lib) optional;
Expand All @@ -34,6 +35,7 @@ in stdenv.mkDerivation {
(if runTests then "-DBUILD_CRYPTO3_TESTS=TRUE" else "-DBUILD_CRYPTO3_TESTS=False")
(if enableDebug then "-DCMAKE_BUILD_TYPE=Debug" else "-DCMAKE_BUILD_TYPE=Release")
(if sanitize then "-DSANITIZE=ON" else "-DSANITIZE=OFF")
(if benchmarkTests then "-DBUILD_CRYPTO3_BENCH_TESTS=ON" else "-DBUILD_CRYPTO3_BENCH_TESTS=OFF")
"-G Ninja"
];

Expand All @@ -42,9 +44,13 @@ in stdenv.mkDerivation {
checkPhase = ''
# JUNIT file without explicit file name is generated after the name of the master test suite inside `CMAKE_CURRENT_SOURCE_DIR`
export BOOST_TEST_LOGGER=JUNIT:HRF
cd crypto3 && ctest --verbose --output-on-failure -R && cd ..
cd crypto3
# remove || true after all tests are fixed under clang-sanitizers check:
ctest --verbose --output-on-failure -R > test_errors.txt || true
cd ..
mkdir -p ${placeholder "out"}/test-logs
find .. -type f -name '*_test.xml' -exec cp {} ${placeholder "out"}/test-logs \;
cp crypto3/test_errors.txt ${placeholder "out"}/test-logs \
'';

shellHook = ''
Expand Down
2 changes: 1 addition & 1 deletion crypto3/benchmarks/algebra/curves.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ void benchmark_curve_operations(std::string const& curve_name)
return A *= B;
});

if constexpr (has_template_g2_type<curve_type>::value) {
if constexpr (has_type_g2_type<curve_type>::value) {
using g2_type = typename curve_type::template g2_type<>;

using g2_field = typename g2_type::field_type;
Expand Down
9 changes: 5 additions & 4 deletions crypto3/benchmarks/zk/lpc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,11 +135,12 @@ void lpc_test_case(std::size_t steps)
math::calculate_domain_set<FieldType>(extended_log, r);

typename fri_type::params_type fri_params(
d - 1,
D,
generate_random_step_list(r, steps),
steps,
r,
lambda
lambda,
2, //expand_factor
true, // use_grinding
12 // grinding_parameter
);

using lpc_scheme_type = nil::crypto3::zk::commitments::lpc_commitment_scheme<lpc_type, math::polynomial<typename FieldType::value_type>>;
Expand Down
54 changes: 49 additions & 5 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,17 @@
enableDebug = true;
runTests = true;
});
crypto3-sanitize = (pkgs.callPackage ./crypto3.nix {
enableDebug = true;
crypto3-clang-sanitize = (pkgs.callPackage ./crypto3.nix {
stdenv = pkgs.llvmPackages_19.stdenv;
runTests = true;
enableDebug = false;
sanitize = true;
});
crypto3-clang-bench = (pkgs.callPackage ./crypto3.nix {
runTests = true;
enableDebug = false;
benchmarkTests = true;
});
crypto3-clang-debug = (pkgs.callPackage ./crypto3.nix {
stdenv = pkgs.llvmPackages_19.stdenv;
runTests = false;
Expand All @@ -53,6 +59,11 @@
runTests = true;
enableDebug = false;
});
parallel-crypto3-clang-bench = (pkgs.callPackage ./parallel-crypto3.nix {
runTests = true;
enableDebug = false;
benchmarkTests = true;
});
parallel-crypto3-debug-tests = (pkgs.callPackage ./parallel-crypto3.nix {
enableDebug = true;
runTests = true;
Expand Down Expand Up @@ -90,7 +101,7 @@
# fetched from the cache.
all = pkgs.symlinkJoin {
name = "all";
paths = [ crypto3 proof-producer];
paths = [ crypto3 parallel-crypto3 proof-producer];
};
default = all;
};
Expand All @@ -100,6 +111,11 @@
runTests = true;
enableDebug = false;
});
crypto3-gcc-bench = (pkgs.callPackage ./crypto3.nix {
runTests = true;
enableDebug = false;
benchmarkTests = true;
});
crypto3-clang = (pkgs.callPackage ./crypto3.nix {
stdenv = pkgs.llvmPackages_19.stdenv;
runTests = true;
Expand All @@ -111,16 +127,38 @@
enableDebug = false;
sanitize = true;
});
crypto3-clang-bench = (pkgs.callPackage ./crypto3.nix {
stdenv = pkgs.llvmPackages_19.stdenv;
runTests = true;
enableDebug = false;
benchmarkTests = true;
});

parallel-crypto3-gcc = (pkgs.callPackage ./parallel-crypto3.nix {
runTests = true;
enableDebug = false;
benchmarkTests = true;
});
parallel-crypto3-gcc-bench = (pkgs.callPackage ./parallel-crypto3.nix {
runTests = true;
enableDebug = false;
});
parallel-crypto3-clang = (pkgs.callPackage ./parallel-crypto3.nix {
stdenv = pkgs.llvmPackages_19.stdenv;
runTests = true;
enableDebug = false;
});
parallel-crypto3-clang-sanitize = (pkgs.callPackage ./parallel-crypto3.nix {
stdenv = pkgs.llvmPackages_19.stdenv;
runTests = true;
enableDebug = false;
});
parallel-crypto3-clang-bench = (pkgs.callPackage ./parallel-crypto3.nix {
stdenv = pkgs.llvmPackages_19.stdenv;
runTests = true;
enableDebug = false;
benchmarkTests = true;
});

proof-producer-gcc = (pkgs.callPackage ./proof-producer.nix {
runTests = true;
Expand All @@ -131,14 +169,20 @@
runTests = true;
enableDebug = false;
});
proof-producer-clang-sanitize = (pkgs.callPackage ./proof-producer.nix {
stdenv = pkgs.llvmPackages_19.stdenv;
runTests = true;
enableDebug = false;
sanitize = true;
});

all-clang = pkgs.symlinkJoin {
name = "all";
paths = [ crypto3-clang parallel-crypto3-clang proof-producer-clang ];
};
all-sanitizers = pkgs.symlinkJoin {
all-clang-sanitize = pkgs.symlinkJoin {
name = "all";
paths = [ crypto3-clang-sanitize ];
paths = [ crypto3-clang-sanitize parallel-crypto3-clang-sanitize proof-producer-clang-sanitize ];
};
all-gcc = pkgs.symlinkJoin {
name = "all";
Expand Down
12 changes: 11 additions & 1 deletion parallel-crypto3.nix
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
enableDebugging,
enableDebug ? false,
runTests ? false,
sanitize? false,
benchmarkTests ? false,
}:
let
inherit (lib) optional;
Expand All @@ -32,13 +34,21 @@ in stdenv.mkDerivation {
[
(if runTests then "-DBUILD_PARALLEL_CRYPTO3_TESTS=TRUE" else "")
(if enableDebug then "-DCMAKE_BUILD_TYPE=Debug" else "-DCMAKE_BUILD_TYPE=Release")
(if sanitize then "-DSANITIZE=ON" else "-DSANITIZE=OFF")
(if benchmarkTests then "-DENABLE_BENCHMARKS=ON" else "-DENABLE_BENCHMARKS=OFF")
"-DPARALLEL_CRYPTO3_ENABLE=TRUE"
];

doCheck = runTests; # tests are inside parallel-crypto3-tests derivation

checkPhase = ''
cd parallel-crypto3 && ctest --verbose --output-on-failure -R && cd ..
# JUNIT file without explicit file name is generated after the name of the master test suite inside `CMAKE_CURRENT_SOURCE_DIR`
export BOOST_TEST_LOGGER=JUNIT:HRF
cd parallel-crypto3
ctest --verbose --output-on-failure -R
cd ..
mkdir -p ${placeholder "out"}/test-logs
find .. -type f -name '*_test.xml' -exec cp {} ${placeholder "out"}/test-logs \;
'';

shellHook = ''
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@
BOOST_AUTO_TEST_SUITE(thread_pool_test_suite)

BOOST_AUTO_TEST_CASE(vector_multiplication_test) {
boost::unit_test::unit_test_log_t::instance().set_threshold_level( boost::unit_test::log_messages );
//boost::unit_test::framework::instance().set_report_level(boost::unit_test::log_silent);
size_t size = 131072;

std::vector<size_t> v(size);
Expand All @@ -55,7 +57,7 @@ BOOST_AUTO_TEST_CASE(vector_multiplication_test) {
}, nil::crypto3::ThreadPool::PoolLevel::HIGH));

for (std::size_t i = 0; i < size; ++i) {
BOOST_CHECK(v[i] == i * i);
BOOST_CHECK_EQUAL(v[i], i * i);
}
}

Expand Down
42 changes: 42 additions & 0 deletions parse_tests.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import logging, json
from junitparser import JUnitXml
import glob, os
from opentelemetry import trace

undefined_behavior_sanitizer=os.environ['UndefinedBehaviorSanitizer']
address_sanitizer=os.environ['AddressSanitizer']
leak_sanitizer=os.environ['LeakSanitizer']

aggregated_test_results = JUnitXml();
for file in glob.glob("result/test-logs/*.xml"):
try:
aggregated_test_results.append(JUnitXml.fromfile(file))
except Exception as ex:
print("Error processing {}".format(file))
print(ex)

succeeded = aggregated_test_results.tests - \
aggregated_test_results.failures - \
aggregated_test_results.errors - \
aggregated_test_results.skipped

result = {
"tests" : aggregated_test_results.tests,
"failures" : aggregated_test_results.failures,
"errors" : aggregated_test_results.errors,
"skipped" : aggregated_test_results.skipped,
"succeeded" : succeeded,
"execution_time" : aggregated_test_results.time,
"undefined_behavior_sanitizer" : int(undefined_behavior_sanitizer),
"address_sanitizer" : int(address_sanitizer),
"leak_sanitizer" : int(leak_sanitizer),
}

print("Resulting JSON: {}".format(json.dumps(result)))

tracer = trace.get_tracer_provider().get_tracer(__name__)
with tracer.start_as_current_span("nightly_span"):
current_span = trace.get_current_span()
current_span.add_event("Nightly build finished")
logging.getLogger().error(json.dumps(result))

Loading
Loading