int main(int argc, char **argv) { ScopedXPCOM xpcom("TestMimeCrash"); if (xpcom.failed()) return 1; // We cannot use malloc() since this crashes depends on memory allocation. // By using mmap()/PR_MemMap(), end of buffer that is last in the page // sets LF. PRUint32 bufsize = PR_GetPageSize(); PRFileMap *fm = PR_OpenAnonFileMap(".", bufsize, PR_PROT_READWRITE); if (!fm) return 1; char *addr = (char *) PR_MemMap(fm, 0, bufsize); if (!addr) return 1; memset(addr, '\r', bufsize); nsresult rv = do_test(addr, bufsize); PR_MemUnmap(addr, bufsize); PR_CloseFileMap(fm); if (NS_FAILED(rv)) { fail("cannot use nsIMimeConverter error=%08x\n", rv); return -1; } passed("no crash"); return 0; }
nsresult AutoMemMap::init(const char* filePath, int flags, int mode, PRFileMapProtect prot) { MOZ_ASSERT(!fd); MOZ_ASSERT(!fileMap); MOZ_ASSERT(!addr); if (PR_GetFileInfo64(filePath, &fileInfo) != PR_SUCCESS) return NS_ERROR_FILE_NOT_FOUND; // Check if the file is too big to memmap. if (fileInfo.size > int64_t(UINT32_MAX)) return NS_ERROR_INVALID_ARG; auto length = uint32_t(fileInfo.size); fd = PR_Open(filePath, flags, flags); if (!fd) return NS_ERROR_UNEXPECTED; fileMap = PR_CreateFileMap(fd, fileInfo.size, prot); if (!fileMap) return NS_ERROR_UNEXPECTED; addr = PR_MemMap(fileMap, 0, length); if (!addr) return NS_ERROR_UNEXPECTED; return NS_OK; }
PRStatus FastFetchFile(PRFileDesc *in, PRFileDesc *out, PRUint32 size) { PRInt32 nBytes; PRFileMap *outfMap; void *addr; char *start; PRUint32 rem; PRUint32 bytesToRead; PRStatus rv; PRInt64 sz64; LL_UI2L(sz64, size); outfMap = PR_CreateFileMap(out, sz64, PR_PROT_READWRITE); PR_ASSERT(outfMap); addr = PR_MemMap(outfMap, LL_ZERO, size); if (addr == (void *) -1) { fprintf(stderr, "cannot memory-map file: (%d, %d)\n", PR_GetError(), PR_GetOSError()); PR_CloseFileMap(outfMap); return PR_FAILURE; } PR_ASSERT(addr != (void *) -1); start = (char *) addr; rem = size; while ((nBytes = DrainInputBuffer(start, rem)) > 0) { start += nBytes; rem -= nBytes; } if (nBytes < 0) { /* Input buffer is empty and end of stream */ return PR_SUCCESS; } bytesToRead = (rem < FCOPY_BUFFER_SIZE) ? rem : FCOPY_BUFFER_SIZE; while (rem > 0 && (nBytes = PR_Read(in, start, bytesToRead)) > 0) { start += nBytes; rem -= nBytes; bytesToRead = (rem < FCOPY_BUFFER_SIZE) ? rem : FCOPY_BUFFER_SIZE; } if (nBytes < 0) { fprintf(stderr, "httpget: cannot read from socket\n"); return PR_FAILURE; } rv = PR_MemUnmap(addr, size); PR_ASSERT(rv == PR_SUCCESS); rv = PR_CloseFileMap(outfMap); PR_ASSERT(rv == PR_SUCCESS); return PR_SUCCESS; }
nsresult mozJSComponentLoader::GlobalForLocation(nsILocalFile *aComponent, JSObject **aGlobal, char **aLocation) { nsresult rv; JSPrincipals* jsPrincipals = nsnull; JSCLContextHelper cx(mContext); #ifndef XPCONNECT_STANDALONE rv = mSystemPrincipal->GetJSPrincipals(cx, &jsPrincipals); NS_ENSURE_SUCCESS(rv, rv); JSPrincipalsHolder princHolder(mContext, jsPrincipals); #endif nsCOMPtr<nsIXPCScriptable> backstagePass; rv = mRuntimeService->GetBackstagePass(getter_AddRefs(backstagePass)); NS_ENSURE_SUCCESS(rv, rv); JSCLAutoErrorReporterSetter aers(cx, mozJSLoaderErrorReporter); nsCOMPtr<nsIXPConnect> xpc = do_GetService(kXPConnectServiceContractID, &rv); NS_ENSURE_SUCCESS(rv, rv); // Make sure InitClassesWithNewWrappedGlobal() installs the // backstage pass as the global in our compilation context. JS_SetGlobalObject(cx, nsnull); nsCOMPtr<nsIXPConnectJSObjectHolder> holder; rv = xpc->InitClassesWithNewWrappedGlobal(cx, backstagePass, NS_GET_IID(nsISupports), nsIXPConnect:: FLAG_SYSTEM_GLOBAL_OBJECT, getter_AddRefs(holder)); NS_ENSURE_SUCCESS(rv, rv); JSObject *global; rv = holder->GetJSObject(&global); NS_ENSURE_SUCCESS(rv, rv); if (!JS_DefineFunctions(cx, global, gGlobalFun)) { return NS_ERROR_FAILURE; } nsCOMPtr<nsIXPConnectJSObjectHolder> locationHolder; rv = xpc->WrapNative(cx, global, aComponent, NS_GET_IID(nsILocalFile), getter_AddRefs(locationHolder)); NS_ENSURE_SUCCESS(rv, rv); JSObject *locationObj; rv = locationHolder->GetJSObject(&locationObj); NS_ENSURE_SUCCESS(rv, rv); if (!JS_DefineProperty(cx, global, "__LOCATION__", OBJECT_TO_JSVAL(locationObj), nsnull, nsnull, 0)) { return NS_ERROR_FAILURE; } nsCAutoString nativePath; // Quick hack to unbust XPCONNECT_STANDALONE. // This leaves the jsdebugger with a non-URL pathname in the // XPCONNECT_STANDALONE case - but at least it builds and runs otherwise. // See: http://bugzilla.mozilla.org/show_bug.cgi?id=121438 #ifdef XPCONNECT_STANDALONE localFile->GetNativePath(nativePath); #else NS_GetURLSpecFromFile(aComponent, nativePath); #endif // Before compiling the script, first check to see if we have it in // the fastload file. Note: as a rule, fastload errors are not fatal // to loading the script, since we can always slow-load. nsCOMPtr<nsIFastLoadService> flSvc = do_GetFastLoadService(&rv); // Save the old state and restore it upon return FastLoadStateHolder flState(flSvc); PRBool fastLoading = PR_FALSE; if (NS_SUCCEEDED(rv)) { rv = StartFastLoad(flSvc); if (NS_SUCCEEDED(rv)) { fastLoading = PR_TRUE; } } nsCOMPtr<nsIURI> uri; rv = NS_NewURI(getter_AddRefs(uri), nativePath); NS_ENSURE_SUCCESS(rv, rv); JSScript *script = nsnull; if (fastLoading) { rv = ReadScript(flSvc, nativePath.get(), uri, cx, &script); if (NS_SUCCEEDED(rv)) { LOG(("Successfully loaded %s from fastload\n", nativePath.get())); fastLoading = PR_FALSE; // no need to write out the script } else if (rv == NS_ERROR_NOT_AVAILABLE) { // This is ok, it just means the script is not yet in the // fastload file. rv = NS_OK; } else { LOG(("Failed to deserialize %s\n", nativePath.get())); // Remove the fastload file, it may be corrupted. LOG(("Invalid fastload file detected, removing it\n")); nsCOMPtr<nsIObjectOutputStream> objectOutput; flSvc->GetOutputStream(getter_AddRefs(objectOutput)); if (objectOutput) { flSvc->SetOutputStream(nsnull); objectOutput->Close(); } nsCOMPtr<nsIObjectInputStream> objectInput; flSvc->GetInputStream(getter_AddRefs(objectInput)); if (objectInput) { flSvc->SetInputStream(nsnull); objectInput->Close(); } if (mFastLoadFile) { mFastLoadFile->Remove(PR_FALSE); } fastLoading = PR_FALSE; } } if (!script || NS_FAILED(rv)) { // The script wasn't in the fastload cache, so compile it now. LOG(("Slow loading %s\n", nativePath.get())); #ifdef HAVE_PR_MEMMAP PRInt64 fileSize; rv = aComponent->GetFileSize(&fileSize); if (NS_FAILED(rv)) return rv; PRInt64 maxSize; LL_UI2L(maxSize, PR_UINT32_MAX); if (LL_CMP(fileSize, >, maxSize)) { NS_ERROR("file too large"); return NS_ERROR_FAILURE; } PRFileDesc *fileHandle; rv = aComponent->OpenNSPRFileDesc(PR_RDONLY, 0, &fileHandle); NS_ENSURE_SUCCESS(rv, rv); // Make sure the file is closed, no matter how we return. FileAutoCloser fileCloser(fileHandle); PRFileMap *map = PR_CreateFileMap(fileHandle, fileSize, PR_PROT_READONLY); if (!map) { NS_ERROR("Failed to create file map"); return NS_ERROR_FAILURE; } // Make sure the file map is closed, no matter how we return. FileMapAutoCloser mapCloser(map); PRUint32 fileSize32; LL_L2UI(fileSize32, fileSize); char *buf = static_cast<char*>(PR_MemMap(map, 0, fileSize32)); if (!buf) { NS_WARNING("Failed to map file"); return NS_ERROR_FAILURE; } script = JS_CompileScriptForPrincipals(cx, global, jsPrincipals, buf, fileSize32, nativePath.get(), 1); PR_MemUnmap(buf, fileSize32); #else /* HAVE_PR_MEMMAP */ /** * No memmap implementation, so fall back to using * JS_CompileFileHandleForPrincipals(). */ FILE *fileHandle; rv = aComponent->OpenANSIFileDesc("r", &fileHandle); NS_ENSURE_SUCCESS(rv, rv); script = JS_CompileFileHandleForPrincipals(cx, global, nativePath.get(), fileHandle, jsPrincipals); /* JS will close the filehandle after compilation is complete. */ #endif /* HAVE_PR_MEMMAP */ }
PR_IMPLEMENT(PRInt32) PR_EmulateSendFile( PRFileDesc *sd, PRSendFileData *sfd, PRTransmitFileFlags flags, PRIntervalTime timeout) { PRInt32 rv, count = 0; PRInt32 len, file_bytes, index = 0; PRFileInfo info; PRIOVec iov[3]; PRFileMap *mapHandle = NULL; void *addr = (void*)0; /* initialized to some arbitrary value. Keeps compiler warnings down. */ PRUint32 file_mmap_offset, alignment; PRInt64 zero64; PROffset64 file_mmap_offset64; PRUint32 addr_offset, mmap_len; /* Get file size */ if (PR_SUCCESS != PR_GetOpenFileInfo(sfd->fd, &info)) { count = -1; goto done; } if (sfd->file_nbytes && (info.size < (sfd->file_offset + sfd->file_nbytes))) { /* * there are fewer bytes in file to send than specified */ PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); count = -1; goto done; } if (sfd->file_nbytes) file_bytes = sfd->file_nbytes; else file_bytes = info.size - sfd->file_offset; alignment = PR_GetMemMapAlignment(); /* number of initial bytes to skip in mmap'd segment */ addr_offset = sfd->file_offset % alignment; /* find previous mmap alignment boundary */ file_mmap_offset = sfd->file_offset - addr_offset; /* * If the file is large, mmap and send the file in chunks so as * to not consume too much virtual address space */ mmap_len = PR_MIN(file_bytes + addr_offset, SENDFILE_MMAP_CHUNK); len = mmap_len - addr_offset; /* * Map in (part of) file. Take care of zero-length files. */ if (len) { LL_I2L(zero64, 0); mapHandle = PR_CreateFileMap(sfd->fd, zero64, PR_PROT_READONLY); if (!mapHandle) { count = -1; goto done; } LL_I2L(file_mmap_offset64, file_mmap_offset); addr = PR_MemMap(mapHandle, file_mmap_offset64, mmap_len); if (!addr) { count = -1; goto done; } } /* * send headers first, followed by the file */ if (sfd->hlen) { iov[index].iov_base = (char *) sfd->header; iov[index].iov_len = sfd->hlen; index++; } if (len) { iov[index].iov_base = (char*)addr + addr_offset; iov[index].iov_len = len; index++; } if ((file_bytes == len) && (sfd->tlen)) { /* * all file data is mapped in; send the trailer too */ iov[index].iov_base = (char *) sfd->trailer; iov[index].iov_len = sfd->tlen; index++; } rv = PR_Writev(sd, iov, index, timeout); if (len) PR_MemUnmap(addr, mmap_len); if (rv < 0) { count = -1; goto done; } PR_ASSERT(rv == sfd->hlen + len + ((len == file_bytes) ? sfd->tlen : 0)); file_bytes -= len; count += rv; if (!file_bytes) /* header, file and trailer are sent */ goto done; /* * send remaining bytes of the file, if any */ len = PR_MIN(file_bytes, SENDFILE_MMAP_CHUNK); while (len > 0) { /* * Map in (part of) file */ file_mmap_offset = sfd->file_offset + count - sfd->hlen; PR_ASSERT((file_mmap_offset % alignment) == 0); LL_I2L(file_mmap_offset64, file_mmap_offset); addr = PR_MemMap(mapHandle, file_mmap_offset64, len); if (!addr) { count = -1; goto done; } rv = PR_Send(sd, addr, len, 0, timeout); PR_MemUnmap(addr, len); if (rv < 0) { count = -1; goto done; } PR_ASSERT(rv == len); file_bytes -= rv; count += rv; len = PR_MIN(file_bytes, SENDFILE_MMAP_CHUNK); } PR_ASSERT(0 == file_bytes); if (sfd->tlen) { rv = PR_Send(sd, sfd->trailer, sfd->tlen, 0, timeout); if (rv >= 0) { PR_ASSERT(rv == sfd->tlen); count += rv; } else count = -1; } done: if (mapHandle) PR_CloseFileMap(mapHandle); if ((count >= 0) && (flags & PR_TRANSMITFILE_CLOSE_SOCKET)) PR_Close(sd); return count; }