GithubHelp home page GithubHelp logo

cil-project / cil Goto Github PK

View Code? Open in Web Editor NEW
341.0 24.0 83.0 31 MB

C Intermediate Language

License: Other

Shell 0.77% Perl 3.23% OCaml 54.86% Makefile 0.79% C 39.74% Standard ML 0.38% Batchfile 0.01% M4 0.23% C++ 0.01%

cil's Introduction

C Intermediate Language (CIL)

Linux Linux build Status Windows Windows build status

CIL is a front-end for the C programming language that facilitates program analysis and transformation. CIL will parse and typecheck a program, and compile it into a simplified subset of C.

CIL supports ANSI C as well as most of the extensions of the GNU C and Microsoft C compilers. A Perl script acts as a drop in replacement for either gcc or Microsoft's cl, and allows merging of the source files in your project. Other features include support for control-flow and points-to analyses.

Quick start

Install the latest release of CIL with opam:

opam install cil

Read the excellent CIL tutorial by Zachary Anderson, and check out the accompanying project template.

Installation

To build and install CIL, you need the OCaml compiler, perl, and ocamlfind. (Of course, you also need some C compiler, preferably gcc.)

Run the following commands to build and install CIL:

./configure
make
make test       # regression test suite, optionnal
make install    # as root or using sudo

If you want to install to some other directory, you can tweak the prefix during the configure step. For instance, to install in your local opam directory:

./configure --prefix=`opam config var prefix`

Usage

You can use cilly (installed in /usr/local/bin by default) as a drop-in replacement for gcc to compile and link your programs.

You can also use CIL as a library to write your own programs. For instance in the OCaml toplevel using findlib:

$ ocaml
        Objective Caml version 4.00.1

# #use "topfind";;
[...]
# #require "cil";;
[...]
# Cil.cilVersion;;           
- : string = "1.7.3"

More documentation

The documentation is located in the doc/html/cil directory. The API documentation (generated by ocamldoc) is in the api subdirectory.

To (re)build the doc, you need Hevea and run:

make doc

You can also browse the documentation online.

Ressources

CIL is maintained by Gabriel Kerneis [email protected]

cil's People

Contributors

ctshepherd avatar egrimley-arm avatar haihaoshen avatar jim-grundy avatar kerneis avatar liblit avatar pmundkur avatar schwahn avatar scolin avatar stephenrkell avatar tbrk avatar yakobowski avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cil's Issues

--prefix option to configure doesn't seem to work

When trying to install CIL's develop branch using ./configure --prefix=/path, make install fails because it is trying to install into /usr. ./configure --help suggests to use --prefix to install to a different location. It seems there's some ocamlfind magic in the Makefile.in that breaks this

cilly over-quotes compiler argument strings

To deal with a build system that wants to run the compiler with "-DSHA1_HEADER=<path/to/blah>" I had to apply the following patch to cilly.

diff --git a/lib/Cilly.pm.in b/lib/Cilly.pm.in
index 3ec40a8..8d1943b 100644
--- a/lib/Cilly.pm.in
+++ b/lib/Cilly.pm.in
@@ -1219,9 +1219,6 @@ sub compilerArgument {
               &{$action->{'RUN'}}($self, @fullarg, $onemore, $pargs);
               $argument_done = 1;
           }
-          # Quote special SHELL caracters 
-          @fullarg = map { $_ =~ s%([<>;&|])%'$1'%g; $_ } @fullarg;
-          # print "fullarg = ", @fullarg, "\n";
           if(defined $action->{'TYPE'}) {
               &classifyArgDebug("  type=$action->{TYPE}\n");
               if($action->{TYPE} eq 'EARLY_PREPROC') {

Without this, the compiler was getting a string in its argv that contained literal quotes. To me, it doesn't look like the quoting is necessary at all, but I might be missing something.

Respect $MAKE environment variable in myocamlbuild.ml

Please consider the following patch for inclusion:

Index: myocamlbuild.ml
--- myocamlbuild.ml.orig
+++ myocamlbuild.ml
@@ -21,22 +21,25 @@ let cil_version =
   with Not_found -> "" ;;
 
 dispatch begin function
+| Before_options ->
+    Options.use_ocamlfind := true
 | After_rules ->
     (* the main CIL library *)
     ocaml_lib "src/cil";
 
     (* residual reliance on make to build some OCaml source files *)
     let make target =
+      let make = try Sys.getenv "MAKE" with Not_found -> "make" in
       let basename = Pathname.basename target in
       rule ("make " ^ target)
       ~dep: "Makefile"
       ~prod: basename
       (fun _ _ -> Cmd (S
-        [A "make"; A "-C"; P ".."; P ("_build" / target)]))
-      in
-      make "cilversion.ml";
-      make "feature_config.ml";
-      make "machdep.ml";
+        [A make; A "-C"; P ".."; P ("_build" / target)]))
+    in
+    make "cilversion.ml";
+    make "feature_config.ml";
+    make "machdep.ml";
 
     (* Build an list of files to install with ocamlfind *)
     rule "%.mllib -> %.libfiles"

Error linking while using callgraph as a lib

I want to simply print out a callgraph while using cil.callgraph as followed:

open Cil
module E = Errormsg
module L = List
module CG = Callgraph
let test f:file = 
  let cg= CG.computeGraph f in
  CG.printGraph stdout cg
(*merge the input file e.t.c.*)

however as I was using

 ocamlfind ocamlc -linkpkg -thread -package cil,cil.callgraph test.ml -o test.byte

the compiler complains

File "test.ml", line 1:
Error: Error while linking /home/lcm/.opam/system/lib/cil/cil.cma(Feature):
Reference to undefined global `Findlib'

I do not know where to start debugging with
Does anyone have any idea?

Parsing pragmas in CIL

I'm trying to pass down some information from a C source file prior to the file being preprocessed. I decide to use the #pragma syntax to achieve this

(Unfortunately), there are some constructs which result in a ParseError. For example:

#pragma __test__("blah")
void my_fn_defn(void *ptr)
#pragma __test__("foo")
{
...
}

Why does this fail, isn't the pragma still at the "toplevel"? I.e The scope of the function hasn't started yet.

Prototypes that preempt built-in functions are wrongly discarded

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

New version for opam

The latest version available in opam is 1.5.1.
It would be nice to have a more recent version in opam.
I forked opam-repository and tried to add versions 1.6.0 and 1.7.0 based on 1.5.1.
For 1.6.0 the library seems to work, but executing cilly fails with Can't locate CilConfig.pm.
For 1.7.0 I'm stuck at make install which tries to install something to /usr/local/bin.
Can it be configured to install to the opam directory? Also, I don't know what to do with the dependency on perl-ExtUtils-MakeMaker.

cil.a is missing after installing via OPAM

I have installed cil-1.7.2 via opam-1.0.0 and have the following error when I tried to compile a package with CIL.


gcc: error: /ocamlbrew/ocaml-4.00.1/.opam/system/lib/cil/cil.a: No such file or directory
File "caml_startup", line 1:
Error: Error during linking

Command exited with code 2.

Support for gcc's __builtin_bswap32

gcc 4.3 added a new intrinsic, __builtin_bswap32. Currently CIL doesn't know about this builtin, so will emit a (wrongly-typed) prototype for it, causing undefined references in the output object file. The following patch fixes the problem for me.

diff --git a/src/cil.ml b/src/cil.ml
index 1c737e8..343216f 100644
--- a/src/cil.ml
+++ b/src/cil.ml
@@ -2835,6 +2835,7 @@ let initGccBuiltins () : unit =
   (* See if we have builtin_va_list *)
   let hasbva = !M.theMachine.M.__builtin_va_list in
   let ulongLongType = TInt(IULongLong, []) in
+  let uIntType = TInt(IUInt, []) in
   let floatType = TFloat(FFloat, []) in
   let longDoubleType = TFloat (FLongDouble, []) in
   let voidConstPtrType = TPtr(TVoid [Attr ("const", [])], []) in
@@ -2878,6 +2879,8 @@ let initGccBuiltins () : unit =
   H.add h "__builtin_atan2l" (longDoubleType, [ longDoubleType; 
                                                 longDoubleType ], false);

+  H.add h "__builtin_bswap32" (uIntType, [ uIntType ], false);
+
   H.add h "__builtin_ceil" (doubleType, [ doubleType ], false);
   H.add h "__builtin_ceilf" (floatType, [ floatType ], false);
   H.add h "__builtin_ceill" (longDoubleType, [ longDoubleType ], false);

GCC Builtin Support

We are currently studying the usage of GCC builtins by GitHub projects and how well various tools support them. To that end, we are also developing a test suite for the most frequently used machine-independent GCC builtins (available at https://github.com/gcc-builtins/tests). We'd be glad to contribute the test suite (or parts of it) to cil, if you are interested.

Out of the currently 100 builtin tests, cilly passes 40. The builtins __builtin_bswap16 and __builtin_types_compatible_p seem to be supported, but produce incorrect results, as the test cases below demonstrate:

#include <assert.h>
#include <stdint.h>

int main() {
  volatile uint16_t value = -1;
  assert(__builtin_bswap16(value) == (uint16_t)-1);
  return 0;
}
#include <assert.h>

int main() {
  assert(!__builtin_types_compatible_p(enum {foo, bar}, enum {hot, dog}));
}

The second test case is derived from an example given by the GCC docs, which state:

An enum type is not considered to be compatible with another enum type even if both are compatible with the same integer type; this is what the C standard specifies. For example, enum {foo, bar} is not similar to enum {hot, dog}.

From the other failing test cases, 4 are due to warnings about long double values being treated as doubles, for example, in 68-__builtin_fabs.c:

treating long double constant 1.79769313486231570814527423731704357e+308L as double constant at test-cases/68-__builtin_fabs.c:11.

15 failures are caused by parsing errors of a header file, for example, included in 2-__builtin_islessequal.c:

/usr/include/x86_64-linux-gnu/bits/mathcalls-helper-functions.h[21:12-28] : syntax error
Parsing errorFatal error: exception Frontc.ParseError("Parse error")

Execution of 34 test cases failed by having received signal 11, for example, in 89-__atomic_compare_exchange.c. These failures seem to affect only atomic builtins.

The remaining 5 failures are due to unrecognized builtins, for example, in 57-__builtin_add_overflow.c:

cil-z7uEm65O.cil.c:(.text+0x3b): undefined reference to `__builtin_add_overflow'

opam package for OCaml 4.02?

It would be nice to have an opam package for OCaml >= 4.02, since the current one leads to segmentation faults (and cilly doesn't terminate).
Also, for the develop-branch, I had to add package(cil.all-features) to my _tags file, which isn't available using the opam package. Could we make that compatible somehow?

Does copyFunction handle CFG-computed successors and predecessors lists?

The docs for copyFunction do not specify what is the behavior of this function when computeCFGInfo has been called on the given fundec. I have preemptively looked into copyFunction's definition and it seems that this case is not handled, vstmt does not touch succs nor preds. This could break the stated invariant that

There should be no sharing between the copy and the original function

The fix should be relatively easy, we need to patch the succs and preds fields of each statement in a similar way as it is done for goto and switch. Something like

stmtmap |> IH.iter (fun _ s ->
    s.succs <- List.map (fun s1 -> findStmt !s1.sid) s.succs;
    s.preds <- List.map (fun s1 -> findStmt !s1.sid) s.preds
    )

Should I?

Warning: I have not yet tried to copy a fundec after computing CFG info. I report this issue based on my sole understanding of the code.

Thanks!

Names of anonymous struct or union types change program semantics

CIL gives names to anonymous structure or union types, such as in the following.

typedef struct { double r; double i; } complex;

CIL will give it a name such as __anonstruct_complex_nn, where 'nn' is a number chosen serially. So, the same header defining the same struct complex will generate different 'nn' in different compilation units, because of the different inclusion contexts.

This is harmless in nearly all applications of CIL. But in my case it causes a problem, because according to the C standard, types with different tags are not compatible (section 6.2.7), whereas before the CIL transformation, they were compatible. It's important for my tool that compatibility across compilation units is preserved; I therefore have to erase the 'nn' to work around this behaviour.

A better option for CIL would be to compute the nn based on a structural analysis of the definition, so that the same nn would always be generated for the "same" struct. This would not be easy to get completely right, but a "good enough" version probably isn't too hard. Consider that an offer to contribute a patch at some point!

How to print GCC function attributes?

I'm trying to print gcc function attributes i.e section.
Running this code on function declarations with attribute((section)) fails to produce any output. Any idea?

open Cil 
open Pervasives
let print_attr func =
        match func with
        | GFun(f, _) ->  (
                (*Printf.printf "%s\n" f.svar.vname;*)
                match f.svar.vtype with
                        | TFun(rt,_,_,attr) ->
                                ignore(d_attrlist () (typeAttrs rt)); ()
                        | _ -> ()
        )
        | _ -> ()


let () =
        let cil_file = Frontc.parse "srcfile" () in
        iterGlobals cil_file print_attr;

Syntactic search does not find variable occurence

Syntactic search returns no results (not when querying through GobView, but also not when querying through Goblint directly).

Steps to reproduce the issue:

Run the Goblint-http server:

./_build/default/gobview/goblint-http-server/goblint_http.exe -with-goblint ../analyzer/goblint -goblint --set save_run run -v --set files[+] "../analyzer/tests/regression/00-sanity/01-assert.c"

Open the web UI. Scroll down until you see "Switch to JSON editor" and click it. Enter the following query and click "Execute":

{"kind":["var"],"target":["name","fail"],"find":["uses"],"expression":"","mode":["Must"]}

If you allow for non-semantic queries in the expression evaluator (expressionEvaluation.ml) in Goblint1 the query can also directly be handed to Goblint. Save the same query in a file (e.g., query.json) and execute the syntactic search in the terminal like this:
./goblint --set trans.activated[+] expeval -v --set trans.expeval.query_file_name query.json tests/regression/00-sanity/01-assert.c

This also does not return any result.

Footnotes

  1. This can for example be quickly hacked by changing
    https://github.com/goblint/analyzer/blob/5464235e9cc77156746da5f25d336f9d9dac0d1e/src/transform/expressionEvaluation.ml#L195
    to
    |> (fun ls -> if query.expression != "" then List.map (fun (n, l, s, i) -> ((n, l, s, i), evaluator#evaluate l query.expression)) ls else List.map (fun a -> (a, None)) ls)

cilly does not handle input on stdin correctly

cilly assumes that source files have names with meaningful extensions. In the case of the source file "-", denoting stdin, this doesn't work.

$ gcc hello.c -S -o hello.s # works okay
$ file hello.s; rm -f hello.s
hello.s: assembler source text

$ cilly hello.c -S -o hello.s # works okay
$ file hello.s; rm -f hello.s
hello.s: assembler source text

$ cat hello.c | gcc -x c - -S -o hello.s # works okay
$ file hello.s; rm -f hello.s
hello.s assembler source text

$ cat hello.c | cilly -x c - -S -o hello.s # BUG!
$ file hello.s
hello.s: ERROR: cannot open `hello.s' (No such file or directory)

A related problem is that cilly doesn't correctly handle gcc's "-x " option, which is often used in combination with input on stdin. Currently cilly just passes this options to the compiler --
which sometimes works, but doesn't preserve the option's semantics. For example,

$ gcc -E -o hello.cc hello.c
$ gcc -x cpp-output -o hello hello.cc

... works, whereas

$ cilly -E -o hello.cc hello.c
$ cilly -x cpp-output -o hello hello.cc
(snip)
/tmp/cil-jSfqyHOy.o:6:4: error: stray ?\2? in program
/tmp/cil-jSfqyHOy.o:6:21: warning: null character(s) ignored
/tmp/cil-jSfqyHOy.o:6:4: error: stray ?\2? in program
/tmp/cil-jSfqyHOy.o:6:25: warning: null character(s) ignored

I have prepared a rough patch with fixes both of these problems. It's not great code (my Perl is amateurish) and could use a quick review. (Am happy to submit by e-mail, and/or rework any part that could do with a better solution.)

diff --git a/lib/perl5/App/Cilly.pm.in b/lib/perl5/App/Cilly.pm.in
index 63f9163..6e48d1f 100644
--- a/lib/perl5/App/Cilly.pm.in
+++ b/lib/perl5/App/Cilly.pm.in
@@ -199,7 +199,7 @@ sub collectArgumentList {
 #
 #        my $arg = shift @args; # Grab the next one
         if(! $self->collectOneArgument($arg, \@args)) {
-            print "Warning: Unknown argument $arg\n";
+            if (! $arg eq "-") { print STDERR "Warning: Unknown argument $arg\n"; }
             push @{$self->{CCARGS}}, $arg;
         }
     }
@@ -541,25 +541,38 @@ sub preprocess_compile {
     &mydebug("preprocess_compile(src=$src, dest=$dest)\n");
     Carp::confess "bad dest: $dest" unless $dest->isa('App::Cilly::OutputFile');

-    my ($base, $dir, $ext) = fileparse($src, "\\.[^.]+");
-    if($ext eq ".c" || $ext eq ".cpp" || $ext eq ".cc") {
-        if($self->leaveAlone($src)) {
-            print "Leaving alone $src\n";
-            # We leave this alone. So just compile as usual
-            return $self->straight_compile($src, $dest, [@{$early_ppargs}, @{$ppargs}], $ccargs);
-        }
-        my $out    = $self->preprocessOutputFile($src);
-        $out = $self->preprocess($src, $out, 
-                                 [@{$early_ppargs}, @{$ppargs},
-                                  "$self->{DEFARG}CIL=1"]);
-        return $self->compile($out, $dest, $ppargs, $ccargs);
+    if (! $src eq "-") {
+      my ($base, $dir, $ext) = fileparse($src, "\\.[^.]+");
+      # check that they're sane
+      die "preprocess_compile requires an unpreprocessed source file! got $src\n"
+         unless ($ext eq ".c" || $ext eq ".cpp" || $ext eq ".cc");
     }
-    if($ext eq ".i") {
-        return $self->compile($src, $dest, $ppargs, $ccargs);
+
+    if($self->leaveAlone($src)) {
+        print "Leaving alone $src\n";
+        # We leave this alone. So just compile as usual
+        return $self->straight_compile($src, $dest, [@{$early_ppargs}, @{$ppargs}], $ccargs);
     }
-    if($ext eq ".$::cilbin") {
-        return $self->compile($src, $dest, $ppargs, $ccargs);
+    my $out    = $self->preprocessOutputFile($src);
+    $out = $self->preprocess($src, $out,
+                             [@{$early_ppargs}, @{$ppargs},
+                              "$self->{DEFARG}CIL=1"]);
+    return $self->compile($out, $dest, $ppargs, $ccargs);
+}
+
+sub compile_nopp {
+    my ($self, $src, $dest, $early_ppargs, $ppargs, $ccargs) = @_;
+    &mydebug("compile_nopp(src=$src, dest=$dest)\n");
+    Carp::confess "bad dest: $dest" unless $dest->isa('App::Cilly::OutputFile');
+
+    if (! $src eq "-") {
+      my ($base, $dir, $ext) = fileparse($src, "\\.[^.]+");
+      # check that they're sane
+      die "compile_nopp requires a preprocessed source file! got $src\n"
+         unless ($ext eq ".i" || $ext eq ".$::cilbin");
     }
+
+    return $self->compile($src, $dest, $ppargs, $ccargs);
 }

 # THIS IS THE ENTRY POINT FOR JUST PREPROCESSING A FILE
@@ -1095,8 +1108,8 @@ sub doit {
     # we can go ahead with the compilation, without having to save 
     # files
     if(! $self->{SEPARATE} && # Not already separate mode
-       $self->{OPERATION} eq "TOEXE" &&  # We are linking to an executable
-       @{$self->{CFILES}} + @{$self->{IFILES}} <= 1) { # At most one source
+       @{$self->{CFILES}} + @{$self->{IFILES}} <= 1 &&  # At most one source
+       ($self->{OPERATION} eq "TOEXE" || defined $self->{OUTARG})) {  # We are linking to an executable
         # If we have object files, we should keep merging if at least one 
         # object file is a disguised source
         my $turnOffMerging = 0;
@@ -1117,16 +1130,22 @@ sub doit {
         }
     }

-    # Turn everything into OBJ files
+    # Turn everything into OBJ files (or assembly, if the user asked for that)
     my @tolink = ();
-
-    foreach $file (@{$self->{IFILES}}, @{$self->{CFILES}}) {
+    foreach $file (@{$self->{CFILES}}) {
         $out = $self->compileOutputFile($file);
         $self->preprocess_compile($file, $out,
                  $self->{EARLY_PPARGS},
                                   $self->{PPARGS}, $self->{CCARGS});
         push @tolink, $out;
     }
+    foreach $file (@{$self->{IFILES}}) {
+        $out = $self->compileOutputFile($file);
+        $self->compile_nopp($file, $out,
+                 $self->{EARLY_PPARGS},
+                                  $self->{PPARGS}, $self->{CCARGS});
+        push @tolink, $out;
+    }
     # Now do the assembly language file
     foreach $file (@{$self->{SFILES}}) {
         $out = $self->assembleOutputFile($file);
@@ -1184,23 +1203,25 @@ sub doit {
 }

 sub classifyArgDebug {
-    if(0) { print @_; }
+    if(1) { print @_; }
 }

 sub mydebug {
-    if(0) { print @_; }
+    if(1) { print @_; }
 }

 sub compilerArgument {
     my($self, $options, $arg, $pargs) = @_;
     &classifyArgDebug("Classifying arg: $arg\n");
     my $idx = 0;
+    my $matched = 0;
     for($idx=0; $idx < $#$options; $idx += 2) {
         my $key = ${$options}[$idx];
         my $action = ${$options}[$idx + 1];
         &classifyArgDebug("Try match with $key\n");
         if($arg =~ m|^$key|) {
           &classifyArgDebug(" match with $key\n");
+          $matched = 1;
           my @fullarg = ($arg);
           my $onemore;
           if(defined $action->{'ONEMORE'}) {
@@ -1218,6 +1239,21 @@ sub compilerArgument {
               }
               &classifyArgDebug(" onemore=$onemore\n");
           }
+          # If we have CURLANG, it might override the action the caller
+          # supplied.
+          if (defined $self->{'CURLANG'}) {
+            if ($action->{TYPE} =~ /.*SOURCE$/) {
+              if    ($self->{CURLANG} =~ /c|c-header/)          { $action->{TYPE} = "CSOURCE"; }
+              elsif ($self->{CURLANG} =~ /cpp-output/)          { $action->{TYPE} = "ISOURCE"; }
+              elsif ($self->{CURLANG} =~ /assembler/)           { $action->{TYPE} = "ASMSOURCE"; }
+              elsif ($self->{CURLANG} =~ /assembler-woth-cpp/)  { $action->{TYPE} = "ASMSOURCE"; }
+              else {
+                print "Warning: didn't understand current language $self->{CURLANG}\n";
+              }
+            }
+          } elsif ($action->{TYPE} eq "UNKNOWNSOURCE") {
+            print "Warning: saw source of unknown language, with no preceding -x <lang>\n";
+          }
           # Now see what action we must perform
           my $argument_done = 1;
           if(defined $action->{'RUN'}) {
@@ -1240,7 +1276,17 @@ sub compilerArgument {
               elsif($action->{TYPE} eq "CC") {
                   push @{$self->{CCARGS}}, @fullarg; return 1;
               }
-              elsif($action->{TYPE} eq "LINKCC") {
+              elsif($action->{TYPE} eq "SETLANG") {
+                  # We pass it to the C compiler, as if it were a "CC" action,
+                  # but we also keep some state so we can classify input files.
+                  if ($onemore eq "none") {
+                    delete $self->{CURLANG};
+                  } else {
+                    $self->{CURLANG} = $onemore;
+                  }
+                  push @{$self->{CCARGS}}, @fullarg; return 1;
+              }
+            elsif($action->{TYPE} eq "LINKCC") {
                   push @{$self->{CCARGS}}, @fullarg; 
                   push @{$self->{LINKARGS}}, @fullarg; return 1;
               }
@@ -1255,6 +1301,7 @@ sub compilerArgument {
               elsif($action->{TYPE} eq "CSOURCE") {
                 App::Cilly::OutputFile->protect(@fullarg);
                   $fullarg[0] = &normalizeFileName($fullarg[0]);
+                  print "Pushing $fullarg[0]\n";
                   push @{$self->{CFILES}}, @fullarg; return 1;
               }
               elsif($action->{TYPE} eq "ASMSOURCE") {
@@ -1285,6 +1332,7 @@ sub compilerArgument {
           print "Don't know what to do with option $arg\n"; 
           return 0;
       }
+
    }
    return 0;
 }
@@ -1924,6 +1972,7 @@ sub new {
             "[^-].*\\.($::cilbin|c|cpp|cc)\$" => { TYPE => 'CSOURCE' },
             "[^-].*\\.(s|S)\$" => { TYPE => 'ASMSOURCE' },
             "[^-].*\\.i\$" => { TYPE => 'ISOURCE' },
+            "-\$" => { TYPE => 'UNKNOWNSOURCE' },
             # .o files can be linker scripts
             "[^-]" => { RUN => sub { &GNUCC::parseLinkerScript(@_); }},

@@ -1935,7 +1984,7 @@ sub new {
             "-o" => { ONEMORE => 1, TYPE => 'OUT' },
        "-combine\$" => { TYPE => 'ALLARGS' },
        "-pipe\$" => { TYPE => 'ALLARGS' },
-            "-x" => { ONEMORE => 1, TYPE => "CC" },
+       "-x" => { ONEMORE => 1, TYPE => "SETLANG" },
        "-v" => { TYPE => 'ALLARGS',
              RUN => sub { $stub->{TRACE_COMMANDS} = 1; } },
        # skipping -###, --help, --target-help, --version
@@ -2176,8 +2225,11 @@ sub lineDirective {
 sub compileOutputFile {
     my($self, $src) = @_;

-    die "objectOutputFile: not a C source file: $src\n"
-   unless $src =~ /\.($::cilbin|c|cc|cpp|i|s|S)$/;
+    # in the "-" case we will have an OUTARG
+    if ($src eq "-") { die "input is '-' but no outarg\n" unless defined $self->{OUTARG}; }
+    else { die "objectOutputFile: not a C source file: $src\n"
+   unless $src =~ /\.($::cilbin|c|cc|cpp|i|asm)$/;
+    }

     if ($self->{OPERATION} eq 'TOOBJ'
         || ($self->{OPERATION} eq 'TOASM')) {

Makefile:102: recipe for target 'ocamlbuild' failed

Hi, when I tried to install the cil in my ubuntu 18.04.4 TLS, I found some problems.

  • First, I tried to use
    opam install cil
    to install cil but it shows
    [ERROR] cil is not a valid versioned package name
    'opam install cil' failed.

  • After that, I tried opam install cil.1.7.3 but it still couldn't work.
    [ERROR] "cil" is not a valid package.
    'opam install cil.1.7.3' failed.

  • Then I tried to use the project to make it.
    But after I run ./configure successfully, when I run make, some error occured.

......
/usr/bin/ld: /usr/lib/ocaml/libasmrun.a(compact.o): relocation R_X86_64_32 against `.rodata.str1.1' can not be used when making a PIE object; recompile with -fPIC
/usr/bin/ld: /usr/lib/ocaml/libasmrun.a(finalise.o): relocation R_X86_64_32 against `.rodata.str1.1' can not be used when making a PIE object; recompile with -fPIC
/usr/bin/ld: /usr/lib/ocaml/libasmrun.a(custom.o): relocation R_X86_64_32S against `.rodata.str1.1' can not be used when making a PIE object; recompile with -fPIC
/usr/bin/ld: /usr/lib/ocaml/libasmrun.a(unix.o): relocation R_X86_64_32 against `.rodata.str1.1' can not be used when making a PIE object; recompile with -fPIC
/usr/bin/ld: /usr/lib/ocaml/libasmrun.a(backtrace.o): relocation R_X86_64_32 against symbol `caml_backtrace_last_exn' can not be used when making a PIE object; recompile with -fPIC
/usr/bin/ld: final link failed: Nonrepresentable section on output
collect2: error: ld returned 1 exit status
File "caml_startup", line 1:
Error: Error during linking
Command exited with code 2.
Makefile:102: recipe for target 'ocamlbuild' failed
make[1]: *** [ocamlbuild] Error 10
make[1]: Leaving directory '/home/zby/Downloads/cil'
Makefile:371: recipe for target 'install-local' failed
make: *** [install-local] Error 2

Extern inline prototypes should not replace definitions

Currently CIL is defeated by always_inline extern inline functions whose prototypes are repeated after their definition (but before their use).

$ cat vminimal.i
extern void f(void);
extern inline __attribute__((always_inline)) void g()
{
        f();
}

extern inline __attribute__((always_inline)) void g();

void v(void)
{
        g();
}

$ cc -c -o vminimal.o vminimal.i
$ cilly -c -o vminimal.o vminimal.i

vminimal.i: In function ‘v’:
vminimal.i:2:59: error: inlining failed in call to always_inline ‘g’: function body not available
 extern inline __attribute__((always_inline)) void g()
                                                           ^
vminimal.i:11:3: error: called from here
  g();
   ^

The following patch fixes things for me. (I'll forward it by e-mail too, since GitHub doesn't let me attach it.)

diff --git a/src/frontc/cabs2cil.ml b/src/frontc/cabs2cil.ml
index dc185e1..30633c6 100644
--- a/src/frontc/cabs2cil.ml
+++ b/src/frontc/cabs2cil.ml
@@ -1792,7 +1792,7 @@ let makeGlobalVarinfo (isadef: bool) (vi: varinfo) : varinfo * bool =

     (* New-style extern inline handling: the real definition replaces the extern
        inline one *)
-    if (not !Cil.oldstyleExternInline) && oldvi.vstorage = Extern && oldvi.vinline then begin
+    if (not !Cil.oldstyleExternInline) && oldvi.vstorage = Extern && oldvi.vinline && isadef then begin
       H.remove alreadyDefined oldvi.vname;
       theFile := Util.list_map (fun g -> match g with
           | GFun (fi, l) when fi.svar == oldvi -> GVarDecl(fi.svar, l)

alias attribute is handled incorrectly (and incompletely)

I recently stumbled on the following code in cabs2cil that handles (non-variadic) function aliases.

  let rt, formals, isva, _ = splitFunctionType vtype in
  if isva then E.s (error "%a: alias unsupported with varargs."
                      d_loc !currentLoc);
  let args = Util.list_map 
               (fun (n,_,_) -> A.VARIABLE n)
               (argsToList formals) in
  let call = A.CALL (A.VARIABLE othername, args) in
  let stmt = if isVoidType rt then A.COMPUTATION(call, loc)
                              else A.RETURN(call, loc)
  in
  let body = { A.blabels = []; A.battrs = []; A.bstmts = [stmt] } in
  let fdef = A.FUNDEF (sname, body, loc, loc) in
  ignore (doDecl true fdef);
  (* get the new function *)
  let v,_ = try lookupGlobalVar thisname
            with Not_found -> E.s (bug "error in doDecl") in
  v.vattr <- dropAttribute "alias" v.vattr

It seems to define the alias by creating a fresh function which calls the aliased function. This is semantically wrong because the two functions' addresses should be equal. Also, it doesn't handle varargs functions, and aliases of variables are not implemented at all. (I am currently trying to compile eglibc with CIL, and it uses aliases a lot.)

The only sane fix seems to be to change the data model, so that every GVar has a list of aliases, each with their own attributes. This would seem to require an API-breaking change -- or is there a better way?

At least the following would then have to happen. Aliases all get declared when the global is declared. Lookups by name must resolve aliases when appropriate. Each alias probably ought to have its own location, although that could probably be finessed away if it were too great a change.

I am adding this to my internal to-do queue, but would welcome suggestions for alternative ways to deal with it.

Cil.typsig conflates distinct function types

CIL typsigs do not distinguish between the types

typedef int f();

and

typedef int f(void);

I will call the first case "no arguments specified" and the second "specified as no-arguments". They both yield the typesigs

TSFun(TSBase(void ), [],false, [])

Note that Cil.typ does encode this distinction, since the argument list can be Some([]) or None.

A possible fix which doesn't break absolutely everybody's code might be to take the C++ approach: the "no arguments specified" case is encoded as a zero-arguments varargs function, i.e.

TSFun(TSBase(void ), [], true, [])

whereas the "specified as no-arguments" case remains as-is.

I could be persuaded to work on a patch to fix this, although I am just working around it for now. :-)

CIL throws syntax error for file wget1.14/lib/md5.c during compilation to create the library libgnu.a

I am trying to compile Wget-1.14 source code with CIL. I made the default configuration of the Makefile in wget-1.14/lib/Makefile from:

AR = ar
ARFLAGS = cru
CC = gcc
CFLAGS = -g -O2 -Wall -pthread -static

to

AR =  cilly --save-temps=build  --merge --keepmerged --mode=AR
ARFLAGS = r
CC =  cilly --save-temps=build --merge --keepmerged
CFLAGS = -g -O2 -Wall -pthread -static

When the make file is run, to create the library libgnu.a the following command is run as the last step:

cilly --save-temps=build  --merge --keepmerged --mode=AR r libgnu.a base32.o c-ctype.o c-strcasecmp.o c-strncasecmp.o cloexec.o md5.o sha1.o dirname-lgpl.o basename-lgpl.o stripslash.o exitfail.o fatal-signal.o fd-hook.o fd-safer-flag.o dup-safer-flag.o gettime.o localcharset.o glthread/lock.o pipe2.o pipe2-safer.o quotearg.o sockets.o spawn-pipe.o stat-time.o tempname.o glthread/threadlib.o timespec.o tmpdir.o dup-safer.o fd-safer.o pipe-safer.o utimens.o wait-process.o xmalloc.o xalloc-die.o asnprintf.o fcntl.o futimens.o getpass.o ioctl.o printf-args.o printf-parse.o strerror_r.o vasnprintf.o

On running this command, the following error is thrown at line 258 of md5.c:

Library libgnu.a not found; creating. at *******
Turning off warn-is-error flag 
***/cil/obj/x86_LINUX/cilly.asm.exe --extrafiles ___extra_files --mergedout libgnu.a
md5.c[258:0-0] : syntax error
Parsing errorFatal error: exception Frontc.ParseError("Parse error")
Makefile:1383: recipe for target 'libgnu.a' failed
make[2]: *** [libgnu.a] Error 2

The code for md5.c from line 258 is in function md5_process_bytes. Lines 253-273 looks like:

253   /* Process available complete blocks.  */
254   if (len >= 64)
255     {
256 #if !_STRING_ARCH_unaligned
257 # define UNALIGNED_P(p) ((uintptr_t) (p) % alignof (uint32_t) != 0)
258       if (UNALIGNED_P (buffer)){
259         while (len > 64)
260           {
261             md5_process_block (memcpy (ctx->buffer, buffer, 64), 64, ctx);
262             buffer = (const char *) buffer + 64;
263             len -= 64;
264           }
265         }
266       else
267 #endif
268         {
269           md5_process_block (buffer, len & ~63, ctx);
270           buffer = (const char *) buffer + (len & ~63);
271           len &= 63;
272         }
273     }

I hope if anyone can share your opinions and suggestions on the potential syntactical error that CIL might be encountering.

Thanks in advance.

cilly: Cannot find GNUCC version

I faced this error when trying to use cilly on Linux with gcc 8, didn't find much related to this issue from Google, but finally was able to fix the prob. So just want to put the solution here just in case others face the same issue.

The problem seems to be that cilly doesn't like gcc 8, so telling cilly to use an older gcc version works.

$ cilly --merge -c ~/Dropbox/git/WSymtraces/symtracesOld/programs/nla/cohendiv.c
Cannot find GNUCC version
debian Fri Apr 12:21:43:15 (2261) /home/SHARED/Devel/CIL/cil-1.7.3
$ cilly --gcc=/usr/bin/gcc-8  --merge -c ~/Dropbox/git/WSymtraces/symtracesOld/programs/nla/cohendiv.c
Cannot find GNUCC version
debian Fri Apr 12:21:43:22 (2262) /home/SHARED/Devel/CIL/cil-1.7.3
$ cilly --gcc=/usr/bin/gcc-6  --merge -c ~/Dropbox/git/WSymtraces/symtracesOld/programs/nla/cohendiv.c
/usr/bin/gcc-6 -D_GNUCC -E -DCIL=1 /home/tnguyen/Dropbox/git/WSymtraces/symtracesOld/programs/nla/cohendiv.c -o /tmp/cil-HIhbdf4L.i
debian Fri Apr 12:21:43:30 (2263) /home/SHARED/Devel/CIL/cil-1.7.3
$ cilly --gcc=/usr/bin/gcc-4.9  --merge -c ~/Dropbox/git/WSymtraces/symtracesOld/programs/nla/cohendiv.c
/usr/bin/gcc-4.9 -D_GNUCC -E -DCIL=1 /home/tnguyen/Dropbox/git/WSymtraces/symtracesOld/programs/nla/cohendiv.c -o /tmp/cil-fuo0RgEZ.i
debian Fri Apr 12:21:43:34 (2264) /home/SHARED/Devel/CIL/cil-1.7.3

Trace is a bad choice of name for a module inside CIL

Trace is a bad choice of name for a module inside CIL. It prevents the OCAML toplevel from linking.

ocamlmktop -o cilmain -I ocamlfind -query cil nums.cma unix.cma str.cma cil.cma cilmain.cmo
File "/home/jrrk2/.opam/4.03.0/lib/cil/cil.cma(Trace)", line 1:
Warning 31: files /home/jrrk2/.opam/4.03.0/lib/cil/cil.cma(Trace) and
/home/jrrk2/.opam/4.03.0/lib/ocaml/compiler-libs/ocamltoplevel.cma(Trace) both define a module named Trace
Error: Some fatal warnings were triggered (1 occurrences)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.