-
Notifications
You must be signed in to change notification settings - Fork 273
Instrument strchr to use the string refinement solver #5200
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
base: develop
Are you sure you want to change the base?
Changes from 1 commit
941eed4
8d82639
3f76f13
80c88cc
ddf72d1
0879ad0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,19 +14,27 @@ Author: Diffblue Ltd. | |
#include <numeric> | ||
#include <unordered_set> | ||
#include <util/arith_tools.h> | ||
#include <util/expr_cast.h> | ||
#include <util/expr_iterator.h> | ||
#include <util/expr_util.h> | ||
#include <util/graph.h> | ||
#include <util/magic.h> | ||
#include <util/make_unique.h> | ||
#include <util/ssa_expr.h> | ||
#include <util/std_expr.h> | ||
#include <util/string2int.h> | ||
#include <util/string_constant.h> | ||
#include <util/unicode.h> | ||
|
||
bool is_char_type(const typet &type) | ||
{ | ||
return type.id() == ID_unsignedbv && to_unsignedbv_type(type).get_width() <= | ||
STRING_REFINEMENT_MAX_CHAR_WIDTH; | ||
if(type.id() == ID_unsignedbv) | ||
return to_unsignedbv_type(type).get_width() <= | ||
STRING_REFINEMENT_MAX_CHAR_WIDTH; | ||
|
||
if(type.id() == ID_signedbv) | ||
return to_signedbv_type(type).get_width() <= 8; | ||
|
||
return false; | ||
} | ||
|
||
bool is_char_array_type(const typet &type, const namespacet &ns) | ||
|
@@ -192,3 +200,68 @@ array_exprt interval_sparse_arrayt::concretize( | |
size, it == entries.end() ? default_value : it->second); | ||
return array; | ||
} | ||
|
||
exprt maybe_byte_extract_expr(const exprt &expr) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ❓ What's "maybe" about this? Would returning an optional make sense here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well it always returns some There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 💡 This function is non-trivial, I'd consider writing a unit test for it to check it is doing everything you expect |
||
{ | ||
if(!can_cast_expr<byte_extract_exprt>(expr)) | ||
return expr; | ||
|
||
const auto &byte_extract_expr = to_byte_extract_expr(expr); | ||
const auto &offset = byte_extract_expr.offset(); | ||
PRECONDITION(offset.id() == ID_constant); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ❔ how come this is a precondition? Seems like should be documented at least |
||
if(offset.id() != ID_constant) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ❓ Unreachable? You've just asserted this isn't true |
||
{ | ||
return expr; | ||
} | ||
const auto &constant_offset = to_constant_expr(offset); | ||
const auto &op = byte_extract_expr.op(); | ||
auto numeric_offset = | ||
string2optional_int(id2string(constant_offset.get_value())); | ||
PRECONDITION(numeric_offset.has_value()); | ||
if(*numeric_offset == 0) | ||
{ | ||
return op; | ||
} | ||
|
||
array_exprt::operandst offset_operands; | ||
offset_operands.insert( | ||
offset_operands.end(), | ||
op.operands().begin() + *numeric_offset, | ||
op.operands().end()); | ||
const auto extracted_array_suffix = | ||
array_exprt{offset_operands, to_array_type(op.type())}; | ||
|
||
return extracted_array_suffix; | ||
} | ||
|
||
exprt maybe_remove_string_exprs(const exprt &expr) | ||
{ | ||
return [&]() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ❓ What's the purpose of this lambda... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am fairly sure there isn’t one. Probably happened by accident during a refactor. |
||
if( | ||
auto const &maybe_string_constant = | ||
expr_try_dynamic_cast<string_constantt>(expr)) | ||
{ | ||
return static_cast<const exprt &>(maybe_string_constant->to_array_expr()); | ||
} | ||
else | ||
{ | ||
return expr; | ||
} | ||
}(); | ||
} | ||
|
||
exprt massage_weird_arrays_into_non_weird_arrays(const exprt &expr) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🚫 This of course needs documentation, or a much better name! And again, a unit test seems wise as a technical documentation of what qualifies as "weird" and "not weird" arrays |
||
{ | ||
auto const byte_extracted = maybe_byte_extract_expr(expr); | ||
auto const string_removed = maybe_remove_string_exprs(byte_extracted); | ||
PRECONDITION(string_removed.type().id() == ID_array); | ||
if(string_removed.id() == ID_if) | ||
{ | ||
return if_exprt{ | ||
string_removed.op0(), | ||
massage_weird_arrays_into_non_weird_arrays(string_removed.op1()), | ||
massage_weird_arrays_into_non_weird_arrays(string_removed.op2()), | ||
string_removed.type()}; | ||
} | ||
return string_removed; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🚫 Magic number here should have some explanation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
documentation of the function needs to be updated, and does it make sense to have signed characters?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@romainbrenguier
char
is allowed to be eithersigned
orunsigned
in C.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Turns out the magic is not needed at all.