-
Notifications
You must be signed in to change notification settings - Fork 18.8k
Description
I used strings.Replace in my application to replace prefix '/cloud/app' with '/cloud/data', and got wrong result sometime.
expect: "/cloud/data/abc/abc/abc/123"
actual: some times "/cloud/app/abc/abc/abc/123" , some times "/cloud/data/abc/abc/abc/123"
Debuged 'strings.Replace' with gdb i found strings.indexShortStr return bad result, which is written with assembly language and i am not able to debug it.
summary of gdb message
strings.Replace (stirngs.go: 696) if m := Count(s, old); m == 0 {
stirngs.Count (strings.go: 85) i := Index(s[offset:], sep)
strings.Index (strings_amd64.go:42) return indexShortStr(s, sep)
strings.indexShortStr () at /home/admin/work/tj16/go/go/src/runtime/asm_amd64.s:1743
strings.Index("/cloud/app/abc/abc/abc", "/cloud/app") return an unexpected -1
cause strings.go:87 return
full gdb message
Thread 1 hit Breakpoint 1, main.main () at /home/admin/work/tj16/go/src/my_application/main/test.go:22 warning: Source file is more recent than executable.
22 fmt.Printf("replace: %s\n", strings.Replace(dir, "/cloud/app", "/cloud/data", 1))
(gdb) s
strings.Replace (s="/cloud/app/abc/abc#/abc", old="/cloud/app", new="/cloud/data", n=1, ~r4="") at /home/admin/work/tj16/go/go/src/strings/strings.go:690
warning: Source file is more recent than executable.
690 func Replace(s, old, new1 string, n int) string {
(gdb) n
691 if old == new1 || n == 0 {
(gdb) n
696 if m := Count(s, old); m == 0 {
(gdb) s
strings.Count (s="/cloud/app/abc/abc#/abc", sep="/cloud/app", ~r2=842350510104)
at /home/admin/work/tj16/go/go/src/strings/strings.go:77
77 func Count(s, sep string) int {
(gdb) n
80 if len(sep) == 0 {
(gdb) n
77 func Count(s, sep string) int {
(gdb) n
85 i := Index(s[offset:], sep)
(gdb) p s
$1 = "/cloud/app/abc/abc#/abc"
(gdb) p sep
$2 = "/cloud/app"
(gdb) s
89 n++
(gdb) n
85 i := Index(s[offset:], sep)
(gdb) s
strings.Index (s="/cloud/app/abc/abc#/abc", sep="/cloud/app", ~r2=0)
at /home/admin/work/tj16/go/go/src/strings/strings_amd64.go:25
25 func Index(s, sep string) int {
(gdb) n
28 case n == 0:
(gdb) n
30 case n == 1:
(gdb) n
32 case n == len(s):
(gdb) n
37 case n > len(s):
(gdb) n
39 case n <= shortStringLen:
(gdb) n
41 if len(s) <= 64 {
(gdb) n
42 return indexShortStr(s, sep)
(gdb) s
strings.indexShortStr () at /home/admin/work/tj16/go/go/src/runtime/asm_amd64.s:1743
1743 MOVQ s+0(FP), DI
(gdb) p s
No symbol "s" in current context.
(gdb) n
1745 MOVQ s_len+8(FP), DX
(gdb) n
1746 MOVQ c+16(FP), BP
(gdb) n
1747 MOVQ c_len+24(FP), AX
(gdb) n
1748 MOVQ DI, R10
(gdb) n
1749 LEAQ ret+32(FP), R11
(gdb) n
1750 JMP runtime·indexShortStr(SB)
(gdb) n
runtime.indexShortStr () at /home/admin/work/tj16/go/go/src/runtime/asm_amd64.s:1767
1767 CMPQ AX, DX
(gdb) n
1768 JA fail
(gdb) n
1769 CMPQ DX, $16
(gdb) n
1770 JAE sse42
(gdb) n
1970 MOVL runtime·cpuid_ecx(SB), CX
(gdb) n
1971 ANDL $0x100000, CX
(gdb) n
1972 JZ no_sse42
(gdb) n
1973 CMPQ AX, $12
(gdb) n
1978 JAE _9_or_more
(gdb) n
1979 LEAQ 16(BP), SI
(gdb) n
1980 TESTW $0xff0, SI
(gdb) n
1981 JEQ no_sse42
(gdb) n
1982 MOVOU (BP), X1
(gdb) n
1983 LEAQ -15(DI)(DX*1), SI
(gdb) n
1984 MOVQ $16, R9
(gdb) n
1985 SUBQ AX, R9 // We advance by 16-len(sep) each iteration, so precalculate it into R9
(gdb) n
1991 PCMPESTRI $0x0c, (DI), X1
(gdb) n
1995 CMPQ CX, R9
(gdb) n
1996 JBE sse42_success
(gdb) n
1997 ADDQ R9, DI
(gdb) n
1998 CMPQ DI, SI
(gdb) n
1999 JB loop_sse42
(gdb) n
1991 PCMPESTRI $0x0c, (DI), X1
(gdb) n
1995 CMPQ CX, R9
(gdb) n
1996 JBE sse42_success
(gdb) n
1997 ADDQ R9, DI
(gdb) n
1998 CMPQ DI, SI
(gdb) n
1999 JB loop_sse42
(gdb) n
1991 PCMPESTRI $0x0c, (DI), X1
(gdb) n
1995 CMPQ CX, R9
(gdb) n
1996 JBE sse42_success
(gdb) n
1997 ADDQ R9, DI
(gdb) n
1998 CMPQ DI, SI
(gdb) n
1999 JB loop_sse42
(gdb) n
1991 PCMPESTRI $0x0c, (DI), X1
(gdb) n
1995 CMPQ CX, R9
(gdb) n
1996 JBE sse42_success
(gdb) n
1997 ADDQ R9, DI
(gdb) n
1998 CMPQ DI, SI
(gdb) n
1999 JB loop_sse42
(gdb) n
1991 PCMPESTRI $0x0c, (DI), X1
(gdb) n
1995 CMPQ CX, R9
(gdb) n
1996 JBE sse42_success
(gdb) n
1997 ADDQ R9, DI
(gdb) n
1998 CMPQ DI, SI
(gdb) n
1999 JB loop_sse42
(gdb) n
2000 PCMPESTRI $0x0c, -1(SI), X1
(gdb) n
2001 CMPQ CX, R9
(gdb) n
2002 JA fail
(gdb) n
1964 MOVQ $-1, (R11)
(gdb) n
runtime.indexShortStr () at /home/admin/work/tj16/go/go/src/runtime/asm_amd64.s:1965
1965 RET
(gdb) n
strings.Count (s="/cloud/app/abc/abc#/abc", sep="/cloud/app", ~r2=842350510104)
at /home/admin/work/tj16/go/go/src/strings/strings.go:86
86 if i == -1 {
(gdb) n
87 return n
(gdb) p s
$3 = "/cloud/app/abc/abc#/abc"
(gdb) p sep
$4 = "/cloud/app"
(gdb) l
82 }
83 offset := 0
84 for {
85 i := Index(s[offset:], sep)
86 if i == -1 {
87 return n
88 }
89 n++
90 offset += i + len(sep)
91 }
What version of Go are you using (go version)?
go1.8
Does this issue reproduce with the latest release?
yes
What operating system and processor architecture are you using (go env)?
gcc version 4.1.2 20080704 (Red Hat 4.1.2-50)
cpu
model name : Intel(R) Xeon(R) CPU E5-2650 v2 @ 2.60GHz
address sizes : 46 bits physical, 48 bits virtual
What did you do?
call: strings.Replace("/cloud/app/abc/abc/abc/123", "/cloud/app", "/cloud/data", 1)
What did you expect to see?
"/cloud/data/abc/abc/abc/123"
What did you see instead?
some times "/cloud/app/abc/abc/abc/123" , some times "/cloud/data/abc/abc/abc/123"