Given the need for an audit of macro ordering in libtool, I decided
I needed all the help and information I could get.

So first, I went through the fun of
  sh -u configure
adding environment variables until I hit bugs.

I also wrote a hacky script to find uninitialized uses by unleashing
weird sed scripts upon `configure' -- attached.  Both target almost the
same thing, with the difference being that the former only analyzes the
actual code path taken, whereas the latter is a pretty bad heuristic but
covers all code without actually knowing anything about logic, and being
blissfully ignorant to shell functions and other nonlinear execution
order.  IOW, the script is primarily useful for autoconf output.

These two tools complement each other, erm, have both uncovered issues..

Cheers,
Ralf
#! /bin/sh
# use-before-set - find some uses of shell vars before setting them

# Copyright (C) 2005
# Ralf Wildenhues <[EMAIL PROTECTED]>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.

# This script assumes GNU sed, and mostly POSIX shell.

# TODO: parse multiple assignments per line
# TODO: parse multiple for loops per line (or don't)
# TODO: parse ${foo:=bar} (not portable, so no issue in configure scripts)
#
# NOTE: This script does not understand 'eval', nor does it follow
#       "interesting" quotation or escaping mechanisms.
# NOTE: This script has no idea of shell functions or any other
#       nonlinear execution paths.  Use `sh -u'.


# Set this to '#' if you want the second sed script
# to see single-quoted content.  (You do, trust me.)
skip_single_quoted='#'

# Ignore these variables, they are user-provided.
# Note: separate with spaces, no newlines in here!
skip_vars="SHELL CPPFLAGS LDFLAGS"

# These variables are user-provided; it's ok to use them
# provided the first use looks like the Autoconf-precious-vars test.
# Note: separate with spaces, no newlines in here!
precious_vars="\
CC CPP CFLAGS CXX CXXCPP CXXFLAGS CXXCPPFLAGS LD LDCXX LIBS \
F77 FFLAGS FC FCFLAGS GCJ GCJFLAGS RC \
AWK EGREP GREP INSTALL MAKE \
AR AS DLLTOOL NM OBJDUMP RANLIB STRIP"


### should not need to modify anything below this line ###

# fail on first error
set -e
set -u

# we rely on ASCII sorting; and please: make it fast
LC_ALL=C
export LC_ALL

if test $# -lt 1
then
  echo >&2 "usage: $0 script-to-check"
  exit 1
fi

last_param=
# Find all probable assignments,
# pair them up with corresponding line numbers.
# sort the resulting list by parameter name, then line
# (in order to pick only the first one later).
sed -n < "$1" '
# skip comments
/^[     ]*#/b next
# parse "foo=bar"
/[a-zA-Z_][a-zA-Z_0-9]*=/ {
        s/.*[^a-zA-Z_]\([a-zA-Z_][a-zA-Z_0-9]*\)=.*/\1/
        s/^\([a-zA-Z_][a-zA-Z_0-9]*\)=.*/\1/
        p;=
}
# parse for loop variable assignment
/\<for[         ][      ]*[a-zA-Z_][a-zA-Z_0-9]*\([     ][      ]*in\|$\)/ {
        s/.*for[        ][      ]*\([a-zA-Z_][a-zA-Z_0-9]*\).*/\1/
        p;=
}
# parse read variable assignments
/\<read[        ][      ]*[a-zA-Z_]/ {
        s/.*read[       ][      ]*\([a-zA-Z_]\)/\1/
        T
        :read
        h
        s/\([a-zA-Z_][a-zA-Z_0-9]*\).*/\1/
        p
        =
        T
        x
        s/[a-zA-Z_][a-zA-Z_0-9]*[       ][      ]*//
        t read
}
:next
' |
sed 'N;s/\n/ /' |
sort -s -k1,1 -k2,2n |
while read param line
do
  if test "$param" = "$last_param"; then continue; fi
  last_param=$param
  case " $skip_vars " in (*" $param "*) continue;; esac
  case " $precious_vars " in
    (*" $param "*) skip_precious= ;;
    (*)            skip_precious='#' ;;
  esac
  prevline=`expr $line - 1`

  # Now, find any probable use of the variable before the assignment.
  sed -n < "$1" "
# end at the line before the assignment
${prevline} q
# skip comments
/^[     ]*#/ b
# if desired, skip single quoted areas
${skip_single_quoted} s/'[^']*'//g
# find parameter expansion
/\(\\\$$param\>\)\|\(\\\${#\{0,1\}$param[#%+-:}]\)/ {
        # for precious variables: end searching without error,
        # when the specific autoconf snippet is found
        ${skip_precious} /\<if test -[nz] \"\\\$$param\"; then/ q
        # autoconf cache variable test idiom:
        /\\\${$param+set}/ b
        # ok, we have a possible bug.
        i\
ERROR: $param used before set at line
        =
        p
}
" | sed 'N;N;s/\n/ /'

done
# vi:set sw=2:

Reply via email to