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

ACSL: Improve handling of dereferences #703

Open
wants to merge 6 commits into
base: dev
Choose a base branch
from
Open

Conversation

schuessf
Copy link
Contributor

@schuessf schuessf commented Jan 7, 2025

In our C translation, we translate dereferences to calls to Boogie procedures, e.g., x = a[i]; is translated to:

call #t~mem0 := read~int({ base: ~a~0!base, offset: ~a~0!offset + 4 * ~i~0 }, 4);
~x~0 := #t~mem0;

where read~int has the following signature (for memsafety we have a stronger contract):

procedure read~int(#ptr : $Pointer$, #sizeOfReadType : int) returns (#value : int);
ensures #value == #memory_int[#ptr];

This read-call is produced byExpressionResultTransformer::switchToRValue.

For ACSL, we attempted to handle this the same way as for C. There were however two problems:

  • In the method to handle ArrayAccessExpression, the call to switchToRValue was missing, which led to a crash (fixed in 07b75aa)
  • This approach with read-calls works for some ACSL statements (e.g., the translation of //@ assert x == a[i]; looks similar to above). There are however other ACSL statements / expressions, the translation with calls does not work, as it produces not only an expression, but also auxiliary statements (e.g., function contracts, loop invariants, quantifiers in the future). Therefore I replaced the read-call by an array-access in the corresponding memory-array (e.g., #memory_int) when handling ACSL. This was implemented through a custom switchToRValue method in ACSLHandler (see d0b8165).

Note: Before this change, every dereference was translated to a read/write-call in Boogie, where the MemorySlicer relied on. Therefore, we now crash, on programs with ACSL dereferences, when MemorySlicer is used (We probably have to replace #memory_int everywhere, not only in the contracts of the read/write-procedures). @Heizmann can you have a look at this issue?

Copy link
Contributor

@maul-esel maul-esel left a comment

Choose a reason for hiding this comment

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

👍 Thanks.

I'm not deeply familiar with the ACSL translation, so unfortunately I can only offer some superficial comments (see below).

Could you also add some test cases here?

final CType type = CEnum.replaceEnumWithInt(expr.getLrValue().getCType().getUnderlyingType());
// Perform a custom switch to RValue without any read calls
// This allows us to use also dereferences inside ACSL expressions that have to be side-effect-free
// (e.g., loop invariant or contracts)
Copy link
Contributor

Choose a reason for hiding this comment

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

But this will now also be used for ACSL asserts, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, it will be used for any ACSL expression.

final Expression memoryAccess = ExpressionFactory.constructNestedArrayAccessExpression(loc,
mCHandler.getMemoryArrayForType(type), new Expression[] { heapValue.getAddress() });
return new ExpressionResultBuilder(expr).resetLrValue(new RValue(memoryAccess, type)).build();
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Do I understand correctly that this code replaces the calls to mExprResultTransformer.switchToRValue (and related methods) that were previously made?

If so, I am a bit unsure if this is a good place to have this. For instance, it could easily get out-of-sync with changes in switchToRValue. Would it be possible to make this a specialized method e.g. mExprResultTransformer.switchToRValueWithoutSideEffects?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Do I understand correctly that this code replaces the calls to mExprResultTransformer.switchToRValue (and related methods) that were previously made?

Yes, any call to mExprResultTransformer.switchToRValue in ACSLHandler was replaced with a call to this method.

If so, I am a bit unsure if this is a good place to have this. For instance, it could easily get out-of-sync with changes in switchToRValue. Would it be possible to make this a specialized method e.g. mExprResultTransformer.switchToRValueWithoutSideEffects?

We cannot get completely out-of-sync, this method still has the call to mExprResultTransformer.switchToRValue as a base case (which does currently nothing, but if this changes, it will also be visible in this method).
We could also make it a public method in ExpressionResultTransformer, but this switchToRValue does not have any memsafety-checks (even if the setting is enabled). Therefore I am not sure, if it is a good idea to have such a public method in ExpressionResultTransformer.

@schuessf
Copy link
Contributor Author

schuessf commented Jan 7, 2025

I just added two test cases. The should actually pass, since the MemorySlicer is not enabled by default.

@schuessf schuessf force-pushed the wip/fs/acsl-arrays branch from 97e14cd to 4915880 Compare January 8, 2025 10:23
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.

2 participants