Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New offset generator only uses local version of Go for stdlib offsets #271

Closed
MrAlias opened this issue Aug 24, 2023 · 5 comments · Fixed by #273
Closed

New offset generator only uses local version of Go for stdlib offsets #271

MrAlias opened this issue Aug 24, 2023 · 5 comments · Fixed by #273
Labels
bug Something isn't working

Comments

@MrAlias
Copy link
Contributor

MrAlias commented Aug 24, 2023

Describe the bug

The recent change to the offset generator only generates offsets for the version of Go used to run the generator.

Environment

  • OS:
    uname -s -r -v -m -p -o
    Linux 6.4.11-arch2-1 #1 SMP PREEMPT_DYNAMIC Sat, 19 Aug 2023 15:38:34 +0000 x86_64 unknown GNU/Linux
  • Go Version: multiple
  • Version: f15ae160c4acfe3872455f87e6133af87859172b

To Reproduce

Update code:

diff --git a/offsets-tracker/downloader/wrapper/go.modstd.txt b/offsets-tracker/downloader/wrapper/go.modstd.txt
index 4e08291..8201c87 100644
--- a/offsets-tracker/downloader/wrapper/go.modstd.txt
+++ b/offsets-tracker/downloader/wrapper/go.modstd.txt
@@ -1,3 +1,3 @@
 module testapp

-go %s
\ No newline at end of file
+go 1.12 // %s

Using a go.mod with version other than MAJOR.MINOR only works in Go 1.21. Changing to work for all versions of Go >= 1.12.

diff --git a/offsets-tracker/downloader/wrapper/main.go.txt b/offsets-tracker/downloader/wrapper/main.go.txt
index cfc277d..f1d3967 100644
--- a/offsets-tracker/downloader/wrapper/main.go.txt
+++ b/offsets-tracker/downloader/wrapper/main.go.txt
@@ -1,7 +1,19 @@
 package main

 import (
-       _ "%s"
+       // _ "%s"
+       "fmt"
+       "net/http"
 )

-func main() {}
\ No newline at end of file
+func getErr() error {
+       return &http.MaxBytesError{Limit: 1}
+}
+
+func main() {
+       err := getErr()
+       for {
+               fmt.Println(err.Error())
+       }
+
+}

Ensure MaxBytesError is included in the DWARF symbols.

diff --git a/offsets-tracker/main.go b/offsets-tracker/main.go
index 7ab9782..1dfa180 100644
--- a/offsets-tracker/main.go
+++ b/offsets-tracker/main.go
@@ -84,6 +84,10 @@ func main() {
                                StructName: "net/http.Request",
                                Field:      "ctx",
                        },
+                       {
+                               StructName: "net/http.MaxBytesError",
+                               Field:      "Limit",
+                       },
                })

        if err != nil {

Get the offset for MaxBytesError which was added in Go 1.19.

Using Go 1.21 on my local system and running:

go version
go version go1.21.0 linux/amd64
OFFSETS_OUTPUT_FILE="../pkg/inject/offset_results.json" go run main.go
...
net/http: Discovering available versions
net/http: Downloading version 1.21.0
net/http: Analyzing binary for version 1.21.0
net/http: Downloading version 1.20.7
net/http: Analyzing binary for version 1.20.7
net/http: Downloading version 1.20.6
net/http: Analyzing binary for version 1.20.6
net/http: Downloading version 1.20.5
net/http: Analyzing binary for version 1.20.5
net/http: Downloading version 1.20.4
net/http: Analyzing binary for version 1.20.4
net/http: Downloading version 1.20.3
net/http: Analyzing binary for version 1.20.3
net/http: Downloading version 1.20.2
net/http: Analyzing binary for version 1.20.2
net/http: Downloading version 1.20.1
net/http: Analyzing binary for version 1.20.1
net/http: Downloading version 1.20
net/http: Analyzing binary for version 1.20
net/http: Downloading version 1.19.12
net/http: Analyzing binary for version 1.19.12
net/http: Downloading version 1.19.11
net/http: Analyzing binary for version 1.19.11
net/http: Downloading version 1.19.10
net/http: Analyzing binary for version 1.19.10
net/http: Downloading version 1.19.9
net/http: Analyzing binary for version 1.19.9
net/http: Downloading version 1.19.8
net/http: Analyzing binary for version 1.19.8
net/http: Downloading version 1.19.7
net/http: Analyzing binary for version 1.19.7
net/http: Downloading version 1.19.6
net/http: Analyzing binary for version 1.19.6
net/http: Downloading version 1.19.5
net/http: Analyzing binary for version 1.19.5
net/http: Downloading version 1.19.4
net/http: Analyzing binary for version 1.19.4
net/http: Downloading version 1.19.3
net/http: Analyzing binary for version 1.19.3
net/http: Downloading version 1.19.2
net/http: Analyzing binary for version 1.19.2
net/http: Downloading version 1.19.1
net/http: Analyzing binary for version 1.19.1
net/http: Downloading version 1.19
net/http: Analyzing binary for version 1.19
net/http: Downloading version 1.18.10
net/http: Analyzing binary for version 1.18.10
net/http: Downloading version 1.18.9
net/http: Analyzing binary for version 1.18.9
net/http: Downloading version 1.18.8
net/http: Analyzing binary for version 1.18.8
net/http: Downloading version 1.18.7
net/http: Analyzing binary for version 1.18.7
net/http: Downloading version 1.18.6
net/http: Analyzing binary for version 1.18.6
net/http: Downloading version 1.18.5
net/http: Analyzing binary for version 1.18.5
net/http: Downloading version 1.18.4
net/http: Analyzing binary for version 1.18.4
net/http: Downloading version 1.18.3
net/http: Analyzing binary for version 1.18.3
net/http: Downloading version 1.18.2
net/http: Analyzing binary for version 1.18.2
net/http: Downloading version 1.18.1
net/http: Analyzing binary for version 1.18.1
net/http: Downloading version 1.18
net/http: Analyzing binary for version 1.18
net/http: Downloading version 1.17.13
net/http: Analyzing binary for version 1.17.13
net/http: Downloading version 1.17.12
net/http: Analyzing binary for version 1.17.12
net/http: Downloading version 1.17.11
net/http: Analyzing binary for version 1.17.11
net/http: Downloading version 1.17.10
net/http: Analyzing binary for version 1.17.10
net/http: Downloading version 1.17.9
net/http: Analyzing binary for version 1.17.9
net/http: Downloading version 1.17.8
net/http: Analyzing binary for version 1.17.8
net/http: Downloading version 1.17.7
net/http: Analyzing binary for version 1.17.7
net/http: Downloading version 1.17.6
net/http: Analyzing binary for version 1.17.6
net/http: Downloading version 1.17.5
net/http: Analyzing binary for version 1.17.5
net/http: Downloading version 1.17.4
net/http: Analyzing binary for version 1.17.4
net/http: Downloading version 1.17.3
net/http: Analyzing binary for version 1.17.3
net/http: Downloading version 1.17.2
net/http: Analyzing binary for version 1.17.2
net/http: Downloading version 1.17.1
net/http: Analyzing binary for version 1.17.1
net/http: Downloading version 1.17
net/http: Analyzing binary for version 1.17
net/http: Downloading version 1.16.15
net/http: Analyzing binary for version 1.16.15
net/http: Downloading version 1.16.14
net/http: Analyzing binary for version 1.16.14
net/http: Downloading version 1.16.13
net/http: Analyzing binary for version 1.16.13
net/http: Downloading version 1.16.12
net/http: Analyzing binary for version 1.16.12
net/http: Downloading version 1.16.11
net/http: Analyzing binary for version 1.16.11
net/http: Downloading version 1.16.10
net/http: Analyzing binary for version 1.16.10
net/http: Downloading version 1.16.9
net/http: Analyzing binary for version 1.16.9
net/http: Downloading version 1.16.8
net/http: Analyzing binary for version 1.16.8
net/http: Downloading version 1.16.7
net/http: Analyzing binary for version 1.16.7
net/http: Downloading version 1.16.6
net/http: Analyzing binary for version 1.16.6
net/http: Downloading version 1.16.5
net/http: Analyzing binary for version 1.16.5
net/http: Downloading version 1.16.4
net/http: Analyzing binary for version 1.16.4
net/http: Downloading version 1.16.3
net/http: Analyzing binary for version 1.16.3
net/http: Downloading version 1.16.2
net/http: Analyzing binary for version 1.16.2
net/http: Downloading version 1.16.1
net/http: Analyzing binary for version 1.16.1
net/http: Downloading version 1.16
net/http: Analyzing binary for version 1.16
net/http: Downloading version 1.15.15
net/http: Analyzing binary for version 1.15.15
net/http: Downloading version 1.15.14
net/http: Analyzing binary for version 1.15.14
net/http: Downloading version 1.15.13
net/http: Analyzing binary for version 1.15.13
net/http: Downloading version 1.15.12
net/http: Analyzing binary for version 1.15.12
net/http: Downloading version 1.15.11
net/http: Analyzing binary for version 1.15.11
net/http: Downloading version 1.15.10
net/http: Analyzing binary for version 1.15.10
net/http: Downloading version 1.15.9
net/http: Analyzing binary for version 1.15.9
net/http: Downloading version 1.15.8
net/http: Analyzing binary for version 1.15.8
net/http: Downloading version 1.15.7
net/http: Analyzing binary for version 1.15.7
net/http: Downloading version 1.15.6
net/http: Analyzing binary for version 1.15.6
net/http: Downloading version 1.15.5
net/http: Analyzing binary for version 1.15.5
net/http: Downloading version 1.15.4
net/http: Analyzing binary for version 1.15.4
net/http: Downloading version 1.15.3
net/http: Analyzing binary for version 1.15.3
net/http: Downloading version 1.15.2
net/http: Analyzing binary for version 1.15.2
net/http: Downloading version 1.15.1
net/http: Analyzing binary for version 1.15.1
net/http: Downloading version 1.15
net/http: Analyzing binary for version 1.15
net/http: Downloading version 1.14.15
net/http: Analyzing binary for version 1.14.15
net/http: Downloading version 1.14.14
net/http: Analyzing binary for version 1.14.14
net/http: Downloading version 1.14.13
net/http: Analyzing binary for version 1.14.13
net/http: Downloading version 1.14.12
net/http: Analyzing binary for version 1.14.12
net/http: Downloading version 1.14.11
net/http: Analyzing binary for version 1.14.11
net/http: Downloading version 1.14.10
net/http: Analyzing binary for version 1.14.10
net/http: Downloading version 1.14.9
net/http: Analyzing binary for version 1.14.9
net/http: Downloading version 1.14.8
net/http: Analyzing binary for version 1.14.8
net/http: Downloading version 1.14.7
net/http: Analyzing binary for version 1.14.7
net/http: Downloading version 1.14.6
net/http: Analyzing binary for version 1.14.6
net/http: Downloading version 1.14.5
net/http: Analyzing binary for version 1.14.5
net/http: Downloading version 1.14.4
net/http: Analyzing binary for version 1.14.4
net/http: Downloading version 1.14.3
net/http: Analyzing binary for version 1.14.3
net/http: Downloading version 1.14.2
net/http: Analyzing binary for version 1.14.2
net/http: Downloading version 1.14.1
net/http: Analyzing binary for version 1.14.1
net/http: Downloading version 1.14
net/http: Analyzing binary for version 1.14
net/http: Downloading version 1.13.15
net/http: Analyzing binary for version 1.13.15
net/http: Downloading version 1.13.14
net/http: Analyzing binary for version 1.13.14
net/http: Downloading version 1.13.13
net/http: Analyzing binary for version 1.13.13
net/http: Downloading version 1.13.12
net/http: Analyzing binary for version 1.13.12
net/http: Downloading version 1.13.11
net/http: Analyzing binary for version 1.13.11
net/http: Downloading version 1.13.10
net/http: Analyzing binary for version 1.13.10
net/http: Downloading version 1.13.9
net/http: Analyzing binary for version 1.13.9
net/http: Downloading version 1.13.8
net/http: Analyzing binary for version 1.13.8
net/http: Downloading version 1.13.7
net/http: Analyzing binary for version 1.13.7
net/http: Downloading version 1.13.6
net/http: Analyzing binary for version 1.13.6
net/http: Downloading version 1.13.5
net/http: Analyzing binary for version 1.13.5
net/http: Downloading version 1.13.4
net/http: Analyzing binary for version 1.13.4
net/http: Downloading version 1.13.3
net/http: Analyzing binary for version 1.13.3
net/http: Downloading version 1.13.2
net/http: Analyzing binary for version 1.13.2
net/http: Downloading version 1.13.1
net/http: Analyzing binary for version 1.13.1
net/http: Downloading version 1.13
net/http: Analyzing binary for version 1.13
net/http: Downloading version 1.12.17
net/http: Analyzing binary for version 1.12.17
net/http: Downloading version 1.12.16
net/http: Analyzing binary for version 1.12.16
net/http: Downloading version 1.12.15
net/http: Analyzing binary for version 1.12.15
net/http: Downloading version 1.12.14
net/http: Analyzing binary for version 1.12.14
net/http: Downloading version 1.12.13
net/http: Analyzing binary for version 1.12.13
net/http: Downloading version 1.12.12
net/http: Analyzing binary for version 1.12.12
net/http: Downloading version 1.12.11
net/http: Analyzing binary for version 1.12.11
net/http: Downloading version 1.12.10
net/http: Analyzing binary for version 1.12.10
net/http: Downloading version 1.12.9
net/http: Analyzing binary for version 1.12.9
net/http: Downloading version 1.12.8
net/http: Analyzing binary for version 1.12.8
net/http: Downloading version 1.12.7
net/http: Analyzing binary for version 1.12.7
net/http: Downloading version 1.12.6
net/http: Analyzing binary for version 1.12.6
net/http: Downloading version 1.12.5
net/http: Analyzing binary for version 1.12.5
net/http: Downloading version 1.12.4
net/http: Analyzing binary for version 1.12.4
net/http: Downloading version 1.12.3
net/http: Analyzing binary for version 1.12.3
net/http: Downloading version 1.12.2
net/http: Analyzing binary for version 1.12.2
net/http: Downloading version 1.12.1
net/http: Analyzing binary for version 1.12.1
net/http: Downloading version 1.12
net/http: Analyzing binary for version 1.12
...

And in ../pkg/inject/offset_results.json:

    "net/http.MaxBytesError": {
      "Limit": {
        "versions": {
          "oldest": "1.12.0",
          "newest": "1.21.0"
        },
        "offsets": [
          {
            "offset": 0,
            "since": "1.12"
          }
        ]
      }
    },

Given this type and field were added in Go 1.19, this is incorrect.

By contrast, running with Go 1.18:

go install golang.org/dl/go1.18@latest
go1.18 download
alias go=go1.18
go version
go version go1.18 linux/amd64
OFFSETS_OUTPUT_FILE="../pkg/inject/offset_results.json" go run main.go
net/http: Discovering available versions
net/http: Downloading version 1.21.0
2023/08/24 14:18:04 error while fetching offsets for "net/http": exit status 2
exit status 1

Which is expected when realized that the offset tracker is building the app with the local version of Go which cannot compile given it does not know about MaxBytesError.

Expected behavior

Offsets should be reflective of the Go STDLIB from that version.

@MrAlias
Copy link
Contributor Author

MrAlias commented Aug 25, 2023

Given the switch was to address the problem that modern versions of the Go binary do not have DWARF symbols, it might make sense to look into using reflect to produce the outputs:

package main

import (
	"fmt"
	"net/http"
	"reflect"
)

func fieldOffsetByName(rt reflect.Type, name string) uintptr {
	f, ok := rt.FieldByName(name)
	if !ok {
		return 0
	}
	return f.Offset
}

func main() {
	r := &http.Request{}
	rt := reflect.TypeOf(r).Elem()
	fmt.Println("Request.Header offset:", fieldOffsetByName(rt, "Header"))
	fmt.Println("Request.Method offset:", fieldOffsetByName(rt, "Method"))
	fmt.Println("Request.RemoteAddr offset:", fieldOffsetByName(rt, "RemoteAddr"))
	fmt.Println("Request.URL offset:", fieldOffsetByName(rt, "URL"))
	fmt.Println("Request.ctx offset:", fieldOffsetByName(rt, "ctx"))
}
$ go version
go version go1.21.0 linux/amd64
$ go run .
Request.Header offset: 56
Request.Method offset: 0
Request.RemoteAddr offset: 176
Request.URL offset: 16
Request.ctx offset: 232

@MrAlias
Copy link
Contributor Author

MrAlias commented Aug 25, 2023

Given the switch was to address the problem that modern versions of the Go binary do not have DWARF symbols, it might make sense to look into using reflect to produce the outputs:

package main

import (
	"fmt"
	"net/http"
	"reflect"
)

func fieldOffsetByName(rt reflect.Type, name string) uintptr {
	f, ok := rt.FieldByName(name)
	if !ok {
		return 0
	}
	return f.Offset
}

func main() {
	r := &http.Request{}
	rt := reflect.TypeOf(r).Elem()
	fmt.Println("Request.Header offset:", fieldOffsetByName(rt, "Header"))
	fmt.Println("Request.Method offset:", fieldOffsetByName(rt, "Method"))
	fmt.Println("Request.RemoteAddr offset:", fieldOffsetByName(rt, "RemoteAddr"))
	fmt.Println("Request.URL offset:", fieldOffsetByName(rt, "URL"))
	fmt.Println("Request.ctx offset:", fieldOffsetByName(rt, "ctx"))
}
$ go version
go version go1.21.0 linux/amd64
$ go run .
Request.Header offset: 56
Request.Method offset: 0
Request.RemoteAddr offset: 176
Request.URL offset: 16
Request.ctx offset: 232

Reflect won't work for unexported types (i.e. runtime.g).

@RonFed
Copy link
Contributor

RonFed commented Aug 25, 2023

The previous approach was to download the go binaries and find the offset with elf and DWARF (using code that analyzes the binary).
If I understand correctly the reflect package gives the offsets relevant to the running program and doesn't operate on a binary.

As I understand there are two possible solutions, both require recompiling a go application with all the different versions:

  • Write a go application that do dummy import and inspect the results DWARF (similar to what is done today)
  • Get the offsets in runtime via reflect package and write the result to the same offset result json file.

@MrAlias
Copy link
Contributor Author

MrAlias commented Aug 25, 2023

  • Write a go application that do dummy import and inspect the results DWARF (similar to what is done today)

I have an implementation of this in #268 that generates the compatibility docs. I'm looking at the unifying the approach into the offset-tracker.

MrAlias referenced this issue in MrAlias/opentelemetry-go-instrumentation Sep 18, 2023
MrAlias referenced this issue in MrAlias/opentelemetry-go-instrumentation Sep 18, 2023
MrAlias added a commit that referenced this issue Sep 21, 2023
* Use internal/pkg/inject data model for offsets

* Remove offset/schema

* Add GetOffset method to TrackedOffsets

* Use data.GetOffset instead of getFieldOffset

* Use data.GetOffset instead of searchOffset

* Rename injector_test.go to data_test.go

* Update offsets

* Use internal for kind tests

* Run go mod tidy

* Expand offset tests

* Manually update net/url.URL.Path offset

This hasn't changed
(https://cs.opensource.google/go/go/+/refs/tags/go1.21.1:src/net/url/url.go;l=362),
but the tooling is broke (#271).

* Fix lint
@MrAlias
Copy link
Contributor Author

MrAlias commented Sep 27, 2023

Testing this issue against #273 I get the following added to the offsets_results.json:

+    "net/http.MaxBytesError": {
+      "Limit": [
+        {
+          "versions": {
+            "oldest": "1.19.0",
+            "newest": "1.21.1"
+          },
+          "offsets": [
+            {
+              "offset": 0,
+              "since": "1.19.0"
+            }
+          ]
+        }
+      ]
+    },

Which indicates it does indeed resolve this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants