@@ -449,7 +449,7 @@ make_label_text (bool can_colorize, const char *fmt, ...)
/* As above, but with singular vs plural. */
label_text
-make_label_text_n (bool can_colorize, int n,
+make_label_text_n (bool can_colorize, unsigned HOST_WIDE_INT n,
const char *singular_fmt,
const char *plural_fmt, ...)
{
@@ -359,7 +359,8 @@ extern const char *get_user_facing_name (const gcall *call);
extern void register_analyzer_pass ();
extern label_text make_label_text (bool can_colorize, const char *fmt, ...);
-extern label_text make_label_text_n (bool can_colorize, int n,
+extern label_text make_label_text_n (bool can_colorize,
+ unsigned HOST_WIDE_INT n,
const char *singular_fmt,
const char *plural_fmt, ...);
@@ -32,6 +32,8 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/analyzer.h"
#include "analyzer/analyzer-logging.h"
#include "analyzer/region-model.h"
+#include "analyzer/checker-event.h"
+#include "analyzer/checker-path.h"
#if ENABLE_ANALYZER
@@ -64,6 +66,20 @@ public:
interest->add_region_creation (m_reg);
}
+ void add_region_creation_events (const region *,
+ tree capacity,
+ location_t loc,
+ tree fndecl, int depth,
+ checker_path &emission_path) override
+ {
+ /* The memory space is described in the diagnostic message itself,
+ so we don't need an event for that. */
+ if (capacity)
+ emission_path.add_event
+ (make_unique<region_creation_event_capacity> (capacity,
+ loc, fndecl, depth));
+ }
+
protected:
enum memory_space get_memory_space () const
{
@@ -147,14 +163,16 @@ public:
other.m_byte_bound));
}
- label_text
- describe_region_creation_event (const evdesc::region_creation &ev) final
- override
+ void add_region_creation_events (const region *,
+ tree,
+ location_t loc,
+ tree fndecl, int depth,
+ checker_path &emission_path) final override
{
if (m_byte_bound && TREE_CODE (m_byte_bound) == INTEGER_CST)
- return ev.formatted_print ("capacity is %E bytes", m_byte_bound);
-
- return label_text ();
+ emission_path.add_event
+ (make_unique<region_creation_event_capacity> (m_byte_bound,
+ loc, fndecl, depth));
}
protected:
@@ -534,16 +552,6 @@ public:
&& pending_diagnostic::same_tree_p (m_capacity, other.m_capacity));
}
- label_text
- describe_region_creation_event (const evdesc::region_creation &ev) final
- override
- {
- if (m_capacity)
- return ev.formatted_print ("capacity is %qE bytes", m_capacity);
-
- return label_text ();
- }
-
protected:
tree m_offset;
tree m_num_bytes;
@@ -293,84 +293,77 @@ statement_event::get_desc (bool) const
/* class region_creation_event : public checker_event. */
-region_creation_event::region_creation_event (const region *reg,
- tree capacity,
- enum rce_kind kind,
- location_t loc,
+region_creation_event::region_creation_event (location_t loc,
tree fndecl,
int depth)
-: checker_event (EK_REGION_CREATION, loc, fndecl, depth),
- m_reg (reg),
- m_capacity (capacity),
- m_rce_kind (kind)
+: checker_event (EK_REGION_CREATION, loc, fndecl, depth)
{
- if (m_rce_kind == RCE_CAPACITY)
- gcc_assert (capacity);
}
-/* Implementation of diagnostic_event::get_desc vfunc for
- region_creation_event.
- There are effectively 3 kinds of region_region_event, to
- avoid combinatorial explosion by trying to convy the
- information in a single message. */
+/* The various region_creation_event subclasses' get_desc
+ implementations. */
label_text
-region_creation_event::get_desc (bool can_colorize) const
+region_creation_event_memory_space::get_desc (bool) const
{
- if (m_pending_diagnostic)
+ switch (m_mem_space)
{
- label_text custom_desc
- = m_pending_diagnostic->describe_region_creation_event
- (evdesc::region_creation (can_colorize, m_reg));
- if (custom_desc.get ())
- return custom_desc;
+ default:
+ return label_text::borrow ("region created here");
+ case MEMSPACE_STACK:
+ return label_text::borrow ("region created on stack here");
+ case MEMSPACE_HEAP:
+ return label_text::borrow ("region created on heap here");
}
+}
- switch (m_rce_kind)
+label_text
+region_creation_event_capacity::get_desc (bool can_colorize) const
+{
+ gcc_assert (m_capacity);
+ if (TREE_CODE (m_capacity) == INTEGER_CST)
{
- default:
- gcc_unreachable ();
-
- case RCE_MEM_SPACE:
- switch (m_reg->get_memory_space ())
- {
- default:
- return label_text::borrow ("region created here");
- case MEMSPACE_STACK:
- return label_text::borrow ("region created on stack here");
- case MEMSPACE_HEAP:
- return label_text::borrow ("region created on heap here");
- }
- break;
+ unsigned HOST_WIDE_INT hwi = tree_to_uhwi (m_capacity);
+ return make_label_text_n (can_colorize,
+ hwi,
+ "capacity: %wu byte",
+ "capacity: %wu bytes",
+ hwi);
+ }
+ else
+ return make_label_text (can_colorize,
+ "capacity: %qE bytes", m_capacity);
+}
- case RCE_CAPACITY:
- gcc_assert (m_capacity);
+label_text
+region_creation_event_allocation_size::get_desc (bool can_colorize) const
+{
+ if (m_capacity)
+ {
if (TREE_CODE (m_capacity) == INTEGER_CST)
- {
- unsigned HOST_WIDE_INT hwi = tree_to_uhwi (m_capacity);
- if (hwi == 1)
- return make_label_text (can_colorize,
- "capacity: %wu byte", hwi);
- else
- return make_label_text (can_colorize,
- "capacity: %wu bytes", hwi);
- }
+ return make_label_text_n (can_colorize,
+ tree_to_uhwi (m_capacity),
+ "allocated %E byte here",
+ "allocated %E bytes here",
+ m_capacity);
else
return make_label_text (can_colorize,
- "capacity: %qE bytes", m_capacity);
-
- case RCE_DEBUG:
- {
- pretty_printer pp;
- pp_format_decoder (&pp) = default_tree_printer;
- pp_string (&pp, "region creation: ");
- m_reg->dump_to_pp (&pp, true);
- if (m_capacity)
- pp_printf (&pp, " capacity: %qE", m_capacity);
- return label_text::take (xstrdup (pp_formatted_text (&pp)));
- }
- break;
+ "allocated %qE bytes here",
+ m_capacity);
}
+ return make_label_text (can_colorize, "allocated here");
+}
+
+label_text
+region_creation_event_debug::get_desc (bool) const
+{
+ pretty_printer pp;
+ pp_format_decoder (&pp) = default_tree_printer;
+ pp_string (&pp, "region creation: ");
+ m_reg->dump_to_pp (&pp, true);
+ if (m_capacity)
+ pp_printf (&pp, " capacity: %qE", m_capacity);
+ return label_text::take (xstrdup (pp_formatted_text (&pp)));
}
/* class function_entry_event : public checker_event. */
@@ -22,6 +22,7 @@ along with GCC; see the file COPYING3. If not see
#define GCC_ANALYZER_CHECKER_EVENT_H
#include "tree-logical-location.h"
+#include "analyzer/program-state.h"
namespace ana {
@@ -211,43 +212,105 @@ public:
const program_state m_dst_state;
};
-/* There are too many combinations to express region creation in one message,
+/* An abstract event subclass describing the creation of a region that
+ is significant for a diagnostic.
+
+ There are too many combinations to express region creation in one message,
so we emit multiple region_creation_event instances when each pertinent
region is created.
- This enum distinguishes between the different messages. */
+ The events are created by pending_diagnostic's add_region_creation_events
+ vfunc, which by default creates a region_creation_event_memory_space, and
+ if a capacity is known, a region_creation_event_capacity, giving e.g.:
+ (1) region created on stack here
+ (2) capacity: 100 bytes
+ but this vfunc can be overridden to create other events if other wordings
+ are more appropriate foa a given pending_diagnostic. */
-enum rce_kind
+class region_creation_event : public checker_event
{
- /* Generate a message based on the memory space of the region
- e.g. "region created on stack here". */
- RCE_MEM_SPACE,
+protected:
+ region_creation_event (location_t loc, tree fndecl, int depth);
+};
+
+/* Concrete subclass of region_creation_event.
+ Generates a message based on the memory space of the region
+ e.g. "region created on stack here". */
- /* Generate a message based on the capacity of the region
- e.g. "capacity: 100 bytes". */
- RCE_CAPACITY,
+class region_creation_event_memory_space : public region_creation_event
+{
+public:
+ region_creation_event_memory_space (enum memory_space mem_space,
+ location_t loc, tree fndecl, int depth)
+ : region_creation_event (loc, fndecl, depth),
+ m_mem_space (mem_space)
+ {
+ }
- /* Generate a debug message. */
- RCE_DEBUG
+ label_text get_desc (bool can_colorize) const final override;
+
+private:
+ enum memory_space m_mem_space;
};
-/* A concrete event subclass describing the creation of a region that
- is significant for a diagnostic. */
+/* Concrete subclass of region_creation_event.
+ Generates a message based on the capacity of the region
+ e.g. "capacity: 100 bytes". */
-class region_creation_event : public checker_event
+class region_creation_event_capacity : public region_creation_event
{
public:
- region_creation_event (const region *reg,
- tree capacity,
- enum rce_kind kind,
- location_t loc, tree fndecl, int depth);
+ region_creation_event_capacity (tree capacity,
+ location_t loc, tree fndecl, int depth)
+ : region_creation_event (loc, fndecl, depth),
+ m_capacity (capacity)
+ {
+ gcc_assert (m_capacity);
+ }
+
+ label_text get_desc (bool can_colorize) const final override;
+
+private:
+ tree m_capacity;
+};
+
+/* Concrete subclass of region_creation_event.
+ Generates a message based on the capacity of the region
+ e.g. "allocated 100 bytes here". */
+
+class region_creation_event_allocation_size : public region_creation_event
+{
+public:
+ region_creation_event_allocation_size (tree capacity,
+ location_t loc, tree fndecl, int depth)
+ : region_creation_event (loc, fndecl, depth),
+ m_capacity (capacity)
+ {}
+
+ label_text get_desc (bool can_colorize) const final override;
+
+private:
+ tree m_capacity;
+};
+
+/* Concrete subclass of region_creation_event.
+ Generates a debug message intended for analyzer developers. */
+
+class region_creation_event_debug : public region_creation_event
+{
+public:
+ region_creation_event_debug (const region *reg, tree capacity,
+ location_t loc, tree fndecl, int depth)
+ : region_creation_event (loc, fndecl, depth),
+ m_reg (reg), m_capacity (capacity)
+ {
+ }
label_text get_desc (bool can_colorize) const final override;
private:
const region *m_reg;
tree m_capacity;
- enum rce_kind m_rce_kind;
};
/* An event subclass describing the entry to a function. */
@@ -141,7 +141,8 @@ checker_path::debug () const
If DEBUG is true, also create an RCE_DEBUG event. */
void
-checker_path::add_region_creation_events (const region *reg,
+checker_path::add_region_creation_events (pending_diagnostic *pd,
+ const region *reg,
const region_model *model,
location_t loc,
tree fndecl, int depth,
@@ -152,16 +153,11 @@ checker_path::add_region_creation_events (const region *reg,
if (const svalue *capacity_sval = model->get_capacity (reg))
capacity = model->get_representative_tree (capacity_sval);
- add_event (make_unique<region_creation_event> (reg, capacity, RCE_MEM_SPACE,
- loc, fndecl, depth));
-
- if (capacity)
- add_event (make_unique<region_creation_event> (reg, capacity, RCE_CAPACITY,
- loc, fndecl, depth));
+ pd->add_region_creation_events (reg, capacity, loc, fndecl, depth, *this);
if (debug)
- add_event (make_unique<region_creation_event> (reg, capacity, RCE_DEBUG,
- loc, fndecl, depth));
+ add_event (make_unique<region_creation_event_debug> (reg, capacity,
+ loc, fndecl, depth));
}
void
@@ -76,7 +76,8 @@ public:
m_events[idx] = new_event;
}
- void add_region_creation_events (const region *reg,
+ void add_region_creation_events (pending_diagnostic *pd,
+ const region *reg,
const region_model *model,
location_t loc,
tree fndecl, int depth,
@@ -1447,7 +1447,8 @@ diagnostic_manager::build_emission_path (const path_builder &pb,
&& DECL_SOURCE_LOCATION (decl) != UNKNOWN_LOCATION)
{
emission_path->add_region_creation_events
- (reg, NULL,
+ (pb.get_pending_diagnostic (),
+ reg, NULL,
DECL_SOURCE_LOCATION (decl),
NULL_TREE,
0,
@@ -1463,7 +1464,8 @@ diagnostic_manager::build_emission_path (const path_builder &pb,
const exploded_edge *eedge = epath.m_edges[i];
add_events_for_eedge (pb, *eedge, emission_path, &interest);
}
- add_event_on_final_node (epath.get_final_enode (), emission_path, &interest);
+ add_event_on_final_node (pb, epath.get_final_enode (),
+ emission_path, &interest);
}
/* Emit a region_creation_event when requested on the last statement in
@@ -1475,7 +1477,8 @@ diagnostic_manager::build_emission_path (const path_builder &pb,
*/
void
-diagnostic_manager::add_event_on_final_node (const exploded_node *final_enode,
+diagnostic_manager::add_event_on_final_node (const path_builder &pb,
+ const exploded_node *final_enode,
checker_path *emission_path,
interesting_t *interest) const
{
@@ -1512,7 +1515,8 @@ diagnostic_manager::add_event_on_final_node (const exploded_node *final_enode,
case RK_HEAP_ALLOCATED:
case RK_ALLOCA:
emission_path->add_region_creation_events
- (reg,
+ (pb.get_pending_diagnostic (),
+ reg,
dst_model,
src_point.get_location (),
src_point.get_fndecl (),
@@ -1940,7 +1944,8 @@ diagnostic_manager::add_events_for_eedge (const path_builder &pb,
&& DECL_SOURCE_LOCATION (decl) != UNKNOWN_LOCATION)
{
emission_path->add_region_creation_events
- (reg, dst_state.m_region_model,
+ (pb.get_pending_diagnostic (),
+ reg, dst_state.m_region_model,
DECL_SOURCE_LOCATION (decl),
dst_point.get_fndecl (),
dst_stack_depth,
@@ -2036,7 +2041,8 @@ diagnostic_manager::add_events_for_eedge (const path_builder &pb,
case RK_HEAP_ALLOCATED:
case RK_ALLOCA:
emission_path->add_region_creation_events
- (reg, dst_model,
+ (pb.get_pending_diagnostic (),
+ reg, dst_model,
src_point.get_location (),
src_point.get_fndecl (),
src_stack_depth,
@@ -148,7 +148,8 @@ private:
const exploded_path &epath,
checker_path *emission_path) const;
- void add_event_on_final_node (const exploded_node *final_enode,
+ void add_event_on_final_node (const path_builder &pb,
+ const exploded_node *final_enode,
checker_path *emission_path,
interesting_t *interest) const;
@@ -199,6 +199,26 @@ pending_diagnostic::add_call_event (const exploded_edge &eedge,
src_stack_depth));
}
+/* Base implementation of pending_diagnostic::add_region_creation_events.
+ See the comment for class region_creation_event. */
+
+void
+pending_diagnostic::add_region_creation_events (const region *reg,
+ tree capacity,
+ location_t loc,
+ tree fndecl, int depth,
+ checker_path &emission_path)
+{
+ emission_path.add_event
+ (make_unique<region_creation_event_memory_space> (reg->get_memory_space (),
+ loc, fndecl, depth));
+
+ if (capacity)
+ emission_path.add_event
+ (make_unique<region_creation_event_capacity> (capacity,
+ loc, fndecl, depth));
+}
+
/* Base implementation of pending_diagnostic::add_final_event.
Add a warning_event to the end of EMISSION_PATH. */
@@ -59,17 +59,6 @@ struct event_desc
bool m_colorize;
};
-/* For use by pending_diagnostic::describe_region_creation. */
-
-struct region_creation : public event_desc
-{
- region_creation (bool colorize, const region *reg)
- : event_desc (colorize), m_reg (reg)
- {}
-
- const region *m_reg;
-};
-
/* For use by pending_diagnostic::describe_state_change. */
struct state_change : public event_desc
@@ -219,23 +208,6 @@ class pending_diagnostic
for the diagnostic, and FALSE for events in their paths. */
virtual location_t fixup_location (location_t loc, bool primary) const;
- /* For greatest precision-of-wording, the various following "describe_*"
- virtual functions give the pending diagnostic a way to describe events
- in a diagnostic_path in terms that make sense for that diagnostic.
-
- In each case, return a non-NULL label_text to give the event a custom
- description; NULL otherwise (falling back on a more generic
- description). */
-
- /* Precision-of-wording vfunc for describing a region creation event
- triggered by the mark_interesting_stuff vfunc. */
- virtual label_text
- describe_region_creation_event (const evdesc::region_creation &)
- {
- /* Default no-op implementation. */
- return label_text ();
- }
-
/* Precision-of-wording vfunc for describing a critical state change
within the diagnostic_path.
@@ -338,6 +310,15 @@ class pending_diagnostic
virtual void add_call_event (const exploded_edge &,
checker_path *);
+ /* Vfunc for adding any events for the creation of regions identified
+ by the mark_interesting_stuff vfunc.
+ See the comment for class region_creation_event. */
+ virtual void add_region_creation_events (const region *reg,
+ tree capacity,
+ location_t loc,
+ tree fndecl, int depth,
+ checker_path &emission_path);
+
/* Vfunc for adding the final warning_event to a checker_path, so that e.g.
the infinite recursion diagnostic can have its diagnostic appear at
the callsite, but the final event in the path be at the entrypoint
@@ -74,6 +74,8 @@ along with GCC; see the file COPYING3. If not see
#include "calls.h"
#include "is-a.h"
#include "gcc-rich-location.h"
+#include "analyzer/checker-event.h"
+#include "analyzer/checker-path.h"
#if ENABLE_ANALYZER
@@ -2777,12 +2779,14 @@ class dubious_allocation_size
{
public:
dubious_allocation_size (const region *lhs, const region *rhs)
- : m_lhs (lhs), m_rhs (rhs), m_expr (NULL_TREE)
+ : m_lhs (lhs), m_rhs (rhs), m_expr (NULL_TREE),
+ m_has_allocation_event (false)
{}
dubious_allocation_size (const region *lhs, const region *rhs,
tree expr)
- : m_lhs (lhs), m_rhs (rhs), m_expr (expr)
+ : m_lhs (lhs), m_rhs (rhs), m_expr (expr),
+ m_has_allocation_event (false)
{}
const char *get_kind () const final override
@@ -2811,34 +2815,17 @@ public:
" of the pointee's size");
}
- label_text
- describe_region_creation_event (const evdesc::region_creation &ev) final
- override
- {
- m_allocation_event = &ev;
- if (m_expr)
- {
- if (TREE_CODE (m_expr) == INTEGER_CST)
- return ev.formatted_print ("allocated %E bytes here", m_expr);
- else
- return ev.formatted_print ("allocated %qE bytes here", m_expr);
- }
-
- return ev.formatted_print ("allocated here");
- }
-
label_text describe_final_event (const evdesc::final_event &ev) final
override
{
tree pointee_type = TREE_TYPE (m_lhs->get_type ());
- if (m_allocation_event)
- /* Fallback: Typically, we should always
- see an m_allocation_event before. */
+ if (m_has_allocation_event)
return ev.formatted_print ("assigned to %qT here;"
" %<sizeof (%T)%> is %qE",
m_lhs->get_type (), pointee_type,
size_in_bytes (pointee_type));
-
+ /* Fallback: Typically, we should always see an allocation_event
+ before. */
if (m_expr)
{
if (TREE_CODE (m_expr) == INTEGER_CST)
@@ -2859,6 +2846,20 @@ public:
size_in_bytes (pointee_type));
}
+ void
+ add_region_creation_events (const region *,
+ tree capacity,
+ location_t loc,
+ tree fndecl, int depth,
+ checker_path &emission_path) final override
+ {
+ emission_path.add_event
+ (make_unique<region_creation_event_allocation_size> (capacity,
+ loc, fndecl, depth));
+
+ m_has_allocation_event = true;
+ }
+
void mark_interesting_stuff (interesting_t *interest) final override
{
interest->add_region_creation (m_rhs);
@@ -2868,7 +2869,7 @@ private:
const region *m_lhs;
const region *m_rhs;
const tree m_expr;
- const evdesc::region_creation *m_allocation_event;
+ bool m_has_allocation_event;
};
/* Return true on dubious allocation sizes for constant sizes. */
@@ -56,6 +56,6 @@ void test_5 (void)
free (ptr);
/* { dg-warning "allocated buffer size is not a multiple of the pointee's size \\\[CWE-131\\\]" "warning" { target *-*-* } malloc5 } */
- /* { dg-message "1 bytes" "note" { target *-*-* } malloc5 } */
+ /* { dg-message "allocated 1 byte here" "note" { target *-*-* } malloc5 } */
/* { dg-message "'struct base \\*' here; 'sizeof \\(struct base\\)' is '\\d+'" "note" { target *-*-* } malloc5 } */
}
new file mode 100644
@@ -0,0 +1,59 @@
+/* { dg-additional-options "-fdiagnostics-path-format=inline-events -fdiagnostics-show-caret" } */
+
+#include <stdint.h>
+
+void test_constant_1 (void)
+{
+ int32_t *ptr = __builtin_malloc (1); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size" } */
+ __builtin_free (ptr);
+}
+
+/* { dg-begin-multiline-output "" }
+ int32_t *ptr = __builtin_malloc (1);
+ ^~~~~~~~~~~~~~~~~~~~
+ 'test_constant_1': events 1-2
+ |
+ | int32_t *ptr = __builtin_malloc (1);
+ | ^~~~~~~~~~~~~~~~~~~~
+ | |
+ | (1) allocated 1 byte here
+ | (2) assigned to 'int32_t *'
+ |
+ { dg-end-multiline-output "" } */
+
+void test_constant_2 (void)
+{
+ int32_t *ptr = __builtin_malloc (2); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size" } */
+ __builtin_free (ptr);
+}
+
+/* { dg-begin-multiline-output "" }
+ int32_t *ptr = __builtin_malloc (2);
+ ^~~~~~~~~~~~~~~~~~~~
+ 'test_constant_2': events 1-2
+ |
+ | int32_t *ptr = __builtin_malloc (2);
+ | ^~~~~~~~~~~~~~~~~~~~
+ | |
+ | (1) allocated 2 bytes here
+ | (2) assigned to 'int32_t *'
+ |
+ { dg-end-multiline-output "" } */
+
+void test_symbolic (int n)
+{
+ int32_t *ptr = __builtin_malloc (n * 2); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size" } */
+ __builtin_free (ptr);
+}
+
+/* { dg-begin-multiline-output "" }
+ int32_t *ptr = __builtin_malloc (n * 2);
+ ^~~~~~~~~~~~~~~~~~~~~~~~
+ 'test_symbolic': event 1
+ |
+ | int32_t *ptr = __builtin_malloc (n * 2);
+ | ^~~~~~~~~~~~~~~~~~~~~~~~
+ | |
+ | (1) allocated 'n * 2' bytes and assigned to 'int32_t *'
+ |
+ { dg-end-multiline-output "" } */
new file mode 100644
@@ -0,0 +1,62 @@
+/* { dg-additional-options "-fdiagnostics-path-format=inline-events -fdiagnostics-show-caret -fanalyzer-fine-grained" } */
+/* { dg-require-effective-target alloca } */
+
+#include <stdint.h>
+
+void test_constant_1 (void)
+{
+ int32_t *ptr = __builtin_alloca (1); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size" } */
+}
+
+/* { dg-begin-multiline-output "" }
+ int32_t *ptr = __builtin_alloca (1);
+ ^~~~~~~~~~~~~~~~~~~~
+ 'test_constant_1': events 1-2
+ |
+ | int32_t *ptr = __builtin_alloca (1);
+ | ^~~~~~~~~~~~~~~~~~~~
+ | |
+ | (1) allocated 1 byte here
+ | (2) assigned to 'int32_t *'
+ |
+ { dg-end-multiline-output "" } */
+
+void test_constant_2 (void)
+{
+ int32_t *ptr = __builtin_alloca (2); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size" } */
+}
+
+/* { dg-begin-multiline-output "" }
+ int32_t *ptr = __builtin_alloca (2);
+ ^~~~~~~~~~~~~~~~~~~~
+ 'test_constant_2': events 1-2
+ |
+ | int32_t *ptr = __builtin_alloca (2);
+ | ^~~~~~~~~~~~~~~~~~~~
+ | |
+ | (1) allocated 2 bytes here
+ | (2) assigned to 'int32_t *'
+ |
+ { dg-end-multiline-output "" } */
+
+void test_symbolic (int n)
+{
+ int32_t *ptr = __builtin_alloca (n * 2); /* { dg-warning "allocated buffer size is not a multiple of the pointee's size" } */
+}
+
+/* { dg-begin-multiline-output "" }
+ int32_t *ptr = __builtin_alloca (n * 2);
+ ^~~~~~~~~~~~~~~~~~~~~~~~
+ 'test_symbolic': events 1-2
+ |
+ | int32_t *ptr = __builtin_alloca (n * 2);
+ | ^~~~~~~~~~~~~~~~~~~~~~~~
+ | |
+ | (1) allocated 'n * 2' bytes here
+ | (2) assigned to 'int32_t *'
+ |
+ { dg-end-multiline-output "" } */
+
+/* FIXME: am getting a duplicate warning here for some reason
+ without -fanalyzer-fine-grained (PR PR analyzer/107851). */
+
@@ -25,7 +25,7 @@ void int_arr_write_element_after_end_off_by_one(int32_t x)
| int32_t arr[10];
| ^~~
| |
- | (1) capacity is 40 bytes
+ | (1) capacity: 40 bytes
|
+--> 'int_arr_write_element_after_end_off_by_one': event 2 (depth 1)
|
new file mode 100644
@@ -0,0 +1,32 @@
+/* Integration test of how the execution path looks for
+ -Wanalyzer-out-of-bounds with a symbolic size. */
+
+/* { dg-additional-options "-fdiagnostics-show-path-depths" } */
+/* { dg-additional-options "-fdiagnostics-path-format=inline-events -fdiagnostics-show-caret" } */
+
+#include <stdint.h>
+#include <stdlib.h>
+
+void int_vla_write_element_after_end_off_by_one(int32_t x, size_t n)
+{
+ int32_t arr[n];
+
+ arr[n] = x; /* { dg-warning "stack-based buffer overflow" } */
+}
+
+/* { dg-begin-multiline-output "" }
+ arr[n] = x;
+ ~~~~~~~^~~
+ 'int_vla_write_element_after_end_off_by_one': events 1-2 (depth 1)
+ |
+ | int32_t arr[n];
+ | ^~~
+ | |
+ | (1) capacity: 'n * 4' bytes
+ |
+ | arr[n] = x;
+ | ~~~~~~~~~~
+ | |
+ | (2) write of 4 bytes at offset 'n * 4' exceeds the buffer
+ |
+ { dg-end-multiline-output "" } */
@@ -1,4 +1,4 @@
-char arr[10]; /* { dg-message "capacity is 10 bytes" } */
+char arr[10]; /* { dg-message "capacity: 10 bytes" } */
char char_arr_read_element_before_start_far(void)
{
@@ -1,6 +1,6 @@
#include <stdint.h>
-int32_t arr[10]; /* { dg-message "capacity is 40 bytes" } */
+int32_t arr[10]; /* { dg-message "capacity: 40 bytes" } */
int32_t int_arr_read_element_before_start_far(void)
{
@@ -1,4 +1,4 @@
-char arr[10]; /* { dg-message "capacity is 10 bytes" } */
+char arr[10]; /* { dg-message "capacity: 10 bytes" } */
void char_arr_write_element_before_start_far(char x)
{
@@ -1,6 +1,6 @@
#include <stdint.h>
-int32_t arr[10]; /* { dg-message "capacity is 40 bytes" } */
+int32_t arr[10]; /* { dg-message "capacity: 40 bytes" } */
void int_arr_write_element_before_start_far(int32_t x)
{