leak_check.lua (1647B)
1 #! /usr/bin/lua 2 3 local lpeg = require( "lpeg" ) 4 local json = require( "cjson.safe" ) 5 6 -- b_ = begin 7 -- e_ = end 8 -- ne_ = not end 9 -- slc = single line comment 10 -- mlc = multiline comment 11 local b_slc = lpeg.P( "//" ) 12 local e_slc = lpeg.P( "\n" ) 13 local ne_slc = ( 1 - e_slc ) ^ 0 14 local slc = b_slc * ne_slc 15 16 local b_mlc = lpeg.P( "/*" ) 17 local e_mlc = lpeg.P( "*/" ) 18 local ne_mlc = ( 1 - e_mlc ) ^ 0 19 local mlc = b_mlc * ne_mlc * e_mlc 20 21 local quote = lpeg.P( "\"" ) 22 local escaped = lpeg.P( "\\" ) * 1 23 local string = quote * ( escaped + ( 1 - quote ) ) ^ 0 * quote 24 25 local comments = slc + mlc 26 local none = 1 - ( string + comments ) 27 28 local just_code = ( comments + string + lpeg.C( none ^ 1 ) ) ^ 0 29 30 local f = io.open( arg[ 1 ] ) 31 local contents = f:read( "*all" ) 32 local stripped = table.concat( { just_code:match( contents ) } ) 33 34 local function check_leaks( leaks, levels, depth, body ) 35 for code, block in ( body .. "{}" ):gmatch( "(.-)(%b{})" ) do 36 if code == "" and block == "{}" then 37 break 38 end 39 40 for line in code:gmatch( "([^\n]+)" ) do 41 if line:find( "memarena_push" ) then 42 if not levels[ depth ] then 43 table.insert( leaks, line ) 44 end 45 end 46 47 if line:find( "MEMARENA_SCOPED_CHECKPOINT" ) then 48 levels[ depth ] = true 49 end 50 end 51 52 if not cp then 53 levels[ depth + 1 ] = false 54 check_leaks( leaks, levels, depth + 1, block:sub( 2, -2 ) ) 55 levels[ depth + 1 ] = nil 56 end 57 end 58 end 59 60 for ret, name, args, body in stripped:gmatch( "([^\n]-)%s*([^%s]+)(%b())\n? *(%b{})" ) do 61 local leaks = { } 62 check_leaks( leaks, { false }, 1, body ) 63 64 if #leaks > 0 then 65 print( name ) 66 print( table.concat( leaks, "\n" ) ) 67 end 68 end