Get sizeof internal go struct - go

I've been playing with uprobes. In order to probe a specific object in runtime, I need to know the size of internal go struct. In my case, the poll.FD. I could count each nested struct manually, but this could increase the complexity if we are working with a lot nested struct.
My first attempt was to use dlv expression , len <variable>. Didn't work Command failed: command not available
My second attempt was to create a program to extract this information:
package main
import (
"fmt"
"internal/poll"
"unsafe"
)
func main() {
fmt.Println("size of internal/poll FD struct:", unsafe.Sizeof(poll.FD{}))
}
When I compile the code above, the following message is shown:
main.go:7:2: use of internal package internal/poll not allowed
Am I missing something? Is there a better way get that information?

You can try do it by Testing in same package, in order to pass this limitation.

unsafe.Sizeof(reflect.ValueOf(<nested struct>)) is this what you're looking for to get the size of nested struct?
PS:This may not be answer but I can't comment.

Related

Go BigQuery package installs with errors (Go version 1.10.1)

For some reason, I get the following errors when installing the cloud.google.com/go/bigquery package. I'm a Go noob, so I assume I'm doing something wrong. I was wondering if anyone was able to replicate, or could point me in the direction about how to resolve these errors? For example, is using a bool type in place of a *bool legal in prior versions of Go? Perhaps this is a bug in the Google package?
$ go get -u cloud.google.com/go/bigquery
# cloud.google.com/go/bigquery
gocode/src/cloud.google.com/go/bigquery/query.go:166:22: cannot use true (type bool) as type *bool in assignment
gocode/src/cloud.google.com/go/bigquery/query.go:168:22: cannot use false (type bool) as type *bool in assignment
gocode/src/cloud.google.com/go/bigquery/query.go:199:15: cannot use qq.UseLegacySql (type *bool) as type bool in field value
gocode/src/cloud.google.com/go/bigquery/query.go:200:22: invalid operation: ! *bool
Looks like someone pushed a broken change to the Go BigQuery client last night.
https://github.com/GoogleCloudPlatform/google-cloud-go/commit/c718c274c122d2ca258bb8f93830d820cbb2160d
Should be fixed now. However, if you're using dep for Go dependency management, it looks like you'll need to set the revision like so in Gopkg.toml (if you are trying to use v0.21.0 of the GoogleCloudPlatform/google-cloud-go client):
[[constraint]]
name = "cloud.google.com/go"
revision = "c718c274c122d2ca258bb8f93830d820cbb2160d"
Sad times.

Where is 's' defined in https://github.com/Workiva/go-datastructures/tree/master/bitarray?

I do not see where s is defined. Guru will not tell me. All I get is "no object for identifier" but it knows about the k right beside it. Here is a snippet that is typical of the linked code:
func getIndexAndRemainder(k uint64) (uint64, uint64) {
return k / s, k % s
}
The one letter variable name definitely makes it harder to grep around for. I have looked for the usual suspects: var s uint64, s := ..., and nothing. Clearly it needs to be a global value defined somewhere.
This leaves me with two questions:
Where is s coming from?
How would I find it without asking here?
EDIT:
For others who stumble on this.
Guru failed me because I did not checkout the source for the package under a proper Go workspace by placing the git clone under /some/path/src and setting the GOPATH to /some/path. So while I thought GOPATH=. guru definition s would work, the GOPATH was ignored. guru could find k because it is in the file but it did not know how to look in other files.
My grep failed cause const uses a simple = not a :=. I will remember this when grepping in the future.
It is defined in go-datastructures/bitarray/block.go:
// s denotes the size of any element in the block array.
// For a block of uint64, s will be equal to 64
// For a block of uint32, s will be equal to 32
// and so on...
const s = uint64(unsafe.Sizeof(block(0)) * 8)
As the variable s was not defined in the function, and it was not prefixed by a package name or alias, it had to be a global (variable or constant) of the bitarray package.
Once that was known, I went through every file in the folder go-datastructures/bitarray that was not suffixed with _test and I looked for a top-level declaration for s.
It's defined in go-datastructures/bitarray/block.go, line #33:
const s = uint64(unsafe.Sizeof(block(0)) * 8)
"Modern" IDEs with Go support usually have the ability to go to the definition of a symbol / identifier your cursor is at or what you click on. For example in Atom with the Go-plus plugin you can go to the definition by holding down the CTRL key while clicking.
These IDEs use the godef open source tool to find the definition source file and line, you may also use it directly. You can find the godef documentation here: https://godoc.org/github.com/rogpeppe/godef
Another tool, guru is also capable of tracking the definition of it. Both guru and godef works in Atom, and were able to jump to block.go, to the definition of s. But it's much easier to use an "armored" IDE and just do a simple click.
Also note that the success of using grep and patterns is limited, as variable and constant declarations can be grouped, and the following are also valid declarations:
var (
longer = 3
s = uint64(3)
)
Or:
var (
s = someExpression
longer = 3
)
Or:
const (
p = uint64(iota)
s
x
)

Trick to quickly find file & line number throwing an error in Go?

In my journey with go discovered that there are no stacktraces. so whenever something breaks, all we get an simple string error message without any information where is this is coming from. This is in stark contrast with other languages where I am used to seing detailed stacktraces
For example, below is the error message from apex
$ cat event.json | apex invoke --logs webhook
тип error parsing response: json: cannot unmarshal array into Go value of type map[string]interface {}
here its telling me that unmarshal to a map ins't working because event.json is an array. We have unmarshal to interface{} to support both arrays & maps.However, it doesn't tell me which file/line is causing this error.
Questions:
What is way to quickly find which file/line this error coming from?
In General, Are there tips/tricks which gophers use to get to the source of problem quickly from this string error message?
is this how stack traces are for most go projects or there are any best practices that should be followed?
What is way to quickly find which file/line this error coming from?
There are no default stacks printed unless it's an unrecovered panic.
In General, Are there tips/tricks which gophers use to get to the source of problem quickly from this string error message? is this how stack traces are for most go projects or there are any best practices that should be followed?
In General, you need to check error returns from most of the function calls. There are more than one way to do that.
I usually use standard library package log to print out error logs with file and line numbers for easy debugging in simple programs. For example:
package main
import "log"
import "errors"
func init() { log.SetFlags(log.Lshortfile | log.LstdFlags) }
func callFunc() error {
return errors.New("error")
}
func main() {
if err := callFunc(); err != nil {
log.Println(err)
}
}
http://play.golang.org/p/0iytNw7eZ7
output:
2009/11/10 23:00:00 main.go:14: error
Also, there are functions for you to print or retrieve current stacks in standard library runtime/debug, e.g. https://golang.org/pkg/runtime/debug/#PrintStack
There are many community efforts on bringing error handling easier, you can search error in GoDoc: https://godoc.org/?q=error
Your attempted solution: Finding the piece of code that produces the error to fix the code.
Your actual problem: The content of event.json.
This is called the X-Y-Problem
Invoke expects a json object, you are passing a json array. Fix that and your problem is gone!
$ echo -n '{ "value": "Tobi the ferret" }' | apex invoke uppercase
Relevant part of the documentation: Invoking Functions
And that's the piece of code that produces the error: Github
And yes, Go does have stack traces! Read Dave Cheneys blog post on errors and exceptions.
Go does produce stack traces when a panic happens, crashing the program. This will happen if the code calls panic() directly, typically in cases like:
if err != nil {
panic("it broke")
}
or, when a runtime error happens:
a := []int{1, 2, 3}
b := a[12] // index out of range
Here's a minimal example:
package main
func main() {
panic("wtf?!")
}
Output:
panic: wtf?!
goroutine 1 [running]:
panic(0x94e60, 0x1030a040)
/usr/local/go/src/runtime/panic.go:464 +0x700
main.main()
/tmp/sandbox366642315/main.go:4 +0x80
Note the main.go:4 indicating the filename and line number.
In your example, the program did not panic, instead opting to call (I'm guessing) os.Exit(1) or log.Fatal("error message") (which calls os.Exit(1)). Or, the panic was simply recovered from in the calling function. Unfortunately, there's nothing you can do about this if you aren't the author of the code.
I would recommend reading Defer, Panic, and Recover on the Golang blog for more about this.
Setting log.SetFlags(log.LstdFlags | log.Lshortfile) in main() should do it.
For example, log.Printf("Deadline!") would print:
03/11/2020 23:59:59 liberty_test.go:42: Deadline!

How to convert ISO 8601 time in golang?

What is the equivalent code in golang for the following shell command ?
date -u +%Y-%m-%dT%T%z
If you're looking for a simple, but not perfect solution consider using time.RFC3339 constant. But also know that there are differences between ISO8601 which are too complex for this answer.
See https://ijmacd.github.io/rfc3339-iso8601/ for differences and also has a handy test file generator to show differences. There is also a good discussion on SO here What's the difference between ISO 8601 and RFC 3339 Date Formats?
package main
import (
"time"
"fmt"
)
func main(){
fmt.Println(time.Now().Format(time.RFC3339))
}
golang Time.Format
package main
import (
"fmt"
"time"
)
func main() {
fmt.Println(time.Now().UTC().Format("2006-01-02T15:04:05-0700"))
}
I had the following spec:
YYYY-MM-DDThh:mm:ss.sssZ
with the final Z being explicitly present in the examples.
Here's how I dealt with it:
first I found the time.RFCxxx that was the closest to my target
I copied its value
I fiddled with it until I found the expected result
which is
2006-01-02T15:04:05.999Z
ISO8601 allows for variable levels of granularity. You can have just a year, year+month, year+month+day, add a time portion, and optionally have a timezone portion. Go's built-in time parsing, however, requires you to know ahead-of-time which parts will be included.
The github.com/btubbs/datetime library provides a more flexible parser that can handle all the commonly used ISO8601 formats. See https://github.com/btubbs/datetime
Disclosure: I wrote that library.
Replacing the sign in the format with a Z triggers the ISO 8601 behavior. Which is exactly time.RFC3339. If you are wanting the string output to end in 'Z' what you need to do is convert to the UTC zone.
package main
import (
"fmt"
"time"
)
func main() {
fmt.Println(time.Now().UTC().Format("2006-01-02T15:04:05Z07:00"))
}
// this is the same format used by RFC3339. just a note on why.

read int64 from fixed64 protobuf field in golang

I have a field that is of type fixed64 in a .proto file.
I want to read it as an int64 field:
score := int64(pb_obj.Score)
When I try to compile the line agove I get the error message cannot convert pb_obj.Score (type *uint64) to type int64. I tried converting the a uint64 as well, and got an almost identical message.
pb_obj.Score's type seems to be *uint64 (pointer to uint64), not uint64. You just need to access to the value the pointer is referencing:
score := int64(*pb_obj.Score)
(See the * prefix as the difference)
Based on the compile error you're working with a uint64 pointer and not a uint64 value. You may get what you want by referencing the value directly using the * operator. I've never worked with protobuf, so I could be off but that should get you moving. Here's a nice reference that may help golang pointers

Resources