#!/usr/bin/perl # # Usage: file_handles.pl < $file.sm # # Checks for comparision of file handles with 0 instead of # INVALID_HANDLE_VALUE. # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. # # Copyright 2006-2007 Michael Stefaniuc use strict; use smatch; # Variables ############ # Names of variables that hold a file handle. my %handles = (); # Regexp with functions that return file handles my $funcs = "(?:CreateFile|CreateMailslot|CreateNamedPipe|FindFirstFile(?:Ex)?|OpenConsole|SetupOpenInfFile|socket)[AW]?"; # Functions ############ sub error_msg ($) { my $handle = shift; $handle =~ s/^var_decl\((.*)\)$/$1/; my $msg = "Comparision of file handle '$handle' with 0"; print get_filename(), " ", get_lineno(), " ", get_func_pos(), " $msg\n"; } # This function searches for the first unbalanced ')' in a string and # returns the string up to the ')' (not included). sub get_str_close_bracket($) { my $str = shift; my $count = 1; # We are searching for the first unbalanced ')' while ($str =~ m/[^()]*(\(|\))/g) { if ($1 eq ')') { $count--; if ($count == 0) { last; } } else { $count++; } } return substr($str, 0, pos($str) - 1); } # Main ####### my $data; while($data = get_data()){ # begin of a function $data =~ /^function_decl / and do { %handles = (); next; }; # handle = CreateFile() $data =~ /(modify_expr\(((?:var_decl|component_ref)\(.+?\))= call_expr\(\(addr_expr function_decl\(($funcs)\)\)\(tree_list: .*)/ and do { my $match = $1; my $handle = $2; my $func = $3; $handles{$handle} = $func; if ($data =~ /if_cond/) { # We have an "if" check in the same line with the call to # the function returning a file handle. Replace the call # with the variable name so we can handle it below. my $replace = quotemeta(get_str_close_bracket($match)); $data =~ s/$replace/$handle/; } }; # if (handle) if ($data =~ s/^if_cond //) { my @vars = (); if ($data !~ /_expr/) { # the smatch gcc generates for "if (bla) blubb;" a # "if_expr bla" smatch code line and not ne_expr with 0 push(@vars, $data); } else { # ubercool regexp to make the simple ".*?" not swallow an # eq_expr or ne_expr while ($data =~ /(?:eq|ne)_expr\(\(((?:.(?!(?:eq|ne)_expr))*?)\)\(integer_cst\(0\)\)\)/g) { # Save all variables that were compared to 0 push(@vars, $1); } } foreach my $h (@vars) { if (exists($handles{$h})) { error_msg($h); } } } }