Check return value bounds#1150
Conversation
…ons, and set the ReturnBounds member to the expanded return bounds
…ue bounds checking errors
…FAIL See checkedc-clang issue 1147. These tests should be updated to avoid the compiler errors that arise due to functions in these test files return expressions with unknown bounds. Once these test files are updated, they should no longer be marked as XFAIL.
…ing return value bounds
…d return bounds checking compiler errors
… using the set of expressions that produce the same value as RetExpr
| FD->getReturnType(), | ||
| BoundsValueExpr::Kind::Return); | ||
| ReturnBounds = | ||
| BoundsUtil::ExpandToRange(S, ReturnVal, FD->getBoundsExpr()); |
There was a problem hiding this comment.
-
The function
ExpandToRangeonly expands count (or, byte_count) bounds expressions. Does this mean that in a range bounds expression likebounds(_Return_value, _Return_value + 2), the abstract place holder_Return_valuewill not be replaced by the concrete valueReturnVal? -
It will be great if a positive test case (no errors or warnings) with similar return bounds as in the test case
f10inclang/test/CheckedC/static-checking/return-bounds.cis added.
There was a problem hiding this comment.
ReturnVal is a _Return_value expression (a BoundsValueExpr with the Kind Return). If a function has declared bounds of count(size), ExpandToRange will return bounds(_Return_value, _Return_value + size). If a function has declared bounds of bounds(_Return_value, _Return_value + size), ExpandToRange will return bounds(_Return_value, _Return_value + size).
I've added a test case for this (function f7 with no errors or warnings) to return-bounds.c.
There was a problem hiding this comment.
Ok, thanks for the clarification.
|
Is it intentional that this change applies to return values with bounds-safe interfaces? Consider the following example: _Array_ptr<char> test(void) : count(1) {
char *x;
return x;
}
char *test_itype(void) : count(1) {
char *x;
return x;
}Both functions compile without error on For
Since 3C has been assuming that a function whose return type has a bounds-safe interface can return an arbitrary unchecked pointer, so if that design is changing, we'll need to find a way to adjust the design of 3C correspondingly. That is, in essence, why the |
|
The behavior in this PR (regarding bounds checking unchecked pointers in unchecked contexts with bounds-safe interfaces) is intentional with respect to the latest Checked C discussion as far as I understand. @dtarditi @sulekhark should we change this behavior so it is more consistent with the 3C design? |
|
Perhaps more to the point: if I'm right that the "latest Checked C discussion" as reflected by this PR is no longer consistent with the specification, can you please update the specification or otherwise point us to where we can get the latest information? |
@mattmccutchen-cci
While our current implementation is consistent with Section 4.9, I think this part of the spec (Section 6.3.8 - middle of page 116) is unclear and we need to modify the spec and add one more scenario to the above statement as shown below. This will make this part of the spec consistent with the previous part.
However, we will discuss this matter once again with David tomorrow, and resolve it (i.e. make the spec and the implementation consistent with each other). |
|
I guess I'm still unclear on the overall design intent of bounds-safe interfaces. Clearly, one important use case is to allow both unmodified C code and fully Checked C code to call external library functions that have bounds-safe interfaces (as in the Checked C system headers). Is it also a goal to be able to add bounds-safe interfaces to plain C functions in the user's code without having to modify those implementations right away? This is essentially what 3C is trying to do. If the answer is indeed "no", I noticed two other parts of the spec that could use clarification. In Section 6.3.1:
That sentence appears in a discussion of what happens when unchecked code uses a program element with a bounds-safe interface. But read in isolation, it does seem to suggest that my Also, an assignment like the following is already rejected by the compiler before this PR (similar to the restriction this PR is adding for return values): char *global : count(1);
void assign_global(void) {
char *x;
global = x;
}But Section 6.3.8 says:
Does another scenario for an unchecked right-hand side need to be added here as well? |
|
We've been discussing this issue over at Correct Computation and the summary is:
One thing I find confusing is that itypes currently used for standard library functions could not be applied to those functions themselves, in their original C. For example, in the header The standard library was compiled from C code that implements this function, e.g., I would have thought that if I can advertise in It feels strange to me that this does not work, but typechecking this code with its original C type and the prototype also present with an itype does work. What principle justifies the difference in treatment? |
|
As per the discussion we had with David today, we agree that if the itypes used in a function declaration are applied to the function definition, and the function definition is compiled in an unchecked scope, and the function body does not use any checked pointers, then the compiler must not issue any bounds-checking errors or warnings. For the currently gives two errors (I have elided the notes): Going forward, these errors will be issued when the above function is analyzed in checked scope but not when analyzed in an unchecked scope. Additionally, in unchecked scope the return bounds checking (as per this PR) on the returned pointer We will update the Checked C spec and the compiler code to be consistent with this behavior. |
|
Thanks for the update. When the new spec is available we will reread with a mindset toward consistency/principle, to see if we have any further thoughts about itypes; if so, we'll comment on a separate thread. |
For the record: it looks like #1157, #1158, and #1159 have been filed for this work. Thanks! |
… a bounds-safe interface, for return values that have not been implicitly converted to an unchecked pointer
The purpose of this function was to test function declaration rewriting for itype array pointers declared with bounds but without an explicit itype. This is equally well tested when a correct bound is inferred for the parameter array. (Matt: Remove the XFAIL now that the test is fixed.) (cherry picked from commit 57d31d2)
…into check-return-bounds
This PR checks that the inferred bounds of a return value expression imply the declared return bounds (if any) for the enclosing function.
This PR does not check modifications to variables or other lvalue expressions that are used in return bounds. For example:
At the assignment
size = 3, the bounds checker will not emit any diagnostic messages even though the modified variablesizeis used in the declared return bounds. This can be done in a separate PR.Test updates: