-
Notifications
You must be signed in to change notification settings - Fork 17.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
html/template: escapeTemplate causes a panic by invoking fmt.Sprintf("%v") on a context with nil *Error field #28854
Comments
The html/template error is very strange. The failing test is
Corresponding GO code:
The stack location that
I do not believe the caller passes a null Error object and I don't think there is any defect in the code being tested. Interestingly the crash only occurs on the following input, but all the other testcases must be present in order for the crash to happen. If you comment out just two other testcases, it passes. This suggests the bug is dependent on memory layout.
I think something is going wrong with stack growth. Stack growth uses tracebacks to update stack pointers. There are known issues with tracebacks so I think tracebacks may be at the root of this. |
Pinging Dr @aclements. Do you have any suggestions about how to debug this? Thank you. Alex |
I found the source of the error on Windows/ARM. The synthetic call to func exceptionhandler
...
if r.ip() != 0 {
sp := unsafe.Pointer(r.sp())
sp = add(sp, ^(unsafe.Sizeof(uintptr(0)) - 1)) // sp--
*((*uintptr)(sp)) = r.ip()
r.setsp(uintptr(sp))
} The correct code for ARM is: if r.ip() != 0 {
sp := unsafe.Pointer(r.sp())
sp = add(sp, ^(unsafe.Sizeof(uintptr(0)) - 1)) // sp--
*((*uintptr)(sp)) = r.lr() // *** LR must be saved to stack instead of PC
r.lrr = uint32(r.ip()) // *** LR must be set to faulting PC
r.setsp(uintptr(sp))
} This allows traceback to unwind the stack correctly. As for the access violation in (gdb) run -test.v -test.run TestErrors
Starting program: /home/jordanrh/work/go/template.test -test.v -test.run TestErrors
[New LWP 5828]
[New LWP 5829]
[New LWP 5830]
[New LWP 5831]
[New LWP 5832]
=== RUN TestErrors
Thread 6 "template.test" received signal SIGSEGV, Segmentation fault.
[Switching to LWP 5832]
0x000000000055bd77 in html/template.(*Error).Error (e=0x0, ~r0=...) at /home/jordanrh/go/src/html/template/error.go:218
218 case e.Node != nil:
(gdb) info registers
rax 0x0 0
rbx 0x20 32
rcx 0xc00006c600 824634164736
rdx 0xc0000fe848 824634763336
rsi 0xc0000fe848 824634763336
rdi 0xc000124260 824634917472
rbp 0xc0000fe828 0xc0000fe828
rsp 0xc0000fe790 0xc0000fe790
r8 0x20 32
r9 0xc000028f88 824633888648
r10 0x0 0
r11 0xc0000291d0 824633889232
r12 0x80 128
r13 0x40 64
r14 0x3 3
r15 0x80 128
rip 0x55bd77 0x55bd77 <html/template.(*Error).Error+55>
eflags 0x10206 [ PF IF RF ]
cs 0x33 51
ss 0x2b 43
ds 0x0 0
---Type <return> to continue, or q <return> to quit---
es 0x0 0
fs 0x0 0
gs 0x0 0
(gdb) @stjj89 @mvdan is it by design that html/template generates access violations? |
More helpful stack trace: #0 0x0000000000152d90 in html/template.(*Error).Error (e=0x0, ~r0=...) at /home/jordanrh/go/src/html/template/error.go:218
#1 0x00000000000c3864 in fmt.(*pp).handleMethods (p=0x40000920c0, verb=118, handled=true) at /home/jordanrh/go/src/fmt/print.go:608
#2 0x00000000000c3ce4 in fmt.(*pp).printArg (p=0x40000920c0, arg=..., verb=118) at /home/jordanrh/go/src/fmt/print.go:697
#3 0x00000000000c70bc in fmt.(*pp).doPrintf (p=0x40000920c0, format=..., a=...) at /home/jordanrh/go/src/fmt/print.go:1014
#4 0x00000000000c0e84 in fmt.Sprintf (format=..., a=..., ~r2=...) at /home/jordanrh/go/src/fmt/print.go:214
#5 0x000000000015186c in html/template.context.String (c=..., ~r0=...) at /home/jordanrh/go/src/html/template/context.go:29
#6 0x0000000000170920 in html/template.(*context).String (~r0=...) at <autogenerated>:1
#7 0x00000000000c3934 in fmt.(*pp).handleMethods (p=0x4000092000, verb=118, handled=true) at /home/jordanrh/go/src/fmt/print.go:614
#8 0x00000000000c3ce4 in fmt.(*pp).printArg (p=0x4000092000, arg=..., verb=118) at /home/jordanrh/go/src/fmt/print.go:697
#9 0x00000000000c70bc in fmt.(*pp).doPrintf (p=0x4000092000, format=..., a=...) at /home/jordanrh/go/src/fmt/print.go:1014
#10 0x00000000000c0e84 in fmt.Sprintf (format=..., a=..., ~r2=...) at /home/jordanrh/go/src/fmt/print.go:214
#11 0x0000000000155740 in html/template.errorf (k=<optimized out>, node=..., f=..., args=..., line=<optimized out>) at /home/jordanrh/go/src/html/template/error.go:232
#12 html/template.join (a=..., b=..., node=..., nodeName=..., ~r4=...) at /home/jordanrh/go/src/html/template/escape.go:461
#13 0x0000000000155860 in html/template.join (a=..., b=..., node=..., nodeName=..., ~r4=...) at /home/jordanrh/go/src/html/template/escape.go:454
#14 0x0000000000155c14 in html/template.(*escaper).escapeBranch (e=0x4000011040, c=..., n=0x4000011000, nodeName=..., ~r3=...) at /home/jordanrh/go/src/html/template/escape.go:484
#15 0x00000000001537ec in html/template.(*escaper).escape (e=0x4000011040, c=..., n=..., ~r2=...) at /home/jordanrh/go/src/html/template/escape.go:128
#16 0x0000000000155df8 in html/template.(*escaper).escapeList (e=0x4000011040, c=..., n=0x40000bd020, ~r2=...) at /home/jordanrh/go/src/html/template/escape.go:493
#17 0x00000000001560ac in html/template.(*escaper).escapeListConditionally (e=0x4000094298, c=..., n=0x40000bd020, filter={void (html/template.escaper *, html/template.context, bool *)} 0x40000b76a8, ~r3=..., ~r4=<optimized out>)
at /home/jordanrh/go/src/html/template/escape.go:508
#18 0x0000000000157004 in html/template.(*escaper).escapeTemplateBody (e=0x4000094298, c=..., t=0x4000010f80, ~r2=..., ~r3=<optimized out>) at /home/jordanrh/go/src/html/template/escape.go:626
#19 0x0000000000156d34 in html/template.(*escaper).computeOutCtx (e=0x4000094298, c=..., t=0x4000010f80, ~r2=...) at /home/jordanrh/go/src/html/template/escape.go:587
#20 0x0000000000156788 in html/template.(*escaper).escapeTree (e=0x4000094298, c=..., node=..., name=..., line=0, ~r4=..., ~r5=...) at /home/jordanrh/go/src/html/template/escape.go:580
#21 0x00000000001530ac in html/template.escapeTemplate (tmpl=0x40000bcfc0, node=..., name=..., ~r3=...) at /home/jordanrh/go/src/html/template/escape.go:22
#22 0x000000000015b2e8 in html/template.(*Template).escape (t=0x40000bcfc0, ~r0=...) at /home/jordanrh/go/src/text/template/template.go:47
#23 0x000000000015b428 in html/template.(*Template).Execute (t=0x40000bcfc0, wr=..., data=..., ~r2=...) at /home/jordanrh/go/src/html/template/template.go:119
#24 0x0000000000167a14 in html/template.TestErrors (t=0x40000a6100) at /home/jordanrh/go/src/html/template/escape_test.go:1069
#25 0x00000000000e2eb0 in testing.tRunner (t=0x40000a6100, fn={void (testing.T *)} 0x40000b7fd0) at /home/jordanrh/go/src/testing/testing.go:862
#26 0x00000000000659e4 in runtime.goexit () at /home/jordanrh/go/src/runtime/asm_arm64.s:1128
Backtrace stopped: previous frame identical to this frame (corrupt stack?) |
Change https://golang.org/cl/150957 mentions this issue: |
The exception handler modifies the stack and continuation context so it looks like the faulting code calls sigpanic() directly. The call was not set up correctly on ARM, because it did not handle the link register correctly. This change handles the link register correctly for ARM. Updates #28854 Change-Id: I7ccf838adfc05cd968a5edd7d19ebba6a2478360 Reviewed-on: https://go-review.googlesource.com/c/150957 Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> Reviewed-by: Austin Clements <austin@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org>
I believe the problem is that context.String prints context.err using the The proper fix should be to add a nil-receiver switch case to (*Error).Error, since it is the Error's responsibility to print itself properly even if it is I don't really understand why this error has gone undetected so long on linux builds. Any clue what is masking this issue on standard |
It looks like there's code in fmt/print to recover from panics: // If a string is acceptable according to the format, see if
// the value satisfies one of the string-valued interfaces.
// Println etc. set verb to %v, which is "stringable".
switch verb {
case 'v', 's', 'x', 'X', 'q':
// Is it an error or Stringer?
// The duplication in the bodies is necessary:
// setting handled and deferring catchPanic
// must happen before calling the method.
switch v := p.arg.(type) {
case error:
handled = true
defer p.catchPanic(p.arg, verb)
p.fmtString(v.Error(), verb)
return
case Stringer:
handled = true
defer p.catchPanic(p.arg, verb)
p.fmtString(v.String(), verb)
return
}
} |
Change https://golang.org/cl/151501 mentions this issue: |
@alexbrainman Since this issue is fixed can it be closed? I'm working on resolving the remaining test failures. I will use #26148. |
I think this issue became about fixing bug in html/template package now. The issue will get closed once https://go-review.googlesource.com/c/go/+/151501 is submitted (CL 151501 mentions this issue in its commit message).
SGTM. Alex |
I've updated the issue title and labels to reflect that. The specific line the issue title refers to is: go/src/html/template/escape.go Line 27 in 0456036
go/src/html/template/context.go Lines 28 to 30 in 0456036
|
Thanks everyone for working on the previous issues and CLs and finally boiling this issue down to html/template -- I have unassigned you @jordanrh1 as it is no longer a Windows issue. |
Change https://golang.org/cl/181579 mentions this issue: |
windows-arm build is broken
https://build.golang.org/log/18c3850b705ffd52fbb0caacb3d2a89aacfaf456
@jordanrh1 please fix the breakage. According to https://github.com/golang/go/wiki/PortingPolicy
We did not have windows-arm builder pass complete build yet. Unfortunately I do not have time to debug this.
Thank you.
Alex
The text was updated successfully, but these errors were encountered: