cil-project / cil

C Intermediate Language
Other
348 stars 86 forks source link

Prototypes that preempt built-in functions are wrongly discarded #15

Open stephenrkell opened 10 years ago

stephenrkell commented 10 years ago

Using cilly to compile eglibc 2.19 fails at configure time, complaining:

configure:6792: error: support for the symbol redirection needed

The failing test program (conftest.c) looks like this:

extern char *strstr (const char *, const char *) __asm ("my_strstr");
char *foo (const char *a, const char *b)
{
  return __builtin_strstr (a, b);
}

The configure script expects to see a reference to my_strstr in the output assembly. This holds for gcc, but not for cilly wrapping gcc.

After fixing a trivial earlier bug (that __builtin_strstr was not included in the builtins list; patch sent!), we get

/* Generated by CIL v. 1.7.3 */
/* print_CIL_Input is true */

/* compiler builtin: 
   char *__builtin_strstr(char const   * , char const   * ) ;  */
#line 2 "conftest.c"
char *foo(char const   *a , char const   *b ) 
{ 
  char *tmp ;

  {
#line 4
  tmp = __builtin_strstr(a, b);
#line 4
  return (tmp);
}
}

where we note that our prototype for strstr has gone away! That's because it appears to be unused. My proposed fix is a gross hack to rmtmps, something like as follows, but I'd be amenable to cleaner suggestions.

diff --git a/src/rmtmps.ml b/src/rmtmps.ml
index 2034623..09b5bde 100644
--- a/src/rmtmps.ml
+++ b/src/rmtmps.ml
@@ -422,6 +422,21 @@ class markReachableVisitor
     | GVarDecl (varinfo, _)
     | GFun ({svar = varinfo}, _) ->
        varinfo.vreferenced <- true;
+       (* If we're a builtin, but we've seen a prototype for the
+        * corresponding non-builtin function, then mark that one
+        * used too. *)
+       let isBuiltin = H.mem builtinFunctions varinfo.vname in
+       if isBuiltin then begin
+         let nonBuiltinName = Str.replace_first (Str.regexp "^__builtin_") "" varinfo.
+         try 
+           let gv = H.find globalMap nonBuiltinName in
+            match gv with 
+             GFun({svar = nbvarinfo}, _) -> nbvarinfo.vreferenced <- true; ()
+           | GVarDecl(nbvarinfo, _) -> nbvarinfo.vreferenced <- true; ()
+           | _ -> ()
+         with Not_found -> ()
+       end
+       ;
        DoChildren
     | _ ->
        SkipChildren