Skip to content

Commit 5802768

Browse files
authored
Merge pull request #7872 from esteffin/esteffin/fix-shadow-memory-float-duplication
Fix shadow memory float issue
2 parents 228b9dd + 1f21648 commit 5802768

File tree

3 files changed

+204
-58
lines changed

3 files changed

+204
-58
lines changed

regression/cbmc-shadow-memory/float1/test.desc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
KNOWNBUG
1+
CORE
22
main.c
33

44
^EXIT=0$

src/util/expr_initializer.cpp

Lines changed: 32 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ Author: Daniel Kroening, [email protected]
1313

1414
#include "arith_tools.h"
1515
#include "bitvector_expr.h"
16+
#include "byte_operators.h"
1617
#include "c_types.h"
1718
#include "config.h"
1819
#include "magic.h"
@@ -344,6 +345,27 @@ optionalt<exprt> expr_initializer(
344345
return expr_initializert(ns)(type, source_location, init_byte_expr);
345346
}
346347

348+
/// Typecast the input to the output if this is a signed/unsigned bv.
349+
/// Perform a reinterpret cast using byte_extract otherwise.
350+
/// @param expr the expression to be casted if necessary.
351+
/// @param out_type the type to cast the expression to.
352+
/// @return the casted or reinterpreted expression.
353+
static exprt cast_or_reinterpret(const exprt &expr, const typet &out_type)
354+
{
355+
// Same type --> no cast
356+
if(expr.type() == out_type)
357+
{
358+
return expr;
359+
}
360+
if(
361+
can_cast_type<signedbv_typet>(out_type) ||
362+
can_cast_type<unsignedbv_typet>(out_type))
363+
{
364+
return typecast_exprt::conditional_cast(expr, out_type);
365+
}
366+
return make_byte_extract(expr, from_integer(0, char_type()), out_type);
367+
}
368+
347369
/// Builds an expression of the given output type with each of its bytes
348370
/// initialized to the given initialization expression.
349371
/// Integer bitvector types are currently supported.
@@ -375,7 +397,7 @@ exprt duplicate_per_byte(const exprt &init_byte_expr, const typet &output_type)
375397
const auto init_size = init_type_as_bitvector->get_width();
376398
const irep_idt init_value = to_constant_expr(init_byte_expr).get_value();
377399

378-
// Create a new BV od `output_type` size with its representation being the
400+
// Create a new BV of `output_type` size with its representation being the
379401
// replication of the init_byte_expr (padded with 0) enough times to fill.
380402
const auto output_value =
381403
make_bvrep(out_width, [&init_size, &init_value](std::size_t index) {
@@ -400,6 +422,11 @@ exprt duplicate_per_byte(const exprt &init_byte_expr, const typet &output_type)
400422
{
401423
operation_type = unsignedbv_typet{ptr_type->get_width()};
402424
}
425+
if(
426+
const auto float_type = type_try_dynamic_cast<floatbv_typet>(output_type))
427+
{
428+
operation_type = unsignedbv_typet{float_type->get_width()};
429+
}
403430
// Let's cast init_byte_expr to output_type.
404431
const exprt casted_init_byte_expr =
405432
typecast_exprt::conditional_cast(init_byte_expr, operation_type);
@@ -410,10 +437,10 @@ exprt duplicate_per_byte(const exprt &init_byte_expr, const typet &output_type)
410437
casted_init_byte_expr,
411438
from_integer(config.ansi_c.char_width * i, size_type())));
412439
}
413-
if(values.size() == 1)
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);
440+
return cast_or_reinterpret(
441+
values.size() == 1 ? values[0]
442+
: multi_ary_exprt(ID_bitor, values, operation_type),
443+
output_type);
417444
}
418445

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

unit/util/expr_initializer.cpp

Lines changed: 171 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include <util/arith_tools.h>
44
#include <util/bitvector_expr.h>
55
#include <util/bitvector_types.h>
6+
#include <util/byte_operators.h>
67
#include <util/c_types.h>
78
#include <util/config.h>
89
#include <util/expr_initializer.h>
@@ -142,7 +143,7 @@ std::string to_hex(unsigned int value)
142143
}
143144

144145
TEST_CASE(
145-
"duplicate_per_byte on unsigned_bv with constant",
146+
"duplicate_per_byte on bitvector types with constant",
146147
"[core][util][duplicate_per_byte]")
147148
{
148149
auto test = expr_initializer_test_environmentt::make();
@@ -161,34 +162,73 @@ TEST_CASE(
161162
rowt{0xAB, 8, 0xABAB, 16}, // smaller-type constant gets replicated
162163
rowt{0xAB, 8, 0xBABAB, 20}); // smaller-type constant gets replicated
163164
SECTION(
164-
"Testing with output size " + std::to_string(output_size) + " init value " +
165-
to_hex(init_expr_value) + " of size " + std::to_string(init_expr_size))
165+
"Testing with init value " + to_hex(init_expr_value) + " of size " +
166+
std::to_string(init_expr_size))
166167
{
167-
typet output_type = unsignedbv_typet{output_size};
168-
const auto result = duplicate_per_byte(
169-
from_integer(init_expr_value, unsignedbv_typet{init_expr_size}),
170-
output_type);
171-
const auto expected =
172-
from_integer(output_expected_value, unsignedbv_typet{output_size});
173-
REQUIRE(result == expected);
174-
175-
// Check that signed-bv values are replicated including the sign bit.
176-
const auto result_with_signed_init_type = duplicate_per_byte(
177-
from_integer(init_expr_value, signedbv_typet{init_expr_size}),
178-
output_type);
179-
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);
168+
SECTION("filling unsignedbv of size " + std::to_string(output_size))
169+
{
170+
typet output_type = unsignedbv_typet{output_size};
171+
const auto result = duplicate_per_byte(
172+
from_integer(init_expr_value, unsignedbv_typet{init_expr_size}),
173+
output_type);
174+
const auto expected =
175+
from_integer(output_expected_value, unsignedbv_typet{output_size});
176+
REQUIRE(result == expected);
177+
178+
// Check that signed-bv values are replicated including the sign bit.
179+
const auto result_with_signed_init_type = duplicate_per_byte(
180+
from_integer(init_expr_value, signedbv_typet{init_expr_size}),
181+
output_type);
182+
REQUIRE(result_with_signed_init_type == result);
183+
}
184+
185+
SECTION("filling signedbv of size " + std::to_string(output_size))
186+
{
187+
typet output_type = signedbv_typet{output_size};
188+
const auto result = duplicate_per_byte(
189+
from_integer(init_expr_value, unsignedbv_typet{init_expr_size}),
190+
output_type);
191+
const auto expected =
192+
from_integer(output_expected_value, signedbv_typet{output_size});
193+
REQUIRE(result == expected);
194+
195+
// Check that signed-bv values are replicated including the sign bit.
196+
const auto result_with_signed_init_type = duplicate_per_byte(
197+
from_integer(init_expr_value, signedbv_typet{init_expr_size}),
198+
output_type);
199+
REQUIRE(result_with_signed_init_type == result);
200+
}
201+
202+
SECTION("filling pointer of size " + std::to_string(output_size))
203+
{
204+
// Check that replicating a pointer_value is same as unsigned_bv.
205+
const pointer_typet output_type{bool_typet{}, output_size};
206+
const auto result = duplicate_per_byte(
207+
from_integer(init_expr_value, signedbv_typet{init_expr_size}),
208+
output_type);
209+
auto expected =
210+
from_integer(output_expected_value, unsignedbv_typet{output_size});
211+
// Forcing the type to be pointer_typet otherwise from_integer fails when
212+
// the init value is not 0 (NULL).
213+
expected.type() = output_type;
214+
REQUIRE(result == expected);
215+
}
216+
217+
SECTION("filling float")
218+
{
219+
// Check that replicating to a float_value is same as unsigned_bv.
220+
const auto result = duplicate_per_byte(
221+
from_integer(init_expr_value, unsignedbv_typet{init_expr_size}),
222+
float_type());
223+
const auto expected_unsigned_value =
224+
expr_try_dynamic_cast<constant_exprt>(duplicate_per_byte(
225+
from_integer(init_expr_value, unsignedbv_typet{init_expr_size}),
226+
unsignedbv_typet{float_type().get_width()}));
227+
REQUIRE(expected_unsigned_value);
228+
const auto expected =
229+
constant_exprt{expected_unsigned_value->get_value(), float_type()};
230+
REQUIRE(result == expected);
231+
}
192232
}
193233
}
194234

@@ -207,38 +247,78 @@ TEST_CASE(
207247
rowt{8, 2, 1}, // bigger type gets truncated
208248
rowt{8, 16, 2}, // replicated twice
209249
rowt{8, 20, 3}); // replicated three times and truncated
210-
SECTION(
211-
"Testing with output size " + std::to_string(output_size) + " init size " +
212-
std::to_string(init_expr_size))
250+
SECTION("Testing with init size " + std::to_string(init_expr_size))
213251
{
214-
typet output_type = signedbv_typet{output_size};
215-
216252
const auto init_expr = plus_exprt{
217253
from_integer(1, unsignedbv_typet{init_expr_size}),
218254
from_integer(2, unsignedbv_typet{init_expr_size})};
219-
const auto result = duplicate_per_byte(init_expr, output_type);
255+
SECTION("filling signedbv of size " + std::to_string(output_size))
256+
{
257+
typet output_type = signedbv_typet{output_size};
220258

221-
const auto casted_init_expr =
222-
typecast_exprt::conditional_cast(init_expr, output_type);
223-
const auto expected =
224-
replicate_expression(casted_init_expr, output_type, replication_count);
259+
const auto result = duplicate_per_byte(init_expr, output_type);
225260

226-
REQUIRE(result == expected);
261+
const auto casted_init_expr =
262+
typecast_exprt::conditional_cast(init_expr, output_type);
263+
const auto expected =
264+
replicate_expression(casted_init_expr, output_type, replication_count);
265+
266+
REQUIRE(result == expected);
267+
}
227268

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);
269+
SECTION("filling unsignedbv of size " + std::to_string(output_size))
270+
{
271+
typet output_type = unsignedbv_typet{output_size};
272+
const auto result = duplicate_per_byte(init_expr, output_type);
240273

241-
REQUIRE(pointer_typed_result == pointer_expected);
274+
const auto casted_init_expr =
275+
typecast_exprt::conditional_cast(init_expr, output_type);
276+
const auto expected =
277+
replicate_expression(casted_init_expr, output_type, replication_count);
278+
279+
REQUIRE(result == expected);
280+
}
281+
282+
SECTION("filling pointer of size " + std::to_string(output_size))
283+
{
284+
// Check that replicating a pointer_value is same as unsigned_bv modulo a
285+
// byte_extract outside.
286+
const pointer_typet output_type{bool_typet{}, output_size};
287+
const auto result = duplicate_per_byte(init_expr, output_type);
288+
const auto unsigned_corr_type = unsignedbv_typet{output_size};
289+
const auto unsigned_init_expr =
290+
typecast_exprt::conditional_cast(init_expr, unsigned_corr_type);
291+
const auto expected = make_byte_extract(
292+
replicate_expression(
293+
unsigned_init_expr, unsigned_corr_type, replication_count),
294+
from_integer(0, char_type()),
295+
output_type);
296+
297+
REQUIRE(result == expected);
298+
}
299+
300+
SECTION("filling float")
301+
{
302+
// Check that replicating a float is same as unsigned_bv modulo a
303+
// byte_extract outside.
304+
// We ignore the output size and replication_count passed above as float
305+
// size is constant
306+
const std::size_t float_replication_count =
307+
(float_type().get_width() + config.ansi_c.char_width - 1) /
308+
config.ansi_c.char_width;
309+
const auto result = duplicate_per_byte(init_expr, float_type());
310+
const auto unsigned_corr_type =
311+
unsignedbv_typet{float_type().get_width()};
312+
const auto unsigned_init_expr =
313+
typecast_exprt::conditional_cast(init_expr, unsigned_corr_type);
314+
const auto expected = make_byte_extract(
315+
replicate_expression(
316+
unsigned_init_expr, unsigned_corr_type, float_replication_count),
317+
from_integer(0, char_type()),
318+
float_type());
319+
320+
REQUIRE(result == expected);
321+
}
242322
}
243323
}
244324

@@ -386,6 +466,45 @@ TEST_CASE(
386466
}
387467
}
388468

469+
TEST_CASE("expr_initializer on float type", "[core][util][expr_initializer]")
470+
{
471+
auto test = expr_initializer_test_environmentt::make();
472+
SECTION("Testing with expected type as float")
473+
{
474+
const typet input_type = float_type();
475+
SECTION("nondet_initializer works")
476+
{
477+
const auto result = nondet_initializer(input_type, test.loc, test.ns);
478+
REQUIRE(result.has_value());
479+
const auto expected = side_effect_expr_nondett{float_type(), test.loc};
480+
REQUIRE(result.value() == expected);
481+
const auto expr_result =
482+
expr_initializer(input_type, test.loc, test.ns, exprt(ID_nondet));
483+
REQUIRE(expr_result == result);
484+
}
485+
SECTION("zero_initializer works")
486+
{
487+
const auto result = zero_initializer(input_type, test.loc, test.ns);
488+
REQUIRE(result.has_value());
489+
auto expected = from_integer(0, float_type());
490+
REQUIRE(result.value() == expected);
491+
const auto expr_result = expr_initializer(
492+
input_type, test.loc, test.ns, constant_exprt(ID_0, char_type()));
493+
REQUIRE(expr_result == result);
494+
}
495+
SECTION("expr_initializer calls duplicate_per_byte")
496+
{
497+
const exprt init_value =
498+
from_integer(0x0A, unsignedbv_typet{config.ansi_c.char_width});
499+
const auto result =
500+
expr_initializer(input_type, test.loc, test.ns, init_value);
501+
REQUIRE(result.has_value());
502+
const auto expected = duplicate_per_byte(init_value, float_type());
503+
REQUIRE(result.value() == expected);
504+
}
505+
}
506+
}
507+
389508
TEST_CASE(
390509
"expr_initializer on c_enum and c_enum_tag",
391510
"[core][util][expr_initializer]")

0 commit comments

Comments
 (0)