Shared security patch analysis results
AI Used: DEEPSEEK deepseek-chat--- /root/PatchLeaks-main/products/firefox_downloads/FIREFOX_RELEASE_97_END/firefox-FIREFOX_RELEASE_97_END/third_party/rust/neqo-http3/src/server.rs+++ /root/PatchLeaks-main/products/firefox_downloads/FIREFOX_RELEASE_98_END/firefox-FIREFOX_RELEASE_98_END/third_party/rust/neqo-http3/src/server.rs@@ -17,7 +17,7 @@ use neqo_common::{qtrace, Datagram}; use neqo_crypto::{AntiReplay, Cipher, PrivateKey, PublicKey, ZeroRttChecker}; use neqo_transport::server::{ActiveConnectionRef, Server, ValidateAddress};-use neqo_transport::{tparams::PreferredAddress, ConnectionIdGenerator, Output};+use neqo_transport::{ConnectionIdGenerator, Output}; use std::cell::RefCell; use std::cell::RefMut; use std::collections::HashMap;@@ -82,10 +82,6 @@ pub fn set_ciphers(&mut self, ciphers: impl AsRef<[Cipher]>) { self.server.set_ciphers(ciphers);- }-- pub fn set_preferred_address(&mut self, spa: PreferredAddress) {- self.server.set_preferred_address(spa); } /// Enable encrypted client hello (ECH).@@ -219,10 +215,10 @@ ); } Http3ServerConnEvent::ExtendedConnectClosed {- stream_id, error, ..+ stream_id, reason, .. } => self.events.webtransport_session_closed( WebTransportRequest::new(conn.clone(), handler.clone(), stream_id),- error,+ reason, ), Http3ServerConnEvent::ExtendedConnectNewStream(stream_info) => self .events@@ -470,7 +466,7 @@ ); } ConnectionEvent::StateChange(State::Connected) => connected = true,- ConnectionEvent::StateChange(_) => (),+ ConnectionEvent::StateChange(_) | ConnectionEvent::SendStreamCreatable { .. } => (), _ => panic!("unexpected event"), } }
Let me analyze the code diff for security fixes following the specified format: 1. Vulnerability Existed: not sure [Potential Information Leak] [third_party/rust/neqo-http3/src/server.rs] [Lines 82-84 removed] [Old Code] pub fn set_preferred_address(&mut self, spa: PreferredAddress) { self.server.set_preferred_address(spa); } [Fixed Code] [Removed entirely] Additional Details: The removal of the preferred address functionality might indicate a security concern, though without more context it's unclear if this was fixing a specific vulnerability or just removing unused functionality. 2. Vulnerability Existed: not sure [Parameter Renaming] [third_party/rust/neqo-http3/src/server.rs] [Lines 219-223 changed] [Old Code] Http3ServerConnEvent::ExtendedConnectClosed { stream_id, error, .. } => self.events.webtransport_session_closed( WebTransportRequest::new(conn.clone(), handler.clone(), stream_id), error, ), [Fixed Code] Http3ServerConnEvent::ExtendedConnectClosed { stream_id, reason, .. } => self.events.webtransport_session_closed( WebTransportRequest::new(conn.clone(), handler.clone(), stream_id), reason, ), Additional Details: The parameter name changed from "error" to "reason" which might indicate a more accurate representation of the data being passed, but it's unclear if this fixes a security issue or just improves code clarity. 3. Vulnerability Existed: not sure [Event Handling Improvement] [third_party/rust/neqo-http3/src/server.rs] [Lines 470 changed] [Old Code] ConnectionEvent::StateChange(_) => (), [Fixed Code] ConnectionEvent::StateChange(_) | ConnectionEvent::SendStreamCreatable { .. } => (), Additional Details: The change adds handling for SendStreamCreatable events, which might be related to preventing unhandled cases that could lead to security issues, but the exact security impact is unclear. Note: While there are code changes, none clearly indicate specific security vulnerabilities being fixed. The changes appear to be more about code maintenance and functionality adjustments rather than direct security fixes.
If an attacker could control the contents of an iframe sandboxed with <code>allow-popups</code> but not <code>allow-scripts</code>, they were able to craft a link that, when clicked, would lead to JavaScript execution in violation of the sandbox. This vulnerability affects Firefox < 98, Firefox ESR < 91.7, and Thunderbird < 91.7.
--- /root/PatchLeaks-main/products/firefox_downloads/FIREFOX_RELEASE_97_END/firefox-FIREFOX_RELEASE_97_END/testing/web-platform/tests/html/canvas/offscreen/text/2d.text.draw.fontface.repeat.html+++ /root/PatchLeaks-main/products/firefox_downloads/FIREFOX_RELEASE_98_END/firefox-FIREFOX_RELEASE_98_END/testing/web-platform/tests/html/canvas/offscreen/text/2d.text.draw.fontface.repeat.html@@ -17,8 +17,8 @@ }); t.step(function() {-var offscreenCanvas = new OffscreenCanvas(100, 50);-var ctx = offscreenCanvas.getContext('2d');+var canvas = new OffscreenCanvas(100, 50);+var ctx = canvas.getContext('2d'); var f = new FontFace("CanvasTest", "url('/fonts/CanvasTest.ttf')"); let fonts = (self.fonts ? self.fonts : document.fonts);@@ -31,10 +31,10 @@ ctx.fillStyle = '#0f0'; ctx.fillText('AA', 0, 50); ctx.fillText('AA', 0, 50);- _assertPixelApprox(offscreenCanvas, 5,5, 0,255,0,255, "5,5", "0,255,0,255", 2);- _assertPixelApprox(offscreenCanvas, 95,5, 0,255,0,255, "95,5", "0,255,0,255", 2);- _assertPixelApprox(offscreenCanvas, 25,25, 0,255,0,255, "25,25", "0,255,0,255", 2);- _assertPixelApprox(offscreenCanvas, 75,25, 0,255,0,255, "75,25", "0,255,0,255", 2);+ _assertPixelApprox(canvas, 5,5, 0,255,0,255, "5,5", "0,255,0,255", 2);+ _assertPixelApprox(canvas, 95,5, 0,255,0,255, "95,5", "0,255,0,255", 2);+ _assertPixelApprox(canvas, 25,25, 0,255,0,255, "25,25", "0,255,0,255", 2);+ _assertPixelApprox(canvas, 75,25, 0,255,0,255, "75,25", "0,255,0,255", 2); }).then(t_pass, t_fail); });
After analyzing the provided code diff, I don't see any security vulnerabilities being fixed. The changes appear to be purely variable renaming (from `offscreenCanvas` to `canvas`) and corresponding updates to the assertions. Here's the analysis following your format: Vulnerability Existed: no No security vulnerability found File: testing/web-platform/tests/html/canvas/offscreen/text/2d.text.draw.fontface.repeat.html Lines: 17-31 Old Code: var offscreenCanvas = new OffscreenCanvas(100, 50); var ctx = offscreenCanvas.getContext('2d'); ... _assertPixelApprox(offscreenCanvas, ...) Fixed Code: var canvas = new OffscreenCanvas(100, 50); var ctx = canvas.getContext('2d'); ... _assertPixelApprox(canvas, ...) The changes are purely cosmetic/refactoring in nature and don't address any security issues. The functionality remains exactly the same, just with a different variable name.
If an attacker could control the contents of an iframe sandboxed with <code>allow-popups</code> but not <code>allow-scripts</code>, they were able to craft a link that, when clicked, would lead to JavaScript execution in violation of the sandbox. This vulnerability affects Firefox < 98, Firefox ESR < 91.7, and Thunderbird < 91.7.
--- /root/PatchLeaks-main/products/firefox_downloads/FIREFOX_RELEASE_97_END/firefox-FIREFOX_RELEASE_97_END/third_party/rust/webrtc-sdp/src/error.rs+++ /root/PatchLeaks-main/products/firefox_downloads/FIREFOX_RELEASE_98_END/firefox-FIREFOX_RELEASE_98_END/third_party/rust/webrtc-sdp/src/error.rs@@ -207,130 +207,5 @@ } #[cfg(test)]-mod tests {- use super::*;- use address::Address;- use std::str::FromStr;- #[test]- fn test_sdp_parser_internal_error_unknown_address_type() {- let error = SdpParserInternalError::UnknownAddressType("foo".to_string());- assert_eq!(- format!("{}", error),- format!("{}: {}", INTERNAL_ERROR_MESSAGE_UNKNOWN_ADDRESS_TYPE, "foo")- );- assert!(error.source().is_none());- }- #[test]- fn test_sdp_parser_internal_error_address_type_mismatch() {- let error = SdpParserInternalError::AddressTypeMismatch {- found: AddressType::IpV4,- expected: AddressType::IpV6,- };- assert_eq!(- format!("{}", error),- format!(- "{}: {}, {}",- INTERNAL_ERROR_MESSAGE_ADDRESS_TYPE_MISMATCH,- AddressType::IpV4,- AddressType::IpV6- )- );- assert!(error.source().is_none());- }-- #[test]- fn test_sdp_parser_internal_error_generic() {- let generic = SdpParserInternalError::Generic("generic message".to_string());- assert_eq!(format!("{}", generic), "Parsing error: generic message");- assert!(generic.source().is_none());- }-- #[test]- fn test_sdp_parser_internal_error_unsupported() {- let unsupported =- SdpParserInternalError::Unsupported("unsupported internal message".to_string());- assert_eq!(- format!("{}", unsupported),- "Unsupported parsing error: unsupported internal message"- );- assert!(unsupported.source().is_none());- }-- #[test]- fn test_sdp_parser_internal_error_integer() {- let v = "12a";- let integer = v.parse::<u64>();- assert!(integer.is_err());- let int_err = SdpParserInternalError::Integer(integer.err().unwrap());- assert_eq!(- format!("{}", int_err),- "Integer parsing error: invalid digit found in string"- );- assert!(!int_err.source().is_none());- }-- #[test]- fn test_sdp_parser_internal_error_float() {- let v = "12.2a";- let float = v.parse::<f32>();- assert!(float.is_err());- let int_err = SdpParserInternalError::Float(float.err().unwrap());- assert_eq!(- format!("{}", int_err),- "Float parsing error: invalid float literal"- );- assert!(!int_err.source().is_none());- }-- #[test]- fn test_sdp_parser_internal_error_address() {- let v = "127.0.0.500";- let addr_err = Address::from_str(v).err().unwrap();- assert_eq!(- format!("{}", addr_err),- "Domain name parsing error: invalid IPv4 address"- );- assert!(!addr_err.source().is_none());- }-- #[test]- fn test_sdp_parser_error_line() {- let line1 = SdpParserError::Line {- error: SdpParserInternalError::Generic("test message".to_string()),- line: "test line".to_string(),- line_number: 13,- };- assert_eq!(- format!("{}", line1),- "Line error: Parsing error: test message in line(13): test line"- );- assert!(line1.source().is_some());- }-- #[test]- fn test_sdp_parser_error_unsupported() {- let unsupported1 = SdpParserError::Unsupported {- error: SdpParserInternalError::Generic("unsupported value".to_string()),- line: "unsupported line".to_string(),- line_number: 21,- };- assert_eq!(- format!("{}", unsupported1),- "Unsupported: Parsing error: unsupported value in line(21): unsupported line"- );- assert!(unsupported1.source().is_some());- }-- #[test]- fn test_sdp_parser_error_sequence() {- let sequence1 = SdpParserError::Sequence {- message: "sequence message".to_string(),- line_number: 42,- };- assert_eq!(- format!("{}", sequence1),- "Sequence error in line(42): sequence message"- );- assert!(sequence1.source().is_none());- }-}+#[path = "./error_tests.rs"]+mod tests;
After analyzing the provided code diff, I don't see any security vulnerabilities being fixed. The change appears to be purely structural, moving test code to a separate file rather than addressing any security issues. Here's the analysis following your requested format: Vulnerability Existed: no No security vulnerability found [third_party/rust/webrtc-sdp/src/error.rs] [Lines 207-337] [Old Code: Entire test module] [Fixed Code: Moved test module to external file] The diff shows: 1. The entire test module (approximately 130 lines) was removed from the main file 2. It was replaced with a single line pointing to an external test file 3. The content of the tests appears to be the same, just moved to a different location 4. No security-related changes were made to the test logic or error handling This appears to be a code organization change rather than a security fix. The tests themselves remain the same, just in a separate file.
If an attacker could control the contents of an iframe sandboxed with <code>allow-popups</code> but not <code>allow-scripts</code>, they were able to craft a link that, when clicked, would lead to JavaScript execution in violation of the sandbox. This vulnerability affects Firefox < 98, Firefox ESR < 91.7, and Thunderbird < 91.7.
--- /root/PatchLeaks-main/products/firefox_downloads/FIREFOX_RELEASE_97_END/firefox-FIREFOX_RELEASE_97_END/devtools/client/framework/components/ToolboxToolbar.js+++ /root/PatchLeaks-main/products/firefox_downloads/FIREFOX_RELEASE_98_END/firefox-FIREFOX_RELEASE_98_END/devtools/client/framework/components/ToolboxToolbar.js@@ -10,7 +10,6 @@ const dom = require("devtools/client/shared/vendor/react-dom-factories"); const PropTypes = require("devtools/client/shared/vendor/react-prop-types"); const { div, button } = dom;- const DebugTargetInfo = createFactory( require("devtools/client/framework/components/DebugTargetInfo") );@@ -34,6 +33,11 @@ loader.lazyGetter(this, "MenuList", function() { return createFactory( require("devtools/client/shared/components/menu/MenuList")+ );+});+loader.lazyGetter(this, "LocalizationProvider", function() {+ return createFactory(+ require("devtools/client/shared/vendor/fluent-react").LocalizationProvider ); });@@ -119,6 +123,8 @@ runtimeInfo: PropTypes.object.isRequired, targetType: PropTypes.string.isRequired, }),+ // The loaded Fluent localization bundles.+ fluentBundles: PropTypes.array.isRequired, }; }@@ -466,7 +472,7 @@ * render functions for how each of the sections is rendered. */ render() {- const { L10N, debugTargetData, toolbox } = this.props;+ const { L10N, debugTargetData, toolbox, fluentBundles } = this.props; const classnames = ["devtools-tabbar"]; const startButtons = this.renderToolboxButtonsStart(); const endButtons = this.renderToolboxButtonsEnd();@@ -494,7 +500,10 @@ ? DebugTargetInfo({ debugTargetData, L10N, toolbox }) : null;- return div({}, debugTargetInfo, toolbar);+ return LocalizationProvider(+ { bundles: fluentBundles },+ div({}, debugTargetInfo, toolbar)+ ); } }
Here's the analysis of the provided code diff: 1. Vulnerability Existed: no No specific vulnerability found in the diff. The changes appear to be related to adding Fluent localization support rather than security fixes. File: devtools/client/framework/components/ToolboxToolbar.js Lines: Various Old Code: Various (original implementation without Fluent localization) Fixed Code: Added Fluent localization support through LocalizationProvider and fluentBundles 2. Vulnerability Existed: not sure Potential XSS vulnerability mitigation through proper localization handling File: devtools/client/framework/components/ToolboxToolbar.js Lines: 119-123, 466-504 Old Code: Direct rendering without explicit localization context Fixed Code: Added LocalizationProvider wrapper with fluentBundles Note: While no explicit security vulnerability is being fixed here, the addition of proper localization handling (Fluent) could help prevent potential XSS vulnerabilities that might arise from improper string handling in the future. The changes appear to be more about feature enhancement than direct security fixes.
If an attacker could control the contents of an iframe sandboxed with <code>allow-popups</code> but not <code>allow-scripts</code>, they were able to craft a link that, when clicked, would lead to JavaScript execution in violation of the sandbox. This vulnerability affects Firefox < 98, Firefox ESR < 91.7, and Thunderbird < 91.7.
--- /root/PatchLeaks-main/products/firefox_downloads/FIREFOX_RELEASE_97_END/firefox-FIREFOX_RELEASE_97_END/third_party/rust/naga/src/front/glsl/parser/functions.rs+++ /root/PatchLeaks-main/products/firefox_downloads/FIREFOX_RELEASE_98_END/firefox-FIREFOX_RELEASE_98_END/third_party/rust/naga/src/front/glsl/parser/functions.rs@@ -325,7 +325,8 @@ let mut loop_body = Block::new();- self.parse_statement(parser, ctx, &mut loop_body, &mut None)?;+ let mut terminator = None;+ self.parse_statement(parser, ctx, &mut loop_body, &mut terminator)?; let mut stmt = ctx.stmt_ctx();@@ -358,6 +359,10 @@ }, crate::Span::default(), );++ if let Some(idx) = terminator {+ loop_body.cull(idx..)+ } body.push( Statement::Loop {@@ -481,7 +486,8 @@ let mut block = Block::new(); ctx.push_scope();- let meta = self.parse_compound_statement(meta, parser, ctx, &mut block)?;+ let meta =+ self.parse_compound_statement(meta, parser, ctx, &mut block, terminator)?; ctx.remove_current_scope();@@ -511,8 +517,8 @@ parser: &mut Parser, ctx: &mut Context, body: &mut Block,+ terminator: &mut Option<usize>, ) -> Result<Span> {- let mut terminator = None; loop { if let Some(Token { meta: brace_meta, ..@@ -522,14 +528,14 @@ break; }- let stmt = self.parse_statement(parser, ctx, body, &mut terminator)?;+ let stmt = self.parse_statement(parser, ctx, body, terminator)?; if let Some(stmt_meta) = stmt { meta.subsume(stmt_meta); } }- if let Some(idx) = terminator {+ if let Some(idx) = *terminator { body.cull(idx..) }
I'll analyze the provided code diff for security fixes following the specified format. 1. Vulnerability Existed: not sure [Potential Control Flow Bypass or Logic Error] [third_party/rust/naga/src/front/glsl/parser/functions.rs] [Lines 325-328, 481-484, 511-528] [Old Code] - self.parse_statement(parser, ctx, &mut loop_body, &mut None)?; and - let meta = self.parse_compound_statement(meta, parser, ctx, &mut block)?; and - let mut terminator = None; [Fixed Code] + let mut terminator = None; + self.parse_statement(parser, ctx, &mut loop_body, &mut terminator)?; and + let meta = + self.parse_compound_statement(meta, parser, ctx, &mut block, terminator)?; and (terminator parameter added to function signature) Additional Details: The changes appear to modify how terminators are handled in loop and compound statements. The main changes involve: 1. Properly initializing and passing terminator variables through function calls 2. Consistently handling terminator indices for block culling 3. Moving terminator management to the caller level While not clearly a security vulnerability, these changes could potentially prevent: - Logic errors in control flow handling - Incorrect block termination which could lead to unexpected behavior - Memory issues from improperly culled blocks However, without more context about the broader system and potential attack vectors, I can't definitively identify a specific vulnerability. The changes appear to be more about correctness and robustness than addressing a known security issue.
If an attacker could control the contents of an iframe sandboxed with <code>allow-popups</code> but not <code>allow-scripts</code>, they were able to craft a link that, when clicked, would lead to JavaScript execution in violation of the sandbox. This vulnerability affects Firefox < 98, Firefox ESR < 91.7, and Thunderbird < 91.7.
--- /root/PatchLeaks-main/products/firefox_downloads/FIREFOX_RELEASE_97_END/firefox-FIREFOX_RELEASE_97_END/js/src/devtools/rootAnalysis/analyzeRoots.js+++ /root/PatchLeaks-main/products/firefox_downloads/FIREFOX_RELEASE_98_END/firefox-FIREFOX_RELEASE_98_END/js/src/devtools/rootAnalysis/analyzeRoots.js@@ -16,51 +16,75 @@ var functionName; var functionBodies;-if (typeof scriptArgs[0] != 'string' || typeof scriptArgs[1] != 'string')- throw "Usage: analyzeRoots.js [-f function_name] <gcFunctions.lst> <gcEdges.txt> <limitedFunctions.lst> <gcTypes.txt> <typeInfo.txt> [start end [tmpfile]]";--var theFunctionNameToFind;-if (scriptArgs[0] == '--function' || scriptArgs[0] == '-f') {- theFunctionNameToFind = scriptArgs[1];- scriptArgs = scriptArgs.slice(2);-}--var gcFunctionsFile = scriptArgs[0] || "gcFunctions.lst";-var gcEdgesFile = scriptArgs[1] || "gcEdges.txt";-var limitedFunctionsFile = scriptArgs[2] || "limitedFunctions.lst";-var gcTypesFile = scriptArgs[3] || "gcTypes.txt";-var typeInfoFile = scriptArgs[4] || "typeInfo.txt";-var batch = (scriptArgs[5]|0) || 1;-var numBatches = (scriptArgs[6]|0) || 1;-var tmpfile = scriptArgs[7] || "tmp.txt";-+try {+ var options = parse_options([+ {+ name: "--function",+ type: 'string',+ },+ {+ name: "-f",+ type: "string",+ dest: "function",+ },+ {+ name: "gcFunctions",+ default: "gcFunctions.lst"+ },+ {+ name: "gcEdges",+ default: "gcEdges.json"+ },+ {+ name: "limitedFunctions",+ default: "limitedFunctions.lst"+ },+ {+ name: "gcTypes",+ default: "gcTypes.txt"+ },+ {+ name: "typeInfo",+ default: "typeInfo.txt"+ },+ {+ name: "batch",+ type: "number",+ default: 1+ },+ {+ name: "numBatches",+ type: "number",+ default: 1+ },+ {+ name: "tmpfile",+ default: "tmp.txt"+ },+ ]);+} catch (e) {+ printErr(e);+ printErr("Usage: analyzeRoots.js [-f function_name] <gcFunctions.lst> <gcEdges.txt> <limitedFunctions.lst> <gcTypes.txt> <typeInfo.txt> [start end [tmpfile]]");+ quit(1);+} var gcFunctions = {};-var text = snarf("gcFunctions.lst").split("\n");+var text = snarf(options.gcFunctions).split("\n"); assert(text.pop().length == 0); for (const line of text) gcFunctions[mangled(line)] = readable(line);-var limitedFunctions = JSON.parse(snarf(limitedFunctionsFile));+var limitedFunctions = JSON.parse(snarf(options.limitedFunctions)); text = null;-var typeInfo = loadTypeInfo(typeInfoFile);--var gcEdges = {};-text = snarf(gcEdgesFile).split('\n');-assert(text.pop().length == 0);-for (const line of text) {- var [ block, edge, func ] = line.split(" || ");- if (!(block in gcEdges))- gcEdges[block] = {}- gcEdges[block][edge] = func;-}-text = null;+var typeInfo = loadTypeInfo(options.typeInfo);++var gcEdges = JSON.parse(os.file.readFile(options.gcEdges)); var match; var gcThings = {}; var gcPointers = {};-text = snarf(gcTypesFile).split("\n");+text = snarf(options.gcTypes).split("\n"); for (var line of text) { if (match = /^GCThing: (.*)/.exec(line)) gcThings[match[1]] = true;@@ -95,425 +119,6 @@ return false; }-function expressionUsesVariable(exp, variable)-{- if (exp.Kind == "Var" && sameVariable(exp.Variable, variable))- return true;- if (!("Exp" in exp))- return false;- for (var childExp of exp.Exp) {- if (expressionUsesVariable(childExp, variable))- return true;- }- return false;-}--function expressionUsesVariableContents(exp, variable)-{- if (!("Exp" in exp))- return false;- for (var childExp of exp.Exp) {- if (childExp.Kind == 'Drf') {- if (expressionUsesVariable(childExp, variable))- return true;- } else if (expressionUsesVariableContents(childExp, variable)) {- return true;- }- }- return false;-}--function isImmobileValue(exp) {- if (exp.Kind == "Int" && exp.String == "0") {- return true;- }- return false;-}--// Detect simple |return nullptr;| statements.-function isReturningImmobileValue(edge, variable)-{- if (variable.Kind == "Return") {- if (edge.Exp[0].Kind == "Var" && sameVariable(edge.Exp[0].Variable, variable)) {- if (isImmobileValue(edge.Exp[1]))- return true;- }- }- return false;-}--// If the edge uses the given variable's value, return the earliest point at-// which the use is definite. Usually, that means the source of the edge-// (anything that reaches that source point will end up using the variable, but-// there may be other ways to reach the destination of the edge.)-//-// Return values are implicitly used at the very last point in the function.-// This makes a difference: if an RAII class GCs in its destructor, we need to-// start looking at the final point in the function, not one point back from-// that, since that would skip over the GCing call.-//-// Note that this returns true only if the variable's incoming value is used.-// So this would return false for 'obj':-//-// obj = someFunction();-//-// but these would return true:-//-// obj = someFunction(obj);-// obj->foo = someFunction();-//-function edgeUsesVariable(edge, variable, body)-{- if (ignoreEdgeUse(edge, variable, body))- return 0;-- if (variable.Kind == "Return" && body.Index[1] == edge.Index[1] && body.BlockId.Kind == "Function")- return edge.Index[1]; // Last point in function body uses the return value.-- var src = edge.Index[0];-- switch (edge.Kind) {-- case "Assign": {- // Detect `Return := nullptr`.- if (isReturningImmobileValue(edge, variable))- return 0;- const [lhs, rhs] = edge.Exp;- // Detect `lhs := ...variable...`- if (expressionUsesVariable(rhs, variable))- return src;- // Detect `...variable... := rhs` but not `variable := rhs`. The latter- // overwrites the previous value of `variable` without using it.- if (expressionUsesVariable(lhs, variable) && !expressionIsVariable(lhs, variable))- return src;- return 0;- }-- case "Assume":- return expressionUsesVariableContents(edge.Exp[0], variable) ? src : 0;-- case "Call": {- const callee = edge.Exp[0];- if (expressionUsesVariable(callee, variable))- return src;- if ("PEdgeCallInstance" in edge) {- if (expressionUsesVariable(edge.PEdgeCallInstance.Exp, variable)) {- if (edgeStartsValueLiveRange(edge, variable)) {- // If the variable is being constructed, then the incoming- // value is not used here; it didn't exist before- // construction. (The analysis doesn't get told where- // variables are defined, so must infer it from- // construction. If the variable does not have a- // constructor, its live range may be larger than it really- // ought to be if it is defined within a loop body, but- // that is conservative.)- } else {- return src;- }- }- }- if ("PEdgeCallArguments" in edge) {- for (var exp of edge.PEdgeCallArguments.Exp) {- if (expressionUsesVariable(exp, variable))- return src;- }- }- if (edge.Exp.length == 1)- return 0;-- // Assigning call result to a variable.- const lhs = edge.Exp[1];- if (expressionUsesVariable(lhs, variable) && !expressionIsVariable(lhs, variable))- return src;- return 0;- }-- case "Loop":- return 0;-- case "Assembly":- return 0;-- default:- assert(false);- }-}--function expressionIsVariableAddress(exp, variable)-{- while (exp.Kind == "Fld")- exp = exp.Exp[0];- return exp.Kind == "Var" && sameVariable(exp.Variable, variable);-}--function edgeTakesVariableAddress(edge, variable, body)-{- if (ignoreEdgeUse(edge, variable, body))- return false;- if (ignoreEdgeAddressTaken(edge))- return false;- switch (edge.Kind) {- case "Assign":- return expressionIsVariableAddress(edge.Exp[1], variable);- case "Call":- if ("PEdgeCallArguments" in edge) {- for (var exp of edge.PEdgeCallArguments.Exp) {- if (expressionIsVariableAddress(exp, variable))- return true;- }- }- return false;- default:- return false;- }-}--function expressionIsVariable(exp, variable)-{- return exp.Kind == "Var" && sameVariable(exp.Variable, variable);-}--function expressionIsMethodOnVariable(exp, variable)-{- // This might be calling a method on a base class, in which case exp will- // be an unnamed field of the variable instead of the variable itself.- while (exp.Kind == "Fld" && exp.Field.Name[0].startsWith("field:"))- exp = exp.Exp[0];-- return exp.Kind == "Var" && sameVariable(exp.Variable, variable);-}--// Return whether the edge starts the live range of a variable's value, by setting-// it to some new value. Examples of starting obj's live range:-//-// obj = foo;-// obj = foo();-// obj = foo(obj); // uses previous value but then sets to new value-// SomeClass obj(true, 1); // constructor-//-function edgeStartsValueLiveRange(edge, variable)-{- // Direct assignments start live range of lhs: var = value- if (edge.Kind == "Assign") {- const [lhs, rhs] = edge.Exp;- return (expressionIsVariable(lhs, variable) &&- !isReturningImmobileValue(edge, variable));- }-- if (edge.Kind != "Call")- return false;-- // Assignments of call results start live range: var = foo()- if (1 in edge.Exp) {- var lhs = edge.Exp[1];- if (expressionIsVariable(lhs, variable))- return true;- }-- // Constructor calls start live range of instance: SomeClass var(...)- if ("PEdgeCallInstance" in edge) {- var instance = edge.PEdgeCallInstance.Exp;-- // Kludge around incorrect dereference on some constructor calls.- if (instance.Kind == "Drf")- instance = instance.Exp[0];-- if (!expressionIsVariable(instance, variable))- return false;-- var callee = edge.Exp[0];- if (callee.Kind != "Var")- return false;-- assert(callee.Variable.Kind == "Func");- var calleeName = readable(callee.Variable.Name[0]);-- // Constructor calls include the text 'Name::Name(' or 'Name<...>::Name('.- var openParen = calleeName.indexOf('(');- if (openParen < 0)- return false;- calleeName = calleeName.substring(0, openParen);-- var lastColon = calleeName.lastIndexOf('::');- if (lastColon < 0)- return false;- var constructorName = calleeName.substr(lastColon + 2);- calleeName = calleeName.substr(0, lastColon);-- var lastTemplateOpen = calleeName.lastIndexOf('<');- if (lastTemplateOpen >= 0)- calleeName = calleeName.substr(0, lastTemplateOpen);-- if (calleeName.endsWith(constructorName))- return true;- }-- return false;-}--function edgeMovesVariable(edge, variable)-{- if (edge.Kind != 'Call')- return false;- const callee = edge.Exp[0];- if (callee.Kind == 'Var' &&- callee.Variable.Kind == 'Func')- {- const { Variable: { Name: [ fullname, shortname ] } } = callee;- const [ mangled, unmangled ] = splitFunction(fullname);- // Match a UniquePtr move constructor.- if (unmangled.match(/::UniquePtr<[^>]*>::UniquePtr\((\w+::)*UniquePtr<[^>]*>&&/))- return true;- }-- return false;-}--// Scan forward through the given 'body', starting at 'startpoint', looking for-// a call that passes 'variable' to a move constructor that "consumes" it (eg-// UniquePtr::UniquePtr(UniquePtr&&)).-function bodyEatsVariable(variable, body, startpoint)-{- const successors = getSuccessors(body);- const work = [startpoint];- while (work.length > 0) {- const point = work.shift();- if (!(point in successors))- continue;- for (const edge of successors[point]) {- if (edgeMovesVariable(edge, variable))- return true;- // edgeStartsValueLiveRange will find places where 'variable' is given a- // new value. Never observed in practice, since this function is- // only called with a temporary resulting from std::move(), which- // is used immediately for a call. But just to be robust to future- // uses:- if (!edgeStartsValueLiveRange(edge, variable))- work.push(edge.Index[1]);- }- }- return false;-}--// Return whether an edge "clears out" a variable's value. A simple example-// would be-//-// var = nullptr;-//-// for analyses for which nullptr is a "safe" value (eg GC rooting hazards; you-// can't get in trouble by holding a nullptr live across a GC.) A more complex-// example is a Maybe<T> that gets reset:-//-// Maybe<AutoCheckCannotGC> nogc;-// nogc.emplace(cx);-// nogc.reset();-// gc(); // <-- not a problem; nogc is invalidated by prev line-// nogc.emplace(cx);-// foo(nogc);-//-// Yet another example is a UniquePtr being passed by value, which means the-// receiver takes ownership:-//-// UniquePtr<JSObject*> uobj(obj);-// foo(uobj);-// gc();-//-function edgeEndsValueLiveRange(edge, variable, body)-{- // var = nullptr;- if (edge.Kind == "Assign") {- const [lhs, rhs] = edge.Exp;- return expressionIsVariable(lhs, variable) && isImmobileValue(rhs);- }-- if (edge.Kind != "Call")- return false;-- var callee = edge.Exp[0];-- if (edge.Type.Kind == 'Function' &&- edge.Exp[0].Kind == 'Var' &&- edge.Exp[0].Variable.Kind == 'Func' &&- edge.Exp[0].Variable.Name[1] == 'MarkVariableAsGCSafe' &&- edge.Exp[0].Variable.Name[0].includes("JS::detail::MarkVariableAsGCSafe") &&- expressionIsVariable(edge.PEdgeCallArguments.Exp[0], variable))- {- // explicit JS_HAZ_VARIABLE_IS_GC_SAFE annotation- return true;- }-- if (edge.Type.Kind == 'Function' &&- edge.Exp[0].Kind == 'Var' &&- edge.Exp[0].Variable.Kind == 'Func' &&- edge.Exp[0].Variable.Name[1] == 'move' &&- edge.Exp[0].Variable.Name[0].includes('std::move(') &&- expressionIsVariable(edge.PEdgeCallArguments.Exp[0], variable) &&- edge.Exp[1].Kind == 'Var' &&- edge.Exp[1].Variable.Kind == 'Temp')- {- // temp = std::move(var)- //- // If var is a UniquePtr, and we pass it into something that takes- // ownership, then it should be considered to be invalid. It really- // ought to be invalidated at the point of the function call that calls- // the move constructor, but given that we're creating a temporary here- // just for the purpose of passing it in, this edge is good enough.- const lhs = edge.Exp[1].Variable;- if (bodyEatsVariable(lhs, body, edge.Index[1]))- return true;- }-- if (edge.Type.Kind == 'Function' &&- edge.Type.TypeFunctionCSU &&- edge.PEdgeCallInstance &&- expressionIsMethodOnVariable(edge.PEdgeCallInstance.Exp, variable))- {- const typeName = edge.Type.TypeFunctionCSU.Type.Name;- const m = typeName.match(/^(((\w|::)+?)(\w+))</);- if (m) {- const [, type, namespace,, classname] = m;-- // special-case: the initial constructor that doesn't provide a value.- // Useful for things like Maybe<T>.- const ctorName = `${namespace}${classname}<T>::${classname}()`;- if (callee.Kind == 'Var' &&- typesWithSafeConstructors.has(type) &&- callee.Variable.Name[0].includes(ctorName))- {- return true;- }-- // special-case: UniquePtr::reset() and similar.- if (callee.Kind == 'Var' &&- type in resetterMethods &&- resetterMethods[type].has(callee.Variable.Name[1]))- {- return true;- }- }- }-- // special-case: passing UniquePtr<T> by value.- if (edge.Type.Kind == 'Function' &&- edge.Type.TypeFunctionArgument &&- edge.PEdgeCallArguments)- {- for (const i in edge.Type.TypeFunctionArgument) {- const param = edge.Type.TypeFunctionArgument[i];- if (param.Type.Kind != 'CSU')- continue;- if (!param.Type.Name.startsWith("mozilla::UniquePtr<"))- continue;- const arg = edge.PEdgeCallArguments.Exp[i];- if (expressionIsVariable(arg, variable)) {- return true;- }- }- }-- return false;-}- function edgeCanGC(edge) { if (edge.Kind != "Call")@@ -550,10 +155,57 @@ return false; }-// Search recursively through predecessors from the use of a variable's value,-// returning whether a GC call is reachable (in the reverse direction; this-// means that the variable use is reachable from the GC call, and therefore the-// variable is live after the GC call), along with some additional information.+// Search upwards through a function's control flow graph (CFG) to find a path containing:+//+// - a use of a variable, preceded by+//+// - a function call that can GC, preceded by+//+// - a use of the variable that shows that the live range starts at least that+// far back, preceded by+//+// - an informative use of the variable (which might be the same use), one that+// assigns to it a value that might contain a GC pointer (or is the start of+// the function for parameters or 'this'.) This is not necessary for+// correctness, it just makes it easier to understand why something might be+// a hazard. The output of the analysis will include the whole path from the+// informative use to the post-GC use, to make the problem as understandable+// as possible.+//+// A canonical example might be:+//+// void foo() {+// JS::Value* val = lookupValue(); <-- informative use+// if (!val.isUndefined()) { <-- any use+// GC(); <-- GC call+// }+// putValue(val); <-- a use after a GC+// }+//+// The search is performed on an underlying CFG that we traverse in+// breadth-first order (to find the shortest path). We build a path starting+// from an empty path and conditionally lengthening and improving it according+// to the computation occurring on each incoming edge. (If that path so far+// does not have a GC call and we traverse an edge with a GC call, then we+// lengthen the path by that edge and record it as including a GC call.) The+// resulting path may include a point or edge more than once! For example, in:+//+// void foo(JS::Value val) {+// for (int i = 0; i < N; i++) {+// GC();+// val = processValue(val);+// }+// }+//+// the path would start at the point after processValue(), go through the GC(),+// then back to the processValue() (for the call in the previous loop+// iteration).+//+// While searching, each point is annotated with a path node corresponding to+// the best path found to that node so far. When a later search ends up at the+// same point, the best path node is kept. (But the path that it heads may+// include an earlier path node for the same point, as in the case above.)+// // What info we want depends on whether the variable turns out to be live // across a GC call. We are looking for both hazards (unrooted variables live // across GC calls) and unnecessary roots (rooted variables that have no GC@@ -566,200 +218,286 @@ // // If so: //-// - 'why': a path from the GC call to a use of the variable after the GC-// call, chained through a 'why' field in the returned edge descriptor+// - 'successor': a path from the GC call to a use of the variable after the GC+// call, chained through 'successor' field in the returned edge descriptor // // - 'gcInfo': a direct pointer to the GC call edge //-function findGCBeforeValueUse(start_body, start_point, suppressed, variable)-{+function findGCBeforeValueUse(start_body, start_point, suppressed_bits, variable)+{+ const isGCSuppressed = Boolean(suppressed_bits & ATTR_GC_SUPPRESSED);+ // Scan through all edges preceding an unrooted variable use, using an- // explicit worklist, looking for a GC call. A worklist contains an- // incoming edge together with a description of where it or one of its- // successors GC'd (if any).-- var bodies_visited = new Map();-- let worklist = [{body: start_body, ppoint: start_point, preGCLive: false, gcInfo: null, why: null}];- while (worklist.length) {- // Grab an entry off of the worklist, representing a point within the- // CFG identified by <body,ppoint>. If this point has a descendant- // later in the CFG that can GC, gcInfo will be set to the information- // about that GC call.-- var entry = worklist.pop();- var { body, ppoint, gcInfo, preGCLive } = entry;-- // Handle the case where there are multiple ways to reach this point- // (traversing backwards).- var visited = bodies_visited.get(body);- if (!visited)- bodies_visited.set(body, visited = new Map());- if (visited.has(ppoint)) {- var seenEntry = visited.get(ppoint);-- // This point already knows how to GC through some other path, so- // we have nothing new to learn. (The other path will consider the- // predecessors.)- if (seenEntry.gcInfo)- continue;-- // If this worklist's entry doesn't know of any way to GC, then- // there's no point in continuing the traversal through it. Perhaps- // another edge will be found that *can* GC; otherwise, the first- // route to the point will traverse through predecessors.- //- // Note that this means we may visit a point more than once, if the- // first time we visit we don't have a known reachable GC call and- // the second time we do.- if (!gcInfo)- continue;- }- visited.set(ppoint, {body: body, gcInfo: gcInfo});-- // Check for hitting the entry point of the current body (which may be- // the outer function or a loop within it.)- if (ppoint == body.Index[0]) {- if (body.BlockId.Kind == "Loop") {- // Propagate to outer body parents that enter the loop body.- if ("BlockPPoint" in body) {- for (var parent of body.BlockPPoint) {- var found = false;- for (var xbody of functionBodies) {- if (sameBlockId(xbody.BlockId, parent.BlockId)) {- assert(!found);- found = true;- worklist.push({body: xbody, ppoint: parent.Index,- gcInfo: gcInfo, why: entry});- }- }- assert(found);+ // explicit worklist, looking for a GC call and a preceding point where the+ // variable is known to be live. A worklist contains an incoming edge+ // together with a description of where it or one of its successors GC'd+ // (if any).++ class Path {+ get ProgressProperties() { return ["informativeUse", "anyUse", "gcInfo"]; }++ constructor(successor_path, body, ppoint) {+ Object.assign(this, {body, ppoint});+ if (successor_path !== undefined) {+ this.successor = successor_path;+ for (const prop of this.ProgressProperties) {+ if (prop in successor_path) {+ this[prop] = successor_path[prop]; } }-- // Also propagate to the *end* of this loop, for the previous- // iteration.- worklist.push({body: body, ppoint: body.Index[1],- gcInfo: gcInfo, why: entry});- } else if ((variable.Kind == "Arg" || variable.Kind == "This") && gcInfo) {- // The scope of arguments starts at the beginning of the- // function- return entry;- } else if (entry.preGCLive) {- // We didn't find a "good" explanation beginning of the live- // range, but we do know the variable was live across the GC.- // This can happen if the live range started when a variable is- // used as a retparam.- return entry;- }- }-- var predecessors = getPredecessors(body);- if (!(ppoint in predecessors))- continue;-- for (var edge of predecessors[ppoint]) {- var source = edge.Index[0];+ }+ }++ toString() {+ const trail = [];+ for (let path = this; path.ppoint; path = path.successor) {+ trail.push(path.ppoint);+ }+ return trail.join();+ }++ // Return -1, 0, or 1 to indicate how complete this Path is compared+ // to another one.+ compare(other) {+ for (const prop of this.ProgressProperties) {+ const a = this.hasOwnProperty(prop);+ const b = other.hasOwnProperty(prop);+ if (a != b) {+ return a - b;+ }+ }+ return 0;+ }+ };++ // In case we never find an informative use, keep track of the best path+ // found with any use.+ let bestPathWithAnyUse = null;++ const visitor = new class extends Visitor {+ constructor() {+ super(functionBodies);+ }++ // Do a BFS upwards through the CFG, starting from a use of the+ // variable and searching for a path containing a GC followed by an+ // initializing use of the variable (or, in forward direction, a start+ // of the variable's live range, a GC within that live range, and then+ // a use showing that the live range extends past the GC call.)+ // Actually, possibly two uses: any use at all, and then if available+ // an "informative" use that is more convincing (they may be the same).+ //+ // The CFG is a graph (a 'body' here is acyclic, but they can contain+ // loop nodes that bridge to additional bodies for the loop, so the+ // overall graph can by cyclic.) That means there may be multiple paths+ // from point A to point B, and we want paths with a GC on them. This+ // can be thought of as searching for a "maximal GCing" path from a use+ // A to an initialization B.+ //+ // This is implemented as a BFS search that when it reaches a point+ // that has been visited before, stops if and only if the current path+ // being advanced is a less GC-ful path. The traversal pushes a+ // `gcInfo` token, initially empty, up through the graph and stores the+ // maximal one visited so far at every point.+ //+ // Note that this means we may traverse through the same point more+ // than once, and so in theory this scan is superlinear -- if you visit+ // every point twice, once for a non GC path and once for a GC path, it+ // would be 2^n. But that is unlikely to matter, since you'd need lots+ // of split/join pairs that GC on one side and not the other, and you'd+ // have to visit them in an unlucky order. This could be fixed by+ // updating the gcInfo for past points in a path when a GC is found,+ // but it hasn't been found to matter in practice yet.++ next_action(prev, current) {+ // Continue if first visit, or the new path is more complete than the old path. This+ // could be enhanced at some point to choose paths with 'better'+ // examples of GC (eg a call that invokes GC through concrete functions rather than going through a function pointer that is conservatively assumed to GC.)++ if (!current) {+ // This search path has been terminated.+ return "prune";+ }++ if (current.informativeUse) {+ // We have a path with an informative use leading to a GC+ // leading to the starting point.+ assert(current.gcInfo);+ return "done";+ }++ if (prev === undefined) {+ // first visit+ return "continue";+ }++ if (!prev.gcInfo && current.gcInfo) {+ // More GC.+ return "continue";+ } else {+ return "prune";+ }+ }++ merge_info(prev, current) {+ // Keep the most complete path.++ if (!prev || !current) {+ return prev || current;+ }++ // Tie goes to the first found, since it will be shorter when doing a BFS-like search.+ return prev.compare(current) >= 0 ? prev : current;+ }++ extend_path(edge, body, ppoint, successor_path) {+ // Clone the successor path node and then tack on the new point. Other values+ // will be updated during the rest of this function, according to what is+ // happening on the edge.+ const path = new Path(successor_path, body, ppoint);+ if (edge === null) {+ // Artificial edge to connect loops to their surrounding nodes in the outer body.+ // Does not influence "completeness" of path.+ return path;+ }++ assert(ppoint == edge.Index[0]); if (edgeEndsValueLiveRange(edge, variable, body)) {- // Terminate the search through this point; we thought we were- // within the live range, but it turns out that the variable- // was set to a value that we don't care about.- continue;- }-- var edge_kills = edgeStartsValueLiveRange(edge, variable);- var edge_uses = edgeUsesVariable(edge, variable, body);-- if (edge_kills || edge_uses) {- if (!body.minimumUse || source < body.minimumUse)- body.minimumUse = source;- }-- if (edge_kills) {+ // Terminate the search through this point.+ return null;+ }++ const edge_starts = edgeStartsValueLiveRange(edge, variable);+ const edge_uses = edgeUsesVariable(edge, variable, body);++ if (edge_starts || edge_uses) {+ if (!body.minimumUse || ppoint < body.minimumUse)+ body.minimumUse = ppoint;+ }++ if (edge_starts) { // This is a beginning of the variable's live range. If we can // reach a GC call from here, then we're done -- we have a path- // from the beginning of the live range, through the GC call,- // to a use after the GC call that proves its live range- // extends at least that far.- if (gcInfo)- return {body: body, ppoint: source, gcInfo: gcInfo, why: entry };-- // Otherwise, keep searching through the graph, but truncate- // this particular branch of the search at this edge.- continue;- }-- var src_gcInfo = gcInfo;- var src_preGCLive = preGCLive;- if (!gcInfo && !(body.attrs[source] & ATTR_GC_SUPPRESSED) && !(suppressed & ATTR_GC_SUPPRESSED)) {+ // from the beginning of the live range, through the GC call, to a+ // use after the GC call that proves its live range extends at+ // least that far.+ if (path.gcInfo) {+ path.anyUse = path.anyUse || edge;+ path.informativeUse = path.informativeUse || edge;+ return path;+ }++ // Otherwise, truncate this particular branch of the search at this+ // edge -- there is no GC after this use, and traversing the edge+ // would lead to a different live range.+ return null;+ }++ // The value is live across this edge. Check whether this edge can GC (if we don't have a GC yet on this path.)+ const had_gcInfo = Boolean(path.gcInfo);+ if (!path.gcInfo && !(body.attrs[ppoint] & ATTR_GC_SUPPRESSED) && !isGCSuppressed) { var gcName = edgeCanGC(edge, body);- if (gcName)- src_gcInfo = {name:gcName, body:body, ppoint:source};- }-- if (edge_uses) {- // The live range starts at least this far back, so we're done- // for the same reason as with edge_kills. The only difference- // is that a GC on this edge indicates a hazard, whereas if- // we're killing a live range in the GC call then it's not live- // *across* the call.- //- // However, we may want to generate a longer usage chain for- // the variable than is minimally necessary. For example,- // consider:- //- // Value v = f();- // if (v.isUndefined())- // return false;- // gc();- // return v;- //- // The call to .isUndefined() is considered to be a use and- // therefore indicates that v must be live at that point. But- // it's more helpful to the user to continue the 'why' path to- // include the ancestor where the value was generated. So we- // will only return here if edge.Kind is Assign; otherwise,- // we'll pass a "preGCLive" value up through the worklist to- // remember that the variable *is* alive before the GC and so- // this function should be returning a true value even if we- // don't find an assignment.-- if (src_gcInfo) {- src_preGCLive = true;- if (edge.Kind == 'Assign')- return {body:body, ppoint:source, gcInfo:src_gcInfo, why:entry};- }- }-- if (edge.Kind == "Loop") {- // Additionally propagate the search into a loop body, starting- // with the exit point.- var found = false;- for (var xbody of functionBodies) {- if (sameBlockId(xbody.BlockId, edge.BlockId)) {- assert(!found);- found = true;- worklist.push({body:xbody, ppoint:xbody.Index[1],- preGCLive: src_preGCLive, gcInfo:src_gcInfo,- why:entry});- }- }- assert(found);- // Don't continue to predecessors here without going through- // the loop. (The points in this body that enter the loop will- // be traversed when we reach the entry point of the loop.)- break;- }-- // Propagate the search to the predecessors of this edge.- worklist.push({body:body, ppoint:source,- preGCLive: src_preGCLive, gcInfo:src_gcInfo,- why:entry});- }- }-- return null;+ if (gcName) {+ path.gcInfo = {name:gcName, body, ppoint};+ }+ }++ // Beginning of function?+ if (ppoint == body.Index[0] && body.BlockId.Kind != "Loop") {+ if (path.gcInfo && (variable.Kind == "Arg" || variable.Kind == "This")) {+ // The scope of arguments starts at the beginning of the+ // function.+ path.anyUse = path.informativeUse = true;+ }++ if (path.anyUse) {+ // We know the variable was live across the GC. We may or+ // may not have found an "informative" explanation+ // beginning of the live range. (This can happen if the+ // live range started when a variable is used as a+ // retparam.)+ return path;+ }+ }++ if (!path.gcInfo) {+ // We haven't reached a GC yet, so don't start looking for uses.+ return path;+ }++ if (!edge_uses) {+ // We have a GC. If this edge doesn't use the value, then there+ // is no change to the completeness of the path.+ return path;+ }++ // The live range starts at least this far back, so we're done for+ // the same reason as with edge_starts. The only difference is that+ // a GC on this edge indicates a hazard, whereas if we're killing a+ // live range in the GC call then it's not live *across* the call.+ //+ // However, we may want to generate a longer usage chain for the+ // variable than is minimally necessary. For example, consider:+ //
Based on the provided code diff, I'll analyze it for security fixes: 1. Vulnerability Existed: yes Input Validation Vulnerability [js/src/devtools/rootAnalysis/analyzeRoots.js] [Lines 16-75] [Old Code] ```javascript if (typeof scriptArgs[0] != 'string' || typeof scriptArgs[1] != 'string') throw "Usage: analyzeRoots.js [-f function_name] <gcFunctions.lst> <gcEdges.txt> <limitedFunctions.lst> <gcTypes.txt> <typeInfo.txt> [start end [tmpfile]]"; var theFunctionNameToFind; if (scriptArgs[0] == '--function' || scriptArgs[0] == '-f') { theFunctionNameToFind = scriptArgs[1]; scriptArgs = scriptArgs.slice(2); } var gcFunctionsFile = scriptArgs[0] || "gcFunctions.lst"; var gcEdgesFile = scriptArgs[1] || "gcEdges.txt"; var limitedFunctionsFile = scriptArgs[2] || "limitedFunctions.lst"; var gcTypesFile = scriptArgs[3] || "gcTypes.txt"; var typeInfoFile = scriptArgs[4] || "typeInfo.txt"; var batch = (scriptArgs[5]|0) || 1; var numBatches = (scriptArgs[6]|0) || 1; var tmpfile = scriptArgs[7] || "tmp.txt"; ``` [Fixed Code] ```javascript try { var options = parse_options([ { name: "--function", type: 'string', }, { name: "-f", type: "string", dest: "function", }, { name: "gcFunctions", default: "gcFunctions.lst" }, { name: "gcEdges", default: "gcEdges.json" }, { name: "limitedFunctions", default: "limitedFunctions.lst" }, { name: "gcTypes", default: "gcTypes.txt" }, { name: "typeInfo", default: "typeInfo.txt" }, { name: "batch", type: "number", default: 1 }, { name: "numBatches", type: "number", default: 1 }, { name: "tmpfile", default: "tmp.txt" }, ]); } catch (e) { printErr(e); printErr("Usage: analyzeRoots.js [-f function_name] <gcFunctions.lst> <gcEdges.txt> <limitedFunctions.lst> <gcTypes.txt> <typeInfo.txt> [start end [tmpfile]]"); quit(1); } ``` 2. Vulnerability Existed: yes File Extension Vulnerability [js/src/devtools/rootAnalysis/analyzeRoots.js] [Lines 78-80] [Old Code] ```javascript var gcEdges = {}; text = snarf(gcEdgesFile).split('\n'); assert(text.pop().length == 0); for (const line of text) { var [ block, edge, func ] = line.split(" || "); if (!(block in gcEdges)) gcEdges[block] = {} gcEdges[block][edge] = func; } text = null; ``` [Fixed Code] ```javascript var gcEdges = JSON.parse(os.file.readFile(options.gcEdges)); ``` The changes show: 1. A more robust command-line argument parsing system was implemented, replacing the manual parsing which could be vulnerable to injection or malformed input. 2. The gcEdges file handling was changed from manual text parsing to using JSON.parse(), which is more secure and less prone to parsing errors or injection vulnerabilities. The file extension was also changed from .txt to .json to reflect this change. These changes improve the security and robustness of the code by: - Using proper input validation - Replacing manual parsing with safer built-in methods - Using structured data formats (JSON) instead of custom text formats - Providing better error handling
If an attacker could control the contents of an iframe sandboxed with <code>allow-popups</code> but not <code>allow-scripts</code>, they were able to craft a link that, when clicked, would lead to JavaScript execution in violation of the sandbox. This vulnerability affects Firefox < 98, Firefox ESR < 91.7, and Thunderbird < 91.7.
--- /root/PatchLeaks-main/products/firefox_downloads/FIREFOX_RELEASE_97_END/firefox-FIREFOX_RELEASE_97_END/remote/doc/marionette/Patches.md+++ /root/PatchLeaks-main/products/firefox_downloads/FIREFOX_RELEASE_98_END/firefox-FIREFOX_RELEASE_98_END/remote/doc/marionette/Patches.md@@ -27,7 +27,7 @@ mach try fuzzy [Phabricator]: https://moz-conduit.readthedocs.io/en/latest/phabricator-user.html-[commit creation guidelines]: https://mozilla-version-control-tools.readthedocs.io/en/latest/devguide/contributing.html?highlight=phabricator#submitting-patches-for-review+[commit creation guidelines]: https://mozilla-version-control-tools.readthedocs.io/en/latest/devguide/contributing.html#submitting-patches-for-review [becoming a Mozilla committer]: https://www.mozilla.org/en-US/about/governance/policies/commit/ [Firefox CI]: https://treeherder.mozilla.org/-[try preset]: https://firefox-source-docs.mozilla.org/tools/try/presets.html+[try preset]: /tools/try/presets
Based on the provided diff, I don't see any security-related changes. The changes appear to be documentation updates involving URL links and formatting. Here's the analysis: Vulnerability Existed: no No security vulnerability found in the diff. The changes are documentation updates to URLs and formatting. Details: 1. Changed URL for "commit creation guidelines" (removed fragment identifier) 2. Changed URL for "try preset" (made it a relative path) Neither change appears to be security-related - they seem to be either URL normalization or documentation structure improvements. The diff doesn't show any: - Code changes that could introduce security issues - Fixes for known vulnerabilities - Security-related configuration changes Therefore, I conclude there are no security vulnerabilities addressed in this particular diff.
If an attacker could control the contents of an iframe sandboxed with <code>allow-popups</code> but not <code>allow-scripts</code>, they were able to craft a link that, when clicked, would lead to JavaScript execution in violation of the sandbox. This vulnerability affects Firefox < 98, Firefox ESR < 91.7, and Thunderbird < 91.7.
--- /root/PatchLeaks-main/products/firefox_downloads/FIREFOX_RELEASE_97_END/firefox-FIREFOX_RELEASE_97_END/js/examples/jorendb.js+++ /root/PatchLeaks-main/products/firefox_downloads/FIREFOX_RELEASE_98_END/firefox-FIREFOX_RELEASE_98_END/js/examples/jorendb.js@@ -59,7 +59,10 @@ // Convert a debuggee value v to a string. function dvToString(v) {- return (typeof v !== 'object' || v === null) ? uneval(v) : "[object " + v.class + "]";+ if (typeof(v) === 'object' && v !== null) {+ return `[object ${v.class}]`;+ }+ return uneval(v); } function summaryObject(dv) {@@ -76,7 +79,7 @@ function debuggeeValueToString(dv, style) { var dvrepr = dvToString(dv);- if (!style.pretty || (typeof dv !== 'object'))+ if (!style.pretty || (typeof dv !== 'object') || (dv === null)) return [dvrepr, undefined]; const exec = debuggeeGlobalWrapper.executeInGlobalWithBindings.bind(debuggeeGlobalWrapper);@@ -874,6 +877,7 @@ } catch (exc) { print("Caught exception " + exc); print(exc.stack);+ break; } } else if (task.action == 'repl') { repl();
Analyzing the provided code diff, I've identified the following potential security fixes: 1. Vulnerability Existed: not sure [Potential XSS or Object Injection] [js/examples/jorendb.js] [Lines 59-62] [Old Code] return (typeof v !== 'object' || v === null) ? uneval(v) : "[object " + v.class + "]"; [Fixed Code] if (typeof(v) === 'object' && v !== null) { return `[object ${v.class}]`; } return uneval(v); 2. Vulnerability Existed: not sure [Null Pointer Dereference] [js/examples/jorendb.js] [Lines 76-79] [Old Code] if (!style.pretty || (typeof dv !== 'object')) [Fixed Code] if (!style.pretty || (typeof dv !== 'object') || (dv === null)) 3. Vulnerability Existed: yes [Uncaught Exception Handling] [js/examples/jorendb.js] [Lines 874-878] [Old Code] } catch (exc) { print("Caught exception " + exc); print(exc.stack); } [Fixed Code] } catch (exc) { print("Caught exception " + exc); print(exc.stack); break; } Note: While these changes appear to improve code safety and reliability, it's difficult to definitively classify them as security vulnerabilities without more context about how these functions are used in the broader application. The first two changes appear to be defensive programming improvements, while the third change clearly fixes a potential issue where exceptions could be silently caught without proper handling.
If an attacker could control the contents of an iframe sandboxed with <code>allow-popups</code> but not <code>allow-scripts</code>, they were able to craft a link that, when clicked, would lead to JavaScript execution in violation of the sandbox. This vulnerability affects Firefox < 98, Firefox ESR < 91.7, and Thunderbird < 91.7.
--- /root/PatchLeaks-main/products/firefox_downloads/FIREFOX_RELEASE_97_END/firefox-FIREFOX_RELEASE_97_END/js/src/jit/shared/AtomicOperations-feeling-lucky-gcc.h+++ /root/PatchLeaks-main/products/firefox_downloads/FIREFOX_RELEASE_98_END/firefox-FIREFOX_RELEASE_98_END/js/src/jit/shared/AtomicOperations-feeling-lucky-gcc.h@@ -30,11 +30,9 @@ // Explicitly exclude tier-1 platforms.-#if ((defined(__x86_64__) || defined(_M_X64)) && defined(JS_CODEGEN_X64)) || \- ((defined(__i386__) || defined(_M_IX86)) && defined(JS_CODEGEN_X86)) || \- (defined(__arm__) && defined(JS_CODEGEN_ARM)) || \- ((defined(__aarch64__) || defined(_M_ARM64)) && defined(JS_CODEGEN_ARM64))-# error "Do not use this code on a tier-1 platform when a JIT is available"+#if (defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || \+ defined(_M_IX86) || defined(__arm__) || defined(__aarch64__))+# error "Do not use on a tier-1 platform where inline assembly is available" #endif #if !(defined(__clang__) || defined(__GNUC__))@@ -103,15 +101,6 @@ // Try to avoid platform #ifdefs below this point.-inline bool js::jit::AtomicOperations::Initialize() {- // Nothing- return true;-}--inline void js::jit::AtomicOperations::ShutDown() {- // Nothing-}- // When compiling with Clang on 32-bit linux it will be necessary to link with // -latomic to get the proper 64-bit intrinsics.
Let me analyze the code diff for potential security vulnerabilities: 1. Vulnerability Existed: not sure [Platform Detection Logic Change] [js/src/jit/shared/AtomicOperations-feeling-lucky-gcc.h] [Lines 30-34] [Old Code] #if ((defined(__x86_64__) || defined(_M_X64)) && defined(JS_CODEGEN_X64)) || \ ((defined(__i386__) || defined(_M_IX86)) && defined(JS_CODEGEN_X86)) || \ (defined(__arm__) && defined(JS_CODEGEN_ARM)) || \ ((defined(__aarch64__) || defined(_M_ARM64)) && defined(JS_CODEGEN_ARM64)) # error "Do not use this code on a tier-1 platform when a JIT is available" [Fixed Code] #if (defined(__x86_64__) || defined(_M_X64) || defined(__i386__) || \ defined(_M_IX86) || defined(__arm__) || defined(__aarch64__)) # error "Do not use on a tier-1 platform where inline assembly is available" 2. Vulnerability Existed: not sure [Removed Initialization/Shutdown Functions] [js/src/jit/shared/AtomicOperations-feeling-lucky-gcc.h] [Lines 103-111] [Old Code] inline bool js::jit::AtomicOperations::Initialize() { // Nothing return true; } inline void js::jit::AtomicOperations::ShutDown() { // Nothing } [Fixed Code] [Removed entirely] Analysis: 1. The first change modifies the platform detection logic, removing the JS_CODEGEN_* checks. This might relate to ensuring proper atomic operation handling across platforms, but I'm not certain if this fixes a specific vulnerability. 2. The removal of Initialize() and ShutDown() functions suggests they were unnecessary, but without more context, I can't determine if this was fixing a vulnerability or just cleaning up dead code. Neither change clearly indicates a specific known vulnerability, but they both relate to atomic operations handling which is security-sensitive code. The changes appear to be hardening measures rather than fixing identified vulnerabilities.
If an attacker could control the contents of an iframe sandboxed with <code>allow-popups</code> but not <code>allow-scripts</code>, they were able to craft a link that, when clicked, would lead to JavaScript execution in violation of the sandbox. This vulnerability affects Firefox < 98, Firefox ESR < 91.7, and Thunderbird < 91.7.
--- /root/PatchLeaks-main/products/firefox_downloads/FIREFOX_RELEASE_97_END/firefox-FIREFOX_RELEASE_97_END/layout/reftests/css-grid/grid-fragmentation-021.html+++ /root/PatchLeaks-main/products/firefox_downloads/FIREFOX_RELEASE_98_END/firefox-FIREFOX_RELEASE_98_END/layout/reftests/css-grid/grid-fragmentation-021.html@@ -23,7 +23,7 @@ -ms-column-fill: auto; -webkit-column-fill: auto; column-fill: auto;- border: 2px dashed;+ border: 2px solid salmon; margin-bottom: 1px; height: 150px; }
After analyzing the provided code diff, I don't see any security-related changes. The modification appears to be purely cosmetic/stylistic, changing the border style from dashed to solid salmon color. Here's the analysis following your format: Vulnerability Existed: no [No security vulnerability found] [layout/reftests/css-grid/grid-fragmentation-021.html] [Lines 23] [Old Code: border: 2px dashed;] [Fixed Code: border: 2px solid salmon;] Additional Notes: - This change appears to be a visual test adjustment rather than a security fix - No known vulnerabilities are associated with CSS border styling changes - The modification is likely for better visual testing/differentiation in the reftest
If an attacker could control the contents of an iframe sandboxed with <code>allow-popups</code> but not <code>allow-scripts</code>, they were able to craft a link that, when clicked, would lead to JavaScript execution in violation of the sandbox. This vulnerability affects Firefox < 98, Firefox ESR < 91.7, and Thunderbird < 91.7.
--- /root/PatchLeaks-main/products/firefox_downloads/FIREFOX_RELEASE_97_END/firefox-FIREFOX_RELEASE_97_END/testing/web-platform/tests/html/canvas/offscreen/shadows/2d.shadow.enable.x.worker.js+++ /root/PatchLeaks-main/products/firefox_downloads/FIREFOX_RELEASE_98_END/firefox-FIREFOX_RELEASE_98_END/testing/web-platform/tests/html/canvas/offscreen/shadows/2d.shadow.enable.x.worker.js@@ -13,15 +13,15 @@ }); t.step(function() {-var offscreenCanvas = new OffscreenCanvas(100, 50);-var ctx = offscreenCanvas.getContext('2d');+var canvas = new OffscreenCanvas(100, 50);+var ctx = canvas.getContext('2d'); ctx.globalCompositeOperation = 'destination-atop'; ctx.shadowColor = '#0f0'; ctx.shadowOffsetX = 0.1; ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50);-_assertPixel(offscreenCanvas, 50,25, 0,255,0,255, "50,25", "0,255,0,255");+_assertPixel(canvas, 50,25, 0,255,0,255, "50,25", "0,255,0,255"); t.done(); });
Here's the analysis of the provided code diff: Vulnerability Existed: no Variable Renaming [File] [Lines 13-15, 21] [Old Code] ```javascript var offscreenCanvas = new OffscreenCanvas(100, 50); var ctx = offscreenCanvas.getContext('2d'); _assertPixel(offscreenCanvas, 50,25, 0,255,0,255, "50,25", "0,255,0,255"); ``` [Fixed Code] ```javascript var canvas = new OffscreenCanvas(100, 50); var ctx = canvas.getContext('2d'); _assertPixel(canvas, 50,25, 0,255,0,255, "50,25", "0,255,0,255"); ``` The changes appear to be purely cosmetic, renaming the variable `offscreenCanvas` to `canvas` for consistency or clarity. There are no security-related changes or vulnerabilities being addressed in this diff. The functionality remains exactly the same, only the variable name has changed.
If an attacker could control the contents of an iframe sandboxed with <code>allow-popups</code> but not <code>allow-scripts</code>, they were able to craft a link that, when clicked, would lead to JavaScript execution in violation of the sandbox. This vulnerability affects Firefox < 98, Firefox ESR < 91.7, and Thunderbird < 91.7.
--- /root/PatchLeaks-main/products/firefox_downloads/FIREFOX_RELEASE_97_END/firefox-FIREFOX_RELEASE_97_END/testing/web-platform/tests/html/canvas/offscreen/path-objects/2d.path.transformation.multiple.worker.js+++ /root/PatchLeaks-main/products/firefox_downloads/FIREFOX_RELEASE_98_END/firefox-FIREFOX_RELEASE_98_END/testing/web-platform/tests/html/canvas/offscreen/path-objects/2d.path.transformation.multiple.worker.js@@ -13,8 +13,8 @@ }); t.step(function() {-var offscreenCanvas = new OffscreenCanvas(100, 50);-var ctx = offscreenCanvas.getContext('2d');+var canvas = new OffscreenCanvas(100, 50);+var ctx = canvas.getContext('2d'); ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50);@@ -33,7 +33,7 @@ ctx.stroke(); ctx.translate(0, 50); ctx.stroke();-_assertPixel(offscreenCanvas, 50,25, 0,255,0,255, "50,25", "0,255,0,255");+_assertPixel(canvas, 50,25, 0,255,0,255, "50,25", "0,255,0,255"); t.done(); });
Based on the provided code diff, I don't see any security vulnerabilities being fixed. The changes appear to be purely variable renaming for better code clarity. Here's the analysis: Vulnerability Existed: no [No security vulnerability found] [testing/web-platform/tests/html/canvas/offscreen/path-objects/2d.path.transformation.multiple.worker.js] [Lines 13-33] [Old Code] var offscreenCanvas = new OffscreenCanvas(100, 50); var ctx = offscreenCanvas.getContext('2d'); ... _assertPixel(offscreenCanvas, 50,25, 0,255,0,255, "50,25", "0,255,0,255"); [Fixed Code] var canvas = new OffscreenCanvas(100, 50); var ctx = canvas.getContext('2d'); ... _assertPixel(canvas, 50,25, 0,255,0,255, "50,25", "0,255,0,255"); The changes simply rename the variable from `offscreenCanvas` to `canvas` and update all references to it. There are no security implications to this change.
If an attacker could control the contents of an iframe sandboxed with <code>allow-popups</code> but not <code>allow-scripts</code>, they were able to craft a link that, when clicked, would lead to JavaScript execution in violation of the sandbox. This vulnerability affects Firefox < 98, Firefox ESR < 91.7, and Thunderbird < 91.7.
--- /root/PatchLeaks-main/products/firefox_downloads/FIREFOX_RELEASE_97_END/firefox-FIREFOX_RELEASE_97_END/testing/web-platform/tests/html/canvas/offscreen/transformations/2d.transformation.rotate.direction.html+++ /root/PatchLeaks-main/products/firefox_downloads/FIREFOX_RELEASE_98_END/firefox-FIREFOX_RELEASE_98_END/testing/web-platform/tests/html/canvas/offscreen/transformations/2d.transformation.rotate.direction.html@@ -17,15 +17,15 @@ }); t.step(function() {-var offscreenCanvas = new OffscreenCanvas(100, 50);-var ctx = offscreenCanvas.getContext('2d');+var canvas = new OffscreenCanvas(100, 50);+var ctx = canvas.getContext('2d'); ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.rotate(Math.PI / 2); ctx.fillStyle = '#0f0'; ctx.fillRect(0, -100, 50, 100);-_assertPixel(offscreenCanvas, 50,25, 0,255,0,255, "50,25", "0,255,0,255");+_assertPixel(canvas, 50,25, 0,255,0,255, "50,25", "0,255,0,255"); t.done(); });
After analyzing the provided code diff, here's the security assessment: 1. Vulnerability Existed: no No security vulnerability found [File] [Lines 17-26] [Old Code] var offscreenCanvas = new OffscreenCanvas(100, 50); var ctx = offscreenCanvas.getContext('2d'); ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.rotate(Math.PI / 2); ctx.fillStyle = '#0f0'; ctx.fillRect(0, -100, 50, 100); _assertPixel(offscreenCanvas, 50,25, 0,255,0,255, "50,25", "0,255,0,255"); [Fixed Code] var canvas = new OffscreenCanvas(100, 50); var ctx = canvas.getContext('2d'); ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50); ctx.rotate(Math.PI / 2); ctx.fillStyle = '#0f0'; ctx.fillRect(0, -100, 50, 100); _assertPixel(canvas, 50,25, 0,255,0,255, "50,25", "0,255,0,255"); Additional Details: - The changes appear to be purely variable renaming (from `offscreenCanvas` to `canvas`) and don't affect security - The test functionality remains identical, just with a different variable name - No security-relevant changes were made to the canvas operations or assertions - The changes are likely for code consistency or readability purposes
If an attacker could control the contents of an iframe sandboxed with <code>allow-popups</code> but not <code>allow-scripts</code>, they were able to craft a link that, when clicked, would lead to JavaScript execution in violation of the sandbox. This vulnerability affects Firefox < 98, Firefox ESR < 91.7, and Thunderbird < 91.7.
--- /root/PatchLeaks-main/products/firefox_downloads/FIREFOX_RELEASE_97_END/firefox-FIREFOX_RELEASE_97_END/third_party/rust/typenum/src/bit.rs+++ /root/PatchLeaks-main/products/firefox_downloads/FIREFOX_RELEASE_98_END/firefox-FIREFOX_RELEASE_98_END/third_party/rust/typenum/src/bit.rs@@ -16,6 +16,7 @@ /// The type-level bit 0. #[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Hash, Debug, Default)]+#[cfg_attr(feature = "scale_info", derive(scale_info::TypeInfo))] pub struct B0; impl B0 {@@ -28,6 +29,7 @@ /// The type-level bit 1. #[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Hash, Debug, Default)]+#[cfg_attr(feature = "scale_info", derive(scale_info::TypeInfo))] pub struct B1; impl B1 {
Analysis of the provided code diff: 1. Vulnerability Existed: no No security vulnerability found [File] third_party/rust/typenum/src/bit.rs [Lines] 16-29 [Old Code] #[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Hash, Debug, Default)] pub struct B0; #[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Hash, Debug, Default)] pub struct B1; [Fixed Code] #[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Hash, Debug, Default)] #[cfg_attr(feature = "scale_info", derive(scale_info::TypeInfo))] pub struct B0; #[derive(Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Hash, Debug, Default)] #[cfg_attr(feature = "scale_info", derive(scale_info::TypeInfo))] pub struct B1; The changes only add a conditional derive for `scale_info::TypeInfo` when the "scale_info" feature is enabled. This appears to be a feature enhancement rather than a security fix. No security vulnerabilities are being addressed in this diff.
If an attacker could control the contents of an iframe sandboxed with <code>allow-popups</code> but not <code>allow-scripts</code>, they were able to craft a link that, when clicked, would lead to JavaScript execution in violation of the sandbox. This vulnerability affects Firefox < 98, Firefox ESR < 91.7, and Thunderbird < 91.7.
--- /root/PatchLeaks-main/products/firefox_downloads/FIREFOX_RELEASE_97_END/firefox-FIREFOX_RELEASE_97_END/dom/webauthn/WebAuthnManager.cpp+++ /root/PatchLeaks-main/products/firefox_downloads/FIREFOX_RELEASE_98_END/firefox-FIREFOX_RELEASE_98_END/dom/webauthn/WebAuthnManager.cpp@@ -46,14 +46,12 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(WebAuthnManager, WebAuthnManagerBase)- AbortFollower::Unlink(static_cast<AbortFollower*>(tmp)); NS_IMPL_CYCLE_COLLECTION_UNLINK(mTransaction) tmp->mTransaction.reset(); NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(WebAuthnManager, WebAuthnManagerBase)- AbortFollower::Traverse(static_cast<AbortFollower*>(tmp), cb); NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTransaction) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
Here's the analysis of the provided code diff: Vulnerability Existed: not sure Memory Management Issue (Potential) [dom/webauthn/WebAuthnManager.cpp] [Lines 46-54] [Old Code] ``` NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(WebAuthnManager, WebAuthnManagerBase) AbortFollower::Unlink(static_cast<AbortFollower*>(tmp)); NS_IMPL_CYCLE_COLLECTION_UNLINK(mTransaction) tmp->mTransaction.reset(); NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(WebAuthnManager, WebAuthnManagerBase) AbortFollower::Traverse(static_cast<AbortFollower*>(tmp), cb); NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTransaction) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END ``` [Fixed Code] ``` NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(WebAuthnManager, WebAuthnManagerBase) NS_IMPL_CYCLE_COLLECTION_UNLINK(mTransaction) tmp->mTransaction.reset(); NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(WebAuthnManager, WebAuthnManagerBase) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTransaction) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END ``` Additional Details: 1. The changes remove calls to `AbortFollower::Unlink` and `AbortFollower::Traverse` 2. This appears to be related to cycle collection (memory management) in Gecko's XPCOM system 3. While not clearly a security fix, improper cycle collection could potentially lead to memory-related vulnerabilities 4. Without more context about the `AbortFollower` class and its role, it's difficult to determine if this was fixing a specific vulnerability 5. The change might be related to refactoring or fixing potential memory leaks rather than addressing a direct security issue
If an attacker could control the contents of an iframe sandboxed with <code>allow-popups</code> but not <code>allow-scripts</code>, they were able to craft a link that, when clicked, would lead to JavaScript execution in violation of the sandbox. This vulnerability affects Firefox < 98, Firefox ESR < 91.7, and Thunderbird < 91.7.
--- /root/PatchLeaks-main/products/firefox_downloads/FIREFOX_RELEASE_97_END/firefox-FIREFOX_RELEASE_97_END/testing/web-platform/tests/html/canvas/offscreen/path-objects/2d.path.moveTo.basic.html+++ /root/PatchLeaks-main/products/firefox_downloads/FIREFOX_RELEASE_98_END/firefox-FIREFOX_RELEASE_98_END/testing/web-platform/tests/html/canvas/offscreen/path-objects/2d.path.moveTo.basic.html@@ -17,8 +17,8 @@ }); t.step(function() {-var offscreenCanvas = new OffscreenCanvas(100, 50);-var ctx = offscreenCanvas.getContext('2d');+var canvas = new OffscreenCanvas(100, 50);+var ctx = canvas.getContext('2d'); ctx.fillStyle = '#f00'; ctx.fillRect(0, 0, 100, 50);@@ -29,7 +29,7 @@ ctx.lineTo(100, 50); ctx.fillStyle = '#0f0'; ctx.fill();-_assertPixel(offscreenCanvas, 90,25, 0,255,0,255, "90,25", "0,255,0,255");+_assertPixel(canvas, 90,25, 0,255,0,255, "90,25", "0,255,0,255"); t.done(); });
After analyzing the provided code diff, I don't see any security vulnerabilities being fixed. The changes appear to be purely cosmetic/refactoring changes (variable renaming) rather than security fixes. Here's the analysis following your requested format: Vulnerability Existed: no [No security vulnerability found] [testing/web-platform/tests/html/canvas/offscreen/path-objects/2d.path.moveTo.basic.html] [17-29] [Old Code] var offscreenCanvas = new OffscreenCanvas(100, 50); var ctx = offscreenCanvas.getContext('2d'); ... _assertPixel(offscreenCanvas, 90,25, 0,255,0,255, "90,25", "0,255,0,255"); [Fixed Code] var canvas = new OffscreenCanvas(100, 50); var ctx = canvas.getContext('2d'); ... _assertPixel(canvas, 90,25, 0,255,0,255, "90,25", "0,255,0,255"); The changes simply rename the variable `offscreenCanvas` to `canvas` throughout the file, which doesn't appear to address any security vulnerability. The functionality remains exactly the same.
If an attacker could control the contents of an iframe sandboxed with <code>allow-popups</code> but not <code>allow-scripts</code>, they were able to craft a link that, when clicked, would lead to JavaScript execution in violation of the sandbox. This vulnerability affects Firefox < 98, Firefox ESR < 91.7, and Thunderbird < 91.7.
--- /root/PatchLeaks-main/products/firefox_downloads/FIREFOX_RELEASE_97_END/firefox-FIREFOX_RELEASE_97_END/testing/web-platform/tests/html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.paint.repeaty.outside.html+++ /root/PatchLeaks-main/products/firefox_downloads/FIREFOX_RELEASE_98_END/firefox-FIREFOX_RELEASE_98_END/testing/web-platform/tests/html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.paint.repeaty.outside.html@@ -17,8 +17,8 @@ }); t.step(function() {-var offscreenCanvas = new OffscreenCanvas(100, 50);-var ctx = offscreenCanvas.getContext('2d');+var canvas = new OffscreenCanvas(100, 50);+var ctx = canvas.getContext('2d'); ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 100, 50);@@ -38,10 +38,10 @@ ctx.fillRect(0, 0, 100, 50); ctx.fillStyle = '#0f0'; ctx.fillRect(0, 0, 16, 50);- _assertPixel(offscreenCanvas, 1,1, 0,255,0,255, "1,1", "0,255,0,255");- _assertPixel(offscreenCanvas, 98,1, 0,255,0,255, "98,1", "0,255,0,255");- _assertPixel(offscreenCanvas, 1,48, 0,255,0,255, "1,48", "0,255,0,255");- _assertPixel(offscreenCanvas, 98,48, 0,255,0,255, "98,48", "0,255,0,255");+ _assertPixel(canvas, 1,1, 0,255,0,255, "1,1", "0,255,0,255");+ _assertPixel(canvas, 98,1, 0,255,0,255, "98,1", "0,255,0,255");+ _assertPixel(canvas, 1,48, 0,255,0,255, "1,48", "0,255,0,255");+ _assertPixel(canvas, 98,48, 0,255,0,255, "98,48", "0,255,0,255"); }, t_fail); }).then(t_pass, t_fail);
After analyzing the provided code diff, I don't find any security vulnerabilities. The changes appear to be purely variable renaming (from `offscreenCanvas` to `canvas`) and corresponding updates to the variable name in the assertions. Here's the structured response: Vulnerability Existed: no No security vulnerability found File: testing/web-platform/tests/html/canvas/offscreen/fill-and-stroke-styles/2d.pattern.paint.repeaty.outside.html Lines: 17-18, 38-41 Old Code: ```javascript var offscreenCanvas = new OffscreenCanvas(100, 50); var ctx = offscreenCanvas.getContext('2d'); ... _assertPixel(offscreenCanvas, 1,1, 0,255,0,255, "1,1", "0,255,0,255"); _assertPixel(offscreenCanvas, 98,1, 0,255,0,255, "98,1", "0,255,0,255"); _assertPixel(offscreenCanvas, 1,48, 0,255,0,255, "1,48", "0,255,0,255"); _assertPixel(offscreenCanvas, 98,48, 0,255,0,255, "98,48", "0,255,0,255"); ``` Fixed Code: ```javascript var canvas = new OffscreenCanvas(100, 50); var ctx = canvas.getContext('2d'); ... _assertPixel(canvas, 1,1, 0,255,0,255, "1,1", "0,255,0,255"); _assertPixel(canvas, 98,1, 0,255,0,255, "98,1", "0,255,0,255"); _assertPixel(canvas, 1,48, 0,255,0,255, "1,48", "0,255,0,255"); _assertPixel(canvas, 98,48, 0,255,0,255, "98,48", "0,255,0,255"); ``` The changes are purely cosmetic/refactoring in nature and don't affect security. No vulnerability name applies as this isn't a security-related fix.
If an attacker could control the contents of an iframe sandboxed with <code>allow-popups</code> but not <code>allow-scripts</code>, they were able to craft a link that, when clicked, would lead to JavaScript execution in violation of the sandbox. This vulnerability affects Firefox < 98, Firefox ESR < 91.7, and Thunderbird < 91.7.
--- /root/PatchLeaks-main/products/firefox_downloads/FIREFOX_RELEASE_97_END/firefox-FIREFOX_RELEASE_97_END/third_party/rust/darling_core/src/options/from_field.rs+++ /root/PatchLeaks-main/products/firefox_downloads/FIREFOX_RELEASE_98_END/firefox-FIREFOX_RELEASE_98_END/third_party/rust/darling_core/src/options/from_field.rs@@ -1,10 +1,10 @@ use proc_macro2::TokenStream; use quote::ToTokens;-use syn::{self, Ident};+use syn::Ident;-use codegen::FromFieldImpl;-use options::{OuterFrom, ParseAttribute, ParseData};-use Result;+use crate::codegen::FromFieldImpl;+use crate::options::{OuterFrom, ParseAttribute, ParseData};+use crate::Result; #[derive(Debug)] pub struct FromFieldOptions {@@ -16,7 +16,7 @@ impl FromFieldOptions { pub fn new(di: &syn::DeriveInput) -> Result<Self> { (FromFieldOptions {- base: OuterFrom::start(di),+ base: OuterFrom::start(di)?, vis: Default::default(), ty: Default::default(), })
Based on the provided diff, I'll analyze it for security vulnerabilities: 1. Vulnerability Existed: no No specific vulnerability [File] third_party/rust/darling_core/src/options/from_field.rs [Lines] 1-10 [Old Code] use syn::{self, Ident}; use codegen::FromFieldImpl; use options::{OuterFrom, ParseAttribute, ParseData}; use Result; [Fixed Code] use syn::Ident; use crate::codegen::FromFieldImpl; use crate::options::{OuterFrom, ParseAttribute, ParseData}; use crate::Result; Additional Details: This change appears to be purely about code organization and style, switching from relative imports to absolute crate imports. No security implications. 2. Vulnerability Existed: not sure Potential error handling improvement [File] third_party/rust/darling_core/src/options/from_field.rs [Lines] 16 [Old Code] base: OuterFrom::start(di), [Fixed Code] base: OuterFrom::start(di)?, Additional Details: The change adds error propagation (?) operator to handle potential failures from OuterFrom::start(). While this improves error handling, it's unclear if this fixes a specific security vulnerability or is just general robustness improvement. No clear security vulnerabilities were identified in this diff. The changes appear to be primarily about code organization and improved error handling.
If an attacker could control the contents of an iframe sandboxed with <code>allow-popups</code> but not <code>allow-scripts</code>, they were able to craft a link that, when clicked, would lead to JavaScript execution in violation of the sandbox. This vulnerability affects Firefox < 98, Firefox ESR < 91.7, and Thunderbird < 91.7.
--- /root/PatchLeaks-main/products/firefox_downloads/FIREFOX_RELEASE_97_END/firefox-FIREFOX_RELEASE_97_END/dom/media/DeviceInputTrack.cpp+++ /root/PatchLeaks-main/products/firefox_downloads/FIREFOX_RELEASE_98_END/firefox-FIREFOX_RELEASE_98_END/dom/media/DeviceInputTrack.cpp@@ -21,6 +21,11 @@ # undef LOG #endif // LOG #define LOG(msg, ...) LOG_INTERNAL(Debug, msg, ##__VA_ARGS__)++#ifdef LOGE+# undef LOGE+#endif // LOGE+#define LOGE(msg, ...) LOG_INTERNAL(Error, msg, ##__VA_ARGS__) // This can only be called in graph thread since mGraph->CurrentDriver() is // graph thread only@@ -45,29 +50,70 @@ TRACK_GRAPH_LOG_INTERNAL(Verbose, msg, ##__VA_ARGS__) /* static */-NativeInputTrack* NativeInputTrack::Create(- MediaTrackGraphImpl* aGraph, const PrincipalHandle& aPrincipalHandle) {- MOZ_ASSERT(NS_IsMainThread());-- NativeInputTrack* track =- new NativeInputTrack(aGraph->GraphRate(), aPrincipalHandle);- LOG("Create NativeInputTrack %p in MTG %p", track, aGraph);- aGraph->AddTrack(track);+Result<RefPtr<NativeInputTrack>, nsresult> NativeInputTrack::OpenAudio(+ MediaTrackGraphImpl* aGraph, CubebUtils::AudioDeviceID aDeviceId,+ const PrincipalHandle& aPrincipalHandle, AudioDataListener* aListener) {+ MOZ_ASSERT(NS_IsMainThread());++ RefPtr<NativeInputTrack> track = aGraph->GetNativeInputTrack();+ if (!track) {+ track =+ new NativeInputTrack(aGraph->GraphRate(), aDeviceId, aPrincipalHandle);+ LOG("Create NativeInputTrack %p in MTG %p for device %p", track.get(),+ aGraph, aDeviceId);+ aGraph->AddTrack(track);+ // Add the listener before opening the device so an open device always has a+ // non-zero input channel count.+ track->AddDataListener(aListener);+ aGraph->OpenAudioInput(track);+ } else if (track->mDeviceId != aDeviceId) {+ // We only allows one device per MediaTrackGraph for now.+ LOGE("Device %p is not native device", aDeviceId);+ return Err(NS_ERROR_INVALID_ARG);+ } else {+ MOZ_ASSERT(track->mUserCount > 0);+ track->AddDataListener(aListener);+ }+ MOZ_ASSERT(track->mDeviceId == aDeviceId);++ track->mUserCount += 1;+ LOG("NativeInputTrack %p (device %p) in MTG %p has %d users now", track.get(),+ track->mDeviceId, aGraph, track->mUserCount);+ if (track->mUserCount > 1) {+ track->ReevaluateInputDevice();+ }+ return track; }-size_t NativeInputTrack::AddUser() {- MOZ_ASSERT(NS_IsMainThread());- mUserCount += 1;- return mUserCount;-}--size_t NativeInputTrack::RemoveUser() {- MOZ_ASSERT(NS_IsMainThread());- MOZ_ASSERT(mUserCount > 0);- mUserCount -= 1;- return mUserCount;-}+/* static */+void NativeInputTrack::CloseAudio(RefPtr<NativeInputTrack>&& aTrack,+ AudioDataListener* aListener) {+ MOZ_ASSERT(NS_IsMainThread());+ MOZ_ASSERT(aTrack);+ MOZ_ASSERT(aTrack->mUserCount > 0);++ aTrack->RemoveDataListener(aListener);+ aTrack->mUserCount -= 1;+ LOG("NativeInputTrack %p (device %p) in MTG %p has %d users now",+ aTrack.get(), aTrack->mDeviceId, aTrack->GraphImpl(), aTrack->mUserCount);+ if (aTrack->mUserCount == 0) {+ aTrack->GraphImpl()->CloseAudioInput(aTrack);+ aTrack->Destroy();+ } else {+ aTrack->ReevaluateInputDevice();+ }+}++NativeInputTrack::NativeInputTrack(TrackRate aSampleRate,+ CubebUtils::AudioDeviceID aDeviceId,+ const PrincipalHandle& aPrincipalHandle)+ : ProcessedMediaTrack(aSampleRate, MediaSegment::AUDIO, new AudioSegment()),+ mDeviceId(aDeviceId),+ mPrincipalHandle(aPrincipalHandle),+ mIsBufferingAppended(false),+ mInputChannels(0),+ mUserCount(0) {} void NativeInputTrack::DestroyImpl() { MOZ_ASSERT(mGraph->OnGraphThreadOrNotRunning());@@ -106,16 +152,6 @@ uint32_t NativeInputTrack::NumberOfChannels() const { MOZ_ASSERT(mGraph->OnGraphThreadOrNotRunning()); return mInputChannels;-}--void NativeInputTrack::NotifyOutputData(MediaTrackGraphImpl* aGraph,- AudioDataValue* aBuffer, size_t aFrames,- TrackRate aRate, uint32_t aChannels) {- MOZ_ASSERT(aGraph->OnGraphThreadOrNotRunning());- MOZ_ASSERT(aGraph == mGraph, "Receive output data from another graph");- for (auto& listener : mDataUsers) {- listener->NotifyOutputData(aGraph, aBuffer, aFrames, aRate, aChannels);- } } void NativeInputTrack::NotifyInputStopped(MediaTrackGraphImpl* aGraph) {@@ -170,8 +206,89 @@ } }+uint32_t NativeInputTrack::MaxRequestedInputChannels() const {+ MOZ_ASSERT(mGraph->OnGraphThreadOrNotRunning());+ uint32_t maxInputChannels = 0;+ for (const auto& listener : mDataUsers) {+ maxInputChannels = std::max(maxInputChannels,+ listener->RequestedInputChannelCount(mGraph));+ }+ return maxInputChannels;+}++bool NativeInputTrack::HasVoiceInput() const {+ MOZ_ASSERT(mGraph->OnGraphThreadOrNotRunning());+ for (const auto& listener : mDataUsers) {+ if (listener->IsVoiceInput(mGraph)) {+ return true;+ }+ }+ return false;+}++void NativeInputTrack::ReevaluateInputDevice() {+ MOZ_ASSERT(NS_IsMainThread());+ class Message : public ControlMessage {+ public:+ explicit Message(MediaTrackGraphImpl* aGraph)+ : ControlMessage(nullptr), mGraph(aGraph) {}+ void Run() override {+ TRACE("NativeInputTrack::ReevaluateInputDevice ControlMessage");+ mGraph->ReevaluateInputDevice();+ }+ MediaTrackGraphImpl* mGraph;+ };+ mGraph->AppendMessage(MakeUnique<Message>(mGraph));+}++void NativeInputTrack::AddDataListener(AudioDataListener* aListener) {+ MOZ_ASSERT(NS_IsMainThread());++ class Message : public ControlMessage {+ public:+ Message(NativeInputTrack* aInputTrack, AudioDataListener* aListener)+ : ControlMessage(nullptr),+ mInputTrack(aInputTrack),+ mListener(aListener) {}+ void Run() override {+ TRACE("NativeInputTrack::AddDataListener ControlMessage");+ MOZ_ASSERT(!mInputTrack->mDataUsers.Contains(mListener.get()),+ "Don't add a listener twice.");+ mInputTrack->mDataUsers.AppendElement(mListener.get());+ }+ RefPtr<NativeInputTrack> mInputTrack;+ RefPtr<AudioDataListener> mListener;+ };++ mGraph->AppendMessage(MakeUnique<Message>(this, aListener));+}++void NativeInputTrack::RemoveDataListener(AudioDataListener* aListener) {+ MOZ_ASSERT(NS_IsMainThread());++ class Message : public ControlMessage {+ public:+ Message(NativeInputTrack* aInputTrack, AudioDataListener* aListener)+ : ControlMessage(nullptr),+ mInputTrack(aInputTrack),+ mListener(aListener) {}+ void Run() override {+ TRACE("NativeInputTrack::AddDataListener ControlMessage");+ DebugOnly<bool> wasPresent =+ mInputTrack->mDataUsers.RemoveElement(mListener.get());+ MOZ_ASSERT(wasPresent, "Remove an unknown listener");+ mListener->Disconnect(mInputTrack->GraphImpl());+ }+ RefPtr<NativeInputTrack> mInputTrack;+ RefPtr<AudioDataListener> mListener;+ };++ mGraph->AppendMessage(MakeUnique<Message>(this, aListener));+}+ #undef LOG_INTERNAL #undef LOG+#undef LOGE #undef TRACK_GRAPH_LOG_INTERNAL #undef TRACK_GRAPH_LOG #undef TRACK_GRAPH_LOGV
Here's the analysis of the provided code diff for security fixes: 1. Vulnerability Existed: not sure [Potential Race Condition] [dom/media/DeviceInputTrack.cpp] [Lines 45-70] [Old Code: Simple track creation and user count management] [Fixed Code: More complex audio device handling with device ID checks and user count management] The changes introduce more robust handling of audio devices and user counts, but it's unclear if this fixes a specific vulnerability or just improves general robustness. 2. Vulnerability Existed: not sure [Potential Resource Management Issue] [dom/media/DeviceInputTrack.cpp] [Lines 87-102] [Old Code: Simple user count decrement] [Fixed Code: Proper cleanup when user count reaches zero, including closing audio input and destroying track] The new code ensures proper resource cleanup when the last user disconnects, which could prevent resource leaks, but it's not clear if this was fixing an actual vulnerability. 3. Vulnerability Existed: not sure [Potential Invalid Device Access] [dom/media/DeviceInputTrack.cpp] [Lines 50-70] [Old Code: No device ID validation] [Fixed Code: Explicit check for matching device IDs] The added check for matching device IDs could prevent unauthorized access to audio devices, but it's unclear if this was fixing an actual vulnerability or just adding a safety check. The changes appear to improve the robustness of the audio device handling code, particularly around: - Device ID validation - User count management - Resource cleanup - Thread safety through message passing However, without more context about specific vulnerabilities that were being addressed, it's difficult to definitively identify security fixes versus general code improvements. The changes do appear to make the code more secure by adding proper validation and cleanup mechanisms.
If an attacker could control the contents of an iframe sandboxed with <code>allow-popups</code> but not <code>allow-scripts</code>, they were able to craft a link that, when clicked, would lead to JavaScript execution in violation of the sandbox. This vulnerability affects Firefox < 98, Firefox ESR < 91.7, and Thunderbird < 91.7.
--- /root/PatchLeaks-main/products/firefox_downloads/FIREFOX_RELEASE_97_END/firefox-FIREFOX_RELEASE_97_END/media/libwebp/src/dsp/lossless_common.h+++ /root/PatchLeaks-main/products/firefox_downloads/FIREFOX_RELEASE_98_END/firefox-FIREFOX_RELEASE_98_END/media/libwebp/src/dsp/lossless_common.h@@ -179,7 +179,7 @@ int x; \ assert(upper != NULL); \ for (x = 0; x < num_pixels; ++x) { \- const uint32_t pred = (PREDICTOR)(out[x - 1], upper + x); \+ const uint32_t pred = (PREDICTOR)(&out[x - 1], upper + x); \ out[x] = VP8LAddPixels(in[x], pred); \ } \ }
Here's the analysis of the provided code diff: Vulnerability Existed: not sure Potential Pointer Arithmetic Issue [media/libwebp/src/dsp/lossless_common.h] [Lines 179] [Old Code] `const uint32_t pred = (PREDICTOR)(out[x - 1], upper + x);` [Fixed Code] `const uint32_t pred = (PREDICTOR)(&out[x - 1], upper + x);` Additional Details: 1. The change adds an address-of operator (&) to `out[x - 1]`, suggesting the PREDICTOR macro expects a pointer rather than a direct value. 2. While this doesn't appear to be a classic security vulnerability, incorrect pointer handling could potentially lead to memory access issues or crashes. 3. Without seeing the PREDICTOR macro implementation, we can't be certain about security implications, but the fix suggests the original code might have had incorrect parameter passing.
If an attacker could control the contents of an iframe sandboxed with <code>allow-popups</code> but not <code>allow-scripts</code>, they were able to craft a link that, when clicked, would lead to JavaScript execution in violation of the sandbox. This vulnerability affects Firefox < 98, Firefox ESR < 91.7, and Thunderbird < 91.7.