mirror of
https://github.com/golang/go
synced 2024-11-22 08:34:40 -07:00
cmd/compile: add support for unsafe.{String,StringData,SliceData}
For #53003 Change-Id: I13a761daca8b433b271a1feb711c103d9820772d Reviewed-on: https://go-review.googlesource.com/c/go/+/423774 Reviewed-by: Heschi Kreinick <heschi@google.com> Reviewed-by: Matthew Dempsky <mdempsky@google.com> Reviewed-by: hopehook <hopehook@golangcn.org> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com> Reviewed-by: Keith Randall <khr@golang.org> Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
parent
301ca7513f
commit
c708532936
@ -180,11 +180,11 @@ func (e *escape) callCommon(ks []hole, call ir.Node, init *ir.Nodes, wrapper *ir
|
||||
argument(e.discardHole(), &call.Args[i])
|
||||
}
|
||||
|
||||
case ir.OLEN, ir.OCAP, ir.OREAL, ir.OIMAG, ir.OCLOSE:
|
||||
case ir.OLEN, ir.OCAP, ir.OREAL, ir.OIMAG, ir.OCLOSE, ir.OUNSAFESTRINGDATA, ir.OUNSAFESLICEDATA:
|
||||
call := call.(*ir.UnaryExpr)
|
||||
argument(e.discardHole(), &call.X)
|
||||
|
||||
case ir.OUNSAFEADD, ir.OUNSAFESLICE:
|
||||
case ir.OUNSAFEADD, ir.OUNSAFESLICE, ir.OUNSAFESTRING:
|
||||
call := call.(*ir.BinaryExpr)
|
||||
argument(ks[0], &call.X)
|
||||
argument(e.discardHole(), &call.Y)
|
||||
|
@ -134,7 +134,9 @@ func (e *escape) exprSkipInit(k hole, n ir.Node) {
|
||||
n := n.(*ir.UnaryExpr)
|
||||
e.discard(n.X)
|
||||
|
||||
case ir.OCALLMETH, ir.OCALLFUNC, ir.OCALLINTER, ir.OINLCALL, ir.OLEN, ir.OCAP, ir.OCOMPLEX, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.OCOPY, ir.ORECOVER, ir.OUNSAFEADD, ir.OUNSAFESLICE:
|
||||
case ir.OCALLMETH, ir.OCALLFUNC, ir.OCALLINTER, ir.OINLCALL,
|
||||
ir.OLEN, ir.OCAP, ir.OCOMPLEX, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.OCOPY, ir.ORECOVER,
|
||||
ir.OUNSAFEADD, ir.OUNSAFESLICE, ir.OUNSAFESTRING, ir.OUNSAFESTRINGDATA, ir.OUNSAFESLICEDATA:
|
||||
e.call([]hole{k}, n)
|
||||
|
||||
case ir.ONEW:
|
||||
|
@ -137,7 +137,7 @@ func (n *BinaryExpr) SetOp(op Op) {
|
||||
panic(n.no("SetOp " + op.String()))
|
||||
case OADD, OADDSTR, OAND, OANDNOT, ODIV, OEQ, OGE, OGT, OLE,
|
||||
OLSH, OLT, OMOD, OMUL, ONE, OOR, ORSH, OSUB, OXOR,
|
||||
OCOPY, OCOMPLEX, OUNSAFEADD, OUNSAFESLICE,
|
||||
OCOPY, OCOMPLEX, OUNSAFEADD, OUNSAFESLICE, OUNSAFESTRING,
|
||||
OEFACE:
|
||||
n.op = op
|
||||
}
|
||||
@ -624,6 +624,21 @@ func NewSliceHeaderExpr(pos src.XPos, typ *types.Type, ptr, len, cap Node) *Slic
|
||||
return n
|
||||
}
|
||||
|
||||
// A StringHeaderExpr expression constructs a string header from its parts.
|
||||
type StringHeaderExpr struct {
|
||||
miniExpr
|
||||
Ptr Node
|
||||
Len Node
|
||||
}
|
||||
|
||||
func NewStringHeaderExpr(pos src.XPos, ptr, len Node) *StringHeaderExpr {
|
||||
n := &StringHeaderExpr{Ptr: ptr, Len: len}
|
||||
n.pos = pos
|
||||
n.op = OSTRINGHEADER
|
||||
n.typ = types.Types[types.TSTRING]
|
||||
return n
|
||||
}
|
||||
|
||||
// A StarExpr is a dereference expression *X.
|
||||
// It may end up being a value or a type.
|
||||
type StarExpr struct {
|
||||
@ -734,7 +749,8 @@ func (n *UnaryExpr) SetOp(op Op) {
|
||||
case OBITNOT, ONEG, ONOT, OPLUS, ORECV,
|
||||
OALIGNOF, OCAP, OCLOSE, OIMAG, OLEN, ONEW,
|
||||
OOFFSETOF, OPANIC, OREAL, OSIZEOF,
|
||||
OCHECKNIL, OCFUNC, OIDATA, OITAB, OSPTR:
|
||||
OCHECKNIL, OCFUNC, OIDATA, OITAB, OSPTR,
|
||||
OUNSAFESTRINGDATA, OUNSAFESLICEDATA:
|
||||
n.op = op
|
||||
}
|
||||
}
|
||||
|
@ -88,6 +88,9 @@ var OpNames = []string{
|
||||
OSWITCH: "switch",
|
||||
OUNSAFEADD: "unsafe.Add",
|
||||
OUNSAFESLICE: "unsafe.Slice",
|
||||
OUNSAFESLICEDATA: "unsafe.SliceData",
|
||||
OUNSAFESTRING: "unsafe.String",
|
||||
OUNSAFESTRINGDATA: "unsafe.StringData",
|
||||
OXOR: "^",
|
||||
}
|
||||
|
||||
@ -212,6 +215,9 @@ var OpPrec = []int{
|
||||
OTYPE: 8,
|
||||
OUNSAFEADD: 8,
|
||||
OUNSAFESLICE: 8,
|
||||
OUNSAFESLICEDATA: 8,
|
||||
OUNSAFESTRING: 8,
|
||||
OUNSAFESTRINGDATA: 8,
|
||||
OINDEXMAP: 8,
|
||||
OINDEX: 8,
|
||||
OSLICE: 8,
|
||||
@ -220,6 +226,7 @@ var OpPrec = []int{
|
||||
OSLICE3: 8,
|
||||
OSLICE3ARR: 8,
|
||||
OSLICEHEADER: 8,
|
||||
OSTRINGHEADER: 8,
|
||||
ODOTINTER: 8,
|
||||
ODOTMETH: 8,
|
||||
ODOTPTR: 8,
|
||||
|
@ -233,6 +233,7 @@ const (
|
||||
OSLICE3 // X[Low : High : Max] (X is untypedchecked or slice)
|
||||
OSLICE3ARR // X[Low : High : Max] (X is pointer to array)
|
||||
OSLICEHEADER // sliceheader{Ptr, Len, Cap} (Ptr is unsafe.Pointer, Len is length, Cap is capacity)
|
||||
OSTRINGHEADER // stringheader{Ptr, Len} (Ptr is unsafe.Pointer, Len is length)
|
||||
ORECOVER // recover()
|
||||
ORECOVERFP // recover(Args) w/ explicit FP argument
|
||||
ORECV // <-X
|
||||
@ -246,6 +247,9 @@ const (
|
||||
OSIZEOF // unsafe.Sizeof(X)
|
||||
OUNSAFEADD // unsafe.Add(X, Y)
|
||||
OUNSAFESLICE // unsafe.Slice(X, Y)
|
||||
OUNSAFESLICEDATA // unsafe.SliceData(X)
|
||||
OUNSAFESTRING // unsafe.String(X, Y)
|
||||
OUNSAFESTRINGDATA // unsafe.StringData(X)
|
||||
OMETHEXPR // X(Args) (method expression T.Method(args), first argument is the method receiver)
|
||||
OMETHVALUE // X.Sel (method expression t.Method, not called)
|
||||
|
||||
|
@ -1146,6 +1146,34 @@ func (n *StarExpr) editChildren(edit func(Node) Node) {
|
||||
}
|
||||
}
|
||||
|
||||
func (n *StringHeaderExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *StringHeaderExpr) copy() Node {
|
||||
c := *n
|
||||
c.init = copyNodes(c.init)
|
||||
return &c
|
||||
}
|
||||
func (n *StringHeaderExpr) doChildren(do func(Node) bool) bool {
|
||||
if doNodes(n.init, do) {
|
||||
return true
|
||||
}
|
||||
if n.Ptr != nil && do(n.Ptr) {
|
||||
return true
|
||||
}
|
||||
if n.Len != nil && do(n.Len) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func (n *StringHeaderExpr) editChildren(edit func(Node) Node) {
|
||||
editNodes(n.init, edit)
|
||||
if n.Ptr != nil {
|
||||
n.Ptr = edit(n.Ptr).(Node)
|
||||
}
|
||||
if n.Len != nil {
|
||||
n.Len = edit(n.Len).(Node)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *StructKeyExpr) Format(s fmt.State, verb rune) { fmtNode(n, s, verb) }
|
||||
func (n *StructKeyExpr) copy() Node {
|
||||
c := *n
|
||||
|
@ -107,62 +107,66 @@ func _() {
|
||||
_ = x[OSLICE3-96]
|
||||
_ = x[OSLICE3ARR-97]
|
||||
_ = x[OSLICEHEADER-98]
|
||||
_ = x[ORECOVER-99]
|
||||
_ = x[ORECOVERFP-100]
|
||||
_ = x[ORECV-101]
|
||||
_ = x[ORUNESTR-102]
|
||||
_ = x[OSELRECV2-103]
|
||||
_ = x[OREAL-104]
|
||||
_ = x[OIMAG-105]
|
||||
_ = x[OCOMPLEX-106]
|
||||
_ = x[OALIGNOF-107]
|
||||
_ = x[OOFFSETOF-108]
|
||||
_ = x[OSIZEOF-109]
|
||||
_ = x[OUNSAFEADD-110]
|
||||
_ = x[OUNSAFESLICE-111]
|
||||
_ = x[OMETHEXPR-112]
|
||||
_ = x[OMETHVALUE-113]
|
||||
_ = x[OBLOCK-114]
|
||||
_ = x[OBREAK-115]
|
||||
_ = x[OCASE-116]
|
||||
_ = x[OCONTINUE-117]
|
||||
_ = x[ODEFER-118]
|
||||
_ = x[OFALL-119]
|
||||
_ = x[OFOR-120]
|
||||
_ = x[OGOTO-121]
|
||||
_ = x[OIF-122]
|
||||
_ = x[OLABEL-123]
|
||||
_ = x[OGO-124]
|
||||
_ = x[ORANGE-125]
|
||||
_ = x[ORETURN-126]
|
||||
_ = x[OSELECT-127]
|
||||
_ = x[OSWITCH-128]
|
||||
_ = x[OTYPESW-129]
|
||||
_ = x[OFUNCINST-130]
|
||||
_ = x[OINLCALL-131]
|
||||
_ = x[OEFACE-132]
|
||||
_ = x[OITAB-133]
|
||||
_ = x[OIDATA-134]
|
||||
_ = x[OSPTR-135]
|
||||
_ = x[OCFUNC-136]
|
||||
_ = x[OCHECKNIL-137]
|
||||
_ = x[ORESULT-138]
|
||||
_ = x[OINLMARK-139]
|
||||
_ = x[OLINKSYMOFFSET-140]
|
||||
_ = x[OJUMPTABLE-141]
|
||||
_ = x[ODYNAMICDOTTYPE-142]
|
||||
_ = x[ODYNAMICDOTTYPE2-143]
|
||||
_ = x[ODYNAMICTYPE-144]
|
||||
_ = x[OTAILCALL-145]
|
||||
_ = x[OGETG-146]
|
||||
_ = x[OGETCALLERPC-147]
|
||||
_ = x[OGETCALLERSP-148]
|
||||
_ = x[OEND-149]
|
||||
_ = x[OSTRINGHEADER-99]
|
||||
_ = x[ORECOVER-100]
|
||||
_ = x[ORECOVERFP-101]
|
||||
_ = x[ORECV-102]
|
||||
_ = x[ORUNESTR-103]
|
||||
_ = x[OSELRECV2-104]
|
||||
_ = x[OREAL-105]
|
||||
_ = x[OIMAG-106]
|
||||
_ = x[OCOMPLEX-107]
|
||||
_ = x[OALIGNOF-108]
|
||||
_ = x[OOFFSETOF-109]
|
||||
_ = x[OSIZEOF-110]
|
||||
_ = x[OUNSAFEADD-111]
|
||||
_ = x[OUNSAFESLICE-112]
|
||||
_ = x[OUNSAFESLICEDATA-113]
|
||||
_ = x[OUNSAFESTRING-114]
|
||||
_ = x[OUNSAFESTRINGDATA-115]
|
||||
_ = x[OMETHEXPR-116]
|
||||
_ = x[OMETHVALUE-117]
|
||||
_ = x[OBLOCK-118]
|
||||
_ = x[OBREAK-119]
|
||||
_ = x[OCASE-120]
|
||||
_ = x[OCONTINUE-121]
|
||||
_ = x[ODEFER-122]
|
||||
_ = x[OFALL-123]
|
||||
_ = x[OFOR-124]
|
||||
_ = x[OGOTO-125]
|
||||
_ = x[OIF-126]
|
||||
_ = x[OLABEL-127]
|
||||
_ = x[OGO-128]
|
||||
_ = x[ORANGE-129]
|
||||
_ = x[ORETURN-130]
|
||||
_ = x[OSELECT-131]
|
||||
_ = x[OSWITCH-132]
|
||||
_ = x[OTYPESW-133]
|
||||
_ = x[OFUNCINST-134]
|
||||
_ = x[OINLCALL-135]
|
||||
_ = x[OEFACE-136]
|
||||
_ = x[OITAB-137]
|
||||
_ = x[OIDATA-138]
|
||||
_ = x[OSPTR-139]
|
||||
_ = x[OCFUNC-140]
|
||||
_ = x[OCHECKNIL-141]
|
||||
_ = x[ORESULT-142]
|
||||
_ = x[OINLMARK-143]
|
||||
_ = x[OLINKSYMOFFSET-144]
|
||||
_ = x[OJUMPTABLE-145]
|
||||
_ = x[ODYNAMICDOTTYPE-146]
|
||||
_ = x[ODYNAMICDOTTYPE2-147]
|
||||
_ = x[ODYNAMICTYPE-148]
|
||||
_ = x[OTAILCALL-149]
|
||||
_ = x[OGETG-150]
|
||||
_ = x[OGETCALLERPC-151]
|
||||
_ = x[OGETCALLERSP-152]
|
||||
_ = x[OEND-153]
|
||||
}
|
||||
|
||||
const _Op_name = "XXXNAMENONAMETYPELITERALNILADDSUBORXORADDSTRADDRANDANDAPPENDBYTES2STRBYTES2STRTMPRUNES2STRSTR2BYTESSTR2BYTESTMPSTR2RUNESSLICE2ARRPTRASAS2AS2DOTTYPEAS2FUNCAS2MAPRAS2RECVASOPCALLCALLFUNCCALLMETHCALLINTERCAPCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVIDATACONVNOPCOPYDCLDCLFUNCDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTDEREFINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMAKESLICECOPYMULDIVMODLSHRSHANDANDNOTNEWNOTBITNOTPLUSNEGORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRSLICEHEADERRECOVERRECOVERFPRECVRUNESTRSELRECV2REALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFUNSAFEADDUNSAFESLICEMETHEXPRMETHVALUEBLOCKBREAKCASECONTINUEDEFERFALLFORGOTOIFLABELGORANGERETURNSELECTSWITCHTYPESWFUNCINSTINLCALLEFACEITABIDATASPTRCFUNCCHECKNILRESULTINLMARKLINKSYMOFFSETJUMPTABLEDYNAMICDOTTYPEDYNAMICDOTTYPE2DYNAMICTYPETAILCALLGETGGETCALLERPCGETCALLERSPEND"
|
||||
const _Op_name = "XXXNAMENONAMETYPELITERALNILADDSUBORXORADDSTRADDRANDANDAPPENDBYTES2STRBYTES2STRTMPRUNES2STRSTR2BYTESSTR2BYTESTMPSTR2RUNESSLICE2ARRPTRASAS2AS2DOTTYPEAS2FUNCAS2MAPRAS2RECVASOPCALLCALLFUNCCALLMETHCALLINTERCAPCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVIDATACONVNOPCOPYDCLDCLFUNCDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTDEREFINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMAKESLICECOPYMULDIVMODLSHRSHANDANDNOTNEWNOTBITNOTPLUSNEGORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRSLICEHEADERSTRINGHEADERRECOVERRECOVERFPRECVRUNESTRSELRECV2REALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFUNSAFEADDUNSAFESLICEUNSAFESLICEDATAUNSAFESTRINGUNSAFESTRINGDATAMETHEXPRMETHVALUEBLOCKBREAKCASECONTINUEDEFERFALLFORGOTOIFLABELGORANGERETURNSELECTSWITCHTYPESWFUNCINSTINLCALLEFACEITABIDATASPTRCFUNCCHECKNILRESULTINLMARKLINKSYMOFFSETJUMPTABLEDYNAMICDOTTYPEDYNAMICDOTTYPE2DYNAMICTYPETAILCALLGETGGETCALLERPCGETCALLERSPEND"
|
||||
|
||||
var _Op_index = [...]uint16{0, 3, 7, 13, 17, 24, 27, 30, 33, 35, 38, 44, 48, 54, 60, 69, 81, 90, 99, 111, 120, 132, 134, 137, 147, 154, 161, 168, 172, 176, 184, 192, 201, 204, 209, 216, 223, 229, 238, 246, 254, 260, 264, 273, 282, 289, 293, 296, 303, 311, 318, 324, 327, 333, 340, 348, 352, 359, 367, 369, 371, 373, 375, 377, 379, 384, 389, 397, 400, 409, 412, 416, 424, 431, 440, 453, 456, 459, 462, 465, 468, 471, 477, 480, 483, 489, 493, 496, 500, 505, 510, 516, 521, 525, 530, 538, 546, 552, 561, 572, 579, 588, 592, 599, 607, 611, 615, 622, 629, 637, 643, 652, 663, 671, 680, 685, 690, 694, 702, 707, 711, 714, 718, 720, 725, 727, 732, 738, 744, 750, 756, 764, 771, 776, 780, 785, 789, 794, 802, 808, 815, 828, 837, 851, 866, 877, 885, 889, 900, 911, 914}
|
||||
var _Op_index = [...]uint16{0, 3, 7, 13, 17, 24, 27, 30, 33, 35, 38, 44, 48, 54, 60, 69, 81, 90, 99, 111, 120, 132, 134, 137, 147, 154, 161, 168, 172, 176, 184, 192, 201, 204, 209, 216, 223, 229, 238, 246, 254, 260, 264, 273, 282, 289, 293, 296, 303, 311, 318, 324, 327, 333, 340, 348, 352, 359, 367, 369, 371, 373, 375, 377, 379, 384, 389, 397, 400, 409, 412, 416, 424, 431, 440, 453, 456, 459, 462, 465, 468, 471, 477, 480, 483, 489, 493, 496, 500, 505, 510, 516, 521, 525, 530, 538, 546, 552, 561, 572, 584, 591, 600, 604, 611, 619, 623, 627, 634, 641, 649, 655, 664, 675, 690, 702, 718, 726, 735, 740, 745, 749, 757, 762, 766, 769, 773, 775, 780, 782, 787, 793, 799, 805, 811, 819, 826, 831, 835, 840, 844, 849, 857, 863, 870, 883, 892, 906, 921, 932, 940, 944, 955, 966, 969}
|
||||
|
||||
func (i Op) String() string {
|
||||
if i >= Op(len(_Op_index)-1) {
|
||||
|
@ -900,7 +900,7 @@ func transformBuiltin(n *ir.CallExpr) ir.Node {
|
||||
transformArgs(n)
|
||||
fallthrough
|
||||
|
||||
case ir.ONEW, ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF:
|
||||
case ir.ONEW, ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF, ir.OUNSAFESLICEDATA, ir.OUNSAFESTRINGDATA:
|
||||
u := ir.NewUnaryExpr(n.Pos(), op, n.Args[0])
|
||||
u1 := typed(n.Type(), ir.InitExpr(n.Init(), u)) // typecheckargs can add to old.Init
|
||||
switch op {
|
||||
@ -913,12 +913,12 @@ func transformBuiltin(n *ir.CallExpr) ir.Node {
|
||||
case ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF:
|
||||
// This corresponds to the EvalConst() call near end of typecheck().
|
||||
return typecheck.EvalConst(u1)
|
||||
case ir.OCLOSE, ir.ONEW:
|
||||
case ir.OCLOSE, ir.ONEW, ir.OUNSAFESTRINGDATA, ir.OUNSAFESLICEDATA:
|
||||
// nothing more to do
|
||||
return u1
|
||||
}
|
||||
|
||||
case ir.OCOMPLEX, ir.OCOPY, ir.OUNSAFEADD, ir.OUNSAFESLICE:
|
||||
case ir.OCOMPLEX, ir.OCOPY, ir.OUNSAFEADD, ir.OUNSAFESLICE, ir.OUNSAFESTRING:
|
||||
transformArgs(n)
|
||||
b := ir.NewBinaryExpr(n.Pos(), op, n.Args[0], n.Args[1])
|
||||
n1 := typed(n.Type(), ir.InitExpr(n.Init(), b))
|
||||
|
@ -1460,7 +1460,7 @@ func (s *state) stmt(n ir.Node) {
|
||||
s.callResult(n, callNormal)
|
||||
if n.Op() == ir.OCALLFUNC && n.X.Op() == ir.ONAME && n.X.(*ir.Name).Class == ir.PFUNC {
|
||||
if fn := n.X.Sym().Name; base.Flag.CompilingRuntime && fn == "throw" ||
|
||||
n.X.Sym().Pkg == ir.Pkgs.Runtime && (fn == "throwinit" || fn == "gopanic" || fn == "panicwrap" || fn == "block" || fn == "panicmakeslicelen" || fn == "panicmakeslicecap" || fn == "panicunsafeslicelen" || fn == "panicunsafeslicenilptr") {
|
||||
n.X.Sym().Pkg == ir.Pkgs.Runtime && (fn == "throwinit" || fn == "gopanic" || fn == "panicwrap" || fn == "block" || fn == "panicmakeslicelen" || fn == "panicmakeslicecap" || fn == "panicunsafeslicelen" || fn == "panicunsafeslicenilptr" || fn == "panicunsafestringlen" || fn == "panicunsafestringnilptr") {
|
||||
m := s.mem()
|
||||
b := s.endBlock()
|
||||
b.Kind = ssa.BlockExit
|
||||
@ -3242,6 +3242,12 @@ func (s *state) exprCheckPtr(n ir.Node, checkPtrOK bool) *ssa.Value {
|
||||
c := s.expr(n.Cap)
|
||||
return s.newValue3(ssa.OpSliceMake, n.Type(), p, l, c)
|
||||
|
||||
case ir.OSTRINGHEADER:
|
||||
n := n.(*ir.StringHeaderExpr)
|
||||
p := s.expr(n.Ptr)
|
||||
l := s.expr(n.Len)
|
||||
return s.newValue2(ssa.OpStringMake, n.Type(), p, l)
|
||||
|
||||
case ir.OSLICE, ir.OSLICEARR, ir.OSLICE3, ir.OSLICE3ARR:
|
||||
n := n.(*ir.SliceExpr)
|
||||
check := s.checkPtrEnabled && n.Op() == ir.OSLICE3ARR && n.X.Op() == ir.OCONVNOP && n.X.(*ir.ConvExpr).X.Type().IsUnsafePtr()
|
||||
|
@ -137,76 +137,79 @@ var runtimeDecls = [...]struct {
|
||||
{"unsafeslicecheckptr", funcTag, 118},
|
||||
{"panicunsafeslicelen", funcTag, 9},
|
||||
{"panicunsafeslicenilptr", funcTag, 9},
|
||||
{"mulUintptr", funcTag, 119},
|
||||
{"memmove", funcTag, 120},
|
||||
{"memclrNoHeapPointers", funcTag, 121},
|
||||
{"memclrHasPointers", funcTag, 121},
|
||||
{"memequal", funcTag, 122},
|
||||
{"memequal0", funcTag, 123},
|
||||
{"memequal8", funcTag, 123},
|
||||
{"memequal16", funcTag, 123},
|
||||
{"memequal32", funcTag, 123},
|
||||
{"memequal64", funcTag, 123},
|
||||
{"memequal128", funcTag, 123},
|
||||
{"f32equal", funcTag, 124},
|
||||
{"f64equal", funcTag, 124},
|
||||
{"c64equal", funcTag, 124},
|
||||
{"c128equal", funcTag, 124},
|
||||
{"strequal", funcTag, 124},
|
||||
{"interequal", funcTag, 124},
|
||||
{"nilinterequal", funcTag, 124},
|
||||
{"memhash", funcTag, 125},
|
||||
{"memhash0", funcTag, 126},
|
||||
{"memhash8", funcTag, 126},
|
||||
{"memhash16", funcTag, 126},
|
||||
{"memhash32", funcTag, 126},
|
||||
{"memhash64", funcTag, 126},
|
||||
{"memhash128", funcTag, 126},
|
||||
{"f32hash", funcTag, 126},
|
||||
{"f64hash", funcTag, 126},
|
||||
{"c64hash", funcTag, 126},
|
||||
{"c128hash", funcTag, 126},
|
||||
{"strhash", funcTag, 126},
|
||||
{"interhash", funcTag, 126},
|
||||
{"nilinterhash", funcTag, 126},
|
||||
{"int64div", funcTag, 127},
|
||||
{"uint64div", funcTag, 128},
|
||||
{"int64mod", funcTag, 127},
|
||||
{"uint64mod", funcTag, 128},
|
||||
{"float64toint64", funcTag, 129},
|
||||
{"float64touint64", funcTag, 130},
|
||||
{"float64touint32", funcTag, 131},
|
||||
{"int64tofloat64", funcTag, 132},
|
||||
{"int64tofloat32", funcTag, 134},
|
||||
{"uint64tofloat64", funcTag, 135},
|
||||
{"uint64tofloat32", funcTag, 136},
|
||||
{"uint32tofloat64", funcTag, 137},
|
||||
{"complex128div", funcTag, 138},
|
||||
{"getcallerpc", funcTag, 139},
|
||||
{"getcallersp", funcTag, 139},
|
||||
{"unsafestringcheckptr", funcTag, 119},
|
||||
{"panicunsafestringlen", funcTag, 9},
|
||||
{"panicunsafestringnilptr", funcTag, 9},
|
||||
{"mulUintptr", funcTag, 120},
|
||||
{"memmove", funcTag, 121},
|
||||
{"memclrNoHeapPointers", funcTag, 122},
|
||||
{"memclrHasPointers", funcTag, 122},
|
||||
{"memequal", funcTag, 123},
|
||||
{"memequal0", funcTag, 124},
|
||||
{"memequal8", funcTag, 124},
|
||||
{"memequal16", funcTag, 124},
|
||||
{"memequal32", funcTag, 124},
|
||||
{"memequal64", funcTag, 124},
|
||||
{"memequal128", funcTag, 124},
|
||||
{"f32equal", funcTag, 125},
|
||||
{"f64equal", funcTag, 125},
|
||||
{"c64equal", funcTag, 125},
|
||||
{"c128equal", funcTag, 125},
|
||||
{"strequal", funcTag, 125},
|
||||
{"interequal", funcTag, 125},
|
||||
{"nilinterequal", funcTag, 125},
|
||||
{"memhash", funcTag, 126},
|
||||
{"memhash0", funcTag, 127},
|
||||
{"memhash8", funcTag, 127},
|
||||
{"memhash16", funcTag, 127},
|
||||
{"memhash32", funcTag, 127},
|
||||
{"memhash64", funcTag, 127},
|
||||
{"memhash128", funcTag, 127},
|
||||
{"f32hash", funcTag, 127},
|
||||
{"f64hash", funcTag, 127},
|
||||
{"c64hash", funcTag, 127},
|
||||
{"c128hash", funcTag, 127},
|
||||
{"strhash", funcTag, 127},
|
||||
{"interhash", funcTag, 127},
|
||||
{"nilinterhash", funcTag, 127},
|
||||
{"int64div", funcTag, 128},
|
||||
{"uint64div", funcTag, 129},
|
||||
{"int64mod", funcTag, 128},
|
||||
{"uint64mod", funcTag, 129},
|
||||
{"float64toint64", funcTag, 130},
|
||||
{"float64touint64", funcTag, 131},
|
||||
{"float64touint32", funcTag, 132},
|
||||
{"int64tofloat64", funcTag, 133},
|
||||
{"int64tofloat32", funcTag, 135},
|
||||
{"uint64tofloat64", funcTag, 136},
|
||||
{"uint64tofloat32", funcTag, 137},
|
||||
{"uint32tofloat64", funcTag, 138},
|
||||
{"complex128div", funcTag, 139},
|
||||
{"getcallerpc", funcTag, 140},
|
||||
{"getcallersp", funcTag, 140},
|
||||
{"racefuncenter", funcTag, 31},
|
||||
{"racefuncexit", funcTag, 9},
|
||||
{"raceread", funcTag, 31},
|
||||
{"racewrite", funcTag, 31},
|
||||
{"racereadrange", funcTag, 140},
|
||||
{"racewriterange", funcTag, 140},
|
||||
{"msanread", funcTag, 140},
|
||||
{"msanwrite", funcTag, 140},
|
||||
{"msanmove", funcTag, 141},
|
||||
{"asanread", funcTag, 140},
|
||||
{"asanwrite", funcTag, 140},
|
||||
{"checkptrAlignment", funcTag, 142},
|
||||
{"checkptrArithmetic", funcTag, 144},
|
||||
{"libfuzzerTraceCmp1", funcTag, 145},
|
||||
{"libfuzzerTraceCmp2", funcTag, 146},
|
||||
{"libfuzzerTraceCmp4", funcTag, 147},
|
||||
{"libfuzzerTraceCmp8", funcTag, 148},
|
||||
{"libfuzzerTraceConstCmp1", funcTag, 145},
|
||||
{"libfuzzerTraceConstCmp2", funcTag, 146},
|
||||
{"libfuzzerTraceConstCmp4", funcTag, 147},
|
||||
{"libfuzzerTraceConstCmp8", funcTag, 148},
|
||||
{"libfuzzerHookStrCmp", funcTag, 149},
|
||||
{"libfuzzerHookEqualFold", funcTag, 149},
|
||||
{"racereadrange", funcTag, 141},
|
||||
{"racewriterange", funcTag, 141},
|
||||
{"msanread", funcTag, 141},
|
||||
{"msanwrite", funcTag, 141},
|
||||
{"msanmove", funcTag, 142},
|
||||
{"asanread", funcTag, 141},
|
||||
{"asanwrite", funcTag, 141},
|
||||
{"checkptrAlignment", funcTag, 143},
|
||||
{"checkptrArithmetic", funcTag, 145},
|
||||
{"libfuzzerTraceCmp1", funcTag, 146},
|
||||
{"libfuzzerTraceCmp2", funcTag, 147},
|
||||
{"libfuzzerTraceCmp4", funcTag, 148},
|
||||
{"libfuzzerTraceCmp8", funcTag, 149},
|
||||
{"libfuzzerTraceConstCmp1", funcTag, 146},
|
||||
{"libfuzzerTraceConstCmp2", funcTag, 147},
|
||||
{"libfuzzerTraceConstCmp4", funcTag, 148},
|
||||
{"libfuzzerTraceConstCmp8", funcTag, 149},
|
||||
{"libfuzzerHookStrCmp", funcTag, 150},
|
||||
{"libfuzzerHookEqualFold", funcTag, 150},
|
||||
{"x86HasPOPCNT", varTag, 6},
|
||||
{"x86HasSSE41", varTag, 6},
|
||||
{"x86HasFMA", varTag, 6},
|
||||
@ -230,7 +233,7 @@ func params(tlist ...*types.Type) []*types.Field {
|
||||
}
|
||||
|
||||
func runtimeTypes() []*types.Type {
|
||||
var typs [150]*types.Type
|
||||
var typs [151]*types.Type
|
||||
typs[0] = types.ByteType
|
||||
typs[1] = types.NewPtr(typs[0])
|
||||
typs[2] = types.Types[types.TANY]
|
||||
@ -350,36 +353,37 @@ func runtimeTypes() []*types.Type {
|
||||
typs[116] = types.NewSlice(typs[2])
|
||||
typs[117] = newSig(params(typs[1], typs[116], typs[15]), params(typs[116]))
|
||||
typs[118] = newSig(params(typs[1], typs[7], typs[22]), nil)
|
||||
typs[119] = newSig(params(typs[5], typs[5]), params(typs[5], typs[6]))
|
||||
typs[120] = newSig(params(typs[3], typs[3], typs[5]), nil)
|
||||
typs[121] = newSig(params(typs[7], typs[5]), nil)
|
||||
typs[122] = newSig(params(typs[3], typs[3], typs[5]), params(typs[6]))
|
||||
typs[123] = newSig(params(typs[3], typs[3]), params(typs[6]))
|
||||
typs[124] = newSig(params(typs[7], typs[7]), params(typs[6]))
|
||||
typs[125] = newSig(params(typs[7], typs[5], typs[5]), params(typs[5]))
|
||||
typs[126] = newSig(params(typs[7], typs[5]), params(typs[5]))
|
||||
typs[127] = newSig(params(typs[22], typs[22]), params(typs[22]))
|
||||
typs[128] = newSig(params(typs[24], typs[24]), params(typs[24]))
|
||||
typs[129] = newSig(params(typs[20]), params(typs[22]))
|
||||
typs[130] = newSig(params(typs[20]), params(typs[24]))
|
||||
typs[131] = newSig(params(typs[20]), params(typs[62]))
|
||||
typs[132] = newSig(params(typs[22]), params(typs[20]))
|
||||
typs[133] = types.Types[types.TFLOAT32]
|
||||
typs[134] = newSig(params(typs[22]), params(typs[133]))
|
||||
typs[135] = newSig(params(typs[24]), params(typs[20]))
|
||||
typs[136] = newSig(params(typs[24]), params(typs[133]))
|
||||
typs[137] = newSig(params(typs[62]), params(typs[20]))
|
||||
typs[138] = newSig(params(typs[26], typs[26]), params(typs[26]))
|
||||
typs[139] = newSig(nil, params(typs[5]))
|
||||
typs[140] = newSig(params(typs[5], typs[5]), nil)
|
||||
typs[141] = newSig(params(typs[5], typs[5], typs[5]), nil)
|
||||
typs[142] = newSig(params(typs[7], typs[1], typs[5]), nil)
|
||||
typs[143] = types.NewSlice(typs[7])
|
||||
typs[144] = newSig(params(typs[7], typs[143]), nil)
|
||||
typs[145] = newSig(params(typs[66], typs[66], typs[15]), nil)
|
||||
typs[146] = newSig(params(typs[60], typs[60], typs[15]), nil)
|
||||
typs[147] = newSig(params(typs[62], typs[62], typs[15]), nil)
|
||||
typs[148] = newSig(params(typs[24], typs[24], typs[15]), nil)
|
||||
typs[149] = newSig(params(typs[28], typs[28], typs[15]), nil)
|
||||
typs[119] = newSig(params(typs[7], typs[22]), nil)
|
||||
typs[120] = newSig(params(typs[5], typs[5]), params(typs[5], typs[6]))
|
||||
typs[121] = newSig(params(typs[3], typs[3], typs[5]), nil)
|
||||
typs[122] = newSig(params(typs[7], typs[5]), nil)
|
||||
typs[123] = newSig(params(typs[3], typs[3], typs[5]), params(typs[6]))
|
||||
typs[124] = newSig(params(typs[3], typs[3]), params(typs[6]))
|
||||
typs[125] = newSig(params(typs[7], typs[7]), params(typs[6]))
|
||||
typs[126] = newSig(params(typs[7], typs[5], typs[5]), params(typs[5]))
|
||||
typs[127] = newSig(params(typs[7], typs[5]), params(typs[5]))
|
||||
typs[128] = newSig(params(typs[22], typs[22]), params(typs[22]))
|
||||
typs[129] = newSig(params(typs[24], typs[24]), params(typs[24]))
|
||||
typs[130] = newSig(params(typs[20]), params(typs[22]))
|
||||
typs[131] = newSig(params(typs[20]), params(typs[24]))
|
||||
typs[132] = newSig(params(typs[20]), params(typs[62]))
|
||||
typs[133] = newSig(params(typs[22]), params(typs[20]))
|
||||
typs[134] = types.Types[types.TFLOAT32]
|
||||
typs[135] = newSig(params(typs[22]), params(typs[134]))
|
||||
typs[136] = newSig(params(typs[24]), params(typs[20]))
|
||||
typs[137] = newSig(params(typs[24]), params(typs[134]))
|
||||
typs[138] = newSig(params(typs[62]), params(typs[20]))
|
||||
typs[139] = newSig(params(typs[26], typs[26]), params(typs[26]))
|
||||
typs[140] = newSig(nil, params(typs[5]))
|
||||
typs[141] = newSig(params(typs[5], typs[5]), nil)
|
||||
typs[142] = newSig(params(typs[5], typs[5], typs[5]), nil)
|
||||
typs[143] = newSig(params(typs[7], typs[1], typs[5]), nil)
|
||||
typs[144] = types.NewSlice(typs[7])
|
||||
typs[145] = newSig(params(typs[7], typs[144]), nil)
|
||||
typs[146] = newSig(params(typs[66], typs[66], typs[15]), nil)
|
||||
typs[147] = newSig(params(typs[60], typs[60], typs[15]), nil)
|
||||
typs[148] = newSig(params(typs[62], typs[62], typs[15]), nil)
|
||||
typs[149] = newSig(params(typs[24], typs[24], typs[15]), nil)
|
||||
typs[150] = newSig(params(typs[28], typs[28], typs[15]), nil)
|
||||
return typs[:]
|
||||
}
|
||||
|
@ -183,6 +183,9 @@ func growslice(typ *byte, old []any, cap int) (ary []any)
|
||||
func unsafeslicecheckptr(typ *byte, ptr unsafe.Pointer, len int64)
|
||||
func panicunsafeslicelen()
|
||||
func panicunsafeslicenilptr()
|
||||
func unsafestringcheckptr(ptr unsafe.Pointer, len int64)
|
||||
func panicunsafestringlen()
|
||||
func panicunsafestringnilptr()
|
||||
|
||||
func mulUintptr(x, y uintptr) (uintptr, bool)
|
||||
|
||||
|
@ -758,7 +758,10 @@ func callOrChan(n ir.Node) bool {
|
||||
ir.ORECOVER,
|
||||
ir.ORECV,
|
||||
ir.OUNSAFEADD,
|
||||
ir.OUNSAFESLICE:
|
||||
ir.OUNSAFESLICE,
|
||||
ir.OUNSAFESLICEDATA,
|
||||
ir.OUNSAFESTRING,
|
||||
ir.OUNSAFESTRINGDATA:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
@ -659,6 +659,40 @@ func tcLenCap(n *ir.UnaryExpr) ir.Node {
|
||||
return n
|
||||
}
|
||||
|
||||
// tcUnsafeData typechecks an OUNSAFESLICEDATA or OUNSAFESTRINGDATA node.
|
||||
func tcUnsafeData(n *ir.UnaryExpr) ir.Node {
|
||||
n.X = Expr(n.X)
|
||||
n.X = DefaultLit(n.X, nil)
|
||||
l := n.X
|
||||
t := l.Type()
|
||||
if t == nil {
|
||||
n.SetType(nil)
|
||||
return n
|
||||
}
|
||||
|
||||
var kind types.Kind
|
||||
if n.Op() == ir.OUNSAFESLICEDATA {
|
||||
kind = types.TSLICE
|
||||
} else {
|
||||
/* kind is string */
|
||||
kind = types.TSTRING
|
||||
}
|
||||
|
||||
if t.Kind() != kind {
|
||||
base.Errorf("invalid argument %L for %v", l, n.Op())
|
||||
n.SetType(nil)
|
||||
return n
|
||||
}
|
||||
|
||||
if kind == types.TSTRING {
|
||||
t = types.ByteType
|
||||
} else {
|
||||
t = t.Elem()
|
||||
}
|
||||
n.SetType(types.NewPtr(t))
|
||||
return n
|
||||
}
|
||||
|
||||
// tcRecv typechecks an ORECV node.
|
||||
func tcRecv(n *ir.UnaryExpr) ir.Node {
|
||||
n.X = Expr(n.X)
|
||||
@ -812,6 +846,31 @@ func tcSliceHeader(n *ir.SliceHeaderExpr) ir.Node {
|
||||
return n
|
||||
}
|
||||
|
||||
// tcStringHeader typechecks an OSTRINGHEADER node.
|
||||
func tcStringHeader(n *ir.StringHeaderExpr) ir.Node {
|
||||
t := n.Type()
|
||||
if t == nil {
|
||||
base.Fatalf("no type specified for OSTRINGHEADER")
|
||||
}
|
||||
|
||||
if !t.IsString() {
|
||||
base.Fatalf("invalid type %v for OSTRINGHEADER", n.Type())
|
||||
}
|
||||
|
||||
if n.Ptr == nil || n.Ptr.Type() == nil || !n.Ptr.Type().IsUnsafePtr() {
|
||||
base.Fatalf("need unsafe.Pointer for OSTRINGHEADER")
|
||||
}
|
||||
|
||||
n.Ptr = Expr(n.Ptr)
|
||||
n.Len = DefaultLit(Expr(n.Len), types.Types[types.TINT])
|
||||
|
||||
if ir.IsConst(n.Len, constant.Int) && ir.Int64Val(n.Len) < 0 {
|
||||
base.Fatalf("len for OSTRINGHEADER must be non-negative")
|
||||
}
|
||||
|
||||
return n
|
||||
}
|
||||
|
||||
// tcStar typechecks an ODEREF node, which may be an expression or a type.
|
||||
func tcStar(n *ir.StarExpr, top int) ir.Node {
|
||||
n.X = typecheck(n.X, ctxExpr|ctxType)
|
||||
|
@ -299,7 +299,7 @@ func tcCall(n *ir.CallExpr, top int) ir.Node {
|
||||
n.SetTypecheck(0) // re-typechecking new op is OK, not a loop
|
||||
return typecheck(n, top)
|
||||
|
||||
case ir.OCAP, ir.OCLOSE, ir.OIMAG, ir.OLEN, ir.OPANIC, ir.OREAL:
|
||||
case ir.OCAP, ir.OCLOSE, ir.OIMAG, ir.OLEN, ir.OPANIC, ir.OREAL, ir.OUNSAFESTRINGDATA, ir.OUNSAFESLICEDATA:
|
||||
typecheckargs(n)
|
||||
fallthrough
|
||||
case ir.ONEW, ir.OALIGNOF, ir.OOFFSETOF, ir.OSIZEOF:
|
||||
@ -311,7 +311,7 @@ func tcCall(n *ir.CallExpr, top int) ir.Node {
|
||||
u := ir.NewUnaryExpr(n.Pos(), l.BuiltinOp, arg)
|
||||
return typecheck(ir.InitExpr(n.Init(), u), top) // typecheckargs can add to old.Init
|
||||
|
||||
case ir.OCOMPLEX, ir.OCOPY, ir.OUNSAFEADD, ir.OUNSAFESLICE:
|
||||
case ir.OCOMPLEX, ir.OCOPY, ir.OUNSAFEADD, ir.OUNSAFESLICE, ir.OUNSAFESTRING:
|
||||
typecheckargs(n)
|
||||
arg1, arg2, ok := needTwoArgs(n)
|
||||
if !ok {
|
||||
@ -907,10 +907,31 @@ func tcUnsafeSlice(n *ir.BinaryExpr) *ir.BinaryExpr {
|
||||
base.Errorf("unsafe.Slice of incomplete (or unallocatable) type not allowed")
|
||||
}
|
||||
|
||||
if !checkunsafeslice(&n.Y) {
|
||||
if !checkunsafesliceorstring(n.Op(), &n.Y) {
|
||||
n.SetType(nil)
|
||||
return n
|
||||
}
|
||||
n.SetType(types.NewSlice(t.Elem()))
|
||||
return n
|
||||
}
|
||||
|
||||
// tcUnsafeString typechecks an OUNSAFESTRING node.
|
||||
func tcUnsafeString(n *ir.BinaryExpr) *ir.BinaryExpr {
|
||||
n.X = Expr(n.X)
|
||||
n.Y = Expr(n.Y)
|
||||
if n.X.Type() == nil || n.Y.Type() == nil {
|
||||
n.SetType(nil)
|
||||
return n
|
||||
}
|
||||
t := n.X.Type()
|
||||
if !t.IsPtr() || !types.Identical(t.Elem(), types.Types[types.TUINT8]) {
|
||||
base.Errorf("first argument to unsafe.String must be *byte; have %L", t)
|
||||
}
|
||||
|
||||
if !checkunsafesliceorstring(n.Op(), &n.Y) {
|
||||
n.SetType(nil)
|
||||
return n
|
||||
}
|
||||
n.SetType(types.Types[types.TSTRING])
|
||||
return n
|
||||
}
|
||||
|
@ -1964,7 +1964,7 @@ func (w *exportWriter) expr(n ir.Node) {
|
||||
w.expr(n.Max)
|
||||
w.typ(n.Type())
|
||||
|
||||
case ir.OCOPY, ir.OCOMPLEX, ir.OUNSAFEADD, ir.OUNSAFESLICE:
|
||||
case ir.OCOPY, ir.OCOMPLEX, ir.OUNSAFEADD, ir.OUNSAFESLICE, ir.OUNSAFESTRING:
|
||||
// treated like other builtin calls (see e.g., OREAL)
|
||||
n := n.(*ir.BinaryExpr)
|
||||
w.op(n.Op())
|
||||
@ -1982,7 +1982,7 @@ func (w *exportWriter) expr(n ir.Node) {
|
||||
w.expr(n.X)
|
||||
w.bool(n.Implicit())
|
||||
|
||||
case ir.OREAL, ir.OIMAG, ir.OCAP, ir.OCLOSE, ir.OLEN, ir.ONEW, ir.OPANIC:
|
||||
case ir.OREAL, ir.OIMAG, ir.OCAP, ir.OCLOSE, ir.OLEN, ir.ONEW, ir.OPANIC, ir.OUNSAFESTRINGDATA, ir.OUNSAFESLICEDATA:
|
||||
n := n.(*ir.UnaryExpr)
|
||||
w.op(n.Op())
|
||||
w.pos(n.Pos())
|
||||
|
@ -1494,16 +1494,18 @@ func (r *importReader) node() ir.Node {
|
||||
n.SetImplicit(r.bool())
|
||||
return n
|
||||
|
||||
case ir.OCOPY, ir.OCOMPLEX, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.OCAP, ir.OCLOSE, ir.ODELETE, ir.OLEN, ir.OMAKE, ir.ONEW, ir.OPANIC, ir.ORECOVER, ir.OPRINT, ir.OPRINTN, ir.OUNSAFEADD, ir.OUNSAFESLICE:
|
||||
case ir.OCOPY, ir.OCOMPLEX, ir.OREAL, ir.OIMAG, ir.OAPPEND, ir.OCAP, ir.OCLOSE, ir.ODELETE, ir.OLEN, ir.OMAKE,
|
||||
ir.ONEW, ir.OPANIC, ir.ORECOVER, ir.OPRINT, ir.OPRINTN,
|
||||
ir.OUNSAFEADD, ir.OUNSAFESLICE, ir.OUNSAFESLICEDATA, ir.OUNSAFESTRING, ir.OUNSAFESTRINGDATA:
|
||||
pos := r.pos()
|
||||
switch op {
|
||||
case ir.OCOPY, ir.OCOMPLEX, ir.OUNSAFEADD, ir.OUNSAFESLICE:
|
||||
case ir.OCOPY, ir.OCOMPLEX, ir.OUNSAFEADD, ir.OUNSAFESLICE, ir.OUNSAFESTRING:
|
||||
init := r.stmtList()
|
||||
n := ir.NewBinaryExpr(pos, op, r.expr(), r.expr())
|
||||
n.SetInit(init)
|
||||
n.SetType(r.typ())
|
||||
return n
|
||||
case ir.OREAL, ir.OIMAG, ir.OCAP, ir.OCLOSE, ir.OLEN, ir.ONEW, ir.OPANIC:
|
||||
case ir.OREAL, ir.OIMAG, ir.OCAP, ir.OCLOSE, ir.OLEN, ir.ONEW, ir.OPANIC, ir.OUNSAFESTRINGDATA, ir.OUNSAFESLICEDATA:
|
||||
n := ir.NewUnaryExpr(pos, op, r.expr())
|
||||
if op != ir.OPANIC {
|
||||
n.SetType(r.typ())
|
||||
|
@ -610,6 +610,10 @@ func typecheck1(n ir.Node, top int) ir.Node {
|
||||
n := n.(*ir.SliceHeaderExpr)
|
||||
return tcSliceHeader(n)
|
||||
|
||||
case ir.OSTRINGHEADER:
|
||||
n := n.(*ir.StringHeaderExpr)
|
||||
return tcStringHeader(n)
|
||||
|
||||
case ir.OMAKESLICECOPY:
|
||||
n := n.(*ir.MakeExpr)
|
||||
return tcMakeSliceCopy(n)
|
||||
@ -692,6 +696,18 @@ func typecheck1(n ir.Node, top int) ir.Node {
|
||||
n := n.(*ir.BinaryExpr)
|
||||
return tcUnsafeSlice(n)
|
||||
|
||||
case ir.OUNSAFESLICEDATA:
|
||||
n := n.(*ir.UnaryExpr)
|
||||
return tcUnsafeData(n)
|
||||
|
||||
case ir.OUNSAFESTRING:
|
||||
n := n.(*ir.BinaryExpr)
|
||||
return tcUnsafeString(n)
|
||||
|
||||
case ir.OUNSAFESTRINGDATA:
|
||||
n := n.(*ir.UnaryExpr)
|
||||
return tcUnsafeData(n)
|
||||
|
||||
case ir.OCLOSURE:
|
||||
n := n.(*ir.ClosureExpr)
|
||||
return tcClosure(n, top)
|
||||
@ -1647,11 +1663,11 @@ func checkmake(t *types.Type, arg string, np *ir.Node) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// checkunsafeslice is like checkmake but for unsafe.Slice.
|
||||
func checkunsafeslice(np *ir.Node) bool {
|
||||
// checkunsafesliceorstring is like checkmake but for unsafe.{Slice,String}.
|
||||
func checkunsafesliceorstring(op ir.Op, np *ir.Node) bool {
|
||||
n := *np
|
||||
if !n.Type().IsInteger() && n.Type().Kind() != types.TIDEAL {
|
||||
base.Errorf("non-integer len argument in unsafe.Slice - %v", n.Type())
|
||||
base.Errorf("non-integer len argument in %v - %v", op, n.Type())
|
||||
return false
|
||||
}
|
||||
|
||||
@ -1660,11 +1676,11 @@ func checkunsafeslice(np *ir.Node) bool {
|
||||
if n.Op() == ir.OLITERAL {
|
||||
v := toint(n.Val())
|
||||
if constant.Sign(v) < 0 {
|
||||
base.Errorf("negative len argument in unsafe.Slice")
|
||||
base.Errorf("negative len argument in %v", op)
|
||||
return false
|
||||
}
|
||||
if ir.ConstOverflow(v, types.Types[types.TINT]) {
|
||||
base.Errorf("len argument too large in unsafe.Slice")
|
||||
base.Errorf("len argument too large in %v", op)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
@ -58,6 +58,9 @@ var unsafeFuncs = [...]struct {
|
||||
{"Offsetof", ir.OOFFSETOF},
|
||||
{"Sizeof", ir.OSIZEOF},
|
||||
{"Slice", ir.OUNSAFESLICE},
|
||||
{"SliceData", ir.OUNSAFESLICEDATA},
|
||||
{"String", ir.OUNSAFESTRING},
|
||||
{"StringData", ir.OUNSAFESTRINGDATA},
|
||||
}
|
||||
|
||||
// InitUniverse initializes the universe block.
|
||||
|
@ -642,6 +642,14 @@ func walkRecoverFP(nn *ir.CallExpr, init *ir.Nodes) ir.Node {
|
||||
return mkcall("gorecover", nn.Type(), init, walkExpr(nn.Args[0], init))
|
||||
}
|
||||
|
||||
// walkUnsafeData walks an OUNSAFESLICEDATA or OUNSAFESTRINGDATA expression.
|
||||
func walkUnsafeData(n *ir.UnaryExpr, init *ir.Nodes) ir.Node {
|
||||
slice := walkExpr(n.X, init)
|
||||
res := typecheck.Expr(ir.NewUnaryExpr(n.Pos(), ir.OSPTR, slice))
|
||||
res.SetType(n.Type())
|
||||
return walkExpr(res, init)
|
||||
}
|
||||
|
||||
func walkUnsafeSlice(n *ir.BinaryExpr, init *ir.Nodes) ir.Node {
|
||||
ptr := safeExpr(n.X, init)
|
||||
len := safeExpr(n.Y, init)
|
||||
@ -731,6 +739,64 @@ func walkUnsafeSlice(n *ir.BinaryExpr, init *ir.Nodes) ir.Node {
|
||||
return walkExpr(typecheck.Expr(h), init)
|
||||
}
|
||||
|
||||
func walkUnsafeString(n *ir.BinaryExpr, init *ir.Nodes) ir.Node {
|
||||
ptr := safeExpr(n.X, init)
|
||||
len := safeExpr(n.Y, init)
|
||||
|
||||
lenType := types.Types[types.TINT64]
|
||||
unsafePtr := typecheck.Conv(ptr, types.Types[types.TUNSAFEPTR])
|
||||
|
||||
// If checkptr enabled, call runtime.unsafestringcheckptr to check ptr and len.
|
||||
// for simplicity, unsafestringcheckptr always uses int64.
|
||||
// Type checking guarantees that TIDEAL len are positive and fit in an int.
|
||||
if ir.ShouldCheckPtr(ir.CurFunc, 1) {
|
||||
fnname := "unsafestringcheckptr"
|
||||
fn := typecheck.LookupRuntime(fnname)
|
||||
init.Append(mkcall1(fn, nil, init, unsafePtr, typecheck.Conv(len, lenType)))
|
||||
} else {
|
||||
// Otherwise, open code unsafe.String to prevent runtime call overhead.
|
||||
// Keep this code in sync with runtime.unsafestring{,64}
|
||||
if len.Type().IsKind(types.TIDEAL) || len.Type().Size() <= types.Types[types.TUINT].Size() {
|
||||
lenType = types.Types[types.TINT]
|
||||
} else {
|
||||
// len64 := int64(len)
|
||||
// if int64(int(len64)) != len64 {
|
||||
// panicunsafestringlen()
|
||||
// }
|
||||
len64 := typecheck.Conv(len, lenType)
|
||||
nif := ir.NewIfStmt(base.Pos, nil, nil, nil)
|
||||
nif.Cond = ir.NewBinaryExpr(base.Pos, ir.ONE, typecheck.Conv(typecheck.Conv(len64, types.Types[types.TINT]), lenType), len64)
|
||||
nif.Body.Append(mkcall("panicunsafestringlen", nil, &nif.Body))
|
||||
appendWalkStmt(init, nif)
|
||||
}
|
||||
|
||||
// if len < 0 { panicunsafestringlen() }
|
||||
nif := ir.NewIfStmt(base.Pos, nil, nil, nil)
|
||||
nif.Cond = ir.NewBinaryExpr(base.Pos, ir.OLT, typecheck.Conv(len, lenType), ir.NewInt(0))
|
||||
nif.Body.Append(mkcall("panicunsafestringlen", nil, &nif.Body))
|
||||
appendWalkStmt(init, nif)
|
||||
|
||||
// if uintpr(len) > -uintptr(ptr) {
|
||||
// if ptr == nil {
|
||||
// panicunsafestringnilptr()
|
||||
// }
|
||||
// panicunsafeslicelen()
|
||||
// }
|
||||
nifLen := ir.NewIfStmt(base.Pos, nil, nil, nil)
|
||||
nifLen.Cond = ir.NewBinaryExpr(base.Pos, ir.OGT, typecheck.Conv(len, types.Types[types.TUINTPTR]), ir.NewUnaryExpr(base.Pos, ir.ONEG, typecheck.Conv(unsafePtr, types.Types[types.TUINTPTR])))
|
||||
nifPtr := ir.NewIfStmt(base.Pos, nil, nil, nil)
|
||||
nifPtr.Cond = ir.NewBinaryExpr(base.Pos, ir.OEQ, unsafePtr, typecheck.NodNil())
|
||||
nifPtr.Body.Append(mkcall("panicunsafestringnilptr", nil, &nifPtr.Body))
|
||||
nifLen.Body.Append(nifPtr, mkcall("panicunsafestringlen", nil, &nifLen.Body))
|
||||
appendWalkStmt(init, nifLen)
|
||||
}
|
||||
h := ir.NewStringHeaderExpr(n.Pos(),
|
||||
typecheck.Conv(ptr, types.Types[types.TUNSAFEPTR]),
|
||||
typecheck.Conv(len, types.Types[types.TINT]),
|
||||
)
|
||||
return walkExpr(typecheck.Expr(h), init)
|
||||
}
|
||||
|
||||
func badtype(op ir.Op, tl, tr *types.Type) {
|
||||
var s string
|
||||
if tl != nil {
|
||||
|
@ -129,6 +129,14 @@ func walkExpr1(n ir.Node, init *ir.Nodes) ir.Node {
|
||||
n := n.(*ir.BinaryExpr)
|
||||
return walkUnsafeSlice(n, init)
|
||||
|
||||
case ir.OUNSAFESTRING:
|
||||
n := n.(*ir.BinaryExpr)
|
||||
return walkUnsafeString(n, init)
|
||||
|
||||
case ir.OUNSAFESTRINGDATA, ir.OUNSAFESLICEDATA:
|
||||
n := n.(*ir.UnaryExpr)
|
||||
return walkUnsafeData(n, init)
|
||||
|
||||
case ir.ODOT, ir.ODOTPTR:
|
||||
n := n.(*ir.SelectorExpr)
|
||||
return walkDot(n, init)
|
||||
@ -244,6 +252,10 @@ func walkExpr1(n ir.Node, init *ir.Nodes) ir.Node {
|
||||
n := n.(*ir.SliceHeaderExpr)
|
||||
return walkSliceHeader(n, init)
|
||||
|
||||
case ir.OSTRINGHEADER:
|
||||
n := n.(*ir.StringHeaderExpr)
|
||||
return walkStringHeader(n, init)
|
||||
|
||||
case ir.OSLICE, ir.OSLICEARR, ir.OSLICESTR, ir.OSLICE3, ir.OSLICE3ARR:
|
||||
n := n.(*ir.SliceExpr)
|
||||
return walkSlice(n, init)
|
||||
@ -849,6 +861,13 @@ func walkSliceHeader(n *ir.SliceHeaderExpr, init *ir.Nodes) ir.Node {
|
||||
return n
|
||||
}
|
||||
|
||||
// walkStringHeader walks an OSTRINGHEADER node.
|
||||
func walkStringHeader(n *ir.StringHeaderExpr, init *ir.Nodes) ir.Node {
|
||||
n.Ptr = walkExpr(n.Ptr, init)
|
||||
n.Len = walkExpr(n.Len, init)
|
||||
return n
|
||||
}
|
||||
|
||||
// TODO(josharian): combine this with its caller and simplify
|
||||
func reduceSlice(n *ir.SliceExpr) ir.Node {
|
||||
if n.High != nil && n.High.Op() == ir.OLEN && ir.SameSafeExpr(n.X, n.High.(*ir.UnaryExpr).X) {
|
||||
|
@ -342,7 +342,7 @@ func mayCall(n ir.Node) bool {
|
||||
ir.OCAP, ir.OIMAG, ir.OLEN, ir.OREAL,
|
||||
ir.OCONVNOP, ir.ODOT,
|
||||
ir.OCFUNC, ir.OIDATA, ir.OITAB, ir.OSPTR,
|
||||
ir.OBYTES2STRTMP, ir.OGETG, ir.OGETCALLERPC, ir.OGETCALLERSP, ir.OSLICEHEADER:
|
||||
ir.OBYTES2STRTMP, ir.OGETG, ir.OGETCALLERPC, ir.OGETCALLERSP, ir.OSLICEHEADER, ir.OSTRINGHEADER:
|
||||
// ok: operations that don't require function calls.
|
||||
// Expand as needed.
|
||||
}
|
||||
|
@ -39,6 +39,8 @@ func TestCheckPtr(t *testing.T) {
|
||||
{"CheckPtrSmall", "fatal error: checkptr: pointer arithmetic computed bad pointer value\n"},
|
||||
{"CheckPtrSliceOK", ""},
|
||||
{"CheckPtrSliceFail", "fatal error: checkptr: unsafe.Slice result straddles multiple allocations\n"},
|
||||
{"CheckPtrStringOK", ""},
|
||||
{"CheckPtrStringFail", "fatal error: checkptr: unsafe.String result straddles multiple allocations\n"},
|
||||
}
|
||||
|
||||
for _, tc := range testCases {
|
||||
|
@ -123,54 +123,6 @@ func mulUintptr(a, b uintptr) (uintptr, bool) {
|
||||
return math.MulUintptr(a, b)
|
||||
}
|
||||
|
||||
// Keep this code in sync with cmd/compile/internal/walk/builtin.go:walkUnsafeSlice
|
||||
func unsafeslice(et *_type, ptr unsafe.Pointer, len int) {
|
||||
if len < 0 {
|
||||
panicunsafeslicelen()
|
||||
}
|
||||
|
||||
if et.size == 0 {
|
||||
if ptr == nil && len > 0 {
|
||||
panicunsafeslicenilptr()
|
||||
}
|
||||
}
|
||||
|
||||
mem, overflow := math.MulUintptr(et.size, uintptr(len))
|
||||
if overflow || mem > -uintptr(ptr) {
|
||||
if ptr == nil {
|
||||
panicunsafeslicenilptr()
|
||||
}
|
||||
panicunsafeslicelen()
|
||||
}
|
||||
}
|
||||
|
||||
// Keep this code in sync with cmd/compile/internal/walk/builtin.go:walkUnsafeSlice
|
||||
func unsafeslice64(et *_type, ptr unsafe.Pointer, len64 int64) {
|
||||
len := int(len64)
|
||||
if int64(len) != len64 {
|
||||
panicunsafeslicelen()
|
||||
}
|
||||
unsafeslice(et, ptr, len)
|
||||
}
|
||||
|
||||
func unsafeslicecheckptr(et *_type, ptr unsafe.Pointer, len64 int64) {
|
||||
unsafeslice64(et, ptr, len64)
|
||||
|
||||
// Check that underlying array doesn't straddle multiple heap objects.
|
||||
// unsafeslice64 has already checked for overflow.
|
||||
if checkptrStraddles(ptr, uintptr(len64)*et.size) {
|
||||
throw("checkptr: unsafe.Slice result straddles multiple allocations")
|
||||
}
|
||||
}
|
||||
|
||||
func panicunsafeslicelen() {
|
||||
panic(errorString("unsafe.Slice: len out of range"))
|
||||
}
|
||||
|
||||
func panicunsafeslicenilptr() {
|
||||
panic(errorString("unsafe.Slice: ptr is nil and len is not zero"))
|
||||
}
|
||||
|
||||
// growslice handles slice growth during append.
|
||||
// It is passed the slice element type, the old slice, and the desired new minimum capacity,
|
||||
// and it returns a new slice with at least that capacity, with the old data
|
||||
|
13
src/runtime/testdata/testprog/checkptr.go
vendored
13
src/runtime/testdata/testprog/checkptr.go
vendored
@ -20,6 +20,8 @@ func init() {
|
||||
register("CheckPtrSmall", CheckPtrSmall)
|
||||
register("CheckPtrSliceOK", CheckPtrSliceOK)
|
||||
register("CheckPtrSliceFail", CheckPtrSliceFail)
|
||||
register("CheckPtrStringOK", CheckPtrStringOK)
|
||||
register("CheckPtrStringFail", CheckPtrStringFail)
|
||||
register("CheckPtrAlignmentNested", CheckPtrAlignmentNested)
|
||||
}
|
||||
|
||||
@ -98,6 +100,17 @@ func CheckPtrSliceFail() {
|
||||
sink2 = unsafe.Slice(p, 100)
|
||||
}
|
||||
|
||||
func CheckPtrStringOK() {
|
||||
p := new([4]byte)
|
||||
sink2 = unsafe.String(&p[1], 3)
|
||||
}
|
||||
|
||||
func CheckPtrStringFail() {
|
||||
p := new(byte)
|
||||
sink2 = p
|
||||
sink2 = unsafe.String(p, 100)
|
||||
}
|
||||
|
||||
func CheckPtrAlignmentNested() {
|
||||
s := make([]int8, 100)
|
||||
p := unsafe.Pointer(&s[0])
|
||||
|
98
src/runtime/unsafe.go
Normal file
98
src/runtime/unsafe.go
Normal file
@ -0,0 +1,98 @@
|
||||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package runtime
|
||||
|
||||
import (
|
||||
"runtime/internal/math"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func unsafestring(ptr unsafe.Pointer, len int) {
|
||||
if len < 0 {
|
||||
panicunsafestringlen()
|
||||
}
|
||||
|
||||
if uintptr(len) > -uintptr(ptr) {
|
||||
if ptr == nil {
|
||||
panicunsafestringnilptr()
|
||||
}
|
||||
panicunsafestringlen()
|
||||
}
|
||||
}
|
||||
|
||||
// Keep this code in sync with cmd/compile/internal/walk/builtin.go:walkUnsafeString
|
||||
func unsafestring64(ptr unsafe.Pointer, len64 int64) {
|
||||
len := int(len64)
|
||||
if int64(len) != len64 {
|
||||
panicunsafestringlen()
|
||||
}
|
||||
unsafestring(ptr, len)
|
||||
}
|
||||
|
||||
func unsafestringcheckptr(ptr unsafe.Pointer, len64 int64) {
|
||||
unsafestring64(ptr, len64)
|
||||
|
||||
// Check that underlying array doesn't straddle multiple heap objects.
|
||||
// unsafestring64 has already checked for overflow.
|
||||
if checkptrStraddles(ptr, uintptr(len64)) {
|
||||
throw("checkptr: unsafe.String result straddles multiple allocations")
|
||||
}
|
||||
}
|
||||
|
||||
func panicunsafestringlen() {
|
||||
panic(errorString("unsafe.String: len out of range"))
|
||||
}
|
||||
|
||||
func panicunsafestringnilptr() {
|
||||
panic(errorString("unsafe.String: ptr is nil and len is not zero"))
|
||||
}
|
||||
|
||||
// Keep this code in sync with cmd/compile/internal/walk/builtin.go:walkUnsafeSlice
|
||||
func unsafeslice(et *_type, ptr unsafe.Pointer, len int) {
|
||||
if len < 0 {
|
||||
panicunsafeslicelen()
|
||||
}
|
||||
|
||||
if et.size == 0 {
|
||||
if ptr == nil && len > 0 {
|
||||
panicunsafeslicenilptr()
|
||||
}
|
||||
}
|
||||
|
||||
mem, overflow := math.MulUintptr(et.size, uintptr(len))
|
||||
if overflow || mem > -uintptr(ptr) {
|
||||
if ptr == nil {
|
||||
panicunsafeslicenilptr()
|
||||
}
|
||||
panicunsafeslicelen()
|
||||
}
|
||||
}
|
||||
|
||||
// Keep this code in sync with cmd/compile/internal/walk/builtin.go:walkUnsafeSlice
|
||||
func unsafeslice64(et *_type, ptr unsafe.Pointer, len64 int64) {
|
||||
len := int(len64)
|
||||
if int64(len) != len64 {
|
||||
panicunsafeslicelen()
|
||||
}
|
||||
unsafeslice(et, ptr, len)
|
||||
}
|
||||
|
||||
func unsafeslicecheckptr(et *_type, ptr unsafe.Pointer, len64 int64) {
|
||||
unsafeslice64(et, ptr, len64)
|
||||
|
||||
// Check that underlying array doesn't straddle multiple heap objects.
|
||||
// unsafeslice64 has already checked for overflow.
|
||||
if checkptrStraddles(ptr, uintptr(len64)*et.size) {
|
||||
throw("checkptr: unsafe.Slice result straddles multiple allocations")
|
||||
}
|
||||
}
|
||||
|
||||
func panicunsafeslicelen() {
|
||||
panic(errorString("unsafe.Slice: len out of range"))
|
||||
}
|
||||
|
||||
func panicunsafeslicenilptr() {
|
||||
panic(errorString("unsafe.Slice: ptr is nil and len is not zero"))
|
||||
}
|
22
test/unsafe_slice_data.go
Normal file
22
test/unsafe_slice_data.go
Normal file
@ -0,0 +1,22 @@
|
||||
// run
|
||||
|
||||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var s = []byte("abc")
|
||||
sh1 := *(*reflect.SliceHeader)(unsafe.Pointer(&s))
|
||||
ptr2 := unsafe.Pointer(unsafe.SliceData(s))
|
||||
if ptr2 != unsafe.Pointer(sh1.Data) {
|
||||
panic(fmt.Errorf("unsafe.SliceData %p != %p", ptr2, unsafe.Pointer(sh1.Data)))
|
||||
}
|
||||
}
|
18
test/unsafe_string.go
Normal file
18
test/unsafe_string.go
Normal file
@ -0,0 +1,18 @@
|
||||
// run
|
||||
|
||||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func main() {
|
||||
hello := [5]byte{'m', 'o', 's', 'h', 'i'}
|
||||
if unsafe.String(&hello[0], uint64(len(hello))) != "moshi" {
|
||||
panic("unsafe.String convert error")
|
||||
}
|
||||
}
|
22
test/unsafe_string_data.go
Normal file
22
test/unsafe_string_data.go
Normal file
@ -0,0 +1,22 @@
|
||||
// run
|
||||
|
||||
// Copyright 2022 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var s = "abc"
|
||||
sh1 := (*reflect.StringHeader)(unsafe.Pointer(&s))
|
||||
ptr2 := unsafe.Pointer(unsafe.StringData(s))
|
||||
if ptr2 != unsafe.Pointer(sh1.Data) {
|
||||
panic(fmt.Errorf("unsafe.StringData ret %p != %p", ptr2, unsafe.Pointer(sh1.Data)))
|
||||
}
|
||||
}
|
@ -53,6 +53,44 @@ func main() {
|
||||
_ = unsafe.Slice(last, 1)
|
||||
mustPanic(func() { _ = unsafe.Slice(last, 2) })
|
||||
}
|
||||
|
||||
// unsafe.String
|
||||
{
|
||||
s := unsafe.String(&p[0], len(p))
|
||||
assert(s == string(p[:]))
|
||||
assert(len(s) == len(p))
|
||||
|
||||
// the empty string
|
||||
assert(unsafe.String(nil, 0) == "")
|
||||
|
||||
// nil pointer with positive length panics
|
||||
mustPanic(func() { _ = unsafe.String(nil, 1) })
|
||||
|
||||
// negative length
|
||||
var neg int = -1
|
||||
mustPanic(func() { _ = unsafe.String(new(byte), neg) })
|
||||
|
||||
// length too large
|
||||
var tooBig uint64 = math.MaxUint64
|
||||
mustPanic(func() { _ = unsafe.String(new(byte), tooBig) })
|
||||
|
||||
// string memory overflows address space
|
||||
last := (*byte)(unsafe.Pointer(^uintptr(0)))
|
||||
_ = unsafe.String(last, 1)
|
||||
mustPanic(func() { _ = unsafe.String(last, 2) })
|
||||
}
|
||||
|
||||
// unsafe.StringData
|
||||
{
|
||||
var s = "string"
|
||||
assert(string(unsafe.Slice(unsafe.StringData(s), len(s))) == s)
|
||||
}
|
||||
|
||||
//unsafe.SliceData
|
||||
{
|
||||
var s = []byte("slice")
|
||||
assert(unsafe.String(unsafe.SliceData(s), len(s)) == string(s))
|
||||
}
|
||||
}
|
||||
|
||||
func assert(ok bool) {
|
||||
|
Loading…
Reference in New Issue
Block a user