Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What are the types of boundary checks for Go

2025-03-27 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

This article mainly talks about "what are the types of boundary check of Go". Interested friends may wish to take a look. The method introduced in this paper is simple, fast and practical. Let's let the editor take you to learn "what are the types of boundary checks for Go"?

1. What is a boundary check?

Boundary check, English name Bounds Check Elimination, abbreviated as BCE. It is a check method in Go language to prevent arrays and slices from crossing boundaries and causing memory insecurity. If you check that the subscript is out of bounds, a Panic is generated.

Boundary checking allows our code to run safely, but on the other hand, it also makes our code slightly less efficient.

For example, the following code does three boundary checks

Package main func f (s [] int) {_ = s [0] / / check the first time _ = s [1] / / check the second time _ = s [2] / / check the third time} func main () {}

You might be curious, three times? How did I know it had to be checked three times.

In fact, all you have to do is add parameters at compile time, and the command is as follows

$go build-gcflags= "- d=ssa/check_bce/debug=1" main.go # command-line-arguments. / main.go:4:7: Found IsInBounds. / main.go:5:7: Found IsInBounds. / main.go:6:7: Found IsInBounds2. What are the conditions of the border check?

Not all indexing operations on arrays and slices require boundary checking.

For example, in the following example, there is no need for boundary checking, because the compiler already knows according to the context, how long the slice s is and what your termination index is, it can immediately determine whether it has crossed the boundary, so there is no need for boundary checking, because you already know whether this place will panic or not at the time of compilation.

Package main func f () {s: = [] int {1, func main 2, 3, 4} _ = s [: 9] / / No boundary check is required} func main () {}

Therefore, it can be concluded that boundary checking is required for index operations that cannot determine whether they are out of bounds at compile time, such as this.

Package main func f (s [] int) {_ = s [: 9] / / requires boundary check} func main () {} 3. Special case of boundary inspection 3.1 case 1

In the following sample code, since index 2 has checked at the top to see if it is out of bounds, the smart compiler can infer that subsequent indexes 0 and 1 no longer need to be checked

Package main func f (s [] int) {_ = s [2] / / check once _ = s [1] / / will not check _ = s [0] / / will not check} func main () {} 3.2 case 2

In the following example, code that can be logically guaranteed not to cross the bounds is also not checked for cross-bounds.

Package main func f (s [] int) {for index, _: = range s {_ = s [index] _ = s [: index+1] _ = s [index: len (s)]}} func main () {} 3.3 case 3

In the following sample code, although the length and capacity of the array can be determined, the index is a random number obtained through the rand.Intn () function, and the index value is uncertain from the compiler's point of view, which may be greater than or less than the length of the array.

So the first time it needs to be checked, and after the first check, the second index can be logically inferred, so there will be no more boundary checking.

Package main import ("math/rand") func f () {s: = make ([] int, 3,3) index: = rand.Intn (3) _ = s [: index] / / first check _ = s [index:] / / will not check} func main () {}

However, if you change the above code slightly to make the length and capacity of the slice different, the result will be different again.

Package main import ("math/rand") func f () {s: = make ([] int, 3,5) index: = rand.Intn (3) _ = s [: index] / / first check _ = s [index:] / / second check} func main () {}

Only when the length and capacity of the array are equal,: index is established, can we definitely deduce index: is also true, in that case, we only need to do a check.

Once the length and capacity of the array are not equal, then in the eyes of the compiler, index may be larger than the length of the array, or even larger than the capacity of the array.

We assume that the random number obtained by index is 4, then it is greater than the length of the array, and s [: index] can succeed, but s [index:] will fail, so a second boundary check is necessary.

You might say, isn't the maximum value of index 3? How could it be 4?

You should know that when compiling, the compiler does not know that the maximum value of index is 3.

Make a brief summary

When the length and capacity of the array are equal, the establishment of s [: index] ensures that s [index:] is also true, because it only needs to be checked once.

When the length and capacity of the array are different, the establishment of s [: index] does not guarantee that s [index:] is also true, because it has to be checked twice.

3.4 case IV

With the above groundwork, let's take a look at the following example. Because the array is a parameter passed in by the caller, the compiler does not know whether the length and capacity of the array are equal, so it can only be safe to check both.

Package main import ("math/rand") func f (s [] int, index int) {_ = s [: index] / / first check _ = s [index:] / / second check} func main () {}

But if you reverse the order of the two expressions, you only need to do a check, and I won't repeat the reasons.

Package main import ("math/rand") func f (s [] int, index int) {_ = s [index:] / / first check _ = s [: index] / / No need to check} func main () {} 5. Actively eliminate boundary check

Although the compiler has worked very hard to eliminate some boundary checks that should be eliminated, there will inevitably be some omissions.

This requires "cooperation between the police and the public". For those scenarios that have not been taken into account by the compiler, but developers are striving for the running efficiency of the program, they can use some tips to give some hints and tell the compiler where they do not have to do boundary checks.

For example, the following example, from the logic of the code, there is no need to do boundary checking, but the compiler is not so smart, in fact, every for loop, it has to do a boundary check, which is a waste of performance.

Package main func f (is [] int, bs [] byte) {if len (is) > = 256 {for _, n: = range bs {_ = is [n] / / each loop needs a boundary check} func main () {}

You can try to add the sentence is = is [: 256] before the for loop to tell the compiler that the length of the new is is 256, and the maximum index value is 255, which will not exceed the maximum value of byte, because is [n] is logically bound.

Package main func f (is [] int, bs [] byte) {if len (is) > = 256{ is = is [: 256] for _, n: = range bs {_ = is [n] / / there is no need for boundary check} func main () {} so far, I believe you have a better understanding of "what are the types of border checks of Go"? You might as well do it in practice. Here is the website, more related content can enter the relevant channels to inquire, follow us, continue to learn!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 263

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report