Skip to content

strings: Replace return wrong result on some machines #21585

@galric

Description

@galric

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"

Metadata

Metadata

Assignees

No one assigned

    Labels

    FrozenDueToAgeNeedsInvestigationSomeone must examine and confirm this is a valid issue and not a duplicate of an existing one.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions