1########################################################################### 2# Module to test API Sanity Checker 3# 4# Copyright (C) 2009-2010 The Linux Foundation 5# Copyright (C) 2009-2011 Institute for System Programming, RAS 6# Copyright (C) 2011-2013 ROSA Lab 7# 8# Written by Andrey Ponomarenko 9# 10# This program is free software: you can redistribute it and/or modify 11# it under the terms of the GNU General Public License or the GNU Lesser 12# General Public License as published by the Free Software Foundation. 13# 14# This program is distributed in the hope that it will be useful, 15# but WITHOUT ANY WARRANTY; without even the implied warranty of 16# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17# GNU General Public License for more details. 18# 19# You should have received a copy of the GNU General Public License 20# and the GNU Lesser General Public License along with this program. 21# If not, see <http://www.gnu.org/licenses/>. 22########################################################################### 23use strict; 24 25my ($Debug, $LIB_EXT, $OpenReport, $TargetCompiler); 26my $OSgroup = get_OSgroup(); 27 28sub testTool($$$$) 29{ 30 ($Debug, $LIB_EXT, $OpenReport, $TargetCompiler) = @_; 31 32 testC(); 33 testCpp(); 34} 35 36sub testCpp() 37{ 38 printMsg("INFO", "testing C++ library API"); 39 my ($DataDefs, $Sources) = (); 40 my $DeclSpec = ($OSgroup eq "windows")?"__declspec( dllexport )":""; 41 42 # Inline 43 $DataDefs .= " 44 inline int inline_func(int param) { return 0; }"; 45 46 # Simple parameters 47 $DataDefs .= " 48 $DeclSpec int func_simple_parameters( 49 int a, 50 float b, 51 double c, 52 long double d, 53 long long e, 54 char f, 55 unsigned int g, 56 const char* h, 57 char* i, 58 unsigned char* j, 59 char** k, 60 const char*& l, 61 const char**& m, 62 char const*const* n, 63 unsigned int* offset 64 );"; 65 $Sources .= " 66 int func_simple_parameters( 67 int a, 68 float b, 69 double c, 70 long double d, 71 long long e, 72 char f, 73 unsigned int g, 74 const char* h, 75 char* i, 76 unsigned char* j, 77 char** k, 78 const char*& l, 79 const char**& m, 80 char const*const* n, 81 unsigned int* offset ) { 82 return 1; 83 }"; 84 85 # Initialization by interface 86 $DataDefs .= " 87 struct simple_struct { 88 int m; 89 }; 90 $DeclSpec struct simple_struct simple_func(int a, int b);"; 91 $Sources .= " 92 struct simple_struct simple_func(int a, int b) 93 { 94 struct simple_struct x = {1}; 95 return x; 96 }"; 97 98 $DataDefs .= " 99 $DeclSpec int func_init_param_by_interface(struct simple_struct p);"; 100 $Sources .= " 101 int func_init_param_by_interface(struct simple_struct p) { 102 return 1; 103 }"; 104 105 # Private Interface 106 $DataDefs .= " 107 class $DeclSpec private_class { 108 private: 109 private_class(){}; 110 int a; 111 float private_func(float p); 112 };"; 113 $Sources .= " 114 float private_class::private_func(float p) { 115 return p; 116 }"; 117 118 # Assembling structure 119 $DataDefs .= " 120 struct complex_struct { 121 int a; 122 float b; 123 struct complex_struct* c; 124 };"; 125 126 $DataDefs .= " 127 $DeclSpec int func_assemble_param(struct complex_struct p);"; 128 $Sources .= " 129 int func_assemble_param(struct complex_struct p) { 130 return 1; 131 }"; 132 133 # Abstract class 134 $DataDefs .= " 135 class $DeclSpec abstract_class { 136 public: 137 abstract_class(){}; 138 int a; 139 virtual float virt_func(float p) = 0; 140 float func(float p); 141 };"; 142 $Sources .= " 143 float abstract_class::func(float p) { 144 return p; 145 }"; 146 147 # Parameter FuncPtr 148 $DataDefs .= " 149 typedef int (*funcptr_type)(int a, int b); 150 $DeclSpec funcptr_type func_return_funcptr(int a); 151 $DeclSpec int func_param_funcptr(const funcptr_type** p);"; 152 $Sources .= " 153 funcptr_type func_return_funcptr(int a) { 154 return 0; 155 } 156 int func_param_funcptr(const funcptr_type** p) { 157 return 0; 158 }"; 159 160 # Parameter FuncPtr (2) 161 $DataDefs .= " 162 typedef int (*funcptr_type2)(int a, int b, float c); 163 $DeclSpec int func_param_funcptr2(funcptr_type2 p);"; 164 $Sources .= " 165 int func_param_funcptr2(funcptr_type2 p) { 166 return 0; 167 }"; 168 169 # Parameter Array 170 $DataDefs .= " 171 $DeclSpec int func_param_array(struct complex_struct const ** x);"; 172 $Sources .= " 173 int func_param_array(struct complex_struct const ** x) { 174 return 0; 175 }"; 176 177 # Nested classes 178 $DataDefs .= "//Nested classes 179 class $DeclSpec A { 180 public: 181 virtual bool method1() { 182 return false; 183 }; 184 }; 185 186 class $DeclSpec B: public A { }; 187 188 class $DeclSpec C: public B { 189 public: 190 C() { }; 191 virtual bool method1(); 192 virtual bool method2() const; 193 };"; 194 $Sources .= "//Nested classes 195 bool C::method1() { 196 return false; 197 }; 198 199 bool C::method2() const { 200 return false; 201 };"; 202 203 # Throw class 204 $DataDefs .= " 205 class $DeclSpec Exception { 206 public: 207 Exception(); 208 int a; 209 };"; 210 $Sources .= " 211 Exception::Exception() { }"; 212 $DataDefs .= " 213 class $DeclSpec throw_class { 214 public: 215 throw_class() { }; 216 int a; 217 virtual float virt_func(float p) throw(Exception) = 0; 218 float func(float p); 219 };"; 220 $Sources .= " 221 float throw_class::func(float p) { 222 return p; 223 }"; 224 225 # Should crash 226 $DataDefs .= " 227 $DeclSpec int func_should_crash();"; 228 $Sources .= " 229 int func_should_crash() 230 { 231 int *x = 0x0; 232 *x = 1; 233 return 1; 234 }"; 235 236 runTests("libsample_cpp", "C++", "namespace TestNS {\n$DataDefs\n}\n", "namespace TestNS {\n$Sources\n}\n", "type_test_opaque", "_ZN18type_test_internal5func1ES_"); 237} 238 239sub testC() 240{ 241 printMsg("INFO", "\ntesting C library API"); 242 my ($DataDefs, $Sources) = (); 243 my $DeclSpec = ($OSgroup eq "windows")?"__declspec( dllexport )":""; 244 245 # Simple parameters 246 $DataDefs .= " 247 $DeclSpec int func_simple_parameters( 248 int a, 249 float b, 250 double c, 251 long double d, 252 long long e, 253 char f, 254 unsigned int g, 255 const char* h, 256 char* i, 257 unsigned char* j, 258 char** k);"; 259 $Sources .= " 260 int func_simple_parameters( 261 int a, 262 float b, 263 double c, 264 long double d, 265 long long e, 266 char f, 267 unsigned int g, 268 const char* h, 269 char* i, 270 unsigned char* j, 271 char** k) { 272 return 1; 273 }"; 274 275 # Initialization by interface 276 $DataDefs .= " 277 struct simple_struct { 278 int m; 279 }; 280 $DeclSpec struct simple_struct simple_func(int a, int b);"; 281 $Sources .= " 282 struct simple_struct simple_func(int a, int b) 283 { 284 struct simple_struct x = {1}; 285 return x; 286 }"; 287 288 $DataDefs .= " 289 $DeclSpec int func_init_param_by_interface(struct simple_struct p);"; 290 $Sources .= " 291 int func_init_param_by_interface(struct simple_struct p) { 292 return 1; 293 }"; 294 295 # Assembling structure 296 $DataDefs .= " 297 typedef struct complex_struct { 298 int a; 299 float b; 300 struct complex_struct* c; 301 } complex_struct;"; 302 303 $DataDefs .= " 304 $DeclSpec int func_assemble_param(struct complex_struct p);"; 305 $Sources .= " 306 int func_assemble_param(struct complex_struct p) { 307 return 1; 308 }"; 309 310 # Initialization by out parameter 311 $DataDefs .= " 312 struct out_opaque_struct; 313 $DeclSpec void create_out_param(struct out_opaque_struct** out);"; 314 $Sources .= " 315 struct out_opaque_struct { 316 const char* str; 317 }; 318 $DeclSpec void create_out_param(struct out_opaque_struct** out) { }\n"; 319 320 $DataDefs .= " 321 $DeclSpec int func_init_param_by_out_param(struct out_opaque_struct* p);"; 322 $Sources .= " 323 int func_init_param_by_out_param(struct out_opaque_struct* p) { 324 return 1; 325 }"; 326 327 # Should crash 328 $DataDefs .= " 329 $DeclSpec int func_should_crash();"; 330 $Sources .= " 331 int func_should_crash() 332 { 333 int *x = 0x0; 334 *x = 1; 335 return 1; 336 }"; 337 338 # Function with out parameter 339 $DataDefs .= " 340 $DeclSpec int func_has_out_opaque_param(struct out_opaque_struct* out);"; 341 $Sources .= " 342 int func_has_out_opaque_param(struct out_opaque_struct* out) { 343 return 1; 344 }"; 345 346 # C++ keywords 347 $DataDefs .= " 348 $DeclSpec int operator();"; 349 $Sources .= " 350 int operator() { 351 return 1; 352 }"; 353 354 355 runTests("libsample_c", "C", $DataDefs, $Sources, "type_test_opaque", "func_test_internal"); 356} 357 358sub readFirstLine($) 359{ 360 my $Path = $_[0]; 361 return "" if(not $Path or not -f $Path); 362 open (FILE, $Path); 363 my $FirstLine = <FILE>; 364 close(FILE); 365 return $FirstLine; 366} 367 368sub runTests($$$$$$) 369{ 370 my ($LibName, $Lang, $DataDefs, $Sources, $Opaque, $Private) = @_; 371 my $Ext = ($Lang eq "C++")?"cpp":"c"; 372 # creating test suite 373 rmtree($LibName); 374 mkpath($LibName); 375 writeFile("$LibName/version", "TEST_1.0 {\n};\nTEST_2.0 {\n};\n"); 376 writeFile("$LibName/libsample.h", $DataDefs."\n"); 377 writeFile("$LibName/libsample.$Ext", "#include \"libsample.h\"\n".$Sources."\n"); 378 writeFile("$LibName/descriptor.xml", " 379 <version> 380 1.0 381 </version> 382 383 <headers> 384 ".abs_path($LibName)." 385 </headers> 386 387 <libs> 388 ".abs_path($LibName)." 389 </libs> 390 391 <opaque_types> 392 $Opaque 393 </opaque_types> 394 395 <skip_symbols> 396 $Private 397 </skip_symbols>\n"); 398 my @BuildCmds = (); 399 if($OSgroup eq "windows") 400 { 401 if($TargetCompiler eq "CL") 402 { 403 push(@BuildCmds, "cl /LD libsample.$Ext >build_out 2>&1"); 404 } 405 else 406 { 407 if($Lang eq "C++") 408 { 409 push(@BuildCmds, "g++ -shared -fpic libsample.$Ext -o libsample.$LIB_EXT"); 410 push(@BuildCmds, "g++ -c libsample.$Ext -o libsample.obj"); 411 } 412 else 413 { 414 push(@BuildCmds, "gcc -shared -fpic libsample.$Ext -o libsample.$LIB_EXT"); 415 push(@BuildCmds, "gcc -c libsample.$Ext -o libsample.obj"); 416 push(@BuildCmds, "lib libsample.obj >build_out 2>&1"); 417 } 418 } 419 } 420 elsif($OSgroup eq "linux") 421 { 422 writeFile("$LibName/version", "VERSION_1.0 {\n};\nVERSION_2.0 {\n};\n"); 423 my $BCmd = ""; 424 if($Lang eq "C++") { 425 $BCmd = "g++ -Wl,--version-script version -shared -fpic libsample.$Ext -o libsample.$LIB_EXT"; 426 } 427 else { 428 $BCmd = "gcc -Wl,--version-script version -shared -fpic libsample.$Ext -o libsample.$LIB_EXT"; 429 } 430 if(getArch()=~/\A(arm|x86_64)\Z/i) 431 { # relocation R_X86_64_32S against `vtable for class' can not be used when making a shared object; recompile with -fPIC 432 $BCmd .= " -fPIC"; 433 } 434 push(@BuildCmds, $BCmd); 435 } 436 elsif($OSgroup eq "macos") 437 { 438 if($Lang eq "C++") { 439 push(@BuildCmds, "g++ -dynamiclib libsample.$Ext -o libsample.$LIB_EXT"); 440 } 441 else { 442 push(@BuildCmds, "gcc -dynamiclib libsample.$Ext -o libsample.$LIB_EXT"); 443 } 444 } 445 else 446 { 447 if($Lang eq "C++") { 448 push(@BuildCmds, "g++ -shared -fpic libsample.$Ext -o libsample.$LIB_EXT"); 449 } 450 else { 451 push(@BuildCmds, "gcc -shared -fpic libsample.$Ext -o libsample.$LIB_EXT"); 452 } 453 } 454 writeFile("$LibName/Makefile", "all:\n\t".join("\n\t", @BuildCmds)."\n"); 455 foreach (@BuildCmds) 456 { 457 system("cd $LibName && $_"); 458 if($?) { 459 exitStatus("Error", "can't compile \'$LibName/libsample.$Ext\'"); 460 } 461 } 462 # running the tool 463 my $Cmd = "perl $0 -l $LibName -d $LibName/descriptor.xml -gen -build -run -show-retval"; 464 if($OpenReport) { 465 $Cmd .= " -open"; 466 } 467 if($TargetCompiler) { 468 $Cmd .= " -target ".$TargetCompiler; 469 } 470 if($Debug) 471 { 472 $Cmd .= " -debug"; 473 printMsg("INFO", "run $Cmd"); 474 } 475 system($Cmd); 476 477 my $ECode = $?>>8; 478 479 if($ECode!~/\A[0-1]\Z/) 480 { # error 481 exitStatus("Error", "analysis has failed"); 482 } 483 484 my ($Total, $Passed, $Failed) = (0, 0, 0); 485 if(my $FLine = readFirstLine("test_results/$LibName/1.0/test_results.html")) 486 { 487 if($FLine=~/total:(\d+)/) { 488 $Total = $1; 489 } 490 if($FLine=~/passed:(\d+)/) { 491 $Passed = $1; 492 } 493 if($FLine=~/failed:(\d+)/) { 494 $Failed = $1; 495 } 496 } 497 if($Total==($Passed+$Failed) and (($LibName eq "libsample_c" and $Total>5 and $Failed>=1) 498 or ($LibName eq "libsample_cpp" and $Total>10 and $Failed>=1))) { 499 printMsg("INFO", "result: SUCCESS ($Total test cases, $Passed passed, $Failed failed)\n"); 500 } 501 else { 502 printMsg("ERROR", "result: FAILED ($Total test cases, $Passed passed, $Failed failed)\n"); 503 } 504} 505 506return 1;