Home  >  Article  >  Backend Development  >  Why *(*string)(unsafe.Pointer(&b)) doesn't work with bufio.Reader

Why *(*string)(unsafe.Pointer(&b)) doesn't work with bufio.Reader

王林
王林forward
2024-02-09 19:54:17988browse

为什么 *(*string)(unsafe.Pointer(&b)) 不适用于 bufio.Reader

In the Go language, we often use type conversion to convert data types. For example, convert a slice of type []byte to a string of type string. Normally, we can use the `string()` function to perform type conversion, but in some special cases, this method can cause problems. In the Go language, the `(string)(unsafe.Pointer(&b))` method is called the "magic pointer" method, which is used to convert a []byte type slice into a string type string. However, this method does not work for the bufio.Reader type. why? Let's answer this question.

Question content

I have a file. It has some ip

1.1.1.0/24
1.1.2.0/24
2.2.1.0/24
2.2.2.0/24

I read this file for slicing and parse the []byte into string using *(*string)(unsafe.pointer(&b)) but it doesn't work

func testinitiprangefromfile(t *testing.t) {
   filepath := "/tmp/test"
   file, err := os.open(filepath)
   if err != nil {
      t.errorf("failed to open ip range file:%s, err:%s", filepath, err)
   }
   reader := bufio.newreader(file)
   ranges := make([]string, 0)
   for {
      ip, _, err := reader.readline()
      if err != nil {
         if err == io.eof {
            break
         }
         logger.fatalf("failed to read ip range file, err:%s", err)
      }
      t.logf("ip:%s", *(*string)(unsafe.pointer(&ip)))
      ranges = append(ranges, *(*string)(unsafe.pointer(&ip)))
   }

   t.logf("%v", ranges)
}

result:

task_test.go:71: ip:1.1.1.0/24
    task_test.go:71: ip:1.1.2.0/24
    task_test.go:71: ip:2.2.1.0/24
    task_test.go:71: ip:2.2.2.0/24
    task_test.go:75: [2.2.2.0/24 1.1.2.0/24 2.2.1.0/24 2.2.2.0/24]

Why is 1.1.1.0/24 changed to 2.2.2.0/24?

Change

*(*string)(unsafe.Pointer(&ip))

to string(ip) it works

Workaround

So while reinterpreting the slice header as a string header, the way you did it is absolutely crazy , and cannot be guaranteed to work properly, but this is only an indirect cause of the problem. p>

The real problem is that you retain a pointer to the return value of bufio/Reader.ReadLine() but the documentation for that method says "The returned buffer is only valid until the next call to ReadLine." This means that the reader is free to reuse that memory later, which is what is happening.

When you do the conversion the right way, string(ip), Go copies the contents of the buffer into a newly created string that will still be valid in the future. However, when you type a slice pun into a string, you retain the exact same pointer, which stops working once the reader refills its buffer.

If you decide to use pointer tricking as a performance hack to avoid copies and allocations...that's too bad. The reader interface forces you to copy the data anyway, so you should just use string().

The above is the detailed content of Why *(*string)(unsafe.Pointer(&b)) doesn't work with bufio.Reader. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:stackoverflow.com. If there is any infringement, please contact admin@php.cn delete