C
    Ruby 1.9 trunk
          @ikegami_ _
@ikegami_ _

•   2003

•   2003-2010

    •              Haskell

    •   C

        •   10/27 - 11/10    2

•   Ruby/Mathematica, Ruby/Ming, RushCheck, Karatsuba
1/2
•                       C++

    •   BLAST

    •   Frama-C

        •
            •
            •
            •     CIL         GCC
2/2
•
                     ←
•
    • cppcheck         C C++

     • Emacs + Flymake
     • Vim +
       • Vim + QuickFix + errormaker
Emacs + Flymake + cppcheck




                    →
•
    • cppcheck
    • splint
•
    • BLAST
    • Frama-C
•               -Wall

•
    •
        •
            •
•
•   division by zero   •   assert

•             unroll
                       •
                           assertion
•   if


•
•
•   Call flow graph

•
cppcheck
•      written in C++

• C/C++
  •
  • Tokenize
  • Run all checks - pattern matching of the tokens
           http://sourceforge.net/apps/trac/cppcheck/
cppcheck                 ruby

•   ruby-1.9 trunk revision 33685 (2011-11-09   )

    •   compile.c      77 files   2:01:02.55

        •   error        6

    •   compile.c   54:46.94s

•
cppcheck                       Ruby
                   6

[hash.c:2351]: (error) Memory leak: str
[io.c:5264]: (error) fflush() called on input stream "stdin" may
result in undefined behaviour
[regcomp.c:5524]: (error) Memory leak: new_reg
[vm_dump.c:831]: (error) Possible null pointer dereference: vm -
otherwise it is redundant to check if vm is null at line 778
[vm_dump.c:834]: (error) Possible null pointer dereference: vm -
otherwise it is redundant to check if vm is null at line 778
[vm_dump.c:835]: (error) Possible null pointer dereference: vm -
otherwise it is redundant to check if vm is null at line 778
hash.c
           [hash.c:2351]: (error) Memory leak: str

2351 } /*              ruby_setenv         */
2303             str = malloc(len += strlen(value) + 2);

                 str     free

                  2287 #elif defined __sun

       Solaris
io.c
   [io.c:5264]: (error) fflush() called on input stream
   "stdin" may result in undefined behaviour

5264        fflush(stdin);          /* is it really needed? */

Q. How can I flush pending input so that a user's
typeahead isn't read at the next prompt? Will
fflush(stdin) work?
A. fflush is defined only for output streams. (omit)
               comp.lang.c FAQ list · Question 12.26a
splint
•                        written in C

•
•                              annotation

•   cppcheck

•
    •   cont.c gc.c random.c thread_pthread.h

                                   http://www.splint.org/
splint hash.c
•   ruby-1.9 trunk revision 33685 (2011-11-09   )

•   397

•   header

    •   Solaris        Solaris       configure



        •   cppcheck             hash.c
            x86
splint regcomp.c

•   ruby-1.9 trunk revision 33685 (2011-11-09   )

•   737

    •
        •
splint regcomp.c
regcomp.c:180:10: Only storage uslist->us->target
(type struct _Node *) derived from released storage is not
released (memory      leak): uslist->us
(omit)

 176     static void
 177     unset_addr_list_end(UnsetAddrList* uslist)
 178     {
 179       if (IS_NOT_NULL(uslist->us))
 180         xfree(uslist->us);
 181     }
176   static void
177   unset_addr_list_end(UnsetAddrList* uslist)
178   {
179     if (IS_NOT_NULL(uslist->us))
180       xfree(uslist->us);
                             typedef struct {
181   }                        int       offset;
                               struct _Node* target;
                             } UnsetAddr;
  uslist->us->target
                             typedef struct {
  free                         int     num;
                               int     alloc;
                               UnsetAddr* us;
                             } UnsetAddrList;
183   static int
184   unset_addr_list_add(UnsetAddrList* uslist, int offset, struct _Node* node)
185   {
186     UnsetAddr* p;
187     int size;
188
189       if (uslist->num >= uslist->alloc) {
190         size = uslist->alloc * 2;
191         p = (UnsetAddr* )xrealloc(uslist->us, sizeof(UnsetAddr) * size);
192         CHECK_NULL_RETURN_MEMERR(p);
193         uslist->alloc = size;
194         uslist->us = p;
195       }
196
197       uslist->us[uslist->num].offset = offset;
198       uslist->us[uslist->num].target = node;
199       uslist->num++;
200       return 0;                ↑ free
201   }
false positive
BLAST
 • with CIL                 OCaml

 •
   •            assert()

   •
   • assert
http://mtc.epfl.ch/software-tools/blast/index-epfl.php
escape
#include <assert.h>
int watched; /* a global variable */
void foo(int i) { watched = i; }     ←
void bar()
{
  int j;

  foo(j);
  assert(j == watched);
  /* assert(j != watched); */
}
   % gcc -E -I ${BLAST_INCLUDE} -main bar target.c
   % pblast.opt target.i -main bar
                                  :-)
#include <assert.h>
int *watched;

void foo(int *p) { watched = p; }

void bar()
{
  int i, *j;
  i = 1;
  j = &i;
  foo(j);
  assert(j == watched);
  /* assert(j != watched); */
}
   % gcc -E -I ${BLAST_INCLUDE} -main bar target.c
   % pblast.opt target.i -main bar
                                  :-)
ruby 1.9 trunk

• for   while

• if
  •
•
  •
  •
Frama-C
• with CIL               OCaml

•C
 •
 •
   • value plug-in   ←
   • users plug-in
                          http://frama-c.com/
division by zero
void foo(int x, int y)
{
  int z = x / y; /* y should not be zero */
  return;
}

int main(int argc, char **argv)
{
  int x = 1, y = 0;
  foo(x, y);
  return 0;
}
Frama-C value plug-in

% frama-c -val foo.c
[value] Analyzing a complete application starting at main

foo.c:3:[kernel] warning: division by zero: assert y ≢ 0;
division by zero
 • ruby trunk revision no. 33685
  • bignum.c
    • 1044 ds[k] = (BDIGIT)(num / hbase);
  • util.c
    •
      • 331 n = (r - l + size) / size;
Frama-C value plugin
Frama-C users plug-in


•       callee

    •
void foo(void) {}
void bar(void) {foo();}

int main(void)
{
  bar();
  return 0;
}
          % frama-c -users foo.c
          [kernel] preprocessing with "gcc -C -E -I. foo.c"

         [users] ====== DISPLAYING USERS ======
              bar: foo
              main: foo bar
              ====== END OF USERS ==========
ruby            string.c
callee
http://sovmoess.tumblr.com/
post/12364993205/frama-c-ruby-1-9-string-c-callee
                  @ikegami_ _
•
    •   false positive

    •
    •                                 CPU

•          annotation

    •                    annotation

    •   Frama-C + jessie plug-in → Coq
•2          C

  • ruby-1.9 trunk revision 33685
•      cppcheck/splint

  • escape
• BLAST/Frama-C
  •

C言語静的解析ツールと Ruby 1.9 trunk

  • 1.
    C Ruby 1.9 trunk @ikegami_ _
  • 2.
    @ikegami_ _ • 2003 • 2003-2010 • Haskell • C • 10/27 - 11/10 2 • Ruby/Mathematica, Ruby/Ming, RushCheck, Karatsuba
  • 4.
    1/2 • C++ • BLAST • Frama-C • • • • CIL GCC
  • 5.
    2/2 • ← • • cppcheck C C++ • Emacs + Flymake • Vim + • Vim + QuickFix + errormaker
  • 6.
    Emacs + Flymake+ cppcheck →
  • 7.
    • cppcheck • splint • • BLAST • Frama-C
  • 8.
    -Wall • • • • •
  • 9.
    division by zero • assert • unroll • assertion • if • • • Call flow graph •
  • 10.
    cppcheck • written in C++ • C/C++ • • Tokenize • Run all checks - pattern matching of the tokens http://sourceforge.net/apps/trac/cppcheck/
  • 11.
    cppcheck ruby • ruby-1.9 trunk revision 33685 (2011-11-09 ) • compile.c 77 files 2:01:02.55 • error 6 • compile.c 54:46.94s •
  • 12.
    cppcheck Ruby 6 [hash.c:2351]: (error) Memory leak: str [io.c:5264]: (error) fflush() called on input stream "stdin" may result in undefined behaviour [regcomp.c:5524]: (error) Memory leak: new_reg [vm_dump.c:831]: (error) Possible null pointer dereference: vm - otherwise it is redundant to check if vm is null at line 778 [vm_dump.c:834]: (error) Possible null pointer dereference: vm - otherwise it is redundant to check if vm is null at line 778 [vm_dump.c:835]: (error) Possible null pointer dereference: vm - otherwise it is redundant to check if vm is null at line 778
  • 13.
    hash.c [hash.c:2351]: (error) Memory leak: str 2351 } /* ruby_setenv */ 2303 str = malloc(len += strlen(value) + 2); str free 2287 #elif defined __sun Solaris
  • 14.
    io.c [io.c:5264]: (error) fflush() called on input stream "stdin" may result in undefined behaviour 5264 fflush(stdin); /* is it really needed? */ Q. How can I flush pending input so that a user's typeahead isn't read at the next prompt? Will fflush(stdin) work? A. fflush is defined only for output streams. (omit) comp.lang.c FAQ list · Question 12.26a
  • 15.
    splint • written in C • • annotation • cppcheck • • cont.c gc.c random.c thread_pthread.h http://www.splint.org/
  • 16.
    splint hash.c • ruby-1.9 trunk revision 33685 (2011-11-09 ) • 397 • header • Solaris Solaris configure • cppcheck hash.c x86
  • 17.
    splint regcomp.c • ruby-1.9 trunk revision 33685 (2011-11-09 ) • 737 • •
  • 18.
    splint regcomp.c regcomp.c:180:10: Onlystorage uslist->us->target (type struct _Node *) derived from released storage is not released (memory leak): uslist->us (omit) 176 static void 177 unset_addr_list_end(UnsetAddrList* uslist) 178 { 179 if (IS_NOT_NULL(uslist->us)) 180 xfree(uslist->us); 181 }
  • 19.
    176 static void 177 unset_addr_list_end(UnsetAddrList* uslist) 178 { 179 if (IS_NOT_NULL(uslist->us)) 180 xfree(uslist->us); typedef struct { 181 } int offset; struct _Node* target; } UnsetAddr; uslist->us->target typedef struct { free int num; int alloc; UnsetAddr* us; } UnsetAddrList;
  • 20.
    183 static int 184 unset_addr_list_add(UnsetAddrList* uslist, int offset, struct _Node* node) 185 { 186 UnsetAddr* p; 187 int size; 188 189 if (uslist->num >= uslist->alloc) { 190 size = uslist->alloc * 2; 191 p = (UnsetAddr* )xrealloc(uslist->us, sizeof(UnsetAddr) * size); 192 CHECK_NULL_RETURN_MEMERR(p); 193 uslist->alloc = size; 194 uslist->us = p; 195 } 196 197 uslist->us[uslist->num].offset = offset; 198 uslist->us[uslist->num].target = node; 199 uslist->num++; 200 return 0; ↑ free 201 }
  • 21.
  • 22.
    BLAST • withCIL OCaml • • assert() • • assert http://mtc.epfl.ch/software-tools/blast/index-epfl.php
  • 23.
  • 24.
    #include <assert.h> int watched;/* a global variable */ void foo(int i) { watched = i; } ← void bar() {   int j;   foo(j);   assert(j == watched);   /* assert(j != watched); */ } % gcc -E -I ${BLAST_INCLUDE} -main bar target.c % pblast.opt target.i -main bar :-)
  • 25.
    #include <assert.h> int *watched; voidfoo(int *p) { watched = p; } void bar() {   int i, *j;   i = 1;   j = &i;   foo(j);   assert(j == watched);   /* assert(j != watched); */ } % gcc -E -I ${BLAST_INCLUDE} -main bar target.c % pblast.opt target.i -main bar :-)
  • 26.
    ruby 1.9 trunk •for while • if • • • •
  • 27.
    Frama-C • with CIL OCaml •C • • • value plug-in ← • users plug-in http://frama-c.com/
  • 28.
    division by zero voidfoo(int x, int y) { int z = x / y; /* y should not be zero */ return; } int main(int argc, char **argv) { int x = 1, y = 0; foo(x, y); return 0; }
  • 29.
    Frama-C value plug-in %frama-c -val foo.c [value] Analyzing a complete application starting at main foo.c:3:[kernel] warning: division by zero: assert y ≢ 0;
  • 30.
    division by zero • ruby trunk revision no. 33685 • bignum.c • 1044 ds[k] = (BDIGIT)(num / hbase); • util.c • • 331 n = (r - l + size) / size; Frama-C value plugin
  • 31.
  • 32.
    void foo(void) {} voidbar(void) {foo();} int main(void) { bar(); return 0; } % frama-c -users foo.c [kernel] preprocessing with "gcc -C -E -I. foo.c" [users] ====== DISPLAYING USERS ====== bar: foo main: foo bar ====== END OF USERS ==========
  • 33.
    ruby string.c callee http://sovmoess.tumblr.com/ post/12364993205/frama-c-ruby-1-9-string-c-callee @ikegami_ _
  • 34.
    • false positive • • CPU • annotation • annotation • Frama-C + jessie plug-in → Coq
  • 35.
    •2 C • ruby-1.9 trunk revision 33685 • cppcheck/splint • escape • BLAST/Frama-C •