Commit c7bee6dc authored by Dominic Mazzoni's avatar Dominic Mazzoni Committed by Commit Bot

Add fuzzer for TtsPlatform on Mac/Win

Bug: none
Change-Id: I3c5f6e3aeea9bfb6b9c00be89b807c2a603cddac
Reviewed-on: https://chromium-review.googlesource.com/c/1340869
Commit-Queue: Dominic Mazzoni <dmazzoni@chromium.org>
Reviewed-by: default avatarJonathan Metzman <metzman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#609032}
parent 72b9e047
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/memory/singleton.h"
#include "chrome/browser/speech/tts_controller.h"
UtteranceContinuousParameters::UtteranceContinuousParameters()
: rate(1.0), pitch(1.0), volume(1.0) {}
VoiceData::VoiceData() : remote(false), native(false) {}
VoiceData::VoiceData(const VoiceData& other) = default;
VoiceData::~VoiceData() {}
class MockTtsController : public TtsController {
public:
static MockTtsController* GetInstance() {
return base::Singleton<MockTtsController>::get();
}
MockTtsController() {}
bool IsSpeaking() override { return false; }
void SpeakOrEnqueue(Utterance* utterance) override {}
void Stop() override {}
void Pause() override {}
void Resume() override {}
void OnTtsEvent(int utterance_id,
TtsEventType event_type,
int char_index,
const std::string& error_message) override {}
void GetVoices(content::BrowserContext* browser_context,
std::vector<VoiceData>* out_voices) override {}
void VoicesChanged() override {}
void AddVoicesChangedDelegate(VoicesChangedDelegate* delegate) override {}
void RemoveVoicesChangedDelegate(VoicesChangedDelegate* delegate) override {}
void RemoveUtteranceEventDelegate(UtteranceEventDelegate* delegate) override {
}
void SetTtsEngineDelegate(TtsEngineDelegate* delegate) override {}
TtsEngineDelegate* GetTtsEngineDelegate() override { return nullptr; }
void SetPlatformImpl(TtsPlatformImpl* platform_impl) override {}
int QueueSize() override { return 0; }
private:
friend struct base::DefaultSingletonTraits<MockTtsController>;
DISALLOW_COPY_AND_ASSIGN(MockTtsController);
};
// static
TtsController* TtsController::GetInstance() {
return MockTtsController::GetInstance();
}
...@@ -11,7 +11,6 @@ ...@@ -11,7 +11,6 @@
#include "base/values.h" #include "base/values.h"
#include "chrome/browser/speech/tts_controller.h" #include "chrome/browser/speech/tts_controller.h"
#include "chrome/browser/speech/tts_platform.h" #include "chrome/browser/speech/tts_platform.h"
#include "extensions/browser/extension_function.h"
#import <Cocoa/Cocoa.h> #import <Cocoa/Cocoa.h>
...@@ -112,6 +111,8 @@ bool TtsPlatformImplMac::Speak( ...@@ -112,6 +111,8 @@ bool TtsPlatformImplMac::Speak(
NSString* utterance_nsstring = NSString* utterance_nsstring =
[NSString stringWithUTF8String:utterance_.c_str()]; [NSString stringWithUTF8String:utterance_.c_str()];
if (!utterance_nsstring)
return false;
// Deliberately construct a new speech synthesizer every time Speak is // Deliberately construct a new speech synthesizer every time Speak is
// called, otherwise there's no way to know whether calls to the delegate // called, otherwise there's no way to know whether calls to the delegate
......
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/speech/tts_platform.h"
// Entry point for LibFuzzer.
extern "C" int LLVMFuzzerTestOneInput(const unsigned char* data, size_t size) {
int utterance_id = 0;
std::string utterance;
std::string lang;
VoiceData voice;
UtteranceContinuousParameters params;
params.pitch = 1.0;
params.rate = 1.0;
params.volume = 0.1;
// First byte gives us the utterance ID.
size_t i = 0;
if (i < size)
utterance_id = data[i++];
// Decide whether we want to fuzz the language, rate, pitch,
// voice name, and all that. Half the time we'll just leave
// those empty and fuzz only the utterance, otherwise it's
// possible the fuzzer would never spend any effort fuzzing
// utteranes.
if (i < size && (data[i++] % 2 == 0)) {
// The next few bytes determine the language. Ensure that
// we frequently get some common real languages but allow
// arbitrary strings up to 10 characters.
if (i < size) {
int lang_choice = data[i++];
switch (lang_choice) {
case 0:
lang = "";
break;
case 1:
lang = "en";
break;
case 2:
lang = "fr";
break;
case 3:
lang = "es";
break;
default:
int lang_len = 1 + (lang_choice - 4) % 10;
for (int j = 0; j < lang_len; j++) {
if (i < size)
lang.append(1, data[i++]);
}
}
}
// Set native_voice_identifier
if (i < size) {
int voice_len = data[i++] % 10;
for (int j = 0; j < voice_len; j++) {
if (i < size)
voice.native_voice_identifier.append(1, data[i++]);
}
}
// Set rate, pitch.
if (i + 4 <= size) {
params.rate = *reinterpret_cast<const float*>(&data[i]);
i += 4;
}
if (i + 4 <= size) {
params.pitch = *reinterpret_cast<const float*>(&data[i]);
i += 4;
}
}
// The rest of the data becomes the utterance.
while (i < size)
utterance.append(1, data[i++]);
TtsPlatformImpl* tts = TtsPlatformImpl::GetInstance();
CHECK(tts->PlatformImplAvailable());
VLOG(1) << "id=" << utterance_id << " lang='" << lang << "'"
<< " voice='" << voice.native_voice_identifier << "'"
<< " pitch=" << params.pitch << " rate=" << params.rate
<< " volume=" << params.volume << " utterance='" << utterance << "'";
tts->StopSpeaking();
tts->Speak(utterance_id, utterance, lang, voice, params);
return 0;
}
...@@ -24,6 +24,7 @@ import("//remoting/remoting_enable.gni") ...@@ -24,6 +24,7 @@ import("//remoting/remoting_enable.gni")
import("//rlz/buildflags/buildflags.gni") import("//rlz/buildflags/buildflags.gni")
import("//services/service_manager/public/service_manifest.gni") import("//services/service_manager/public/service_manifest.gni")
import("//services/catalog/public/tools/catalog.gni") import("//services/catalog/public/tools/catalog.gni")
import("//testing/libfuzzer/fuzzer_test.gni")
import("//testing/test.gni") import("//testing/test.gni")
import("//third_party/widevine/cdm/widevine.gni") import("//third_party/widevine/cdm/widevine.gni")
import("//ui/base/ui_features.gni") import("//ui/base/ui_features.gni")
...@@ -5781,3 +5782,28 @@ if (!is_android && !is_fuchsia) { ...@@ -5781,3 +5782,28 @@ if (!is_android && !is_fuchsia) {
] ]
} }
} }
# Note: this compiles and runs on Mac but may cause
# system instability; if you try it out, close other
# programs and then reboot afterwards. It should be
# possible to make it work on Linux if you use the
# --enable-speech-dispatcher flag.
if (is_win) {
fuzzer_test("tts_platform_fuzzer") {
sources = [
"../browser/speech/mock_tts_controller.cc",
"../browser/speech/tts_controller.h",
"../browser/speech/tts_mac.mm",
"../browser/speech/tts_platform.cc",
"../browser/speech/tts_platform.h",
"../browser/speech/tts_platform_fuzzer.cc",
"../browser/speech/tts_win.cc",
]
deps = [
"//base",
"//base/test:test_support",
"//ui/base",
]
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment