analyzer: handle __attribute__((const)) [PR104434]
When testing -fanalyzer on openblas-0.3, I noticed slightly over 2000 false positives from -Wanalyzer-malloc-leak on code like this: if( LAPACKE_lsame( vect, 'b' ) || LAPACKE_lsame( vect, 'p' ) ) { pt_t = (lapack_complex_float*) LAPACKE_malloc( sizeof(lapack_complex_float) * ldpt_t * MAX(1,n) ); [...snip...] } [...snip lots of code...] if( LAPACKE_lsame( vect, 'b' ) || LAPACKE_lsame( vect, 'q' ) ) { LAPACKE_free( pt_t ); } where LAPACKE_lsame is a char-comparison function implemented in a different TU. The analyzer naively considers the execution path where: LAPACKE_lsame( vect, 'b' ) || LAPACKE_lsame( vect, 'p' ) is true at the malloc guard, but then false at the free guard, which is thus a memory leak. This patch makes -fanalyer respect __attribute__((const)), so that the analyzer treats such functions as returning the same value when given the same inputs. I've filed https://github.com/xianyi/OpenBLAS/issues/3543 suggesting that LAPACKE_lsame be annotated with __attribute__((const)); with that, and with this patch, the false positives seem to be fixed. gcc/analyzer/ChangeLog: PR analyzer/104434 * analyzer.h (class const_fn_result_svalue): New decl. * region-model-impl-calls.cc (call_details::get_manager): New. * region-model-manager.cc (region_model_manager::get_or_create_const_fn_result_svalue): New. (region_model_manager::log_stats): Log m_const_fn_result_values_map. * region-model.cc (const_fn_p): New. (maybe_get_const_fn_result): New. (region_model::on_call_pre): Handle fndecls with __attribute__((const)) by calling the above rather than making a conjured_svalue. * region-model.h (visitor::visit_const_fn_result_svalue): New. (region_model_manager::get_or_create_const_fn_result_svalue): New decl. (region_model_manager::const_fn_result_values_map_t): New typedef. (region_model_manager::m_const_fn_result_values_map): New field. (call_details::get_manager): New decl. * svalue.cc (svalue::cmp_ptr): Handle SK_CONST_FN_RESULT. (const_fn_result_svalue::dump_to_pp): New. (const_fn_result_svalue::dump_input): New. (const_fn_result_svalue::accept): New. * svalue.h (enum svalue_kind): Add SK_CONST_FN_RESULT. (svalue::dyn_cast_const_fn_result_svalue): New. (class const_fn_result_svalue): New. (is_a_helper <const const_fn_result_svalue *>::test): New. (template <> struct default_hash_traits<const_fn_result_svalue::key_t>): New. gcc/testsuite/ChangeLog: PR analyzer/104434 * gcc.dg/analyzer/attr-const-1.c: New test. * gcc.dg/analyzer/attr-const-2.c: New test. * gcc.dg/analyzer/attr-const-3.c: New test. * gcc.dg/analyzer/pr104434-const.c: New test. * gcc.dg/analyzer/pr104434-nonconst.c: New test. * gcc.dg/analyzer/pr104434.h: New test. Signed-off-by: David Malcolm <dmalcolm@redhat.com>
This commit is contained in:
parent
cdcea7c1ef
commit
aee1adf2cd
|
@ -54,6 +54,7 @@ class svalue;
|
|||
class compound_svalue;
|
||||
class conjured_svalue;
|
||||
class asm_output_svalue;
|
||||
class const_fn_result_svalue;
|
||||
typedef hash_set<const svalue *> svalue_set;
|
||||
class region;
|
||||
class frame_region;
|
||||
|
|
|
@ -80,6 +80,14 @@ call_details::call_details (const gcall *call, region_model *model,
|
|||
}
|
||||
}
|
||||
|
||||
/* Get the manager from m_model. */
|
||||
|
||||
region_model_manager *
|
||||
call_details::get_manager () const
|
||||
{
|
||||
return m_model->get_manager ();
|
||||
}
|
||||
|
||||
/* Get any uncertainty_t associated with the region_model_context. */
|
||||
|
||||
uncertainty_t *
|
||||
|
|
|
@ -1232,6 +1232,32 @@ get_or_create_asm_output_svalue (tree type,
|
|||
return asm_output_sval;
|
||||
}
|
||||
|
||||
|
||||
/* Return the svalue * of type TYPE for the result of a call to FNDECL
|
||||
with __attribute__((const)), given INPUTS as inputs. */
|
||||
|
||||
const svalue *
|
||||
region_model_manager::
|
||||
get_or_create_const_fn_result_svalue (tree type,
|
||||
tree fndecl,
|
||||
const vec<const svalue *> &inputs)
|
||||
{
|
||||
gcc_assert (type);
|
||||
gcc_assert (fndecl);
|
||||
gcc_assert (DECL_P (fndecl));
|
||||
gcc_assert (TREE_READONLY (fndecl));
|
||||
gcc_assert (inputs.length () <= const_fn_result_svalue::MAX_INPUTS);
|
||||
|
||||
const_fn_result_svalue::key_t key (type, fndecl, inputs);
|
||||
if (const_fn_result_svalue **slot = m_const_fn_result_values_map.get (key))
|
||||
return *slot;
|
||||
const_fn_result_svalue *const_fn_result_sval
|
||||
= new const_fn_result_svalue (type, fndecl, inputs);
|
||||
RETURN_UNKNOWN_IF_TOO_COMPLEX (const_fn_result_sval);
|
||||
m_const_fn_result_values_map.put (key, const_fn_result_sval);
|
||||
return const_fn_result_sval;
|
||||
}
|
||||
|
||||
/* Given STRING_CST, a STRING_CST and BYTE_OFFSET_CST a constant,
|
||||
attempt to get the character at that offset, returning either
|
||||
the svalue for the character constant, or NULL if unsuccessful. */
|
||||
|
@ -1671,6 +1697,8 @@ region_model_manager::log_stats (logger *logger, bool show_objs) const
|
|||
log_uniq_map (logger, show_objs, "conjured_svalue", m_conjured_values_map);
|
||||
log_uniq_map (logger, show_objs, "asm_output_svalue",
|
||||
m_asm_output_values_map);
|
||||
log_uniq_map (logger, show_objs, "const_fn_result_svalue",
|
||||
m_const_fn_result_values_map);
|
||||
|
||||
logger->log ("max accepted svalue num_nodes: %i",
|
||||
m_max_complexity.m_num_nodes);
|
||||
|
|
|
@ -1207,6 +1207,51 @@ region_model::check_call_args (const call_details &cd) const
|
|||
cd.get_arg_svalue (arg_idx);
|
||||
}
|
||||
|
||||
/* Return true if CD is known to be a call to a function with
|
||||
__attribute__((const)). */
|
||||
|
||||
static bool
|
||||
const_fn_p (const call_details &cd)
|
||||
{
|
||||
tree fndecl = cd.get_fndecl_for_call ();
|
||||
if (!fndecl)
|
||||
return false;
|
||||
gcc_assert (DECL_P (fndecl));
|
||||
return TREE_READONLY (fndecl);
|
||||
}
|
||||
|
||||
/* If this CD is known to be a call to a function with
|
||||
__attribute__((const)), attempt to get a const_fn_result_svalue
|
||||
based on the arguments, or return NULL otherwise. */
|
||||
|
||||
static const svalue *
|
||||
maybe_get_const_fn_result (const call_details &cd)
|
||||
{
|
||||
if (!const_fn_p (cd))
|
||||
return NULL;
|
||||
|
||||
unsigned num_args = cd.num_args ();
|
||||
if (num_args > const_fn_result_svalue::MAX_INPUTS)
|
||||
/* Too many arguments. */
|
||||
return NULL;
|
||||
|
||||
auto_vec<const svalue *> inputs (num_args);
|
||||
for (unsigned arg_idx = 0; arg_idx < num_args; arg_idx++)
|
||||
{
|
||||
const svalue *arg_sval = cd.get_arg_svalue (arg_idx);
|
||||
if (!arg_sval->can_have_associated_state_p ())
|
||||
return NULL;
|
||||
inputs.quick_push (arg_sval);
|
||||
}
|
||||
|
||||
region_model_manager *mgr = cd.get_manager ();
|
||||
const svalue *sval
|
||||
= mgr->get_or_create_const_fn_result_svalue (cd.get_lhs_type (),
|
||||
cd.get_fndecl_for_call (),
|
||||
inputs);
|
||||
return sval;
|
||||
}
|
||||
|
||||
/* Update this model for the CALL stmt, using CTXT to report any
|
||||
diagnostics - the first half.
|
||||
|
||||
|
@ -1245,10 +1290,16 @@ region_model::on_call_pre (const gcall *call, region_model_context *ctxt,
|
|||
if (tree lhs = gimple_call_lhs (call))
|
||||
{
|
||||
const region *lhs_region = get_lvalue (lhs, ctxt);
|
||||
const svalue *sval
|
||||
= m_mgr->get_or_create_conjured_svalue (TREE_TYPE (lhs), call,
|
||||
lhs_region);
|
||||
purge_state_involving (sval, ctxt);
|
||||
const svalue *sval = maybe_get_const_fn_result (cd);
|
||||
if (!sval)
|
||||
{
|
||||
/* For the common case of functions without __attribute__((const)),
|
||||
use a conjured value, and purge any prior state involving that
|
||||
value (in case this is in a loop). */
|
||||
sval = m_mgr->get_or_create_conjured_svalue (TREE_TYPE (lhs), call,
|
||||
lhs_region);
|
||||
purge_state_involving (sval, ctxt);
|
||||
}
|
||||
set_value (lhs_region, sval, ctxt);
|
||||
}
|
||||
|
||||
|
|
|
@ -224,6 +224,7 @@ public:
|
|||
virtual void visit_compound_svalue (const compound_svalue *) {}
|
||||
virtual void visit_conjured_svalue (const conjured_svalue *) {}
|
||||
virtual void visit_asm_output_svalue (const asm_output_svalue *) {}
|
||||
virtual void visit_const_fn_result_svalue (const const_fn_result_svalue *) {}
|
||||
|
||||
virtual void visit_region (const region *) {}
|
||||
};
|
||||
|
@ -282,6 +283,10 @@ public:
|
|||
const gasm *asm_stmt,
|
||||
unsigned output_idx,
|
||||
const vec<const svalue *> &inputs);
|
||||
const svalue *
|
||||
get_or_create_const_fn_result_svalue (tree type,
|
||||
tree fndecl,
|
||||
const vec<const svalue *> &inputs);
|
||||
|
||||
const svalue *maybe_get_char_from_string_cst (tree string_cst,
|
||||
tree byte_offset_cst);
|
||||
|
@ -436,6 +441,10 @@ private:
|
|||
asm_output_svalue *> asm_output_values_map_t;
|
||||
asm_output_values_map_t m_asm_output_values_map;
|
||||
|
||||
typedef hash_map<const_fn_result_svalue::key_t,
|
||||
const_fn_result_svalue *> const_fn_result_values_map_t;
|
||||
const_fn_result_values_map_t m_const_fn_result_values_map;
|
||||
|
||||
bool m_checking_feasibility;
|
||||
|
||||
/* "Dynamically-allocated" svalue instances.
|
||||
|
@ -496,6 +505,7 @@ public:
|
|||
call_details (const gcall *call, region_model *model,
|
||||
region_model_context *ctxt);
|
||||
|
||||
region_model_manager *get_manager () const;
|
||||
region_model_context *get_ctxt () const { return m_ctxt; }
|
||||
uncertainty_t *get_uncertainty () const;
|
||||
tree get_lhs_type () const { return m_lhs_type; }
|
||||
|
|
|
@ -540,6 +540,26 @@ svalue::cmp_ptr (const svalue *sval1, const svalue *sval2)
|
|||
return 0;
|
||||
}
|
||||
break;
|
||||
case SK_CONST_FN_RESULT:
|
||||
{
|
||||
const const_fn_result_svalue *const_fn_result_sval1
|
||||
= (const const_fn_result_svalue *)sval1;
|
||||
const const_fn_result_svalue *const_fn_result_sval2
|
||||
= (const const_fn_result_svalue *)sval2;
|
||||
int d1 = DECL_UID (const_fn_result_sval1->get_fndecl ());
|
||||
int d2 = DECL_UID (const_fn_result_sval2->get_fndecl ());
|
||||
if (int cmp_fndecl = d1 - d2)
|
||||
return cmp_fndecl;
|
||||
if (int cmp = ((int)const_fn_result_sval1->get_num_inputs ()
|
||||
- (int)const_fn_result_sval2->get_num_inputs ()))
|
||||
return cmp;
|
||||
for (unsigned i = 0; i < const_fn_result_sval1->get_num_inputs (); i++)
|
||||
if (int input_cmp
|
||||
= svalue::cmp_ptr (const_fn_result_sval1->get_input (i),
|
||||
const_fn_result_sval2->get_input (i)))
|
||||
return input_cmp;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1892,6 +1912,59 @@ asm_output_svalue::accept (visitor *v) const
|
|||
m_input_arr[i]->accept (v);
|
||||
}
|
||||
|
||||
/* class const_fn_result_svalue : public svalue. */
|
||||
|
||||
/* Implementation of svalue::dump_to_pp vfunc for const_fn_result_svalue. */
|
||||
|
||||
void
|
||||
const_fn_result_svalue::dump_to_pp (pretty_printer *pp, bool simple) const
|
||||
{
|
||||
if (simple)
|
||||
{
|
||||
pp_printf (pp, "CONST_FN_RESULT(%qD, {", m_fndecl);
|
||||
for (unsigned i = 0; i < m_num_inputs; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
pp_string (pp, ", ");
|
||||
dump_input (pp, i, m_input_arr[i], simple);
|
||||
}
|
||||
pp_string (pp, "})");
|
||||
}
|
||||
else
|
||||
{
|
||||
pp_printf (pp, "CONST_FN_RESULT(%qD, {", m_fndecl);
|
||||
for (unsigned i = 0; i < m_num_inputs; i++)
|
||||
{
|
||||
if (i > 0)
|
||||
pp_string (pp, ", ");
|
||||
dump_input (pp, i, m_input_arr[i], simple);
|
||||
}
|
||||
pp_string (pp, "})");
|
||||
}
|
||||
}
|
||||
|
||||
/* Subroutine of const_fn_result_svalue::dump_to_pp. */
|
||||
|
||||
void
|
||||
const_fn_result_svalue::dump_input (pretty_printer *pp,
|
||||
unsigned input_idx,
|
||||
const svalue *sval,
|
||||
bool simple) const
|
||||
{
|
||||
pp_printf (pp, "arg%i: ", input_idx);
|
||||
sval->dump_to_pp (pp, simple);
|
||||
}
|
||||
|
||||
/* Implementation of svalue::accept vfunc for const_fn_result_svalue. */
|
||||
|
||||
void
|
||||
const_fn_result_svalue::accept (visitor *v) const
|
||||
{
|
||||
v->visit_const_fn_result_svalue (this);
|
||||
for (unsigned i = 0; i < m_num_inputs; i++)
|
||||
m_input_arr[i]->accept (v);
|
||||
}
|
||||
|
||||
} // namespace ana
|
||||
|
||||
#endif /* #if ENABLE_ANALYZER */
|
||||
|
|
|
@ -48,7 +48,8 @@ enum svalue_kind
|
|||
SK_WIDENING,
|
||||
SK_COMPOUND,
|
||||
SK_CONJURED,
|
||||
SK_ASM_OUTPUT
|
||||
SK_ASM_OUTPUT,
|
||||
SK_CONST_FN_RESULT
|
||||
};
|
||||
|
||||
/* svalue and its subclasses.
|
||||
|
@ -77,7 +78,9 @@ enum svalue_kind
|
|||
compound_svalue (SK_COMPOUND): a mapping of bit-ranges to svalues
|
||||
conjured_svalue (SK_CONJURED): a value arising from a stmt
|
||||
asm_output_svalue (SK_ASM_OUTPUT): an output from a deterministic
|
||||
asm stmt. */
|
||||
asm stmt.
|
||||
const_fn_result_svalue (SK_CONST_FN_RESULT): the return value from
|
||||
a function with __attribute((const)) for given inputs. */
|
||||
|
||||
/* An abstract base class representing a value held by a region of memory. */
|
||||
|
||||
|
@ -129,6 +132,8 @@ public:
|
|||
dyn_cast_conjured_svalue () const { return NULL; }
|
||||
virtual const asm_output_svalue *
|
||||
dyn_cast_asm_output_svalue () const { return NULL; }
|
||||
virtual const const_fn_result_svalue *
|
||||
dyn_cast_const_fn_result_svalue () const { return NULL; }
|
||||
|
||||
tree maybe_get_constant () const;
|
||||
const region *maybe_get_region () const;
|
||||
|
@ -1535,4 +1540,128 @@ template <> struct default_hash_traits<asm_output_svalue::key_t>
|
|||
{
|
||||
static const bool empty_zero_p = true;
|
||||
};
|
||||
|
||||
namespace ana {
|
||||
|
||||
/* The return value from a function with __attribute((const)) for given
|
||||
inputs, provided that we don't have too many inputs, and all of them
|
||||
are deterministic.
|
||||
|
||||
Comparisons of variables that share the same const_fn_result_svalue are known
|
||||
to be equal, even if we don't know what the value is. */
|
||||
|
||||
class const_fn_result_svalue : public svalue
|
||||
{
|
||||
public:
|
||||
/* Imposing an upper limit and using a (small) array allows key_t
|
||||
to avoid memory management. */
|
||||
static const unsigned MAX_INPUTS = 2;
|
||||
|
||||
/* A support class for uniquifying instances of const_fn_result_svalue. */
|
||||
struct key_t
|
||||
{
|
||||
key_t (tree type,
|
||||
tree fndecl,
|
||||
const vec<const svalue *> &inputs)
|
||||
: m_type (type), m_fndecl (fndecl),
|
||||
m_num_inputs (inputs.length ())
|
||||
{
|
||||
gcc_assert (inputs.length () <= MAX_INPUTS);
|
||||
for (unsigned i = 0; i < m_num_inputs; i++)
|
||||
m_input_arr[i] = inputs[i];
|
||||
}
|
||||
|
||||
hashval_t hash () const
|
||||
{
|
||||
inchash::hash hstate;
|
||||
hstate.add_ptr (m_type);
|
||||
hstate.add_ptr (m_fndecl);
|
||||
for (unsigned i = 0; i < m_num_inputs; i++)
|
||||
hstate.add_ptr (m_input_arr[i]);
|
||||
return hstate.end ();
|
||||
}
|
||||
|
||||
bool operator== (const key_t &other) const
|
||||
{
|
||||
if (!(m_type == other.m_type
|
||||
&& m_fndecl == other.m_fndecl
|
||||
&& m_num_inputs == other.m_num_inputs))
|
||||
return false;
|
||||
for (unsigned i = 0; i < m_num_inputs; i++)
|
||||
if (m_input_arr[i] != other.m_input_arr[i])
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Use m_fndecl to mark empty/deleted. */
|
||||
void mark_deleted () { m_fndecl = reinterpret_cast<tree> (1); }
|
||||
void mark_empty () { m_fndecl = NULL; }
|
||||
bool is_deleted () const
|
||||
{
|
||||
return m_fndecl == reinterpret_cast<tree> (1);
|
||||
}
|
||||
bool is_empty () const { return m_fndecl == NULL; }
|
||||
|
||||
tree m_type;
|
||||
tree m_fndecl;
|
||||
unsigned m_num_inputs;
|
||||
const svalue *m_input_arr[MAX_INPUTS];
|
||||
};
|
||||
|
||||
const_fn_result_svalue (tree type,
|
||||
tree fndecl,
|
||||
const vec<const svalue *> &inputs)
|
||||
: svalue (complexity::from_vec_svalue (inputs), type),
|
||||
m_fndecl (fndecl),
|
||||
m_num_inputs (inputs.length ())
|
||||
{
|
||||
gcc_assert (inputs.length () <= MAX_INPUTS);
|
||||
for (unsigned i = 0; i < m_num_inputs; i++)
|
||||
m_input_arr[i] = inputs[i];
|
||||
}
|
||||
|
||||
enum svalue_kind get_kind () const FINAL OVERRIDE
|
||||
{
|
||||
return SK_CONST_FN_RESULT;
|
||||
}
|
||||
const const_fn_result_svalue *
|
||||
dyn_cast_const_fn_result_svalue () const FINAL OVERRIDE
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE;
|
||||
void accept (visitor *v) const FINAL OVERRIDE;
|
||||
|
||||
tree get_fndecl () const { return m_fndecl; }
|
||||
unsigned get_num_inputs () const { return m_num_inputs; }
|
||||
const svalue *get_input (unsigned idx) const { return m_input_arr[idx]; }
|
||||
|
||||
private:
|
||||
void dump_input (pretty_printer *pp,
|
||||
unsigned input_idx,
|
||||
const svalue *sval,
|
||||
bool simple) const;
|
||||
|
||||
tree m_fndecl;
|
||||
unsigned m_num_inputs;
|
||||
const svalue *m_input_arr[MAX_INPUTS];
|
||||
};
|
||||
|
||||
} // namespace ana
|
||||
|
||||
template <>
|
||||
template <>
|
||||
inline bool
|
||||
is_a_helper <const const_fn_result_svalue *>::test (const svalue *sval)
|
||||
{
|
||||
return sval->get_kind () == SK_CONST_FN_RESULT;
|
||||
}
|
||||
|
||||
template <> struct default_hash_traits<const_fn_result_svalue::key_t>
|
||||
: public member_function_hash_traits<const_fn_result_svalue::key_t>
|
||||
{
|
||||
static const bool empty_zero_p = true;
|
||||
};
|
||||
|
||||
#endif /* GCC_ANALYZER_SVALUE_H */
|
||||
|
|
|
@ -0,0 +1,152 @@
|
|||
/* Verify that we handle functions with __attribute__ ((const)) correctly. */
|
||||
|
||||
#include "analyzer-decls.h"
|
||||
|
||||
extern int nonconst_fn (int);
|
||||
|
||||
extern int const_fn_0 () __attribute__ ((const));
|
||||
extern int const_fn_1 (int) __attribute__ ((const));
|
||||
extern int const_fn_2 (int, int) __attribute__ ((const));
|
||||
extern int const_fn_3 (int, int, int) __attribute__ ((const));
|
||||
extern int const_fn_variadic (int, ...) __attribute__ ((const));
|
||||
|
||||
/* Verify that functions without __attribute__ ((const)) have a different
|
||||
result each time. */
|
||||
|
||||
void test_nonconst_fn (int x, int y)
|
||||
{
|
||||
int x_1 = nonconst_fn (x);
|
||||
int x_2 = nonconst_fn (x);
|
||||
int y_1 = nonconst_fn (y);
|
||||
int y_2 = nonconst_fn (y);
|
||||
__analyzer_eval (x_1 == x_2); /* { dg-warning "UNKNOWN" } */
|
||||
__analyzer_eval (y_1 == y_2); /* { dg-warning "UNKNOWN" } */
|
||||
__analyzer_eval (x_1 == y_1); /* { dg-warning "UNKNOWN" } */
|
||||
}
|
||||
|
||||
/* Verify functions with __attribute__ ((const)) have the same result
|
||||
for the same arguments. */
|
||||
|
||||
/* 0 args. */
|
||||
|
||||
extern int other_const_fn_0 () __attribute__ ((const));
|
||||
|
||||
void test_const_fn_0 (void)
|
||||
{
|
||||
int a = const_fn_0 ();
|
||||
int b = const_fn_0 ();
|
||||
int c = other_const_fn_0 ();
|
||||
int d = other_const_fn_0 ();
|
||||
__analyzer_eval (a == b); /* { dg-warning "TRUE" } */
|
||||
__analyzer_eval (c == d); /* { dg-warning "TRUE" } */
|
||||
__analyzer_eval (a == c); /* { dg-warning "UNKNOWN" } */
|
||||
}
|
||||
|
||||
/* 1 arg. */
|
||||
|
||||
void test_const_fn_1 (int x, int y)
|
||||
{
|
||||
int x_1 = const_fn_1 (x);
|
||||
int x_2 = const_fn_1 (x);
|
||||
int y_1 = const_fn_1 (y);
|
||||
int y_2 = const_fn_1 (y);
|
||||
__analyzer_eval (x_1 == x_2); /* { dg-warning "TRUE" } */
|
||||
__analyzer_eval (y_1 == y_2); /* { dg-warning "TRUE" } */
|
||||
__analyzer_eval (x_1 == y_1); /* { dg-warning "UNKNOWN" } */
|
||||
}
|
||||
|
||||
/* 2 args. */
|
||||
|
||||
void test_const_fn_2 (int x, int y, int p, int q)
|
||||
{
|
||||
int xy_1 = const_fn_2 (x, y);
|
||||
int xy_2 = const_fn_2 (x, y);
|
||||
int pq_1 = const_fn_2 (p, q);
|
||||
int pq_2 = const_fn_2 (p, q);
|
||||
__analyzer_eval (xy_1 == xy_2); /* { dg-warning "TRUE" } */
|
||||
__analyzer_eval (pq_1 == pq_2); /* { dg-warning "TRUE" } */
|
||||
__analyzer_eval (xy_1 == pq_1); /* { dg-warning "UNKNOWN" } */
|
||||
}
|
||||
|
||||
/* We don't handle above 2 args. */
|
||||
|
||||
void test_const_fn_3 (int x, int y, int z, int p, int q, int r)
|
||||
{
|
||||
int xyz_1 = const_fn_3 (x, y, z);
|
||||
int xyz_2 = const_fn_3 (x, y, z);
|
||||
int pqr_1 = const_fn_3 (p, q, r);
|
||||
int pqr_2 = const_fn_3 (p, q, r);
|
||||
__analyzer_eval (xyz_1 == xyz_2); /* { dg-warning "UNKNOWN" } */
|
||||
__analyzer_eval (pqr_1 == pqr_2); /* { dg-warning "UNKNOWN" } */
|
||||
__analyzer_eval (xyz_1 == pqr_1); /* { dg-warning "UNKNOWN" } */
|
||||
}
|
||||
|
||||
/* Variadic fn, with various numbers of extra args. */
|
||||
|
||||
void test_const_fn_variadic (int x, int y, int z, int p, int q, int r)
|
||||
{
|
||||
/* 0 extra args, for 1 arg in total. */
|
||||
int x_1 = const_fn_variadic (x);
|
||||
int x_2 = const_fn_variadic (x);
|
||||
int p_1 = const_fn_variadic (p);
|
||||
int p_2 = const_fn_variadic (p);
|
||||
__analyzer_eval (x_1 == x_2); /* { dg-warning "TRUE" } */
|
||||
__analyzer_eval (p_1 == p_2); /* { dg-warning "TRUE" } */
|
||||
__analyzer_eval (x_1 == p_1); /* { dg-warning "UNKNOWN" } */
|
||||
|
||||
/* 1 extra arg, for 2 args in total. */
|
||||
int xy_1 = const_fn_variadic (x, y);
|
||||
int xy_2 = const_fn_variadic (x, y);
|
||||
int pq_1 = const_fn_variadic (p, q);
|
||||
int pq_2 = const_fn_variadic (p, q);
|
||||
__analyzer_eval (xy_1 == xy_2); /* { dg-warning "TRUE" } */
|
||||
__analyzer_eval (pq_1 == pq_2); /* { dg-warning "TRUE" } */
|
||||
__analyzer_eval (xy_1 == pq_1); /* { dg-warning "UNKNOWN" } */
|
||||
__analyzer_eval (x_1 == xy_1); /* { dg-warning "UNKNOWN" } */
|
||||
__analyzer_eval (p_1 == pq_1); /* { dg-warning "UNKNOWN" } */
|
||||
|
||||
/* Above that, we don't track results. */
|
||||
int xyz_1 = const_fn_variadic (x, y, z);
|
||||
int xyz_2 = const_fn_variadic (x, y, z);
|
||||
int pqr_1 = const_fn_variadic (p, q, r);
|
||||
int pqr_2 = const_fn_variadic (p, q, r);
|
||||
__analyzer_eval (xyz_1 == xyz_2); /* { dg-warning "UNKNOWN" } */
|
||||
__analyzer_eval (pqr_1 == pqr_2); /* { dg-warning "UNKNOWN" } */
|
||||
__analyzer_eval (xyz_1 == x_1); /* { dg-warning "UNKNOWN" } */
|
||||
__analyzer_eval (xyz_1 == xy_1); /* { dg-warning "UNKNOWN" } */
|
||||
__analyzer_eval (xyz_1 == pqr_1); /* { dg-warning "UNKNOWN" } */
|
||||
}
|
||||
|
||||
/* Builtins with __attribute__ ((const)). */
|
||||
|
||||
void test_builtin_isascii (int x, int y)
|
||||
{
|
||||
int x_1 = __builtin_isascii (x);
|
||||
int x_2 = __builtin_isascii (x);
|
||||
int y_1 = __builtin_isascii (y);
|
||||
int y_2 = __builtin_isascii (y);
|
||||
__analyzer_eval (x_1 == x_2); /* { dg-warning "TRUE" } */
|
||||
__analyzer_eval (y_1 == y_2); /* { dg-warning "TRUE" } */
|
||||
__analyzer_eval (x_1 == y_1); /* { dg-warning "UNKNOWN" } */
|
||||
}
|
||||
|
||||
void test_builtin_popcount (unsigned x, unsigned y)
|
||||
{
|
||||
unsigned x_1 = __builtin_popcount (x);
|
||||
unsigned x_2 = __builtin_popcount (x);
|
||||
unsigned y_1 = __builtin_popcount (y);
|
||||
unsigned y_2 = __builtin_popcount (y);
|
||||
__analyzer_eval (x_1 == x_2); /* { dg-warning "TRUE" } */
|
||||
__analyzer_eval (y_1 == y_2); /* { dg-warning "TRUE" } */
|
||||
__analyzer_eval (x_1 == y_1); /* { dg-warning "UNKNOWN" } */
|
||||
}
|
||||
|
||||
void test_loop (void)
|
||||
{
|
||||
for (int i = 0; i < 100; i++)
|
||||
{
|
||||
int iter_val_a = const_fn_1 (i);
|
||||
int iter_val_b = const_fn_1 (i);
|
||||
__analyzer_eval (iter_val_a == iter_val_b); /* { dg-warning "TRUE" } */
|
||||
}
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
extern int const_p (int) __attribute__((const));
|
||||
extern void do_stuff (void);
|
||||
|
||||
void test (int a)
|
||||
{
|
||||
void *p;
|
||||
if (const_p (a))
|
||||
{
|
||||
p = __builtin_malloc (1024);
|
||||
if (!p)
|
||||
return;
|
||||
}
|
||||
do_stuff ();
|
||||
if (const_p (a))
|
||||
__builtin_free (p); /* { dg-bogus "uninit" } */
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/* Verify that we handle unknown values passed to __attribute__ ((const))
|
||||
(by imposing a complexity limit). */
|
||||
|
||||
/* { dg-additional-options "--param analyzer-max-svalue-depth=0" } */
|
||||
|
||||
#include "analyzer-decls.h"
|
||||
|
||||
extern int const_fn_1 (int) __attribute__ ((const));
|
||||
|
||||
void test_const_fn_1 (int x, int y)
|
||||
{
|
||||
int x_1 = const_fn_1 (x);
|
||||
int x_2 = const_fn_1 (x);
|
||||
int y_1 = const_fn_1 (y);
|
||||
int y_2 = const_fn_1 (y);
|
||||
__analyzer_eval (x_1 == x_2); /* { dg-warning "UNKNOWN" } */
|
||||
__analyzer_eval (y_1 == y_2); /* { dg-warning "UNKNOWN" } */
|
||||
__analyzer_eval (x_1 == y_1); /* { dg-warning "UNKNOWN" } */
|
||||
}
|
||||
|
||||
void test_2 (int x)
|
||||
{
|
||||
int once = const_fn_1 (x);
|
||||
int again = const_fn_1 (once);
|
||||
__analyzer_eval (once == again); /* { dg-warning "UNKNOWN" } */
|
||||
}
|
|
@ -0,0 +1,173 @@
|
|||
/* { dg-additional-options "-Wno-analyzer-too-complex" } */
|
||||
|
||||
#include "pr104434.h"
|
||||
|
||||
/* Declare LAPACKE_lsame with __attribute__((const)). */
|
||||
int LAPACKE_lsame( char ca, char cb ) __attribute__((const));
|
||||
|
||||
/* Testcase adapted/reduced from
|
||||
https://github.com/xianyi/OpenBLAS/blob/c5f280a7f0e875d83833d895b2b8b0e341efabf4/lapack-netlib/LAPACKE/src/lapacke_cgbbrd_work.c
|
||||
which has this license text. */
|
||||
|
||||
/*****************************************************************************
|
||||
Copyright (c) 2014, Intel Corp.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of Intel Corporation nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************
|
||||
* Contents: Native middle-level C interface to LAPACK function cgbbrd
|
||||
* Author: Intel Corporation
|
||||
* Generated November 2015
|
||||
*****************************************************************************/
|
||||
|
||||
lapack_int LAPACKE_cgbbrd_work( int matrix_layout, char vect, lapack_int m,
|
||||
lapack_int n, lapack_int ncc, lapack_int kl,
|
||||
lapack_int ku, lapack_complex_float* ab,
|
||||
lapack_int ldab, float* d, float* e,
|
||||
lapack_complex_float* q, lapack_int ldq,
|
||||
lapack_complex_float* pt, lapack_int ldpt,
|
||||
lapack_complex_float* c, lapack_int ldc,
|
||||
lapack_complex_float* work, float* rwork )
|
||||
{
|
||||
lapack_int info = 0;
|
||||
if( matrix_layout == LAPACK_COL_MAJOR ) {
|
||||
/* Call LAPACK function and adjust info */
|
||||
LAPACK_cgbbrd( &vect, &m, &n, &ncc, &kl, &ku, ab, &ldab, d, e, q, &ldq,
|
||||
pt, &ldpt, c, &ldc, work, rwork, &info );
|
||||
if( info < 0 ) {
|
||||
info = info - 1;
|
||||
}
|
||||
} else if( matrix_layout == LAPACK_ROW_MAJOR ) {
|
||||
lapack_int ldab_t = MAX(1,kl+ku+1);
|
||||
lapack_int ldc_t = MAX(1,m);
|
||||
lapack_int ldpt_t = MAX(1,n);
|
||||
lapack_int ldq_t = MAX(1,m);
|
||||
lapack_complex_float* ab_t = NULL;
|
||||
lapack_complex_float* q_t = NULL;
|
||||
lapack_complex_float* pt_t = NULL;
|
||||
lapack_complex_float* c_t = NULL;
|
||||
/* Check leading dimension(s) */
|
||||
if( ldab < n ) {
|
||||
info = -9;
|
||||
LAPACKE_xerbla( "LAPACKE_cgbbrd_work", info );
|
||||
return info;
|
||||
}
|
||||
if( ldc < ncc ) {
|
||||
info = -17;
|
||||
LAPACKE_xerbla( "LAPACKE_cgbbrd_work", info );
|
||||
return info;
|
||||
}
|
||||
if( ldpt < n ) {
|
||||
info = -15;
|
||||
LAPACKE_xerbla( "LAPACKE_cgbbrd_work", info );
|
||||
return info;
|
||||
}
|
||||
if( ldq < m ) {
|
||||
info = -13;
|
||||
LAPACKE_xerbla( "LAPACKE_cgbbrd_work", info );
|
||||
return info;
|
||||
}
|
||||
/* Allocate memory for temporary array(s) */
|
||||
ab_t = (lapack_complex_float*)
|
||||
LAPACKE_malloc( sizeof(lapack_complex_float) * ldab_t * MAX(1,n) );
|
||||
if( ab_t == NULL ) {
|
||||
info = LAPACK_TRANSPOSE_MEMORY_ERROR;
|
||||
goto exit_level_0;
|
||||
}
|
||||
if( LAPACKE_lsame( vect, 'b' ) || LAPACKE_lsame( vect, 'q' ) ) {
|
||||
q_t = (lapack_complex_float*)
|
||||
LAPACKE_malloc( sizeof(lapack_complex_float) *
|
||||
ldq_t * MAX(1,m) );
|
||||
if( q_t == NULL ) {
|
||||
info = LAPACK_TRANSPOSE_MEMORY_ERROR;
|
||||
goto exit_level_1;
|
||||
}
|
||||
}
|
||||
if( LAPACKE_lsame( vect, 'b' ) || LAPACKE_lsame( vect, 'p' ) ) {
|
||||
pt_t = (lapack_complex_float*)
|
||||
LAPACKE_malloc( sizeof(lapack_complex_float) *
|
||||
ldpt_t * MAX(1,n) );
|
||||
if( pt_t == NULL ) {
|
||||
info = LAPACK_TRANSPOSE_MEMORY_ERROR;
|
||||
goto exit_level_2;
|
||||
}
|
||||
}
|
||||
if( ncc != 0 ) {
|
||||
c_t = (lapack_complex_float*)
|
||||
LAPACKE_malloc( sizeof(lapack_complex_float) *
|
||||
ldc_t * MAX(1,ncc) );
|
||||
if( c_t == NULL ) {
|
||||
info = LAPACK_TRANSPOSE_MEMORY_ERROR;
|
||||
goto exit_level_3;
|
||||
}
|
||||
}
|
||||
/* Transpose input matrices */
|
||||
LAPACKE_cgb_trans( matrix_layout, m, n, kl, ku, ab, ldab, ab_t, ldab_t );
|
||||
if( ncc != 0 ) {
|
||||
LAPACKE_cge_trans( matrix_layout, m, ncc, c, ldc, c_t, ldc_t );
|
||||
}
|
||||
/* Call LAPACK function and adjust info */
|
||||
LAPACK_cgbbrd( &vect, &m, &n, &ncc, &kl, &ku, ab_t, &ldab_t, d, e, q_t,
|
||||
&ldq_t, pt_t, &ldpt_t, c_t, &ldc_t, work, rwork, &info );
|
||||
if( info < 0 ) {
|
||||
info = info - 1;
|
||||
}
|
||||
/* Transpose output matrices */
|
||||
LAPACKE_cgb_trans( LAPACK_COL_MAJOR, m, n, kl, ku, ab_t, ldab_t, ab,
|
||||
ldab );
|
||||
if( LAPACKE_lsame( vect, 'b' ) || LAPACKE_lsame( vect, 'q' ) ) {
|
||||
LAPACKE_cge_trans( LAPACK_COL_MAJOR, m, m, q_t, ldq_t, q, ldq );
|
||||
}
|
||||
if( LAPACKE_lsame( vect, 'b' ) || LAPACKE_lsame( vect, 'p' ) ) {
|
||||
LAPACKE_cge_trans( LAPACK_COL_MAJOR, n, n, pt_t, ldpt_t, pt, ldpt );
|
||||
}
|
||||
if( ncc != 0 ) {
|
||||
LAPACKE_cge_trans( LAPACK_COL_MAJOR, m, ncc, c_t, ldc_t, c, ldc );
|
||||
}
|
||||
/* Release memory and exit */
|
||||
if( ncc != 0 ) {
|
||||
LAPACKE_free( c_t );
|
||||
}
|
||||
exit_level_3:
|
||||
if( LAPACKE_lsame( vect, 'b' ) || LAPACKE_lsame( vect, 'p' ) ) {
|
||||
LAPACKE_free( pt_t );
|
||||
}
|
||||
exit_level_2:
|
||||
if( LAPACKE_lsame( vect, 'b' ) || LAPACKE_lsame( vect, 'q' ) ) {
|
||||
LAPACKE_free( q_t );
|
||||
}
|
||||
exit_level_1:
|
||||
LAPACKE_free( ab_t );
|
||||
exit_level_0:
|
||||
if( info == LAPACK_TRANSPOSE_MEMORY_ERROR ) {
|
||||
LAPACKE_xerbla( "LAPACKE_cgbbrd_work", info );
|
||||
}
|
||||
} else {
|
||||
info = -1;
|
||||
LAPACKE_xerbla( "LAPACKE_cgbbrd_work", info );
|
||||
}
|
||||
return info; /* { dg-bogus "leak of 'q_t'" "leak of q_t" } */
|
||||
/* { dg-bogus "leak of 'pt_t'" "leak of pt_t" { target *-*-* } .-1 } */
|
||||
}
|
|
@ -0,0 +1,173 @@
|
|||
/* { dg-additional-options "-Wno-analyzer-too-complex" } */
|
||||
|
||||
#include "pr104434.h"
|
||||
|
||||
/* Declare LAPACKE_lsame *without* __attribute__((const)). */
|
||||
int LAPACKE_lsame( char ca, char cb );
|
||||
|
||||
/* Testcase adapted/reduced from
|
||||
https://github.com/xianyi/OpenBLAS/blob/c5f280a7f0e875d83833d895b2b8b0e341efabf4/lapack-netlib/LAPACKE/src/lapacke_cgbbrd_work.c
|
||||
which has this license text. */
|
||||
|
||||
/*****************************************************************************
|
||||
Copyright (c) 2014, Intel Corp.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of Intel Corporation nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************
|
||||
* Contents: Native middle-level C interface to LAPACK function cgbbrd
|
||||
* Author: Intel Corporation
|
||||
* Generated November 2015
|
||||
*****************************************************************************/
|
||||
|
||||
lapack_int LAPACKE_cgbbrd_work( int matrix_layout, char vect, lapack_int m,
|
||||
lapack_int n, lapack_int ncc, lapack_int kl,
|
||||
lapack_int ku, lapack_complex_float* ab,
|
||||
lapack_int ldab, float* d, float* e,
|
||||
lapack_complex_float* q, lapack_int ldq,
|
||||
lapack_complex_float* pt, lapack_int ldpt,
|
||||
lapack_complex_float* c, lapack_int ldc,
|
||||
lapack_complex_float* work, float* rwork )
|
||||
{
|
||||
lapack_int info = 0;
|
||||
if( matrix_layout == LAPACK_COL_MAJOR ) {
|
||||
/* Call LAPACK function and adjust info */
|
||||
LAPACK_cgbbrd( &vect, &m, &n, &ncc, &kl, &ku, ab, &ldab, d, e, q, &ldq,
|
||||
pt, &ldpt, c, &ldc, work, rwork, &info );
|
||||
if( info < 0 ) {
|
||||
info = info - 1;
|
||||
}
|
||||
} else if( matrix_layout == LAPACK_ROW_MAJOR ) {
|
||||
lapack_int ldab_t = MAX(1,kl+ku+1);
|
||||
lapack_int ldc_t = MAX(1,m);
|
||||
lapack_int ldpt_t = MAX(1,n);
|
||||
lapack_int ldq_t = MAX(1,m);
|
||||
lapack_complex_float* ab_t = NULL;
|
||||
lapack_complex_float* q_t = NULL;
|
||||
lapack_complex_float* pt_t = NULL;
|
||||
lapack_complex_float* c_t = NULL;
|
||||
/* Check leading dimension(s) */
|
||||
if( ldab < n ) {
|
||||
info = -9;
|
||||
LAPACKE_xerbla( "LAPACKE_cgbbrd_work", info );
|
||||
return info;
|
||||
}
|
||||
if( ldc < ncc ) {
|
||||
info = -17;
|
||||
LAPACKE_xerbla( "LAPACKE_cgbbrd_work", info );
|
||||
return info;
|
||||
}
|
||||
if( ldpt < n ) {
|
||||
info = -15;
|
||||
LAPACKE_xerbla( "LAPACKE_cgbbrd_work", info );
|
||||
return info;
|
||||
}
|
||||
if( ldq < m ) {
|
||||
info = -13;
|
||||
LAPACKE_xerbla( "LAPACKE_cgbbrd_work", info );
|
||||
return info;
|
||||
}
|
||||
/* Allocate memory for temporary array(s) */
|
||||
ab_t = (lapack_complex_float*)
|
||||
LAPACKE_malloc( sizeof(lapack_complex_float) * ldab_t * MAX(1,n) );
|
||||
if( ab_t == NULL ) {
|
||||
info = LAPACK_TRANSPOSE_MEMORY_ERROR;
|
||||
goto exit_level_0;
|
||||
}
|
||||
if( LAPACKE_lsame( vect, 'b' ) || LAPACKE_lsame( vect, 'q' ) ) {
|
||||
q_t = (lapack_complex_float*)
|
||||
LAPACKE_malloc( sizeof(lapack_complex_float) *
|
||||
ldq_t * MAX(1,m) );
|
||||
if( q_t == NULL ) {
|
||||
info = LAPACK_TRANSPOSE_MEMORY_ERROR;
|
||||
goto exit_level_1;
|
||||
}
|
||||
}
|
||||
if( LAPACKE_lsame( vect, 'b' ) || LAPACKE_lsame( vect, 'p' ) ) {
|
||||
pt_t = (lapack_complex_float*)
|
||||
LAPACKE_malloc( sizeof(lapack_complex_float) *
|
||||
ldpt_t * MAX(1,n) );
|
||||
if( pt_t == NULL ) {
|
||||
info = LAPACK_TRANSPOSE_MEMORY_ERROR;
|
||||
goto exit_level_2;
|
||||
}
|
||||
}
|
||||
if( ncc != 0 ) {
|
||||
c_t = (lapack_complex_float*)
|
||||
LAPACKE_malloc( sizeof(lapack_complex_float) *
|
||||
ldc_t * MAX(1,ncc) );
|
||||
if( c_t == NULL ) {
|
||||
info = LAPACK_TRANSPOSE_MEMORY_ERROR;
|
||||
goto exit_level_3;
|
||||
}
|
||||
}
|
||||
/* Transpose input matrices */
|
||||
LAPACKE_cgb_trans( matrix_layout, m, n, kl, ku, ab, ldab, ab_t, ldab_t );
|
||||
if( ncc != 0 ) {
|
||||
LAPACKE_cge_trans( matrix_layout, m, ncc, c, ldc, c_t, ldc_t );
|
||||
}
|
||||
/* Call LAPACK function and adjust info */
|
||||
LAPACK_cgbbrd( &vect, &m, &n, &ncc, &kl, &ku, ab_t, &ldab_t, d, e, q_t,
|
||||
&ldq_t, pt_t, &ldpt_t, c_t, &ldc_t, work, rwork, &info );
|
||||
if( info < 0 ) {
|
||||
info = info - 1;
|
||||
}
|
||||
/* Transpose output matrices */
|
||||
LAPACKE_cgb_trans( LAPACK_COL_MAJOR, m, n, kl, ku, ab_t, ldab_t, ab,
|
||||
ldab );
|
||||
if( LAPACKE_lsame( vect, 'b' ) || LAPACKE_lsame( vect, 'q' ) ) {
|
||||
LAPACKE_cge_trans( LAPACK_COL_MAJOR, m, m, q_t, ldq_t, q, ldq );
|
||||
}
|
||||
if( LAPACKE_lsame( vect, 'b' ) || LAPACKE_lsame( vect, 'p' ) ) {
|
||||
LAPACKE_cge_trans( LAPACK_COL_MAJOR, n, n, pt_t, ldpt_t, pt, ldpt );
|
||||
}
|
||||
if( ncc != 0 ) {
|
||||
LAPACKE_cge_trans( LAPACK_COL_MAJOR, m, ncc, c_t, ldc_t, c, ldc );
|
||||
}
|
||||
/* Release memory and exit */
|
||||
if( ncc != 0 ) {
|
||||
LAPACKE_free( c_t );
|
||||
}
|
||||
exit_level_3:
|
||||
if( LAPACKE_lsame( vect, 'b' ) || LAPACKE_lsame( vect, 'p' ) ) {
|
||||
LAPACKE_free( pt_t );
|
||||
}
|
||||
exit_level_2:
|
||||
if( LAPACKE_lsame( vect, 'b' ) || LAPACKE_lsame( vect, 'q' ) ) {
|
||||
LAPACKE_free( q_t );
|
||||
}
|
||||
exit_level_1:
|
||||
LAPACKE_free( ab_t );
|
||||
exit_level_0:
|
||||
if( info == LAPACK_TRANSPOSE_MEMORY_ERROR ) {
|
||||
LAPACKE_xerbla( "LAPACKE_cgbbrd_work", info );
|
||||
}
|
||||
} else {
|
||||
info = -1;
|
||||
LAPACKE_xerbla( "LAPACKE_cgbbrd_work", info );
|
||||
}
|
||||
return info; /* { dg-warning "leak of 'q_t'" "leak of q_t" } */
|
||||
/* { dg-warning "leak of 'pt_t'" "leak of pt_t" { target *-*-* } .-1 } */
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
/* Shared header for testing memory leak false positives seen in OpenBLAS,
|
||||
e.g. in lapacke_cgbbrd_work.c.
|
||||
|
||||
The code is of the form:
|
||||
|
||||
if( LAPACKE_lsame( vect, 'b' ) || LAPACKE_lsame( vect, 'p' ) ) {
|
||||
pt_t = (lapack_complex_float*)
|
||||
LAPACKE_malloc( sizeof(lapack_complex_float) *
|
||||
ldpt_t * MAX(1,n) );
|
||||
...snip...
|
||||
}
|
||||
|
||||
[...snip lots of code...]
|
||||
|
||||
if( LAPACKE_lsame( vect, 'b' ) || LAPACKE_lsame( vect, 'p' ) ) {
|
||||
LAPACKE_free( pt_t );
|
||||
}
|
||||
|
||||
where LAPACKE_lsame is a case-insensitive comparison, implemented in its
|
||||
own source file. Without __attribute__((const)) on LAPACKE_lsame, the
|
||||
analyzer considers the execution paths where the malloc is called, and
|
||||
then the free is not called. With __attribute__((const)), the analyzer
|
||||
ought to rule out such paths. */
|
||||
|
||||
#define NULL ((void *)0)
|
||||
typedef __SIZE_TYPE__ size_t;
|
||||
|
||||
extern void *malloc (size_t __size)
|
||||
__attribute__ ((__nothrow__ , __leaf__))
|
||||
__attribute__ ((__malloc__))
|
||||
__attribute__ ((__alloc_size__ (1)))
|
||||
__attribute__ ((__warn_unused_result__));
|
||||
extern void free (void *__ptr)
|
||||
__attribute__ ((__nothrow__ , __leaf__));
|
||||
|
||||
/* Header adapted/reduced from
|
||||
https://github.com/xianyi/OpenBLAS/
|
||||
which has this license text. */
|
||||
|
||||
/*****************************************************************************
|
||||
Copyright (c) 2014, Intel Corp.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
* Neither the name of Intel Corporation nor the names of its contributors
|
||||
may be used to endorse or promote products derived from this software
|
||||
without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
#define lapack_int int
|
||||
#define lapack_logical lapack_int
|
||||
|
||||
#define LAPACKE_malloc( size ) malloc( size )
|
||||
#define LAPACKE_free( p ) free( p )
|
||||
|
||||
#define LAPACK_ROW_MAJOR 101
|
||||
#define LAPACK_COL_MAJOR 102
|
||||
|
||||
#define LAPACK_TRANSPOSE_MEMORY_ERROR -1011
|
||||
|
||||
#define MAX(x,y) (((x) > (y)) ? (x) : (y))
|
||||
|
||||
#define LAPACK_GLOBAL(lcname,UCNAME) lcname##_
|
||||
|
||||
typedef float _Complex lapack_complex_float;
|
||||
|
||||
void LAPACKE_xerbla( const char *name, int info );
|
||||
|
||||
void LAPACKE_cgb_trans( int matrix_layout, int m, int n,
|
||||
int kl, int ku,
|
||||
const lapack_complex_float *in, int ldin,
|
||||
lapack_complex_float *out, int ldout );
|
||||
void LAPACKE_cge_trans( int matrix_layout, int m, int n,
|
||||
const lapack_complex_float* in, int ldin,
|
||||
lapack_complex_float* out, int ldout );
|
||||
|
||||
#define LAPACK_cgbbrd LAPACK_GLOBAL(cgbbrd,CGBBRD)
|
||||
void LAPACK_cgbbrd(
|
||||
char const* vect,
|
||||
lapack_int const* m, lapack_int const* n, lapack_int const* ncc, lapack_int const* kl, lapack_int const* ku,
|
||||
lapack_complex_float* AB, lapack_int const* ldab,
|
||||
float* D,
|
||||
float* E,
|
||||
lapack_complex_float* Q, lapack_int const* ldq,
|
||||
lapack_complex_float* PT, lapack_int const* ldpt,
|
||||
lapack_complex_float* C, lapack_int const* ldc,
|
||||
lapack_complex_float* work,
|
||||
float* rwork,
|
||||
lapack_int* info );
|
Loading…
Reference in New Issue