【bug报告】wasm 虚拟机内存池数据竞争问题

  • commitID:ce292e9814b7c0fbcbdb586c7705eaf304edc599

  • 文件:life/exec/mem_pool.go

  • 问题描述:

type MemPool struct {
	sync.Mutex
	memBlock []*MemBlock
	largeMem map[int]*sync.Pool
}

内存池的memblock字段用来做内存的预先分配,用的数据结构是slice,没有对这个slice进行数据竞争的管理,在多线程同时申请内存时(运行wasm合约),会引起不可预知的错误。
虽然每个block的tx是串行的,但是外部用户可以通过rpc请求节点,做查询操作,这个时候就会出现多个wasm并行问题。

以下代码是对memBlock字段的访问,可以看到没有做任何的数据竞争管理。

func (mp *MemPool) Get(pages int) []byte {
	mp.Lock()
	defer mp.Unlock()
	if pages <= 0 {
		return nil
	}
	var mem []byte
	pages = fixSize(pages - DefaultMemoryPages)

	pos := int(math.Log2(float64(pages)))
	if pos >= len(mp.memBlock) {

		pool, ok := mp.largeMem[pages]
		if !ok {
			pool = &sync.Pool{
				New: func() interface{} {
					return make([]byte, DefaultPageSize*(pages+DefaultMemoryPages))
				},
			}
			mp.largeMem[pages] = pool
		}
		mem = pool.Get().([]byte)
	} else {
		mem = mp.memBlock[pos].Get()
	}

	memset(mem)

	return mem
}

func (mp *MemPool) Put(mem []byte) {
	mp.Lock()
	defer mp.Unlock()
	pages := len(mem) / DefaultPageSize

	pages = fixSize(pages - DefaultMemoryPages)
	pos := int(math.Log2(float64(pages)))
	if pos >= len(mp.memBlock) {
		pool, ok := mp.largeMem[pages]
		if !ok {
			return
		}
		pool.Put(mem)
	} else {
		mp.memBlock[pos].Put(mem)
	}
}

2 Likes

感谢您的提报,已反馈给内部同学跟进,有进展我会随时给您同步!

master分支代码不是最新的,目前最新版本代码已删除life虚拟机

master分支代码会在主网上线后更新哈,目前最新代码可以使用develop分支代码

最新版本是哪个?

换成wagon了啊,为什么呐?

之前版本是不支持WASM的,目前0.12.0版本新增WASM合约,是基于wagon基础优化的哈

测试网目前用的是release-0.12.0,建议用这个,
目前正在开发的分支是feature/change-addr-to-bech32

1 Like