svalue_set result_set; /* Used as a mapping of svalue*->bool. */
};
+/* Return true if SIZE_CST is a power of 2, and we have
+ CAPACITY_SVAL == ((X | (Y - 1) ) + 1), since it is then a multiple
+ of SIZE_CST, as used by Linux kernel's round_up macro. */
+
+static bool
+is_round_up (tree size_cst,
+ const svalue *capacity_sval)
+{
+ if (!integer_pow2p (size_cst))
+ return false;
+ const binop_svalue *binop_sval = capacity_sval->dyn_cast_binop_svalue ();
+ if (!binop_sval)
+ return false;
+ if (binop_sval->get_op () != PLUS_EXPR)
+ return false;
+ tree rhs_cst = binop_sval->get_arg1 ()->maybe_get_constant ();
+ if (!rhs_cst)
+ return false;
+ if (!integer_onep (rhs_cst))
+ return false;
+
+ /* We have CAPACITY_SVAL == (LHS + 1) for some LHS expression. */
+
+ const binop_svalue *lhs_binop_sval
+ = binop_sval->get_arg0 ()->dyn_cast_binop_svalue ();
+ if (!lhs_binop_sval)
+ return false;
+ if (lhs_binop_sval->get_op () != BIT_IOR_EXPR)
+ return false;
+
+ tree inner_rhs_cst = lhs_binop_sval->get_arg1 ()->maybe_get_constant ();
+ if (!inner_rhs_cst)
+ return false;
+
+ if (wi::to_widest (inner_rhs_cst) + 1 != wi::to_widest (size_cst))
+ return false;
+ return true;
+}
+
+/* Return true if CAPACITY_SVAL is known to be a multiple of SIZE_CST. */
+
+static bool
+is_multiple_p (tree size_cst,
+ const svalue *capacity_sval)
+{
+ if (const svalue *sval = capacity_sval->maybe_undo_cast ())
+ return is_multiple_p (size_cst, sval);
+
+ if (is_round_up (size_cst, capacity_sval))
+ return true;
+
+ return false;
+}
+
+/* Return true if we should emit a dubious_allocation_size warning
+ on assigning a region of capacity CAPACITY_SVAL bytes to a pointer
+ of type with size SIZE_CST, where CM expresses known constraints. */
+
+static bool
+is_dubious_capacity (tree size_cst,
+ const svalue *capacity_sval,
+ constraint_manager *cm)
+{
+ if (is_multiple_p (size_cst, capacity_sval))
+ return false;
+ size_visitor v (size_cst, capacity_sval, cm);
+ return v.is_dubious_capacity ();
+}
+
+
/* Return true if a struct or union either uses the inheritance pattern,
where the first field is a base struct, or the flexible array member
pattern, where the last field is an array without a specified size. */
{
if (!is_struct)
{
- size_visitor v (pointee_size_tree, capacity, m_constraints);
- if (v.is_dubious_capacity ())
+ if (is_dubious_capacity (pointee_size_tree,
+ capacity,
+ m_constraints))
{
tree expr = get_representative_tree (capacity);
ctxt->warn (make_unique <dubious_allocation_size> (lhs_reg,
--- /dev/null
+/* Adapted from include/linux/math.h */
+#define __round_mask(x, y) ((__typeof__(x))((y)-1))
+#define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1)
+
+/* Reduced from Linux kernel's drivers/gpu/drm/i915/display/intel_bios.c */
+typedef unsigned short u16;
+typedef unsigned int u32;
+typedef unsigned long __kernel_size_t;
+typedef __kernel_size_t size_t;
+
+extern __attribute__((__alloc_size__(1))) __attribute__((__malloc__))
+void* kzalloc(size_t size);
+
+typedef struct
+{
+ u32 reg;
+} i915_reg_t;
+struct intel_uncore;
+struct intel_uncore_funcs
+{
+ u32 (*mmio_readl)(struct intel_uncore* uncore, i915_reg_t r);
+};
+struct intel_uncore
+{
+ void* regs;
+ struct intel_uncore_funcs funcs;
+};
+static inline __attribute__((__gnu_inline__)) __attribute__((__unused__))
+__attribute__((no_instrument_function)) u32
+intel_uncore_read(struct intel_uncore* uncore, i915_reg_t reg)
+{
+ return uncore->funcs.mmio_readl(uncore, reg);
+}
+struct drm_i915_private
+{
+ struct intel_uncore uncore;
+};
+struct vbt_header*
+spi_oprom_get_vbt(struct drm_i915_private* i915)
+{
+ u16 vbt_size;
+ u32* vbt;
+ vbt_size =
+ intel_uncore_read(&i915->uncore, ((const i915_reg_t){ .reg = (0x102040) }));
+ vbt_size &= 0xffff;
+ vbt = (u32*)kzalloc(round_up (vbt_size, 4)); /* { dg-bogus "allocated buffer size is not a multiple of the pointee's size" "PR analyzer/113654" } */
+ if (!vbt)
+ goto err_not_found;
+ return (struct vbt_header*)vbt;
+err_not_found:
+ return ((struct vbt_header*)0);
+}