Skip to content

Commit 46135da

Browse files
author
Enrico Steffinlongo
committed
Fix SAT failure when bit-or-ing pointers
When setting shadow memory for pointer types the value is replicated by applying left shift and combining the shifted values with bitwise-or. However the SAT solver does not support bitwise-or for pointer types. This commit changes the way the replication is done for pointer types by converting them to an unsigned bitvector of the pointer type size, performing the shift and bitwise-or on this bitvector type and then casting it to pointer at the end.
1 parent c7b7bdc commit 46135da

File tree

2 files changed

+85
-3
lines changed

2 files changed

+85
-3
lines changed

src/util/expr_initializer.cpp

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ Author: Daniel Kroening, [email protected]
1818
#include "magic.h"
1919
#include "namespace.h" // IWYU pragma: keep
2020
#include "std_code.h"
21+
#include "symbol_table.h"
2122

2223
class expr_initializert
2324
{
@@ -393,9 +394,15 @@ exprt duplicate_per_byte(const exprt &init_byte_expr, const typet &output_type)
393394

394395
// We haven't got a constant. So, build the expression using shift-and-or.
395396
exprt::operandst values;
397+
398+
typet operation_type = output_type;
399+
if(const auto ptr_type = type_try_dynamic_cast<pointer_typet>(output_type))
400+
{
401+
operation_type = unsignedbv_typet{ptr_type->get_width()};
402+
}
396403
// Let's cast init_byte_expr to output_type.
397404
const exprt casted_init_byte_expr =
398-
typecast_exprt::conditional_cast(init_byte_expr, output_type);
405+
typecast_exprt::conditional_cast(init_byte_expr, operation_type);
399406
values.push_back(casted_init_byte_expr);
400407
for(size_t i = 1; i < size; ++i)
401408
{
@@ -404,8 +411,9 @@ exprt duplicate_per_byte(const exprt &init_byte_expr, const typet &output_type)
404411
from_integer(config.ansi_c.char_width * i, size_type())));
405412
}
406413
if(values.size() == 1)
407-
return values[0];
408-
return multi_ary_exprt(ID_bitor, values, output_type);
414+
return typecast_exprt::conditional_cast(values[0], output_type);
415+
return typecast_exprt::conditional_cast(
416+
multi_ary_exprt(ID_bitor, values, operation_type), output_type);
409417
}
410418

411419
// Anything else. We don't know what to do with it. So, just cast.

unit/util/expr_initializer.cpp

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,18 @@ TEST_CASE(
177177
from_integer(init_expr_value, signedbv_typet{init_expr_size}),
178178
output_type);
179179
REQUIRE(result_with_signed_init_type == result);
180+
181+
// Check that replicating a pointer_value is same as unsigned_bv.
182+
const pointer_typet pointer_type{bool_typet{}, output_size};
183+
const auto result_with_pointer_type = duplicate_per_byte(
184+
from_integer(init_expr_value, signedbv_typet{init_expr_size}),
185+
pointer_type);
186+
auto pointer_typed_expected =
187+
from_integer(output_expected_value, unsignedbv_typet{output_size});
188+
// Forcing the type to be pointer_typet otherwise from_integer fails when
189+
// the init value is not 0 (NULL).
190+
pointer_typed_expected.type() = pointer_type;
191+
REQUIRE(result_with_pointer_type == pointer_typed_expected);
180192
}
181193
}
182194

@@ -212,6 +224,21 @@ TEST_CASE(
212224
replicate_expression(casted_init_expr, output_type, replication_count);
213225

214226
REQUIRE(result == expected);
227+
228+
// Check that replicating a pointer_value is same as unsigned_bv modulo a
229+
// typecast outside.
230+
const pointer_typet pointer_type{bool_typet{}, output_size};
231+
const auto pointer_typed_result =
232+
duplicate_per_byte(init_expr, pointer_type);
233+
const auto pointer_unsigned_corr_type = unsignedbv_typet{output_size};
234+
const auto pointer_init_expr =
235+
typecast_exprt::conditional_cast(init_expr, pointer_unsigned_corr_type);
236+
const auto pointer_expected = typecast_exprt::conditional_cast(
237+
replicate_expression(
238+
pointer_init_expr, pointer_unsigned_corr_type, replication_count),
239+
pointer_type);
240+
241+
REQUIRE(pointer_typed_result == pointer_expected);
215242
}
216243
}
217244

@@ -312,6 +339,53 @@ TEST_CASE(
312339
}
313340
}
314341

342+
TEST_CASE(
343+
"expr_initializer on variable-bit pointer type",
344+
"[core][util][expr_initializer]")
345+
{
346+
auto test = expr_initializer_test_environmentt::make();
347+
const std::size_t input_type_size = GENERATE(3, 8, 16, 20);
348+
SECTION(
349+
"Testing with expected type as unsigned_bv of size " +
350+
std::to_string(input_type_size))
351+
{
352+
typet input_type = pointer_typet{bool_typet{}, input_type_size};
353+
SECTION("nondet_initializer works")
354+
{
355+
const auto result = nondet_initializer(input_type, test.loc, test.ns);
356+
REQUIRE(result.has_value());
357+
const auto expected = side_effect_expr_nondett{
358+
pointer_typet{bool_typet{}, input_type_size}, test.loc};
359+
REQUIRE(result.value() == expected);
360+
const auto expr_result =
361+
expr_initializer(input_type, test.loc, test.ns, exprt(ID_nondet));
362+
REQUIRE(expr_result == result);
363+
}
364+
SECTION("zero_initializer works")
365+
{
366+
const auto result = zero_initializer(input_type, test.loc, test.ns);
367+
REQUIRE(result.has_value());
368+
auto expected =
369+
from_integer(0, pointer_typet{bool_typet{}, input_type_size});
370+
REQUIRE(result.value() == expected);
371+
const auto expr_result = expr_initializer(
372+
input_type, test.loc, test.ns, constant_exprt(ID_0, char_type()));
373+
REQUIRE(expr_result == result);
374+
}
375+
SECTION("expr_initializer calls duplicate_per_byte")
376+
{
377+
const exprt init_value =
378+
from_integer(0x0A, unsignedbv_typet{config.ansi_c.char_width});
379+
const auto result =
380+
expr_initializer(input_type, test.loc, test.ns, init_value);
381+
REQUIRE(result.has_value());
382+
const auto expected = duplicate_per_byte(
383+
init_value, pointer_typet{bool_typet{}, input_type_size});
384+
REQUIRE(result.value() == expected);
385+
}
386+
}
387+
}
388+
315389
TEST_CASE(
316390
"expr_initializer on c_enum and c_enum_tag",
317391
"[core][util][expr_initializer]")

0 commit comments

Comments
 (0)