Skip to content

Commit 8015a72

Browse files
committed
analyzer: support RAW_DATA_CST [PR117262]
gcc/analyzer/ChangeLog: PR analyzer/117262 * region-model-manager.cc (region_model_manager::get_or_create_constant_svalue): Use NULL_TREE for the types of constant_svalue for RAW_DATA_CST. (region_model_manager::maybe_fold_sub_svalue): Generalize STRING_CST logic to also handle RAW_DATA_CST. (region_model_manager::maybe_get_char_from_cst): New. (region_model_manager::maybe_get_char_from_raw_data_cst): New. * region-model-manager.h (region_model_manager::maybe_get_char_from_cst): New decl. (region_model_manager::maybe_get_char_from_raw_data_cst): New decl. * region-model.cc (region_model::get_rvalue_1): Handle RAW_DATA_CST. * store.cc (get_subregion_within_ctor_for_ctor_pair): New. (binding_map::apply_ctor_pair_to_child_region): Call get_subregion_within_ctor_for_ctor_pair so that we handle RAW_DATA_CST. gcc/testsuite/ChangeLog: PR analyzer/117262 * c-c++-common/analyzer/raw-data-cst-pr117262-1.c: New test. * c-c++-common/analyzer/raw-data-cst-pr117262-2.c: New test. Signed-off-by: David Malcolm <[email protected]>
1 parent 0385556 commit 8015a72

File tree

6 files changed

+140
-6
lines changed

6 files changed

+140
-6
lines changed

gcc/analyzer/region-model-manager.cc

+48-5
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,12 @@ region_model_manager::get_or_create_constant_svalue (tree type, tree cst_expr)
242242
const svalue *
243243
region_model_manager::get_or_create_constant_svalue (tree cst_expr)
244244
{
245-
return get_or_create_constant_svalue (TREE_TYPE (cst_expr), cst_expr);
245+
tree type = TREE_TYPE (cst_expr);
246+
if (TREE_CODE (cst_expr) == RAW_DATA_CST)
247+
/* The type of a RAW_DATA_CST is the type of each element, rather than
248+
that of the constant as a whole, so use NULL_TREE for simplicity. */
249+
type = NULL_TREE;
250+
return get_or_create_constant_svalue (type, cst_expr);
246251
}
247252

248253
/* Return the svalue * for a constant_svalue for the INTEGER_CST
@@ -972,23 +977,24 @@ region_model_manager::maybe_fold_sub_svalue (tree type,
972977
}
973978
}
974979

975-
/* Handle getting individual chars from a STRING_CST. */
980+
/* Handle getting individual chars from a STRING_CST or RAW_DATA_CST. */
976981
if (tree cst = parent_svalue->maybe_get_constant ())
977-
if (TREE_CODE (cst) == STRING_CST)
982+
if (TREE_CODE (cst) == STRING_CST
983+
|| TREE_CODE (cst) == RAW_DATA_CST)
978984
{
979985
/* If we have a concrete 1-byte access within the parent region... */
980986
byte_range subregion_bytes (0, 0);
981987
if (subregion->get_relative_concrete_byte_range (&subregion_bytes)
982988
&& subregion_bytes.m_size_in_bytes == 1
983989
&& type)
984990
{
985-
/* ...then attempt to get that char from the STRING_CST. */
991+
/* ...then attempt to get that char from the constant. */
986992
HOST_WIDE_INT hwi_start_byte
987993
= subregion_bytes.m_start_byte_offset.to_shwi ();
988994
tree cst_idx
989995
= build_int_cst_type (size_type_node, hwi_start_byte);
990996
if (const svalue *char_sval
991-
= maybe_get_char_from_string_cst (cst, cst_idx))
997+
= maybe_get_char_from_cst (cst, cst_idx))
992998
return get_or_create_cast (type, char_sval);
993999
}
9941000
}
@@ -1505,6 +1511,24 @@ get_or_create_const_fn_result_svalue (tree type,
15051511
return const_fn_result_sval;
15061512
}
15071513

1514+
/* Given DATA_CST (a STRING_CST or RAW_DATA_CST) and BYTE_OFFSET_CST a constant,
1515+
attempt to get the character at that offset, returning either
1516+
the svalue for the character constant, or NULL if unsuccessful. */
1517+
1518+
const svalue *
1519+
region_model_manager::maybe_get_char_from_cst (tree data_cst,
1520+
tree byte_offset_cst)
1521+
{
1522+
switch (TREE_CODE (data_cst))
1523+
{
1524+
default: gcc_unreachable ();
1525+
case STRING_CST:
1526+
return maybe_get_char_from_string_cst (data_cst, byte_offset_cst);
1527+
case RAW_DATA_CST:
1528+
return maybe_get_char_from_raw_data_cst (data_cst, byte_offset_cst);
1529+
}
1530+
}
1531+
15081532
/* Get a tree for the size of STRING_CST, or NULL_TREE.
15091533
Note that this may be larger than TREE_STRING_LENGTH (implying
15101534
a run of trailing zero bytes from TREE_STRING_LENGTH up to this
@@ -1558,6 +1582,25 @@ region_model_manager::maybe_get_char_from_string_cst (tree string_cst,
15581582
return NULL;
15591583
}
15601584

1585+
/* Given RAW_DATA_CST, a RAW_DATA_CST and BYTE_OFFSET_CST a constant,
1586+
attempt to get the character at that offset, returning either
1587+
the svalue for the character constant, or NULL if unsuccessful. */
1588+
1589+
const svalue *
1590+
region_model_manager::maybe_get_char_from_raw_data_cst (tree raw_data_cst,
1591+
tree byte_offset_cst)
1592+
{
1593+
gcc_assert (TREE_CODE (raw_data_cst) == RAW_DATA_CST);
1594+
gcc_assert (TREE_CODE (byte_offset_cst) == INTEGER_CST);
1595+
1596+
offset_int o = (wi::to_offset (byte_offset_cst));
1597+
if (o >= 0 && o < RAW_DATA_LENGTH (raw_data_cst))
1598+
return get_or_create_int_cst
1599+
(TREE_TYPE (raw_data_cst),
1600+
RAW_DATA_UCHAR_ELT (raw_data_cst, o.to_uhwi ()));
1601+
return nullptr;
1602+
}
1603+
15611604
/* region consolidation. */
15621605

15631606
/* Return the region for FNDECL, creating it if necessary. */

gcc/analyzer/region-model-manager.h

+4
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,12 @@ class region_model_manager
9898
tree fndecl,
9999
const vec<const svalue *> &inputs);
100100

101+
const svalue *maybe_get_char_from_cst (tree data_cst,
102+
tree byte_offset_cst);
101103
const svalue *maybe_get_char_from_string_cst (tree string_cst,
102104
tree byte_offset_cst);
105+
const svalue *maybe_get_char_from_raw_data_cst (tree raw_data_cst,
106+
tree byte_offset_cst);
103107

104108
/* Dynamically-allocated svalue instances.
105109
The number of these within the analysis can grow arbitrarily.

gcc/analyzer/region-model.cc

+1
Original file line numberDiff line numberDiff line change
@@ -2801,6 +2801,7 @@ region_model::get_rvalue_1 (path_var pv, region_model_context *ctxt) const
28012801
case COMPLEX_CST:
28022802
case VECTOR_CST:
28032803
case STRING_CST:
2804+
case RAW_DATA_CST:
28042805
return m_mgr->get_or_create_constant_svalue (pv.m_tree);
28052806

28062807
case POINTER_PLUS_EXPR:

gcc/analyzer/store.cc

+34-1
Original file line numberDiff line numberDiff line change
@@ -905,6 +905,37 @@ get_subregion_within_ctor (const region *parent_reg, tree index,
905905
}
906906
}
907907

908+
/* Get the child region of PARENT_REG based upon (INDEX, VALUE) within a
909+
CONSTRUCTOR. */
910+
911+
static const region *
912+
get_subregion_within_ctor_for_ctor_pair (const region *parent_reg,
913+
tree index,
914+
tree value,
915+
region_model_manager *mgr)
916+
{
917+
if (TREE_CODE (index) == INTEGER_CST
918+
&& TREE_CODE (value) == RAW_DATA_CST)
919+
{
920+
/* Special-case; see tree.def's description of CONSTRUCTOR.
921+
We have RAW_DATA_LENGTH of bytes, starting at INDEX's start. */
922+
const region *start_reg
923+
= get_subregion_within_ctor (parent_reg, index, mgr);
924+
/* Build a bit range, relative to PARENT_REG. */
925+
region_offset start_offset = start_reg->get_offset (mgr);
926+
927+
if (!start_offset.concrete_p ())
928+
return nullptr;
929+
bit_offset_t start_bit_offset = start_offset.get_bit_offset ();
930+
int length = RAW_DATA_LENGTH (value);
931+
bit_range bits (start_bit_offset, length * BITS_PER_UNIT);
932+
933+
return mgr->get_bit_range (parent_reg, NULL_TREE, bits);
934+
}
935+
936+
return get_subregion_within_ctor (parent_reg, index, mgr);
937+
}
938+
908939
/* Get the svalue for VAL, a non-CONSTRUCTOR value within a CONSTRUCTOR. */
909940

910941
static const svalue *
@@ -1035,7 +1066,9 @@ binding_map::apply_ctor_pair_to_child_region (const region *parent_reg,
10351066
tree index, tree val)
10361067
{
10371068
const region *child_reg
1038-
= get_subregion_within_ctor (parent_reg, index, mgr);
1069+
= get_subregion_within_ctor_for_ctor_pair (parent_reg, index, val, mgr);
1070+
if (!child_reg)
1071+
return false;
10391072
if (TREE_CODE (val) == CONSTRUCTOR)
10401073
return apply_ctor_to_region (child_reg, val, mgr);
10411074
else
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
int
2+
main ()
3+
{
4+
const unsigned char meow_bytes[] = {
5+
0x69, 0x6e, 0x74, 0x0a, 0x6d, 0x61, 0x69, 0x6e, 0x20, 0x28, 0x29, 0x0a,
6+
0x7b, 0x0a, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x20, 0x75, 0x6e,
7+
0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x63, 0x68, 0x61, 0x72, 0x20,
8+
0x6d, 0x65, 0x6f, 0x77, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5b, 0x5d,
9+
0x20, 0x3d, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20,
10+
0x7d, 0x3b, 0x0a, 0x20, 0x20, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x20, 0x6d,
11+
};
12+
short meow[sizeof (meow_bytes) / sizeof (short)] = {};
13+
for (int i = 0; i < (int) (sizeof (meow) / sizeof (short)); i++)
14+
meow[i] = (meow_bytes[i * 2] << 8) | meow_bytes[i * 2 + 1];
15+
if (meow[0] != (0x69 << 8) + 0x6e)
16+
__builtin_abort ();
17+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#include "analyzer-decls.h"
2+
3+
extern void use (unsigned char);
4+
5+
void
6+
test ()
7+
{
8+
const unsigned char meow_bytes[] = {
9+
0x69, 0x6e, 0x74, 0x0a, 0x6d, 0x61, 0x69, 0x6e, 0x20, 0x28, 0x29, 0x0a,
10+
0x7b, 0x0a, 0x20, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x20, 0x75, 0x6e,
11+
0x73, 0x69, 0x67, 0x6e, 0x65, 0x64, 0x20, 0x63, 0x68, 0x61, 0x72, 0x20,
12+
0x6d, 0x65, 0x6f, 0x77, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5b, 0x5d,
13+
0x20, 0x3d, 0x20, 0x7b, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x0a, 0x20, 0x20,
14+
0x7d, 0x3b, 0x0a, 0x20, 0x20, 0x73, 0x68, 0x6f, 0x72, 0x74, 0x20, 0x6d,
15+
};
16+
17+
/* Verify that analyzer "knows" the values of individual bytes in
18+
the array. */
19+
20+
/* First row. */
21+
__analyzer_eval (meow_bytes[0] == 0x69); /* { dg-warning "TRUE" } */
22+
__analyzer_eval (meow_bytes[1] == 0x6e); /* { dg-warning "TRUE" } */
23+
__analyzer_eval (meow_bytes[11] == 0x0a); /* { dg-warning "TRUE" } */
24+
25+
/* Second row. */
26+
__analyzer_eval (meow_bytes[12] == 0x7b); /* { dg-warning "TRUE" } */
27+
__analyzer_eval (meow_bytes[23] == 0x6e); /* { dg-warning "TRUE" } */
28+
29+
/* Final row. */
30+
__analyzer_eval (meow_bytes[60] == 0x7d); /* { dg-warning "TRUE" } */
31+
__analyzer_eval (meow_bytes[70] == 0x20); /* { dg-warning "TRUE" } */
32+
__analyzer_eval (meow_bytes[71] == 0x6d); /* { dg-warning "TRUE" } */
33+
34+
use (meow_bytes[-1]); /* { dg-warning "stack-based buffer under-read" } */
35+
use (meow_bytes[72]); /* { dg-warning "stack-based buffer over-read" } */
36+
}

0 commit comments

Comments
 (0)