зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1613900 - P2 - Report original JS error message to StructuredCloneCallbacksError; r=baku,sfink
The idea is to propagate error messages defined in js.msg to StructuredCloneHolder and throw it with a data clone error later. So that developers can still understand the reason why serialization/deserialization fails and we don't need to implement two similar set of error messages on JS and DOM sides. Note that this patch gave up the original idea (report error message to console), but developers can stil get the error message by catching the exception. Differential Revision: https://phabricator.services.mozilla.com/D62260 --HG-- extra : moz-landing-system : lando
This commit is contained in:
Родитель
5c2a4608ad
Коммит
0e080c84cd
|
@ -113,8 +113,13 @@ bool StructuredCloneCallbacksCanTransfer(JSContext* aCx,
|
|||
aSameProcessScopeRequired);
|
||||
}
|
||||
|
||||
void StructuredCloneCallbacksError(JSContext* aCx, uint32_t aErrorId) {
|
||||
void StructuredCloneCallbacksError(JSContext* aCx, uint32_t aErrorId,
|
||||
void* aClosure, const char* aErrorMessage) {
|
||||
NS_WARNING("Failed to clone data.");
|
||||
StructuredCloneHolderBase* holder =
|
||||
static_cast<StructuredCloneHolderBase*>(aClosure);
|
||||
MOZ_ASSERT(holder);
|
||||
return holder->SetErrorMessage(aErrorMessage);
|
||||
}
|
||||
|
||||
void AssertTagValues() {
|
||||
|
@ -276,7 +281,7 @@ void StructuredCloneHolder::Write(JSContext* aCx, JS::Handle<JS::Value> aValue,
|
|||
ErrorResult& aRv) {
|
||||
if (!StructuredCloneHolderBase::Write(aCx, aValue, aTransfer,
|
||||
aCloneDataPolicy)) {
|
||||
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
|
||||
aRv.ThrowDataCloneError(mErrorMessage);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -294,11 +299,12 @@ void StructuredCloneHolder::Read(nsIGlobalObject* aGlobal, JSContext* aCx,
|
|||
MOZ_ASSERT(aGlobal);
|
||||
|
||||
mozilla::AutoRestore<nsIGlobalObject*> guard(mGlobal);
|
||||
auto errorMessageGuard = MakeScopeExit([&] { mErrorMessage.Truncate(); });
|
||||
mGlobal = aGlobal;
|
||||
|
||||
if (!StructuredCloneHolderBase::Read(aCx, aValue, aCloneDataPolicy)) {
|
||||
JS_ClearPendingException(aCx);
|
||||
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
|
||||
aRv.ThrowDataCloneError(mErrorMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -327,12 +333,14 @@ void StructuredCloneHolder::ReadFromBuffer(
|
|||
MOZ_ASSERT(!mBuffer, "ReadFromBuffer() must be called without a Write().");
|
||||
|
||||
mozilla::AutoRestore<nsIGlobalObject*> guard(mGlobal);
|
||||
auto errorMessageGuard = MakeScopeExit([&] { mErrorMessage.Truncate(); });
|
||||
mGlobal = aGlobal;
|
||||
|
||||
if (!JS_ReadStructuredClone(aCx, aBuffer, aAlgorithmVersion, CloneScope(),
|
||||
aValue, aCloneDataPolicy, &sCallbacks, this)) {
|
||||
JS_ClearPendingException(aCx);
|
||||
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
|
||||
aRv.ThrowDataCloneError(mErrorMessage);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -127,11 +127,20 @@ class StructuredCloneHolderBase {
|
|||
return size;
|
||||
}
|
||||
|
||||
void SetErrorMessage(const char* aErrorMessage) {
|
||||
mErrorMessage.Assign(aErrorMessage);
|
||||
}
|
||||
|
||||
protected:
|
||||
UniquePtr<JSAutoStructuredCloneBuffer> mBuffer;
|
||||
|
||||
StructuredCloneScope mStructuredCloneScope;
|
||||
|
||||
// Error message when a data clone error is about to throw. It's held while
|
||||
// the error callback is fired and it will be throw with a data clone error
|
||||
// later.
|
||||
nsCString mErrorMessage;
|
||||
|
||||
#ifdef DEBUG
|
||||
bool mClearCalled;
|
||||
#endif
|
||||
|
|
|
@ -275,7 +275,8 @@ typedef bool (*WriteStructuredCloneOp)(JSContext* cx,
|
|||
* To follow HTML5, the application must throw a DATA_CLONE_ERR DOMException
|
||||
* with error set to one of the JS_SCERR_* values.
|
||||
*/
|
||||
typedef void (*StructuredCloneErrorOp)(JSContext* cx, uint32_t errorid);
|
||||
typedef void (*StructuredCloneErrorOp)(JSContext* cx, uint32_t errorid,
|
||||
void* closure, const char* errorMessage);
|
||||
|
||||
/**
|
||||
* This is called when JS_ReadStructuredClone receives a transferable object
|
||||
|
|
|
@ -4870,6 +4870,20 @@ JS_PUBLIC_API void JS_ReportAllocationOverflow(JSContext* cx) {
|
|||
ReportAllocationOverflow(cx);
|
||||
}
|
||||
|
||||
JS_PUBLIC_API bool JS_ExpandErrorArgumentsASCII(JSContext* cx,
|
||||
JSErrorCallback errorCallback,
|
||||
const unsigned errorNumber,
|
||||
JSErrorReport* reportp, ...) {
|
||||
va_list ap;
|
||||
bool ok;
|
||||
|
||||
AssertHeapIsIdle();
|
||||
va_start(ap, reportp);
|
||||
ok = ExpandErrorArgumentsVA(cx, errorCallback, nullptr, errorNumber, nullptr,
|
||||
ArgumentsAreASCII, reportp, ap);
|
||||
va_end(ap);
|
||||
return ok;
|
||||
}
|
||||
/************************************************************************/
|
||||
|
||||
JS_PUBLIC_API bool JS_SetDefaultLocale(JSRuntime* rt, const char* locale) {
|
||||
|
|
|
@ -2479,6 +2479,10 @@ extern JS_PUBLIC_API bool JS_ReportErrorFlagsAndNumberUC(
|
|||
*/
|
||||
extern MOZ_COLD JS_PUBLIC_API void JS_ReportOutOfMemory(JSContext* cx);
|
||||
|
||||
extern JS_PUBLIC_API bool JS_ExpandErrorArgumentsASCII(
|
||||
JSContext* cx, JSErrorCallback errorCallback, const unsigned errorNumber,
|
||||
JSErrorReport* reportp, ...);
|
||||
|
||||
/**
|
||||
* Complain when an allocation size overflows the maximum supported limit.
|
||||
*/
|
||||
|
|
|
@ -592,59 +592,67 @@ static_assert(Scalar::Int8 == 0);
|
|||
template <typename... Args>
|
||||
static void ReportDataCloneError(JSContext* cx,
|
||||
const JSStructuredCloneCallbacks* callbacks,
|
||||
uint32_t errorId, Args&&... aArgs) {
|
||||
if (callbacks && callbacks->reportError) {
|
||||
callbacks->reportError(cx, errorId);
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t errorId, void* closure,
|
||||
Args&&... aArgs) {
|
||||
unsigned errorNumber;
|
||||
switch (errorId) {
|
||||
case JS_SCERR_DUP_TRANSFERABLE:
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
||||
JSMSG_SC_DUP_TRANSFERABLE);
|
||||
errorNumber = JSMSG_SC_DUP_TRANSFERABLE;
|
||||
break;
|
||||
|
||||
case JS_SCERR_TRANSFERABLE:
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
||||
JSMSG_SC_NOT_TRANSFERABLE);
|
||||
errorNumber = JSMSG_SC_NOT_TRANSFERABLE;
|
||||
break;
|
||||
|
||||
case JS_SCERR_UNSUPPORTED_TYPE:
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
||||
JSMSG_SC_UNSUPPORTED_TYPE);
|
||||
errorNumber = JSMSG_SC_UNSUPPORTED_TYPE;
|
||||
break;
|
||||
|
||||
case JS_SCERR_SHMEM_TRANSFERABLE:
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
||||
JSMSG_SC_SHMEM_TRANSFERABLE);
|
||||
errorNumber = JSMSG_SC_SHMEM_TRANSFERABLE;
|
||||
break;
|
||||
|
||||
case JS_SCERR_TYPED_ARRAY_DETACHED:
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
||||
JSMSG_TYPED_ARRAY_DETACHED);
|
||||
errorNumber = JSMSG_TYPED_ARRAY_DETACHED;
|
||||
break;
|
||||
|
||||
case JS_SCERR_WASM_NO_TRANSFER:
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
||||
JSMSG_WASM_NO_TRANSFER);
|
||||
errorNumber = JSMSG_WASM_NO_TRANSFER;
|
||||
break;
|
||||
|
||||
case JS_SCERR_NOT_CLONABLE:
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
||||
JSMSG_SC_NOT_CLONABLE,
|
||||
std::forward<Args>(aArgs)...);
|
||||
errorNumber = JSMSG_SC_NOT_CLONABLE;
|
||||
break;
|
||||
|
||||
case JS_SCERR_NOT_CLONABLE_WITH_COOP_COEP:
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
|
||||
JSMSG_SC_NOT_CLONABLE_WITH_COOP_COEP,
|
||||
std::forward<Args>(aArgs)...);
|
||||
errorNumber = JSMSG_SC_NOT_CLONABLE_WITH_COOP_COEP;
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_CRASH("Unkown errorId");
|
||||
break;
|
||||
}
|
||||
|
||||
if (callbacks && callbacks->reportError) {
|
||||
MOZ_RELEASE_ASSERT(!cx->isExceptionPending());
|
||||
|
||||
JSErrorReport report;
|
||||
// Get js error message if it's possible and propagate it through callback.
|
||||
if (JS_ExpandErrorArgumentsASCII(cx, GetErrorMessage, errorNumber, &report,
|
||||
std::forward<Args>(aArgs)...) &&
|
||||
report.message()) {
|
||||
callbacks->reportError(cx, errorId, closure, report.message().c_str());
|
||||
} else {
|
||||
ReportOutOfMemory(cx);
|
||||
|
||||
callbacks->reportError(cx, errorId, closure, "");
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, errorNumber,
|
||||
std::forward<Args>(aArgs)...);
|
||||
}
|
||||
|
||||
bool WriteStructuredClone(JSContext* cx, HandleValue v,
|
||||
|
@ -1154,7 +1162,7 @@ bool JSStructuredCloneWriter::parseTransferable() {
|
|||
template <typename... Args>
|
||||
bool JSStructuredCloneWriter::reportDataCloneError(uint32_t errorId,
|
||||
Args&&... aArgs) {
|
||||
ReportDataCloneError(context(), out.buf.callbacks_, errorId,
|
||||
ReportDataCloneError(context(), out.buf.callbacks_, errorId, out.buf.closure_,
|
||||
std::forward<Args>(aArgs)...);
|
||||
return false;
|
||||
}
|
||||
|
@ -2260,7 +2268,8 @@ bool JSStructuredCloneReader::readSharedArrayBuffer(MutableHandleValue vp) {
|
|||
auto error = context()->realm()->creationOptions().getCoopAndCoepEnabled()
|
||||
? JS_SCERR_NOT_CLONABLE_WITH_COOP_COEP
|
||||
: JS_SCERR_NOT_CLONABLE;
|
||||
ReportDataCloneError(context(), callbacks, error, "SharedArrayBuffer");
|
||||
ReportDataCloneError(context(), callbacks, error, closure,
|
||||
"SharedArrayBuffer");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2323,7 +2332,7 @@ bool JSStructuredCloneReader::readSharedWasmMemory(uint32_t nbytes,
|
|||
auto error = context()->realm()->creationOptions().getCoopAndCoepEnabled()
|
||||
? JS_SCERR_NOT_CLONABLE_WITH_COOP_COEP
|
||||
: JS_SCERR_NOT_CLONABLE;
|
||||
ReportDataCloneError(cx, callbacks, error, "WebAssembly.Memory");
|
||||
ReportDataCloneError(cx, callbacks, error, closure, "WebAssembly.Memory");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2754,7 +2763,7 @@ bool JSStructuredCloneReader::readTransferMap() {
|
|||
}
|
||||
|
||||
if (tag == SCTAG_TRANSFER_MAP_PENDING_ENTRY) {
|
||||
ReportDataCloneError(cx, callbacks, JS_SCERR_TRANSFERABLE);
|
||||
ReportDataCloneError(cx, callbacks, JS_SCERR_TRANSFERABLE, closure);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2777,7 +2786,7 @@ bool JSStructuredCloneReader::readTransferMap() {
|
|||
// Transferred ArrayBuffers in a DifferentProcess clone buffer
|
||||
// are treated as if they weren't Transferred at all. We should
|
||||
// only see SCTAG_TRANSFER_MAP_STORED_ARRAY_BUFFER.
|
||||
ReportDataCloneError(cx, callbacks, JS_SCERR_TRANSFERABLE);
|
||||
ReportDataCloneError(cx, callbacks, JS_SCERR_TRANSFERABLE, closure);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -2800,7 +2809,7 @@ bool JSStructuredCloneReader::readTransferMap() {
|
|||
return false;
|
||||
}
|
||||
if (tag != SCTAG_ARRAY_BUFFER_OBJECT) {
|
||||
ReportDataCloneError(cx, callbacks, JS_SCERR_TRANSFERABLE);
|
||||
ReportDataCloneError(cx, callbacks, JS_SCERR_TRANSFERABLE, closure);
|
||||
return false;
|
||||
}
|
||||
RootedValue val(cx);
|
||||
|
@ -2810,7 +2819,7 @@ bool JSStructuredCloneReader::readTransferMap() {
|
|||
obj = &val.toObject();
|
||||
} else {
|
||||
if (!callbacks || !callbacks->readTransfer) {
|
||||
ReportDataCloneError(cx, callbacks, JS_SCERR_TRANSFERABLE);
|
||||
ReportDataCloneError(cx, callbacks, JS_SCERR_TRANSFERABLE, closure);
|
||||
return false;
|
||||
}
|
||||
if (!callbacks->readTransfer(cx, this, tag, content, extraData, closure,
|
||||
|
|
Загрузка…
Ссылка в новой задаче