mirror of
https://github.com/go-delve/delve.git
synced 2025-10-28 04:35:19 +08:00
proc: correctly truncate the result of binary ops on integers (#2463)
Truncates the result of binary operations on integers to the size of the resulting type. Also rewrites convertInt to not require allocations. Fixes #2454
This commit is contained in:
committed by
GitHub
parent
db291698e0
commit
32946b2d7c
@ -3,7 +3,6 @@ package proc
|
||||
import (
|
||||
"bytes"
|
||||
"debug/dwarf"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
@ -905,17 +904,14 @@ func (scope *EvalScope) evalTypeCast(node *ast.CallExpr) (*Variable, error) {
|
||||
}
|
||||
|
||||
func convertInt(n uint64, signed bool, size int64) uint64 {
|
||||
buf := make([]byte, 64/8)
|
||||
binary.BigEndian.PutUint64(buf, n)
|
||||
m := 64/8 - int(size)
|
||||
s := byte(0)
|
||||
if signed && (buf[m]&0x80 > 0) {
|
||||
s = 0xff
|
||||
bits := uint64(size) * 8
|
||||
mask := uint64((1 << bits) - 1)
|
||||
r := n & mask
|
||||
if signed && (r>>(bits-1)) != 0 {
|
||||
// sign extension
|
||||
r |= ^uint64(0) &^ mask
|
||||
}
|
||||
for i := 0; i < m; i++ {
|
||||
buf[i] = s
|
||||
}
|
||||
return uint64(binary.BigEndian.Uint64(buf))
|
||||
return r
|
||||
}
|
||||
|
||||
func (scope *EvalScope) evalBuiltinCall(node *ast.CallExpr) (*Variable, error) {
|
||||
@ -1636,8 +1632,15 @@ func (scope *EvalScope) evalBinary(node *ast.BinaryExpr) (*Variable, error) {
|
||||
|
||||
r := xv.newVariable("", 0, typ, scope.Mem)
|
||||
r.Value = rc
|
||||
if r.Kind == reflect.String {
|
||||
switch r.Kind {
|
||||
case reflect.String:
|
||||
r.Len = xv.Len + yv.Len
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
n, _ := constant.Int64Val(r.Value)
|
||||
r.Value = constant.MakeInt64(int64(convertInt(uint64(n), true, typ.Size())))
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
|
||||
n, _ := constant.Uint64Val(r.Value)
|
||||
r.Value = constant.MakeUint64(convertInt(n, false, typ.Size()))
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
@ -73,3 +73,26 @@ func TestAlignAddr(t *testing.T) {
|
||||
c(example.align, example.in+0x10000, example.tgt+0x10000)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConvertInt(t *testing.T) {
|
||||
var testCases = []struct {
|
||||
in uint64
|
||||
signed bool
|
||||
size int64
|
||||
tgt uint64
|
||||
}{
|
||||
{1, false, 1, 1},
|
||||
{uint64(0xf0), true, 1, 0xfffffffffffffff0},
|
||||
{uint64(0xf0), false, 1, 0xf0},
|
||||
{uint64(0x70), true, 1, 0x70},
|
||||
{uint64(0x90f0), true, 2, 0xffffffffffff90f0},
|
||||
{uint64(0x90f0), false, 2, 0x90f0},
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
out := convertInt(tc.in, tc.signed, tc.size)
|
||||
t.Logf("in=%#016x signed=%v size=%d -> %#016x\n", tc.in, tc.signed, tc.size, out)
|
||||
if out != tc.tgt {
|
||||
t.Errorf("expected=%#016x got=%#016x\n", tc.tgt, out)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -836,6 +836,10 @@ func TestEvalExpression(t *testing.T) {
|
||||
{`iface2map.(data)`, false, "…", "…", "map[string]interface {}", nil},
|
||||
|
||||
{"issue1578", false, "main.Block {cache: *main.Cache nil}", "main.Block {cache: *main.Cache nil}", "main.Block", nil},
|
||||
{"ni8 << 2", false, "-20", "-20", "int8", nil},
|
||||
{"ni8 << 8", false, "0", "0", "int8", nil},
|
||||
{"ni8 >> 1", false, "-3", "-3", "int8", nil},
|
||||
{"bytearray[0] * bytearray[0]", false, "144", "144", "uint8", nil},
|
||||
}
|
||||
|
||||
ver, _ := goversion.Parse(runtime.Version())
|
||||
|
||||
Reference in New Issue
Block a user