// genConv generates constraints for the conversion operation conv. func (a *analysis) genConv(conv *ssa.Convert, cgn *cgnode) { res := a.valueNode(conv) if res == 0 { return // result is non-pointerlike } tSrc := conv.X.Type() tDst := conv.Type() switch utSrc := tSrc.Underlying().(type) { case *types.Slice: // []byte/[]rune -> string? return case *types.Pointer: // *T -> unsafe.Pointer? if tDst.Underlying() == tUnsafePtr { return // we don't model unsafe aliasing (unsound) } case *types.Basic: switch tDst.Underlying().(type) { case *types.Pointer: // Treat unsafe.Pointer->*T conversions like // new(T) and create an unaliased object. if utSrc == tUnsafePtr { obj := a.addNodes(mustDeref(tDst), "unsafe.Pointer conversion") a.endObject(obj, cgn, conv) a.addressOf(tDst, res, obj) return } case *types.Slice: // string -> []byte/[]rune (or named aliases)? if utSrc.Info()&types.IsString != 0 { obj := a.addNodes(sliceToArray(tDst), "convert") a.endObject(obj, cgn, conv) a.addressOf(tDst, res, obj) return } case *types.Basic: // All basic-to-basic type conversions are no-ops. // This includes uintptr<->unsafe.Pointer conversions, // which we (unsoundly) ignore. return } } panic(fmt.Sprintf("illegal *ssa.Convert %s -> %s: %s", tSrc, tDst, conv.Parent())) }
// genConv generates constraints for the conversion operation conv. func (a *analysis) genConv(conv *ssa.Convert, cgn *cgnode) { res := a.valueNode(conv) if res == 0 { return // result is non-pointerlike } tSrc := conv.X.Type() tDst := conv.Type() switch utSrc := tSrc.Underlying().(type) { case *types.Slice: // []byte/[]rune -> string? return case *types.Pointer: // *T -> unsafe.Pointer? if tDst.Underlying() == tUnsafePtr { // ignore for now // a.copy(res, a.valueNode(conv.X), 1) return } case *types.Basic: switch utDst := tDst.Underlying().(type) { case *types.Pointer: // unsafe.Pointer -> *T? (currently unsound) if utSrc == tUnsafePtr { // For now, suppress unsafe.Pointer conversion // warnings on "syscall" package. // TODO(adonovan): audit for soundness. if conv.Parent().Pkg.Object.Path() != "syscall" { a.warnf(conv.Pos(), "unsound: %s contains an unsafe.Pointer conversion (to %s)", conv.Parent(), tDst) } // For now, we treat unsafe.Pointer->*T // conversion like new(T) and create an // unaliased object. In future we may handle // unsafe conversions soundly; see TODO file. obj := a.addNodes(mustDeref(tDst), "unsafe.Pointer conversion") a.endObject(obj, cgn, conv) a.addressOf(tDst, res, obj) return } case *types.Slice: // string -> []byte/[]rune (or named aliases)? if utSrc.Info()&types.IsString != 0 { obj := a.addNodes(sliceToArray(tDst), "convert") a.endObject(obj, cgn, conv) a.addressOf(tDst, res, obj) return } case *types.Basic: // TODO(adonovan): // unsafe.Pointer -> uintptr? // uintptr -> unsafe.Pointer // // The language doesn't adequately specify the // behaviour of these operations, but almost // all uses of these conversions (even in the // spec) seem to imply a non-moving garbage // collection strategy, or implicit "pinning" // semantics for unsafe.Pointer conversions. // TODO(adonovan): we need more work before we can handle // cryptopointers well. if utSrc == tUnsafePtr || utDst == tUnsafePtr { // Ignore for now. See TODO file for ideas. return } return // ignore all other basic type conversions } } panic(fmt.Sprintf("illegal *ssa.Convert %s -> %s: %s", tSrc, tDst, conv.Parent())) }