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

Fin3 #53

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open

Fin3 #53

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions internal/engine/compiler/compiler_controlflow_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -659,7 +659,7 @@ func TestCompiler_compileCallIndirect(t *testing.T) {
env.addTable(&wasm.TableInstance{References: table})

cf := &function{typeID: 50}
table[0] = uintptr(unsafe.Pointer(cf))
table[0] = unsafe.Pointer(cf)

// Place the offset value.
err = compiler.compileConstI32(targetOffset)
Expand Down Expand Up @@ -737,7 +737,7 @@ func TestCompiler_compileCallIndirect(t *testing.T) {
moduleInstance: env.moduleInstance,
typeID: targetTypeID,
}
table[i] = uintptr(unsafe.Pointer(&me.functions[i]))
table[i] = unsafe.Pointer(&me.functions[i])
}

// Test to ensure that we can call all the functions stored in the table.
Expand Down Expand Up @@ -827,7 +827,7 @@ func TestCompiler_callIndirect_largeTypeIndex(t *testing.T) {
moduleInstance: env.moduleInstance,
}
me.functions = append(me.functions, f)
table[0] = uintptr(unsafe.Pointer(&f))
table[0] = unsafe.Pointer(&f)
}

compiler := env.requireNewCompiler(t, &wasm.FunctionType{}, newCompiler, &wazeroir.CompilationResult{
Expand Down
68 changes: 36 additions & 32 deletions internal/engine/compiler/compiler_post1_0_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -476,7 +476,7 @@ func TestCompiler_compileMemoryInit(t *testing.T) {
}

func TestCompiler_compileElemDrop(t *testing.T) {
origins := []wasm.ElementInstance{{1}, {2}, {3}, {4}, {5}}
origins := []wasm.ElementInstance{{asReference(1)}, {asReference(2)}, {asReference(3)}, {asReference(4)}, {asReference(5)}}

for i := 0; i < len(origins); i++ {
t.Run(strconv.Itoa(i), func(t *testing.T) {
Expand Down Expand Up @@ -595,7 +595,7 @@ func TestCompiler_compileTableCopy(t *testing.T) {
table := make([]wasm.Reference, tableSize)
env.addTable(&wasm.TableInstance{References: table})
for i := 0; i < tableSize; i++ {
table[i] = uintptr(i)
table[i] = asReference(uint(i))
}

// Run code.
Expand All @@ -604,7 +604,7 @@ func TestCompiler_compileTableCopy(t *testing.T) {
if !tc.requireOutOfBoundsError {
exp := make([]wasm.Reference, tableSize)
for i := 0; i < tableSize; i++ {
exp[i] = uintptr(i)
exp[i] = asReference(uint(i))
}
copy(exp[tc.destOffset:],
exp[tc.sourceOffset:tc.sourceOffset+tc.size])
Expand All @@ -621,7 +621,7 @@ func TestCompiler_compileTableCopy(t *testing.T) {

func TestCompiler_compileTableInit(t *testing.T) {
elementInstances := []wasm.ElementInstance{
{}, {1, 2, 3, 4, 5},
{}, {asReference(1), asReference(2), asReference(3), asReference(4), asReference(5)},
}

const tableSize = 100
Expand Down Expand Up @@ -680,7 +680,7 @@ func TestCompiler_compileTableInit(t *testing.T) {
table := make([]wasm.Reference, tableSize)
env.addTable(&wasm.TableInstance{References: table})
for i := 0; i < tableSize; i++ {
table[i] = uintptr(i)
table[i] = asReference(uint(i))
}

code := asm.CodeSegment{}
Expand All @@ -699,7 +699,7 @@ func TestCompiler_compileTableInit(t *testing.T) {
require.Equal(t, nativeCallStatusCodeReturned, env.compilerStatus())
exp := make([]wasm.Reference, tableSize)
for i := 0; i < tableSize; i++ {
exp[i] = uintptr(i)
exp[i] = asReference(uint(i))
}
if inst := elementInstances[tc.elemIndex]; inst != nil {
copy(exp[tc.destOffset:], inst[tc.sourceOffset:tc.sourceOffset+tc.copySize])
Expand All @@ -716,19 +716,19 @@ type dog struct{ name string }

func TestCompiler_compileTableSet(t *testing.T) {
externDog := &dog{name: "sushi"}
externrefOpaque := uintptr(unsafe.Pointer(externDog))
externrefOpaque := unsafe.Pointer(externDog)
funcref := &function{moduleInstance: &wasm.ModuleInstance{}}
funcrefOpaque := uintptr(unsafe.Pointer(funcref))
funcrefOpaque := unsafe.Pointer(funcref)

externTable := &wasm.TableInstance{Type: wasm.RefTypeExternref, References: []wasm.Reference{0, 0, externrefOpaque, 0, 0}}
funcrefTable := &wasm.TableInstance{Type: wasm.RefTypeFuncref, References: []wasm.Reference{0, 0, 0, 0, funcrefOpaque}}
externTable := &wasm.TableInstance{Type: wasm.RefTypeExternref, References: []wasm.Reference{nil, nil, externrefOpaque, nil, nil}}
funcrefTable := &wasm.TableInstance{Type: wasm.RefTypeFuncref, References: []wasm.Reference{nil, nil, nil, nil, funcrefOpaque}}
tables := []*wasm.TableInstance{externTable, funcrefTable}

tests := []struct {
name string
tableIndex uint32
offset uint32
in uintptr
in unsafe.Pointer
expExtern bool
expError bool
}{
Expand All @@ -743,14 +743,14 @@ func TestCompiler_compileTableSet(t *testing.T) {
name: "externref - nil",
tableIndex: 0,
offset: 1,
in: 0,
in: nil,
expExtern: true,
},
{
name: "externref - out of bounds",
tableIndex: 0,
offset: 10,
in: 0,
in: nil,
expError: true,
},
{
Expand All @@ -764,14 +764,14 @@ func TestCompiler_compileTableSet(t *testing.T) {
name: "funcref - nil",
tableIndex: 1,
offset: 3,
in: 0,
in: nil,
expExtern: false,
},
{
name: "funcref - out of bounds",
tableIndex: 1,
offset: 100000,
in: 0,
in: nil,
expError: true,
},
}
Expand All @@ -795,7 +795,7 @@ func TestCompiler_compileTableSet(t *testing.T) {
err = compiler.compileConstI32(operationPtr(wazeroir.NewOperationConstI32(tc.offset)))
require.NoError(t, err)

err = compiler.compileConstI64(operationPtr(wazeroir.NewOperationConstI64(uint64(tc.in))))
err = compiler.compileConstI64(operationPtr(wazeroir.NewOperationConstI64(uint64(uintptr(tc.in)))))
require.NoError(t, err)

err = compiler.compileTableSet(operationPtr(wazeroir.NewOperationTableSet(tc.tableIndex)))
Expand All @@ -822,14 +822,14 @@ func TestCompiler_compileTableSet(t *testing.T) {
if tc.expExtern {
actual := dogFromPtr(externTable.References[tc.offset])
exp := externDog
if tc.in == 0 {
if tc.in == nil {
exp = nil
}
require.Equal(t, exp, actual)
} else {
actual := functionFromPtr(funcrefTable.References[tc.offset])
exp := funcref
if tc.in == 0 {
if tc.in == nil {
exp = nil
}
require.Equal(t, exp, actual)
Expand All @@ -840,36 +840,36 @@ func TestCompiler_compileTableSet(t *testing.T) {
}

//go:nocheckptr ignore "pointer arithmetic result points to invalid allocation"
func dogFromPtr(ptr uintptr) *dog {
if ptr == 0 {
func dogFromPtr(ptr unsafe.Pointer) *dog {
if ptr == nil {
return nil
}
return (*dog)(unsafe.Pointer(ptr))
return (*dog)(ptr)
}

//go:nocheckptr ignore "pointer arithmetic result points to invalid allocation"
func functionFromPtr(ptr uintptr) *function {
if ptr == 0 {
func functionFromPtr(ptr unsafe.Pointer) *function {
if ptr == nil {
return nil
}
return (*function)(unsafe.Pointer(ptr))
return (*function)(ptr)
}

func TestCompiler_compileTableGet(t *testing.T) {
externDog := &dog{name: "sushi"}
externrefOpaque := uintptr(unsafe.Pointer(externDog))
externrefOpaque := unsafe.Pointer(externDog)
funcref := &function{moduleInstance: &wasm.ModuleInstance{}}
funcrefOpaque := uintptr(unsafe.Pointer(funcref))
funcrefOpaque := unsafe.Pointer(funcref)
tables := []*wasm.TableInstance{
{Type: wasm.RefTypeExternref, References: []wasm.Reference{0, 0, externrefOpaque, 0, 0}},
{Type: wasm.RefTypeFuncref, References: []wasm.Reference{0, 0, 0, 0, funcrefOpaque}},
{Type: wasm.RefTypeExternref, References: []wasm.Reference{nil, nil, externrefOpaque, nil, nil}},
{Type: wasm.RefTypeFuncref, References: []wasm.Reference{nil, nil, nil, nil, funcrefOpaque}},
}

tests := []struct {
name string
tableIndex uint32
offset uint32
exp uintptr
exp unsafe.Pointer
expError bool
}{
{
Expand All @@ -882,7 +882,7 @@ func TestCompiler_compileTableGet(t *testing.T) {
name: "externref - nil",
tableIndex: 0,
offset: 4,
exp: 0,
exp: nil,
},
{
name: "externref - out of bounds",
Expand All @@ -900,7 +900,7 @@ func TestCompiler_compileTableGet(t *testing.T) {
name: "funcref - nil",
tableIndex: 1,
offset: 1,
exp: 0,
exp: nil,
},
{
name: "funcref - out of bounds",
Expand Down Expand Up @@ -949,7 +949,7 @@ func TestCompiler_compileTableGet(t *testing.T) {
} else {
require.Equal(t, nativeCallStatusCodeReturned, env.compilerStatus())
require.Equal(t, uint64(1), env.stackPointer())
require.Equal(t, uint64(tc.exp), env.stackTopAsUint64())
require.Equal(t, uint64(uintptr(tc.exp)), env.stackTopAsUint64())
}
})
}
Expand Down Expand Up @@ -997,3 +997,7 @@ func TestCompiler_compileRefFunc(t *testing.T) {
})
}
}

func asReference(u uint) wasm.Reference {
return unsafe.Pointer(uintptr(u))
}
24 changes: 11 additions & 13 deletions internal/engine/compiler/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -499,7 +499,8 @@ func (s nativeCallStatusCode) String() (ret string) {
}

// releaseCompiledModule is a runtime.SetFinalizer function that munmaps the compiledModule.executable.
func releaseCompiledModule(cm *compiledModule) {
func releaseCompiledModule(cm *compiledCode) {
// log.Printf("compiler: releasing compiled module %#x", cm.executable.Addr())
if err := cm.executable.Unmap(); err != nil {
// munmap failure cannot recover, and happen asynchronously on the
// finalizer thread. While finalizer functions can return errors,
Expand Down Expand Up @@ -555,7 +556,7 @@ func (e *engine) CompileModule(_ context.Context, module *wasm.Module, listeners
}

// As this uses mmap, we need to munmap on the compiled machine code when it's GCed.
e.setFinalizer(cm, releaseCompiledModule)
e.setFinalizer(cm.compiledCode, releaseCompiledModule)
ln := len(listeners)
cmp := newCompiler()
asmNodes := new(asmNodes)
Expand Down Expand Up @@ -675,7 +676,10 @@ func (e *moduleEngine) ResolveImportedMemory(wasm.ModuleEngine) {}

// FunctionInstanceReference implements the same method as documented on wasm.ModuleEngine.
func (e *moduleEngine) FunctionInstanceReference(funcIndex wasm.Index) wasm.Reference {
return uintptr(unsafe.Pointer(&e.functions[funcIndex]))
fptr := &e.functions[funcIndex]
u := unsafe.Pointer(fptr)
// log.Printf("function instance reference %#x", u)
return u
}

// DoneInstantiation implements wasm.ModuleEngine.
Expand All @@ -700,7 +704,7 @@ func (e *moduleEngine) LookupFunction(t *wasm.TableInstance, typeId wasm.Functio
panic(wasmruntime.ErrRuntimeInvalidTableAccess)
}
rawPtr := t.References[tableOffset]
if rawPtr == 0 {
if rawPtr == nil {
panic(wasmruntime.ErrRuntimeInvalidTableAccess)
}

Expand All @@ -713,14 +717,8 @@ func (e *moduleEngine) LookupFunction(t *wasm.TableInstance, typeId wasm.Functio

// functionFromUintptr resurrects the original *function from the given uintptr
// which comes from either funcref table or OpcodeRefFunc instruction.
func functionFromUintptr(ptr uintptr) *function {
// Wraps ptrs as the double pointer in order to avoid the unsafe access as detected by race detector.
//
// For example, if we have (*function)(unsafe.Pointer(ptr)) instead, then the race detector's "checkptr"
// subroutine wanrs as "checkptr: pointer arithmetic result points to invalid allocation"
// https://github.com/golang/go/blob/1ce7fcf139417d618c2730010ede2afb41664211/src/runtime/checkptr.go#L69
var wrapped *uintptr = &ptr
return *(**function)(unsafe.Pointer(wrapped))
func functionFromUintptr(ptr wasm.Reference) *function {
return (*function)(ptr)
}

// Definition implements the same method as documented on wasm.ModuleEngine.
Expand Down Expand Up @@ -1193,7 +1191,7 @@ func (ce *callEngine) builtinFunctionTableGrow(tables []*wasm.TableInstance) {
table := tables[tableIndex] // verified not to be out of range by the func validation at compilation phase.
num := ce.popValue()
ref := ce.popValue()
res := table.Grow(uint32(num), uintptr(ref))
res := table.Grow(uint32(num), unsafe.Pointer(uintptr(ref)))
ce.pushValue(uint64(res))
}

Expand Down
2 changes: 1 addition & 1 deletion internal/engine/compiler/engine_cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func (e *engine) getCompiledModule(module *wasm.Module, listeners []experimental
}

// As this uses mmap, we need to munmap on the compiled machine code when it's GCed.
e.setFinalizer(cm, releaseCompiledModule)
e.setFinalizer(cm.compiledCode, releaseCompiledModule)
}
return
}
Expand Down
17 changes: 8 additions & 9 deletions internal/engine/compiler/engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@ func requireSupportedOSArch(t *testing.T) {
}
}

type fakeFinalizer map[*compiledModule]func(module *compiledModule)
type fakeFinalizer map[*compiledCode]func(module *compiledCode)

func (f fakeFinalizer) setFinalizer(obj interface{}, finalizer interface{}) {
cf := obj.(*compiledModule)
cf := obj.(*compiledCode)
if _, ok := f[cf]; ok { // easier than adding a field for testing.T
panic(fmt.Sprintf("BUG: %v already had its finalizer set", cf))
}
f[cf] = finalizer.(func(*compiledModule))
f[cf] = finalizer.(func(*compiledCode))
}

func TestCompiler_CompileModule(t *testing.T) {
Expand Down Expand Up @@ -95,11 +95,10 @@ func TestCompiler_CompileModule(t *testing.T) {

func TestCompiler_Releasecode_Panic(t *testing.T) {
captured := require.CapturePanic(func() {
releaseCompiledModule(&compiledModule{
compiledCode: &compiledCode{
executable: makeCodeSegment(1, 2),
},
})
releaseCompiledModule(&compiledCode{
executable: makeCodeSegment(1, 2),
},
)
})
require.Contains(t, captured.Error(), "compiler: failed to munmap code segment")
}
Expand Down Expand Up @@ -241,7 +240,7 @@ func TestCallEngine_builtinFunctionTableGrow(t *testing.T) {
ce.builtinFunctionTableGrow([]*wasm.TableInstance{table})

require.Equal(t, 1, len(table.References))
require.Equal(t, uintptr(0xff), table.References[0])
require.Equal(t, unsafe.Pointer(uintptr(0xff)), table.References[0])
}

func ptrAsUint64(f *function) uint64 {
Expand Down
2 changes: 1 addition & 1 deletion internal/engine/compiler/impl_amd64_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func TestAmd64Compiler_indirectCallWithTargetOnCallingConvReg(t *testing.T) {
typeID: 0,
}
me.functions = append(me.functions, f)
table[0] = uintptr(unsafe.Pointer(&f))
table[0] = unsafe.Pointer(&f)
}

compiler := env.requireNewCompiler(t, &wasm.FunctionType{}, newCompiler, &wazeroir.CompilationResult{
Expand Down
2 changes: 1 addition & 1 deletion internal/engine/compiler/impl_arm64_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func TestArm64Compiler_indirectCallWithTargetOnCallingConvReg(t *testing.T) {
moduleInstance: env.moduleInstance,
}
me.functions = append(me.functions, f)
table[0] = uintptr(unsafe.Pointer(&f))
table[0] = unsafe.Pointer(&f)
}

compiler := env.requireNewCompiler(t, &wasm.FunctionType{}, newCompiler, &wazeroir.CompilationResult{
Expand Down
Loading
Loading