DEV Community

Christophe Colombier
Christophe Colombier

Posted on

go-safecast: Safe number conversion in Go πŸͺ„

I worked on my first open-source package last weekend.

GitHub logo ccoVeille / go-safecast

Safe number conversion in Go: address gosec G115 and cwe-190 Integer Overflow or Wraparound

πŸͺ„ go-safecast: safe numbers conversion

Go Report Card GoDoc codecov Code Climate

Project purpose

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

This package is made to help to convert any number to another, and report an error when if there would be a loss or overflow in the conversion

Usage

package main
import (
  "fmt"
  "math"

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

func main() {

  // when there is no overflow
  //
  fmt.Println(safecast.ToInt8(float64(42)))
  // Output: 42, nil
  fmt.Println(safecast.ToInt8(int64(-1)))
  // Output: -1, nil

  // when there is an overflow
  //
  fmt.Println(safecast.ToInt8(float64(20000)))
  // Output: 0 conversion issue: 20000 is greater than 127
  fmt.Println(safecast.ToUint8(int64(-1)))
  //
…
Enter fullscreen mode Exit fullscreen mode

About the story behind this library, you can read my first article about integer overflow in Go

As I found nothing to cope with this kind of error, except adding a lot of boilerplate for each cast to do, so I decided to make my own Go package.

@ldemailly helped me to review the code and the idea. Thank you guy.

The package is now mature enough for me to talk about it.

So instead of this


var a int
var b uint8

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

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

c, d := 255, 300
res := max(c, d)
if res < 0 || res > math.MaxInt8 {
    log.Println("overflow")
}
fmt.Println(int8(res))

str := "\x99" // hexadecimal representation of Trademark ASCII character: β„’
e := str[0]
if e < 0 || e > math.MaxInt8 {
    log.Println("overflow")
}
fmt.Println(int8(e))
Enter fullscreen mode Exit fullscreen mode

Go Playground

You can now do this

var a int
var b uint8

a = 255 + 1
b, err := safecast.ToUint8(a)
if err != nil {
    log.Println(err)
}
fmt.Println(b)

a = -1
b, err = safecast.ToUint8(a)
if err != nil {
    log.Println(err)
}
fmt.Println(b)

c, d := 255, 300
res := max(c, d)
g, err := safecast.ToInt8(res)
if err != nil {
    log.Println(err)
}
fmt.Println(g)

str := "\x99" // hexadecimal representation of Trademark ASCII character: β„’
e := str[0]
f, err := safecast.ToUint8(e)
if err != nil {
    log.Println(err)
}
fmt.Println(f)
Enter fullscreen mode Exit fullscreen mode

Go Playground

I'm curious about your feedbacks

Top comments (0)