summaryrefslogtreecommitdiff
path: root/vendor/github.com/ccoveille/go-safecast/README.md
blob: 171a5bb3b2f760ca738d67b9aaa9db52cbe5422b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# 🪄 go-safecast: safe numbers conversion

[![Go Report Card](https://goreportcard.com/badge/github.com/ccoveille/go-safecast)](https://goreportcard.com/report/github.com/ccoveille/go-safecast)
[![GoDoc](https://godoc.org/github.com/ccoVeille/go-safecast?status.svg)](https://godoc.org/github.com/ccoVeille/go-safecast)
[![codecov](https://codecov.io/gh/ccoVeille/go-safecast/graph/badge.svg?token=VW0VO503U6)](https://codecov.io/gh/ccoVeille/go-safecast)
[![Code Climate](https://codeclimate.com/github/ccoVeille/go-safecast.png)](https://codeclimate.com/github/ccoVeille/go-safecast)
[![Go Imports](https://img.shields.io/github/search?query=%22%5C%22github.com%2Fccoveille%2Fgo-safecast%5C%22%22%20language%3Ago%20%20-is%3Afork%20-is%3Aarchived%20&label=Go%20imports)](https://github.com/search?q=%22%5C%22github.com%2Fccoveille%2Fgo-safecast%5C%22%22+language%3Ago++-is%3Afork+-is%3Aarchived+&type=code)
![GitHub Repo stars](https://img.shields.io/github/stars/ccoveille/go-safecast)

go-safecast solves the type conversion issues in Go

In Go, integer type conversion can lead to a silent and unexpected behavior and errors if not handled carefully.

This package helps to convert any number to another, and report an error when if there would be a [loss or overflow in the conversion](#conversion-issues)

## Usage

```go
package main

import (
  "fmt"
  "math"

  "github.com/ccoveille/go-safecast"
)

func main() {
  var a int

  a = 42
  b, err := safecast.ToUint8(a) // everything is fine
  if err != nil {
    fmt.Println(err)
  }
  fmt.Println(b)
  // Output: 42

  a = 255 + 1
  _, err = safecast.ToUint8(a) // 256 is greater than uint8 maximum value
  if err != nil {
    fmt.Println(err)
    // Output: conversion issue: 256 (int) is greater than 255 (uint8): maximum value for this type exceeded
  }

  a = -1
  _, err = safecast.ToUint8(a) // -1 cannot fit in uint8
  if err != nil {
    fmt.Println(err)
    // Output: conversion issue: -1 (int) is less than 0 (uint8): minimum value for this type exceeded
  }

  str := "\x99" // ASCII code 153 for Trademark symbol
  e := str[0]
  _, err = safecast.ToInt8(e)
  if err != nil {
    fmt.Println(err)
    // Output: conversion issue: 153 (uint8) is greater than 127 (int8): maximum value for this type exceeded
  }
}
```

[Go Playground](https://go.dev/play/p/nelJshulOnj)

## Conversion issues

Issues can happen when converting between signed and unsigned integers, or when converting to a smaller integer type.

```go
package main

import "fmt"

func main() {
  var a int64
  a = 42
  b := uint8(a)
  fmt.Println(b) // 42

  a = 255 // this is the math.MaxUint8
  b = uint8(a)
  fmt.Println(b) // 255

  a = 255 + 1
  b = uint8(a)
  fmt.Println(b) // 0 conversion overflow

  a = -1
  b = uint8(a)
  fmt.Println(b) // 255 conversion overflow
}
```

[Go Playground](https://go.dev/play/p/DHfNUcZBvVn)

So you need to adapt your code to write something like this.

```go
package main

import "fmt"

func main() {
  var a int64
  a = 42
  if a < 0 || a > math.MaxUint8 {
    log.Println("overflow") // Output: overflow
  }
  fmt.Println(b) // 42

  a = 255 // this is the math.MaxUint8
  b = uint8(a)
  fmt.Println(b) // 255

  a = 255 + 1
  b = uint8(a)
  if a < 0 || a > math.MaxUint8 {
    log.Println("overflow") // Output: overflow
  }
  fmt.Println(b) // Output: 0

  a = -1
  b = uint8(a)
  if a < 0 || a > math.MaxUint8 {
    log.Println("overflow") // Output: overflow
  }
  fmt.Println(b) // Output:255
}
```

[Go Playground](https://go.dev/play/p/qAHGyy4NCLP)

`go-safecast` is there to avoid boilerplate copy pasta.

## Motivation

The gosec project raised this to my attention when the gosec [G115 rule was added](https://github.com/securego/gosec/pull/1149)

> G115: Potential overflow when converting between integer types.

This issue was way more complex than expected, and required multiple fixes.

[CWE-190](https://cwe.mitre.org/data/definitions/190.html) explains in detail.

But to sum it up, you can face:

- infinite loop
- access to wrong resource by id
- grant access to someone who exhausted their quota

The gosec G115 will now report issues in a lot of project.

## Alternatives

Some libraries existed, but they were not able to cover all the use cases.

- [github.com/rung/go-safecast](https://github.com/rung/go-safecast):
  Unmaintained, not architecture agnostic, do not support `uint` -> `int` conversion

- [github.com/cybergarage/go-safecast](https://github.com/cybergarage/go-safecast)
  Work with pointer like `json.Marshall`

## Stargazers over time

[![Stargazers over time](https://starchart.cc/ccoVeille/go-safecast.svg?variant=adaptive)](https://starchart.cc/ccoVeille/go-safecast)