Skip to content

Implement runtime checking for dynamic_bounds_cast #256

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

Closed
dtarditi opened this issue Apr 7, 2017 · 5 comments
Closed

Implement runtime checking for dynamic_bounds_cast #256

dtarditi opened this issue Apr 7, 2017 · 5 comments
Assignees
Labels
feature This labels new features and enhancements.

Comments

@dtarditi
Copy link
Member

dtarditi commented Apr 7, 2017

The dynamic_bounds_cast operator requires runtime checks of bounds. I think this runtime checking should be inserted during the lowering to clang IR.

@dtarditi dtarditi added the feature This labels new features and enhancements. label Apr 7, 2017
@dtarditi
Copy link
Member Author

dtarditi commented Apr 7, 2017

Correct the name of the operator: it is dynamic_bounds_cast.

@dtarditi dtarditi assigned jijoongmoon and unassigned wonsubkim Apr 7, 2017
@dtarditi dtarditi added this to the Runtime checking milestone Apr 14, 2017
@dtarditi dtarditi changed the title Implement runtime checking for dynamic_check Implement runtime checking for dynamic_bounds_cast Apr 14, 2017
@wonsubkim
Copy link
Collaborator

I think that it works as follows

  • DynamicBoundsCast/AssumeBoundsCast kinds exist
  • For DynamicBoundsCast casting kind, CodeGen emits dynamic bounds check code
    • BoundsCastExpr has bounds for bounds casting operation - bounds(castlb, castub)
    • BoundsCastExpr has inferred bounds for source expression - bounds(lb, ub)
    • It inserts Dynamic_check(lb <= castlb && castub <= ub)
  • How does the type casting works?
    • In C++ dynamic_cast, it generates code to call dynamic cast function call
    • In checked-c, how does it work except for generating dynamic check?

@lenary
Copy link
Collaborator

lenary commented Apr 19, 2017

@wonsubkim I can't say how code generation works for the casting itself, but I can help you with finding the code you need to call.

You want to call CGF.EmitDynamicBoundsCheck(const Address PtrAddr, const BoundsExpr *Bounds), using the pointer you're casting and the BoundsExpr you have. Sometimes you may not have the pointer as an Address object (it may be an LValue, Clang has weird conventions around this). There are methods on the LValue struct to turn it into an address, but you have to use the right one for the kind of LValue you have (there's an enum in the LValue which tells you).

This method will do all the calculation for you. You can see it being used a lot in CGExpr.cpp.

@wonsubkim
Copy link
Collaborator

wonsubkim commented Apr 20, 2017

Thanks for your suggestion.
I am now preparing runtime check insertion for bounds cast
After current bounds casting parsing implementation is completed, I will do PR for this issue

I think that dynamic_bounds_cast code generation consists of two parts

  1. if required, dynamic bounds check insertion
  2. explicit type casting code generation

For code generation of dynamic check, I refer to EmitDynamicBoundsCheck but it will be little bit different since it requires inferred source bounds not PtrAddr
I plan to implement as follows
EmitDyanmicBoundsCheck(const BoundsExpr *DynamicBounds, const BoundsExpr *SrcBounds)

DynamicBounds is bounds generated by bounds cast operator, bounds(castlb, castub)
SourceBounds is bounds inferred from source expression, bounds(lb, ub)
It will produce dynamnic check, dynamic_check(lb <= castlb && castub <=ub)

I think that dynamic_bounds_cast is same as explicit type casting except for generating bounds information.
So, I plan to implement type casting code generation based on explicit type casting expression.

wonsubkim added a commit to wonsubkim/checkedc-clang that referenced this issue May 17, 2017
  + implement emission of dynamic checking for bounds_cast
  it does two things as follows:
  it generates codes for explicit type casting
  since subexpression can be non-pointer type, it SHOULD take care about it
  it also generates dynamic_check for bounds casting by using both bounds of cast and bounds of subexpression
  : bounds (castlb, castub), bounds of cast operation
  : bounds(lb, ub), bounds of subexpression of cast operation
  -> emits non-null check for subexpression (dynamic_check(base != NULL))
  -> emits dynamic check (dynamic_check(lb <= castlb && castub <= ub)
  + add inferred bounds of subexpression since code generation requires source bounds
  when inferring bounds of subexpression, it also binds inferred source bounds to cast operation
wonsubkim added a commit to wonsubkim/checkedc-clang that referenced this issue May 17, 2017
wonsubkim added a commit to wonsubkim/checkedc-clang that referenced this issue May 30, 2017
  + modify code generation for bounds cast operation
  let bounds cast operation be bounds_cast<T>(E)
  CastBounds - bounds(castlb, castub)
  SubExprBounds - bounds(lb, ub)
  code generation for bounds cast operation is as follows:
  Dynamic_check(E == NULL || (lb <= castlb && castub <= ub))
  if E is NULL(0), it skips code generation runtime dynamic check
  Otherwise, it emits dynamic check

  + add dynamic_check blocks with two conditions being ORed
  EmitDynamicCheckBlocks(cond1, cond2)
  if (cond1) { success }
  else {
    fall-through
    if (cond2) { success }
    else { fail }
  }

  + add enum value for CastBounds & SubExprBounds
  SubExprs[CASTBOUNDS, SUBEXPRBOUNDS] is added
  CastBounds is inferred/expanded bounds for cast operation
  SubExprBounds is inferred/expanded bounds for subexpression of bounds cast operation
  In bounds inferrence, it sets cast bounds & subexpr bounds in inferrence step

  + rename function, parameters
wonsubkim added a commit to wonsubkim/checkedc-clang that referenced this issue May 31, 2017
)

  + dynamic_bounds_cast operation SHOULD always succeed if runtime value of subexpression of cast is NULL(0)
  it finally emits dynamic_check(E == NULL || (lb <= castlb && castub <= ub))
  it checks if subexpression value is NULL
  if subexpression value is not NULL, then it emits range bounds check code
  Otherwise(E == NULL), it skips range bounds check
  range bounds check is generated only if E is not NULL

  generated code is as follows:
  if (E == NULL) {
success_block:
  }
  else {
fallthrough_block:
    if (lb <= castlb && castub <= ub) {
success_block:
    }
    else {
fail_block:
      trap(); llvm_unreachable();
    }
  }

  To check this code, we have checked generated llvm IR code for test code & modified test code
wonsubkim added a commit to wonsubkim/checkedc-clang that referenced this issue Jun 1, 2017
@dtarditi
Copy link
Member Author

This work is complete, except for handling requirements related to relative alignment. That is covered by feature #330.

dopelsunce pushed a commit to dopelsunce/checkedc-clang that referenced this issue Sep 28, 2020
)

The existing syntax of the *_bound_cast operators is confusing.  The kind
of bounds being specified is not explicit.  It depends on the number of
arguments to the operator.  It is clearer to just use a bounds expression
to describe the bounds.  That involves a little more typing, but it is
easier to understand and allows programmers to use all the different variants
of bounds expressions.

Add examples of using dynamic_bounds_cast and assume_bounds_cast for
clarity.
mgrang pushed a commit that referenced this issue Nov 23, 2020
Test sync with BigRefactor_master
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature This labels new features and enhancements.
Projects
None yet
Development

No branches or pull requests

4 participants