Configure: complete the changed fuzz option checks
[openssl.git] / Configure
index 3d36783941dc0139e7b7600406569f1e7e2467be..7bbb5b7697b348390a29eccf22d2244ff08ee3f0 100755 (executable)
--- a/Configure
+++ b/Configure
@@ -14,6 +14,7 @@ use strict;
 use File::Basename;
 use File::Spec::Functions qw/:DEFAULT abs2rel rel2abs/;
 use File::Path qw/mkpath/;
+use if $^O ne "VMS", 'File::Glob' => qw/glob/;
 
 # see INSTALL for instructions.
 
@@ -210,7 +211,7 @@ die "erroneous version information in opensslv.h: ",
 # Collect target configurations
 
 my $pattern = catfile(dirname($0), "Configurations", "*.conf");
-foreach (sort glob($pattern) ) {
+foreach (sort glob($pattern)) {
     &read_config($_);
 }
 
@@ -223,7 +224,7 @@ if (defined $ENV{$local_config_envname}) {
         $pattern = catfile($ENV{$local_config_envname}, '*.conf');
     }
 
-    foreach (sort glob($pattern) ) {
+    foreach (sort glob($pattern)) {
         &read_config($_);
     }
 }
@@ -266,6 +267,7 @@ my @dtls = qw(dtls1 dtls1_2);
 
 my @disablables = (
     "afalgeng",
+    "asan",
     "asm",
     "async",
     "autoalginit",
@@ -299,6 +301,8 @@ my @disablables = (
     "engine",
     "err",
     "filenames",
+    "fuzz-libfuzzer",
+    "fuzz-afl",
     "gost",
     "heartbeats",
     "hw(-.+)?",
@@ -337,6 +341,7 @@ my @disablables = (
     "threads",
     "tls",
     "ts",
+    "ubsan",
     "ui",
     "unit-test",
     "whirlpool",
@@ -352,24 +357,30 @@ foreach my $proto ((@tls, @dtls))
 
 my @deprecated_disablables = (
     "ssl2",
+    "buf-freelists",
     );
 
 # All of the following is disabled by default (RC5 was enabled before 0.9.8):
 
 our %disabled = ( # "what"         => "comment"
+                  "asan"               => "default",
                  "ec_nistp_64_gcc_128" => "default",
                  "egd"                 => "default",
+                 "fuzz-libfuzzer"      => "default",
+                 "fuzz-afl"            => "default",
                  "md2"                 => "default",
                  "rc5"                 => "default",
                  "sctp"                => "default",
                  "ssl-trace"           => "default",
                  "ssl3"                => "default",
                  "ssl3-method"         => "default",
+                  "ubsan"              => "default",
                  "unit-test"           => "default",
                  "weak-ssl-ciphers"    => "default",
                  "zlib"                => "default",
                  "zlib-dynamic"        => "default",
                  "crypto-mdebug"       => "default",
+                 "crypto-mdebug-backtrace" => "default",
                  "heartbeats"          => "default",
                );
 
@@ -689,6 +700,14 @@ foreach (@argvcopy)
                        {
                        $withargs{zlib_include}=$1;
                        }
+               elsif (/^--with-fuzzer-lib=(.*)$/)
+                       {
+                       $withargs{fuzzer_lib}=$1;
+                       }
+               elsif (/^--with-fuzzer-include=(.*)$/)
+                       {
+                       $withargs{fuzzer_include}=$1;
+                       }
                elsif (/^--with-fipslibdir=(.*)$/)
                        {
                        $config{fipslibdir}="$1/";
@@ -903,9 +922,13 @@ $config{cross_compile_prefix} = $ENV{'CROSS_COMPILE'}
 # Allow overriding the names of some tools.  USE WITH CARE
 $config{perl} =    $ENV{'PERL'}    || ($^O ne "VMS" ? $^X : "perl");
 $target{cc} =      $ENV{'CC'}      || $target{cc}      || "cc";
-$target{ranlib} =  $ENV{'RANLIB'}  || $target{ranlib}  || which("ranlib") || "true";
+$target{ranlib} =  $ENV{'RANLIB'}  || $target{ranlib}  ||
+                   (which("$config{cross_compile_prefix}ranlib") ?
+                          "\$(CROSS_COMPILE)ranlib" : "true");
 $target{ar} =      $ENV{'AR'}      || $target{ar}      || "ar";
 $target{nm} =      $ENV{'NM'}      || $target{nm}      || "nm";
+$target{rc} =
+    $ENV{'RC'}  || $ENV{'WINDRES'} || $target{rc}      || "windres";
 
 # For cflags, lflags, plib_lflags, ex_libs and defines, add the debug_
 # or release_ attributes.
@@ -1029,6 +1052,29 @@ if ($disabled{"dynamic-engine"}) {
         $config{dynamic_engines} = 1;
 }
 
+unless ($disabled{"fuzz-libfuzzer"}) {
+    push @{$config{dirs}}, "fuzz";
+    $config{cflags} .= "-fsanitize-coverage=edge,indirect-calls ";
+}
+
+unless ($disabled{"fuzz-afl"}) {
+    push @{$config{dirs}}, "fuzz";
+}
+
+unless ($disabled{asan}) {
+    $config{cflags} .= "-fsanitize=address ";
+}
+
+unless ($disabled{ubsan}) {
+    # -DPEDANTIC or -fnosanitize=aligmnent may also be required on some
+    # platforms.
+    $config{cflags} .= "-fsanitize=undefined -fno-sanitize-recover=all ";
+}
+
+unless ($disabled{"fuzz-libfuzzer"} && $disabled{"fuzz-afl"}
+        && $disabled{asan} && $disabled{ubsan}) {
+    $config{cflags} .= "-fno-omit-frame-pointer -g ";
+}
 #
 # Platform fix-ups
 #
@@ -1238,12 +1284,27 @@ my $buildinfo_debug = defined($ENV{CONFIGURE_DEBUG_BUILDINFO});
 if ($builder eq "unified") {
     # Store the name of the template file we will build the build file from
     # in %config.  This may be useful for the build file itself.
-    my $build_file_template =
-        catfile($srcdir, "Configurations",
-                $builder_platform."-".$target{build_file}.".tmpl");
-    $build_file_template =
-        catfile($srcdir, "Configurations", $target{build_file}.".tmpl")
-        if (! -f $build_file_template);
+    my $build_file_template;
+
+    for my $filename (( $builder_platform."-".$target{build_file}.".tmpl",
+                        $target{build_file}.".tmpl" )) {
+        if (defined $ENV{$local_config_envname}) {
+            if ($^O eq 'VMS') {
+                # VMS environment variables are logical names,
+                # which can be used as is
+                $build_file_template = $local_config_envname . ':' . $filename;
+            } else {
+                $build_file_template = catfile($ENV{$local_config_envname},
+                                               $filename);
+            }
+        }
+
+        last if -f $build_file_template;
+
+        $build_file_template = catfile($srcdir, "Configurations", $filename);
+
+        last if -f $build_file_template;
+    }
     $config{build_file_template} = $build_file_template;
 
     use lib catdir(dirname(__FILE__),"util");
@@ -1333,6 +1394,7 @@ if ($builder eq "unified") {
             $template->fill_in(HASH => { config => \%config,
                                          target => \%target,
                                          disabled => \%disabled,
+                                         withargs => \%withargs,
                                          builddir => abs2rel($buildd, $blddir),
                                          sourcedir => abs2rel($sourced, $blddir),
                                          buildtop => abs2rel($blddir, $blddir),
@@ -1373,47 +1435,47 @@ if ($builder eq "unified") {
             => sub { die "ENDIF out of scope" if ! @skip;
                      pop @skip; },
             qr/^\s*PROGRAMS\s*=\s*(.*)\s*$/
-            => sub { push @programs, split(/\s+/, $1)
+            => sub { push @programs, tokenize($1)
                          if !@skip || $skip[$#skip] > 0 },
             qr/^\s*LIBS\s*=\s*(.*)\s*$/
-            => sub { push @libraries, split(/\s+/, $1)
+            => sub { push @libraries, tokenize($1)
                          if !@skip || $skip[$#skip] > 0 },
             qr/^\s*ENGINES\s*=\s*(.*)\s*$/
-            => sub { push @engines, split(/\s+/, $1)
+            => sub { push @engines, tokenize($1)
                          if !@skip || $skip[$#skip] > 0 },
             qr/^\s*SCRIPTS\s*=\s*(.*)\s*$/
-            => sub { push @scripts, split(/\s+/, $1)
+            => sub { push @scripts, tokenize($1)
                          if !@skip || $skip[$#skip] > 0 },
             qr/^\s*EXTRA\s*=\s*(.*)\s*$/
-            => sub { push @extra, split(/\s+/, $1)
+            => sub { push @extra, tokenize($1)
                          if !@skip || $skip[$#skip] > 0 },
             qr/^\s*OVERRIDES\s*=\s*(.*)\s*$/
-            => sub { push @overrides, split(/\s+/, $1)
+            => sub { push @overrides, tokenize($1)
                          if !@skip || $skip[$#skip] > 0 },
 
             qr/^\s*ORDINALS\[((?:\\.|[^\\\]])+)\]\s*=\s*(.*)\s*$/,
-            => sub { push @{$ordinals{$1}}, split(/\s+/, $2)
+            => sub { push @{$ordinals{$1}}, tokenize($2)
                          if !@skip || $skip[$#skip] > 0 },
             qr/^\s*SOURCE\[((?:\\.|[^\\\]])+)\]\s*=\s*(.*)\s*$/
-            => sub { push @{$sources{$1}}, split(/\s+/, $2)
+            => sub { push @{$sources{$1}}, tokenize($2)
                          if !@skip || $skip[$#skip] > 0 },
             qr/^\s*SHARED_SOURCE\[((?:\\.|[^\\\]])+)\]\s*=\s*(.*)\s*$/
-            => sub { push @{$shared_sources{$1}}, split(/\s+/, $2)
+            => sub { push @{$shared_sources{$1}}, tokenize($2)
                          if !@skip || $skip[$#skip] > 0 },
             qr/^\s*INCLUDE\[((?:\\.|[^\\\]])+)\]\s*=\s*(.*)\s*$/
-            => sub { push @{$includes{$1}}, split(/\s+/, $2)
+            => sub { push @{$includes{$1}}, tokenize($2)
                          if !@skip || $skip[$#skip] > 0 },
             qr/^\s*DEPEND\[((?:\\.|[^\\\]])+)\]\s*=\s*(.*)\s*$/
-            => sub { push @{$depends{$1}}, split(/\s+/, $2)
+            => sub { push @{$depends{$1}}, tokenize($2)
                          if !@skip || $skip[$#skip] > 0 },
             qr/^\s*GENERATE\[((?:\\.|[^\\\]])+)\]\s*=\s*(.*)\s*$/
             => sub { push @{$generate{$1}}, $2
                          if !@skip || $skip[$#skip] > 0 },
             qr/^\s*RENAME\[((?:\\.|[^\\\]])+)\]\s*=\s*(.*)\s*$/
-            => sub { push @{$renames{$1}}, split(/\s+/, $2)
+            => sub { push @{$renames{$1}}, tokenize($2)
                          if !@skip || $skip[$#skip] > 0 },
             qr/^\s*SHARED_NAME\[((?:\\.|[^\\\]])+)\]\s*=\s*(.*)\s*$/
-            => sub { push @{$sharednames{$1}}, split(/\s+/, $2)
+            => sub { push @{$sharednames{$1}}, tokenize($2)
                          if !@skip || $skip[$#skip] > 0 },
             qr/^\s*BEGINRAW\[((?:\\.|[^\\\]])+)\]\s*$/
             => sub {
@@ -1834,7 +1896,7 @@ print OUT "1;\n";
 close(OUT);
 
 
-print "CC            =$target{cc}\n";
+print "CC            =$config{cross_compile_prefix}$target{cc}\n";
 print "CFLAG         =$target{cflags} $config{cflags}\n";
 print "SHARED_CFLAG  =$target{shared_cflag}\n";
 print "DEFINES       =",join(" ", @{$target{defines}}, @{$config{defines}}),"\n";
@@ -1862,7 +1924,9 @@ print "CHACHA_ENC    =$target{chacha_obj}\n";
 print "POLY1305_OBJ  =$target{poly1305_obj}\n";
 print "BLAKE2_OBJ    =$target{blake2_obj}\n";
 print "PROCESSOR     =$config{processor}\n";
-print "RANLIB        =$target{ranlib}\n";
+print "RANLIB        =", $target{ranlib} eq '$(CROSS_COMPILE)ranlib' ?
+                             "$config{cross_compile_prefix}ranlib" :
+                             "$target{ranlib}", "\n";
 print "ARFLAGS       =$target{arflags}\n";
 print "PERL          =$config{perl}\n";
 print "\n";
@@ -1878,53 +1942,12 @@ for (@generated_headers) {
                catfile($srcdir, $_.".in"));
 }
 
-###
-### When the old "unixmake" scheme goes away, so does this function
-###
-sub build_Makefile {
-    run_dofile("Makefile","Makefile.in");
-
-    # Copy all Makefile.in to Makefile (except top-level)
-    use File::Find;
-    use IO::File;
-    find(
-        {
-            preprocess => sub {
-                grep(!/^\./, @_);
-            },
-            wanted => sub {
-                return if ($_ ne "Makefile.in" || $File::Find::dir eq ".");
-                my $in = IO::File->new($_, "r") or
-                    die sprintf "Error reading Makefile.in in %s: !$\n",
-                    $File::Find::dir;
-                my $out = IO::File->new("Makefile", "w") or
-                    die sprintf "Error writing Makefile in %s: !$\n",
-                    $File::Find::dir;
-                print $out "# Generated from $_, do not edit\n";
-                while (my $line = <$in>) { print $out $line }
-                $in->close() or
-                    die sprintf "Error reading Makefile.in in %s: !$\n",
-                    $File::Find::dir;
-                $out->close() or
-                    die sprintf "Error writing Makefile in %s: !$\n",
-                    $File::Find::dir;
-            },
-        },
-        ".");
-}
-
 my %builders = (
     unified => sub {
         run_dofile(catfile($blddir, $target{build_file}),
                    $config{build_file_template},
                    catfile($srcdir, "Configurations", "common.tmpl"));
     },
-    unixmake => sub {
-        build_Makefile();
-
-        run_dofile("util/domd", "util/domd.in");
-        chmod 0755, "util/domd";
-    },
     );
 
 $builders{$builder}->($builder_platform, @builder_opts);
@@ -2285,13 +2308,34 @@ sub run_dofile
     foreach (@templates) {
         die "Can't open $_, $!" unless -f $_;
     }
-    my $cmd = "$config{perl} \"-I.\" \"-Mconfigdata\" $dofile -o\"Configure\" \"".join("\" \"",@templates)."\" > \"$out.new\"";
+    my $cmd = "$config{perl} \"-I.\" \"-Mconfigdata\" \"$dofile\" -o\"Configure\" \"".join("\" \"",@templates)."\" > \"$out.new\"";
     #print STDERR "DEBUG[run_dofile]: \$cmd = $cmd\n";
     system($cmd);
     exit 1 if $? != 0;
     rename("$out.new", $out) || die "Can't rename $out.new, $!";
 }
 
+sub which
+{
+    my ($name)=@_;
+
+    if (eval { require IPC::Cmd; 1; }) {
+        IPC::Cmd->import();
+        return scalar IPC::Cmd::can_run($name);
+    } else {
+        # if there is $directories component in splitpath,
+        # then it's not something to test with $PATH...
+        return $name if (File::Spec->splitpath($name))[1];
+
+        foreach (File::Spec->path()) {
+            my $fullpath = catfile($_, "$name$target{exe_extension}");
+            if (-f $fullpath and -x $fullpath) {
+                return $fullpath;
+            }
+        }
+    }
+}
+
 # Configuration printer ##############################################
 
 sub print_table_entry
@@ -2419,22 +2463,6 @@ sub absolutedir {
     return realpath($dir);
 }
 
-sub which
-       {
-       my($name)=@_;
-       my $path;
-       foreach $path (split /:/, $ENV{PATH})
-               {
-               my $fullpath = "$path/$name$target{exe_extension}";
-               if (-f $fullpath and -x $fullpath)
-                       {
-                       return $fullpath
-                           unless ($name eq "perl" and
-                                   system("$fullpath -e " . '\'exit($]<5.0);\''));
-                       }
-               }
-       }
-
 sub quotify {
     my %processors = (
        perl    => sub { my $x = shift;
@@ -2538,3 +2566,41 @@ sub collect_information {
         }
     }
 }
+
+# tokenize($line)
+# $line is a line of text to split up into tokens
+# returns a list of tokens
+#
+# Tokens are divided by spaces.  If the tokens include spaces, they
+# have to be quoted with single or double quotes.  Double quotes
+# inside a double quoted token must be escaped.  Escaping is done
+# with backslash.
+# Basically, the same quoting rules apply for " and ' as in any
+# Unix shell.
+sub tokenize {
+    my $line = my $debug_line = shift;
+    my @result = ();
+
+    while ($line =~ s|^\s+||, $line ne "") {
+        my $token = "";
+        while ($line ne "" && $line !~ m|^\s|) {
+            if ($line =~ m/^"((?:[^"\\]+|\\.)*)"/) {
+                $token .= $1;
+                $line = $';
+            } elsif ($line =~ m/^'([^']*)'/) {
+                $token .= $1;
+                $line = $';
+            } elsif ($line =~ m/^(\S+)/) {
+                $token .= $1;
+                $line = $';
+            }
+        }
+        push @result, $token;
+    }
+
+    if ($ENV{CONFIGURE_DEBUG_TOKENIZE}) {
+       print STDERR "DEBUG[tokenize]: Parsed '$debug_line' into:\n";
+       print STDERR "DEBUG[tokenize]: ('", join("', '", @result), "')\n";
+    }
+    return @result;
+}