1#!/usr/bin/perl -W 2#!/usr/bin/perl -W 3# 4# 5# Copyright (c) 2004, 2005 Voltaire, Inc. All rights reserved. 6# Copyright (c) 2002-2005 Mellanox Technologies LTD. All rights reserved. 7# Copyright (c) 1996-2003 Intel Corporation. All rights reserved. 8# 9# This software is available to you under a choice of one of two 10# licenses. You may choose to be licensed under the terms of the GNU 11# General Public License (GPL) Version 2, available from the file 12# COPYING in the main directory of this source tree, or the 13# OpenIB.org BSD license below: 14# 15# Redistribution and use in source and binary forms, with or 16# without modification, are permitted provided that the following 17# conditions are met: 18# 19# - Redistributions of source code must retain the above 20# copyright notice, this list of conditions and the following 21# disclaimer. 22# 23# - Redistributions in binary form must reproduce the above 24# copyright notice, this list of conditions and the following 25# disclaimer in the documentation and/or other materials 26# provided with the distribution. 27# 28# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 29# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 30# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 31# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 32# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 33# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 34# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 35# SOFTWARE. 36# 37# 38# 39# Abstract: 40# Perl script for simple source code error checking. 41# 42# Environment: 43# Linux User Mode 44# 45# $Revision: 1.4 $ 46# 47# 48# 49# DESCRIPTION: 50# 51# This script performs some simple conformance checks on the 52# OpenSM source code. It does NOT attempt to act like a full 53# blown 'C' language parser, so it can be fooled. Something 54# is better than nothing. Running the 'osm_indent' script before 55# running this script will increase your chances of catching 56# problems. 57# 58# 59# The following checks are performed: 60# 1) Verify that the function name provided in a log statement 61# matches the name of the current function. 62# 63# 2) Verify that log statements are in the form that this script 64# can readily parse. Improvements to the regular expressions 65# might make this unnecessary. 66# 67# 3) Verify that lower two digits of the error codes used in log 68# statements are unique within that file. 69# 70# 4) Verify that upper two digits of the error codes used in log 71# statements are not used by any other module. 72# 73# USAGE: 74# 75# In the OpenSM source directory, type: 76# osm_check.pl *.c 77# 78 79# Do necessary upfront initialization 80$verbose = 0; 81$in_c_comment = 0; 82 83if( !exists $ARGV[0] ) 84{ 85 print "ERROR: You must specify the files on which to operate, such as '*.c'\n"; 86 osm_check_usage(); 87 exit; 88} 89 90# loop through all the command line options 91do 92{ 93 $doing_params = 0; 94 95 # First, look for command line options. 96 if( $ARGV[0] =~ /-[v|V]/ ) 97 { 98 $verbose += 1; 99 shift; 100 print "Verbose mode on, level = $verbose.\n"; 101 $doing_params = 1; 102 } 103 104 if( !exists $ARGV[0] ) 105 { 106 print "ERROR: You must specify the files on which to operate, such as '*.c'\n"; 107 osm_check_usage(); 108 exit; 109 } 110}while( $doing_params == 1 ); 111 112LINE: while( <> ) 113{ 114 # Skip C single line C style comments 115 # This line must come before the multi-line C comment check! 116 if( /\/\*.*\*\// ) 117 { 118 $in_c_comment = 0; 119 next LINE; 120 } 121 122 # skip multi-line C style comments 123 if( /\/\*/ ) 124 { 125 $in_c_comment = 1; 126 next LINE; 127 } 128 129 # end skipping of multi-line C style comments 130 if( /\*\// ) 131 { 132 $in_c_comment = 0; 133 next LINE; 134 } 135 136 # We're still in a C comment, so ignore input 137 if( $in_c_comment == 1 ) 138 { 139 next LINE; 140 } 141 142 143 # skip C++ style comment lines 144 if( /^\s*\/\// ) 145 { 146 next LINE; 147 } 148 149 # check for bad PRIx64 usage 150 # It's a common mistake to forget the % before the PRIx64 151 if( /[^%]\"\s*PRIx64/ ) 152 { 153 print "No % sign before PRx64!!: $ARGV $.\n"; 154 } 155 156 # This simple script doesn't handle checking PRIx64 usage 157 # when PRIx64 starts the line. Just give a warning. 158 if( /^\s*PRIx64/ ) 159 { 160 print "Warning: PRIx64 at start of line. $ARGV $.\n"; 161 } 162 163 # Attempt to locate function names. 164 # Function names must start on the beginning of the line. 165 if( /^(\w+)\s*\(/ ) 166 { 167 $current_func = $1; 168 if( $verbose == 1 ) 169 { 170 print "Processing $ARGV: $current_func\n"; 171 } 172 } 173 174 # Attempt to find OSM_LOG_ENTER entries. 175 # When found, verify that the function name provided matches 176 # the actual function. 177 if( /OSM_LOG_ENTER\s*\(\s*([\-\.\>\w]+)\s*,\s*(\w+)\s*\)/ ) 178 { 179 $log_func = $2; 180 if( $current_func ne $log_func ) 181 { 182 printf "MISMATCH!! $ARGV $.: $current_func != $log_func\n"; 183 } 184 } 185 186 # Check for non-conforming log statements. 187 # Log statements must not start the log string on the same line 188 # as the osm_log function itself. 189 # Watch out for the #include "osm_log.h" statement as a false positive. 190 if( /osm_log\s*\(.*\"/ ) 191 { 192 print "NON-CONFORMING LOG STATEMENT!! $ARGV $.\n"; 193 } 194 195 # Attempt to find osm_log entries. 196 if( /^\s*\"(\w+):/ ) 197 { 198 $log_func = $1; 199 if( $current_func ne $log_func ) 200 { 201 print "MISMATCHED LOG FUNCTION!! $ARGV $.: $current_func != $log_func\n"; 202 } 203 } 204 205 # Error logging must look like 'ERR 1234:' 206 # The upper two digits are error range assigned to that module. 207 # The lower two digits are the error code itself. 208 # Error codes are in hexadecimal. 209 if( /ERR(\s+)([0-9a-fA-F]{2})([0-9a-fA-F]{2})(..)/ ) 210 { 211 # Check if we already established the error prefix for this module 212 $err_prefix = $module_err_prefixes{$ARGV}; 213 if( $err_prefix ) 214 { 215 if( $err_prefix ne $2 ) 216 { 217 print "BAD ERR RANGE IN LOG ENTRY!! $ARGV $.: $current_func\n"; 218 print "\tExpected $err_prefix but found $2\n"; 219 } 220 } 221 else 222 { 223 # Create a new prefix for this module. 224 $module_err_prefixes{$ARGV} = $2; 225 } 226 227 $err_base = $module_err_bases{$3}; 228 if( $err_base ) 229 { 230 print "DUPLICATE ERR NUMBER IN LOG ENTRY!! $ARGV $.: $current_func: $3\n"; 231 print "\tPrevious use on line $err_base.\n"; 232 } 233 else 234 { 235 # Add this error code to the list used by this module 236 # The data stored in the line number on which it is used. 237 $module_err_bases{$3} = $.; 238 if( $verbose > 1 ) 239 { 240 print "Adding new error: $1$2 in $ARGV.\n"; 241 } 242 } 243 244 if( $4 ne ": " ) 245 { 246 print "MALFORMED LOG STATEMENT!! NEEDS ': ' $ARGV $.\n"; 247 } 248 249 if( $1 ne " " ) 250 { 251 print "USE ONLY 1 SPACE AFTER ERR!! $ARGV $.\n"; 252 } 253 } 254 255 # verify expected use of sizeof() with pointers 256 if( /sizeof\s*\(\s*[h|p]_/ ) 257 { 258 print "SUSPICIOUS USE OF SIZEOF(), DO YOU NEED AN '*' $ARGV $.\n"; 259 } 260 261 262} 263continue 264{ 265 # reset the module base error index when we finished out 266 # each source file. 267 if( eof ) 268 { 269 # reset the base error value, since each module can 270 # repeat this range. 271 %module_err_bases = (); 272 # closing the file here resets the line number with each new file 273 close ARGV; 274 } 275} 276 277sub osm_check_usage 278{ 279 print "Usage:\n"; 280 print "osm_check.pl [-v|V] <file list>\n"; 281 print "[-v|V] - enable verbose mode.\n\n"; 282} 283