DEV Community

Christophe Colombier
Christophe Colombier

Posted on • Edited 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 Go Imports GitHub Repo stars

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

Usage

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
…
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, thank.

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 (1)

Collapse
 
ldemailly profile image
Laurent Demailly • Edited

Great series on a serious problem, and thanks for the mention!

If you don’t mind I’d like to offer my smaller and simpler (I think) generic version: pkg.go.dev/fortio.org/safecast for people to consider. It also has Must* variant of the conversions.