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

Go: fix models for built-in functions #16413

Merged
merged 16 commits into from May 14, 2024
Merged

Conversation

owen-mc
Copy link
Contributor

@owen-mc owen-mc commented May 3, 2024

Our model for append was wrong, as append is variadic. We were missing a model for copy. Here are the package docs and the relevant part of the spec.

I had to fix two bugs which I made into separate PRs

And I fixed one bug in this PR which is hard to otherwise test for.

I also span out #16444 to make the value flow tests have the same results as the taint flow tests.

@github-actions github-actions bot added the Go label May 3, 2024
Copy link
Contributor

github-actions bot commented May 3, 2024

⚠️ The head of this PR and the base branch were compared for differences in the framework coverage reports. The generated reports are available in the artifacts of this workflow run. The differences will be picked up by the nightly job after the PR gets merged.

Click to show differences in coverage

go

Generated file changes for go

  • Changes to framework-coverage-go.rst:
-    `Standard library <https://pkg.go.dev/std>`_,"````, ``archive/*``, ``bufio``, ``bytes``, ``cmp``, ``compress/*``, ``container/*``, ``context``, ``crypto``, ``crypto/*``, ``database/*``, ``debug/*``, ``embed``, ``encoding``, ``encoding/*``, ``errors``, ``expvar``, ``flag``, ``fmt``, ``go/*``, ``hash``, ``hash/*``, ``html``, ``html/*``, ``image``, ``image/*``, ``index/*``, ``io``, ``io/*``, ``log``, ``log/*``, ``maps``, ``math``, ``math/*``, ``mime``, ``mime/*``, ``net``, ``net/*``, ``os``, ``os/*``, ``path``, ``path/*``, ``plugin``, ``reflect``, ``reflect/*``, ``regexp``, ``regexp/*``, ``slices``, ``sort``, ``strconv``, ``strings``, ``sync``, ``sync/*``, ``syscall``, ``syscall/*``, ``testing``, ``testing/*``, ``text/*``, ``time``, ``time/*``, ``unicode``, ``unicode/*``, ``unsafe``",8,578,
+    `Standard library <https://pkg.go.dev/std>`_,"````, ``archive/*``, ``bufio``, ``bytes``, ``cmp``, ``compress/*``, ``container/*``, ``context``, ``crypto``, ``crypto/*``, ``database/*``, ``debug/*``, ``embed``, ``encoding``, ``encoding/*``, ``errors``, ``expvar``, ``flag``, ``fmt``, ``go/*``, ``hash``, ``hash/*``, ``html``, ``html/*``, ``image``, ``image/*``, ``index/*``, ``io``, ``io/*``, ``log``, ``log/*``, ``maps``, ``math``, ``math/*``, ``mime``, ``mime/*``, ``net``, ``net/*``, ``os``, ``os/*``, ``path``, ``path/*``, ``plugin``, ``reflect``, ``reflect/*``, ``regexp``, ``regexp/*``, ``slices``, ``sort``, ``strconv``, ``strings``, ``sync``, ``sync/*``, ``syscall``, ``syscall/*``, ``testing``, ``testing/*``, ``text/*``, ``time``, ``time/*``, ``unicode``, ``unicode/*``, ``unsafe``",8,581,
-    Totals,,20,871,24
+    Totals,,20,874,24
  • Changes to framework-coverage-go.csv:
- ,,,2,,,,,2
+ ,,,5,,,,,5

@owen-mc owen-mc force-pushed the go/fix-builtin-models branch 3 times, most recently from 0a0d54d to 95eeefd Compare May 7, 2024 15:05
@owen-mc owen-mc marked this pull request as ready for review May 7, 2024 15:06
@owen-mc owen-mc requested a review from a team as a code owner May 7, 2024 15:06
smowton
smowton previously approved these changes May 7, 2024
Copy link
Contributor

@smowton smowton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Haven't reviewed the test changes, but the code changes look good to me.

@@ -455,8 +455,8 @@ module Public {
CallNode getCallNode() { result = call }

override Type getType() {
exists(Function f | f = call.getTarget() |
result = f.getParameterType(f.getNumParameter() - 1)
exists(SignatureType t | t = call.getCall().getCalleeType() |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
exists(SignatureType t | t = call.getCall().getCalleeType() |
// Note this differs from `call.getTarget()`'s parameter types for polymorphic builtins like `append`.
exists(SignatureType t | t = call.getCall().getCalleeType() |

@smowton
Copy link
Contributor

smowton commented May 7, 2024

To check: are there old-school QL models relating to either function that are now duplicative or redundant?

@owen-mc owen-mc marked this pull request as ready for review May 11, 2024 06:49
@owen-mc
Copy link
Contributor Author

owen-mc commented May 11, 2024

I've now updated this to remove the old-style models and make sure all tests changes are ones we expect/want. It's ready to review again.

- ["", "", False, "append", "", "", "Argument[1].ArrayElement", "ReturnValue.ArrayElement", "value", "manual"]
- ["", "", False, "copy", "", "", "Argument[1].ArrayElement", "Argument[0].ArrayElement", "value", "manual"]
- ["", "", False, "max", "", "", "Argument[0]", "ReturnValue", "value", "manual"]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per https://pkg.go.dev/builtin#max min and max are variadic

Copy link
Contributor Author

@owen-mc owen-mc May 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oops, I hadn't realised that there could be more than two arguments. Although, despite what those docs say, if I try to implement the model like that then it doesn't work. It seems that the compiler has special-cased these functions, and they just have an invalid signature and aren't considered variadic. Maybe because of lack of generics originally stopping them from being implemented normally. I can get the type for the CallExpr and for three arguments it's func(int, int, int) int. It's a bit annoying, as we don't have a way of saying "any argument" in models-as-data (according to our docs, at least). I guess we could do 0..1000. I'll experiment.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I asked on the Gophers slack and someone pointed me to this comment. It turns out that min and max were only added in Go 1.21, and after some debate they decided to make them built-in functions because it's nicer to write max(a, b) than Math.Max(a, b) and they seem to provide a fundamental utility (though Go survived without it for a long time).

@@ -127,12 +127,10 @@
| main.go:64:7:64:18 | call to min | main.go:64:2:64:2 | definition of a |
| main.go:64:11:64:11 | x | main.go:64:7:64:18 | call to min |
| main.go:64:14:64:14 | y | main.go:64:7:64:18 | call to min |
| main.go:64:17:64:17 | z | main.go:64:7:64:18 | call to min |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lost results due to min and max being variadic functions

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This has been fixed now.

@@ -3,13 +3,6 @@
| main.go:38:13:38:13 | 1 | main.go:38:7:38:20 | slice literal |
| main.go:38:16:38:16 | 2 | main.go:38:7:38:20 | slice literal |
| main.go:38:19:38:19 | 3 | main.go:38:7:38:20 | slice literal |
| main.go:39:15:39:15 | s | main.go:39:8:39:25 | call to append |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're sure taint still works as expected here, just via different steps?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test, and the value flow counterpart, only show steps without any reads or stores. The model for append is now a value step with a store, so it isn't shown. The test in go/ql/test/library-tests/semmle/go/dataflow/ExternalTaintFlow/test.go still shows taint flow through append.

Although the documentation makes them look variadic (and generic), they
are actually special-cased in the compiler. Like all built-in functions
they don't have a signature type, but the type of `min(a, b, c)` is
`func(int, int, int) int` and not `func(int, ...int) int`.

Go doesn't allow open-ended ranges for argument indices in
models-as-data specifications (though Ruby and Python do), so I've used
`1..1000`.
@owen-mc owen-mc merged commit 145873f into github:main May 14, 2024
14 checks passed
@owen-mc owen-mc deleted the go/fix-builtin-models branch May 14, 2024 20:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants