Skip to content

Conversation

@hvitved
Copy link
Contributor

@hvitved hvitved commented May 28, 2019

For methods compiled without optimization (and possibly also with optimization), it is possible for a variable update to have multiple possible assigned values. For example, the non-optimized CIL for

return cond ? null : "not null"

is

0: nop
1: ldarg.0
2: ldfld cond
3: brtrue.s 6:
4: ldstr "not null"
5: br.s 7:
6: ldnull
7: stloc.0 L0 // stores either `null` or "not null"
8: br.s 9:
9: ldloc.0
10: ret

Consequently, an existential in CallableReturns.qll must be a forex.

This change eliminates all the false positives here: https://lgtm.com/projects/g/sharpsuite/sharpinit/alerts/?mode=tree&ruleFocus=1506094316834

hvitved added 2 commits May 28, 2019 10:05
…analysis

For methods compiled without optimization (and possibly also with optimization),
it is possible for a variable update to have multiple possible assigned values.
For example, the non-optimized CIL for

```
return cond ? null : "not null"
```

is

```
0: nop
1: ldarg.0
2: ldfld cond
3: brtrue.s 6:
4: ldstr "not null"
5: br.s 7:
6: ldnull
7: stloc.0 L0 // stores either `null` or "not null"
8: br.s 9:
9: ldloc.0
10: ret
```

Consequently, an existential in `CallableReturns.qll` must be a `forex`.
@hvitved hvitved added the C# label May 28, 2019
@hvitved hvitved requested a review from calumgrant May 28, 2019 08:21
@hvitved hvitved requested a review from a team as a code owner May 28, 2019 08:21
Copy link
Contributor

@calumgrant calumgrant left a comment

Choose a reason for hiding this comment

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

This is really great stuff, and I like that you have taken care to produce binaries to reproduce the result. I have one general question, and happy to merge as-is.

or
forex(VariableUpdate vu | DefUse::variableUpdateUse(_, vu, expr) |
alwaysNotNullExpr(vu.getSource())
forex(Expr src | src = vu.getSource() | alwaysNotNullExpr(src))
Copy link
Contributor

Choose a reason for hiding this comment

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

Great sleuthing. Do you think it makes sense to rename getSource to getASource? The problem is that quite a few methods could be renamed to getA... for expressions, due to the multi-valued nature of optimized code?

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 did consider it, but I don't think it is worthwhile. Actually, it is getOperand(int i) that can have multiple values, so I wonder if we could end up in a situation where an instruction that pops two values could get mixed operands:

1. ldfld cond
2. brtrue.s 6:
3. ldstr "a"
4: ldstr "b"
5: br.s 8:
6: ldstr "c"
7: ldstr "d"
8. // instruction that pops two values

I.e., I wonder if we could end up with the instruction 7 having e.g. getOperand(0) = "a" and getOperand(1) = "d".

@hvitved
Copy link
Contributor Author

hvitved commented May 29, 2019

Here is the performance report: https://git.semmle.com/gist/tom/2cdcfed314fd154cc98ac7ff35566996 (internal link), which shows that performance is unchanged.

@hvitved hvitved added this to the 1.21.0 milestone May 29, 2019
@calumgrant calumgrant merged commit 59a006e into github:master May 29, 2019
@hvitved hvitved deleted the csharp/cil-nullness branch June 3, 2019 07:50
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants