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

SMTChecker: Parse invariants from SMT-LIB response #15032

Merged
merged 5 commits into from Apr 30, 2024
Merged

Conversation

blishko
Copy link
Contributor

@blishko blishko commented Apr 16, 2024

This PR adds initial support for parsing invariants, computed by CHC solver, in SMT-LIB format.

This is done in a few separate steps (found in individual commits):

  1. Introduction of a basic SMT-LIB parser that parses string representation and creates S-expression representation. This parser was originally developed by @chriseth (for solsmt) and we only updated it slightly to handle malformed SMT-LIB strings.
  2. Instructing Eldarica to produce model (invariants) when this is requested by the user.
  3. Reorganization of where we remember declared SMT-LIB sorts. This is necessary for proper parsing of the solver response and creation of our representation of the invariants.
  4. The actual translation from SMT-LIB S-expressions to our Expression representation of the invariants.

Note: This is only initial support and will require more iterations as we add more tests.

};


#define precondition(CONDITION) if(!(CONDITION)) return {}
Copy link
Contributor Author

@blishko blishko Apr 16, 2024

Choose a reason for hiding this comment

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

Is there a better for to achieve this?
If I don't what to explicitly write 10 if checks like this

if (!<condition>)
    return {};

Yet, I want to check these conditions, but only bail out on further processing, not throwing an exception.
It feels like there currently isn't a better way than a macro.

@blishko blishko force-pushed the smt-eld-invariants branch 2 times, most recently from b7b26b5 to e98f8ed Compare April 16, 2024 13:18
@ethereum ethereum deleted a comment from stackenbotten Apr 16, 2024
@ethereum ethereum deleted a comment from stackenbotten Apr 16, 2024
@ethereum ethereum deleted a comment from stackenbotten Apr 16, 2024
@blishko blishko marked this pull request as ready for review April 16, 2024 13:29
Copy link
Collaborator

@nikola-matic nikola-matic left a comment

Choose a reason for hiding this comment

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

These are (almost) exclusively stylistic - unfortunately I can't seem to help much with the actual SMT stuff :)

CHCSmtLib2Interface const& m_chcInterface;
std::map<std::string, SortPointer> knownVariables;

bool isNumber(std::string const& _expr)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is this supposed to handle only positive numbers?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Good question. It turns out yes, because in SMT-LIB, unary minus is an operator, so negative number should be represented as (- <number>).

I'll try invariant with a negative number, to check this case.

libsmtutil/CHCSmtLib2Interface.cpp Outdated Show resolved Hide resolved
libsmtutil/CHCSmtLib2Interface.cpp Outdated Show resolved Hide resolved
libsmtutil/CHCSmtLib2Interface.cpp Outdated Show resolved Hide resolved
libsmtutil/CHCSmtLib2Interface.cpp Outdated Show resolved Hide resolved
else if (isNumber(_atom))
return smtutil::Expression(_atom, {}, SortProvider::sintSort);
else if (knownVariables.find(_atom) != knownVariables.end())
return smtutil::Expression(_atom, {}, knownVariables.at(_atom));
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
return smtutil::Expression(_atom, {}, knownVariables.at(_atom));
return smtutil::Expression(_atom, {}, knownVariables[_atom]);

std::vector<std::pair<std::string, SortPointer>> boundVariables;
for (auto const& sortedVar: varList)
{
solAssert(!isAtom(sortedVar));
Copy link
Collaborator

Choose a reason for hiding this comment

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

Just curious - why do you sometimes use smtAssert(), and other times solAssert()?

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 don't know :)
I've changed everything to smtAssert.

libsmtutil/CHCSmtLib2Interface.cpp Outdated Show resolved Hide resolved
switch (_sort.kind)
if (!m_sortNames.count(_sort))
m_sortNames[_sort] = toSmtLibSortInternal(_sort);
return m_sortNames.at(_sort);
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
return m_sortNames.at(_sort);
return m_sortNames.at[_sort];

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What is it about at that you don't like?

Copy link
Collaborator

Choose a reason for hiding this comment

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

at() throws an exception if the element is not present in the container, but you already check for that in the if above, so it's just unnecessary overhead.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Well, for map operator [] default-initializes a new value and insert the new pair into the map, if the key was not present. So I think it has even more overhead than at.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Sure, but not in this case, because you've already checked for the existence of the element. It's not a big deal regardless, so no need to make this change.

libsmtutil/CHCSmtLib2Interface.cpp Outdated Show resolved Hide resolved
@nikola-matic
Copy link
Collaborator

The failing tests have been fixed by the way, you just need to rebase.

libsmtutil/CHCSmtLib2Interface.cpp Outdated Show resolved Hide resolved
libsmtutil/CHCSmtLib2Interface.cpp Show resolved Hide resolved
libsmtutil/SMTLib2Parser.cpp Outdated Show resolved Hide resolved
libsmtutil/SMTLib2Interface.cpp Show resolved Hide resolved
libsmtutil/SMTLib2Interface.h Show resolved Hide resolved
libsmtutil/SMTLib2Interface.cpp Show resolved Hide resolved
libsmtutil/CHCSmtLib2Interface.cpp Show resolved Hide resolved
@blishko blishko force-pushed the smt-eld-invariants branch 2 times, most recently from 4866974 to 5df3915 Compare April 23, 2024 15:34
libsmtutil/CHCSmtLib2Interface.cpp Outdated Show resolved Hide resolved
libsmtutil/CHCSmtLib2Interface.cpp Outdated Show resolved Hide resolved
@blishko
Copy link
Contributor Author

blishko commented Apr 25, 2024

@nikola-matic , @pgebal , I fixed the code according to your suggestions, or at least commented on your comments :)
So, this should be ready for another round.

@cameel cameel added the smt label Apr 26, 2024
pgebal
pgebal previously approved these changes Apr 29, 2024
@pgebal
Copy link
Collaborator

pgebal commented Apr 29, 2024

@nikola-matic , @pgebal , I fixed the code according to your suggestions, or at least commented on your comments :) So, this should be ready for another round.

@blishko the code looks good to me

Comment on lines 425 to 435
if (typeArgs.size() == 4 && typeArgs[0].toString() == "_")
{
if (typeArgs[1].toString() == "extract")
{
return smtutil::Expression(
"extract",
{toSMTUtilExpression(typeArgs[2]), toSMTUtilExpression(typeArgs[3])},
SortProvider::bitVectorSort // TODO: Compute bit size properly?
);
}
}
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
if (typeArgs.size() == 4 && typeArgs[0].toString() == "_")
{
if (typeArgs[1].toString() == "extract")
{
return smtutil::Expression(
"extract",
{toSMTUtilExpression(typeArgs[2]), toSMTUtilExpression(typeArgs[3])},
SortProvider::bitVectorSort // TODO: Compute bit size properly?
);
}
}
if (typeArgs.size() == 4 && typeArgs[0].toString() == "_" && typeArgs[1].toString() == "extract")
return smtutil::Expression(
"extract",
{toSMTUtilExpression(typeArgs[2]), toSMTUtilExpression(typeArgs[3])},
SortProvider::bitVectorSort // TODO: Compute bit size properly?
);

nikola-matic
nikola-matic previously approved these changes Apr 30, 2024
Copy link
Collaborator

@nikola-matic nikola-matic left a comment

Choose a reason for hiding this comment

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

Eh, there are a few tiny style issues (mostly around overuse of scoping braces with conditional statements), but it's our fault for not having a sane formatting check, so merge away :)

@@ -223,3 +226,282 @@ std::string CHCSmtLib2Interface::createHeaderAndDeclarations() {
std::string CHCSmtLib2Interface::createQueryAssertion(std::string name) {
return "(assert\n(forall " + forall() + "\n" + "(=> " + name + " false)))";
}

class SMTLibTranslationContext
Copy link
Collaborator

Choose a reason for hiding this comment

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

Uh, everything in the class has an extra indent by the way.

Parser code was originally written by @chriseth for solsmt, an SMT
solver developed internally for Solidity
We add support for parsing CHC solver response containing a model, i.e.,
invariants. We utilise our SMT parser to build S-expression
representation which we then interpret using the context we remembered
while building the query.  We have to rememeber all predicates declared
to the solver, and, consequently, all sorts we have declared to the
solver.
@blishko blishko merged commit 5afa25e into develop Apr 30, 2024
72 checks passed
@blishko blishko deleted the smt-eld-invariants branch April 30, 2024 14:31
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.

None yet

4 participants