bool UnshareUserNamespace() { // The uid and gid need to be retrieved before the unshare; see // below. uid_t uid = getuid(); gid_t gid = getgid(); char buf[80]; size_t len; if (syscall(__NR_unshare, CLONE_NEWUSER) != 0) { return false; } // As mentioned in the header, this function sets up uid/gid // mappings that preserve the process's previous ids. Mapping the // uid/gid to something is necessary in order to nest user // namespaces (not used yet, but we'll need this in the future for // pid namespace support), and leaving the ids unchanged is the // least confusing option. // // In recent kernels (3.19, 3.18.2, 3.17.8), for security reasons, // establishing gid mappings will fail unless the process first // revokes its ability to call setgroups() by using a /proc node // added in the same set of patches. // // Note that /proc/self points to the thread group leader, not the // current thread. However, CLONE_NEWUSER can be unshared only in a // single-threaded process, so those are equivalent if we reach this // point. len = size_t(SprintfLiteral(buf, "%u %u 1\n", uid, uid)); MOZ_ASSERT(len < sizeof(buf)); if (!WriteStringToFile("/proc/self/uid_map", buf, len)) { MOZ_CRASH("Failed to write /proc/self/uid_map"); } Unused << WriteStringToFile("/proc/self/setgroups", "deny", 4); len = size_t(SprintfLiteral(buf, "%u %u 1\n", gid, gid)); MOZ_ASSERT(len < sizeof(buf)); if (!WriteStringToFile("/proc/self/gid_map", buf, len)) { MOZ_CRASH("Failed to write /proc/self/gid_map"); } return true; }
static int do_main(int argc, char* argv[]) { nsCOMPtr<nsIFile> appini; nsresult rv; // 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"); if (appDataFile && *appDataFile) { rv = XRE_GetFileFromPath(appDataFile, getter_AddRefs(appini)); if (NS_FAILED(rv)) { Output("Invalid path found: '%s'", appDataFile); return 255; } } else if (argc > 1 && IsArg(argv[1], "app")) { if (argc == 2) { Output("Incorrect number of arguments passed to -app"); return 255; } rv = XRE_GetFileFromPath(argv[2], getter_AddRefs(appini)); if (NS_FAILED(rv)) { Output("application.ini path not recognized: '%s'", argv[2]); return 255; } char appEnv[MAXPATHLEN]; SprintfLiteral(appEnv, "XUL_APP_FILE=%s", argv[2]); if (putenv(strdup(appEnv))) { Output("Couldn't set %s.\n", appEnv); return 255; } argv[2] = argv[0]; argv += 2; argc -= 2; } #ifdef MOZ_WIDGET_GONK /* Start boot animation */ mozilla::StartBootAnimation(); #endif if (appini) { nsXREAppData *appData; rv = XRE_CreateAppData(appini, &appData); if (NS_FAILED(rv)) { Output("Couldn't read application.ini"); return 255; } int result = XRE_main(argc, argv, appData, 0); XRE_FreeAppData(appData); return result; } return XRE_main(argc, argv, &sAppData, 0); }
void FeatureState::Instance::Set(FeatureStatus aStatus, const char* aMessage /* = nullptr */) { mStatus = aStatus; if (aMessage) { SprintfLiteral(mMessage, "%s", aMessage); } else { mMessage[0] = '\0'; } }
// Generate 'usage' and 'help' properties for the given object. // JS_DefineFunctionsWithHelp will define individual function objects with both // of those properties (eg getpid.usage = "getpid()" and getpid.help = "return // the process id"). This function will generate strings for an "interface // object", eg os.file, which contains some number of functions. // // .usage will be set to "<name> - interface object". // // .help will be set to a newline-separated list of functions that have either // 'help' or 'usage' properties. Functions are described with their usage // strings, if they have them, else with just their names. // bool GenerateInterfaceHelp(JSContext* cx, HandleObject obj, const char* name) { AutoIdVector idv(cx); if (!GetPropertyKeys(cx, obj, JSITER_OWNONLY | JSITER_HIDDEN, &idv)) return false; StringBuffer buf(cx); int numEntries = 0; for (size_t i = 0; i < idv.length(); i++) { RootedId id(cx, idv[i]); RootedValue v(cx); if (!JS_GetPropertyById(cx, obj, id, &v)) return false; if (!v.isObject()) continue; RootedObject prop(cx, &v.toObject()); RootedValue usage(cx); RootedValue help(cx); if (!JS_GetProperty(cx, prop, "usage", &usage)) return false; if (!JS_GetProperty(cx, prop, "help", &help)) return false; if (!usage.isString() && !help.isString()) continue; if (numEntries && !buf.append("\n")) return false; numEntries++; if (!buf.append(" ", 2)) return false; if (!buf.append(usage.isString() ? usage.toString() : JSID_TO_FLAT_STRING(id))) return false; } RootedString s(cx, buf.finishString()); if (!s || !JS_DefineProperty(cx, obj, "help", s, 0)) return false; buf.clear(); if (!buf.append(name, strlen(name)) || !buf.append(" - interface object with ", 25)) return false; char cbuf[100]; SprintfLiteral(cbuf, "%d %s", numEntries, numEntries == 1 ? "entry" : "entries"); if (!buf.append(cbuf, strlen(cbuf))) return false; s = buf.finishString(); if (!s || !JS_DefineProperty(cx, obj, "usage", s, 0)) return false; return true; }
NS_IMETHODIMP nsScriptableDateFormat::FormatDateTime( const char16_t *aLocale, nsDateFormatSelector dateFormatSelector, nsTimeFormatSelector timeFormatSelector, int32_t year, int32_t month, int32_t day, int32_t hour, int32_t minute, int32_t second, char16_t **dateTimeString) { // We can't have a valid date with the year, month or day // being lower than 1. if (year < 1 || month < 1 || day < 1) return NS_ERROR_INVALID_ARG; nsresult rv; *dateTimeString = nullptr; tm tmTime; time_t timetTime; memset(&tmTime, 0, sizeof(tmTime)); tmTime.tm_year = year - 1900; tmTime.tm_mon = month - 1; tmTime.tm_mday = day; tmTime.tm_hour = hour; tmTime.tm_min = minute; tmTime.tm_sec = second; tmTime.tm_yday = tmTime.tm_wday = 0; tmTime.tm_isdst = -1; timetTime = mktime(&tmTime); if ((time_t)-1 != timetTime) { rv = mozilla::DateTimeFormat::FormatTime(dateFormatSelector, timeFormatSelector, timetTime, mStringOut); } else { // if mktime fails (e.g. year <= 1970), then try NSPR. PRTime prtime; char string[32]; SprintfLiteral(string, "%.2d/%.2d/%d %.2d:%.2d:%.2d", month, day, year, hour, minute, second); if (PR_SUCCESS != PR_ParseTimeString(string, false, &prtime)) return NS_ERROR_INVALID_ARG; rv = mozilla::DateTimeFormat::FormatPRTime(dateFormatSelector, timeFormatSelector, prtime, mStringOut); } if (NS_SUCCEEDED(rv)) *dateTimeString = ToNewUnicode(mStringOut); return rv; }
void ResourceQueue::Dump(const char* aPath) { for (uint32_t i = 0; i < uint32_t(GetSize()); ++i) { ResourceItem* item = ResourceAt(i); char buf[255]; SprintfLiteral(buf, "%s/%08u.bin", aPath, i); FILE* fp = fopen(buf, "wb"); if (!fp) { return; } Unused << fwrite(item->mData->Elements(), item->mData->Length(), 1, fp); fclose(fp); } }
detail::LogFile* OpenFile(bool aShouldAppend, uint32_t aFileNum) { FILE* file; if (mRotate > 0) { char buf[2048]; SprintfLiteral(buf, "%s.%d", mOutFilePath.get(), aFileNum); // rotate doesn't support append. file = fopen(buf, "w"); } else { file = fopen(mOutFilePath.get(), aShouldAppend ? "a" : "w"); } if (!file) { return nullptr; } return new detail::LogFile(file, aFileNum); }
static FILE* OpenDumpFile(uint32_t aChannels, uint32_t aRate) { /** * When MOZ_DUMP_AUDIO is set in the environment (to anything), * we'll drop a series of files in the current working directory named * dumped-audio-<nnn>.wav, one per AudioStream created, containing * the audio for the stream including any skips due to underruns. */ static Atomic<int> gDumpedAudioCount(0); if (!getenv("MOZ_DUMP_AUDIO")) return nullptr; char buf[100]; SprintfLiteral(buf, "dumped-audio-%d.wav", ++gDumpedAudioCount); FILE* f = fopen(buf, "wb"); if (!f) return nullptr; uint8_t header[] = { // RIFF header 0x52, 0x49, 0x46, 0x46, 0x00, 0x00, 0x00, 0x00, 0x57, 0x41, 0x56, 0x45, // fmt chunk. We always write 16-bit samples. 0x66, 0x6d, 0x74, 0x20, 0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0x10, 0x00, // data chunk 0x64, 0x61, 0x74, 0x61, 0xFE, 0xFF, 0xFF, 0x7F }; static const int CHANNEL_OFFSET = 22; static const int SAMPLE_RATE_OFFSET = 24; static const int BLOCK_ALIGN_OFFSET = 32; SetUint16LE(header + CHANNEL_OFFSET, aChannels); SetUint32LE(header + SAMPLE_RATE_OFFSET, aRate); SetUint16LE(header + BLOCK_ALIGN_OFFSET, aChannels * 2); Unused << fwrite(header, sizeof(header), 1, f); return f; }
void GPUProcessManager::OnProcessUnexpectedShutdown(GPUProcessHost* aHost) { MOZ_ASSERT(mProcess && mProcess == aHost); DestroyProcess(); if (mNumProcessAttempts > uint32_t(gfxPrefs::GPUProcessMaxRestarts())) { char disableMessage[64]; SprintfLiteral(disableMessage, "GPU process disabled after %d attempts", mNumProcessAttempts); DisableGPUProcess(disableMessage); } else if (mNumProcessAttempts > uint32_t(gfxPrefs::GPUProcessMaxRestartsWithDecoder()) && mDecodeVideoOnGpuProcess) { mDecodeVideoOnGpuProcess = false; Telemetry::Accumulate(Telemetry::GPU_PROCESS_CRASH_FALLBACKS, uint32_t(FallbackType::DECODINGDISABLED)); } else { Telemetry::Accumulate(Telemetry::GPU_PROCESS_CRASH_FALLBACKS, uint32_t(FallbackType::NONE)); } HandleProcessLost(); }
RefPtr<DtlsIdentity> DtlsIdentity::Generate() { UniquePK11SlotInfo slot(PK11_GetInternalSlot()); if (!slot) { return nullptr; } uint8_t random_name[16]; SECStatus rv = PK11_GenerateRandomOnSlot(slot.get(), random_name, sizeof(random_name)); if (rv != SECSuccess) return nullptr; std::string name; char chunk[3]; for (size_t i = 0; i < sizeof(random_name); ++i) { SprintfLiteral(chunk, "%.2x", random_name[i]); name += chunk; } std::string subject_name_string = "CN=" + name; UniqueCERTName subject_name(CERT_AsciiToName(subject_name_string.c_str())); if (!subject_name) { return nullptr; } unsigned char paramBuf[12]; // OIDs are small SECItem ecdsaParams = { siBuffer, paramBuf, sizeof(paramBuf) }; SECOidData* oidData = SECOID_FindOIDByTag(SEC_OID_SECG_EC_SECP256R1); if (!oidData || (oidData->oid.len > (sizeof(paramBuf) - 2))) { return nullptr; } ecdsaParams.data[0] = SEC_ASN1_OBJECT_ID; ecdsaParams.data[1] = oidData->oid.len; memcpy(ecdsaParams.data + 2, oidData->oid.data, oidData->oid.len); ecdsaParams.len = oidData->oid.len + 2; SECKEYPublicKey *pubkey; UniqueSECKEYPrivateKey private_key( PK11_GenerateKeyPair(slot.get(), CKM_EC_KEY_PAIR_GEN, &ecdsaParams, &pubkey, PR_FALSE, PR_TRUE, nullptr)); if (private_key == nullptr) return nullptr; UniqueSECKEYPublicKey public_key(pubkey); pubkey = nullptr; UniqueCERTSubjectPublicKeyInfo spki( SECKEY_CreateSubjectPublicKeyInfo(public_key.get())); if (!spki) { return nullptr; } UniqueCERTCertificateRequest certreq( CERT_CreateCertificateRequest(subject_name.get(), spki.get(), nullptr)); if (!certreq) { return nullptr; } // From 1 day before todayto 30 days after. // This is a sort of arbitrary range designed to be valid // now with some slack in case the other side expects // some before expiry. // // Note: explicit casts necessary to avoid // warning C4307: '*' : integral constant overflow static const PRTime oneDay = PRTime(PR_USEC_PER_SEC) * PRTime(60) // sec * PRTime(60) // min * PRTime(24); // hours PRTime now = PR_Now(); PRTime notBefore = now - oneDay; PRTime notAfter = now + (PRTime(30) * oneDay); UniqueCERTValidity validity(CERT_CreateValidity(notBefore, notAfter)); if (!validity) { return nullptr; } unsigned long serial; // Note: This serial in principle could collide, but it's unlikely rv = PK11_GenerateRandomOnSlot(slot.get(), reinterpret_cast<unsigned char *>(&serial), sizeof(serial)); if (rv != SECSuccess) { return nullptr; } UniqueCERTCertificate certificate( CERT_CreateCertificate(serial, subject_name.get(), validity.get(), certreq.get())); if (!certificate) { return nullptr; } PLArenaPool *arena = certificate->arena; rv = SECOID_SetAlgorithmID(arena, &certificate->signature, SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE, 0); if (rv != SECSuccess) return nullptr; // Set version to X509v3. *(certificate->version.data) = SEC_CERTIFICATE_VERSION_3; certificate->version.len = 1; SECItem innerDER; innerDER.len = 0; innerDER.data = nullptr; if (!SEC_ASN1EncodeItem(arena, &innerDER, certificate.get(), SEC_ASN1_GET(CERT_CertificateTemplate))) { return nullptr; } SECItem *signedCert = PORT_ArenaZNew(arena, SECItem); if (!signedCert) { return nullptr; } rv = SEC_DerSignData(arena, signedCert, innerDER.data, innerDER.len, private_key.get(), SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE); if (rv != SECSuccess) { return nullptr; } certificate->derCert = *signedCert; RefPtr<DtlsIdentity> identity = new DtlsIdentity(Move(private_key), Move(certificate), ssl_kea_ecdh); return identity.forget(); }
void ThreadStackHelper::CollectPseudoEntry(const js::ProfileEntry& aEntry) { // For non-js frames we just include the raw label. if (!aEntry.isJs()) { const char* entryLabel = aEntry.label(); // entryLabel is a statically allocated string, so we want to store a // reference to it without performing any allocations. This is important, as // we aren't allowed to allocate within this function. // // The variant for this kind of label in our HangStack object is a // `nsCString`, which normally contains heap allocated string data. However, // `nsCString` has an optimization for literal strings which causes the // backing data to not be copied when being copied between nsCString // objects. // // We take advantage of that optimization by creating a nsCString object // which has the LITERAL flag set. Without this optimization, this code // would be incorrect. nsCString label; label.AssignLiteral(entryLabel, strlen(entryLabel)); // Let's make sure we don't deadlock here, by asserting that `label`'s // backing data matches. MOZ_RELEASE_ASSERT(label.BeginReading() == entryLabel, "String copy performed during ThreadStackHelper::CollectPseudoEntry"); TryAppendFrame(label); return; } if (!aEntry.script()) { TryAppendFrame(HangEntrySuppressed()); return; } if (!IsChromeJSScript(aEntry.script())) { TryAppendFrame(HangEntryContent()); return; } // Rather than using the profiler's dynamic string, we compute our own string. // This is because we want to do some size-saving strategies, and throw out // information which won't help us as much. // XXX: We currently don't collect the function name which hung. const char* filename = JS_GetScriptFilename(aEntry.script()); unsigned lineno = JS_PCToLineNumber(aEntry.script(), aEntry.pc()); // Some script names are in the form "foo -> bar -> baz". // Here we find the origin of these redirected scripts. const char* basename = GetPathAfterComponent(filename, " -> "); if (basename) { filename = basename; } // Strip chrome:// or resource:// off of the filename if present. basename = GetFullPathForScheme(filename, "chrome://"); if (!basename) { basename = GetFullPathForScheme(filename, "resource://"); } if (!basename) { // If we're in an add-on script, under the {profile}/extensions // directory, extract the path after the /extensions/ part. basename = GetPathAfterComponent(filename, "/extensions/"); } if (!basename) { // Only keep the file base name for paths outside the above formats. basename = strrchr(filename, '/'); basename = basename ? basename + 1 : filename; // Look for Windows path separator as well. filename = strrchr(basename, '\\'); if (filename) { basename = filename + 1; } } char buffer[128]; // Enough to fit longest js file name from the tree size_t len = SprintfLiteral(buffer, "%s:%u", basename, lineno); if (len < sizeof(buffer)) { mDesiredBufferSize += len + 1; if (mStackToFill->stack().Capacity() > mStackToFill->stack().Length() && (mStackToFill->strbuffer().Capacity() - mStackToFill->strbuffer().Length()) > len + 1) { // NOTE: We only increment this if we're going to successfully append. mDesiredStackSize += 1; uint32_t start = mStackToFill->strbuffer().Length(); mStackToFill->strbuffer().AppendElements(buffer, len); mStackToFill->strbuffer().AppendElement('\0'); mStackToFill->stack().AppendElement(HangEntryBufOffset(start)); return; } } TryAppendFrame(HangEntryChromeScript()); }
NS_IMETHODIMP nsScriptableDateFormat::FormatDateTime( const char16_t *aLocale, nsDateFormatSelector dateFormatSelector, nsTimeFormatSelector timeFormatSelector, int32_t year, int32_t month, int32_t day, int32_t hour, int32_t minute, int32_t second, char16_t **dateTimeString) { // We can't have a valid date with the year, month or day // being lower than 1. if (year < 1 || month < 1 || day < 1) return NS_ERROR_INVALID_ARG; nsresult rv; nsAutoString localeName(aLocale); *dateTimeString = nullptr; nsCOMPtr<nsILocale> locale; // re-initialise locale pointer only if the locale was given explicitly if (!localeName.IsEmpty()) { // get locale service nsCOMPtr<nsILocaleService> localeService(do_GetService(kLocaleServiceCID, &rv)); NS_ENSURE_SUCCESS(rv, rv); // get locale rv = localeService->NewLocale(localeName, getter_AddRefs(locale)); NS_ENSURE_SUCCESS(rv, rv); } nsCOMPtr<nsIDateTimeFormat> dateTimeFormat(do_CreateInstance(kDateTimeFormatCID, &rv)); NS_ENSURE_SUCCESS(rv, rv); tm tmTime; time_t timetTime; memset(&tmTime, 0, sizeof(tmTime)); tmTime.tm_year = year - 1900; tmTime.tm_mon = month - 1; tmTime.tm_mday = day; tmTime.tm_hour = hour; tmTime.tm_min = minute; tmTime.tm_sec = second; tmTime.tm_yday = tmTime.tm_wday = 0; tmTime.tm_isdst = -1; timetTime = mktime(&tmTime); if ((time_t)-1 != timetTime) { rv = dateTimeFormat->FormatTime(locale, dateFormatSelector, timeFormatSelector, timetTime, mStringOut); } else { // if mktime fails (e.g. year <= 1970), then try NSPR. PRTime prtime; char string[32]; SprintfLiteral(string, "%.2d/%.2d/%d %.2d:%.2d:%.2d", month, day, year, hour, minute, second); if (PR_SUCCESS != PR_ParseTimeString(string, false, &prtime)) return NS_ERROR_INVALID_ARG; rv = dateTimeFormat->FormatPRTime(locale, dateFormatSelector, timeFormatSelector, prtime, mStringOut); } if (NS_SUCCEEDED(rv)) *dateTimeString = ToNewUnicode(mStringOut); return rv; }
int main(int argc, char* argv[]) { if (test_common_init(&argc, &argv) != 0) return -1; nsresult ret; nsCOMPtr<nsIServiceManager> servMan; NS_InitXPCOM2(getter_AddRefs(servMan), nullptr, nullptr); nsIInputStream* in = nullptr; nsCOMPtr<nsIScriptSecurityManager> secman = do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID, &ret); if (NS_FAILED(ret)) return 1; nsCOMPtr<nsIPrincipal> systemPrincipal; ret = secman->GetSystemPrincipal(getter_AddRefs(systemPrincipal)); if (NS_FAILED(ret)) return 1; nsCOMPtr<nsIURI> uri; ret = NS_NewURI(getter_AddRefs(uri), NS_LITERAL_CSTRING(TEST_URL)); if (NS_FAILED(ret)) return 1; nsIChannel *channel = nullptr; ret = NS_NewChannel(&channel, uri, systemPrincipal, nsILoadInfo::SEC_ALLOW_CROSS_ORIGIN_DATA_IS_NULL, nsIContentPolicy::TYPE_OTHER); if (NS_FAILED(ret)) return 1; ret = channel->Open2(&in); if (NS_FAILED(ret)) return 1; nsIPersistentProperties* props; ret = CallCreateInstance(kPersistentPropertiesCID, &props); if (NS_FAILED(ret) || (!props)) { printf("create nsIPersistentProperties failed\n"); return 1; } ret = props->Load(in); if (NS_FAILED(ret)) { printf("cannot load properties\n"); return 1; } int i = 1; while (1) { char name[16]; name[0] = 0; SprintfLiteral(name, "%d", i); nsAutoString v; ret = props->GetStringProperty(nsDependentCString(name), v); if (NS_FAILED(ret) || (!v.Length())) { break; } printf("\"%d\"=\"%s\"\n", i, NS_ConvertUTF16toUTF8(v).get()); i++; } nsCOMPtr<nsISimpleEnumerator> propEnum; ret = props->Enumerate(getter_AddRefs(propEnum)); if (NS_FAILED(ret)) { printf("cannot enumerate properties\n"); return 1; } printf("\nKey\tValue\n"); printf( "---\t-----\n"); bool hasMore; while (NS_SUCCEEDED(propEnum->HasMoreElements(&hasMore)) && hasMore) { nsCOMPtr<nsISupports> sup; ret = propEnum->GetNext(getter_AddRefs(sup)); nsCOMPtr<nsIPropertyElement> propElem = do_QueryInterface(sup, &ret); if (NS_FAILED(ret)) { printf("failed to get current item\n"); return 1; } nsAutoCString key; nsAutoString value; ret = propElem->GetKey(key); if (NS_FAILED(ret)) { printf("failed to get current element's key\n"); return 1; } ret = propElem->GetValue(value); if (NS_FAILED(ret)) { printf("failed to get current element's value\n"); return 1; } printf("%s\t%s\n", key.get(), NS_ConvertUTF16toUTF8(value).get()); } return 0; }
const char* ThreadStackHelper::AppendJSEntry(const volatile StackEntry* aEntry, intptr_t& aAvailableBufferSize, const char* aPrevLabel) { // May be called from another thread or inside a signal handler. // We assume querying the script is safe but we must not manupulate it. // Also we must not allocate any memory from heap. MOZ_ASSERT(aEntry->isJs()); MOZ_ASSERT(aEntry->script()); const char* label; if (IsChromeJSScript(aEntry->script())) { const char* filename = JS_GetScriptFilename(aEntry->script()); const unsigned lineno = JS_PCToLineNumber(aEntry->script(), aEntry->pc()); MOZ_ASSERT(filename); char buffer[128]; // Enough to fit longest js file name from the tree // Some script names are in the form "foo -> bar -> baz". // Here we find the origin of these redirected scripts. const char* basename = GetPathAfterComponent(filename, " -> "); if (basename) { filename = basename; } basename = GetFullPathForScheme(filename, "chrome://"); if (!basename) { basename = GetFullPathForScheme(filename, "resource://"); } if (!basename) { // If the (add-on) script is located under the {profile}/extensions // directory, extract the path after the /extensions/ part. basename = GetPathAfterComponent(filename, "/extensions/"); } if (!basename) { // Only keep the file base name for paths outside the above formats. basename = strrchr(filename, '/'); basename = basename ? basename + 1 : filename; // Look for Windows path separator as well. filename = strrchr(basename, '\\'); if (filename) { basename = filename + 1; } } size_t len = SprintfLiteral(buffer, "%s:%u", basename, lineno); if (len < sizeof(buffer)) { if (mStackToFill->IsSameAsEntry(aPrevLabel, buffer)) { return aPrevLabel; } // Keep track of the required buffer size aAvailableBufferSize -= (len + 1); if (aAvailableBufferSize >= 0) { // Buffer is big enough. return mStackToFill->InfallibleAppendViaBuffer(buffer, len); } // Buffer is not big enough; fall through to using static label below. } // snprintf failed or buffer is not big enough. label = "(chrome script)"; } else { label = "(content script)"; } if (mStackToFill->IsSameAsEntry(aPrevLabel, label)) { return aPrevLabel; } mStackToFill->infallibleAppend(label); return label; }
void Print(const char* aName, LogLevel aLevel, const char* aFmt, va_list aArgs) { const size_t kBuffSize = 1024; char buff[kBuffSize]; char* buffToWrite = buff; // For backwards compat we need to use the NSPR format string versions // of sprintf and friends and then hand off to printf. va_list argsCopy; va_copy(argsCopy, aArgs); size_t charsWritten = PR_vsnprintf(buff, kBuffSize, aFmt, argsCopy); va_end(argsCopy); if (charsWritten == kBuffSize - 1) { // We may have maxed out, allocate a buffer instead. buffToWrite = PR_vsmprintf(aFmt, aArgs); charsWritten = strlen(buffToWrite); } // Determine if a newline needs to be appended to the message. const char* newline = ""; if (charsWritten == 0 || buffToWrite[charsWritten - 1] != '\n') { newline = "\n"; } FILE* out = stderr; // In case we use rotate, this ensures the FILE is kept alive during // its use. Increased before we load mOutFile. ++mPrintEntryCount; detail::LogFile* outFile = mOutFile; if (outFile) { out = outFile->File(); } // This differs from the NSPR format in that we do not output the // opaque system specific thread pointer (ie pthread_t) cast // to a long. The address of the current PR_Thread continues to be // prefixed. // // Additionally we prefix the output with the abbreviated log level // and the module name. PRThread *currentThread = PR_GetCurrentThread(); const char *currentThreadName = (mMainThread == currentThread) ? "Main Thread" : PR_GetThreadName(currentThread); char noNameThread[40]; if (!currentThreadName) { SprintfLiteral(noNameThread, "Unnamed thread %p", currentThread); currentThreadName = noNameThread; } if (!mAddTimestamp) { fprintf_stderr(out, "[%s]: %s/%s %s%s", currentThreadName, ToLogStr(aLevel), aName, buffToWrite, newline); } else { PRExplodedTime now; PR_ExplodeTime(PR_Now(), PR_GMTParameters, &now); fprintf_stderr( out, "%04d-%02d-%02d %02d:%02d:%02d.%06d UTC - [%s]: %s/%s %s%s", now.tm_year, now.tm_month + 1, now.tm_mday, now.tm_hour, now.tm_min, now.tm_sec, now.tm_usec, currentThreadName, ToLogStr(aLevel), aName, buffToWrite, newline); } if (mIsSync) { fflush(out); } if (buffToWrite != buff) { PR_smprintf_free(buffToWrite); } if (mRotate > 0 && outFile) { int32_t fileSize = ftell(out); if (fileSize > mRotate) { uint32_t fileNum = outFile->Num(); uint32_t nextFileNum = fileNum + 1; if (nextFileNum >= kRotateFilesNumber) { nextFileNum = 0; } // And here is the trick. The current out-file remembers its order // number. When no other thread shifted the global file number yet, // we are the thread to open the next file. if (mOutFileNum.compareExchange(fileNum, nextFileNum)) { // We can work with mToReleaseFile because we are sure the // mPrintEntryCount can't drop to zero now - the condition // to actually delete what's stored in that member. // And also, no other thread can enter this piece of code // because mOutFile is still holding the current file with // the non-shifted number. The compareExchange() above is // a no-op for other threads. outFile->mNextToRelease = mToReleaseFile; mToReleaseFile = outFile; mOutFile = OpenFile(false, nextFileNum); } } } if (--mPrintEntryCount == 0 && mToReleaseFile) { // We were the last Print() entered, if there is a file to release // do it now. exchange() is atomic and makes sure we release the file // only once on one thread. detail::LogFile* release = mToReleaseFile.exchange(nullptr); delete release; } }
void RemoveFile(uint32_t aFileNum) { char buf[2048]; SprintfLiteral(buf, "%s.%d", mOutFilePath.get(), aFileNum); remove(buf); }
/** * Loads config from env vars if present. */ void Init() { bool shouldAppend = false; bool addTimestamp = false; bool isSync = false; int32_t rotate = 0; const char* modules = PR_GetEnv("MOZ_LOG"); if (!modules || !modules[0]) { modules = PR_GetEnv("MOZ_LOG_MODULES"); if (modules) { NS_WARNING("MOZ_LOG_MODULES is deprecated." "\nPlease use MOZ_LOG instead."); } } if (!modules || !modules[0]) { modules = PR_GetEnv("NSPR_LOG_MODULES"); if (modules) { NS_WARNING("NSPR_LOG_MODULES is deprecated." "\nPlease use MOZ_LOG instead."); } } NSPRLogModulesParser(modules, [&shouldAppend, &addTimestamp, &isSync, &rotate] (const char* aName, LogLevel aLevel, int32_t aValue) mutable { if (strcmp(aName, "append") == 0) { shouldAppend = true; } else if (strcmp(aName, "timestamp") == 0) { addTimestamp = true; } else if (strcmp(aName, "sync") == 0) { isSync = true; } else if (strcmp(aName, "rotate") == 0) { rotate = (aValue << 20) / kRotateFilesNumber; } else { LogModule::Get(aName)->SetLevel(aLevel); } }); // Rotate implies timestamp to make the files readable mAddTimestamp = addTimestamp || rotate > 0; mIsSync = isSync; mRotate = rotate; if (rotate > 0 && shouldAppend) { NS_WARNING("MOZ_LOG: when you rotate the log, you cannot use append!"); } const char* logFile = PR_GetEnv("MOZ_LOG_FILE"); if (!logFile || !logFile[0]) { logFile = PR_GetEnv("NSPR_LOG_FILE"); } if (logFile && logFile[0]) { static const char kPIDToken[] = "%PID"; const char* pidTokenPtr = strstr(logFile, kPIDToken); char buf[2048]; if (pidTokenPtr && SprintfLiteral(buf, "%.*s%d%s", static_cast<int>(pidTokenPtr - logFile), logFile, detail::log_pid(), pidTokenPtr + strlen(kPIDToken)) > 0) { logFile = buf; } mOutFilePath.reset(strdup(logFile)); if (mRotate > 0) { // Delete all the previously captured files, including non-rotated // log files, so that users don't complain our logs eat space even // after the rotate option has been added and don't happen to send // us old large logs along with the rotated files. remove(mOutFilePath.get()); for (uint32_t i = 0; i < kRotateFilesNumber; ++i) { RemoveFile(i); } } mOutFile = OpenFile(shouldAppend, mOutFileNum); } }