Skip to content

Commit 8116784

Browse files
committed
Make pointers-to-member work
Change the memory-analyze to produce correct member expressions. Iterate over the offset from gdb, e.g. `st+4` means jump to the second member component inside `st`.
1 parent 28a6561 commit 8116784

File tree

2 files changed

+79
-1
lines changed

2 files changed

+79
-1
lines changed

src/memory-analyzer/analyze_symbol.cpp

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,10 @@ Author: Malte Mues <[email protected]>
1313
#include <util/c_types_util.h>
1414
#include <util/config.h>
1515
#include <util/expr_initializer.h>
16+
#include <util/pointer_offset_size.h>
17+
#include <util/string2int.h>
1618
#include <util/string_constant.h>
19+
#include <util/string_utils.h>
1720

1821
gdb_value_extractort::gdb_value_extractort(
1922
const symbol_tablet &symbol_table,
@@ -167,6 +170,43 @@ exprt gdb_value_extractort::get_char_pointer_value(
167170
}
168171
}
169172

173+
exprt gdb_value_extractort::get_pointer_to_member_value(
174+
const exprt &expr,
175+
const pointer_valuet &pointer_value,
176+
const source_locationt &location)
177+
{
178+
PRECONDITION(expr.type().id() == ID_pointer);
179+
PRECONDITION(!is_c_char_type(expr.type().subtype()));
180+
std::string memory_location = pointer_value.address.string();
181+
PRECONDITION(memory_location != "0x0");
182+
PRECONDITION(!pointer_value.pointee.empty());
183+
184+
std::string struct_name;
185+
size_t member_offset;
186+
if(pointer_value.pointee.find("+") != std::string::npos)
187+
{
188+
std::string member_offset_string;
189+
split_string(
190+
pointer_value.pointee, '+', struct_name, member_offset_string, true);
191+
member_offset = safe_string2size_t(member_offset_string);
192+
}
193+
else
194+
{
195+
struct_name = pointer_value.pointee;
196+
member_offset = 0;
197+
}
198+
199+
const symbolt *struct_symbol = symbol_table.lookup(struct_name);
200+
DATA_INVARIANT(struct_symbol != nullptr, "unknown struct");
201+
202+
const auto maybe_member_expr = get_subexpression_at_offset(
203+
struct_symbol->symbol_expr(), member_offset, expr.type().subtype(), ns);
204+
if(maybe_member_expr.has_value())
205+
return *maybe_member_expr;
206+
207+
UNREACHABLE;
208+
}
209+
170210
exprt gdb_value_extractort::get_non_char_pointer_value(
171211
const exprt &expr,
172212
const memory_addresst &memory_location,
@@ -212,6 +252,24 @@ exprt gdb_value_extractort::get_non_char_pointer_value(
212252
}
213253
}
214254

255+
bool gdb_value_extractort::points_to_member(
256+
const pointer_valuet &pointer_value) const
257+
{
258+
if(pointer_value.pointee.find("+") != std::string::npos)
259+
return true;
260+
261+
const symbolt *pointee_symbol = symbol_table.lookup(pointer_value.pointee);
262+
if(pointee_symbol == nullptr)
263+
return false;
264+
const auto pointee_type = pointee_symbol->type;
265+
if(
266+
pointee_type.id() == ID_struct_tag || pointee_type.id() == ID_union_tag ||
267+
pointee_type.id() == ID_array || pointee_type.id() == ID_struct ||
268+
pointee_type.id() == ID_union)
269+
return true;
270+
return false;
271+
}
272+
215273
exprt gdb_value_extractort::get_pointer_value(
216274
const exprt &expr,
217275
const exprt &zero_expr,
@@ -236,7 +294,9 @@ exprt gdb_value_extractort::get_pointer_value(
236294
else
237295
{
238296
const exprt target_expr =
239-
get_non_char_pointer_value(expr, memory_location, location);
297+
points_to_member(value)
298+
? get_pointer_to_member_value(expr, value, location)
299+
: get_non_char_pointer_value(expr, memory_location, location);
240300

241301
if(target_expr.id() == ID_nil)
242302
{

src/memory-analyzer/analyze_symbol.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,18 @@ class gdb_value_extractort
150150
const exprt &zero_expr,
151151
const source_locationt &location);
152152

153+
/// Call \ref get_subexpression_at_offset to get the correct member
154+
/// expression.
155+
/// \param expr: the input pointer expression (needed to get the right type)
156+
/// \param pointer_value: pointer value with structure name and offset as the
157+
/// pointee member
158+
/// \param location: the source location
159+
/// \return \ref member_exprt that the \p pointer_value points to
160+
exprt get_pointer_to_member_value(
161+
const exprt &expr,
162+
const pointer_valuet &pointer_value,
163+
const source_locationt &location);
164+
153165
/// Similar to \ref get_char_pointer_value. Doesn't re-call
154166
/// \ref gdb_apit::get_memory, calls \ref get_expr_value on _dereferenced_
155167
/// \p expr (the result of which is assigned to a new symbol).
@@ -184,6 +196,12 @@ class gdb_value_extractort
184196
/// \param expr: expression to be extracted
185197
/// \return the value as a string
186198
std::string get_gdb_value(const exprt &expr);
199+
200+
/// Analyzes the \p pointer_value to decide if it point to a struct or a
201+
/// union (or array)
202+
/// \param pointer_value: pointer value to be analyzed
203+
/// \return true if pointing to a member
204+
bool points_to_member(const pointer_valuet &pointer_value) const;
187205
};
188206

189207
#endif // CPROVER_MEMORY_ANALYZER_ANALYZE_SYMBOL_H

0 commit comments

Comments
 (0)