Skip to content

Commit 80b88e4

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 a599602 commit 80b88e4

File tree

2 files changed

+125
-1
lines changed

2 files changed

+125
-1
lines changed

src/memory-analyzer/analyze_symbol.cpp

Lines changed: 107 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,89 @@ 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+
const auto &memory_location = pointer_value.address;
181+
std::string memory_location_string = memory_location.string();
182+
PRECONDITION(memory_location_string != "0x0");
183+
PRECONDITION(!pointer_value.pointee.empty());
184+
185+
std::string struct_name;
186+
size_t member_offset;
187+
if(pointer_value.pointee.find("+") != std::string::npos)
188+
{
189+
std::string member_offset_string;
190+
split_string(
191+
pointer_value.pointee, '+', struct_name, member_offset_string, true);
192+
member_offset = safe_string2size_t(member_offset_string);
193+
}
194+
else
195+
{
196+
struct_name = pointer_value.pointee;
197+
member_offset = 0;
198+
}
199+
200+
const symbolt *struct_symbol = symbol_table.lookup(struct_name);
201+
DATA_INVARIANT(struct_symbol != nullptr, "unknown struct");
202+
const auto maybe_struct_size =
203+
pointer_offset_size(struct_symbol->symbol_expr().type(), ns);
204+
bool found = false;
205+
CHECK_RETURN(maybe_struct_size.has_value());
206+
for(const auto &value_pair : values)
207+
{
208+
const auto &value_symbol_expr = value_pair.second;
209+
if(
210+
struct_name ==
211+
id2string(to_symbol_expr(value_symbol_expr).get_identifier()))
212+
{
213+
found = true;
214+
break;
215+
}
216+
}
217+
218+
if(!found)
219+
{
220+
const typet target_type = expr.type().subtype();
221+
222+
symbol_exprt dummy(expr.type());
223+
code_blockt assignments;
224+
225+
const symbol_exprt new_symbol =
226+
to_symbol_expr(allocate_objects.allocate_automatic_local_object(
227+
assignments, dummy, target_type));
228+
229+
dereference_exprt dereference_expr(expr);
230+
231+
const auto zero_expr = zero_initializer(target_type, location, ns);
232+
CHECK_RETURN(zero_expr);
233+
234+
// add assignment of value to newly created symbol
235+
add_assignment(new_symbol, *zero_expr);
236+
237+
values[memory_location] = new_symbol;
238+
239+
const auto &struct_symbol = values.find(memory_location);
240+
241+
const auto maybe_member_expr = get_subexpression_at_offset(
242+
struct_symbol->second, member_offset, expr.type().subtype(), ns);
243+
if(maybe_member_expr.has_value())
244+
return *maybe_member_expr;
245+
UNREACHABLE;
246+
}
247+
248+
const auto maybe_member_expr = get_subexpression_at_offset(
249+
struct_symbol->symbol_expr(), member_offset, expr.type().subtype(), ns);
250+
if(maybe_member_expr.has_value())
251+
return *maybe_member_expr;
252+
253+
UNREACHABLE;
254+
}
255+
170256
exprt gdb_value_extractort::get_non_char_pointer_value(
171257
const exprt &expr,
172258
const memory_addresst &memory_location,
@@ -212,6 +298,24 @@ exprt gdb_value_extractort::get_non_char_pointer_value(
212298
}
213299
}
214300

301+
bool gdb_value_extractort::points_to_member(
302+
const pointer_valuet &pointer_value) const
303+
{
304+
if(pointer_value.pointee.find("+") != std::string::npos)
305+
return true;
306+
307+
const symbolt *pointee_symbol = symbol_table.lookup(pointer_value.pointee);
308+
if(pointee_symbol == nullptr)
309+
return false;
310+
const auto pointee_type = pointee_symbol->type;
311+
if(
312+
pointee_type.id() == ID_struct_tag || pointee_type.id() == ID_union_tag ||
313+
pointee_type.id() == ID_array || pointee_type.id() == ID_struct ||
314+
pointee_type.id() == ID_union)
315+
return true;
316+
return false;
317+
}
318+
215319
exprt gdb_value_extractort::get_pointer_value(
216320
const exprt &expr,
217321
const exprt &zero_expr,
@@ -236,7 +340,9 @@ exprt gdb_value_extractort::get_pointer_value(
236340
else
237341
{
238342
const exprt target_expr =
239-
get_non_char_pointer_value(expr, memory_location, location);
343+
points_to_member(value)
344+
? get_pointer_to_member_value(expr, value, location)
345+
: get_non_char_pointer_value(expr, memory_location, location);
240346

241347
if(target_expr.id() == ID_nil)
242348
{

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)