commit 459880d45518445afafc1f719348b8adc175a988
parent 0f95ad06ca0c379a67165c493b2a8c36e659e814
Author: Zijie Zhao <zijie4@illinois.edu>
Date: Fri, 31 Oct 2025 05:17:53 +0000
Bug 1997216 - Fix Exception::ColumnNumber to return actual column number. r=arai,emilio
Differential Revision: https://phabricator.services.mozilla.com/D270636
Diffstat:
8 files changed, 79 insertions(+), 20 deletions(-)
diff --git a/dom/base/DOMException.cpp b/dom/base/DOMException.cpp
@@ -289,7 +289,13 @@ uint32_t Exception::LineNumber(JSContext* aCx) const {
return 0;
}
-uint32_t Exception::ColumnNumber() const { return 0; }
+uint32_t Exception::ColumnNumber(JSContext* aCx) const {
+ if (mLocation) {
+ return mLocation->GetColumnNumber(aCx);
+ }
+
+ return 0;
+}
already_AddRefed<nsIStackFrame> Exception::GetLocation() const {
nsCOMPtr<nsIStackFrame> location = mLocation;
diff --git a/dom/base/DOMException.h b/dom/base/DOMException.h
@@ -89,7 +89,7 @@ class Exception : public nsIException, public nsWrapperCache {
uint32_t LineNumber(JSContext* aCx) const;
- uint32_t ColumnNumber() const;
+ uint32_t ColumnNumber(JSContext* aCx) const;
already_AddRefed<nsIStackFrame> GetLocation() const;
diff --git a/dom/bindings/Bindings.conf b/dom/bindings/Bindings.conf
@@ -219,7 +219,7 @@ DOMInterfaces = {
},
'DOMException': {
- 'implicitJSContext': [ 'filename', 'lineNumber', 'stack' ],
+ 'implicitJSContext': [ 'filename', 'lineNumber', 'columnNumber', 'stack' ],
},
'DOMMatrixReadOnly': {
@@ -260,7 +260,7 @@ DOMInterfaces = {
'Exception': {
'headerFile': 'mozilla/dom/DOMException.h',
- 'implicitJSContext': [ '__stringifier', 'filename', 'lineNumber', 'stack' ],
+ 'implicitJSContext': [ '__stringifier', 'filename', 'lineNumber', 'columnNumber', 'stack' ],
},
'ExtendableEvent': {
diff --git a/dom/bindings/test/mochitest.toml b/dom/bindings/test/mochitest.toml
@@ -96,6 +96,8 @@ skip-if = ["!debug"]
["test_exceptionThrowing.html"]
+["test_exception_line_column.html"]
+
["test_exception_messages.html"]
["test_exception_options_from_jsimplemented.html"]
diff --git a/dom/bindings/test/test_exception_line_column.html b/dom/bindings/test/test_exception_line_column.html
@@ -0,0 +1,52 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1997216
+-->
+<head>
+ <meta charset="utf-8">
+ <title>Test for Bug 1997216</title>
+ <script src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+ <script type="application/javascript">
+
+ /** Test for Bug 1997216 */
+
+ // Test 1: DOMException from querySelector
+ try {
+ document.querySelector('###INVALID_SELECTOR###');
+ ok(false, "Should have thrown");
+ } catch (e) {
+ is(e.lineNumber, 17, "querySelector exception should be on line 17");
+ is(e.columnNumber, 14, "querySelector exception should be on column 14");
+ }
+
+ // Test 2: Manually created DOMException
+ try {
+ throw new DOMException('Test exception', 'NotFoundError');
+ } catch (e) {
+ is(e.lineNumber, 26, "Manual DOMException should be on line 26");
+ is(e.columnNumber, 11, "Manual DOMException should be on column 11");
+ }
+
+ // Test 3: DOMException from invalid appendChild
+ try {
+ document.documentElement.appendChild(null);
+ ok(false, "Should have thrown");
+ } catch (e) {
+ is(e.lineNumber, 34, "appendChild exception should be on line 34");
+ is(e.columnNumber, 30, "appendChild exception should be on column 30");
+ }
+
+ </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1997216">Mozilla Bug 1997216</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+
+</div>
+<pre id="test">
+</pre>
+</body>
+</html>
diff --git a/dom/bindings/test/test_exception_options_from_jsimplemented.html b/dom/bindings/test/test_exception_options_from_jsimplemented.html
@@ -20,7 +20,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1107592
var asyncFrame;
/* Async parent frames from pushPrefEnv don't show up in e10s. */
if (!SpecialPowers.getBoolPref("javascript.options.asyncstack_capture_debuggee_only")) {
- asyncFrame = `Async*@${file}:153:17
+ asyncFrame = `Async*@${file}:152:17
`;
} else {
asyncFrame = "";
@@ -64,8 +64,7 @@ ${asyncFrame}`,
file,
"Should still have the right file name");
is(e.lineNumber, 50, "Should still have the right line number");
- todo_isnot(e.columnNumber, 0,
- "No column number support for DOMException yet");
+ is(e.columnNumber, 9, "Should have the right column number");
}
try {
@@ -78,13 +77,13 @@ ${asyncFrame}`,
is(e.message, "We are a TypeError",
"Should also have the right message (2)");
is(e.stack,
- `doTest@${file}:72:9
+ `doTest@${file}:71:9
${asyncFrame}`,
"Exception stack for TypeError should only show our code");
is(e.fileName,
file,
"Should still have the right file name for TypeError");
- is(e.lineNumber, 72, "Should still have the right line number for TypeError");
+ is(e.lineNumber, 71, "Should still have the right line number for TypeError");
is(e.columnNumber, 9, "Should have the right column number for TypeError");
}
@@ -98,14 +97,14 @@ ${asyncFrame}`,
is(e.message, "missing argument 0 when calling function Array.prototype.forEach",
"Should also have the right message (3)");
is(e.stack,
- `doTest/<@${file}:92:61
-doTest@${file}:92:9
+ `doTest/<@${file}:91:61
+doTest@${file}:91:9
${asyncFrame}`,
"Exception stack for TypeError should only show our code (3)");
is(e.fileName,
file,
"Should still have the right file name for TypeError (3)");
- is(e.lineNumber, 92, "Should still have the right line number for TypeError (3)");
+ is(e.lineNumber, 91, "Should still have the right line number for TypeError (3)");
is(e.columnNumber, 61, "Should have the right column number for TypeError (3)");
}
@@ -118,14 +117,14 @@ ${asyncFrame}`,
is(e.name, "NS_ERROR_UNEXPECTED", "Name should be sanitized (4)");
is(e.message, "", "Message should be sanitized (5)");
is(e.stack,
- `doTest@${file}:113:9
+ `doTest@${file}:112:9
${asyncFrame}`,
"Exception stack for sanitized exception should only show our code (4)");
is(e.filename,
file,
"Should still have the right file name for sanitized exception (4)");
- is(e.lineNumber, 113, "Should still have the right line number for sanitized exception (4)");
- todo_isnot(e.columnNumber, 0, "Should have the right column number for sanitized exception (4)");
+ is(e.lineNumber, 112, "Should still have the right line number for sanitized exception (4)");
+ is(e.columnNumber, 9, "Should have the right column number for sanitized exception (4)");
}
try {
@@ -137,14 +136,14 @@ ${asyncFrame}`,
is(e.name, "NS_ERROR_UNEXPECTED", "Name should be sanitized (5)");
is(e.message, "", "Message should be sanitized (5)");
is(e.stack,
- `doTest@${file}:132:9
+ `doTest@${file}:131:9
${asyncFrame}`,
"Exception stack for sanitized exception should only show our code (5)");
is(e.filename,
file,
"Should still have the right file name for sanitized exception (5)");
- is(e.lineNumber, 132, "Should still have the right line number for sanitized exception (5)");
- todo_isnot(e.columnNumber, 0, "Should have the right column number for sanitized exception (5)");
+ is(e.lineNumber, 131, "Should still have the right line number for sanitized exception (5)");
+ is(e.columnNumber, 9, "Should have the right column number for sanitized exception (5)");
}
SimpleTest.finish();
diff --git a/js/xpconnect/src/ExecutionTracerIntegration.cpp b/js/xpconnect/src/ExecutionTracerIntegration.cpp
@@ -168,7 +168,7 @@ bool ExecutionTracerIntegration::WriteExceptionSummary(
uint32_t line = exception->LineNumber(aCx);
aWriter->writeUint32(line);
- uint32_t column = exception->ColumnNumber();
+ uint32_t column = exception->ColumnNumber(aCx);
aWriter->writeUint32(column);
nsCOMPtr<nsIStackFrame> stack = exception->GetLocation();
diff --git a/js/xpconnect/src/nsXPConnect.cpp b/js/xpconnect/src/nsXPConnect.cpp
@@ -253,7 +253,7 @@ void xpc::ErrorReport::Init(JSContext* aCx, mozilla::dom::Exception* aException,
}
mSourceId = aException->SourceId(aCx);
mLineNumber = aException->LineNumber(aCx);
- mColumn = aException->ColumnNumber();
+ mColumn = aException->ColumnNumber(aCx);
}
static LazyLogModule gJSDiagnostics("JSDiagnostics");