Skip to content
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

fix: panic caused by uintptr #60

Closed
wants to merge 1 commit into from
Closed

Conversation

jxskiss
Copy link

@jxskiss jxskiss commented Oct 29, 2018

When I used this library on windows, ReadHeader returns full zero Header after about 3-5 calls, and sometimes the program panic. After some debug I found it's caused by the usage of uintptr.

According to doc of unsafe.Pointer, most of the previous uintptr usage are incorrect. This PR fixes the issue.

Change-Id: Iddd9c07d7c1c1d3f1cf5239b6524e9399b49725d

Change-Id: Iddd9c07d7c1c1d3f1cf5239b6524e9399b49725d
@jxskiss
Copy link
Author

jxskiss commented Oct 29, 2018

FYI: the panic logs

2018/10/29 00:44:20 connection.ping: uid= 0YP62KHlVrCntuDG3T9T
2018/10/29 00:44:20 connection.processFrame: header= {false 0 0 false [0 0 0 0] 0}
2018/10/29 00:44:20 connection.processFrame: check header: frames from client to server must be masked
2018/10/29 00:44:22 connhub.closer: closing 1 connections
runtime: pointer 0xc00038bc74 to unallocated span span.base()=0xc00038a000 span.limit=0xc000188000 span.state=3
runtime: found in object at *(0xc000308580+0x68)
object=0xc000308580 s.base()=0xc000308000 s.limit=0xc000309e40 s.spanclass=56 s.elemsize=704 s.state=_MSpanInUse
*(object+0) = 0x1
*(object+8) = 0x0
*(object+16) = 0xffffffffffffffff
*(object+24) = 0x0
*(object+32) = 0x2
*(object+40) = 0x0
*(object+48) = 0x0
*(object+56) = 0x34207b8
*(object+64) = 0x72
*(object+72) = 0x2
*(object+80) = 0xc000308580
*(object+88) = 0x0
*(object+96) = 0x2
*(object+104) = 0xc00038bc74 <==
*(object+112) = 0x0
*(object+120) = 0x0
*(object+128) = 0x0
*(object+136) = 0x0
*(object+144) = 0x0
*(object+152) = 0x0
*(object+160) = 0x0
*(object+168) = 0x0
*(object+176) = 0x0
*(object+184) = 0x0
*(object+192) = 0x0
*(object+200) = 0x0
*(object+208) = 0x0
*(object+216) = 0x0
*(object+224) = 0x0
*(object+232) = 0x0
*(object+240) = 0x0
*(object+248) = 0x2
*(object+256) = 0x0
*(object+264) = 0x0
*(object+272) = 0x34207b8
*(object+280) = 0x77
*(object+288) = 0x2
*(object+296) = 0xc000308580
*(object+304) = 0x0
*(object+312) = 0x2
*(object+320) = 0xc00006c6c0
*(object+328) = 0x0
*(object+336) = 0x0
*(object+344) = 0x0
*(object+352) = 0x0
*(object+360) = 0x0
*(object+368) = 0x0
*(object+376) = 0x0
*(object+384) = 0x0
*(object+392) = 0x0
*(object+400) = 0x0
*(object+408) = 0x0
*(object+416) = 0x0
*(object+424) = 0x0
*(object+432) = 0x0
*(object+440) = 0x0
*(object+448) = 0x0
*(object+456) = 0x0
*(object+464) = 0x0
*(object+472) = 0x0
*(object+480) = 0x0
*(object+488) = 0x0
*(object+496) = 0x0
*(object+504) = 0x0
*(object+512) = 0x0
*(object+520) = 0x0
*(object+528) = 0x0
*(object+536) = 0x0
*(object+544) = 0x0
*(object+552) = 0x0
*(object+560) = 0x1010100000000
*(object+568) = 0x0
*(object+576) = 0x17
*(object+584) = 0x1
*(object+592) = 0x0
*(object+600) = 0x9ed76e
*(object+608) = 0x3
*(object+616) = 0xa82ac0
*(object+624) = 0xc0002b09c0
*(object+632) = 0xa82ac0
*(object+640) = 0xc0002b09f0
*(object+648) = 0x0
*(object+656) = 0x0
*(object+664) = 0x0
*(object+672) = 0x0
*(object+680) = 0x0
*(object+688) = 0x0
*(object+696) = 0x0
fatal error: found bad pointer in Go heap (incorrect use of unsafe or cgo?)

runtime stack:
runtime.throw(0xa0e325, 0x3e)
...... // many stacktrace info

@gobwas
Copy link
Owner

gobwas commented Oct 30, 2018

@jxskiss hi. Could you please provide more info on how pointers are used incorrectly? The lot of changes you provide simply bring in performance degradation and thats all.

@gobwas
Copy link
Owner

gobwas commented Oct 30, 2018

Also could you paste more stack trace? How can I reproduce this?

@jxskiss
Copy link
Author

jxskiss commented Oct 31, 2018

@jxskiss hi. Could you please provide more info on how pointers are used incorrectly? The lot of changes you provide simply bring in performance degradation and thats all.

Hi, nice to talk about this.

First thing, from unsafe.Pointer doc, uintptr cannot be stored in variable.

// (3) Conversion of a Pointer to a uintptr and back, with arithmetic.
//
// If p points into an allocated object, it can be advanced through the object
// by conversion to uintptr, addition of an offset, and conversion back to Pointer.
//
// p = unsafe.Pointer(uintptr(p) + offset)
//
// The most common use of this pattern is to access fields in a struct
// or elements of an array:
//
// // equivalent to f := unsafe.Pointer(&s.f)
// f := unsafe.Pointer(uintptr(unsafe.Pointer(&s)) + unsafe.Offsetof(s.f))
//
// // equivalent to e := unsafe.Pointer(&x[i])
// e := unsafe.Pointer(uintptr(unsafe.Pointer(&x[0])) + i*unsafe.Sizeof(x[0]))
//
// It is valid both to add and to subtract offsets from a pointer in this way.
// It is also valid to use &^ to round pointers, usually for alignment.
// In all cases, the result must continue to point into the original allocated object.
//
// ... // other docs
//
// Note that both conversions must appear in the same expression, with only
// the intervening arithmetic between them:
//
// // INVALID: uintptr cannot be stored in variable
// // before conversion back to Pointer.
// u := uintptr(p)
// p = unsafe.Pointer(u + offset)

thus, the uintptr variable usage is considered invalid, and is problematic to cause panic.

Another thing, in the PR, I keeped the bytes allocated as fixed length array, which I think will
still make the allocation stack-based and will not bring performance degradation. Also the usages
of b[:] is just reslice of an allocated slice, it does not allocate new memory.

As a reference, there's an post explaining Golang's memory allocation:
https://segment.com/blog/allocation-efficiency-in-high-performance-go-services/

@jxskiss
Copy link
Author

jxskiss commented Oct 31, 2018

Also could you paste more stack trace? How can I reproduce this?

The massive stack trace logs does not provide much helpful info, so I did not post them. Regard of reproducing the issue, I will try to make an minimal example :-)

@gobwas
Copy link
Owner

gobwas commented Oct 31, 2018

Hi @jxskiss.
Thank you for sharing the docs with me. =)

First, few sentences above your cite:

Conversion of a uintptr back to Pointer is not valid in general.
A uintptr is an integer, not a reference. Converting a Pointer to a uintptr creates an integer value with no pointer semantics. Even if a uintptr holds the address of some object, the garbage collector will not update that uintptr's value if the object moves, nor will that uintptr keep the object from being reclaimed.

I agree, in general it is not valid, but how the stack may be moved while running Cipher()? Or, in more general, how that saved uintptr may become invalid while masking?

Another thing, in the PR, I keeped the bytes allocated as fixed length array, which I think will
still make the allocation stack-based and will not bring performance degradation. Also the usages
of b[:] is just reslice of an allocated slice, it does not allocate new memory.

It does allocate new memory. When you passing stack-allocated array via [:] it creates slice header that points to the stack and everything looks like you saying. But, when you passing that slice to some interface method, compiler does not know which implementation what will do with it, thus it escapes to heap. If you make slice with unsafe, escape skips it. It pretty much the same as noescape helper in the standard library.

Currently I may agree only with cipher.go:45 changes, if it provable.
We can also try to add //go:nosplit before Cipher() to check stack growth.
Then, the question may arise for func (nonce) bytes() – if it is not inlined, it may theoretically return slice that points to the trashed stack. We may check it.

Again, we need to reproduce this to get an ideas of how to solve the problem.

@jxskiss
Copy link
Author

jxskiss commented Nov 1, 2018

Well, I failed to construct a minimal example reproduce the problem. And for some reason, I can't publish the code which can easily trigger the issue (it's a lot of code running many goroutines).

But I have found an old thread which may explain the issue: https://groups.google.com/d/msg/golang-nuts/W_Up0e4TOfs/bt9UjGCXyk4J

The problem was observed in ws.ReadHeader first as the log showed in previous post, I guess it is related to Go's runtime behavior.

And after removing the uintptr usage within read.go my program works just as expected.

Update: consider the memory allocation, you are right, pass a slice to another function will make the slice escapes to heap, I confirmed this using go build -gcflags '-m -m'. But is it un-avoidable to make the program work correctly?

@gobwas
Copy link
Owner

gobwas commented Nov 1, 2018

Thank you for the link. As an experiment, could you put //go:nosplit before ReadHeader() declaration? Will panics be reproduced?

@jxskiss
Copy link
Author

jxskiss commented Nov 1, 2018

Thank you for the link. As an experiment, could you put //go:nosplit before ReadHeader() declaration? Will panics be reproduced?

Hi, @gobwas , I have tried nosplit, the zero-value header and panic is still there (the zero-value header happens more often than panic). The stacktrace is basically same with previous post:

runtime: pointer 0xc00078fc24 to unused region of span span.base()=0xc0001be000 span.limit=0xc0001bffa0 span.state=1
runtime: found in object at *(0xc000313340+0x68)
object=0xc000313340 s.base()=0xc000312000 s.limit=0xc000313e40 s.spanclass=56 s.elemsize=704 s.state=_MSpanInUse
 *(object+0) = 0x1
 *(object+8) = 0x0
 *(object+16) = 0xffffffffffffffff
 *(object+24) = 0x0
 *(object+32) = 0x2
 *(object+40) = 0x0
 *(object+48) = 0x0
 *(object+56) = 0x55504c0
 *(object+64) = 0x72
 *(object+72) = 0x2
 *(object+80) = 0xc000313340
 *(object+88) = 0x0
 *(object+96) = 0x2
 *(object+104) = 0xc00078fc24 <==
 *(object+112) = 0x0
 *(object+120) = 0x0
 *(object+128) = 0x0
 *(object+136) = 0x0
 *(object+144) = 0x0
 *(object+152) = 0x0
 *(object+160) = 0x0
 *(object+168) = 0x0
 *(object+176) = 0x0
 *(object+184) = 0x0
 *(object+192) = 0x0
 *(object+200) = 0x0
 *(object+208) = 0x0
 *(object+216) = 0x0
 *(object+224) = 0x0
 *(object+232) = 0x0
 *(object+240) = 0x0
 *(object+248) = 0x2
 *(object+256) = 0x0
 *(object+264) = 0x0
 *(object+272) = 0x55504c0
 *(object+280) = 0x77
 *(object+288) = 0x2
 *(object+296) = 0xc000313340
 *(object+304) = 0x0
 *(object+312) = 0x2
 *(object+320) = 0xc000110350
 *(object+328) = 0x0
 *(object+336) = 0x0
 *(object+344) = 0x0
 *(object+352) = 0x0
 *(object+360) = 0x0
 *(object+368) = 0x0
 *(object+376) = 0x0
 *(object+384) = 0x0
 *(object+392) = 0x0
 *(object+400) = 0x0
 *(object+408) = 0x0
 *(object+416) = 0x0
 *(object+424) = 0x0
 *(object+432) = 0x0
 *(object+440) = 0x0
 *(object+448) = 0x0
 *(object+456) = 0x0
 *(object+464) = 0x0
 *(object+472) = 0x0
 *(object+480) = 0x0
 *(object+488) = 0x0
 *(object+496) = 0x0
 *(object+504) = 0x0
 *(object+512) = 0x0
 *(object+520) = 0x0
 *(object+528) = 0x0
 *(object+536) = 0x0
 *(object+544) = 0x0
 *(object+552) = 0x0
 *(object+560) = 0x1010100000000
 *(object+568) = 0x0
 *(object+576) = 0x2
 *(object+584) = 0x1
 *(object+592) = 0x0
 *(object+600) = 0x9ecdce
 *(object+608) = 0x3
 *(object+616) = 0xa81ee0
 *(object+624) = 0xc0006d24e0
 *(object+632) = 0xa81ee0
 *(object+640) = 0xc0006d2510
 *(object+648) = 0x0
 *(object+656) = 0x0
 *(object+664) = 0x0
 *(object+672) = 0x0
 *(object+680) = 0x0
 *(object+688) = 0x0
 *(object+696) = 0x0
fatal error: found bad pointer in Go heap (incorrect use of unsafe or cgo?)

runtime stack:
runtime.throw(0xa0d919, 0x3e)
	D:/devel/golang/src/runtime/panic.go:608 +0x79 fp=0x59cfdb8 sp=0x59cfd88 pc=0x42ee29
runtime.findObject(0xc00078fc24, 0xc000313340, 0x68, 0x3760be0, 0xc00002f270, 0x7)
	D:/devel/golang/src/runtime/mbitmap.go:399 +0x3dd fp=0x59cfe08 sp=0x59cfdb8 pc=0x41455d
runtime.scanobject(0xc000313340, 0xc00002f270)
	D:/devel/golang/src/runtime/mgcmark.go:1150 +0x24e fp=0x59cfe98 sp=0x59cfe08 pc=0x41f9fe
runtime.gcDrain(0xc00002f270, 0x5)
	D:/devel/golang/src/runtime/mgcmark.go:913 +0x24c fp=0x59cfef0 sp=0x59cfe98 pc=0x41f21c
runtime.gcBgMarkWorker.func2()
	D:/devel/golang/src/runtime/mgc.go:1839 +0x87 fp=0x59cff30 sp=0x59cfef0 pc=0x458397
runtime.systemstack(0x0)
	D:/devel/golang/src/runtime/asm_amd64.s:351 +0x6b fp=0x59cff38 sp=0x59cff30 pc=0x45a8fb
runtime.mstart()
	D:/devel/golang/src/runtime/proc.go:1229 fp=0x59cff40 sp=0x59cff38 pc=0x4336a0

goroutine 54 [GC worker (idle)]:
runtime.systemstack_switch()
	D:/devel/golang/src/runtime/asm_amd64.s:311 fp=0xc0004abf60 sp=0xc0004abf58 pc=0x45a880
runtime.gcBgMarkWorker(0xc00002e000)
	D:/devel/golang/src/runtime/mgc.go:1826 +0x1d4 fp=0xc0004abfd8 sp=0xc0004abf60 pc=0x41bd54
runtime.goexit()
	D:/devel/golang/src/runtime/asm_amd64.s:1333 +0x1 fp=0xc0004abfe0 sp=0xc0004abfd8 pc=0x45c871
created by runtime.gcBgMarkStartWorkers
	D:/devel/golang/src/runtime/mgc.go:1720 +0x7e

goroutine 1 [chan receive, 8 minutes]:
runtime.gopark(0xa17ca0, 0xc0002f2118, 0xc00003170d, 0x3)
	D:/devel/golang/src/runtime/proc.go:302 +0x100 fp=0xc00047bd50 sp=0xc00047bd30 pc=0x430ba0
runtime.goparkunlock(0xc0002f2118, 0x170d, 0x3)
	D:/devel/golang/src/runtime/proc.go:308 +0x5a fp=0xc00047bd80 sp=0xc00047bd50 pc=0x430c5a
runtime.chanrecv(0xc0002f20c0, 0x0, 0x939401, 0x8b72b2)
	D:/devel/golang/src/runtime/chan.go:520 +0x2cc fp=0xc00047be10 sp=0xc00047bd80 pc=0x40591c
runtime.chanrecv1(0xc0002f20c0, 0x0)
	D:/devel/golang/src/runtime/chan.go:402 +0x2b fp=0xc00047be40 sp=0xc00047be10 pc=0x4055fb
main.main()
	E:/workspace/gohome/src/github.com/jxskiss/wsgateway/cmd/comet/main.go:118 +0x7a2 fp=0xc00047bf98 sp=0xc00047be40 pc=0x8b72e2
runtime.main()
	D:/devel/golang/src/runtime/proc.go:201 +0x207 fp=0xc00047bfe0 sp=0xc00047bf98 pc=0x4307c7
runtime.goexit()
	D:/devel/golang/src/runtime/asm_amd64.s:1333 +0x1 fp=0xc00047bfe8 sp=0xc00047bfe0 pc=0x45c871

goroutine 2 [force gc (idle), 2 minutes]:
runtime.gopark(0xa17ca0, 0xe5df50, 0x451410, 0x1)
	D:/devel/golang/src/runtime/proc.go:302 +0x100 fp=0xc00004bf80 sp=0xc00004bf60 pc=0x430ba0
runtime.goparkunlock(0xe5df50, 0x1410, 0x1)
	D:/devel/golang/src/runtime/proc.go:308 +0x5a fp=0xc00004bfb0 sp=0xc00004bf80 pc=0x430c5a
runtime.forcegchelper()
	D:/devel/golang/src/runtime/proc.go:251 +0xc1 fp=0xc00004bfe0 sp=0xc00004bfb0 pc=0x430a01
runtime.goexit()
	D:/devel/golang/src/runtime/asm_amd64.s:1333 +0x1 fp=0xc00004bfe8 sp=0xc00004bfe0 pc=0x45c871
created by runtime.init.4
	D:/devel/golang/src/runtime/proc.go:240 +0x3c

goroutine 3 [GC sweep wait]:
runtime.gopark(0xa17ca0, 0xe5e660, 0x45140c, 0x1)
	D:/devel/golang/src/runtime/proc.go:302 +0x100 fp=0xc00004df80 sp=0xc00004df60 pc=0x430ba0
runtime.goparkunlock(0xe5e660, 0xa7140c, 0x1)
	D:/devel/golang/src/runtime/proc.go:308 +0x5a fp=0xc00004dfb0 sp=0xc00004df80 pc=0x430c5a
runtime.bgsweep(0xc000026070)
	D:/devel/golang/src/runtime/mgcsweep.go:71 +0x110 fp=0xc00004dfd8 sp=0xc00004dfb0 pc=0x420c50
runtime.goexit()
	D:/devel/golang/src/runtime/asm_amd64.s:1333 +0x1 fp=0xc00004dfe0 sp=0xc00004dfd8 pc=0x45c871
created by runtime.gcenable
	D:/devel/golang/src/runtime/mgc.go:216 +0x5f

goroutine 18 [finalizer wait, 8 minutes]:
runtime.gopark(0xa17ca0, 0xe7ca10, 0xc00002140f, 0x1)
	D:/devel/golang/src/runtime/proc.go:302 +0x100 fp=0xc00004ff28 sp=0xc00004ff08 pc=0x430ba0
runtime.goparkunlock(0xe7ca10, 0x140f, 0x1)
	D:/devel/golang/src/runtime/proc.go:308 +0x5a fp=0xc00004ff58 sp=0xc00004ff28 pc=0x430c5a
runtime.runfinq()
	D:/devel/golang/src/runtime/mfinal.go:175 +0xa7 fp=0xc00004ffe0 sp=0xc00004ff58 pc=0x4182b7
runtime.goexit()
	D:/devel/golang/src/runtime/asm_amd64.s:1333 +0x1 fp=0xc00004ffe8 sp=0xc00004ffe0 pc=0x45c871
created by runtime.createfing
	D:/devel/golang/src/runtime/mfinal.go:156 +0x68

goroutine 4 [syscall]:
runtime.notetsleepg(0xe63000, 0x3b987d54, 0x0)
	D:/devel/golang/src/runtime/lock_sema.go:280 +0x52 fp=0xc000107f58 sp=0xc000107f18 pc=0x40b232
runtime.timerproc(0xe62fe0)
	D:/devel/golang/src/runtime/time.go:288 +0x31c fp=0xc000107fd8 sp=0xc000107f58 pc=0x44c7cc
runtime.goexit()
	D:/devel/golang/src/runtime/asm_amd64.s:1333 +0x1 fp=0xc000107fe0 sp=0xc000107fd8 pc=0x45c871
created by runtime.(*timersBucket).addtimerLocked
	D:/devel/golang/src/runtime/time.go:170 +0x11b

// ....... many other goroutine info

@jxskiss
Copy link
Author

jxskiss commented Nov 1, 2018

The program is briefly like following (it did not reproduce the problem):

package main

import (
	"github.com/gobwas/ws"
	"github.com/gobwas/ws/wsutil"
	"io"
	"log"
	"net"
	"sync"
	"sync/atomic"
	"time"
)

var (
	counter int64
	pingCh  chan *connWrapper

	mu  sync.Mutex
	hub map[int64]*connWrapper
)

func init() {
	pingCh = make(chan *connWrapper, 100)
	hub = make(map[int64]*connWrapper)

	for i := 0; i < 10; i++ {
		go ping()
	}

	go func() {
		ticker := time.NewTicker(30 * time.Second)
		for range ticker.C {
			mu.Lock()
			for _, cc := range hub {
				pingCh <- cc
			}
			mu.Unlock()
		}
	}()
}

func main() {
	// run some dummy goroutines
	for i := 0; i < 100; i++ {
		go func() {
			for {
				time.Sleep(time.Second)
			}
		}()
	}

	svr := NewWebSocketServer()
	log.Fatalln(svr.ListenAndServe())
}

type WebsocketServer struct {
	ln net.Listener
}

func NewWebSocketServer() *WebsocketServer {
	return &WebsocketServer{}
}

func (s *WebsocketServer) ListenAndServe() error {
	ln, err := net.Listen("tcp", "127.0.0.1:8888")
	if err != nil {
		log.Fatalln("error listen socket:", err)
	}
	s.ln = ln

	for {
		conn, err := s.ln.Accept()
		if err != nil {
			return err
		}
		go handle(conn)
	}
}

func ping() {
	for cc := range pingCh {
		log.Println("ping: id=", cc.id)
		cc.io.Lock()
		_, err := cc.Write(ws.CompiledPing)
		cc.io.Unlock()
		if err != nil {
			log.Println("ping error:", err)
			cc.Close()
		}
	}
}

func handle(conn net.Conn) {
	cc := &connWrapper{
		id:   atomic.AddInt64(&counter, 1),
		Conn: conn,
		ctl: wsutil.ControlHandler{
			Src:   conn,
			Dst:   conn,
			State: ws.StateServerSide,
		},
	}
	_, err := ws.Upgrade(cc)
	if err != nil {
		log.Println("upgrade error:", err)
		cc.Conn.Close()
		return
	}

	mu.Lock()
	hub[cc.id] = cc
	mu.Unlock()
	for {
		err := cc.Receive()
		if err != nil {
			log.Println("receive error:", err)
			cc.Close()
			return
		}
	}
}

type connWrapper struct {
	id int64

	io sync.Mutex
	net.Conn

	ctl wsutil.ControlHandler
}

func (c *connWrapper) Receive() error {
	header, err := ws.ReadHeader(c)
	log.Println("receive: header=", header)
	if err != nil {
		return err
	}
	if err := ws.CheckHeader(header, ws.StateServerSide); err != nil {
		return err
	}

	c.io.Lock()
	defer c.io.Unlock()

	if header.OpCode.IsControl() {
		return c.ctl.Handle(header)
	}

	payload := make([]byte, header.Length)
	if _, err := io.ReadFull(c, payload); err != nil {
		return err
	}
	resp := ws.NewFrame(header.OpCode, true, payload)
	if err := ws.WriteFrame(c, resp); err != nil {
		return err
	}
	return nil
}

func (c *connWrapper) Close() error {
	mu.Lock()
	delete(hub, c.id)
	mu.Unlock()
	return c.Conn.Close()
}

@gobwas
Copy link
Owner

gobwas commented Nov 1, 2018

Hi @jxskiss. Am I right, that the failed experiment with //go:nosplit means that stack is not copied during the ReadHeader() call?

Do you really check errors returned by ReadHeader()? I mean, empty header may also be result of receiving io.EOF when connection is closed.

@gobwas
Copy link
Owner

gobwas commented Nov 1, 2018

By the way, for the clear experiment, //go:nosplit must be set to the WriteHeader() as well as for all funcs that use unsafe.

@jxskiss
Copy link
Author

jxskiss commented Nov 2, 2018

Do you really check errors returned by ReadHeader()? I mean, empty header may also be result of receiving io.EOF when connection is closed.

Yes, I do checked errors from ReadHeader().

By the way, for the clear experiment, //go:nosplit must be set to the WriteHeader() as well as for all funcs that use unsafe.

Have tried this but no lucky. And this time it fails after about 5 minutes, the complete log size is small, so I will post them below, hope that helps.

diff --git a/cipher.go b/cipher.go
index 6620254..f50bfcb 100644
--- a/cipher.go
+++ b/cipher.go
@@ -2,6 +2,8 @@ package ws
 
 import "unsafe"
 
+//go:nosplit
+
 // Cipher applies XOR cipher to the payload using mask.
 // Offset is used to cipher chunked data (e.g. in io.Reader implementations).
 //
diff --git a/nonce.go b/nonce.go
index 114e0cb..00b1b92 100644
--- a/nonce.go
+++ b/nonce.go
@@ -38,9 +38,10 @@ var sha1Pool sync.Pool
 type nonce [nonceSize]byte
 
 func (n *nonce) bytes() []byte {
-	h := uintptr(unsafe.Pointer(n))
-	b := &reflect.SliceHeader{Data: h, Len: nonceSize, Cap: nonceSize}
-	return *(*[]byte)(unsafe.Pointer(b))
+	//h := uintptr(unsafe.Pointer(n))
+	//b := &reflect.SliceHeader{Data: h, Len: nonceSize, Cap: nonceSize}
+	//return *(*[]byte)(unsafe.Pointer(b))
+	return n[:]
 }
 
 func acquireSha1() hash.Hash {
diff --git a/read.go b/read.go
index 2ea33fe..c96c3bb 100644
--- a/read.go
+++ b/read.go
@@ -14,6 +14,8 @@ var (
 	ErrHeaderLengthUnexpected = fmt.Errorf("header error: unexpected payload length bits")
 )
 
+//go:nosplit
+
 // ReadHeader reads a frame header from r.
 func ReadHeader(r io.Reader) (h Header, err error) {
 	// Make slice of bytes with capacity 12 that could hold any header.
diff --git a/util.go b/util.go
index f86cd24..5075149 100644
--- a/util.go
+++ b/util.go
@@ -198,6 +198,8 @@ func readLine(br *bufio.Reader) ([]byte, error) {
 	}
 }
 
+//go:nosplit
+
 // strEqualFold checks s to be case insensitive equal to p.
 // Note that p must be only ascii letters. That is, every byte in p belongs to
 // range ['a','z'] or ['A','Z'].
@@ -236,6 +238,8 @@ func strEqualFold(s, p string) bool {
 	return true
 }
 
+//go:nosplit
+
 // btsEqualFold checks s to be case insensitive equal to p.
 // Note that p must be only ascii letters. That is, every byte in p belongs to
 // range ['a','z'] or ['A','Z'].
diff --git a/write.go b/write.go
index 83142a5..950c2dd 100644
--- a/write.go
+++ b/write.go
@@ -47,6 +47,8 @@ func HeaderSize(h Header) (n int) {
 	return n
 }
 
+//go:nosplit
+
 // WriteHeader writes header binary representation into w.
 func WriteHeader(w io.Writer, h Header) error {
 	// Make slice of bytes with capacity 14 that could hold any header.
2018/11/02 08:47:47 starting pprof server on: :12345
2018/11/02 08:47:47 starting rpc server on: 127.0.0.1:3334
2018/11/02 08:47:47 starting websocket server on: 127.0.0.1:3333
2018/11/02 08:47:47 starting http server on: 127.0.0.1:8888

(ps: from browser, make connections, it's a chat server modified from ws-examples)

2018/11/02 08:47:55 passport.auth: params= {{1 1 123123123 345 0 1541120275} map[]}
2018/11/02 08:47:55 backend.rpc.auth: user_id= 1
2018/11/02 08:47:55 handle_token: params= product_id:1 app_id:1 client_version:123123123 device_id:345 user_id:1 expire_at:1541120275 
2018/11/02 08:47:55 onRequest req: /ws?tok=nXHycC5vchEeNpdSQWHG6HQFDE6-SzK50kS__m4-zGvLFgLM2HrSH1737zLeJJFswgjdLAAAAAA&a=1&b=2&c=3
2018/11/02 08:47:55 validate_token: token= nXHycC5vchEeNpdSQWHG6HQFDE6-SzK50kS__m4-zGvLFgLM2HrSH1737zLeJJFswgjdLAAAAAA address= 127.0.0.1:50677
2018/11/02 08:47:55 onRequest conn: 0Yime86JI6RNNTGHye5p
2018/11/02 08:47:55 127.0.0.1:3333 > 127.0.0.1:50677: established websocket connection: {Protocol:v1.json Extensions:[]}
2018/11/02 08:47:55 connhub.touch: conn.uid= 0Yime86JI6RNNTGHye5p hashshard= 601
2018/11/02 08:47:55 websocket.handle: c.meta= 0Yime86JI6RNNTGHye5p
2018/11/02 08:47:55 eventbus.flush: len(events)= 1
2018/11/02 08:47:55 center.register: uid= 0Yime86JI6RNNTGHye5p
2018/11/02 08:47:55 backend.rpc.on_events, register user: 0Yime86JI6RNNTGHye5p
2018/11/02 08:47:55 chat.register: meta: {1 1 {1 345 0Yime86JI6RNNTGHye5p 123123123 127.0.0.1:50677 map[b:2 c:3 a:1] map[]}}
2018/11/02 08:47:55 rpc.push: uids= [0Yime86JI6RNNTGHye5p]
2018/11/02 08:47:55 connhub.get: uid= 0Yime86JI6RNNTGHye5p hashshard= 601
2018/11/02 08:47:55 connection.send: uid= 0Yime86JI6RNNTGHye5p
2018/11/02 08:47:55 connhub.touch: conn.uid= 0Yime86JI6RNNTGHye5p hashshard= 601
2018/11/02 08:47:55 chat.writer: push message: uids= [0Yime86JI6RNNTGHye5p]
2018/11/02 08:47:55 connhub.get: uid= 0Yime86JI6RNNTGHye5p hashshard= 601
2018/11/02 08:47:55 rpc.push: uids= [0Yime86JI6RNNTGHye5p]
2018/11/02 08:47:55 connhub.get: uid= 0Yime86JI6RNNTGHye5p hashshard= 601
2018/11/02 08:47:55 connection.send: uid= 0Yime86JI6RNNTGHye5p
2018/11/02 08:47:55 eventbus.flush: len(events)= 1
2018/11/02 08:47:55 center.register: uid= 0Yime86JI6RNNTGHye5p
2018/11/02 08:47:55 backend.rpc.on_events, register user: 0Yime86JI6RNNTGHye5p
2018/11/02 08:47:55 connhub.get: uid= 0Yime86JI6RNNTGHye5p hashshard= 601
2018/11/02 08:47:57 passport.auth: params= {{1 1 123123123 345 0 1541120277} map[]}
2018/11/02 08:47:57 backend.rpc.auth: user_id= 2
2018/11/02 08:47:57 handle_token: params= product_id:1 app_id:1 client_version:123123123 device_id:345 user_id:2 expire_at:1541120277 
2018/11/02 08:47:57 onRequest req: /ws?tok=mL3KAWV2d8-vLMVDhvzTstESQ0CqzjzgZkZkofSScTrD69YUWD5AmxDQC7uLddOwfKAyEQAAAAA&a=1&b=2&c=3
2018/11/02 08:47:57 validate_token: token= mL3KAWV2d8-vLMVDhvzTstESQ0CqzjzgZkZkofSScTrD69YUWD5AmxDQC7uLddOwfKAyEQAAAAA address= 127.0.0.1:50683
2018/11/02 08:47:57 onRequest conn: 0YimeX3VxJOXtKWf13By
2018/11/02 08:47:57 127.0.0.1:3333 > 127.0.0.1:50683: established websocket connection: {Protocol:v1.json Extensions:[]}
2018/11/02 08:47:57 connhub.touch: conn.uid= 0YimeX3VxJOXtKWf13By hashshard= 602
2018/11/02 08:47:57 websocket.handle: c.meta= 0YimeX3VxJOXtKWf13By
2018/11/02 08:47:57 eventbus.flush: len(events)= 1
2018/11/02 08:47:57 center.register: uid= 0YimeX3VxJOXtKWf13By
2018/11/02 08:47:57 backend.rpc.on_events, register user: 0YimeX3VxJOXtKWf13By
2018/11/02 08:47:57 chat.register: meta: {1 1 {2 345 0YimeX3VxJOXtKWf13By 123123123 127.0.0.1:50683 map[c:3 a:1 b:2] map[]}}
2018/11/02 08:47:57 rpc.push: uids= [0YimeX3VxJOXtKWf13By]
2018/11/02 08:47:57 connhub.get: uid= 0YimeX3VxJOXtKWf13By hashshard= 602
2018/11/02 08:47:57 connection.send: uid= 0YimeX3VxJOXtKWf13By
2018/11/02 08:47:57 connhub.touch: conn.uid= 0YimeX3VxJOXtKWf13By hashshard= 602
2018/11/02 08:47:57 chat.writer: push message: uids= [0Yime86JI6RNNTGHye5p 0YimeX3VxJOXtKWf13By]
2018/11/02 08:47:57 connhub.get: uid= 0YimeX3VxJOXtKWf13By hashshard= 602
2018/11/02 08:47:57 rpc.push: uids= [0Yime86JI6RNNTGHye5p 0YimeX3VxJOXtKWf13By]
2018/11/02 08:47:57 connhub.get: uid= 0Yime86JI6RNNTGHye5p hashshard= 601
2018/11/02 08:47:57 connhub.get: uid= 0YimeX3VxJOXtKWf13By hashshard= 602
2018/11/02 08:47:57 connection.send: uid= 0Yime86JI6RNNTGHye5p
2018/11/02 08:47:57 connection.send: uid= 0YimeX3VxJOXtKWf13By
2018/11/02 08:47:57 eventbus.flush: len(events)= 1
2018/11/02 08:47:57 center.register: uid= 0YimeX3VxJOXtKWf13By
2018/11/02 08:47:57 backend.rpc.on_events, register user: 0YimeX3VxJOXtKWf13By
2018/11/02 08:47:57 connhub.get: uid= 0YimeX3VxJOXtKWf13By hashshard= 602
2018/11/02 08:47:58 passport.auth: params= {{1 1 123123123 345 0 1541120278} map[]}
2018/11/02 08:47:58 backend.rpc.auth: user_id= 3
2018/11/02 08:47:58 handle_token: params= product_id:1 app_id:1 client_version:123123123 device_id:345 user_id:3 expire_at:1541120278 
2018/11/02 08:47:58 onRequest req: /ws?tok=_YeuHASLu4SEYF9a2LZvOwwEoJiyu9s1n1N63FlL5VE8sLJroSYSCJOJiOzIpbdEnXdDdQAAAAA&a=1&b=2&c=3
2018/11/02 08:47:58 validate_token: token= _YeuHASLu4SEYF9a2LZvOwwEoJiyu9s1n1N63FlL5VE8sLJroSYSCJOJiOzIpbdEnXdDdQAAAAA address= 127.0.0.1:50684
2018/11/02 08:47:58 onRequest conn: 0YimejX7Hus89G9qXFk3
2018/11/02 08:47:58 127.0.0.1:3333 > 127.0.0.1:50684: established websocket connection: {Protocol:v1.json Extensions:[]}
2018/11/02 08:47:58 connhub.touch: conn.uid= 0YimejX7Hus89G9qXFk3 hashshard= 603
2018/11/02 08:47:58 websocket.handle: c.meta= 0YimejX7Hus89G9qXFk3
2018/11/02 08:47:58 eventbus.flush: len(events)= 1
2018/11/02 08:47:58 center.register: uid= 0YimejX7Hus89G9qXFk3
2018/11/02 08:47:58 backend.rpc.on_events, register user: 0YimejX7Hus89G9qXFk3
2018/11/02 08:47:58 chat.register: meta: {1 1 {3 345 0YimejX7Hus89G9qXFk3 123123123 127.0.0.1:50684 map[a:1 b:2 c:3] map[]}}
2018/11/02 08:47:58 rpc.push: uids= [0YimejX7Hus89G9qXFk3]
2018/11/02 08:47:58 connhub.get: uid= 0YimejX7Hus89G9qXFk3 hashshard= 603
2018/11/02 08:47:58 connection.send: uid= 0YimejX7Hus89G9qXFk3
2018/11/02 08:47:58 connhub.touch: conn.uid= 0YimejX7Hus89G9qXFk3 hashshard= 603
2018/11/02 08:47:58 chat.writer: push message: uids= [0Yime86JI6RNNTGHye5p 0YimeX3VxJOXtKWf13By 0YimejX7Hus89G9qXFk3]
2018/11/02 08:47:58 connhub.get: uid= 0YimejX7Hus89G9qXFk3 hashshard= 603
2018/11/02 08:47:58 rpc.push: uids= [0Yime86JI6RNNTGHye5p 0YimeX3VxJOXtKWf13By 0YimejX7Hus89G9qXFk3]
2018/11/02 08:47:58 connhub.get: uid= 0Yime86JI6RNNTGHye5p hashshard= 601
2018/11/02 08:47:58 connhub.get: uid= 0YimeX3VxJOXtKWf13By hashshard= 602
2018/11/02 08:47:58 connhub.get: uid= 0YimejX7Hus89G9qXFk3 hashshard= 603
2018/11/02 08:47:58 connection.send: uid= 0Yime86JI6RNNTGHye5p
2018/11/02 08:47:58 connection.send: uid= 0YimeX3VxJOXtKWf13By
2018/11/02 08:47:58 connection.send: uid= 0YimejX7Hus89G9qXFk3
2018/11/02 08:47:58 eventbus.flush: len(events)= 1
2018/11/02 08:47:58 center.register: uid= 0YimejX7Hus89G9qXFk3
2018/11/02 08:47:58 backend.rpc.on_events, register user: 0YimejX7Hus89G9qXFk3
2018/11/02 08:47:58 connhub.get: uid= 0YimejX7Hus89G9qXFk3 hashshard= 603
2018/11/02 08:48:00 passport.auth: params= {{1 1 123123123 345 0 1541120280} map[]}
2018/11/02 08:48:00 backend.rpc.auth: user_id= 4
2018/11/02 08:48:00 handle_token: params= product_id:1 app_id:1 client_version:123123123 device_id:345 user_id:4 expire_at:1541120280 
2018/11/02 08:48:00 onRequest req: /ws?tok=MRUNsg21-L2S55HGxFbg1yW5SwWcglFtz_mTQa60eox4uIN3Zi-LKq6o-Pg_DrPq5-DDmgAAAAA&a=1&b=2&c=3
2018/11/02 08:48:00 validate_token: token= MRUNsg21-L2S55HGxFbg1yW5SwWcglFtz_mTQa60eox4uIN3Zi-LKq6o-Pg_DrPq5-DDmgAAAAA address= 127.0.0.1:50687
2018/11/02 08:48:00 onRequest conn: 0Yimf8UJx7pIf7QDZeqC
2018/11/02 08:48:00 127.0.0.1:3333 > 127.0.0.1:50687: established websocket connection: {Protocol:v1.json Extensions:[]}
2018/11/02 08:48:00 connhub.touch: conn.uid= 0Yimf8UJx7pIf7QDZeqC hashshard= 604
2018/11/02 08:48:00 websocket.handle: c.meta= 0Yimf8UJx7pIf7QDZeqC
2018/11/02 08:48:00 eventbus.flush: len(events)= 1
2018/11/02 08:48:00 center.register: uid= 0Yimf8UJx7pIf7QDZeqC
2018/11/02 08:48:00 backend.rpc.on_events, register user: 0Yimf8UJx7pIf7QDZeqC
2018/11/02 08:48:00 chat.register: meta: {1 1 {4 345 0Yimf8UJx7pIf7QDZeqC 123123123 127.0.0.1:50687 map[a:1 c:3 b:2] map[]}}
2018/11/02 08:48:00 rpc.push: uids= [0Yimf8UJx7pIf7QDZeqC]
2018/11/02 08:48:00 connhub.get: uid= 0Yimf8UJx7pIf7QDZeqC hashshard= 604
2018/11/02 08:48:00 connection.send: uid= 0Yimf8UJx7pIf7QDZeqC
2018/11/02 08:48:00 connhub.touch: conn.uid= 0Yimf8UJx7pIf7QDZeqC hashshard= 604
2018/11/02 08:48:00 chat.writer: push message: uids= [0Yime86JI6RNNTGHye5p 0YimeX3VxJOXtKWf13By 0YimejX7Hus89G9qXFk3 0Yimf8UJx7pIf7QDZeqC]
2018/11/02 08:48:00 connhub.get: uid= 0Yimf8UJx7pIf7QDZeqC hashshard= 604
2018/11/02 08:48:00 rpc.push: uids= [0Yime86JI6RNNTGHye5p 0YimeX3VxJOXtKWf13By 0YimejX7Hus89G9qXFk3 0Yimf8UJx7pIf7QDZeqC]
2018/11/02 08:48:00 connhub.get: uid= 0Yime86JI6RNNTGHye5p hashshard= 601
2018/11/02 08:48:00 connhub.get: uid= 0YimeX3VxJOXtKWf13By hashshard= 602
2018/11/02 08:48:00 connhub.get: uid= 0YimejX7Hus89G9qXFk3 hashshard= 603
2018/11/02 08:48:00 connhub.get: uid= 0Yimf8UJx7pIf7QDZeqC hashshard= 604
2018/11/02 08:48:00 connection.send: uid= 0Yime86JI6RNNTGHye5p
2018/11/02 08:48:00 connection.send: uid= 0YimeX3VxJOXtKWf13By
2018/11/02 08:48:00 connection.send: uid= 0YimejX7Hus89G9qXFk3
2018/11/02 08:48:00 connection.send: uid= 0Yimf8UJx7pIf7QDZeqC
2018/11/02 08:48:00 eventbus.flush: len(events)= 1
2018/11/02 08:48:00 center.register: uid= 0Yimf8UJx7pIf7QDZeqC
2018/11/02 08:48:00 backend.rpc.on_events, register user: 0Yimf8UJx7pIf7QDZeqC
2018/11/02 08:48:00 connhub.get: uid= 0Yimf8UJx7pIf7QDZeqC hashshard= 604
2018/11/02 08:48:05 passport.auth: params= {{1 1 123123123 345 0 1541120285} map[]}
2018/11/02 08:48:05 backend.rpc.auth: user_id= 5
2018/11/02 08:48:05 handle_token: params= product_id:1 app_id:1 client_version:123123123 device_id:345 user_id:5 expire_at:1541120285 
2018/11/02 08:48:05 onRequest req: /ws?tok=g9gRmstGIKUpoC4BYiKxPeNBIlc3h7TcxM5GCgvgUWYwBbOpkzw9Vsuj4zM2x6uDiXdHXgAAAAA&a=1&b=2&c=3
2018/11/02 08:48:05 validate_token: token= g9gRmstGIKUpoC4BYiKxPeNBIlc3h7TcxM5GCgvgUWYwBbOpkzw9Vsuj4zM2x6uDiXdHXgAAAAA address= 127.0.0.1:50696
2018/11/02 08:48:05 onRequest conn: 0Yimg8sKc9DDwla9AfaX
2018/11/02 08:48:05 127.0.0.1:3333 > 127.0.0.1:50696: established websocket connection: {Protocol:v1.json Extensions:[]}
2018/11/02 08:48:05 connhub.touch: conn.uid= 0Yimg8sKc9DDwla9AfaX hashshard= 605
2018/11/02 08:48:05 websocket.handle: c.meta= 0Yimg8sKc9DDwla9AfaX
2018/11/02 08:48:05 eventbus.flush: len(events)= 1
2018/11/02 08:48:05 center.register: uid= 0Yimg8sKc9DDwla9AfaX
2018/11/02 08:48:05 backend.rpc.on_events, register user: 0Yimg8sKc9DDwla9AfaX
2018/11/02 08:48:05 chat.register: meta: {1 1 {5 345 0Yimg8sKc9DDwla9AfaX 123123123 127.0.0.1:50696 map[a:1 b:2 c:3] map[]}}
2018/11/02 08:48:05 rpc.push: uids= [0Yimg8sKc9DDwla9AfaX]
2018/11/02 08:48:05 connhub.get: uid= 0Yimg8sKc9DDwla9AfaX hashshard= 605
2018/11/02 08:48:05 connection.send: uid= 0Yimg8sKc9DDwla9AfaX
2018/11/02 08:48:05 connhub.touch: conn.uid= 0Yimg8sKc9DDwla9AfaX hashshard= 605
2018/11/02 08:48:05 chat.writer: push message: uids= [0Yime86JI6RNNTGHye5p 0YimeX3VxJOXtKWf13By 0YimejX7Hus89G9qXFk3 0Yimf8UJx7pIf7QDZeqC 0Yimg8sKc9DDwla9AfaX]
2018/11/02 08:48:05 connhub.get: uid= 0Yimg8sKc9DDwla9AfaX hashshard= 605
2018/11/02 08:48:05 rpc.push: uids= [0Yime86JI6RNNTGHye5p 0YimeX3VxJOXtKWf13By 0YimejX7Hus89G9qXFk3 0Yimf8UJx7pIf7QDZeqC 0Yimg8sKc9DDwla9AfaX]
2018/11/02 08:48:05 connhub.get: uid= 0Yime86JI6RNNTGHye5p hashshard= 601
2018/11/02 08:48:05 connhub.get: uid= 0YimeX3VxJOXtKWf13By hashshard= 602
2018/11/02 08:48:05 connhub.get: uid= 0YimejX7Hus89G9qXFk3 hashshard= 603
2018/11/02 08:48:05 connhub.get: uid= 0Yimf8UJx7pIf7QDZeqC hashshard= 604
2018/11/02 08:48:05 connhub.get: uid= 0Yimg8sKc9DDwla9AfaX hashshard= 605
2018/11/02 08:48:05 connection.send: uid= 0Yime86JI6RNNTGHye5p
2018/11/02 08:48:05 connection.send: uid= 0YimeX3VxJOXtKWf13By
2018/11/02 08:48:05 connection.send: uid= 0YimejX7Hus89G9qXFk3
2018/11/02 08:48:05 connection.send: uid= 0Yimf8UJx7pIf7QDZeqC
2018/11/02 08:48:05 connection.send: uid= 0Yimg8sKc9DDwla9AfaX
2018/11/02 08:48:05 eventbus.flush: len(events)= 1
2018/11/02 08:48:05 center.register: uid= 0Yimg8sKc9DDwla9AfaX
2018/11/02 08:48:05 backend.rpc.on_events, register user: 0Yimg8sKc9DDwla9AfaX
2018/11/02 08:48:05 connhub.get: uid= 0Yimg8sKc9DDwla9AfaX hashshard= 605

(ps: a client refreshed web page)

2018/11/02 08:48:10 connection.processFrame: header= {true 0 8 true [174 0 180 39] 2}
2018/11/02 08:48:10 connection.receive: hanlding control frame: {true 0 8 true [174 0 180 39] 2}
2018/11/02 08:48:10 connection.receive: failed process frame: ws closed: 1001 
2018/11/02 08:48:10 connection receive failed: ws closed: 1001 
2018/11/02 08:48:10 eventbus.flush: len(events)= 1
2018/11/02 08:48:10 center.register: uid= 0Yime86JI6RNNTGHye5p
2018/11/02 08:48:10 backend.rpc.on_events, remove user: 0Yime86JI6RNNTGHye5p
2018/11/02 08:48:10 chat.writer: push message: uids= [0YimeX3VxJOXtKWf13By 0YimejX7Hus89G9qXFk3 0Yimf8UJx7pIf7QDZeqC 0Yimg8sKc9DDwla9AfaX]
2018/11/02 08:48:10 rpc.push: uids= [0YimeX3VxJOXtKWf13By 0YimejX7Hus89G9qXFk3 0Yimf8UJx7pIf7QDZeqC 0Yimg8sKc9DDwla9AfaX]
2018/11/02 08:48:10 connhub.get: uid= 0YimeX3VxJOXtKWf13By hashshard= 602
2018/11/02 08:48:10 connhub.get: uid= 0YimejX7Hus89G9qXFk3 hashshard= 603
2018/11/02 08:48:10 connhub.get: uid= 0Yimf8UJx7pIf7QDZeqC hashshard= 604
2018/11/02 08:48:10 connhub.get: uid= 0Yimg8sKc9DDwla9AfaX hashshard= 605
2018/11/02 08:48:10 connection.send: uid= 0YimeX3VxJOXtKWf13By
2018/11/02 08:48:10 connection.send: uid= 0YimejX7Hus89G9qXFk3
2018/11/02 08:48:10 connection.send: uid= 0Yimf8UJx7pIf7QDZeqC
2018/11/02 08:48:10 connection.send: uid= 0Yimg8sKc9DDwla9AfaX
2018/11/02 08:48:11 passport.auth: params= {{1 1 123123123 345 0 1541120291} map[]}
2018/11/02 08:48:11 backend.rpc.auth: user_id= 6
2018/11/02 08:48:11 handle_token: params= product_id:1 app_id:1 client_version:123123123 device_id:345 user_id:6 expire_at:1541120291 
2018/11/02 08:48:11 onRequest req: /ws?tok=pgKqkHhvyNKfgHPA8IE0UVkcMcCmFrSWDBQvDrpZbnjOLeMnJXaotdQIoUmtBY_xpo5bJAAAAAA&a=1&b=2&c=3
2018/11/02 08:48:11 validate_token: token= pgKqkHhvyNKfgHPA8IE0UVkcMcCmFrSWDBQvDrpZbnjOLeMnJXaotdQIoUmtBY_xpo5bJAAAAAA address= 127.0.0.1:50708
2018/11/02 08:48:11 onRequest conn: 0YimhLjwbm4jULNGHssw
2018/11/02 08:48:11 127.0.0.1:3333 > 127.0.0.1:50708: established websocket connection: {Protocol:v1.json Extensions:[]}
2018/11/02 08:48:11 connhub.touch: conn.uid= 0YimhLjwbm4jULNGHssw hashshard= 606
2018/11/02 08:48:11 websocket.handle: c.meta= 0YimhLjwbm4jULNGHssw
2018/11/02 08:48:11 eventbus.flush: len(events)= 1
2018/11/02 08:48:11 center.register: uid= 0YimhLjwbm4jULNGHssw
2018/11/02 08:48:11 backend.rpc.on_events, register user: 0YimhLjwbm4jULNGHssw
2018/11/02 08:48:11 chat.register: meta: {1 1 {6 345 0YimhLjwbm4jULNGHssw 123123123 127.0.0.1:50708 map[b:2 a:1 c:3] map[]}}
2018/11/02 08:48:11 rpc.push: uids= [0YimhLjwbm4jULNGHssw]
2018/11/02 08:48:11 connhub.get: uid= 0YimhLjwbm4jULNGHssw hashshard= 606
2018/11/02 08:48:11 connection.send: uid= 0YimhLjwbm4jULNGHssw
2018/11/02 08:48:11 connhub.touch: conn.uid= 0YimhLjwbm4jULNGHssw hashshard= 606
2018/11/02 08:48:11 chat.writer: push message: uids= [0YimeX3VxJOXtKWf13By 0YimejX7Hus89G9qXFk3 0Yimf8UJx7pIf7QDZeqC 0Yimg8sKc9DDwla9AfaX 0YimhLjwbm4jULNGHssw]
2018/11/02 08:48:11 connhub.get: uid= 0YimhLjwbm4jULNGHssw hashshard= 606
2018/11/02 08:48:11 rpc.push: uids= [0YimeX3VxJOXtKWf13By 0YimejX7Hus89G9qXFk3 0Yimf8UJx7pIf7QDZeqC 0Yimg8sKc9DDwla9AfaX 0YimhLjwbm4jULNGHssw]
2018/11/02 08:48:11 connhub.get: uid= 0YimeX3VxJOXtKWf13By hashshard= 602
2018/11/02 08:48:11 connhub.get: uid= 0YimejX7Hus89G9qXFk3 hashshard= 603
2018/11/02 08:48:11 connhub.get: uid= 0Yimf8UJx7pIf7QDZeqC hashshard= 604
2018/11/02 08:48:11 connhub.get: uid= 0Yimg8sKc9DDwla9AfaX hashshard= 605
2018/11/02 08:48:11 connhub.get: uid= 0YimhLjwbm4jULNGHssw hashshard= 606
2018/11/02 08:48:11 connection.send: uid= 0YimeX3VxJOXtKWf13By
2018/11/02 08:48:11 connection.send: uid= 0YimejX7Hus89G9qXFk3
2018/11/02 08:48:11 connection.send: uid= 0Yimf8UJx7pIf7QDZeqC
2018/11/02 08:48:11 connection.send: uid= 0Yimg8sKc9DDwla9AfaX
2018/11/02 08:48:11 connection.send: uid= 0YimhLjwbm4jULNGHssw
2018/11/02 08:48:11 eventbus.flush: len(events)= 1
2018/11/02 08:48:11 center.register: uid= 0YimhLjwbm4jULNGHssw
2018/11/02 08:48:11 backend.rpc.on_events, register user: 0YimhLjwbm4jULNGHssw
2018/11/02 08:48:11 connhub.get: uid= 0YimhLjwbm4jULNGHssw hashshard= 606
2018/11/02 08:48:12 connhub.closer: closing 1 connections
2018/11/02 08:48:15 connection.processFrame: header= {true 0 1 true [12 214 61 158] 242}
2018/11/02 08:48:15 msgbus.flush: flushing messages
2018/11/02 08:48:15 backend.rpc.on_message, uid= 0YimhLjwbm4jULNGHssw
2018/11/02 08:48:15 chat.join: user antelope joining room 1234
2018/11/02 08:48:15 rpc.tag: uids= [0YimhLjwbm4jULNGHssw] tags= map[room:1234]
2018/11/02 08:48:15 connhub.get: uid= 0YimhLjwbm4jULNGHssw hashshard= 606
2018/11/02 08:48:15 conhub.UpdateTags: removed= [] added= [room:1234]
2018/11/02 08:48:15 chat.BroadcastByTag: tags= map[room:1234]
2018/11/02 08:48:15 connhub.FindTags: tags= [room:1234]
2018/11/02 08:48:15 connhub.get: uid= 0YimhLjwbm4jULNGHssw hashshard= 606
2018/11/02 08:48:15 rpc.broadcast: tags= map[room:1234]
2018/11/02 08:48:15 connection.send: uid= 0YimhLjwbm4jULNGHssw

(ps: no client activity, ping every 30 seconds, 5 clients total)

2018/11/02 08:48:41 connection.ping: uid= 0Yimg8sKc9DDwla9AfaX
2018/11/02 08:48:41 connection.ping: uid= 0Yimf8UJx7pIf7QDZeqC
2018/11/02 08:48:41 connection.ping: uid= 0YimeX3VxJOXtKWf13By
2018/11/02 08:48:41 connection.ping: uid= 0YimejX7Hus89G9qXFk3
2018/11/02 08:48:41 connection.processFrame: header= {true 0 10 true [209 239 179 216] 0}
2018/11/02 08:48:41 connection.receive: hanlding control frame: {true 0 10 true [209 239 179 216] 0}
2018/11/02 08:48:41 connection.processFrame: header= {true 0 10 true [93 200 153 73] 0}
2018/11/02 08:48:41 connection.receive: hanlding control frame: {true 0 10 true [93 200 153 73] 0}
2018/11/02 08:48:41 connection.processFrame: header= {true 0 10 true [216 25 36 102] 0}
2018/11/02 08:48:41 connection.processFrame: header= {true 0 10 true [227 70 45 82] 0}
2018/11/02 08:48:41 connection.receive: hanlding control frame: {true 0 10 true [216 25 36 102] 0}
2018/11/02 08:48:41 connection.receive: hanlding control frame: {true 0 10 true [227 70 45 82] 0}
2018/11/02 08:49:11 connection.ping: uid= 0YimhLjwbm4jULNGHssw
2018/11/02 08:49:11 connection.ping: uid= 0YimejX7Hus89G9qXFk3
2018/11/02 08:49:11 connection.ping: uid= 0Yimg8sKc9DDwla9AfaX
2018/11/02 08:49:11 connection.ping: uid= 0YimeX3VxJOXtKWf13By
2018/11/02 08:49:11 connection.ping: uid= 0Yimf8UJx7pIf7QDZeqC
2018/11/02 08:49:11 connection.processFrame: header= {true 0 10 true [46 161 143 98] 0}
2018/11/02 08:49:11 connection.receive: hanlding control frame: {true 0 10 true [46 161 143 98] 0}
2018/11/02 08:49:11 connection.processFrame: header= {true 0 10 true [59 248 171 115] 0}
2018/11/02 08:49:11 connection.receive: hanlding control frame: {true 0 10 true [59 248 171 115] 0}
2018/11/02 08:49:11 connection.processFrame: header= {true 0 10 true [251 174 39 43] 0}
2018/11/02 08:49:11 connection.receive: hanlding control frame: {true 0 10 true [251 174 39 43] 0}
2018/11/02 08:49:11 connection.processFrame: header= {true 0 10 true [236 196 138 21] 0}
2018/11/02 08:49:11 connection.receive: hanlding control frame: {true 0 10 true [236 196 138 21] 0}
2018/11/02 08:49:11 connection.processFrame: header= {true 0 10 true [32 40 45 22] 0}
2018/11/02 08:49:11 connection.receive: hanlding control frame: {true 0 10 true [32 40 45 22] 0}
2018/11/02 08:49:41 connection.ping: uid= 0Yimg8sKc9DDwla9AfaX
2018/11/02 08:49:41 connection.ping: uid= 0YimejX7Hus89G9qXFk3
2018/11/02 08:49:41 connection.ping: uid= 0YimeX3VxJOXtKWf13By
2018/11/02 08:49:41 connection.ping: uid= 0YimhLjwbm4jULNGHssw
2018/11/02 08:49:41 connection.ping: uid= 0Yimf8UJx7pIf7QDZeqC
2018/11/02 08:49:41 connection.processFrame: header= {true 0 10 true [188 219 2 126] 0}
2018/11/02 08:49:41 connection.receive: hanlding control frame: {true 0 10 true [188 219 2 126] 0}
2018/11/02 08:49:41 connection.processFrame: header= {true 0 10 true [60 37 224 96] 0}
2018/11/02 08:49:41 connection.receive: hanlding control frame: {true 0 10 true [60 37 224 96] 0}
2018/11/02 08:49:41 connection.processFrame: header= {true 0 10 true [41 170 98 214] 0}
2018/11/02 08:49:41 connection.receive: hanlding control frame: {true 0 10 true [41 170 98 214] 0}
2018/11/02 08:49:41 connection.processFrame: header= {true 0 10 true [217 148 86 148] 0}
2018/11/02 08:49:41 connection.receive: hanlding control frame: {true 0 10 true [217 148 86 148] 0}
2018/11/02 08:49:41 connection.processFrame: header= {true 0 10 true [105 166 86 146] 0}
2018/11/02 08:49:41 connection.receive: hanlding control frame: {true 0 10 true [105 166 86 146] 0}
2018/11/02 08:50:11 connection.ping: uid= 0Yimg8sKc9DDwla9AfaX
2018/11/02 08:50:11 connection.ping: uid= 0YimhLjwbm4jULNGHssw
2018/11/02 08:50:11 connection.ping: uid= 0YimejX7Hus89G9qXFk3
2018/11/02 08:50:11 connection.processFrame: header= {true 0 10 true [247 26 185 249] 0}
2018/11/02 08:50:11 connection.ping: uid= 0Yimf8UJx7pIf7QDZeqC
2018/11/02 08:50:11 connection.receive: hanlding control frame: {true 0 10 true [247 26 185 249] 0}
2018/11/02 08:50:11 connection.processFrame: header= {true 0 10 true [188 180 58 195] 0}
2018/11/02 08:50:11 connection.ping: uid= 0YimeX3VxJOXtKWf13By
2018/11/02 08:50:11 connection.receive: hanlding control frame: {true 0 10 true [188 180 58 195] 0}
2018/11/02 08:50:11 connection.processFrame: header= {true 0 10 true [174 57 52 103] 0}
2018/11/02 08:50:11 connection.receive: hanlding control frame: {true 0 10 true [174 57 52 103] 0}
2018/11/02 08:50:11 connection.processFrame: header= {true 0 10 true [122 10 16 56] 0}
2018/11/02 08:50:11 connection.processFrame: header= {true 0 10 true [15 82 188 250] 0}
2018/11/02 08:50:11 connection.receive: hanlding control frame: {true 0 10 true [122 10 16 56] 0}
2018/11/02 08:50:11 connection.receive: hanlding control frame: {true 0 10 true [15 82 188 250] 0}
2018/11/02 08:50:41 connection.ping: uid= 0Yimg8sKc9DDwla9AfaX
2018/11/02 08:50:41 connection.ping: uid= 0YimejX7Hus89G9qXFk3
2018/11/02 08:50:41 connection.ping: uid= 0Yimf8UJx7pIf7QDZeqC
2018/11/02 08:50:41 connection.ping: uid= 0YimeX3VxJOXtKWf13By
2018/11/02 08:50:41 connection.ping: uid= 0YimhLjwbm4jULNGHssw

(ps: here we got empty headers for 3 clients, making them closed from server)

2018/11/02 08:50:41 connection.processFrame: header= {false 0 0 false [0 0 0 0] 0}
2018/11/02 08:50:41 connection.processFrame: check header: frames from client to server must be masked
2018/11/02 08:50:41 connection.receive: failed process frame: frames from client to server must be masked
2018/11/02 08:50:41 connection receive failed: frames from client to server must be masked
2018/11/02 08:50:41 connection.processFrame: header= {false 0 0 false [0 0 0 0] 0}
2018/11/02 08:50:41 connection.processFrame: header= {true 0 10 true [21 101 147 237] 0}
2018/11/02 08:50:41 connection.processFrame: header= {true 0 10 true [158 44 195 72] 0}
2018/11/02 08:50:41 connection.receive: hanlding control frame: {true 0 10 true [158 44 195 72] 0}
2018/11/02 08:50:41 connection.processFrame: header= {false 0 0 false [0 0 0 0] 0}
2018/11/02 08:50:41 connection.processFrame: check header: frames from client to server must be masked
2018/11/02 08:50:41 connection.receive: failed process frame: frames from client to server must be masked
2018/11/02 08:50:41 connection receive failed: frames from client to server must be masked
2018/11/02 08:50:41 connection.processFrame: check header: frames from client to server must be masked
2018/11/02 08:50:41 connection.receive: failed process frame: frames from client to server must be masked
2018/11/02 08:50:41 connection receive failed: frames from client to server must be masked
2018/11/02 08:50:41 connection.receive: hanlding control frame: {true 0 10 true [21 101 147 237] 0}
2018/11/02 08:50:41 eventbus.flush: len(events)= 1
2018/11/02 08:50:41 eventbus.flush: len(events)= 1
2018/11/02 08:50:41 eventbus.flush: len(events)= 1
2018/11/02 08:50:41 center.register: uid= 0Yimg8sKc9DDwla9AfaX
2018/11/02 08:50:41 center.register: uid= 0YimejX7Hus89G9qXFk3
2018/11/02 08:50:41 center.register: uid= 0YimhLjwbm4jULNGHssw
2018/11/02 08:50:41 backend.rpc.on_events, remove user: 0YimhLjwbm4jULNGHssw
2018/11/02 08:50:41 backend.rpc.on_events, remove user: 0YimejX7Hus89G9qXFk3
2018/11/02 08:50:41 backend.rpc.on_events, remove user: 0Yimg8sKc9DDwla9AfaX
2018/11/02 08:50:41 chat.writer: push message: uids= [0YimeX3VxJOXtKWf13By 0Yimf8UJx7pIf7QDZeqC]
2018/11/02 08:50:41 rpc.push: uids= [0YimeX3VxJOXtKWf13By 0Yimf8UJx7pIf7QDZeqC]
2018/11/02 08:50:41 connhub.get: uid= 0YimeX3VxJOXtKWf13By hashshard= 602
2018/11/02 08:50:41 connhub.get: uid= 0Yimf8UJx7pIf7QDZeqC hashshard= 604
2018/11/02 08:50:41 connection.send: uid= 0YimeX3VxJOXtKWf13By
2018/11/02 08:50:41 connection.send: uid= 0Yimf8UJx7pIf7QDZeqC
2018/11/02 08:50:41 chat.writer: push message: uids= [0YimeX3VxJOXtKWf13By 0Yimf8UJx7pIf7QDZeqC]
2018/11/02 08:50:41 rpc.push: uids= [0YimeX3VxJOXtKWf13By 0Yimf8UJx7pIf7QDZeqC]
2018/11/02 08:50:41 connhub.get: uid= 0YimeX3VxJOXtKWf13By hashshard= 602
2018/11/02 08:50:41 connhub.get: uid= 0Yimf8UJx7pIf7QDZeqC hashshard= 604
2018/11/02 08:50:41 connection.send: uid= 0YimeX3VxJOXtKWf13By
2018/11/02 08:50:41 connection.send: uid= 0Yimf8UJx7pIf7QDZeqC
2018/11/02 08:50:41 chat.writer: push message: uids= [0YimeX3VxJOXtKWf13By 0Yimf8UJx7pIf7QDZeqC]
2018/11/02 08:50:41 rpc.push: uids= [0YimeX3VxJOXtKWf13By 0Yimf8UJx7pIf7QDZeqC]
2018/11/02 08:50:41 connhub.get: uid= 0YimeX3VxJOXtKWf13By hashshard= 602
2018/11/02 08:50:41 connhub.get: uid= 0Yimf8UJx7pIf7QDZeqC hashshard= 604
2018/11/02 08:50:41 connection.send: uid= 0YimeX3VxJOXtKWf13By
2018/11/02 08:50:41 connection.send: uid= 0Yimf8UJx7pIf7QDZeqC
2018/11/02 08:50:42 connhub.closer: closing 1 connections
2018/11/02 08:50:43 connhub.closer: closing 1 connections
2018/11/02 08:50:44 connhub.closer: closing 1 connections

(ps: here we have 2 clients left)

2018/11/02 08:51:11 connection.ping: uid= 0Yimf8UJx7pIf7QDZeqC
2018/11/02 08:51:11 connection.ping: uid= 0YimeX3VxJOXtKWf13By
2018/11/02 08:51:11 connection.processFrame: header= {true 0 10 true [99 145 82 227] 0}
2018/11/02 08:51:11 connection.receive: hanlding control frame: {true 0 10 true [99 145 82 227] 0}
2018/11/02 08:51:11 connection.processFrame: header= {true 0 10 true [249 115 230 59] 0}
2018/11/02 08:51:11 connection.receive: hanlding control frame: {true 0 10 true [249 115 230 59] 0}
2018/11/02 08:51:41 connection.ping: uid= 0Yimf8UJx7pIf7QDZeqC
2018/11/02 08:51:41 connection.ping: uid= 0YimeX3VxJOXtKWf13By
2018/11/02 08:51:41 connection.processFrame: header= {true 0 10 true [98 103 172 242] 0}
2018/11/02 08:51:41 connection.receive: hanlding control frame: {true 0 10 true [98 103 172 242] 0}
2018/11/02 08:51:41 connection.processFrame: header= {true 0 10 true [31 194 210 131] 0}
2018/11/02 08:51:41 connection.receive: hanlding control frame: {true 0 10 true [31 194 210 131] 0}
2018/11/02 08:52:11 connection.ping: uid= 0YimeX3VxJOXtKWf13By
2018/11/02 08:52:11 connection.ping: uid= 0Yimf8UJx7pIf7QDZeqC
2018/11/02 08:52:11 connection.processFrame: header= {true 0 10 true [200 169 120 252] 0}
2018/11/02 08:52:11 connection.receive: hanlding control frame: {true 0 10 true [200 169 120 252] 0}
2018/11/02 08:52:11 connection.processFrame: header= {true 0 10 true [190 155 43 92] 0}
2018/11/02 08:52:11 connection.receive: hanlding control frame: {true 0 10 true [190 155 43 92] 0}

(ps: panic again)

runtime: pointer 0xc0005c3c24 to unallocated span span.base()=0xc0005bc000 span.limit=0xc0005c4000 span.state=0
runtime: found in object at *(0xc0000e58c0+0x68)
object=0xc0000e58c0 s.base()=0xc0000e4000 s.limit=0xc0000e5e40 s.spanclass=56 s.elemsize=704 s.state=_MSpanInUse
 *(object+0) = 0x1
 *(object+8) = 0x0
 *(object+16) = 0xffffffffffffffff
 *(object+24) = 0x0
 *(object+32) = 0x2
 *(object+40) = 0x0
 *(object+48) = 0x0
 *(object+56) = 0x53c0a70
 *(object+64) = 0x72
 *(object+72) = 0x2
 *(object+80) = 0xc0000e58c0
 *(object+88) = 0x0
 *(object+96) = 0x2
 *(object+104) = 0xc0005c3c24 <==
 *(object+112) = 0x0
 *(object+120) = 0x0
 *(object+128) = 0x0
 *(object+136) = 0x0
 *(object+144) = 0x0
 *(object+152) = 0x0
 *(object+160) = 0x0
 *(object+168) = 0x0
 *(object+176) = 0x0
 *(object+184) = 0x0
 *(object+192) = 0x0
 *(object+200) = 0x0
 *(object+208) = 0x0
 *(object+216) = 0x0
 *(object+224) = 0x0
 *(object+232) = 0x0
 *(object+240) = 0xffff980d00000000
 *(object+248) = 0x2
 *(object+256) = 0x0
 *(object+264) = 0x0
 *(object+272) = 0x53c0a70
 *(object+280) = 0x77
 *(object+288) = 0x2
 *(object+296) = 0xc0000e58c0
 *(object+304) = 0x0
 *(object+312) = 0x2
 *(object+320) = 0xc00001a3b0
 *(object+328) = 0x0
 *(object+336) = 0x0
 *(object+344) = 0x0
 *(object+352) = 0x0
 *(object+360) = 0x0
 *(object+368) = 0x0
 *(object+376) = 0x0
 *(object+384) = 0x0
 *(object+392) = 0x0
 *(object+400) = 0x0
 *(object+408) = 0x0
 *(object+416) = 0x0
 *(object+424) = 0x0
 *(object+432) = 0x0
 *(object+440) = 0x0
 *(object+448) = 0x0
 *(object+456) = 0x0
 *(object+464) = 0x0
 *(object+472) = 0x0
 *(object+480) = 0x0
 *(object+488) = 0x0
 *(object+496) = 0x0
 *(object+504) = 0x0
 *(object+512) = 0x0
 *(object+520) = 0x0
 *(object+528) = 0x0
 *(object+536) = 0x0
 *(object+544) = 0x0
 *(object+552) = 0x0
 *(object+560) = 0x1010100000000
 *(object+568) = 0x0
 *(object+576) = 0x2
 *(object+584) = 0x1
 *(object+592) = 0x0
 *(object+600) = 0x9ebdce
 *(object+608) = 0x3
 *(object+616) = 0xa80ee0
 *(object+624) = 0xc000506f00
 *(object+632) = 0xa80ee0
 *(object+640) = 0xc000506f30
 *(object+648) = 0x0
 *(object+656) = 0x0
 *(object+664) = 0x0
 *(object+672) = 0x0
 *(object+680) = 0x0
 *(object+688) = 0x0
 *(object+696) = 0x0
fatal error: found bad pointer in Go heap (incorrect use of unsafe or cgo?)

runtime stack:
runtime.throw(0xa0c919, 0x3e)

My environment:

Microsoft Windows [Version 10.0.17134.345]
go version go1.11 windows/amd64

@jxskiss jxskiss changed the title fix: incorrect usage of unsafe uintptr fix: panic caused by uintptr Nov 6, 2018
@gobwas
Copy link
Owner

gobwas commented May 19, 2019

Hi @jxskiss,

Long time ago you have opened this issue, and today I have pushed changes that may potentially fix your problem too. Are you still able to try out new ws code from master branch against your application?

Also, travis.ci now allows to run tests against windows servers, so we are able now to write some close to your use case test and run it during CI.

Cheers.

gobwas added a commit that referenced this pull request Jun 1, 2019
This commit removes stack-based slice usage from from ReadHeader(),
WriteHeader() and nonce type manipulation. That stack-based hacks were
working well on Linux but were crashing applications on Windows with
errors indicating that GC found pointer not to the allocated span.

For sure, allocation on heap will bring some penalty to the performance,
but since Go uses TCMalloc under the hood that penalties could be not
significant.

Fixes #73 #63 #60
@gobwas gobwas closed this Jun 1, 2019
gobwas added a commit that referenced this pull request Jun 1, 2019
This commit removes stack-based slice usage from from ReadHeader(),
WriteHeader() and nonce type manipulation. That stack-based hacks were
working well on Linux but were crashing applications on Windows with
errors indicating that GC found pointer not to the allocated span.

For sure, allocation on heap will bring some penalty to the performance,
but since Go uses TCMalloc under the hood that penalties could be not
significant.

Fixes #73 #63 #60
@jxskiss
Copy link
Author

jxskiss commented Jun 2, 2019

@gobwas Sorry for the late reply, I didn't noticed the updates. I will give it a try later soon. Thx!

@jxskiss
Copy link
Author

jxskiss commented Jun 2, 2019

@gobwas Sorry for the late reply, I didn't noticed the updates. I will give it a try later soon. Thx!

@gobwas I have tried the latest master, it did not panic, but it reports error ""unexpected continuation data frame" for concurrent connections test, so I guess there is still some problems.

FYI, the program runs as expected using the changes I proposed in this PR (use slice instead of uintptr).
My go version is "go version go1.11 windows/amd64".

@gobwas
Copy link
Owner

gobwas commented Jun 2, 2019

Could you please try it against appropriate pull request branch, not against master? It is not yet merged. Thanks!

@jxskiss
Copy link
Author

jxskiss commented Jun 3, 2019

@gobwas Sorry for the mistake -_-
I tried the latest commit 493808b8bcdb from branch fix/less-unsafe, I ran my test for 20 minutes, it worked all as expected.
Thanks for your continuous work!

@euclid1990
Copy link

@gobwas Thank you all

gobwas added a commit that referenced this pull request Jun 4, 2019
This commit removes stack-based slice usage from from ReadHeader(),
WriteHeader() and nonce type manipulation. That stack-based hacks were
working well on Linux but were crashing applications on Windows with
errors indicating that GC found pointer not to the allocated span.

For sure, allocation on heap will bring some penalty to the performance,
but since Go uses TCMalloc under the hood that penalties could be not
significant.

Fixes #73 #63 #60
gobwas added a commit that referenced this pull request Jun 4, 2019
This commit removes stack-based slice usage from from ReadHeader(),
WriteHeader() and nonce type manipulation. That stack-based hacks were
working well on Linux but were crashing applications on Windows with
errors indicating that GC found pointer not to the allocated span.

For sure, allocation on heap will bring some penalty to the performance,
but since Go uses TCMalloc under the hood that penalties could be not
significant.

Fixes #73 #63 #60
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants