From f61c0471dedc68b367931cad9e04edf9a24ee05a Mon Sep 17 00:00:00 2001 From: Harry Cutts Date: Mon, 10 Jul 2023 14:45:15 +0000 Subject: inputflinger fuzzers: Remove FuzzContainer As discussed on the touchpad fuzzer CL [0], FuzzContainer was hiding quite a bit of internal state and making fuzzers harder to understand. Its constructor appeared to be deduplicating code, but looking more closely, it wasn't really helping that much, especially for the most common cases. Replace it with a few static methods, making it clearer how state is being changed in the fuzzers. [0] Change ID Ic22ac0f29d433fdf3c17331df620a39937ebd7eb Bug: 245989146 Test: build and briefly run all modified fuzzers $ SANITIZE_TARGET=hwaddress make ${FUZZER_NAME} $ cd $ANDROID_PRODUCT_OUT $ adb root $ adb sync data $ adb shell /data/fuzz/$(get_build_var TARGET_ARCH)/${FUZZER_NAME}/${FUZZER_NAME} Change-Id: I6e28b1f5ec62dc2d084173c1eb461c4bb699678b --- .../tests/fuzzers/CursorInputFuzzer.cpp | 29 +++++--- .../inputflinger/tests/fuzzers/FuzzContainer.h | 86 ---------------------- .../tests/fuzzers/KeyboardInputFuzzer.cpp | 35 +++++---- .../inputflinger/tests/fuzzers/MapperHelpers.h | 35 ++++++++- .../tests/fuzzers/MultiTouchInputFuzzer.cpp | 48 +++++++----- .../tests/fuzzers/SwitchInputFuzzer.cpp | 12 ++- .../tests/fuzzers/TouchpadInputFuzzer.cpp | 72 ++++++++++-------- 7 files changed, 148 insertions(+), 169 deletions(-) delete mode 100644 services/inputflinger/tests/fuzzers/FuzzContainer.h diff --git a/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp index e93b5929c7..af20a271b8 100644 --- a/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp +++ b/services/inputflinger/tests/fuzzers/CursorInputFuzzer.cpp @@ -15,38 +15,47 @@ */ #include -#include +#include #include #include namespace android { -static void addProperty(FuzzContainer& fuzzer, std::shared_ptr fdp) { +static void addProperty(FuzzEventHub& eventHub, std::shared_ptr fdp) { // Pick a random property to set for the mapper to have set. fdp->PickValueInArray>( - {[&]() -> void { fuzzer.addProperty("cursor.mode", "pointer"); }, - [&]() -> void { fuzzer.addProperty("cursor.mode", "navigation"); }, + {[&]() -> void { eventHub.addProperty("cursor.mode", "pointer"); }, + [&]() -> void { eventHub.addProperty("cursor.mode", "navigation"); }, [&]() -> void { - fuzzer.addProperty("cursor.mode", fdp->ConsumeRandomLengthString(100).data()); + eventHub.addProperty("cursor.mode", fdp->ConsumeRandomLengthString(100).data()); }, [&]() -> void { - fuzzer.addProperty("cursor.orientationAware", - fdp->ConsumeRandomLengthString(100).data()); + eventHub.addProperty("cursor.orientationAware", + fdp->ConsumeRandomLengthString(100).data()); }})(); } extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) { std::shared_ptr fdp = std::make_shared(data, size); - FuzzContainer fuzzer(fdp); + + // Create mocked objects to support the fuzzed input mapper. + std::shared_ptr eventHub = std::make_shared(fdp); + FuzzInputReaderContext context(eventHub, fdp); + InputDevice device = getFuzzedInputDevice(*fdp, &context); InputReaderConfiguration policyConfig; - CursorInputMapper& mapper = fuzzer.getMapper(policyConfig); + CursorInputMapper& mapper = + getMapperForDevice(*fdp.get(), device, + policyConfig); // Loop through mapper operations until randomness is exhausted. while (fdp->remaining_bytes() > 0) { fdp->PickValueInArray>({ - [&]() -> void { addProperty(fuzzer, fdp); }, + [&]() -> void { + addProperty(*eventHub.get(), fdp); + configureAndResetDevice(*fdp, device); + }, [&]() -> void { std::string dump; mapper.dump(dump); diff --git a/services/inputflinger/tests/fuzzers/FuzzContainer.h b/services/inputflinger/tests/fuzzers/FuzzContainer.h deleted file mode 100644 index ade53281a6..0000000000 --- a/services/inputflinger/tests/fuzzers/FuzzContainer.h +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright 2022 The Android Open Source Project - * - * Licensed 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. - */ - -#pragma once - -#include -#include -#include -#include - -namespace android { - -class FuzzContainer { - std::shared_ptr mFuzzEventHub; - FuzzInputListener mFuzzListener; - std::unique_ptr mFuzzContext; - std::unique_ptr mFuzzDevice; - std::shared_ptr mFdp; - -public: - FuzzContainer(std::shared_ptr fdp) : mFdp(fdp) { - // Setup parameters. - std::string deviceName = mFdp->ConsumeRandomLengthString(16); - std::string deviceLocation = mFdp->ConsumeRandomLengthString(12); - int32_t deviceID = mFdp->ConsumeIntegralInRange(0, 5); - int32_t deviceGeneration = mFdp->ConsumeIntegralInRange(/*from=*/0, /*to=*/5); - - // Create mocked objects. - mFuzzEventHub = std::make_shared(mFdp); - sp policy = sp::make(mFdp); - mFuzzContext = std::make_unique(mFuzzEventHub, policy, - mFuzzListener, mFdp); - - InputDeviceIdentifier identifier; - identifier.name = deviceName; - identifier.location = deviceLocation; - mFuzzDevice = std::make_unique(mFuzzContext.get(), deviceID, deviceGeneration, - identifier); - } - - ~FuzzContainer() {} - - void configureDevice() { - nsecs_t arbitraryTime = mFdp->ConsumeIntegral(); - std::list out; - out += mFuzzDevice->configure(arbitraryTime, /*readerConfig=*/{}, /*changes=*/{}); - out += mFuzzDevice->reset(arbitraryTime); - for (const NotifyArgs& args : out) { - mFuzzListener.notify(args); - } - } - - void addProperty(std::string key, std::string value) { - mFuzzEventHub->addProperty(key, value); - configureDevice(); - } - - void setAbsoluteAxisInfo(int axis, const RawAbsoluteAxisInfo& axisInfo) { - mFuzzEventHub->setAbsoluteAxisInfo(mFuzzDevice->getId(), axis, axisInfo); - } - - template - T& getMapper(Args... args) { - int32_t eventhubId = mFdp->ConsumeIntegral(); - // ensure a device entry exists for this eventHubId - mFuzzDevice->addEmptyEventHubDevice(eventhubId); - configureDevice(); - - return mFuzzDevice->template constructAndAddMapper(eventhubId, args...); - } -}; - -} // namespace android diff --git a/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp index 54977df2ed..922cbdfb87 100644 --- a/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp +++ b/services/inputflinger/tests/fuzzers/KeyboardInputFuzzer.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include +#include #include #include #include @@ -23,38 +23,43 @@ namespace android { const int32_t kMaxKeycodes = 100; -static void addProperty(FuzzContainer& fuzzer, std::shared_ptr fdp) { +static void addProperty(FuzzEventHub& eventHub, std::shared_ptr fdp) { // Pick a random property to set for the mapper to have set. fdp->PickValueInArray>( - {[&]() -> void { fuzzer.addProperty("keyboard.orientationAware", "1"); }, + {[&]() -> void { eventHub.addProperty("keyboard.orientationAware", "1"); }, [&]() -> void { - fuzzer.addProperty("keyboard.orientationAware", - fdp->ConsumeRandomLengthString(100).data()); + eventHub.addProperty("keyboard.orientationAware", + fdp->ConsumeRandomLengthString(100).data()); }, [&]() -> void { - fuzzer.addProperty("keyboard.doNotWakeByDefault", - fdp->ConsumeRandomLengthString(100).data()); + eventHub.addProperty("keyboard.doNotWakeByDefault", + fdp->ConsumeRandomLengthString(100).data()); }, [&]() -> void { - fuzzer.addProperty("keyboard.handlesKeyRepeat", - fdp->ConsumeRandomLengthString(100).data()); + eventHub.addProperty("keyboard.handlesKeyRepeat", + fdp->ConsumeRandomLengthString(100).data()); }})(); } extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) { std::shared_ptr fdp = std::make_shared(data, size); - FuzzContainer fuzzer(fdp); - KeyboardInputMapper& mapper = - fuzzer.getMapper(InputReaderConfiguration{}, - fdp->ConsumeIntegral(), - fdp->ConsumeIntegral()); + // Create mocked objects to support the fuzzed input mapper. + std::shared_ptr eventHub = std::make_shared(fdp); + FuzzInputReaderContext context(eventHub, fdp); + InputDevice device = getFuzzedInputDevice(*fdp, &context); + + KeyboardInputMapper& mapper = getMapperForDevice< + ThreadSafeFuzzedDataProvider, + KeyboardInputMapper>(*fdp.get(), device, InputReaderConfiguration{}, + /*source=*/fdp->ConsumeIntegral(), + /*keyboardType=*/fdp->ConsumeIntegral()); // Loop through mapper operations until randomness is exhausted. while (fdp->remaining_bytes() > 0) { fdp->PickValueInArray>({ - [&]() -> void { addProperty(fuzzer, fdp); }, + [&]() -> void { addProperty(*eventHub.get(), fdp); }, [&]() -> void { std::string dump; mapper.dump(dump); diff --git a/services/inputflinger/tests/fuzzers/MapperHelpers.h b/services/inputflinger/tests/fuzzers/MapperHelpers.h index 5039d1a5f1..e88731aafd 100644 --- a/services/inputflinger/tests/fuzzers/MapperHelpers.h +++ b/services/inputflinger/tests/fuzzers/MapperHelpers.h @@ -16,6 +16,7 @@ #pragma once #include +#include #include #include @@ -328,10 +329,8 @@ class FuzzInputReaderContext : public InputReaderContext { public: FuzzInputReaderContext(std::shared_ptr eventHub, - const sp& policy, - InputListenerInterface& listener, - std::shared_ptr mFdp) - : mEventHub(eventHub), mPolicy(policy), mFdp(mFdp) {} + std::shared_ptr fdp) + : mEventHub(eventHub), mPolicy(sp::make(fdp)), mFdp(fdp) {} ~FuzzInputReaderContext() {} void updateGlobalMetaState() override {} int32_t getGlobalMetaState() { return mFdp->ConsumeIntegral(); } @@ -358,4 +357,32 @@ public: void notifyStylusGestureStarted(int32_t, nsecs_t) {} }; +template +InputDevice getFuzzedInputDevice(Fdp& fdp, FuzzInputReaderContext* context) { + InputDeviceIdentifier identifier; + identifier.name = fdp.ConsumeRandomLengthString(16); + identifier.location = fdp.ConsumeRandomLengthString(12); + int32_t deviceID = fdp.ConsumeIntegralInRange(0, 5); + int32_t deviceGeneration = fdp.ConsumeIntegralInRange(0, 5); + return InputDevice(context, deviceID, deviceGeneration, identifier); +} + +template +void configureAndResetDevice(Fdp& fdp, InputDevice& device) { + nsecs_t arbitraryTime = fdp.template ConsumeIntegral(); + std::list out; + out += device.configure(arbitraryTime, /*readerConfig=*/{}, /*changes=*/{}); + out += device.reset(arbitraryTime); +} + +template +T& getMapperForDevice(Fdp& fdp, InputDevice& device, Args... args) { + int32_t eventhubId = fdp.template ConsumeIntegral(); + // ensure a device entry exists for this eventHubId + device.addEmptyEventHubDevice(eventhubId); + configureAndResetDevice(fdp, device); + + return device.template constructAndAddMapper(eventhubId, args...); +} + } // namespace android diff --git a/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp index 569767f8c0..d3f66900da 100644 --- a/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp +++ b/services/inputflinger/tests/fuzzers/MultiTouchInputFuzzer.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include +#include #include #include #include @@ -23,53 +23,63 @@ namespace android { const int32_t kMaxKeycodes = 100; -static void addProperty(FuzzContainer& fuzzer, std::shared_ptr fdp) { +static void addProperty(FuzzEventHub& eventHub, std::shared_ptr fdp) { // Pick a random property to set for the mapper to have set. fdp->PickValueInArray>( - {[&]() -> void { fuzzer.addProperty("touch.deviceType", "touchScreen"); }, + {[&]() -> void { eventHub.addProperty("touch.deviceType", "touchScreen"); }, [&]() -> void { - fuzzer.addProperty("touch.deviceType", fdp->ConsumeRandomLengthString(8).data()); + eventHub.addProperty("touch.deviceType", fdp->ConsumeRandomLengthString(8).data()); }, [&]() -> void { - fuzzer.addProperty("touch.size.scale", fdp->ConsumeRandomLengthString(8).data()); + eventHub.addProperty("touch.size.scale", fdp->ConsumeRandomLengthString(8).data()); }, [&]() -> void { - fuzzer.addProperty("touch.size.bias", fdp->ConsumeRandomLengthString(8).data()); + eventHub.addProperty("touch.size.bias", fdp->ConsumeRandomLengthString(8).data()); }, [&]() -> void { - fuzzer.addProperty("touch.size.isSummed", - fdp->ConsumeRandomLengthString(8).data()); + eventHub.addProperty("touch.size.isSummed", + fdp->ConsumeRandomLengthString(8).data()); }, [&]() -> void { - fuzzer.addProperty("touch.size.calibration", - fdp->ConsumeRandomLengthString(8).data()); + eventHub.addProperty("touch.size.calibration", + fdp->ConsumeRandomLengthString(8).data()); }, [&]() -> void { - fuzzer.addProperty("touch.pressure.scale", - fdp->ConsumeRandomLengthString(8).data()); + eventHub.addProperty("touch.pressure.scale", + fdp->ConsumeRandomLengthString(8).data()); }, [&]() -> void { - fuzzer.addProperty("touch.size.calibration", - fdp->ConsumeBool() ? "diameter" : "area"); + eventHub.addProperty("touch.size.calibration", + fdp->ConsumeBool() ? "diameter" : "area"); }, [&]() -> void { - fuzzer.addProperty("touch.pressure.calibration", - fdp->ConsumeRandomLengthString(8).data()); + eventHub.addProperty("touch.pressure.calibration", + fdp->ConsumeRandomLengthString(8).data()); }})(); } extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) { std::shared_ptr fdp = std::make_shared(data, size); - FuzzContainer fuzzer(fdp); + + // Create mocked objects to support the fuzzed input mapper. + std::shared_ptr eventHub = std::make_shared(fdp); + FuzzInputReaderContext context(eventHub, fdp); + InputDevice device = getFuzzedInputDevice(*fdp, &context); InputReaderConfiguration policyConfig; - MultiTouchInputMapper& mapper = fuzzer.getMapper(policyConfig); + MultiTouchInputMapper& mapper = + getMapperForDevice(*fdp.get(), + device, + policyConfig); // Loop through mapper operations until randomness is exhausted. while (fdp->remaining_bytes() > 0) { fdp->PickValueInArray>({ - [&]() -> void { addProperty(fuzzer, fdp); }, + [&]() -> void { + addProperty(*eventHub.get(), fdp); + configureAndResetDevice(*fdp, device); + }, [&]() -> void { std::string dump; mapper.dump(dump); diff --git a/services/inputflinger/tests/fuzzers/SwitchInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/SwitchInputFuzzer.cpp index 80eebd58e3..ac2030afd3 100644 --- a/services/inputflinger/tests/fuzzers/SwitchInputFuzzer.cpp +++ b/services/inputflinger/tests/fuzzers/SwitchInputFuzzer.cpp @@ -14,7 +14,7 @@ * limitations under the License. */ -#include +#include #include #include #include @@ -24,9 +24,15 @@ namespace android { extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) { std::shared_ptr fdp = std::make_shared(data, size); - FuzzContainer fuzzer(fdp); - SwitchInputMapper& mapper = fuzzer.getMapper(InputReaderConfiguration{}); + // Create mocked objects to support the fuzzed input mapper. + std::shared_ptr eventHub = std::make_shared(fdp); + FuzzInputReaderContext context(eventHub, fdp); + InputDevice device = getFuzzedInputDevice(*fdp, &context); + + SwitchInputMapper& mapper = + getMapperForDevice(*fdp.get(), device, InputReaderConfiguration{}); // Loop through mapper operations until randomness is exhausted. while (fdp->remaining_bytes() > 0) { diff --git a/services/inputflinger/tests/fuzzers/TouchpadInputFuzzer.cpp b/services/inputflinger/tests/fuzzers/TouchpadInputFuzzer.cpp index 796178addd..be765cc364 100644 --- a/services/inputflinger/tests/fuzzers/TouchpadInputFuzzer.cpp +++ b/services/inputflinger/tests/fuzzers/TouchpadInputFuzzer.cpp @@ -15,12 +15,13 @@ */ #include +#include #include #include #include -#include +#include #include #include #include @@ -29,30 +30,30 @@ namespace android { namespace { -void setAxisInfo(ThreadSafeFuzzedDataProvider& fdp, FuzzContainer& fuzzer, int axis) { +void setAxisInfo(ThreadSafeFuzzedDataProvider& fdp, FuzzEventHub& eventHub, int32_t id, int axis) { if (fdp.ConsumeBool()) { - fuzzer.setAbsoluteAxisInfo(axis, - RawAbsoluteAxisInfo{ - .valid = fdp.ConsumeBool(), - .minValue = fdp.ConsumeIntegral(), - .maxValue = fdp.ConsumeIntegral(), - .flat = fdp.ConsumeIntegral(), - .fuzz = fdp.ConsumeIntegral(), - .resolution = fdp.ConsumeIntegral(), - }); + eventHub.setAbsoluteAxisInfo(id, axis, + RawAbsoluteAxisInfo{ + .valid = fdp.ConsumeBool(), + .minValue = fdp.ConsumeIntegral(), + .maxValue = fdp.ConsumeIntegral(), + .flat = fdp.ConsumeIntegral(), + .fuzz = fdp.ConsumeIntegral(), + .resolution = fdp.ConsumeIntegral(), + }); } } -void setAxisInfos(ThreadSafeFuzzedDataProvider& fdp, FuzzContainer& fuzzer) { - setAxisInfo(fdp, fuzzer, ABS_MT_SLOT); - setAxisInfo(fdp, fuzzer, ABS_MT_POSITION_X); - setAxisInfo(fdp, fuzzer, ABS_MT_POSITION_Y); - setAxisInfo(fdp, fuzzer, ABS_MT_PRESSURE); - setAxisInfo(fdp, fuzzer, ABS_MT_ORIENTATION); - setAxisInfo(fdp, fuzzer, ABS_MT_TOUCH_MAJOR); - setAxisInfo(fdp, fuzzer, ABS_MT_TOUCH_MINOR); - setAxisInfo(fdp, fuzzer, ABS_MT_WIDTH_MAJOR); - setAxisInfo(fdp, fuzzer, ABS_MT_WIDTH_MINOR); +void setAxisInfos(ThreadSafeFuzzedDataProvider& fdp, FuzzEventHub& eventHub, int32_t id) { + setAxisInfo(fdp, eventHub, id, ABS_MT_SLOT); + setAxisInfo(fdp, eventHub, id, ABS_MT_POSITION_X); + setAxisInfo(fdp, eventHub, id, ABS_MT_POSITION_Y); + setAxisInfo(fdp, eventHub, id, ABS_MT_PRESSURE); + setAxisInfo(fdp, eventHub, id, ABS_MT_ORIENTATION); + setAxisInfo(fdp, eventHub, id, ABS_MT_TOUCH_MAJOR); + setAxisInfo(fdp, eventHub, id, ABS_MT_TOUCH_MINOR); + setAxisInfo(fdp, eventHub, id, ABS_MT_WIDTH_MAJOR); + setAxisInfo(fdp, eventHub, id, ABS_MT_WIDTH_MINOR); } const std::vector boolPropertiesToFuzz = { @@ -89,32 +90,32 @@ const std::vector doublePropertiesToFuzz = { "gestureProp.Two_Finger_Vertical_Close_Distance_Thresh", }; -void setDeviceSpecificConfig(ThreadSafeFuzzedDataProvider& fdp, FuzzContainer& fuzzer) { +void setDeviceSpecificConfig(ThreadSafeFuzzedDataProvider& fdp, FuzzEventHub& eventHub) { // There are a great many gesture properties offered by the Gestures library, all of which could // potentially be set in Input Device Configuration files. Maintaining a complete list is // impractical, so instead we only fuzz properties which are used in at least one IDC file, or // which are likely to be used in future (e.g. ones for controlling palm rejection). if (fdp.ConsumeBool()) { - fuzzer.addProperty("gestureProp.Touchpad_Stack_Version", - std::to_string(fdp.ConsumeIntegral())); + eventHub.addProperty("gestureProp.Touchpad_Stack_Version", + std::to_string(fdp.ConsumeIntegral())); } for (auto& propertyName : boolPropertiesToFuzz) { if (fdp.ConsumeBool()) { - fuzzer.addProperty(propertyName, fdp.ConsumeBool() ? "1" : "0"); + eventHub.addProperty(propertyName, fdp.ConsumeBool() ? "1" : "0"); } } for (auto& propertyName : doublePropertiesToFuzz) { if (fdp.ConsumeBool()) { - fuzzer.addProperty(propertyName, std::to_string(fdp.ConsumeFloatingPoint())); + eventHub.addProperty(propertyName, std::to_string(fdp.ConsumeFloatingPoint())); } } if (fdp.ConsumeBool()) { - fuzzer.addProperty("gestureProp." + fdp.ConsumeRandomLengthString(), - std::to_string(fdp.ConsumeIntegral())); + eventHub.addProperty("gestureProp." + fdp.ConsumeRandomLengthString(), + std::to_string(fdp.ConsumeIntegral())); } } @@ -130,16 +131,23 @@ void setTouchpadSettings(ThreadSafeFuzzedDataProvider& fdp, InputReaderConfigura extern "C" int LLVMFuzzerTestOneInput(uint8_t* data, size_t size) { std::shared_ptr fdp = std::make_shared(data, size); - FuzzContainer fuzzer(fdp); - setAxisInfos(*fdp, fuzzer); - setDeviceSpecificConfig(*fdp, fuzzer); + + // Create mocked objects to support the fuzzed input mapper. + std::shared_ptr eventHub = std::make_shared(fdp); + FuzzInputReaderContext context(eventHub, fdp); + InputDevice device = getFuzzedInputDevice(*fdp, &context); + + setAxisInfos(*fdp, *eventHub.get(), device.getId()); + setDeviceSpecificConfig(*fdp, *eventHub.get()); InputReaderConfiguration policyConfig; // Some settings are fuzzed here, as well as in the main loop, to provide randomized data to the // TouchpadInputMapper constructor. setTouchpadSettings(*fdp, policyConfig); policyConfig.pointerCaptureRequest.enable = fdp->ConsumeBool(); - TouchpadInputMapper& mapper = fuzzer.getMapper(policyConfig); + TouchpadInputMapper& mapper = + getMapperForDevice(*fdp, device, + policyConfig); // Loop through mapper operations until randomness is exhausted. while (fdp->remaining_bytes() > 0) { -- cgit v1.2.3-59-g8ed1b