diff options
Diffstat (limited to 'extensions/spellcheck/hunspell/glue/mozHunspellRLBoxHost.cpp')
-rw-r--r-- | extensions/spellcheck/hunspell/glue/mozHunspellRLBoxHost.cpp | 235 |
1 files changed, 235 insertions, 0 deletions
diff --git a/extensions/spellcheck/hunspell/glue/mozHunspellRLBoxHost.cpp b/extensions/spellcheck/hunspell/glue/mozHunspellRLBoxHost.cpp new file mode 100644 index 0000000000..cd80fb989b --- /dev/null +++ b/extensions/spellcheck/hunspell/glue/mozHunspellRLBoxHost.cpp @@ -0,0 +1,235 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include <limits> + +#include "mozHunspellRLBoxHost.h" +#include "mozilla/DebugOnly.h" +#include "nsContentUtils.h" +#include "nsILoadInfo.h" +#include "nsNetUtil.h" +#include "nsUnicharUtils.h" + +#include "hunspell_csutil.hxx" + +using namespace mozilla; + +mozHunspellFileMgrHost::mozHunspellFileMgrHost(const nsCString& aFilename) { + nsCOMPtr<nsIChannel> channel; + DebugOnly<Result<Ok, nsresult>> result = Open(aFilename, channel, mStream); + NS_WARNING_ASSERTION(result.value.isOk(), "Failed to open Hunspell file"); +} + +/* static */ +Result<Ok, nsresult> mozHunspellFileMgrHost::Open( + const nsCString& aPath, nsCOMPtr<nsIChannel>& aChannel, + nsCOMPtr<nsIInputStream>& aStream) { + nsCOMPtr<nsIURI> uri; + MOZ_TRY(NS_NewURI(getter_AddRefs(uri), aPath)); + + MOZ_TRY(NS_NewChannel( + getter_AddRefs(aChannel), uri, nsContentUtils::GetSystemPrincipal(), + nsILoadInfo::SEC_REQUIRE_SAME_ORIGIN_INHERITS_SEC_CONTEXT, + nsIContentPolicy::TYPE_OTHER)); + + MOZ_TRY(aChannel->Open(getter_AddRefs(aStream))); + return Ok(); +} + +Result<Ok, nsresult> mozHunspellFileMgrHost::ReadLine(nsCString& aLine) { + if (!mStream) { + return Err(NS_ERROR_NOT_INITIALIZED); + } + + bool ok; + MOZ_TRY(NS_ReadLine(mStream.get(), &mLineBuffer, aLine, &ok)); + if (!ok) { + mStream = nullptr; + } + + mLineNum++; + return Ok(); +} + +/* static */ +Result<int64_t, nsresult> mozHunspellFileMgrHost::GetSize( + const nsCString& aFilename) { + int64_t ret = -1; + + nsCOMPtr<nsIChannel> channel; + nsCOMPtr<nsIInputStream> stream; + MOZ_TRY(Open(aFilename, channel, stream)); + + channel->GetContentLength(&ret); + return ret; +} + +bool mozHunspellFileMgrHost::GetLine(std::string& aResult) { + nsAutoCString line; + auto res = ReadLine(line); + if (res.isErr()) { + return false; + } + + aResult.assign(line.BeginReading(), line.Length()); + return true; +} + +/* static */ +uint32_t mozHunspellCallbacks::sCurrentFreshId = 0; +/* static */ +mozilla::StaticRWLock mozHunspellCallbacks::sFileMgrMapLock; +/* static */ +std::map<uint32_t, std::unique_ptr<mozHunspellFileMgrHost>> + mozHunspellCallbacks::sFileMgrMap; +/* static */ +std::set<nsCString> mozHunspellCallbacks::sFileMgrAllowList; + +/* static */ +void mozHunspellCallbacks::AllowFile(const nsCString& aFilename) { + mozilla::StaticAutoWriteLock lock(sFileMgrMapLock); + sFileMgrAllowList.insert(aFilename); +} + +/* static */ +void mozHunspellCallbacks::Clear() { + mozilla::StaticAutoWriteLock lock(sFileMgrMapLock); + sCurrentFreshId = 0; + sFileMgrMap.clear(); + sFileMgrAllowList.clear(); +} + +/* static */ +tainted_hunspell<uint32_t> mozHunspellCallbacks::CreateFilemgr( + rlbox_sandbox_hunspell& aSandbox, + tainted_hunspell<const char*> t_aFilename) { + mozilla::StaticAutoWriteLock lock(sFileMgrMapLock); + + return t_aFilename.copy_and_verify_string( + [&](std::unique_ptr<char[]> aFilename) { + nsCString cFilename = nsDependentCString(aFilename.get()); + + // Ensure that the filename is in the allowlist + auto it = sFileMgrAllowList.find(cFilename); + MOZ_RELEASE_ASSERT(it != sFileMgrAllowList.end()); + + // Get new id + uint32_t freshId = GetFreshId(); + // Save mapping of id to file manager + sFileMgrMap[freshId] = std::unique_ptr<mozHunspellFileMgrHost>( + new mozHunspellFileMgrHost(cFilename)); + + return freshId; + }); +} + +/* static */ +uint32_t mozHunspellCallbacks::GetFreshId() { + // i is uint64_t to prevent overflow during loop increment which would cause + // an infinite loop + for (uint64_t i = sCurrentFreshId; i < std::numeric_limits<uint32_t>::max(); + i++) { + auto it = sFileMgrMap.find(i); + if (it == sFileMgrMap.end()) { + // set sCurrentFreshId to the next (possibly) available id + sCurrentFreshId = i + 1; + return static_cast<uint32_t>(i); + } + } + + MOZ_CRASH("Ran out of unique file ids for hunspell dictionaries"); +} + +/* static */ +mozHunspellFileMgrHost& mozHunspellCallbacks::GetMozHunspellFileMgrHost( + tainted_hunspell<uint32_t> t_aFd) { + mozilla::StaticAutoReadLock lock(sFileMgrMapLock); + uint32_t aFd = t_aFd.copy_and_verify([](uint32_t aFd) { return aFd; }); + auto iter = sFileMgrMap.find(aFd); + MOZ_RELEASE_ASSERT(iter != sFileMgrMap.end()); + return *(iter->second.get()); +} + +/* static */ +tainted_hunspell<bool> mozHunspellCallbacks::GetLine( + rlbox_sandbox_hunspell& aSandbox, tainted_hunspell<uint32_t> t_aFd, + tainted_hunspell<char**> t_aLinePtr) { + mozHunspellFileMgrHost& inst = + mozHunspellCallbacks::GetMozHunspellFileMgrHost(t_aFd); + std::string line; + bool ok = inst.GetLine(line); + // If the getline fails, return a null which is "graceful" failure + if (ok) { + // Copy the line into the sandbox. This memory is eventually freed by + // hunspell. + size_t size = line.size() + 1; + tainted_hunspell<char*> t_line = aSandbox.malloc_in_sandbox<char>(size); + + if (t_line == nullptr) { + // If malloc fails, we should go to "graceful" failure path + ok = false; + } else { + rlbox::memcpy(aSandbox, t_line, line.c_str(), size); + } + *t_aLinePtr = t_line; + } else { + *t_aLinePtr = nullptr; + } + return ok; +} + +/* static */ +tainted_hunspell<int> mozHunspellCallbacks::GetLineNum( + rlbox_sandbox_hunspell& aSandbox, tainted_hunspell<uint32_t> t_aFd) { + mozHunspellFileMgrHost& inst = + mozHunspellCallbacks::GetMozHunspellFileMgrHost(t_aFd); + int num = inst.GetLineNum(); + return num; +} + +/* static */ +void mozHunspellCallbacks::DestructFilemgr(rlbox_sandbox_hunspell& aSandbox, + tainted_hunspell<uint32_t> t_aFd) { + mozilla::StaticAutoWriteLock lock(sFileMgrMapLock); + uint32_t aFd = t_aFd.copy_and_verify([](uint32_t aFd) { return aFd; }); + + auto iter = sFileMgrMap.find(aFd); + if (iter != sFileMgrMap.end()) { + sFileMgrMap.erase(iter); + } +} + +// Callbacks for using Firefox's encoding instead of hunspell's + +/* static */ +tainted_hunspell<uint32_t> mozHunspellCallbacks::ToUpperCase( + rlbox_sandbox_hunspell& aSandbox, tainted_hunspell<uint32_t> t_aChar) { + uint32_t aChar = + t_aChar.copy_and_verify([](uint32_t aChar) { return aChar; }); + return ::ToUpperCase(aChar); +} + +/* static */ +tainted_hunspell<uint32_t> mozHunspellCallbacks::ToLowerCase( + rlbox_sandbox_hunspell& aSandbox, tainted_hunspell<uint32_t> t_aChar) { + uint32_t aChar = + t_aChar.copy_and_verify([](uint32_t aChar) { return aChar; }); + return ::ToLowerCase(aChar); +} + +/* static */ tainted_hunspell<struct cs_info*> +mozHunspellCallbacks::GetCurrentCS(rlbox_sandbox_hunspell& aSandbox, + tainted_hunspell<const char*> t_es) { + tainted_hunspell<struct cs_info*> t_ccs = + aSandbox.malloc_in_sandbox<struct cs_info>(256); + MOZ_RELEASE_ASSERT(t_ccs); + return t_es.copy_and_verify_string([&](std::unique_ptr<char[]> es) { + struct cs_info* ccs = hunspell_get_current_cs(es.get()); + rlbox::memcpy(aSandbox, t_ccs, ccs, sizeof(struct cs_info) * 256); + delete[] ccs; + return t_ccs; + }); +} |