Print this page
new smatch


  30 #include <string.h>
  31 #include <ctype.h>
  32 #include <unistd.h>
  33 #include <fcntl.h>
  34 
  35 #include "lib.h"
  36 #include "allocate.h"
  37 #include "token.h"
  38 #include "parse.h"
  39 #include "symbol.h"
  40 #include "expression.h"
  41 #include "linearize.h"
  42 
  43 static int context_increase(struct basic_block *bb, int entry)
  44 {
  45         int sum = 0;
  46         struct instruction *insn;
  47 
  48         FOR_EACH_PTR(bb->insns, insn) {
  49                 int val;


  50                 if (insn->opcode != OP_CONTEXT)
  51                         continue;
  52                 val = insn->increment;
  53                 if (insn->check) {
  54                         int current = sum + entry;
  55                         if (!val) {
  56                                 if (!current)
  57                                         continue;
  58                         } else if (current >= val)
  59                                 continue;
  60                         warning(insn->pos, "context check failure");
  61                         continue;
  62                 }
  63                 sum += val;
  64         } END_FOR_EACH_PTR(insn);
  65         return sum;
  66 }
  67 
  68 static int imbalance(struct entrypoint *ep, struct basic_block *bb, int entry, int exit, const char *why)
  69 {


 103 
 104         /* Now that's not good.. */
 105         if (bb->context >= 0)
 106                 return imbalance(ep, bb, entry, bb->context, "different lock contexts for basic block");
 107 
 108         bb->context = entry;
 109         entry += context_increase(bb, entry);
 110         if (entry < 0)
 111                 return imbalance(ep, bb, entry, exit, "unexpected unlock");
 112 
 113         return check_children(ep, bb, entry, exit);
 114 }
 115 
 116 static void check_cast_instruction(struct instruction *insn)
 117 {
 118         struct symbol *orig_type = insn->orig_type;
 119         if (orig_type) {
 120                 int old = orig_type->bit_size;
 121                 int new = insn->size;
 122                 int oldsigned = (orig_type->ctype.modifiers & MOD_SIGNED) != 0;
 123                 int newsigned = insn->opcode == OP_SCAST;
 124 
 125                 if (new > old) {
 126                         if (oldsigned == newsigned)
 127                                 return;
 128                         if (newsigned)
 129                                 return;
 130                         warning(insn->pos, "cast loses sign");
 131                         return;
 132                 }
 133                 if (new < old) {
 134                         warning(insn->pos, "cast drops bits");
 135                         return;
 136                 }
 137                 if (oldsigned == newsigned) {
 138                         warning(insn->pos, "cast wasn't removed");
 139                         return;
 140                 }
 141                 warning(insn->pos, "cast changes sign");
 142         }
 143 }


 197                 { &copy_from_user_ident, check_cfu },
 198         };
 199         int i;
 200 
 201         if (fn->type != PSEUDO_SYM)
 202                 return;
 203         ident = fn->sym->ident;
 204         if (!ident)
 205                 return;
 206         for (i = 0; i < ARRAY_SIZE(check_fn); i++) {
 207                 if (check_fn[i].id != ident)
 208                         continue;
 209                 check_fn[i].check(insn);
 210                 break;
 211         }
 212 }
 213 
 214 static void check_one_instruction(struct instruction *insn)
 215 {
 216         switch (insn->opcode) {
 217         case OP_CAST: case OP_SCAST:

 218                 if (verbose)
 219                         check_cast_instruction(insn);
 220                 break;
 221         case OP_RANGE:
 222                 check_range_instruction(insn);
 223                 break;
 224         case OP_CALL:
 225                 check_call_instruction(insn);
 226                 break;
 227         default:
 228                 break;
 229         }
 230 }
 231 
 232 static void check_bb_instructions(struct basic_block *bb)
 233 {
 234         struct instruction *insn;
 235         FOR_EACH_PTR(bb->insns, insn) {
 236                 if (!insn->bb)
 237                         continue;
 238                 check_one_instruction(insn);
 239         } END_FOR_EACH_PTR(insn);
 240 }
 241 
 242 static void check_instructions(struct entrypoint *ep)
 243 {
 244         struct basic_block *bb;
 245         FOR_EACH_PTR(ep->bbs, bb) {

 246                 check_bb_instructions(bb);
 247         } END_FOR_EACH_PTR(bb);
 248 }
 249 
 250 static void check_context(struct entrypoint *ep)
 251 {
 252         struct symbol *sym = ep->name;
 253         struct context *context;
 254         unsigned int in_context = 0, out_context = 0;
 255 
 256         if (Wuninitialized && verbose && ep->entry->bb->needs) {
 257                 pseudo_t pseudo;
 258                 FOR_EACH_PTR(ep->entry->bb->needs, pseudo) {
 259                         if (pseudo->type != PSEUDO_ARG)
 260                                 warning(sym->pos, "%s: possible uninitialized variable (%s)",
 261                                         show_ident(sym->ident), show_pseudo(pseudo));
 262                 } END_FOR_EACH_PTR(pseudo);
 263         }
 264 
 265         check_instructions(ep);
 266 
 267         FOR_EACH_PTR(sym->ctype.contexts, context) {
 268                 in_context += context->in;
 269                 out_context += context->out;
 270         } END_FOR_EACH_PTR(context);
 271         check_bb_context(ep, ep->entry->bb, in_context, out_context);
 272 }
 273 































 274 static void check_symbols(struct symbol_list *list)
 275 {
 276         struct symbol *sym;
 277 
 278         FOR_EACH_PTR(list, sym) {
 279                 struct entrypoint *ep;
 280 
 281                 expand_symbol(sym);
 282                 ep = linearize_symbol(sym);
 283                 if (ep) {
 284                         if (dbg_entry)
 285                                 show_entry(ep);
 286 
 287                         check_context(ep);
 288                 }


 289         } END_FOR_EACH_PTR(sym);
 290 
 291         if (Wsparse_error && die_if_error)
 292                 exit(1);
 293 }
 294 
 295 int main(int argc, char **argv)
 296 {
 297         struct string_list *filelist = NULL;
 298         char *file;
 299 



 300         // Expand, linearize and show it.
 301         check_symbols(sparse_initialize(argc, argv, &filelist));
 302         FOR_EACH_PTR_NOTAG(filelist, file) {
 303                 check_symbols(sparse(file));
 304         } END_FOR_EACH_PTR_NOTAG(file);
 305 
 306         report_stats();
 307         return 0;
 308 }


  30 #include <string.h>
  31 #include <ctype.h>
  32 #include <unistd.h>
  33 #include <fcntl.h>
  34 
  35 #include "lib.h"
  36 #include "allocate.h"
  37 #include "token.h"
  38 #include "parse.h"
  39 #include "symbol.h"
  40 #include "expression.h"
  41 #include "linearize.h"
  42 
  43 static int context_increase(struct basic_block *bb, int entry)
  44 {
  45         int sum = 0;
  46         struct instruction *insn;
  47 
  48         FOR_EACH_PTR(bb->insns, insn) {
  49                 int val;
  50                 if (!insn->bb)
  51                         continue;
  52                 if (insn->opcode != OP_CONTEXT)
  53                         continue;
  54                 val = insn->increment;
  55                 if (insn->check) {
  56                         int current = sum + entry;
  57                         if (!val) {
  58                                 if (!current)
  59                                         continue;
  60                         } else if (current >= val)
  61                                 continue;
  62                         warning(insn->pos, "context check failure");
  63                         continue;
  64                 }
  65                 sum += val;
  66         } END_FOR_EACH_PTR(insn);
  67         return sum;
  68 }
  69 
  70 static int imbalance(struct entrypoint *ep, struct basic_block *bb, int entry, int exit, const char *why)
  71 {


 105 
 106         /* Now that's not good.. */
 107         if (bb->context >= 0)
 108                 return imbalance(ep, bb, entry, bb->context, "different lock contexts for basic block");
 109 
 110         bb->context = entry;
 111         entry += context_increase(bb, entry);
 112         if (entry < 0)
 113                 return imbalance(ep, bb, entry, exit, "unexpected unlock");
 114 
 115         return check_children(ep, bb, entry, exit);
 116 }
 117 
 118 static void check_cast_instruction(struct instruction *insn)
 119 {
 120         struct symbol *orig_type = insn->orig_type;
 121         if (orig_type) {
 122                 int old = orig_type->bit_size;
 123                 int new = insn->size;
 124                 int oldsigned = (orig_type->ctype.modifiers & MOD_SIGNED) != 0;
 125                 int newsigned = insn->opcode == OP_SEXT;
 126 
 127                 if (new > old) {
 128                         if (oldsigned == newsigned)
 129                                 return;
 130                         if (newsigned)
 131                                 return;
 132                         warning(insn->pos, "cast loses sign");
 133                         return;
 134                 }
 135                 if (new < old) {
 136                         warning(insn->pos, "cast drops bits");
 137                         return;
 138                 }
 139                 if (oldsigned == newsigned) {
 140                         warning(insn->pos, "cast wasn't removed");
 141                         return;
 142                 }
 143                 warning(insn->pos, "cast changes sign");
 144         }
 145 }


 199                 { &copy_from_user_ident, check_cfu },
 200         };
 201         int i;
 202 
 203         if (fn->type != PSEUDO_SYM)
 204                 return;
 205         ident = fn->sym->ident;
 206         if (!ident)
 207                 return;
 208         for (i = 0; i < ARRAY_SIZE(check_fn); i++) {
 209                 if (check_fn[i].id != ident)
 210                         continue;
 211                 check_fn[i].check(insn);
 212                 break;
 213         }
 214 }
 215 
 216 static void check_one_instruction(struct instruction *insn)
 217 {
 218         switch (insn->opcode) {
 219         case OP_SEXT: case OP_ZEXT:
 220         case OP_TRUNC:
 221                 if (verbose)
 222                         check_cast_instruction(insn);
 223                 break;
 224         case OP_RANGE:
 225                 check_range_instruction(insn);
 226                 break;
 227         case OP_CALL:
 228                 check_call_instruction(insn);
 229                 break;
 230         default:
 231                 break;
 232         }
 233 }
 234 
 235 static void check_bb_instructions(struct basic_block *bb)
 236 {
 237         struct instruction *insn;
 238         FOR_EACH_PTR(bb->insns, insn) {
 239                 if (!insn->bb)
 240                         continue;
 241                 check_one_instruction(insn);
 242         } END_FOR_EACH_PTR(insn);
 243 }
 244 
 245 static void check_instructions(struct entrypoint *ep)
 246 {
 247         struct basic_block *bb;
 248         FOR_EACH_PTR(ep->bbs, bb) {
 249                 bb->context = -1;
 250                 check_bb_instructions(bb);
 251         } END_FOR_EACH_PTR(bb);
 252 }
 253 
 254 static void check_context(struct entrypoint *ep)
 255 {
 256         struct symbol *sym = ep->name;
 257         struct context *context;
 258         unsigned int in_context = 0, out_context = 0;
 259 
 260         if (Wuninitialized && verbose && ep->entry->bb->needs) {
 261                 pseudo_t pseudo;
 262                 FOR_EACH_PTR(ep->entry->bb->needs, pseudo) {
 263                         if (pseudo->type != PSEUDO_ARG)
 264                                 warning(sym->pos, "%s: possible uninitialized variable (%s)",
 265                                         show_ident(sym->ident), show_pseudo(pseudo));
 266                 } END_FOR_EACH_PTR(pseudo);
 267         }
 268 
 269         check_instructions(ep);
 270 
 271         FOR_EACH_PTR(sym->ctype.contexts, context) {
 272                 in_context += context->in;
 273                 out_context += context->out;
 274         } END_FOR_EACH_PTR(context);
 275         check_bb_context(ep, ep->entry->bb, in_context, out_context);
 276 }
 277 
 278 /* list_compound_symbol - symbol info for arrays, structures, unions */
 279 static void list_compound_symbol(struct symbol *sym)
 280 {
 281         struct symbol *base;
 282 
 283         /* Only show symbols that have a positive size */
 284         if (sym->bit_size <= 0)
 285                 return;
 286         if (!sym->ctype.base_type)
 287                 return;
 288         /* Don't show unnamed types */
 289         if (!sym->ident)
 290                 return;
 291 
 292         if (sym->type == SYM_NODE)
 293                 base = sym->ctype.base_type;
 294         else
 295                 base = sym;
 296         switch (base->type) {
 297         case SYM_STRUCT: case SYM_UNION: case SYM_ARRAY:
 298                 break;
 299         default:
 300                 return;
 301         }
 302 
 303         info(sym->pos, "%s: compound size %u, alignment %lu",
 304                 show_typename(sym),
 305                 bits_to_bytes(sym->bit_size),
 306                 sym->ctype.alignment);
 307 }
 308 
 309 static void check_symbols(struct symbol_list *list)
 310 {
 311         struct symbol *sym;
 312 
 313         FOR_EACH_PTR(list, sym) {
 314                 struct entrypoint *ep;
 315 
 316                 expand_symbol(sym);
 317                 ep = linearize_symbol(sym);
 318                 if (ep && ep->entry) {
 319                         if (dbg_entry)
 320                                 show_entry(ep);
 321 
 322                         check_context(ep);
 323                 }
 324                 if (dbg_compound)
 325                         list_compound_symbol(sym);
 326         } END_FOR_EACH_PTR(sym);
 327 
 328         if (Wsparse_error && die_if_error)
 329                 exit(1);
 330 }
 331 
 332 int main(int argc, char **argv)
 333 {
 334         struct string_list *filelist = NULL;
 335         char *file;
 336 
 337         // by default ignore -o <file>
 338         do_output = 0;
 339 
 340         // Expand, linearize and show it.
 341         check_symbols(sparse_initialize(argc, argv, &filelist));
 342         FOR_EACH_PTR(filelist, file) {
 343                 check_symbols(sparse(file));
 344         } END_FOR_EACH_PTR(file);
 345 
 346         report_stats();
 347         return 0;
 348 }