Skip to content

unexpect panic:Embedded type's unexported interface methods have nil function pointers #1597

@luoliwoshang

Description

@luoliwoshang

Summary

When a type embeds another type from a different package to implement an interface that has unexported methods, the interface method table (itab) contains nil function pointers for those unexported methods. This causes a runtime panic when the interface method is called.

Root Cause

In ssa/abitype.go:426-434, when generating the method table for a type, unexported methods from other packages have their Ifn_ (interface function pointer) set to nil:

if !token.IsExported(mName) {
    name = b.Str(abi.FullName(mPkg, mName)).impl
    skipfn = PathOf(mPkg) != pkgPath  // true when method is from another package
}
// ...
if skipfn {
    tfn = prog.Nil(prog.VoidPtr()).impl
    ifn = tfn  // nil!
}

This means when go/types.(*Scope).Insert calls obj.setParent(s) (an unexported interface method), it attempts to call a nil function pointer.

Minimal Reproduction

package main

import (
      "go/token"
      "go/types"
)

// wrappedFunc embeds *types.Func to implement types.Object
type wrappedFunc struct {
      *types.Func
}

func main() {
      pkg := types.NewPackage("test", "test")
      scope := pkg.Scope()

      // Create a types.Func
      sig := types.NewSignatureType(nil, nil, nil, nil, nil, false)
      fn := types.NewFunc(token.NoPos, pkg, "testFunc", sig)

      // Wrap it
      wrapped := &wrappedFunc{Func: fn}

      // Convert to types.Object interface
      var obj types.Object = wrapped

      // This crashes because setParent (unexported method) has nil function pointer
      scope.Insert(obj)

      println("OK")
}

Steps to Reproduce

llgo run main.go

Expected Behavior

Program prints "OK" and exits normally.

Actual Behavior

panic: runtime error: invalid memory address or nil pointer dereference

[... go/types.(*Scope).Insert+0x18 ...]

Analysis

The types.Object interface has 17 methods (8 exported + 9 unexported). When *wrappedFunc implements this interface through embedding *types.Func:

  • Exported methods (Name, String, etc.): Work correctly, have valid function pointers
  • Unexported methods (setParent, setType, etc.): Have Ifn_ = 0x0 because they're from go/types package

When scope.Insert(obj) internally calls obj.setParent(s), it reads the nil function pointer from the itab and crashes.

Environment

  • llgo version: latest main branch
  • Go version: 1.24
  • OS: macOS (arm64)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions