/* * Since memory has been exhausted, avoid the normal error-handling path which * allocates an error object, report and callstack. If code is running, simply * throw the static atom "out of memory". If code is not running, call the * error reporter directly. * * Furthermore, callers of ReportOutOfMemory (viz., malloc) assume a GC does * not occur, so GC must be avoided or suppressed. */ void js::ReportOutOfMemory(ExclusiveContext* cxArg) { #ifdef JS_MORE_DETERMINISTIC /* * OOMs are non-deterministic, especially across different execution modes * (e.g. interpreter vs JIT). In more-deterministic builds, print to stderr * so that the fuzzers can detect this. */ fprintf(stderr, "ReportOutOfMemory called\n"); #endif if (!cxArg->isJSContext()) return cxArg->addPendingOutOfMemory(); JSContext* cx = cxArg->asJSContext(); cx->runtime()->hadOutOfMemory = true; AutoSuppressGC suppressGC(cx); /* Report the oom. */ if (JS::OutOfMemoryCallback oomCallback = cx->runtime()->oomCallback) oomCallback(cx, cx->runtime()->oomCallbackData); if (cx->options().autoJSAPIOwnsErrorReporting() || JS_IsRunning(cx)) { cx->setPendingException(StringValue(cx->names().outOfMemory)); return; } /* Get the message for this error, but we don't expand any arguments. */ const JSErrorFormatString* efs = GetErrorMessage(nullptr, JSMSG_OUT_OF_MEMORY); const char* msg = efs ? efs->format : "Out of memory"; /* Fill out the report, but don't do anything that requires allocation. */ JSErrorReport report; report.flags = JSREPORT_ERROR; report.errorNumber = JSMSG_OUT_OF_MEMORY; PopulateReportBlame(cx, &report); /* Report the error. */ if (JSErrorReporter onError = cx->runtime()->errorReporter) onError(cx, msg, &report); /* * We would like to enforce the invariant that any exception reported * during an OOM situation does not require wrapping. Besides avoiding * allocation when memory is low, this reduces the number of places where * we might need to GC. * * When JS code is running, we set the pending exception to an atom, which * does not need wrapping. If no JS code is running, no exception should be * set at all. */ MOZ_ASSERT(!cx->isExceptionPending()); }