mirror of
https://github.com/zotero/zotero.git
synced 2026-10-11 03:38:25 +00:00
242 lines
8 KiB
Diff
242 lines
8 KiB
Diff
diff --git a/browser/app/nsBrowserApp.cpp b/browser/app/nsBrowserApp.cpp
|
|
--- a/browser/app/nsBrowserApp.cpp
|
|
+++ b/browser/app/nsBrowserApp.cpp
|
|
@@ -193,19 +193,31 @@ static bool HasFlag(int argc, char* argv[], const char* s) {
|
|
}
|
|
return false;
|
|
}
|
|
#endif
|
|
|
|
constinit Bootstrap::UniquePtr gBootstrap;
|
|
|
|
static int do_main(int argc, char* argv[], char* envp[]) {
|
|
+ // Allow profile downgrade for Zotero
|
|
+ setenv("MOZ_ALLOW_DOWNGRADE", "1", 1);
|
|
+ // Don't create dedicated profile (default-esr)
|
|
+ setenv("MOZ_LEGACY_PROFILES", "1", 1);
|
|
+
|
|
// Allow firefox.exe to launch XULRunner apps via -app <application.ini>
|
|
// Note that -app must be the *first* argument.
|
|
- const char* appDataFile = getenv("XUL_APP_FILE");
|
|
+ UniqueFreePtr<char> iniPath = BinaryPath::GetApplicationIni();
|
|
+ if (!iniPath) {
|
|
+ Output("Couldn't find application.ini.\n");
|
|
+ return 255;
|
|
+ }
|
|
+ char *appDataFile = iniPath.get();
|
|
+
|
|
+
|
|
if ((!appDataFile || !*appDataFile) && (argc > 1 && IsFlag(argv[1], "app"))) {
|
|
if (argc == 2) {
|
|
Output("Incorrect number of arguments passed to -app");
|
|
return 255;
|
|
}
|
|
appDataFile = argv[2];
|
|
|
|
char appEnv[MAXPATHLEN];
|
|
diff --git a/xpcom/build/BinaryPath.h b/xpcom/build/BinaryPath.h
|
|
--- a/xpcom/build/BinaryPath.h
|
|
+++ b/xpcom/build/BinaryPath.h
|
|
@@ -126,16 +126,56 @@ class BinaryPath {
|
|
} else {
|
|
rv = NS_ERROR_FAILURE;
|
|
}
|
|
|
|
CFRelease(executableURL);
|
|
return rv;
|
|
}
|
|
|
|
+ static nsresult GetApplicationIni(char aResult[MAXPATHLEN])
|
|
+ {
|
|
+ // Works even if we're not bundled.
|
|
+ CFBundleRef appBundle = CFBundleGetMainBundle();
|
|
+ if (!appBundle) {
|
|
+ return NS_ERROR_FAILURE;
|
|
+ }
|
|
+
|
|
+ CFURLRef iniURL = CFBundleCopyResourceURL(appBundle, CFSTR("application.ini"),
|
|
+ NULL, CFSTR("app"));
|
|
+ if (!iniURL) {
|
|
+ return NS_ERROR_FAILURE;
|
|
+ }
|
|
+
|
|
+ nsresult rv;
|
|
+ if (CFURLGetFileSystemRepresentation(iniURL, false, (UInt8*)aResult,
|
|
+ MAXPATHLEN)) {
|
|
+ // Sanitize path in case the app was launched from Terminal via
|
|
+ // './firefox' for example.
|
|
+ size_t readPos = 0;
|
|
+ size_t writePos = 0;
|
|
+ while (aResult[readPos] != '\0') {
|
|
+ if (aResult[readPos] == '.' && aResult[readPos + 1] == '/') {
|
|
+ readPos += 2;
|
|
+ } else {
|
|
+ aResult[writePos] = aResult[readPos];
|
|
+ readPos++;
|
|
+ writePos++;
|
|
+ }
|
|
+ }
|
|
+ aResult[writePos] = '\0';
|
|
+ rv = NS_OK;
|
|
+ } else {
|
|
+ rv = NS_ERROR_FAILURE;
|
|
+ }
|
|
+
|
|
+ CFRelease(iniURL);
|
|
+ return rv;
|
|
+ }
|
|
+
|
|
#elif defined(ANDROID)
|
|
static nsresult Get(char aResult[MAXPATHLEN]) {
|
|
// On Android, we use the MOZ_ANDROID_LIBDIR variable that is set by the
|
|
// Java bootstrap code.
|
|
const char* libDir = getenv("MOZ_ANDROID_LIBDIR");
|
|
if (!libDir) {
|
|
return NS_ERROR_FAILURE;
|
|
}
|
|
@@ -281,16 +321,29 @@ class BinaryPath {
|
|
if (NS_FAILED(Get(path))) {
|
|
return nullptr;
|
|
}
|
|
UniqueFreePtr<char> result;
|
|
result.reset(strdup(path));
|
|
return result;
|
|
}
|
|
|
|
+#if defined(XP_MACOSX)
|
|
+ static UniqueFreePtr<char> GetApplicationIni()
|
|
+ {
|
|
+ char path[MAXPATHLEN];
|
|
+ if (NS_FAILED(GetApplicationIni(path))) {
|
|
+ return nullptr;
|
|
+ }
|
|
+ UniqueFreePtr<char> result;
|
|
+ result.reset(strdup(path));
|
|
+ return result;
|
|
+ }
|
|
+#endif
|
|
+
|
|
#ifdef MOZILLA_INTERNAL_API
|
|
static nsresult GetFile(nsIFile** aResult) {
|
|
nsCOMPtr<nsIFile> lf;
|
|
# ifdef XP_WIN
|
|
wchar_t exePath[MAXPATHLEN];
|
|
nsresult rv = GetW(exePath);
|
|
# else
|
|
char exePath[MAXPATHLEN];
|
|
diff --git a/mozglue/build/AudioQueueSanitizer.cpp b/mozglue/build/AudioQueueSanitizer.cpp
|
|
new file mode 100644
|
|
index 000000000000..9efa3255c472
|
|
--- /dev/null
|
|
+++ b/mozglue/build/AudioQueueSanitizer.cpp
|
|
@@ -0,0 +1,91 @@
|
|
+/* -*- 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/. */
|
|
+
|
|
+// Work around a use-after-free in the macOS 27 system speech synthesizer.
|
|
+//
|
|
+// When an utterance finishes, the AudioQueue player in the private
|
|
+// TextToSpeech framework (used by both NSSpeechSynthesizer and
|
|
+// AVSpeechSynthesizer) enqueues a short de-click ramp that starts from a
|
|
+// sample read out of a buffer it has already freed. With the system
|
|
+// allocator, which zeroes freed memory, that sample is 0 and the ramp is
|
|
+// silent. mozjemalloc poisons freed memory with 0xE5 instead, which reads
|
|
+// as -1.36e23 in float32, so every utterance ends with a ~10 ms full-scale
|
|
+// burst.
|
|
+//
|
|
+// We can't fix the framework, so we interpose AudioQueueEnqueueBuffer and
|
|
+// zero any float samples that are non-finite or far outside the nominal
|
|
+// [-1, 1] range before they reach CoreAudio. Real audio never gets close
|
|
+// to kMaxSampleMagnitude, so this only ever affects garbage.
|
|
+//
|
|
+// dyld only honors __interpose tuples in images loaded at launch, which is
|
|
+// why this needs to be in mozglue rather than in XUL (loaded with dlopen)
|
|
+// alongside OSXSpeechSynthesizerService.
|
|
+
|
|
+#include <AudioToolbox/AudioToolbox.h>
|
|
+#include <math.h>
|
|
+
|
|
+namespace {
|
|
+
|
|
+constexpr float kMaxSampleMagnitude = 16.0f;
|
|
+
|
|
+void SanitizeBuffer(AudioQueueRef aQueue, AudioQueueBufferRef aBuffer) {
|
|
+ AudioStreamBasicDescription format;
|
|
+ UInt32 size = sizeof(format);
|
|
+ if (AudioQueueGetProperty(aQueue, kAudioQueueProperty_StreamDescription,
|
|
+ &format, &size) != noErr) {
|
|
+ return;
|
|
+ }
|
|
+ if (format.mFormatID != kAudioFormatLinearPCM ||
|
|
+ !(format.mFormatFlags & kAudioFormatFlagIsFloat) ||
|
|
+ format.mBitsPerChannel != 32) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ float* samples = static_cast<float*>(aBuffer->mAudioData);
|
|
+ UInt32 count = aBuffer->mAudioDataByteSize / sizeof(float);
|
|
+ for (UInt32 i = 0; i < count; i++) {
|
|
+ // Written so that NaN also fails the comparison.
|
|
+ if (!(fabsf(samples[i]) <= kMaxSampleMagnitude)) {
|
|
+ samples[i] = 0.0f;
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+OSStatus SanitizingEnqueueBuffer(
|
|
+ AudioQueueRef aQueue, AudioQueueBufferRef aBuffer, UInt32 aNumPackets,
|
|
+ const AudioStreamPacketDescription* aPacketDescs) {
|
|
+ SanitizeBuffer(aQueue, aBuffer);
|
|
+ return AudioQueueEnqueueBuffer(aQueue, aBuffer, aNumPackets, aPacketDescs);
|
|
+}
|
|
+
|
|
+OSStatus SanitizingEnqueueBufferWithParameters(
|
|
+ AudioQueueRef aQueue, AudioQueueBufferRef aBuffer, UInt32 aNumPackets,
|
|
+ const AudioStreamPacketDescription* aPacketDescs, UInt32 aTrimFrames,
|
|
+ UInt32 aTrimFramesAtEnd, UInt32 aNumParamValues,
|
|
+ const AudioQueueParameterEvent* aParamValues,
|
|
+ const AudioTimeStamp* aStartTime, AudioTimeStamp* aActualStartTime) {
|
|
+ SanitizeBuffer(aQueue, aBuffer);
|
|
+ return AudioQueueEnqueueBufferWithParameters(
|
|
+ aQueue, aBuffer, aNumPackets, aPacketDescs, aTrimFrames,
|
|
+ aTrimFramesAtEnd, aNumParamValues, aParamValues, aStartTime,
|
|
+ aActualStartTime);
|
|
+}
|
|
+
|
|
+struct Interpose {
|
|
+ const void* mReplacement;
|
|
+ const void* mReplacee;
|
|
+};
|
|
+
|
|
+__attribute__((used, section("__DATA,__interpose"))) const Interpose
|
|
+ kInterposes[] = {
|
|
+ {reinterpret_cast<const void*>(&SanitizingEnqueueBuffer),
|
|
+ reinterpret_cast<const void*>(&AudioQueueEnqueueBuffer)},
|
|
+ {reinterpret_cast<const void*>(&SanitizingEnqueueBufferWithParameters),
|
|
+ reinterpret_cast<const void*>(
|
|
+ &AudioQueueEnqueueBufferWithParameters)},
|
|
+};
|
|
+
|
|
+} // namespace
|
|
diff --git a/mozglue/build/moz.build b/mozglue/build/moz.build
|
|
index f8f01e999e54..111fe5af1b0d 100644
|
|
--- a/mozglue/build/moz.build
|
|
+++ b/mozglue/build/moz.build
|
|
@@ -41,6 +41,14 @@ if CONFIG["OS_TARGET"] == "WINNT":
|
|
"winmm.dll",
|
|
]
|
|
|
|
+if CONFIG["OS_TARGET"] == "Darwin" and FORCE_SHARED_LIB:
|
|
+ SOURCES += [
|
|
+ "AudioQueueSanitizer.cpp",
|
|
+ ]
|
|
+ OS_LIBS += [
|
|
+ "-framework AudioToolbox",
|
|
+ ]
|
|
+
|
|
if CONFIG["MOZ_WIDGET_TOOLKIT"]:
|
|
if CONFIG["MOZ_MEMORY"] and FORCE_SHARED_LIB:
|
|
pass
|