alhudz commented on PR #1831:
URL: https://github.com/apache/commons-lang/pull/1831#issuecomment-6360031294
Sure. Repro is a shared factory method that builds both exceptions, so the
cause and wrapper traces have the same bottom frame (`make`) and the same tail
(`run`, `main`), with a different frame in between:
```java
static RuntimeException make(String m, Throwable c) { return new
RuntimeException(m, c); }
static void viaA() { throw make("cause", null); }
static void viaB(Throwable c) { throw make("wrapper", c); }
static void run() { try { viaA(); } catch (RuntimeException e) { viaB(e); } }
```
Top to bottom, the cause trace is `make, viaA, run, main` and the wrapper
trace is `make, viaB, run, main`.
Expected, `e.printStackTrace()` on JDK 17:
```
java.lang.RuntimeException: wrapper
at Rz.make(Rz.java:3)
at Rz.viaB(Rz.java:5)
at Rz.run(Rz.java:6)
at Rz.main(Rz.java:8)
Caused by: java.lang.RuntimeException: cause
at Rz.make(Rz.java:3)
at Rz.viaA(Rz.java:4)
... 2 more
```
Actual, `ExceptionUtils.getRootCauseStackTrace(e)` on master:
```
java.lang.RuntimeException: cause
at Rz.viaA(Rz.java:4)
[wrapped] java.lang.RuntimeException: wrapper
at Rz.make(Rz.java:3)
at Rz.viaB(Rz.java:5)
at Rz.run(Rz.java:6)
at Rz.main(Rz.java:8)
```
With this PR:
```
java.lang.RuntimeException: cause
at Rz.make(Rz.java:3)
at Rz.viaA(Rz.java:4)
[wrapped] java.lang.RuntimeException: wrapper
at Rz.make(Rz.java:3)
at Rz.viaB(Rz.java:5)
at Rz.run(Rz.java:6)
at Rz.main(Rz.java:8)
```
At the list level: `removeCommonFrames([make, viaA, run, main], [make, viaB,
run, main])` leaves `[viaA]` on master and `[make, viaA]` with the PR.
On "common": I'm reading it the way the JDK does. The common frames are the
shared tail, the frames below the point where the two call paths split (`run`,
`main` here), which is exactly what `... 2 more` folds.
`Throwable.printEnclosedStackTrace` walks both traces from the bottom and stops
at the first unequal frame. Master walks from the bottom too but doesn't stop,
so after `viaA`/`viaB` differ it carries on, compares `make` with `make`, and
drops `make` from the cause even though that's the cause's own construction
frame rather than a shared one. The root cause trace then no longer says where
the root cause was created. When the shared part is a single trailing run,
which is the usual case, master and the PR print the same thing.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]