C-sparse
view release on metacpan or search on metacpan
src/sparse-0.4.4/sparse.c view on Meta::CPAN
}
sum += val;
} END_FOR_EACH_PTR(insn);
return sum;
}
static int imbalance(SCTX_ struct entrypoint *ep, struct basic_block *bb, int entry, int exit, const char *why)
{
if (sctxp Wcontext) {
struct symbol *sym = ep->name;
warning(sctx_ bb->pos->pos, "context imbalance in '%s' - %s", show_ident(sctx_ sym->ident), why);
}
return -1;
}
static int check_bb_context(SCTX_ struct entrypoint *ep, struct basic_block *bb, int entry, int exit);
static int check_children(SCTX_ struct entrypoint *ep, struct basic_block *bb, int entry, int exit)
{
struct instruction *insn;
struct basic_block *child;
insn = last_instruction(sctx_ bb->insns);
if (!insn)
return 0;
if (insn->opcode == OP_RET)
return entry != exit ? imbalance(sctx_ ep, bb, entry, exit, "wrong count at exit") : 0;
FOR_EACH_PTR(bb->children, child) {
if (check_bb_context(sctx_ ep, child, entry, exit))
return -1;
} END_FOR_EACH_PTR(child);
return 0;
}
static int check_bb_context(SCTX_ struct entrypoint *ep, struct basic_block *bb, int entry, int exit)
{
if (!bb)
return 0;
if (bb->context == entry)
return 0;
/* Now that's not good.. */
if (bb->context >= 0)
return imbalance(sctx_ ep, bb, entry, bb->context, "different lock contexts for basic block");
bb->context = entry;
entry += context_increase(sctx_ bb, entry);
if (entry < 0)
return imbalance(sctx_ ep, bb, entry, exit, "unexpected unlock");
return check_children(sctx_ ep, bb, entry, exit);
}
static void check_cast_instruction(SCTX_ struct instruction *insn)
{
struct symbol *orig_type = insn->orig_type;
if (orig_type) {
int old = orig_type->bit_size;
int new = insn->size;
int oldsigned = (orig_type->ctype.modifiers & MOD_SIGNED) != 0;
int newsigned = insn->opcode == OP_SCAST;
if (new > old) {
if (oldsigned == newsigned)
return;
if (newsigned)
return;
warning(sctx_ insn->pos, "cast loses sign");
return;
}
if (new < old) {
warning(sctx_ insn->pos, "cast drops bits");
return;
}
if (oldsigned == newsigned) {
warning(sctx_ insn->pos, "cast wasn't removed");
return;
}
warning(sctx_ insn->pos, "cast changes sign");
}
}
static void check_range_instruction(SCTX_ struct instruction *insn)
{
warning(sctx_ insn->pos, "value out of range");
}
static void check_byte_count(SCTX_ struct instruction *insn, pseudo_t count)
{
if (!count)
return;
if (count->type == PSEUDO_VAL) {
long long val = count->value;
if (val <= 0 || val > 100000)
warning(sctx_ insn->pos, "%s with byte count of %lld",
show_ident(sctx_ insn->func->sym->ident), val);
return;
}
/* OK, we could try to do the range analysis here */
}
static pseudo_t argument(SCTX_ struct instruction *call, unsigned int argno)
{
pseudo_t args[8];
struct ptr_list *arg_list = (struct ptr_list *) call->arguments;
argno--;
if (linearize_ptr_list(sctx_ arg_list, (void *)args, 8) > argno)
return args[argno];
return NULL;
}
static void check_memset(SCTX_ struct instruction *insn)
{
check_byte_count(sctx_ insn, argument(sctx_ insn, 3));
}
#define check_memcpy check_memset
#define check_ctu check_memset
#define check_cfu check_memset
struct checkfn {
struct ident *id;
void (*check)(SCTX_ struct instruction *insn);
};
static void check_call_instruction(SCTX_ struct instruction *insn)
{
pseudo_t fn = insn->func;
struct ident *ident;
/*static*/ const struct checkfn check_fn[] = {
{ (struct ident *)&sctxp memset_ident, check_memset },
{ (struct ident *)&sctxp memcpy_ident, check_memcpy },
{ (struct ident *)&sctxp copy_to_user_ident, check_ctu },
{ (struct ident *)&sctxp copy_from_user_ident, check_cfu },
( run in 0.440 second using v1.01-cache-2.11-cpan-71847e10f99 )