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

Add tests for type assertions and type switches #149

Merged
merged 5 commits into from
Nov 6, 2020

Conversation

PurelyApplied
Copy link
Collaborator

It crossed my mind that we don't have test coverage for type switches. We appear to catch any source when it's reassigned to an identifyable type, but don't identify an source obfuscated by interface, even when we're in a block that would require that type.

That make sense given our current implementation and limitations. This might be trivialized by our general conversations surrounding how we plan to puncture the interface obfuscation problem. If not, we might need a way to mark an item as a source only within the scope of specific Blocks.

We have a good priority set right now. I just wanted to get a thread stated while it was top of mind.

@mlevesquedion
Copy link
Contributor

If not, we might need a way to mark an item as a source only within the scope of specific Blocks.

In passing: this sounds to me like something that would be straightforward to implement within an interpretation-based approach. (Which is not to say that there isn't a straightforward way to do it under the current approach.)

Copy link
Contributor

@mlevesquedion mlevesquedion left a comment

Choose a reason for hiding this comment

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

Great idea! I like that you opened a PR with code so we can comment on specific lines.

func TestTypeSwitchInline(i interface{}) {
switch i.(type) {
case core.Innocuous, *core.Source, core.Source:
core.Sink(i) // TODO/discuss - do we want "a source has reached a sink"
Copy link
Contributor

Choose a reason for hiding this comment

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

I think so.

If this case is taken, then we know there's a possibility that i could be a Source, so to me this code is unsafe and should be fixed. Of course, it is possible that TestTypeSwitchInline is only ever called with core.Innocuous values, so producing a report would be "incorrect" when considering the whole program. However, to me that would be a programming error that I don't think we should accomodate.

// See the License for the specific language governing permissions and
// limitations under the License.

package _switch
Copy link
Contributor

Choose a reason for hiding this comment

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

I know this is a draft, and my question is besides the point, but: why the leading underscore? 🤔

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Since switch is a keyword, package switch refuses to compile.

I probably should've gone with package name typeswitch anyway.

Copy link
Contributor

Choose a reason for hiding this comment

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

That makes sense, didn't cross my mind to remove the underscore and see. 😅

core.Sink(i)
core.Sink(t)
case *core.Source:
core.Sink(i) // TODO/discuss - do we want "a source has reached a sink"
Copy link
Contributor

Choose a reason for hiding this comment

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

I think it should, since within that branch we know that i is a Source.

core.Sink(i) // TODO/discuss - do we want "a source has reached a sink"
core.Sink(t) // want "a source has reached a sink"
case core.Source:
core.Sink(i) // TODO/discuss - do we want "a source has reached a sink"
Copy link
Contributor

Choose a reason for hiding this comment

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

Same as above. I think it should, since within that branch we know that i is a Source.

case core.Source:
core.Sink(i) // TODO/discuss - do we want "a source has reached a sink"
core.Sink(t) // want "a source has reached a sink"
default:
Copy link
Contributor

Choose a reason for hiding this comment

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

This is more an interface{} problem than a type switch problem, but it is possible that i is a source that just wasn't caught by any of the previous cases (e.g., i has type Foo and Foo was configured to be a source) and that this code is in fact unsafe.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This is more an interface{} problem

Yeah, my interpretation here is that just circles back to the interface problems. All we know for sure is that it definitely isn't one of the above by type identity. That leaves a lot of options.

@mlevesquedion
Copy link
Contributor

An observation: at the SSA level type switches are implemented as a series of comma-ok TypeAsserts, each in their own block. This is also the case for multi-type cases.

Honing in on this case:

	case core.Source:
		core.Sink(i) // TODO/discuss - do we want "a source has reached a sink"
		core.Sink(t) // want "a source has reached a sink"

This is the SSA for core.Sink(t):

	 0(*ssa.Alloc          ): t3 = local example.com/core.Source (t)
	 1(*ssa.Store          ): *t3 = t1
	 7(*ssa.UnOp           ): t8 = *t3
	 8(*ssa.Alloc          ): t9 = new [1]interface{} (varargs)
	 9(*ssa.IndexAddr      ): t10 = &t9[0:int]
	10(*ssa.MakeInterface  ): t11 = make interface{} <- example.com/core.Source (t8)
	11(*ssa.Store          ): *t10 = t11
	12(*ssa.Slice          ): t12 = slice t9[:]
	13(*ssa.Call           ): t13 = example.com/core.Sink(t12...)
	14(*ssa.Jump           ): jump 1

There is a clear path from t to the Sink call.

This is the SSA for core.Sink(i):

	 2(*ssa.Alloc          ): t4 = new [1]interface{} (varargs)
	 3(*ssa.IndexAddr      ): t5 = &t4[0:int]
	 4(*ssa.Store          ): *t5 = i
	 5(*ssa.Slice          ): t6 = slice t4[:]
	 6(*ssa.Call           ): t7 = example.com/core.Sink(t6...)

It seems like since core.Sink takes interface{} arguments, the SSA uses i directly. By itself, this code doesn't allow us to determine whether something bad is going on. We would need to know what case we're in, as you've suggested in the description.

@@ -0,0 +1,45 @@
// Copyright 2020 Google LLC
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

To add: test case from discussion in 159.

@PurelyApplied PurelyApplied marked this pull request as ready for review October 22, 2020 19:05
@PurelyApplied
Copy link
Collaborator Author

Tests updated and moved to a more sensible package. Issue opened for intended work.

@PurelyApplied PurelyApplied changed the title [Discuss] Handling sources in type switches Add tests for type assertions and type switches Oct 27, 2020
@PurelyApplied
Copy link
Collaborator Author

PurelyApplied commented Oct 27, 2020

Vaguely related to the Extract propagation work in #146, I have noticed that type assertions s, ok := iface.(Source) seems to "backflow" and taint iface by the association of s. That seems a bit absurd, and is one more to the pile of mounting evidence that we need to have some explicit "from A to B" logic for each instruction type.

[edit: Nevermind. That was fixed since the last time I merged with master. I had thought we'd talked about it!]

Copy link
Contributor

@mlevesquedion mlevesquedion left a comment

Choose a reason for hiding this comment

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

LGTM. These are all important tests/test targets for us to have.

Sorry I didn't approve earlier, this fell off my radar.

@PurelyApplied PurelyApplied merged commit 0002d4e into google:master Nov 6, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants