MetadataList CreateASTMetadataHLSL(TIntermNode *root, const CallDAG &callDag) { MetadataList metadataList(callDag.size()); // Compute all the information related to when gradient operations are used. // We want to know for each function and control flow operation if they have // a gradient operation in their call graph (shortened to "using a gradient" // in the rest of the file). // // This computation is logically split in three steps: // 1 - For each function compute if it uses a gradient in its body, ignoring // calls to other user-defined functions. // 2 - For each function determine if it uses a gradient in its call graph, // using the result of step 1 and the CallDAG to know its callees. // 3 - For each control flow statement of each function, check if it uses a // gradient in the function's body, or if it calls a user-defined function that // uses a gradient. // // We take advantage of the call graph being a DAG and instead compute 1, 2 and 3 // for leaves first, then going down the tree. This is correct because 1 doesn't // depend on other functions, and 2 and 3 depend only on callees. for (size_t i = 0; i < callDag.size(); i++) { PullGradient pull(&metadataList, i, callDag); pull.traverse(callDag.getRecordFromIndex(i).node); } // Compute which loops are discontinuous and which function are called in // these loops. The same way computing gradient usage is a "pull" process, // computing "bing used in a discont. loop" is a push process. However we also // need to know what ifs have a discontinuous loop inside so we do the same type // of callgraph analysis as for the gradient. // First compute which loops are discontinuous (no specific order) and pull // the ifs and functions using a discontinuous loop. for (size_t i = 0; i < callDag.size(); i++) { PullComputeDiscontinuousLoops pull(&metadataList, i, callDag); pull.traverse(callDag.getRecordFromIndex(i).node); } // Then push the information to callees, either from the a local discontinuous // loop or from the caller being called in a discontinuous loop already for (size_t i = callDag.size(); i-- > 0;) { PushDiscontinuousLoops push(&metadataList, i, callDag); push.traverse(callDag.getRecordFromIndex(i).node); } // We create "Lod0" version of functions with the gradient operations replaced // by non-gradient operations so that the D3D compiler is happier with discont // loops. for (auto &metadata : metadataList) { metadata.mNeedsLod0 = metadata.mCalledInDiscontinuousLoop && metadata.mUsesGradient; } return metadataList; }
/* static */ nsresult SRICheck::IntegrityMetadata(const nsAString& aMetadataList, const nsIDocument* aDocument, SRIMetadata* outMetadata) { NS_ENSURE_ARG_POINTER(outMetadata); NS_ENSURE_ARG_POINTER(aDocument); MOZ_ASSERT(outMetadata->IsEmpty()); // caller must pass empty metadata if (!Preferences::GetBool("security.sri.enable", false)) { SRILOG(("SRICheck::IntegrityMetadata, sri is disabled (pref)")); return NS_ERROR_SRI_DISABLED; } // put a reasonable bound on the length of the metadata NS_ConvertUTF16toUTF8 metadataList(aMetadataList); if (metadataList.Length() > SRICheck::MAX_METADATA_LENGTH) { metadataList.Truncate(SRICheck::MAX_METADATA_LENGTH); } MOZ_ASSERT(metadataList.Length() <= aMetadataList.Length()); // the integrity attribute is a list of whitespace-separated hashes // and options so we need to look at them one by one and pick the // strongest (valid) one nsCWhitespaceTokenizer tokenizer(metadataList); nsAutoCString token; for (uint32_t i=0; tokenizer.hasMoreTokens() && i < SRICheck::MAX_METADATA_TOKENS; ++i) { token = tokenizer.nextToken(); SRIMetadata metadata(token); if (metadata.IsMalformed()) { NS_ConvertUTF8toUTF16 tokenUTF16(token); const char16_t* params[] = { tokenUTF16.get() }; nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, NS_LITERAL_CSTRING("Sub-resource Integrity"), aDocument, nsContentUtils::eSECURITY_PROPERTIES, "MalformedIntegrityURI", params, ArrayLength(params)); } else if (!metadata.IsAlgorithmSupported()) { nsAutoCString alg; metadata.GetAlgorithm(&alg); NS_ConvertUTF8toUTF16 algUTF16(alg); const char16_t* params[] = { algUTF16.get() }; nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, NS_LITERAL_CSTRING("Sub-resource Integrity"), aDocument, nsContentUtils::eSECURITY_PROPERTIES, "UnsupportedHashAlg", params, ArrayLength(params)); } nsAutoCString alg1, alg2; if (MOZ_LOG_TEST(GetSriLog(), mozilla::LogLevel::Debug)) { outMetadata->GetAlgorithm(&alg1); metadata.GetAlgorithm(&alg2); } if (*outMetadata == metadata) { SRILOG(("SRICheck::IntegrityMetadata, alg '%s' is the same as '%s'", alg1.get(), alg2.get())); *outMetadata += metadata; // add new hash to strongest metadata } else if (*outMetadata < metadata) { SRILOG(("SRICheck::IntegrityMetadata, alg '%s' is weaker than '%s'", alg1.get(), alg2.get())); *outMetadata = metadata; // replace strongest metadata with current } } if (MOZ_LOG_TEST(GetSriLog(), mozilla::LogLevel::Debug)) { if (outMetadata->IsValid()) { nsAutoCString alg; outMetadata->GetAlgorithm(&alg); SRILOG(("SRICheck::IntegrityMetadata, using a '%s' hash", alg.get())); } else if (outMetadata->IsEmpty()) { SRILOG(("SRICheck::IntegrityMetadata, no metadata")); } else { SRILOG(("SRICheck::IntegrityMetadata, no valid metadata found")); } } return NS_OK; }