Index: lib/Fuzzer/CMakeLists.txt =================================================================== --- lib/Fuzzer/CMakeLists.txt +++ lib/Fuzzer/CMakeLists.txt @@ -2,7 +2,7 @@ # Disable the coverage and sanitizer instrumentation for the fuzzer itself. set(CMAKE_CXX_FLAGS "${LIBFUZZER_FLAGS_BASE} -mpopcnt -fno-sanitize=all -fno-sanitize-coverage=edge,trace-cmp,indirect-calls,8bit-counters -Werror") if( LLVM_USE_SANITIZE_COVERAGE ) - if(NOT "${LLVM_USE_SANITIZER}" STREQUAL "Address") + if(NOT "${LLVM_USE_SANITIZER}" STREQUAL "Address;Undefined") message(FATAL_ERROR "LibFuzzer and its tests require LLVM_USE_SANITIZER=Address and " "LLVM_USE_SANITIZE_COVERAGE=YES to be set." Index: lib/Support/APInt.cpp =================================================================== --- lib/Support/APInt.cpp +++ lib/Support/APInt.cpp @@ -1042,7 +1042,11 @@ if (isSingleWord()) { if (shiftAmt == BitWidth) return APInt(BitWidth, 0); // undefined - return APInt(BitWidth, SignExtend64(VAL, BitWidth) >> shiftAmt); + else { + unsigned SignBit = APINT_BITS_PER_WORD - BitWidth; + return APInt(BitWidth, + (((int64_t(VAL) << SignBit) >> SignBit) >> shiftAmt)); + } } // If all the bits were shifted out, the result is, technically, undefined. Index: tools/CMakeLists.txt =================================================================== --- tools/CMakeLists.txt +++ tools/CMakeLists.txt @@ -39,6 +39,7 @@ add_llvm_tool_subdirectory(llvm-config) add_llvm_tool_subdirectory(llvm-lto) add_llvm_tool_subdirectory(llvm-profdata) +add_llvm_tool_subdirectory(llvm-apint-fuzzer) # Projects supported via LLVM_EXTERNAL_*_SOURCE_DIR need to be explicitly # specified. Index: tools/llvm-apint-fuzzer/CMakeLists.txt =================================================================== --- tools/llvm-apint-fuzzer/CMakeLists.txt +++ tools/llvm-apint-fuzzer/CMakeLists.txt @@ -0,0 +1,10 @@ +if( LLVM_USE_SANITIZE_COVERAGE ) + set(LLVM_LINK_COMPONENTS + Support + ) + add_llvm_tool(llvm-apint-fuzzer + llvm-apint-fuzzer.cpp) + target_link_libraries(llvm-apint-fuzzer + LLVMFuzzer + ) +endif() Index: tools/llvm-apint-fuzzer/llvm-apint-fuzzer.cpp =================================================================== --- tools/llvm-apint-fuzzer/llvm-apint-fuzzer.cpp +++ tools/llvm-apint-fuzzer/llvm-apint-fuzzer.cpp @@ -0,0 +1,54 @@ +//===--- fuzz-llvm-as.cpp - Fuzzer for llvm-as using lib/Fuzzer -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/APInt.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/Support/Endian.h" + +#include +#include + +using namespace llvm; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { + + if (Size < 4) + return 0; + + uint32_t Amount = llvm::support::endian::read32le(Data); + Data += 4; + Size -= 4; + + if (Size < 4) + return 0; + + uint32_t Value = llvm::support::endian::read32le(Data); + Data += 4; + Size -= 4; + + if (Size < 1) + return 0; + + uint32_t Bits = Data[0]; + + Bits = std::max(Bits, 1u); + + APInt Input(Bits, Value); + + Amount = std::min(Amount, Bits); + + // Check that: + // (X >> Amount) >> 1 + // can be commuted to: + // (X >> 1) >> Amount + auto Fst = Input.ashr(Amount).ashr(1); + auto Snd = Input.ashr(1).ashr(Amount); + + return Fst == Snd ? 0 : 1; +} Index: unittests/ADT/APIntTest.cpp =================================================================== --- unittests/ADT/APIntTest.cpp +++ unittests/ADT/APIntTest.cpp @@ -32,11 +32,6 @@ EXPECT_FALSE(Shl[1]); } -TEST(APIntTest, i64_ArithmeticRightShiftNegative) { - const APInt neg_one(64, static_cast(-1), true); - EXPECT_EQ(neg_one, neg_one.ashr(7)); -} - TEST(APIntTest, i128_NegativeCount) { APInt Minus3(128, static_cast(-3), true); EXPECT_EQ(126u, Minus3.countLeadingOnes());