malloc-init.pl 2.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. #!/usr/bin/perl
  2. # Check for malloc calls not shortly followed by initialisation.
  3. #
  4. # Known limitations:
  5. # - false negative: can't see allocations spanning more than one line
  6. # - possible false negatives, see patterns
  7. # - false positive: malloc-malloc-init-init is not accepted
  8. # - false positives: "non-standard" init functions (eg, the things being
  9. # initialised is not the first arg, or initialise struct members)
  10. #
  11. # Since false positives are expected, the results must be manually reviewed.
  12. #
  13. # Typical usage: scripts/malloc-init.pl library/*.c
  14. use warnings;
  15. use strict;
  16. use utf8;
  17. use open qw(:std utf8);
  18. my $limit = 7;
  19. my $inits = qr/memset|memcpy|_init|fread|base64_..code/;
  20. # cases to bear in mind:
  21. #
  22. # 0. foo = malloc(...); memset( foo, ... );
  23. # 1. *foo = malloc(...); memset( *foo, ... );
  24. # 2. type *foo = malloc(...); memset( foo, ...);
  25. # 3. foo = malloc(...); foo_init( (type *) foo );
  26. # 4. foo = malloc(...); for(i=0..n) { init( &foo[i] ); }
  27. #
  28. # The chosen patterns are a bit relaxed, but unlikely to cause false positives
  29. # in real code (initialising *foo or &foo instead of foo will likely be caught
  30. # by functional tests).
  31. #
  32. my $id = qr/([a-zA-Z-0-9_\->\.]*)/;
  33. my $prefix = qr/\s(?:\*?|\&?|\([a-z_]* \*\))\s*/;
  34. my $name;
  35. my $line;
  36. my @bad;
  37. die "Usage: $0 file.c [...]\n" unless @ARGV;
  38. while (my $file = shift @ARGV)
  39. {
  40. open my $fh, "<", $file or die "read $file failed: $!\n";
  41. while (<$fh>)
  42. {
  43. if( /mbedtls_malloc\(/ ) {
  44. if( /$id\s*=.*mbedtls_malloc\(/ ) {
  45. push @bad, "$file:$line:$name" if $name;
  46. $name = $1;
  47. $line = $.;
  48. } else {
  49. push @bad, "$file:$.:???" unless /return mbedtls_malloc/;
  50. }
  51. } elsif( $name && /(?:$inits)\($prefix\Q$name\E\b/ ) {
  52. undef $name;
  53. } elsif( $name && $. - $line > $limit ) {
  54. push @bad, "$file:$line:$name";
  55. undef $name;
  56. undef $line;
  57. }
  58. }
  59. close $fh or die;
  60. }
  61. print "$_\n" for @bad;