@@ -29,6 +29,8 @@ along with GCC; see the file COPYING3. If not see
#include "diagnostic.h"
#include "intl.h"
#include "analyzer/analyzer.h"
+#include "tree-pretty-print.h"
+#include "diagnostic-event-id.h"
#if ENABLE_ANALYZER
@@ -216,6 +218,63 @@ get_diagnostic_tree_for_gassign (const gassign *assign_stmt)
return get_diagnostic_tree_for_gassign_1 (assign_stmt, &visited);
}
+/* Generate a JSON value for NODE, which can be NULL_TREE.
+ This is intended for debugging the analyzer rather than serialization and
+ thus is a string (or null, for NULL_TREE). */
+
+json::value *
+tree_to_json (tree node)
+{
+ if (!node)
+ return new json::literal (json::JSON_NULL);
+
+ pretty_printer pp;
+ dump_generic_node (&pp, node, 0, TDF_VOPS|TDF_MEMSYMS, false);
+ return new json::string (pp_formatted_text (&pp));
+}
+
+/* Generate a JSON value for EVENT_ID.
+ This is intended for debugging the analyzer rather than serialization and
+ thus is a string matching those seen in event messags (or null,
+ for unknown). */
+
+json::value *
+diagnostic_event_id_to_json (const diagnostic_event_id_t &event_id)
+{
+ if (event_id.known_p ())
+ {
+ pretty_printer pp;
+ pp_printf (&pp, "%@", &event_id);
+ return new json::string (pp_formatted_text (&pp));
+ }
+ else
+ return new json::literal (json::JSON_NULL);
+}
+
+/* Generate a JSON value for OFFSET.
+ This is intended for debugging the analyzer rather than serialization and
+ thus is a string. */
+
+json::value *
+bit_offset_to_json (const bit_offset_t &offset)
+{
+ pretty_printer pp;
+ pp_wide_int_large (&pp, offset, SIGNED);
+ return new json::string (pp_formatted_text (&pp));
+}
+
+/* Generate a JSON value for OFFSET.
+ This is intended for debugging the analyzer rather than serialization and
+ thus is a string. */
+
+json::value *
+byte_offset_to_json (const byte_offset_t &offset)
+{
+ pretty_printer pp;
+ pp_wide_int_large (&pp, offset, SIGNED);
+ return new json::string (pp_formatted_text (&pp));
+}
+
} // namespace ana
/* Helper function for checkers. Is the CALL to the given function name,
@@ -415,6 +415,18 @@ extern void log_stashed_constants (logger *logger);
extern FILE *get_or_create_any_logfile ();
+extern json::value *
+tree_to_json (tree node);
+
+extern json::value *
+diagnostic_event_id_to_json (const diagnostic_event_id_t &);
+
+extern json::value *
+bit_offset_to_json (const bit_offset_t &offset);
+
+extern json::value *
+byte_offset_to_json (const byte_offset_t &offset);
+
} // namespace ana
extern bool is_special_named_call_p (const gcall *call, const char *funcname,
@@ -31,6 +31,7 @@ along with GCC; see the file COPYING3. If not see
#include "gimple-iterator.h"
#include "diagnostic-core.h"
#include "diagnostic-diagram.h"
+#include "diagnostic-format-sarif.h"
#include "analyzer/analyzer.h"
#include "analyzer/analyzer-logging.h"
#include "analyzer/region-model.h"
@@ -110,6 +111,23 @@ public:
*this));
}
+ void maybe_add_sarif_properties (sarif_object &result_obj)
+ const override
+ {
+ sarif_property_bag &props = result_obj.get_or_create_properties ();
+#define PROPERTY_PREFIX "gcc/analyzer/out_of_bounds/"
+ props.set_string (PROPERTY_PREFIX "dir",
+ get_dir () == DIR_READ ? "read" : "write");
+ props.set (PROPERTY_PREFIX "model", m_model.to_json ());
+ props.set (PROPERTY_PREFIX "region", m_reg->to_json ());
+ props.set (PROPERTY_PREFIX "diag_arg", tree_to_json (m_diag_arg));
+ if (m_sval_hint)
+ props.set (PROPERTY_PREFIX "sval_hint", m_sval_hint->to_json ());
+ props.set (PROPERTY_PREFIX "region_creation_event_id",
+ diagnostic_event_id_to_json (m_region_creation_event_id));
+#undef PROPERTY_PREFIX
+ }
+
virtual enum access_direction get_dir () const = 0;
protected:
@@ -220,6 +238,21 @@ public:
&& m_out_of_bounds_bits == other.m_out_of_bounds_bits);
}
+ void maybe_add_sarif_properties (sarif_object &result_obj)
+ const override
+ {
+ out_of_bounds::maybe_add_sarif_properties (result_obj);
+ sarif_property_bag &props = result_obj.get_or_create_properties ();
+#define PROPERTY_PREFIX "gcc/analyzer/concrete_out_of_bounds/"
+ props.set (PROPERTY_PREFIX "out_of_bounds_bits",
+ m_out_of_bounds_bits.to_json ());
+ byte_range out_of_bounds_bytes (0, 0);
+ if (get_out_of_bounds_bytes (&out_of_bounds_bytes))
+ props.set (PROPERTY_PREFIX "out_of_bounds_bytes",
+ out_of_bounds_bytes.to_json ());
+#undef PROPERTY_PREFIX
+ }
+
bool get_out_of_bounds_bytes (byte_range *out) const
{
return m_out_of_bounds_bits.as_byte_range (out);
@@ -271,6 +304,19 @@ public:
*this));
}
+ void maybe_add_sarif_properties (sarif_object &result_obj)
+ const final override
+ {
+ concrete_out_of_bounds::maybe_add_sarif_properties (result_obj);
+ sarif_property_bag &props = result_obj.get_or_create_properties ();
+#define PROPERTY_PREFIX "gcc/analyzer/concrete_past_the_end/"
+ props.set (PROPERTY_PREFIX "bit_bound",
+ tree_to_json (m_bit_bound));
+ props.set (PROPERTY_PREFIX "byte_bound",
+ tree_to_json (m_byte_bound));
+#undef PROPERTY_PREFIX
+ }
+
protected:
tree m_bit_bound;
tree m_byte_bound;
@@ -862,6 +908,18 @@ public:
&& pending_diagnostic::same_tree_p (m_capacity, other.m_capacity));
}
+ void maybe_add_sarif_properties (sarif_object &result_obj)
+ const final override
+ {
+ out_of_bounds::maybe_add_sarif_properties (result_obj);
+ sarif_property_bag &props = result_obj.get_or_create_properties ();
+#define PROPERTY_PREFIX "gcc/analyzer/symbolic_past_the_end/"
+ props.set (PROPERTY_PREFIX "offset", tree_to_json (m_offset));
+ props.set (PROPERTY_PREFIX "num_bytes", tree_to_json (m_num_bytes));
+ props.set (PROPERTY_PREFIX "capacity", tree_to_json (m_capacity));
+#undef PROPERTY_PREFIX
+ }
+
protected:
tree m_offset;
tree m_num_bytes;
@@ -211,6 +211,31 @@ region_to_value_map::dump (bool simple) const
pp_flush (&pp);
}
+/* Generate a JSON value for this region_to_value_map.
+ This is intended for debugging the analyzer rather than
+ serialization. */
+
+json::object *
+region_to_value_map::to_json () const
+{
+ json::object *map_obj = new json::object ();
+
+ auto_vec<const region *> regs;
+ for (iterator iter = begin (); iter != end (); ++iter)
+ regs.safe_push ((*iter).first);
+ regs.qsort (region::cmp_ptr_ptr);
+
+ unsigned i;
+ const region *reg;
+ FOR_EACH_VEC_ELT (regs, i, reg)
+ {
+ label_text reg_desc = reg->get_desc ();
+ const svalue *sval = *get (reg);
+ map_obj->set (reg_desc.get (), sval->to_json ());
+ }
+
+ return map_obj;
+}
/* Attempt to merge THIS with OTHER, writing the result
to OUT.
@@ -429,6 +454,22 @@ region_model::debug () const
dump (true);
}
+/* Generate a JSON value for this region_model.
+ This is intended for debugging the analyzer rather than
+ serialization. */
+
+json::object *
+region_model::to_json () const
+{
+ json::object *model_obj = new json::object ();
+ model_obj->set ("store", m_store.to_json ());
+ model_obj->set ("constraints", m_constraints->to_json ());
+ if (m_current_frame)
+ model_obj->set ("current_frame", m_current_frame->to_json ());
+ model_obj->set ("dynamic_extents", m_dynamic_extents.to_json ());
+ return model_obj;
+}
+
/* Assert that this object is valid. */
void
@@ -175,6 +175,8 @@ public:
void dump_to_pp (pretty_printer *pp, bool simple, bool multiline) const;
void dump (bool simple) const;
+ json::object *to_json () const;
+
bool can_merge_with_p (const region_to_value_map &other,
region_to_value_map *out) const;
@@ -278,6 +280,8 @@ class region_model
void debug () const;
+ json::object *to_json () const;
+
void validate () const;
void canonicalize ();
@@ -235,6 +235,21 @@ bit_range::dump () const
pp_flush (&pp);
}
+/* Generate a JSON value for this bit_range.
+ This is intended for debugging the analyzer rather
+ than serialization. */
+
+json::object *
+bit_range::to_json () const
+{
+ json::object *obj = new json::object ();
+ obj->set ("start_bit_offset",
+ bit_offset_to_json (m_start_bit_offset));
+ obj->set ("size_in_bits",
+ bit_offset_to_json (m_size_in_bits));
+ return obj;
+}
+
/* If OTHER is a subset of this, return true and, if OUT is
non-null, write to *OUT the relative range of OTHER within this.
Otherwise return false. */
@@ -484,6 +499,21 @@ byte_range::dump () const
pp_flush (&pp);
}
+/* Generate a JSON value for this byte_range.
+ This is intended for debugging the analyzer rather
+ than serialization. */
+
+json::object *
+byte_range::to_json () const
+{
+ json::object *obj = new json::object ();
+ obj->set ("start_byte_offset",
+ byte_offset_to_json (m_start_byte_offset));
+ obj->set ("size_in_bytes",
+ byte_offset_to_json (m_size_in_bytes));
+ return obj;
+}
+
/* If OTHER is a subset of this, return true and write
to *OUT the relative range of OTHER within this.
Otherwise return false. */
@@ -237,6 +237,8 @@ struct bit_range
void dump_to_pp (pretty_printer *pp) const;
void dump () const;
+ json::object *to_json () const;
+
bool empty_p () const
{
return m_size_in_bits == 0;
@@ -311,6 +313,8 @@ struct byte_range
void dump_to_pp (pretty_printer *pp) const;
void dump () const;
+ json::object *to_json () const;
+
bool empty_p () const
{
return m_size_in_bytes == 0;