summaryrefslogtreecommitdiff
path: root/usr/src
diff options
context:
space:
mode:
authorJohn Levon <john.levon@joyent.com>2019-07-24 13:20:02 -0700
committerJohn Levon <john.levon@joyent.com>2019-08-12 08:25:47 -0700
commitefe51d0cc2398b9ac179568b63a44e4bf295b8e2 (patch)
tree7cfc305912bf3c9efe1a234885b96678a89af2a5 /usr/src
parentcc7e66e6be0e280179bd43f44f08e442d9839a8f (diff)
downloadillumos-joyent-efe51d0cc2398b9ac179568b63a44e4bf295b8e2.tar.gz
11506 smatch resync
Reviewed by: Yuri Pankov <yuri.pankov@nexenta.com> Reviewed by: Toomas Soome <tsoome@me.com> Approved by: Robert Mustacchi <rm@joyent.com>
Diffstat (limited to 'usr/src')
-rw-r--r--usr/src/Makefile.smatch2
-rw-r--r--usr/src/boot/lib/libstand/Makefile.inc4
-rw-r--r--usr/src/boot/sys/boot/Makefile.inc7
-rw-r--r--usr/src/boot/sys/boot/efi/libefi/i386/Makefile4
-rw-r--r--usr/src/boot/sys/boot/libstand/Makefile.com10
-rw-r--r--usr/src/cmd/ls/Makefile.com10
-rw-r--r--usr/src/cmd/sgs/libld/Makefile.com6
-rw-r--r--usr/src/cmd/svc/configd/Makefile11
-rw-r--r--usr/src/cmd/syseventd/modules/sysevent_conf_mod/Makefile7
-rw-r--r--usr/src/common/ficl/vm.c8
-rw-r--r--usr/src/lib/libpctx/Makefile.com17
-rw-r--r--usr/src/lib/libumem/Makefile.com16
-rw-r--r--usr/src/tools/smatch/Makefile8
-rw-r--r--usr/src/tools/smatch/src/Documentation/sparse-README.txt2
-rw-r--r--usr/src/tools/smatch/src/Makefile4
-rw-r--r--usr/src/tools/smatch/src/check_64bit_shift.c32
-rw-r--r--usr/src/tools/smatch/src/check_buffer_too_small_for_struct.c15
-rw-r--r--usr/src/tools/smatch/src/check_cmn_err.c52
-rw-r--r--usr/src/tools/smatch/src/check_debug.c46
-rw-r--r--usr/src/tools/smatch/src/check_debug.h2
-rw-r--r--usr/src/tools/smatch/src/check_dma_mapping_error.c6
-rw-r--r--usr/src/tools/smatch/src/check_err_ptr_deref.c2
-rw-r--r--usr/src/tools/smatch/src/check_free_strict.c33
-rw-r--r--usr/src/tools/smatch/src/check_held_dev.c2
-rw-r--r--usr/src/tools/smatch/src/check_kernel.c72
-rw-r--r--usr/src/tools/smatch/src/check_kernel_printf.c12
-rw-r--r--usr/src/tools/smatch/src/check_list.h7
-rw-r--r--usr/src/tools/smatch/src/check_locking.c97
-rw-r--r--usr/src/tools/smatch/src/check_macro_side_effects.c6
-rw-r--r--usr/src/tools/smatch/src/check_missing_break.c1
-rw-r--r--usr/src/tools/smatch/src/check_no_return.c3
-rw-r--r--usr/src/tools/smatch/src/check_nospec.c16
-rw-r--r--usr/src/tools/smatch/src/check_off_by_one_relative.c29
-rw-r--r--usr/src/tools/smatch/src/check_precedence.c11
-rw-r--r--usr/src/tools/smatch/src/check_return_cast.c3
-rw-r--r--usr/src/tools/smatch/src/check_rosenberg.c1
-rw-r--r--usr/src/tools/smatch/src/check_shift_to_zero.c2
-rw-r--r--usr/src/tools/smatch/src/check_snprintf.c1
-rw-r--r--usr/src/tools/smatch/src/check_spectre.c8
-rw-r--r--usr/src/tools/smatch/src/check_spectre_second_half.c125
-rw-r--r--usr/src/tools/smatch/src/check_string_len.c39
-rw-r--r--usr/src/tools/smatch/src/check_syscall_arg_type.c1
-rw-r--r--usr/src/tools/smatch/src/check_testing_index_after_use.c38
-rw-r--r--usr/src/tools/smatch/src/check_uninitialized.c42
-rw-r--r--usr/src/tools/smatch/src/check_unwind.c9
-rw-r--r--usr/src/tools/smatch/src/check_wine_WtoA.c2
-rw-r--r--usr/src/tools/smatch/src/check_zero_to_err_ptr.c57
-rw-r--r--usr/src/tools/smatch/src/evaluate.c2
-rw-r--r--usr/src/tools/smatch/src/expression.h1
-rw-r--r--usr/src/tools/smatch/src/graph.c2
-rw-r--r--usr/src/tools/smatch/src/smatch.c11
-rw-r--r--usr/src/tools/smatch/src/smatch.h134
-rw-r--r--usr/src/tools/smatch/src/smatch_about_fn_ptr_arg.c2
-rw-r--r--usr/src/tools/smatch/src/smatch_address.c153
-rw-r--r--usr/src/tools/smatch/src/smatch_array_values.c5
-rw-r--r--usr/src/tools/smatch/src/smatch_assigned_expr.c14
-rw-r--r--usr/src/tools/smatch/src/smatch_bits.c450
-rw-r--r--usr/src/tools/smatch/src/smatch_buf_comparison.c354
-rw-r--r--usr/src/tools/smatch/src/smatch_buf_size.c31
-rw-r--r--usr/src/tools/smatch/src/smatch_capped.c54
-rw-r--r--usr/src/tools/smatch/src/smatch_comparison.c84
-rw-r--r--usr/src/tools/smatch/src/smatch_conditions.c2
-rw-r--r--usr/src/tools/smatch/src/smatch_constraints.c22
-rw-r--r--usr/src/tools/smatch/src/smatch_constraints_required.c6
-rw-r--r--usr/src/tools/smatch/src/smatch_container_of.c313
-rwxr-xr-xusr/src/tools/smatch/src/smatch_data/db/apply_return_fixes.sh20
-rwxr-xr-xusr/src/tools/smatch/src/smatch_data/db/create_db.sh7
-rwxr-xr-xusr/src/tools/smatch/src/smatch_data/db/delete_too_common_fn_ptr.sh14
-rwxr-xr-xusr/src/tools/smatch/src/smatch_data/db/fixup_kernel.sh80
-rw-r--r--usr/src/tools/smatch/src/smatch_data/db/function_ptr.schema10
-rwxr-xr-xusr/src/tools/smatch/src/smatch_data/db/init_constraints.pl4
-rwxr-xr-xusr/src/tools/smatch/src/smatch_data/db/init_constraints_required.pl4
-rw-r--r--usr/src/tools/smatch/src/smatch_data/db/kernel.return_fixes27
-rwxr-xr-xusr/src/tools/smatch/src/smatch_data/db/smdb.py33
-rwxr-xr-xusr/src/tools/smatch/src/smatch_data/db/vim_smdb2
-rw-r--r--usr/src/tools/smatch/src/smatch_data/illumos_kernel.skipped_functions5
-rw-r--r--usr/src/tools/smatch/src/smatch_data/illumos_user.skipped_functions4
-rw-r--r--usr/src/tools/smatch/src/smatch_data/kernel.allocation_funcs_gfp.remove1
-rw-r--r--usr/src/tools/smatch/src/smatch_data/kernel.ignore_casted_params15
-rw-r--r--usr/src/tools/smatch/src/smatch_data/kernel.ignore_side_effects4
-rw-r--r--usr/src/tools/smatch/src/smatch_data/kernel.ignore_uninitialized_param7
-rw-r--r--usr/src/tools/smatch/src/smatch_data/kernel.ignored_warnings1
-rw-r--r--usr/src/tools/smatch/src/smatch_data/kernel.no_inline_functions2
-rw-r--r--usr/src/tools/smatch/src/smatch_data/kernel.no_return_funcs.add2
-rw-r--r--usr/src/tools/smatch/src/smatch_data/kernel.silenced_functions1
-rw-r--r--usr/src/tools/smatch/src/smatch_data_source.c10
-rw-r--r--usr/src/tools/smatch/src/smatch_db.c376
-rw-r--r--usr/src/tools/smatch/src/smatch_equiv.c44
-rw-r--r--usr/src/tools/smatch/src/smatch_estate.c66
-rw-r--r--usr/src/tools/smatch/src/smatch_expressions.c9
-rw-r--r--usr/src/tools/smatch/src/smatch_extra.c651
-rw-r--r--usr/src/tools/smatch/src/smatch_extra.h11
-rw-r--r--usr/src/tools/smatch/src/smatch_flow.c36
-rw-r--r--usr/src/tools/smatch/src/smatch_function_hooks.c104
-rw-r--r--usr/src/tools/smatch/src/smatch_function_ptrs.c56
-rw-r--r--usr/src/tools/smatch/src/smatch_helper.c98
-rw-r--r--usr/src/tools/smatch/src/smatch_ignore.c46
-rw-r--r--usr/src/tools/smatch/src/smatch_imaginary_absolute.c3
-rw-r--r--usr/src/tools/smatch/src/smatch_implied.c217
-rw-r--r--usr/src/tools/smatch/src/smatch_integer_overflow.c292
-rw-r--r--usr/src/tools/smatch/src/smatch_kernel_user_data.c663
-rw-r--r--usr/src/tools/smatch/src/smatch_links.c1
-rw-r--r--usr/src/tools/smatch/src/smatch_local_values.c1
-rw-r--r--usr/src/tools/smatch/src/smatch_math.c1219
-rw-r--r--usr/src/tools/smatch/src/smatch_mem_tracker.c18
-rw-r--r--usr/src/tools/smatch/src/smatch_modification_hooks.c9
-rw-r--r--usr/src/tools/smatch/src/smatch_mtag.c465
-rw-r--r--usr/src/tools/smatch/src/smatch_mtag_data.c62
-rw-r--r--usr/src/tools/smatch/src/smatch_mtag_map.c20
-rw-r--r--usr/src/tools/smatch/src/smatch_nul_terminator.c34
-rw-r--r--usr/src/tools/smatch/src/smatch_param_compare_limit.c9
-rw-r--r--usr/src/tools/smatch/src/smatch_param_filter.c6
-rw-r--r--usr/src/tools/smatch/src/smatch_param_limit.c4
-rw-r--r--usr/src/tools/smatch/src/smatch_param_set.c11
-rw-r--r--usr/src/tools/smatch/src/smatch_param_to_mtag_data.c41
-rw-r--r--usr/src/tools/smatch/src/smatch_param_used.c9
-rw-r--r--usr/src/tools/smatch/src/smatch_parse_call_math.c36
-rw-r--r--usr/src/tools/smatch/src/smatch_passes_array_size.c18
-rw-r--r--usr/src/tools/smatch/src/smatch_ranges.c548
-rw-r--r--usr/src/tools/smatch/src/smatch_real_absolute.c4
-rw-r--r--usr/src/tools/smatch/src/smatch_return_to_param.c69
-rw-r--r--usr/src/tools/smatch/src/smatch_returns.c1
-rwxr-xr-xusr/src/tools/smatch/src/smatch_scripts/build_kernel_data.sh4
-rwxr-xr-xusr/src/tools/smatch/src/smatch_scripts/kpatch.sh36
-rwxr-xr-xusr/src/tools/smatch/src/smatch_scripts/test_kernel.sh10
-rw-r--r--usr/src/tools/smatch/src/smatch_slist.c188
-rw-r--r--usr/src/tools/smatch/src/smatch_slist.h1
-rw-r--r--usr/src/tools/smatch/src/smatch_statement_count.c1
-rw-r--r--usr/src/tools/smatch/src/smatch_states.c15
-rw-r--r--usr/src/tools/smatch/src/smatch_stored_conditions.c3
-rw-r--r--usr/src/tools/smatch/src/smatch_string_list.c19
-rw-r--r--usr/src/tools/smatch/src/smatch_strlen.c3
-rw-r--r--usr/src/tools/smatch/src/smatch_struct_assignment.c20
-rw-r--r--usr/src/tools/smatch/src/smatch_sval.c49
-rw-r--r--usr/src/tools/smatch/src/smatch_type.c61
-rw-r--r--usr/src/tools/smatch/src/smatch_type_val.c3
-rw-r--r--usr/src/tools/smatch/src/smatch_untracked_param.c91
-rw-r--r--usr/src/tools/smatch/src/validation/sm_bitwise1.c2
-rw-r--r--usr/src/tools/smatch/src/validation/sm_equiv1.c8
-rw-r--r--usr/src/tools/smatch/src/validation/sm_implied.c1
-rw-r--r--usr/src/tools/smatch/src/validation/sm_implied10.c8
-rw-r--r--usr/src/tools/smatch/src/validation/sm_implied11.c2
-rw-r--r--usr/src/tools/smatch/src/validation/sm_implied12.c2
-rw-r--r--usr/src/tools/smatch/src/validation/sm_implied2.c1
-rw-r--r--usr/src/tools/smatch/src/validation/sm_implied5.c1
-rw-r--r--usr/src/tools/smatch/src/validation/sm_memory.c1
-rw-r--r--usr/src/tools/smatch/src/validation/sm_null_deref.c1
-rw-r--r--usr/src/tools/smatch/src/validation/sm_select5.c2
-rw-r--r--usr/src/uts/i86pc/unix/Makefile5
-rw-r--r--usr/src/uts/intel/emlxs/Makefile24
-rw-r--r--usr/src/uts/intel/genunix/Makefile44
-rw-r--r--usr/src/uts/intel/mega_sas/Makefile21
-rw-r--r--usr/src/uts/intel/simnet/Makefile14
-rw-r--r--usr/src/uts/intel/spppcomp/Makefile29
-rw-r--r--usr/src/uts/intel/xge/Makefile31
155 files changed, 5977 insertions, 2762 deletions
diff --git a/usr/src/Makefile.smatch b/usr/src/Makefile.smatch
index 27f302cb47..4f20c0497b 100644
--- a/usr/src/Makefile.smatch
+++ b/usr/src/Makefile.smatch
@@ -28,7 +28,7 @@ SMATCH_ARGS += -Wno-external-function-has-definition
SMATCH_ARGS += -Wno-old-style-definition
SMATCH_ARGS += -Wno-strict-prototypes
SMATCH_ARGS += --fatal-checks
-SMATCH_ARGS += --timeout=120
+SMATCH_ARGS += --timeout=0
CERRWARN += $(SMATCH_ARGS:%=-_smatch=%)
diff --git a/usr/src/boot/lib/libstand/Makefile.inc b/usr/src/boot/lib/libstand/Makefile.inc
index de07d9a0e9..6c46fdeefd 100644
--- a/usr/src/boot/lib/libstand/Makefile.inc
+++ b/usr/src/boot/lib/libstand/Makefile.inc
@@ -11,6 +11,7 @@
#
# Copyright 2016 Toomas Soome <tsoome@me.com>
+# Copyright 2019 Joyent, Inc.
#
#
@@ -85,6 +86,9 @@ _bzlib.o _crctable.o _decompress.o _huffman.o _randtable.o bzipfs.o \
:= CFLAGS += -DBZ_LOADER -DBZ_NO_STDIO -DBZ_NO_COMPRESS
SRCS += libstand_bzlib_private.h
+# too hairy
+_inflate.o := SMATCH=off
+
SRCS += _bzlib.c _crctable.c _decompress.c _huffman.c _randtable.c
OBJS += _bzlib.o _crctable.o _decompress.o _huffman.o _randtable.o
CLEANFILES += _bzlib.c _crctable.c _decompress.c _huffman.c _randtable.c
diff --git a/usr/src/boot/sys/boot/Makefile.inc b/usr/src/boot/sys/boot/Makefile.inc
index 777aa87b32..6b13275062 100644
--- a/usr/src/boot/sys/boot/Makefile.inc
+++ b/usr/src/boot/sys/boot/Makefile.inc
@@ -11,6 +11,7 @@
#
# Copyright 2017 Toomas Soome <tsoome@me.com>
+# Copyright 2019 Joyent, Inc.
#
# loader.help build needs better awk
@@ -52,6 +53,10 @@ CFLAGS += $(CCNOAUTOINLINE) $(CCNOREORDER) $(CSTD_GNU99)
CCASFLAGS= -fPIC -Wa,--divide
ASFLAGS= --divide
+SMATCH_ =
+SMATCH_on =
+SMATCH_off = -_smatch=off
+
# smatch does not define __amd64 and __amd64__
SMATCH_amd64= -_smatch=-D__amd64 -_smatch=-D__amd64__
@@ -59,6 +64,8 @@ SMATCH_amd64= -_smatch=-D__amd64 -_smatch=-D__amd64__
#CFLAGS += $(SMATCH_ARGS:%=-_smatch=%)
CFLAGS += $(SMOFF:%=-_smatch=--disable=%)
CFLAGS += $(SMATCH_$(MACHINE))
+CFLAGS += $(SMATCH_$(SMATCH))
+CFLAGS += -_smatch=--timeout=0
COMPILE.S= $(CC) $(SMATCH_off) $(CCASFLAGS) $(CPPFLAGS) -c
diff --git a/usr/src/boot/sys/boot/efi/libefi/i386/Makefile b/usr/src/boot/sys/boot/efi/libefi/i386/Makefile
index 3d1c95feed..cc749255bd 100644
--- a/usr/src/boot/sys/boot/efi/libefi/i386/Makefile
+++ b/usr/src/boot/sys/boot/efi/libefi/i386/Makefile
@@ -12,6 +12,7 @@
#
# Copyright 2016 Toomas Soome <tsoome@me.com>
# Copyright 2016 RackTop Systems.
+# Copyright 2019 Joyent, Inc.
#
MACHINE= $(MACH)
@@ -23,6 +24,9 @@ include ../Makefile.com
CFLAGS += -m32
+# false positive only with a 64-bit smatch
+SMOFF += uninitialized
+
CLEANFILES += machine x86
$(OBJS): machine x86
diff --git a/usr/src/boot/sys/boot/libstand/Makefile.com b/usr/src/boot/sys/boot/libstand/Makefile.com
index 135944335c..07598ccf90 100644
--- a/usr/src/boot/sys/boot/libstand/Makefile.com
+++ b/usr/src/boot/sys/boot/libstand/Makefile.com
@@ -11,6 +11,7 @@
#
# Copyright 2016 Toomas Soome <tsoome@me.com>
+# Copyright 2019 Joyent, Inc.
#
include $(SRC)/Makefile.master
@@ -27,6 +28,15 @@ include $(ZFSSRC)/Makefile.inc
CPPFLAGS += -I$(SRC)/uts/common
+# needs work
+printf.o := SMOFF += 64bit_shift
+
+# too hairy
+_inflate.o := SMATCH=off
+
+# 64-bit smatch false positive :/
+SMOFF += uninitialized
+
clean: clobber
clobber:
$(RM) $(CLEANFILES) $(OBJS) machine $(LIBRARY)
diff --git a/usr/src/cmd/ls/Makefile.com b/usr/src/cmd/ls/Makefile.com
index cc3ca0ad81..c31f661cf3 100644
--- a/usr/src/cmd/ls/Makefile.com
+++ b/usr/src/cmd/ls/Makefile.com
@@ -22,7 +22,7 @@
# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# cmd/ls/Makefile.com
+# Copyright 2019 Joyent, Inc.
#
PROG= ls
@@ -43,14 +43,14 @@ $(XPG6) := CFLAGS64 += -DXPG4 -DXPG6
CFLAGS64 += $(CCVERBOSE)
CPPFLAGS += -D_FILE_OFFSET_BITS=64
-LINTFLAGS64 += -errchk=longptr64
+
+# main() can be too hairy
+SMATCH=off
.KEEP_STATE:
all: $(PROG) $(XPG4) $(XPG6)
-lint: lint_SRCS
-
clean:
$(RM) $(CLEANFILES)
@@ -61,7 +61,7 @@ include ../../Makefile.targ
$(POST_PROCESS)
%.xpg6: ../%.c
- $(LINK.c) -o $@ $< $(LDLIBS)
+ $(LINK.c) -o $@ $< $(LDLIBS)
$(POST_PROCESS)
%: ../%.c
diff --git a/usr/src/cmd/sgs/libld/Makefile.com b/usr/src/cmd/sgs/libld/Makefile.com
index 2119ecec29..b007c46bad 100644
--- a/usr/src/cmd/sgs/libld/Makefile.com
+++ b/usr/src/cmd/sgs/libld/Makefile.com
@@ -23,7 +23,7 @@
# Copyright 2010 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# Copyright (c) 2018, Joyent, Inc.
+# Copyright 2019 Joyent, Inc.
# Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
LIBRARY = libld.a
@@ -113,6 +113,10 @@ DYNFLAGS += $(VERSREF) $(CC_USE_PROTO) '-R$$ORIGIN'
native:= DYNFLAGS += $(CONVLIBDIR)
+# too hairy
+pics/sections32.o := SMATCH=off
+pics/sections64.o := SMATCH=off
+
BLTDEFS = msg.h
BLTDATA = msg.c
BLTMESG = $(SGSMSGDIR)/libld
diff --git a/usr/src/cmd/svc/configd/Makefile b/usr/src/cmd/svc/configd/Makefile
index 9617a53f79..419ca6248b 100644
--- a/usr/src/cmd/svc/configd/Makefile
+++ b/usr/src/cmd/svc/configd/Makefile
@@ -24,6 +24,8 @@
#
# Copyright 2015 RackTop Systems.
#
+# Copyright 2019 Joyent, Inc.
+#
MYPROG = svc.configd
MYOBJS = \
@@ -60,9 +62,12 @@ CERRWARN += -_gcc=-Wno-unused-label
CERRWARN += -_gcc=-Wno-unused-variable
CERRWARN += -_gcc=-Wno-unused-function
CERRWARN += -_gcc=-Wno-uninitialized
+
+# strange false positive
+SMOFF += free
+
MYLDLIBS = -lumem -luutil
LDLIBS += -lsecdb -lbsm $(MYLDLIBS)
-LINTFLAGS += -errtags -erroff=E_BAD_FORMAT_ARG_TYPE2 -erroff=E_NAME_DEF_NOT_USED2
CLOBBERFILES += $(MYPROG:%=%-native)
@@ -125,10 +130,6 @@ clean: FRC
clobber:
-lint: lint_SRCS
-
-lint_SRCS:
-
include ../../Makefile.targ
FRC:
diff --git a/usr/src/cmd/syseventd/modules/sysevent_conf_mod/Makefile b/usr/src/cmd/syseventd/modules/sysevent_conf_mod/Makefile
index 377c91df68..94cba19b73 100644
--- a/usr/src/cmd/syseventd/modules/sysevent_conf_mod/Makefile
+++ b/usr/src/cmd/syseventd/modules/sysevent_conf_mod/Makefile
@@ -22,6 +22,8 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
+# Copyright 2019 Joyent, Inc.
+#
LIBRARY = sysevent_conf_mod
@@ -32,11 +34,14 @@ CPPFLAGS += -I ../../daemons/syseventconfd
CERRWARN += -_gcc=-Wno-uninitialized
+# strange smatch false positive
+SMOFF += allocating_enough_data
+
.KEEP_STATE:
all: $(DYNLIB)
-install: all \
+install: all \
$(ROOTLIBSYSEVENTDIR) \
$(ROOTLIBDIR) \
$(ROOTLIBS)
diff --git a/usr/src/common/ficl/vm.c b/usr/src/common/ficl/vm.c
index e6db0e3a73..dc3f40202f 100644
--- a/usr/src/common/ficl/vm.c
+++ b/usr/src/common/ficl/vm.c
@@ -47,6 +47,10 @@
* SUCH DAMAGE.
*/
+/*
+ * Copyright 2019 Joyent, Inc.
+ */
+
#include "ficl.h"
#if FICL_ROBUST >= 2
@@ -2165,8 +2169,8 @@ ficlVmGetWordToPad(ficlVm *vm)
char *pad = (char *)vm->pad;
s = ficlVmGetWord(vm);
- if (FICL_STRING_GET_LENGTH(s) > FICL_PAD_SIZE)
- FICL_STRING_SET_LENGTH(s, FICL_PAD_SIZE);
+ if (FICL_STRING_GET_LENGTH(s) >= FICL_PAD_SIZE)
+ FICL_STRING_SET_LENGTH(s, FICL_PAD_SIZE - 1);
(void) strncpy(pad, FICL_STRING_GET_POINTER(s),
FICL_STRING_GET_LENGTH(s));
diff --git a/usr/src/lib/libpctx/Makefile.com b/usr/src/lib/libpctx/Makefile.com
index c9d50e434c..1cd8757729 100644
--- a/usr/src/lib/libpctx/Makefile.com
+++ b/usr/src/lib/libpctx/Makefile.com
@@ -22,7 +22,7 @@
# Copyright 2006 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# ident "%Z%%M% %I% %E% SMI"
+# Copyright 2019 Joyent, Inc.
#
LIBRARY = libpctx.a
@@ -33,25 +33,20 @@ OBJECTS = libpctx.o
# include library definitions
include ../../Makefile.lib
-LIBS = $(DYNLIB) $(LINTLIB)
-$(LINTLIB) := SRCS = ../common/llib-lpctx
+LIBS = $(DYNLIB)
LDLIBS += -lproc -lc
SRCDIR = ../common
CFLAGS += $(CCVERBOSE)
-CPPFLAGS += -D_REENTRANT -I$(SRCDIR)
+CPPFLAGS += -D_REENTRANT -I$(SRCDIR)
+
+# false positive: pctx_run() error: dereferencing freed memory 'pctx'
+SMOFF += free
.KEEP_STATE:
all: $(LIBS)
-# x86 and sparc have different alignment complaints (all LINTED).
-# Make lint shut up about suppression directive not used.
-lint := LINTFLAGS += -erroff=E_SUPPRESSION_DIRECTIVE_UNUSED
-lint := LINTFLAGS64 += -erroff=E_SUPPRESSION_DIRECTIVE_UNUSED
-
-lint: lintcheck
-
# include library targets
include ../../Makefile.targ
diff --git a/usr/src/lib/libumem/Makefile.com b/usr/src/lib/libumem/Makefile.com
index 70bbb164a7..504a8beb38 100644
--- a/usr/src/lib/libumem/Makefile.com
+++ b/usr/src/lib/libumem/Makefile.com
@@ -22,7 +22,7 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# Copyright (c) 2019, Joyent, Inc.
+# Copyright 2019 Joyent, Inc.
#
#
@@ -112,7 +112,7 @@ CLOBBERFILES_standalone = $(LINKTEST_OBJ)
CLOBBERFILES += $(CLOBBERFILES_$(CURTYPE))
LIBS_standalone = $(STANDLIBRARY)
-LIBS_library = $(DYNLIB) $(LINTLIB)
+LIBS_library = $(DYNLIB)
LIBS = $(LIBS_$(CURTYPE))
MAPFILE_SUPPLEMENTAL_standalone = ../common/stand_mapfile
@@ -128,8 +128,6 @@ ASFLAGS_standalone = -DUMEM_STANDALONE
ASFLAGS_library =
ASFLAGS += -P $(ASFLAGS_$(CURTYPE)) -D_ASM
-$(LINTLIB) := SRCS = ../common/$(LINTSRC)
-
# We want the thread-specific errno in the library, but we don't want it in
# the standalone. $(DTS_ERRNO) is designed to add -D_TS_ERRNO to $(CPPFLAGS),
# in order to enable this feature. Conveniently, -D_REENTRANT does the same
@@ -157,13 +155,11 @@ CFLAGS += $(CFLAGS_$(CURTYPE)) $(CFLAGS_common)
CFLAGS64_standalone = $(STAND_FLAGS_64)
CFLAGS64 += $(CCVERBOSE) $(CFLAGS64_$(CURTYPE)) $(CFLAGS64_common)
-INSTALL_DEPS_library = $(ROOTLINKS) $(ROOTLINT) $(ROOTLIBS)
+# false positive for umem_alloc_sizes_add()
+pics/umem.o := SMOFF += index_overflow
+objs/umem.o := SMOFF += index_overflow
-#
-# turn off ptr-cast warnings, since we do them all the time
-#
-LINTFLAGS += -erroff=E_BAD_PTR_CAST_ALIGN
-LINTFLAGS64 += -erroff=E_BAD_PTR_CAST_ALIGN
+INSTALL_DEPS_library = $(ROOTLINKS) $(ROOTLIBS)
DYNFLAGS += $(ZINTERPOSE)
diff --git a/usr/src/tools/smatch/Makefile b/usr/src/tools/smatch/Makefile
index 075cb12458..4079d9542e 100644
--- a/usr/src/tools/smatch/Makefile
+++ b/usr/src/tools/smatch/Makefile
@@ -13,14 +13,14 @@
#
# The src/ sub-directory is un-modified copy of
-# https://github.com/illumos/smatch/tree/0.5.1-il-3
+# https://github.com/illumos/smatch/tree/0.5.1-il-4
#
# This Makefile installs just enough for us to be able to run smatch
# locally.
#
PROG = smatch
-SPARSE_VERSION = 0.5.1-il-3
+SPARSE_VERSION = 0.5.1-il-4
include ../Makefile.tools
@@ -28,7 +28,7 @@ include ../Makefile.tools
i386_CC = $(GNUC_ROOT)/bin/gcc
sparc_CC = $(GNUC_ROOT)/bin/gcc
-CFLAGS = -O -D__sun -Wall -Wno-unknown-pragmas -std=gnu99 -nodefaultlibs
+CFLAGS = -O -m64 -msave-args -D__sun -Wall -Wno-unknown-pragmas -std=gnu99 -nodefaultlibs
SMATCHDATADIR = $(ROOTONBLDSHARE)/smatch
@@ -77,7 +77,7 @@ OBJS += smatch_flow.o smatch_conditions.o smatch_slist.o smatch_states.o \
smatch_mtag_map.o smatch_mtag_data.o \
smatch_param_to_mtag_data.o smatch_mem_tracker.o smatch_array_values.o \
smatch_nul_terminator.o smatch_assigned_expr.o smatch_kernel_user_data.o \
- smatch_statement_count.o
+ smatch_statement_count.o smatch_bits.o smatch_integer_overflow.o
OBJS += target.o parse.o tokenize.o pre-process.o symbol.o lib.o scope.o \
expression.o show-parse.o evaluate.o expand.o inline.o linearize.o \
diff --git a/usr/src/tools/smatch/src/Documentation/sparse-README.txt b/usr/src/tools/smatch/src/Documentation/sparse-README.txt
index 144d27459d..033ae15d5d 100644
--- a/usr/src/tools/smatch/src/Documentation/sparse-README.txt
+++ b/usr/src/tools/smatch/src/Documentation/sparse-README.txt
@@ -1,5 +1,5 @@
- sparse (spärs), adj,., spars-er, spars-est.
+ sparse (spärs), adj,., spars-er, spars-est.
1. thinly scattered or distributed; "a sparse population"
2. thin; not thick or dense: "sparse hair"
3. scanty; meager.
diff --git a/usr/src/tools/smatch/src/Makefile b/usr/src/tools/smatch/src/Makefile
index d77fd2b2da..c1423afbbf 100644
--- a/usr/src/tools/smatch/src/Makefile
+++ b/usr/src/tools/smatch/src/Makefile
@@ -1,4 +1,4 @@
-VERSION=0.5.1
+VERSION=0.5.1-il-4
# Generating file version.h if current version has changed
SPARSE_VERSION:=$(shell git describe 2>/dev/null || echo '$(VERSION)')
@@ -90,7 +90,7 @@ SMATCH_FILES=smatch_flow.o smatch_conditions.o smatch_slist.o smatch_states.o \
smatch_mtag_map.o smatch_mtag_data.o \
smatch_param_to_mtag_data.o smatch_mem_tracker.o smatch_array_values.o \
smatch_nul_terminator.o smatch_assigned_expr.o smatch_kernel_user_data.o \
- smatch_statement_count.o
+ smatch_statement_count.o smatch_integer_overflow.o smatch_bits.o
SMATCH_CHECKS=$(shell ls check_*.c | sed -e 's/\.c/.o/')
SMATCH_DATA=smatch_data/kernel.allocation_funcs \
diff --git a/usr/src/tools/smatch/src/check_64bit_shift.c b/usr/src/tools/smatch/src/check_64bit_shift.c
index 89b1c23d3f..66c0bbd2b8 100644
--- a/usr/src/tools/smatch/src/check_64bit_shift.c
+++ b/usr/src/tools/smatch/src/check_64bit_shift.c
@@ -16,9 +16,40 @@
*/
#include "smatch.h"
+#include "smatch_extra.h"
static int my_id;
+static void match_shift_mask(struct expression *expr)
+{
+ struct expression *right, *shifter;
+ struct range_list *rl;
+ char *str;
+
+ expr = strip_expr(expr);
+ if (expr->type != EXPR_BINOP || expr->op != '&')
+ return;
+
+ if (get_type(expr->left) != &ullong_ctype)
+ return;
+
+ if (type_bits(get_type(expr->right)) == 64)
+ return;
+
+ right = strip_expr(expr->right);
+ if (right->type != EXPR_BINOP || right->op != SPECIAL_LEFTSHIFT)
+ return;
+
+ shifter = strip_expr(right->right);
+ get_real_absolute_rl(shifter, &rl);
+ if (rl_max(rl).uvalue < 32)
+ return;
+
+ str = expr_to_str(expr->right);
+ sm_warning("should '%s' be a 64 bit type?", str);
+ free_string(str);
+}
+
static void match_shift_assignment(struct expression *expr)
{
struct symbol *left_type, *right_type;
@@ -63,4 +94,5 @@ void check_64bit_shift(int id)
my_id = id;
add_hook(&match_shift_assignment, ASSIGNMENT_HOOK);
+ add_hook(&match_shift_mask, BINOP_HOOK);
}
diff --git a/usr/src/tools/smatch/src/check_buffer_too_small_for_struct.c b/usr/src/tools/smatch/src/check_buffer_too_small_for_struct.c
index 06b69d89fa..2e470ba7a3 100644
--- a/usr/src/tools/smatch/src/check_buffer_too_small_for_struct.c
+++ b/usr/src/tools/smatch/src/check_buffer_too_small_for_struct.c
@@ -26,6 +26,8 @@ static void match_assign(struct expression *expr)
struct symbol *left_type, *right_type;
struct expression *size_expr;
sval_t min_size;
+ int limit_type;
+ int bytes;
left_type = get_type(expr->left);
if (!left_type || left_type->type != SYM_PTR)
@@ -43,9 +45,15 @@ static void match_assign(struct expression *expr)
if (right_type != &void_ctype && type_bits(right_type) != 8)
return;
- size_expr = get_size_variable(expr->right);
+ bytes = get_array_size_bytes(expr->right);
+ if (bytes >= type_bytes(left_type))
+ return;
+
+ size_expr = get_size_variable(expr->right, &limit_type);
if (!size_expr)
return;
+ if (limit_type != ELEM_COUNT)
+ return;
get_absolute_min(size_expr, &min_size);
if (min_size.value >= type_bytes(left_type))
@@ -62,6 +70,7 @@ static void match_dereferences(struct expression *expr)
char *name;
struct expression *size_expr;
sval_t min_size;
+ int limit_type;
if (expr->type != EXPR_PREOP)
return;
@@ -79,9 +88,11 @@ static void match_dereferences(struct expression *expr)
return;
right = get_assigned_expr(expr);
- size_expr = get_size_variable(right);
+ size_expr = get_size_variable(right, &limit_type);
if (!size_expr)
return;
+ if (limit_type != ELEM_COUNT)
+ return;
get_absolute_min(size_expr, &min_size);
if (min_size.value >= type_bytes(left_type))
diff --git a/usr/src/tools/smatch/src/check_cmn_err.c b/usr/src/tools/smatch/src/check_cmn_err.c
new file mode 100644
index 0000000000..1063efeb47
--- /dev/null
+++ b/usr/src/tools/smatch/src/check_cmn_err.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2016 Oracle.
+ *
+ * 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 program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
+ *
+ * Copyright 2019 Joyent, Inc.
+ */
+
+/*
+ * Heavily borrowed from check_wine.c: what we're doing here is teaching smatch
+ * that cmn_err(CE_PANIC, ...) is noreturn.
+ */
+
+#include "scope.h"
+#include "smatch.h"
+#include "smatch_extra.h"
+
+#define CE_PANIC (3)
+
+void match_cmn_err(const char *fn, struct expression *expr,
+ void *unused)
+{
+ struct expression *arg;
+ sval_t sval;
+
+ arg = get_argument_from_call_expr(expr->args, 0);
+ if (!get_implied_value(arg, &sval))
+ return;
+
+ if (sval.value == CE_PANIC)
+ nullify_path();
+}
+
+
+void check_cmn_err(int id)
+{
+ if (option_project != PROJ_ILLUMOS_KERNEL)
+ return;
+
+ add_function_hook("cmn_err", &match_cmn_err, NULL);
+}
diff --git a/usr/src/tools/smatch/src/check_debug.c b/usr/src/tools/smatch/src/check_debug.c
index 0defd2bfad..155e62535c 100644
--- a/usr/src/tools/smatch/src/check_debug.c
+++ b/usr/src/tools/smatch/src/check_debug.c
@@ -19,6 +19,11 @@
#include "smatch_slist.h"
#include "smatch_extra.h"
+void show_sname_alloc(void);
+void show_data_range_alloc(void);
+void show_ptrlist_alloc(void);
+void show_sm_state_alloc(void);
+
int local_debug;
static int my_id;
char *trace_variable;
@@ -198,7 +203,7 @@ static void match_print_implied_max(const char *fn, struct expression *expr, voi
static void match_user_rl(const char *fn, struct expression *expr, void *info)
{
struct expression *arg;
- struct range_list *rl;
+ struct range_list *rl = NULL;
char *name;
arg = get_argument_from_call_expr(expr->args, 0);
@@ -384,6 +389,7 @@ static void match_buf_size(const char *fn, struct expression *expr, void *info)
int elements, bytes;
char *name;
char buf[256] = "";
+ int limit_type;
int n;
sval_t sval;
@@ -392,7 +398,7 @@ static void match_buf_size(const char *fn, struct expression *expr, void *info)
elements = get_array_size(arg);
bytes = get_array_size_bytes_max(arg);
rl = get_array_size_bytes_rl(arg);
- comp = get_size_variable(arg);
+ comp = get_size_variable(arg, &limit_type);
name = expr_to_str(arg);
n = snprintf(buf, sizeof(buf), "buf size: '%s' %d elements, %d bytes", name, elements, bytes);
@@ -403,7 +409,7 @@ static void match_buf_size(const char *fn, struct expression *expr, void *info)
if (comp) {
name = expr_to_str(comp);
- snprintf(buf + n, sizeof(buf) - n, "[size_var=%s]", name);
+ snprintf(buf + n, sizeof(buf) - n, "[size_var=%s %s]", limit_type_str(limit_type), name);
free_string(name);
}
sm_msg("%s", buf);
@@ -504,16 +510,6 @@ static void match_local_debug_off(const char *fn, struct expression *expr, void
local_debug = 0;
}
-static void match_debug_implied_on(const char *fn, struct expression *expr, void *info)
-{
- option_debug_implied = 1;
-}
-
-static void match_debug_implied_off(const char *fn, struct expression *expr, void *info)
-{
- option_debug_implied = 0;
-}
-
static void match_about(const char *fn, struct expression *expr, void *info)
{
struct expression *arg;
@@ -644,11 +640,12 @@ static void match_mtag(const char *fn, struct expression *expr, void *info)
struct expression *arg;
char *name;
mtag_t tag = 0;
+ int offset = 0;
arg = get_argument_from_call_expr(expr->args, 0);
name = expr_to_str(arg);
- get_mtag(arg, &tag);
- sm_msg("mtag: '%s' => tag: %lld", name, tag);
+ expr_to_mtag_offset(arg, &tag, &offset);
+ sm_msg("mtag: '%s' => tag: %llu %d", name, tag, offset);
free_string(name);
}
@@ -666,6 +663,22 @@ static void match_mtag_data_offset(const char *fn, struct expression *expr, void
free_string(name);
}
+static void match_container(const char *fn, struct expression *expr, void *info)
+{
+ struct expression *container, *x;
+ char *cont, *name, *str;
+
+ container = get_argument_from_call_expr(expr->args, 0);
+ x = get_argument_from_call_expr(expr->args, 1);
+
+ str = get_container_name(container, x);
+ cont = expr_to_str(container);
+ name = expr_to_str(x);
+ sm_msg("container: '%s' vs '%s' --> '%s'", cont, name, str);
+ free_string(cont);
+ free_string(name);
+}
+
static void match_state_count(const char *fn, struct expression *expr, void *info)
{
sm_msg("state_count = %d\n", sm_state_counter);
@@ -754,8 +767,6 @@ void check_debug(int id)
add_function_hook("__smatch_debug_off", &match_debug_off, NULL);
add_function_hook("__smatch_local_debug_on", &match_local_debug_on, NULL);
add_function_hook("__smatch_local_debug_off", &match_local_debug_off, NULL);
- add_function_hook("__smatch_debug_implied_on", &match_debug_implied_on, NULL);
- add_function_hook("__smatch_debug_implied_off", &match_debug_implied_off, NULL);
add_function_hook("__smatch_intersection", &match_intersection, NULL);
add_function_hook("__smatch_type", &match_type, NULL);
add_implied_return_hook("__smatch_type_rl_helper", &match_type_rl_return, NULL);
@@ -766,6 +777,7 @@ void check_debug(int id)
add_function_hook("__smatch_state_count", &match_state_count, NULL);
add_function_hook("__smatch_mem", &match_mem, NULL);
add_function_hook("__smatch_exit", &match_exit, NULL);
+ add_function_hook("__smatch_container", &match_container, NULL);
add_hook(free_old_stree, AFTER_FUNC_HOOK);
add_hook(trace_var, STMT_HOOK_AFTER);
diff --git a/usr/src/tools/smatch/src/check_debug.h b/usr/src/tools/smatch/src/check_debug.h
index 8e6a97f4e4..52a71a619b 100644
--- a/usr/src/tools/smatch/src/check_debug.h
+++ b/usr/src/tools/smatch/src/check_debug.h
@@ -74,4 +74,6 @@ static inline void __smatch_exit(void){}
static inline void __smatch_state_count(void){}
static inline void __smatch_mem(void){}
+
+static inline void __smatch_container(long long container, long long x){}
#endif
diff --git a/usr/src/tools/smatch/src/check_dma_mapping_error.c b/usr/src/tools/smatch/src/check_dma_mapping_error.c
index a786813cd5..10662db373 100644
--- a/usr/src/tools/smatch/src/check_dma_mapping_error.c
+++ b/usr/src/tools/smatch/src/check_dma_mapping_error.c
@@ -32,6 +32,12 @@ static void ok_to_use(struct sm_state *sm, struct expression *mod_expr)
static void match_assign(const char *fn, struct expression *expr, void *unused)
{
+ struct range_list *rl;
+
+ if (!get_implied_rl(expr->right, &rl))
+ return;
+ if (rl_max(rl).value != 1)
+ return;
set_state_expr(my_id, expr->left, &positive);
}
diff --git a/usr/src/tools/smatch/src/check_err_ptr_deref.c b/usr/src/tools/smatch/src/check_err_ptr_deref.c
index 50a79cd3ad..814d6469d3 100644
--- a/usr/src/tools/smatch/src/check_err_ptr_deref.c
+++ b/usr/src/tools/smatch/src/check_err_ptr_deref.c
@@ -222,7 +222,7 @@ void check_err_ptr_deref(int id)
return_implies_state("IS_ERR_OR_NULL", 0, 0, &match_checked, NULL);
return_implies_state("IS_ERR_OR_NULL", 1, 1, &match_err, NULL);
return_implies_state("PTR_RET", 0, 0, &match_checked, NULL);
- return_implies_state("PTR_RET", -4096, -1, &match_err, NULL);
+ return_implies_state("PTR_RET", -4095, -1, &match_err, NULL);
register_err_ptr_funcs();
add_hook(&match_dereferences, DEREF_HOOK);
add_function_hook("ERR_PTR", &match_err_ptr_positive_const, NULL);
diff --git a/usr/src/tools/smatch/src/check_free_strict.c b/usr/src/tools/smatch/src/check_free_strict.c
index dd551cba52..4da29cced5 100644
--- a/usr/src/tools/smatch/src/check_free_strict.c
+++ b/usr/src/tools/smatch/src/check_free_strict.c
@@ -291,6 +291,38 @@ free:
return ret;
}
+static void match_untracked(struct expression *call, int param)
+{
+ struct state_list *slist = NULL;
+ struct expression *arg;
+ struct sm_state *sm;
+ char *name;
+ char buf[64];
+ int len;
+
+ arg = get_argument_from_call_expr(call->args, param);
+ if (!arg)
+ return;
+
+ name = expr_to_var(arg);
+ if (!name)
+ return;
+ snprintf(buf, sizeof(buf), "%s->", name);
+ free_string(name);
+ len = strlen(buf);
+
+ FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
+ if (strncmp(sm->name, buf, len) == 0)
+ add_ptr_list(&slist, sm);
+ } END_FOR_EACH_SM(sm);
+
+ FOR_EACH_PTR(slist, sm) {
+ set_state(sm->owner, sm->name, sm->sym, &ok);
+ } END_FOR_EACH_PTR(sm);
+
+ free_slist(&slist);
+}
+
void check_free_strict(int id)
{
my_id = id;
@@ -311,4 +343,5 @@ void check_free_strict(int id)
add_pre_merge_hook(my_id, &pre_merge_hook);
select_return_states_hook(PARAM_FREED, &set_param_freed);
+ add_untracked_param_hook(&match_untracked);
}
diff --git a/usr/src/tools/smatch/src/check_held_dev.c b/usr/src/tools/smatch/src/check_held_dev.c
index 43f61d7712..c776e1a653 100644
--- a/usr/src/tools/smatch/src/check_held_dev.c
+++ b/usr/src/tools/smatch/src/check_held_dev.c
@@ -113,7 +113,7 @@ static void register_returns_held_funcs(void)
if (token_type(token) != TOKEN_IDENT)
return;
func = show_ident(token->ident);
- return_implies_state(func, valid_ptr_min, valid_ptr_max,
+ return_implies_state_sval(func, valid_ptr_min_sval, valid_ptr_max_sval,
&match_returns_held, NULL);
return_implies_state(func, 0, 0, &match_returns_null,
NULL);
diff --git a/usr/src/tools/smatch/src/check_kernel.c b/usr/src/tools/smatch/src/check_kernel.c
index 98a4342fe7..69c9a37555 100644
--- a/usr/src/tools/smatch/src/check_kernel.c
+++ b/usr/src/tools/smatch/src/check_kernel.c
@@ -23,13 +23,19 @@
#include "smatch.h"
#include "smatch_extra.h"
+static sval_t err_ptr_min;
+static sval_t err_ptr_max;
+static sval_t null_ptr;
+
static int implied_err_cast_return(struct expression *call, void *unused, struct range_list **rl)
{
struct expression *arg;
arg = get_argument_from_call_expr(call->args, 0);
- if (!get_implied_rl(arg, rl))
- *rl = alloc_rl(ll_to_sval(-4095), ll_to_sval(-1));
+ if (!get_implied_rl(arg, rl)) {
+ *rl = alloc_rl(err_ptr_min, err_ptr_max);
+ *rl = cast_rl(get_type(arg), *rl);
+ }
return 1;
}
@@ -78,10 +84,18 @@ static void match_param_valid_ptr(const char *fn, struct expression *call_expr,
struct expression *arg;
struct smatch_state *pre_state;
struct smatch_state *end_state;
+ struct range_list *rl;
arg = get_argument_from_call_expr(call_expr->args, param);
pre_state = get_state_expr(SMATCH_EXTRA, arg);
- end_state = estate_filter_range(pre_state, ll_to_sval(-4095), ll_to_sval(0));
+ if (estate_rl(pre_state)) {
+ rl = estate_rl(pre_state);
+ rl = remove_range(rl, null_ptr, null_ptr);
+ rl = remove_range(rl, err_ptr_min, err_ptr_max);
+ } else {
+ rl = alloc_rl(valid_ptr_min_sval, valid_ptr_max_sval);
+ }
+ end_state = alloc_estate_rl(rl);
set_extra_expr_nomod(arg, end_state);
}
@@ -96,9 +110,9 @@ static void match_param_err_or_null(const char *fn, struct expression *call_expr
arg = get_argument_from_call_expr(call_expr->args, param);
pre_state = get_state_expr(SMATCH_EXTRA, arg);
- rl = alloc_rl(ll_to_sval(-4095), ll_to_sval(0));
+ call_results_to_rl(call_expr, &ptr_ctype, "0,(-4095)-(-1)", &rl);
rl = rl_intersection(estate_rl(pre_state), rl);
- rl = cast_rl(estate_type(pre_state), rl);
+ rl = cast_rl(get_type(arg), rl);
end_state = alloc_estate_rl(rl);
set_extra_expr_nomod(arg, end_state);
}
@@ -108,12 +122,18 @@ static void match_not_err(const char *fn, struct expression *call_expr,
{
struct expression *arg;
struct smatch_state *pre_state;
- struct smatch_state *new_state;
+ struct range_list *rl;
arg = get_argument_from_call_expr(call_expr->args, 0);
pre_state = get_state_expr(SMATCH_EXTRA, arg);
- new_state = estate_filter_range(pre_state, sval_type_min(&long_ctype), ll_to_sval(-1));
- set_extra_expr_nomod(arg, new_state);
+ if (estate_rl(pre_state)) {
+ rl = estate_rl(pre_state);
+ rl = remove_range(rl, err_ptr_min, err_ptr_max);
+ } else {
+ rl = alloc_rl(valid_ptr_min_sval, valid_ptr_max_sval);
+ }
+ rl = cast_rl(get_type(arg), rl);
+ set_extra_expr_nomod(arg, alloc_estate_rl(rl));
}
static void match_err(const char *fn, struct expression *call_expr,
@@ -121,13 +141,16 @@ static void match_err(const char *fn, struct expression *call_expr,
{
struct expression *arg;
struct smatch_state *pre_state;
- struct smatch_state *new_state;
+ struct range_list *rl;
arg = get_argument_from_call_expr(call_expr->args, 0);
pre_state = get_state_expr(SMATCH_EXTRA, arg);
- new_state = estate_filter_range(pre_state, sval_type_min(&long_ctype), ll_to_sval(-4096));
- new_state = estate_filter_range(new_state, ll_to_sval(0), sval_type_max(&long_ctype));
- set_extra_expr_nomod(arg, new_state);
+ rl = estate_rl(pre_state);
+ if (!rl)
+ rl = alloc_rl(err_ptr_min, err_ptr_max);
+ rl = rl_intersection(rl, alloc_rl(err_ptr_min, err_ptr_max));
+ rl = cast_rl(get_type(arg), rl);
+ set_extra_expr_nomod(arg, alloc_estate_rl(rl));
}
static void match_container_of_macro(const char *fn, struct expression *expr, void *unused)
@@ -379,11 +402,36 @@ static void match__read_once_size(const char *fn, struct expression *call,
__in_fake_assign--;
}
+bool is_ignored_kernel_data(const char *name)
+{
+ if (option_project != PROJ_KERNEL)
+ return false;
+
+ /*
+ * On the file I was looking at lockdep was 25% of the DB.
+ */
+ if (strstr(name, ".dep_map."))
+ return true;
+ if (strstr(name, ".lockdep_map."))
+ return true;
+ return false;
+}
+
void check_kernel(int id)
{
if (option_project != PROJ_KERNEL)
return;
+ err_ptr_min.type = &ptr_ctype;
+ err_ptr_min.value = -4095;
+ err_ptr_max.type = &ptr_ctype;
+ err_ptr_max.value = -1l;
+ null_ptr.type = &ptr_ctype;
+ null_ptr.value = 0;
+
+ err_ptr_min = sval_cast(&ptr_ctype, err_ptr_min);
+ err_ptr_max = sval_cast(&ptr_ctype, err_ptr_max);
+
add_implied_return_hook("ERR_PTR", &implied_err_cast_return, NULL);
add_implied_return_hook("ERR_CAST", &implied_err_cast_return, NULL);
add_implied_return_hook("PTR_ERR", &implied_err_cast_return, NULL);
diff --git a/usr/src/tools/smatch/src/check_kernel_printf.c b/usr/src/tools/smatch/src/check_kernel_printf.c
index c85dac1e20..8992a83fd7 100644
--- a/usr/src/tools/smatch/src/check_kernel_printf.c
+++ b/usr/src/tools/smatch/src/check_kernel_printf.c
@@ -521,6 +521,15 @@ static void dentry_file(const char *fmt, struct symbol *type, struct symbol *bas
fmt[0], tag, vaidx, type_to_str(type));
}
+static void time_and_date(const char *fmt, struct symbol *type, struct symbol *basetype, int vaidx)
+{
+ assert(tolower(fmt[0]) == 't');
+
+ if (fmt[1] == 'R' && !is_struct_tag(basetype, "rtc_time"))
+ sm_error("'%%ptR' expects argument of type struct 'rtc_time', argument %d has type '%s'",
+ vaidx, type_to_str(type));
+}
+
static void check_clock(const char *fmt, struct symbol *type, struct symbol *basetype, int vaidx)
{
assert(fmt[0] == 'C');
@@ -756,6 +765,9 @@ pointer(const char *fmt, struct expression *arg, int vaidx)
case 'd':
dentry_file(fmt, type, basetype, vaidx);
break;
+ case 't':
+ time_and_date(fmt, type, basetype, vaidx);
+ break;
case 'C':
check_clock(fmt, type, basetype, vaidx);
break;
diff --git a/usr/src/tools/smatch/src/check_list.h b/usr/src/tools/smatch/src/check_list.h
index 0c6ab0cd5f..6e0a0d7a8c 100644
--- a/usr/src/tools/smatch/src/check_list.h
+++ b/usr/src/tools/smatch/src/check_list.h
@@ -53,8 +53,11 @@ CK(register_type_links)
CK(register_impossible)
CK(register_impossible_return)
CK(register_strings)
+CK(register_integer_overflow)
+CK(register_integer_overflow_links)
CK(register_real_absolute)
CK(register_imaginary_absolute)
+CK(register_bits)
CK(register_fn_arg_link)
CK(register_parameter_names)
CK(register_return_to_param)
@@ -71,8 +74,8 @@ CK(register_nul_terminator)
CK(register_nul_terminator_param_set)
CK(register_statement_count)
+CK(register_kernel_user_data)
CK(register_kernel_user_data2)
-CK(register_kernel_user_data3)
CK(check_debug)
@@ -187,6 +190,7 @@ CK(check_dma_mapping_error)
CK(check_nospec)
CK(check_nospec_barrier)
CK(check_spectre)
+CK(check_spectre_second_half)
CK(check_implicit_dependencies)
/* wine specific stuff */
@@ -195,6 +199,7 @@ CK(check_wine_WtoA)
/* illumos specific */
CK(check_all_func_returns)
+CK(check_cmn_err)
#include "check_list_local.h"
diff --git a/usr/src/tools/smatch/src/check_locking.c b/usr/src/tools/smatch/src/check_locking.c
index 06cc7a597a..81fe9dda75 100644
--- a/usr/src/tools/smatch/src/check_locking.c
+++ b/usr/src/tools/smatch/src/check_locking.c
@@ -49,6 +49,7 @@ enum return_type {
ret_any,
ret_non_zero,
ret_zero,
+ ret_one,
ret_negative,
ret_positive,
};
@@ -151,18 +152,18 @@ static struct lock_info kernel_lock_table[] = {
{"__spin_lock_bh", LOCK, "spin_lock", 0, ret_any},
{"__spin_unlock_bh", UNLOCK, "spin_lock", 0, ret_any},
- {"spin_trylock", LOCK, "spin_lock", 0, ret_non_zero},
- {"_spin_trylock", LOCK, "spin_lock", 0, ret_non_zero},
- {"__spin_trylock", LOCK, "spin_lock", 0, ret_non_zero},
- {"raw_spin_trylock", LOCK, "spin_lock", 0, ret_non_zero},
- {"_raw_spin_trylock", LOCK, "spin_lock", 0, ret_non_zero},
- {"spin_trylock_irq", LOCK, "spin_lock", 0, ret_non_zero},
- {"spin_trylock_irqsave", LOCK, "spin_lock", 0, ret_non_zero},
- {"spin_trylock_bh", LOCK, "spin_lock", 0, ret_non_zero},
- {"_spin_trylock_bh", LOCK, "spin_lock", 0, ret_non_zero},
- {"__spin_trylock_bh", LOCK, "spin_lock", 0, ret_non_zero},
- {"__raw_spin_trylock", LOCK, "spin_lock", 0, ret_non_zero},
- {"_atomic_dec_and_lock", LOCK, "spin_lock", 1, ret_non_zero},
+ {"spin_trylock", LOCK, "spin_lock", 0, ret_one},
+ {"_spin_trylock", LOCK, "spin_lock", 0, ret_one},
+ {"__spin_trylock", LOCK, "spin_lock", 0, ret_one},
+ {"raw_spin_trylock", LOCK, "spin_lock", 0, ret_one},
+ {"_raw_spin_trylock", LOCK, "spin_lock", 0, ret_one},
+ {"spin_trylock_irq", LOCK, "spin_lock", 0, ret_one},
+ {"spin_trylock_irqsave", LOCK, "spin_lock", 0, ret_one},
+ {"spin_trylock_bh", LOCK, "spin_lock", 0, ret_one},
+ {"_spin_trylock_bh", LOCK, "spin_lock", 0, ret_one},
+ {"__spin_trylock_bh", LOCK, "spin_lock", 0, ret_one},
+ {"__raw_spin_trylock", LOCK, "spin_lock", 0, ret_one},
+ {"_atomic_dec_and_lock", LOCK, "spin_lock", 1, ret_one},
{"read_lock", LOCK, "read_lock", 0, ret_any},
{"read_unlock", UNLOCK, "read_lock", 0, ret_any},
@@ -197,13 +198,13 @@ static struct lock_info kernel_lock_table[] = {
{"__raw_read_lock_bh", LOCK, "read_lock", 0, ret_any},
{"__raw_read_unlock_bh", UNLOCK, "read_lock", 0, ret_any},
- {"generic__raw_read_trylock", LOCK, "read_lock", 0, ret_non_zero},
- {"read_trylock", LOCK, "read_lock", 0, ret_non_zero},
- {"_read_trylock", LOCK, "read_lock", 0, ret_non_zero},
- {"raw_read_trylock", LOCK, "read_lock", 0, ret_non_zero},
- {"_raw_read_trylock", LOCK, "read_lock", 0, ret_non_zero},
- {"__raw_read_trylock", LOCK, "read_lock", 0, ret_non_zero},
- {"__read_trylock", LOCK, "read_lock", 0, ret_non_zero},
+ {"generic__raw_read_trylock", LOCK, "read_lock", 0, ret_one},
+ {"read_trylock", LOCK, "read_lock", 0, ret_one},
+ {"_read_trylock", LOCK, "read_lock", 0, ret_one},
+ {"raw_read_trylock", LOCK, "read_lock", 0, ret_one},
+ {"_raw_read_trylock", LOCK, "read_lock", 0, ret_one},
+ {"__raw_read_trylock", LOCK, "read_lock", 0, ret_one},
+ {"__read_trylock", LOCK, "read_lock", 0, ret_one},
{"write_lock", LOCK, "write_lock", 0, ret_any},
{"write_unlock", UNLOCK, "write_lock", 0, ret_any},
@@ -234,12 +235,12 @@ static struct lock_info kernel_lock_table[] = {
{"_raw_write_unlock", UNLOCK, "write_lock", 0, ret_any},
{"__raw_write_unlock", UNLOCK, "write_lock", 0, ret_any},
- {"write_trylock", LOCK, "write_lock", 0, ret_non_zero},
- {"_write_trylock", LOCK, "write_lock", 0, ret_non_zero},
- {"raw_write_trylock", LOCK, "write_lock", 0, ret_non_zero},
- {"_raw_write_trylock", LOCK, "write_lock", 0, ret_non_zero},
- {"__write_trylock", LOCK, "write_lock", 0, ret_non_zero},
- {"__raw_write_trylock", LOCK, "write_lock", 0, ret_non_zero},
+ {"write_trylock", LOCK, "write_lock", 0, ret_one},
+ {"_write_trylock", LOCK, "write_lock", 0, ret_one},
+ {"raw_write_trylock", LOCK, "write_lock", 0, ret_one},
+ {"_raw_write_trylock", LOCK, "write_lock", 0, ret_one},
+ {"__write_trylock", LOCK, "write_lock", 0, ret_one},
+ {"__raw_write_trylock", LOCK, "write_lock", 0, ret_one},
{"down", LOCK, "sem", 0, ret_any},
{"up", UNLOCK, "sem", 0, ret_any},
@@ -247,16 +248,30 @@ static struct lock_info kernel_lock_table[] = {
{"down_timeout", LOCK, "sem", 0, ret_zero},
{"down_interruptible", LOCK, "sem", 0, ret_zero},
+
+ {"down_write", LOCK, "rw_sem", 0, ret_any},
+ {"downgrade_write", UNLOCK, "rw_sem", 0, ret_any},
+ {"downgrade_write", LOCK, "read_sem", 0, ret_any},
+ {"up_write", UNLOCK, "rw_sem", 0, ret_any},
+ {"down_write_trylock", LOCK, "rw_sem", 0, ret_one},
+ {"down_write_killable", LOCK, "rw_sem", 0, ret_zero},
+ {"down_read", LOCK, "read_sem", 0, ret_any},
+ {"down_read_trylock", LOCK, "read_sem", 0, ret_one},
+ {"down_read_killable", LOCK, "read_sem", 0, ret_zero},
+ {"up_read", UNLOCK, "read_sem", 0, ret_any},
+
{"mutex_lock", LOCK, "mutex", 0, ret_any},
+ {"mutex_lock_io", LOCK, "mutex", 0, ret_any},
{"mutex_unlock", UNLOCK, "mutex", 0, ret_any},
{"mutex_lock_nested", LOCK, "mutex", 0, ret_any},
+ {"mutex_lock_io_nested", LOCK, "mutex", 0, ret_any},
{"mutex_lock_interruptible", LOCK, "mutex", 0, ret_zero},
{"mutex_lock_interruptible_nested", LOCK, "mutex", 0, ret_zero},
{"mutex_lock_killable", LOCK, "mutex", 0, ret_zero},
{"mutex_lock_killable_nested", LOCK, "mutex", 0, ret_zero},
- {"mutex_trylock", LOCK, "mutex", 0, ret_non_zero},
+ {"mutex_trylock", LOCK, "mutex", 0, ret_one},
{"raw_local_irq_disable", LOCK, "irq", NO_ARG, ret_any},
{"raw_local_irq_enable", UNLOCK, "irq", NO_ARG, ret_any},
@@ -269,7 +284,7 @@ static struct lock_info kernel_lock_table[] = {
{"_raw_spin_lock_irq", LOCK, "irq", NO_ARG, ret_any},
{"_raw_spin_unlock_irq", UNLOCK, "irq", NO_ARG, ret_any},
{"__raw_spin_unlock_irq", UNLOCK, "irq", NO_ARG, ret_any},
- {"spin_trylock_irq", LOCK, "irq", NO_ARG, ret_non_zero},
+ {"spin_trylock_irq", LOCK, "irq", NO_ARG, ret_one},
{"read_lock_irq", LOCK, "irq", NO_ARG, ret_any},
{"read_unlock_irq", UNLOCK, "irq", NO_ARG, ret_any},
{"_read_lock_irq", LOCK, "irq", NO_ARG, ret_any},
@@ -304,7 +319,7 @@ static struct lock_info kernel_lock_table[] = {
{"__raw_spin_lock_irqsave", LOCK, "irqsave", RETURN_VAL, ret_any},
{"__raw_spin_unlock_irqrestore",UNLOCK, "irqsave", 1, ret_any},
{"_raw_spin_lock_irqsave_nested", LOCK, "irqsave", RETURN_VAL, ret_any},
- {"spin_trylock_irqsave", LOCK, "irqsave", 1, ret_non_zero},
+ {"spin_trylock_irqsave", LOCK, "irqsave", 1, ret_one},
{"read_lock_irqsave", LOCK, "irqsave", RETURN_VAL, ret_any},
{"read_lock_irqsave", LOCK, "irqsave", 1, ret_any},
{"read_unlock_irqrestore", UNLOCK, "irqsave", 1, ret_any},
@@ -348,9 +363,9 @@ static struct lock_info kernel_lock_table[] = {
{"_write_unlock_bh", UNLOCK, "bottom_half", NO_ARG, ret_any},
{"__write_lock_bh", LOCK, "bottom_half", NO_ARG, ret_any},
{"__write_unlock_bh", UNLOCK, "bottom_half", NO_ARG, ret_any},
- {"spin_trylock_bh", LOCK, "bottom_half", NO_ARG, ret_non_zero},
- {"_spin_trylock_bh", LOCK, "bottom_half", NO_ARG, ret_non_zero},
- {"__spin_trylock_bh", LOCK, "bottom_half", NO_ARG, ret_non_zero},
+ {"spin_trylock_bh", LOCK, "bottom_half", NO_ARG, ret_one},
+ {"_spin_trylock_bh", LOCK, "bottom_half", NO_ARG, ret_one},
+ {"__spin_trylock_bh", LOCK, "bottom_half", NO_ARG, ret_one},
{"ffs_mutex_lock", LOCK, "mutex", 0, ret_zero},
};
@@ -447,6 +462,15 @@ static void pre_merge_hook(struct sm_state *sm)
set_state(my_id, sm->name, sm->sym, &impossible);
}
+static bool nestable(const char *name)
+{
+ if (strstr(name, "read_sem:"))
+ return true;
+ if (strcmp(name, "bottom_half:") == 0)
+ return true;
+ return false;
+}
+
static void do_lock(const char *name)
{
struct sm_state *sm;
@@ -457,8 +481,7 @@ static void do_lock(const char *name)
sm = get_sm_state(my_id, name, NULL);
if (!sm)
add_tracker(&starts_unlocked, my_id, name, NULL);
- if (sm && slist_has_state(sm->possible, &locked) &&
- strcmp(name, "bottom_half:") != 0)
+ if (sm && slist_has_state(sm->possible, &locked) && !nestable(name))
sm_error("double lock '%s'", name);
if (sm)
func_has_transition = TRUE;
@@ -744,12 +767,15 @@ static void print_inconsistent_returns(struct tracker *lock,
static int matches_return_type(struct range_list *rl, enum return_type type)
{
sval_t zero_sval = ll_to_sval(0);
+ sval_t one_sval = ll_to_sval(1);
/* All these double negatives are super ugly! */
switch (type) {
case ret_zero:
return !possibly_true_rl(rl, SPECIAL_NOTEQUAL, alloc_rl(zero_sval, zero_sval));
+ case ret_one:
+ return !possibly_true_rl(rl, SPECIAL_NOTEQUAL, alloc_rl(one_sval, one_sval));
case ret_non_zero:
return !possibly_true_rl(rl, SPECIAL_EQUAL, alloc_rl(zero_sval, zero_sval));
case ret_negative:
@@ -906,7 +932,7 @@ static void register_lock(int index)
void *idx = INT_PTR(index);
if (lock->return_type == ret_non_zero) {
- return_implies_state(lock->function, valid_ptr_min, valid_ptr_max, &match_lock_held, idx);
+ return_implies_state(lock->function, 1, INT_MAX, &match_lock_held, idx);
return_implies_state(lock->function, 0, 0, &match_lock_failed, idx);
} else if (lock->return_type == ret_any && lock->arg == RETURN_VAL) {
add_function_assign_hook(lock->function, &match_returns_locked, idx);
@@ -915,6 +941,9 @@ static void register_lock(int index)
} else if (lock->return_type == ret_zero) {
return_implies_state(lock->function, 0, 0, &match_lock_held, idx);
return_implies_state(lock->function, -4095, -1, &match_lock_failed, idx);
+ } else if (lock->return_type == ret_one) {
+ return_implies_state(lock->function, 1, 1, &match_lock_held, idx);
+ return_implies_state(lock->function, 0, 0, &match_lock_failed, idx);
}
}
diff --git a/usr/src/tools/smatch/src/check_macro_side_effects.c b/usr/src/tools/smatch/src/check_macro_side_effects.c
index 29c92b0e4b..ef4e7de4eb 100644
--- a/usr/src/tools/smatch/src/check_macro_side_effects.c
+++ b/usr/src/tools/smatch/src/check_macro_side_effects.c
@@ -30,9 +30,12 @@ static struct smatch_state *alloc_my_state(struct expression *expr)
struct smatch_state *state;
char *name;
- state = __alloc_smatch_state(0);
expr = strip_expr(expr);
name = expr_to_str(expr);
+ if (!name)
+ return NULL;
+
+ state = __alloc_smatch_state(0);
state->name = alloc_sname(name);
free_string(name);
state->data = expr;
@@ -160,6 +163,7 @@ void check_macro_side_effects(int id)
if (!option_spammy)
return;
+ set_dynamic_states(my_id);
add_hook(&match_unop, OP_HOOK);
add_hook(&match_stmt, STMT_HOOK);
register_ignored_macros();
diff --git a/usr/src/tools/smatch/src/check_missing_break.c b/usr/src/tools/smatch/src/check_missing_break.c
index fb30518131..4b6b0c032d 100644
--- a/usr/src/tools/smatch/src/check_missing_break.c
+++ b/usr/src/tools/smatch/src/check_missing_break.c
@@ -177,6 +177,7 @@ void check_missing_break(int id)
if (!option_spammy)
return;
+ set_dynamic_states(my_id);
add_unmatched_state_hook(my_id, &unmatched_state);
add_merge_hook(my_id, &merge_hook);
diff --git a/usr/src/tools/smatch/src/check_no_return.c b/usr/src/tools/smatch/src/check_no_return.c
index 57c6afdf38..3971ecce92 100644
--- a/usr/src/tools/smatch/src/check_no_return.c
+++ b/usr/src/tools/smatch/src/check_no_return.c
@@ -16,6 +16,7 @@
*/
#include "smatch.h"
+#include "smatch_slist.h"
static int my_id;
static int returned;
@@ -32,6 +33,8 @@ static void match_func_end(struct symbol *sym)
{
if (__inline_fn)
return;
+ if (out_of_memory() || taking_too_long())
+ return;
if (!is_reachable() && !returned)
sm_info("info: add to no_return_funcs");
returned = 0;
diff --git a/usr/src/tools/smatch/src/check_nospec.c b/usr/src/tools/smatch/src/check_nospec.c
index a4d5baef89..a2aea00dfe 100644
--- a/usr/src/tools/smatch/src/check_nospec.c
+++ b/usr/src/tools/smatch/src/check_nospec.c
@@ -96,6 +96,7 @@ static void struct_member_callback(struct expression *call, int param, char *pri
static void returned_struct_members(int return_id, char *return_ranges, struct expression *expr)
{
+ struct stree *start_states = get_start_states();
struct symbol *returned_sym;
struct sm_state *sm;
const char *param_name;
@@ -105,6 +106,8 @@ static void returned_struct_members(int return_id, char *return_ranges, struct e
returned_sym = expr_to_sym(expr);
FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
+ if (get_state_stree(start_states, my_id, sm->name, sm->sym) == sm->state)
+ continue;
param = get_param_num_from_sym(sm->sym);
if (param < 0) {
if (!returned_sym || returned_sym != sm->sym)
@@ -222,7 +225,8 @@ static void match_barrier(struct statement *stmt)
return;
if (strcmp(macro, "rmb") != 0 &&
strcmp(macro, "smp_rmb") != 0 &&
- strcmp(macro, "barrier_nospec") != 0)
+ strcmp(macro, "barrier_nospec") != 0 &&
+ strcmp(macro, "preempt_disable") != 0)
return;
set_state(barrier_id, "barrier", NULL, &nospec);
@@ -234,6 +238,15 @@ static void db_returns_barrier(struct expression *expr, int param, char *key, ch
mark_user_data_as_nospec();
}
+static void select_return_stmt_cnt(struct expression *expr, int param, char *key, char *value)
+{
+ int cnt;
+
+ cnt = atoi(value);
+ if (cnt > 400)
+ mark_user_data_as_nospec();
+}
+
void check_nospec(int id)
{
my_id = id;
@@ -248,6 +261,7 @@ void check_nospec(int id)
add_split_return_callback(&returned_struct_members);
select_return_states_hook(NOSPEC, &db_returns_nospec);
select_return_states_hook(NOSPEC_WB, &db_returns_barrier);
+ select_return_states_hook(STMT_CNT, &select_return_stmt_cnt);
add_hook(&match_asm, ASM_HOOK);
add_hook(&match_after_nospec_asm, STMT_HOOK_AFTER);
diff --git a/usr/src/tools/smatch/src/check_off_by_one_relative.c b/usr/src/tools/smatch/src/check_off_by_one_relative.c
index f6f6e6fac7..2249288e51 100644
--- a/usr/src/tools/smatch/src/check_off_by_one_relative.c
+++ b/usr/src/tools/smatch/src/check_off_by_one_relative.c
@@ -33,19 +33,23 @@ static void array_check(struct expression *expr)
struct expression *size;
struct expression *offset;
char *array_str, *offset_str;
+ int limit_type;
expr = strip_expr(expr);
if (!is_array(expr))
return;
array = get_array_base(expr);
- size = get_size_variable(array);
- if (!size)
+ size = get_size_variable(array, &limit_type);
+ if (!size || limit_type != ELEM_COUNT)
return;
offset = get_array_offset(expr);
if (!possible_comparison(size, SPECIAL_EQUAL, offset))
return;
+ if (buf_comparison_index_ok(expr))
+ return;
+
array_str = expr_to_str(array);
offset_str = expr_to_str(offset);
sm_warning("potentially one past the end of array '%s[%s]'", array_str, offset_str);
@@ -53,25 +57,6 @@ static void array_check(struct expression *expr)
free_string(offset_str);
}
-static int known_access_ok_comparison(struct expression *expr)
-{
- struct expression *array;
- struct expression *size;
- struct expression *offset;
- int comparison;
-
- array = get_array_base(expr);
- size = get_size_variable(array);
- if (!size)
- return 0;
- offset = get_array_offset(expr);
- comparison = get_comparison(size, offset);
- if (comparison == '>' || comparison == SPECIAL_UNSIGNED_GT)
- return 1;
-
- return 0;
-}
-
static int known_access_ok_numbers(struct expression *expr)
{
struct expression *array;
@@ -108,7 +93,7 @@ static void array_check_data_info(struct expression *expr)
if (known_access_ok_numbers(expr))
return;
- if (known_access_ok_comparison(expr))
+ if (buf_comparison_index_ok(expr))
return;
array = get_array_base(expr);
diff --git a/usr/src/tools/smatch/src/check_precedence.c b/usr/src/tools/smatch/src/check_precedence.c
index 3ee062295c..a7220ab8b5 100644
--- a/usr/src/tools/smatch/src/check_precedence.c
+++ b/usr/src/tools/smatch/src/check_precedence.c
@@ -120,6 +120,16 @@ static void match_mask(struct expression *expr)
sm_warning("shift has higher precedence than mask");
}
+static void match_mask_compare(struct expression *expr)
+{
+ if (expr->op != '&')
+ return;
+ if (expr->right->type != EXPR_COMPARE)
+ return;
+
+ sm_warning("compare has higher precedence than mask");
+}
+
static void match_subtract_shift(struct expression *expr)
{
if (expr->op != SPECIAL_LEFTSHIFT)
@@ -138,5 +148,6 @@ void check_precedence(int id)
add_hook(&match_condition, CONDITION_HOOK);
add_hook(&match_binop, BINOP_HOOK);
add_hook(&match_mask, BINOP_HOOK);
+ add_hook(&match_mask_compare, BINOP_HOOK);
add_hook(&match_subtract_shift, BINOP_HOOK);
}
diff --git a/usr/src/tools/smatch/src/check_return_cast.c b/usr/src/tools/smatch/src/check_return_cast.c
index 5a87a6e27f..d0237e4584 100644
--- a/usr/src/tools/smatch/src/check_return_cast.c
+++ b/usr/src/tools/smatch/src/check_return_cast.c
@@ -28,6 +28,9 @@ static void match_return(struct expression *ret_value)
struct symbol *func_type = get_real_base_type(cur_func_sym);
sval_t sval;
+ if (!func_type || func_type->type != SYM_FN)
+ return;
+ func_type = get_real_base_type(func_type);
if (!func_type)
return;
if (!type_unsigned(func_type))
diff --git a/usr/src/tools/smatch/src/check_rosenberg.c b/usr/src/tools/smatch/src/check_rosenberg.c
index bde603a706..7a03ee488d 100644
--- a/usr/src/tools/smatch/src/check_rosenberg.c
+++ b/usr/src/tools/smatch/src/check_rosenberg.c
@@ -382,6 +382,7 @@ void check_rosenberg2(int id)
return;
my_member_id = id;
+ set_dynamic_states(my_member_id);
add_extra_mod_hook(&extra_mod_hook);
}
diff --git a/usr/src/tools/smatch/src/check_shift_to_zero.c b/usr/src/tools/smatch/src/check_shift_to_zero.c
index 57cc3cbb84..019b06fb75 100644
--- a/usr/src/tools/smatch/src/check_shift_to_zero.c
+++ b/usr/src/tools/smatch/src/check_shift_to_zero.c
@@ -35,6 +35,8 @@ static void match_binop(struct expression *expr)
return;
if (type_bits(type) == -1 || type_bits(type) > bits.value)
return;
+ if (is_ignored_expr(my_id, expr))
+ return;
sm_warning("right shifting more than type allows %d vs %lld", type_bits(type), bits.value);
}
diff --git a/usr/src/tools/smatch/src/check_snprintf.c b/usr/src/tools/smatch/src/check_snprintf.c
index 162e07c6db..43f5131787 100644
--- a/usr/src/tools/smatch/src/check_snprintf.c
+++ b/usr/src/tools/smatch/src/check_snprintf.c
@@ -79,6 +79,7 @@ void check_snprintf(int id)
return;
my_id = id;
+ set_dynamic_states(my_id);
add_hook(&match_call, FUNCTION_CALL_HOOK);
add_function_assign_hook("snprintf", &match_snprintf, NULL);
add_modification_hook(my_id, &ok_to_use);
diff --git a/usr/src/tools/smatch/src/check_spectre.c b/usr/src/tools/smatch/src/check_spectre.c
index e35527b5e4..014235daef 100644
--- a/usr/src/tools/smatch/src/check_spectre.c
+++ b/usr/src/tools/smatch/src/check_spectre.c
@@ -19,6 +19,8 @@
#include "smatch_extra.h"
static int my_id;
+extern int second_half_id;
+extern void set_spectre_first_half(struct expression *expr);
static int suppress_multiple = 1;
@@ -165,8 +167,10 @@ static void array_check(struct expression *expr)
return;
array_expr = get_array_base(expr);
- if (suppress_multiple && is_ignored_expr(my_id, array_expr))
+ if (suppress_multiple && is_ignored_expr(my_id, array_expr)) {
+ set_spectre_first_half(expr);
return;
+ }
offset = get_array_offset(expr);
if (!is_user_rl(offset))
@@ -192,6 +196,8 @@ static void array_check(struct expression *expr)
name,
is_read(expr) ? "r" : "w",
conditions ? " (local cap)" : "");
+
+ set_spectre_first_half(expr);
if (suppress_multiple)
add_ignore_expr(my_id, array_expr);
free_string(name);
diff --git a/usr/src/tools/smatch/src/check_spectre_second_half.c b/usr/src/tools/smatch/src/check_spectre_second_half.c
new file mode 100644
index 0000000000..158fc81da2
--- /dev/null
+++ b/usr/src/tools/smatch/src/check_spectre_second_half.c
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 2018 Oracle.
+ *
+ * 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 program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
+ */
+
+#include "smatch.h"
+#include "smatch_extra.h"
+#include "smatch_slist.h"
+
+/* New chips will probably be able to speculate further ahead */
+#define MAX_SPEC_STMT 200
+
+static int my_id;
+
+struct stree *first_halfs;
+
+struct expression *recently_set;
+
+void set_spectre_first_half(struct expression *expr)
+{
+ char buf[64];
+ char *name;
+
+ name = expr_to_str(expr);
+ snprintf(buf, sizeof(buf), "%p %s", expr, name);
+ free_string(name);
+
+ set_state_stree(&first_halfs, my_id, buf, NULL, alloc_state_num(get_stmt_cnt()));
+}
+
+void clear_spectre_second_halfs(void)
+{
+ struct sm_state *sm;
+
+ FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
+ set_state(my_id, sm->name, sm->sym, alloc_state_num(-MAX_SPEC_STMT));
+ } END_FOR_EACH_SM(sm);
+}
+
+static struct smatch_state *get_spectre_first_half(struct expression *expr)
+{
+ char buf[64];
+ char *name;
+
+ name = expr_to_str(expr);
+ snprintf(buf, sizeof(buf), "%p %s", expr, name);
+ free_string(name);
+
+ return get_state_stree(first_halfs, my_id, buf, NULL);
+}
+
+static void match_assign(struct expression *expr)
+{
+ struct smatch_state *state;
+
+ if (expr->op == SPECIAL_AND_ASSIGN)
+ return;
+
+ state = get_spectre_first_half(expr->right);
+ if (state) {
+ set_state_expr(my_id, expr->left, state);
+ recently_set = expr->left;
+ return;
+ }
+ state = get_state_expr(my_id, expr->right);
+ if (!state)
+ return;
+ set_state_expr(my_id, expr->left, state);
+ recently_set = expr->left;
+}
+
+static void match_done(struct expression *expr)
+{
+ struct smatch_state *state;
+ char *name;
+
+ if (expr == recently_set)
+ return;
+
+ state = get_state_expr(my_id, expr);
+ if (!state)
+ return;
+
+ if (get_stmt_cnt() - (long)state->data > MAX_SPEC_STMT)
+ return;
+
+ name = expr_to_str(expr);
+ sm_msg("warn: possible spectre second half. '%s'", name);
+ free_string(name);
+
+ set_state_expr(my_id, expr, alloc_state_num(-MAX_SPEC_STMT));
+}
+
+static void match_end_func(struct symbol *sym)
+{
+ if (__inline_fn)
+ return;
+ free_stree(&first_halfs);
+}
+
+void check_spectre_second_half(int id)
+{
+ my_id = id;
+
+ if (option_project != PROJ_KERNEL)
+ return;
+ set_dynamic_states(my_id);
+ add_hook(&match_assign, ASSIGNMENT_HOOK);
+ add_hook(&match_done, SYM_HOOK);
+ add_hook(&match_done, DEREF_HOOK);
+
+ add_hook(&match_end_func, END_FUNC_HOOK);
+}
diff --git a/usr/src/tools/smatch/src/check_string_len.c b/usr/src/tools/smatch/src/check_string_len.c
index 3d6fd7f105..f8c102ae01 100644
--- a/usr/src/tools/smatch/src/check_string_len.c
+++ b/usr/src/tools/smatch/src/check_string_len.c
@@ -35,13 +35,13 @@ struct param_info {
struct param_info zero_one = {0, 1};
-static int handle_format(struct expression *call, char **pp, int *arg_nr)
+static int handle_format(struct expression *call, char **pp, int *arg_nr, bool use_max)
{
struct expression *arg;
char *p = *pp;
int ret = 1;
char buf[256];
- sval_t max;
+ sval_t sval;
p++; /* we passed it with *p == '%' */
@@ -141,23 +141,30 @@ static int handle_format(struct expression *call, char **pp, int *arg_nr)
goto out;
}
- get_absolute_max(arg, &max);
+ if (use_max) {
+ get_absolute_max(arg, &sval);
+ } else {
+ get_absolute_min(arg, &sval);
+ if (sval_is_negative(sval))
+ sval.value = 0;
+ }
+
if (*p == 'x' || *p == 'X' || *p == 'p') {
- ret = snprintf(buf, sizeof(buf), "%llx", max.uvalue);
+ ret = snprintf(buf, sizeof(buf), "%llx", sval.uvalue);
} else if (*p == 'u') {
- ret = snprintf(buf, sizeof(buf), "%llu", max.uvalue);
+ ret = snprintf(buf, sizeof(buf), "%llu", sval.uvalue);
} else if (!expr_unsigned(arg)) {
sval_t min;
int tmp;
- ret = snprintf(buf, sizeof(buf), "%lld", max.value);
+ ret = snprintf(buf, sizeof(buf), "%lld", sval.value);
get_absolute_min(arg, &min);
tmp = snprintf(buf, sizeof(buf), "%lld", min.value);
if (tmp > ret)
ret = tmp;
} else {
- ret = snprintf(buf, sizeof(buf), "%lld", max.value);
+ ret = snprintf(buf, sizeof(buf), "%lld", sval.value);
}
p++;
@@ -168,7 +175,7 @@ out_no_arg:
return ret;
}
-int get_formatted_string_size(struct expression *call, int arg)
+int get_formatted_string_size_helper(struct expression *call, int arg, bool use_max)
{
struct expression *expr;
char *p;
@@ -184,7 +191,7 @@ int get_formatted_string_size(struct expression *call, int arg)
while (*p) {
if (*p == '%') {
- count += handle_format(call, &p, &arg);
+ count += handle_format(call, &p, &arg, use_max);
} else if (*p == '\\') {
p++;
}else {
@@ -193,10 +200,19 @@ int get_formatted_string_size(struct expression *call, int arg)
}
}
- count++; /* count the NUL terminator */
return count;
}
+int get_formatted_string_size(struct expression *call, int arg)
+{
+ return get_formatted_string_size_helper(call, arg, true);
+}
+
+int get_formatted_string_min_size(struct expression *call, int arg)
+{
+ return get_formatted_string_size_helper(call, arg, false);
+}
+
static void match_not_limited(const char *fn, struct expression *call, void *info)
{
struct param_info *params = info;
@@ -224,10 +240,11 @@ static void match_not_limited(const char *fn, struct expression *call, void *inf
return;
size = get_formatted_string_size(call, params->string);
- if (size <= 0)
+ if (size < 0)
return;
if (size < offset)
size -= offset;
+ size++; /* add the NULL terminator */
if (size <= buf_size)
return;
diff --git a/usr/src/tools/smatch/src/check_syscall_arg_type.c b/usr/src/tools/smatch/src/check_syscall_arg_type.c
index 1beb27f33c..dbabaae679 100644
--- a/usr/src/tools/smatch/src/check_syscall_arg_type.c
+++ b/usr/src/tools/smatch/src/check_syscall_arg_type.c
@@ -161,6 +161,7 @@ void check_syscall_arg_type(int id)
if (option_project != PROJ_KERNEL)
return;
+ set_dynamic_states(my_id);
add_merge_hook(my_id, &merge_states);
add_function_hook("fdget", &match_fdget, NULL);
}
diff --git a/usr/src/tools/smatch/src/check_testing_index_after_use.c b/usr/src/tools/smatch/src/check_testing_index_after_use.c
index 18b0fcffe6..b04ceece5d 100644
--- a/usr/src/tools/smatch/src/check_testing_index_after_use.c
+++ b/usr/src/tools/smatch/src/check_testing_index_after_use.c
@@ -35,29 +35,12 @@ static void delete(struct sm_state *sm, struct expression *mod_expr)
set_state(my_used_id, sm->name, sm->sym, &undefined);
}
-static int get_the_max(struct expression *expr, sval_t *sval)
-{
- struct range_list *rl;
-
- if (get_hard_max(expr, sval))
- return 1;
- if (!option_spammy)
- return 0;
- if (get_fuzzy_max(expr, sval))
- return 1;
- if (get_user_rl(expr, &rl)) {
- *sval = rl_max(rl);
- return 1;
- }
- return 0;
-}
-
static void array_check(struct expression *expr)
{
struct expression *array_expr;
int array_size;
struct expression *offset;
- sval_t max;
+ struct range_list *rl;
expr = strip_expr(expr);
if (!is_array(expr))
@@ -69,13 +52,17 @@ static void array_check(struct expression *expr)
return;
offset = get_array_offset(expr);
- if (!get_the_max(offset, &max)) {
- if (getting_address())
- return;
- if (is_capped(offset))
- return;
- set_state_expr(my_used_id, offset, alloc_state_num(array_size));
- }
+ get_absolute_rl(offset, &rl);
+ if (rl_max(rl).uvalue < array_size)
+ return;
+ if (buf_comparison_index_ok(expr))
+ return;
+
+ if (getting_address())
+ return;
+ if (is_capped(offset))
+ return;
+ set_state_expr(my_used_id, offset, alloc_state_num(array_size));
}
static void match_condition(struct expression *expr)
@@ -121,6 +108,7 @@ static void match_condition(struct expression *expr)
void check_testing_index_after_use(int id)
{
my_used_id = id;
+ set_dynamic_states(my_used_id);
add_hook(&array_check, OP_HOOK);
add_hook(&match_condition, CONDITION_HOOK);
add_modification_hook(my_used_id, &delete);
diff --git a/usr/src/tools/smatch/src/check_uninitialized.c b/usr/src/tools/smatch/src/check_uninitialized.c
index 9cf28f3612..97d8d51f54 100644
--- a/usr/src/tools/smatch/src/check_uninitialized.c
+++ b/usr/src/tools/smatch/src/check_uninitialized.c
@@ -95,6 +95,41 @@ static void match_assign(struct expression *expr)
set_state_expr(my_id, right->unop, &initialized);
}
+static void match_negative_comparison(struct expression *expr)
+{
+ struct expression *success;
+ struct sm_state *sm;
+ sval_t max;
+
+ /*
+ * In the kernel, people don't use "if (ret) {" and "if (ret < 0) {"
+ * consistently. Ideally Smatch would know the return but often it
+ * doesn't.
+ *
+ */
+
+ if (option_project != PROJ_KERNEL)
+ return;
+
+ if (expr->type != EXPR_COMPARE || expr->op != '<')
+ return;
+ if (!is_zero(expr->right))
+ return;
+ if (get_implied_max(expr->left, &max) && max.value == 0)
+ return;
+
+ success = compare_expression(expr->left, SPECIAL_EQUAL, expr->right);
+ if (!assume(success))
+ return;
+
+ FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
+ if (sm->state == &initialized)
+ set_true_false_states(my_id, sm->name, sm->sym, NULL, &initialized);
+ } END_FOR_EACH_SM(sm);
+
+ end_assume();
+}
+
static int is_initialized(struct expression *expr)
{
struct sm_state *sm;
@@ -114,7 +149,7 @@ static void match_dereferences(struct expression *expr)
{
char *name;
- if (parse_error)
+ if (implications_off || parse_error)
return;
if (expr->type != EXPR_PREOP)
@@ -135,7 +170,7 @@ static void match_condition(struct expression *expr)
{
char *name;
- if (parse_error)
+ if (implications_off || parse_error)
return;
if (is_impossible_path())
@@ -265,7 +300,7 @@ static void match_symbol(struct expression *expr)
{
char *name;
- if (parse_error)
+ if (implications_off || parse_error)
return;
if (is_impossible_path())
@@ -352,6 +387,7 @@ void check_uninitialized(int id)
add_hook(&match_declarations, DECLARATION_HOOK);
add_extra_mod_hook(&extra_mod_hook);
add_hook(&match_assign, ASSIGNMENT_HOOK);
+ add_hook(&match_negative_comparison, CONDITION_HOOK);
add_untracked_param_hook(&match_untracked);
add_pre_merge_hook(my_id, &pre_merge_hook);
diff --git a/usr/src/tools/smatch/src/check_unwind.c b/usr/src/tools/smatch/src/check_unwind.c
index 9fa6d0cfe2..b29b8362f6 100644
--- a/usr/src/tools/smatch/src/check_unwind.c
+++ b/usr/src/tools/smatch/src/check_unwind.c
@@ -194,21 +194,21 @@ void check_unwind(int id)
add_function_hook("release_resource", &match_release, INT_PTR(0));
release_function_indicator("release_resource");
- return_implies_state("__request_region", valid_ptr_min, valid_ptr_max, &request_granted, INT_PTR(1));
+ return_implies_state_sval("__request_region", valid_ptr_min_sval, valid_ptr_max_sval, &request_granted, INT_PTR(1));
return_implies_state("__request_region", 0, 0, &request_denied, INT_PTR(1));
add_function_hook("__release_region", &match_release, INT_PTR(1));
release_function_indicator("__release_region");
- return_implies_state("ioremap", valid_ptr_min, valid_ptr_max, &request_granted, INT_PTR(-1));
+ return_implies_state_sval("ioremap", valid_ptr_min_sval, valid_ptr_max_sval, &request_granted, INT_PTR(-1));
return_implies_state("ioremap", 0, 0, &request_denied, INT_PTR(-1));
add_function_hook("iounmap", &match_release, INT_PTR(0));
- return_implies_state("pci_iomap", valid_ptr_min, valid_ptr_max, &request_granted, INT_PTR(-1));
+ return_implies_state_sval("pci_iomap", valid_ptr_min_sval, valid_ptr_max_sval, &request_granted, INT_PTR(-1));
return_implies_state("pci_iomap", 0, 0, &request_denied, INT_PTR(-1));
add_function_hook("pci_iounmap", &match_release, INT_PTR(1));
release_function_indicator("pci_iounmap");
- return_implies_state("__create_workqueue_key", valid_ptr_min, valid_ptr_max, &request_granted,
+ return_implies_state_sval("__create_workqueue_key", valid_ptr_min_sval, valid_ptr_max_sval, &request_granted,
INT_PTR(-1));
return_implies_state("__create_workqueue_key", 0, 0, &request_denied, INT_PTR(-1));
add_function_hook("destroy_workqueue", &match_release, INT_PTR(0));
@@ -228,6 +228,5 @@ void check_unwind(int id)
add_function_hook("misc_deregister", &match_release, INT_PTR(0));
release_function_indicator("misc_deregister");
-
add_hook(&match_return, RETURN_HOOK);
}
diff --git a/usr/src/tools/smatch/src/check_wine_WtoA.c b/usr/src/tools/smatch/src/check_wine_WtoA.c
index 4ef4529231..f074471bd7 100644
--- a/usr/src/tools/smatch/src/check_wine_WtoA.c
+++ b/usr/src/tools/smatch/src/check_wine_WtoA.c
@@ -16,7 +16,7 @@
*/
/*
- * Idea from Michael Stefaniuc and Vincent Béron's earlier WtoA
+ * Idea from Michael Stefaniuc and Vincent Béron's earlier WtoA
* check.
*
* Apparently when you are coding WINE, you are not allowed to call
diff --git a/usr/src/tools/smatch/src/check_zero_to_err_ptr.c b/usr/src/tools/smatch/src/check_zero_to_err_ptr.c
index 8d5984a183..618f24abcc 100644
--- a/usr/src/tools/smatch/src/check_zero_to_err_ptr.c
+++ b/usr/src/tools/smatch/src/check_zero_to_err_ptr.c
@@ -74,15 +74,48 @@ static int next_line_checks_IS_ERR(struct expression *call, struct expression *a
return expr_equiv(next, arg);
}
+static int is_non_zero_int(struct range_list *rl)
+{
+ struct data_range *tmp;
+ int cnt = -1;
+
+ FOR_EACH_PTR(rl, tmp) {
+ cnt++;
+
+ if (cnt == 0) {
+ if (tmp->min.value == INT_MIN &&
+ tmp->max.value == -1)
+ continue;
+ } else if (cnt == 1) {
+ if (tmp->min.value == 1 &&
+ tmp->max.value == INT_MAX)
+ return 1;
+ }
+ return 0;
+ } END_FOR_EACH_PTR(tmp);
+ return 0;
+}
+
static int is_valid_ptr(sval_t sval)
{
- if (sval.type == &int_ctype &&
- (sval.value == INT_MIN || sval.value == INT_MAX))
+ if (sval.value == INT_MIN || sval.value == INT_MAX)
return 0;
if (sval_cmp(valid_ptr_min_sval, sval) <= 0 &&
- sval_cmp(valid_ptr_max_sval, sval) >= 0)
+ sval_cmp(valid_ptr_max_sval, sval) >= 0) {
return 1;
+ }
+ return 0;
+}
+
+static int has_distinct_zero(struct range_list *rl)
+{
+ struct data_range *tmp;
+
+ FOR_EACH_PTR(rl, tmp) {
+ if (tmp->min.value == 0 || tmp->max.value == 0)
+ return 1;
+ } END_FOR_EACH_PTR(tmp);
return 0;
}
@@ -90,7 +123,9 @@ static void match_err_ptr(const char *fn, struct expression *expr, void *data)
{
struct expression *arg_expr;
struct sm_state *sm, *tmp;
- sval_t sval;
+
+ if (is_impossible_path())
+ return;
arg_expr = get_argument_from_call_expr(expr->args, 0);
sm = get_sm_state_expr(SMATCH_EXTRA, arg_expr);
@@ -109,17 +144,19 @@ static void match_err_ptr(const char *fn, struct expression *expr, void *data)
FOR_EACH_PTR(sm->possible, tmp) {
if (!estate_rl(tmp->state))
continue;
+ if (is_non_zero_int(estate_rl(tmp->state)))
+ continue;
+ if (has_distinct_zero(estate_rl(tmp->state))) {
+ sm_warning("passing zero to '%s'", fn);
+ return;
+ }
+ if (strcmp(fn, "PTR_ERR") != 0)
+ continue;
if (is_valid_ptr(estate_min(tmp->state)) &&
is_valid_ptr(estate_max(tmp->state))) {
sm_warning("passing a valid pointer to '%s'", fn);
return;
}
- if (!rl_to_sval(estate_rl(tmp->state), &sval))
- continue;
- if (sval.value != 0)
- continue;
- sm_warning("passing zero to '%s'", fn);
- return;
} END_FOR_EACH_PTR(tmp);
}
diff --git a/usr/src/tools/smatch/src/evaluate.c b/usr/src/tools/smatch/src/evaluate.c
index 8f07d08cf5..14abc8fa5c 100644
--- a/usr/src/tools/smatch/src/evaluate.c
+++ b/usr/src/tools/smatch/src/evaluate.c
@@ -1946,7 +1946,7 @@ static struct symbol *evaluate_preop(struct expression *expr)
return ctype;
}
-static struct symbol *find_identifier(struct ident *ident, struct symbol_list *_list, int *offset)
+struct symbol *find_identifier(struct ident *ident, struct symbol_list *_list, int *offset)
{
struct ptr_list *head = (struct ptr_list *)_list;
struct ptr_list *list = head;
diff --git a/usr/src/tools/smatch/src/expression.h b/usr/src/tools/smatch/src/expression.h
index 78813602b8..214313786d 100644
--- a/usr/src/tools/smatch/src/expression.h
+++ b/usr/src/tools/smatch/src/expression.h
@@ -261,6 +261,7 @@ struct token *assignment_expression(struct token *token, struct expression **tre
extern void evaluate_symbol_list(struct symbol_list *list);
extern struct symbol *evaluate_statement(struct statement *stmt);
extern struct symbol *evaluate_expression(struct expression *);
+struct symbol *find_identifier(struct ident *ident, struct symbol_list *_list, int *offset);
extern int expand_symbol(struct symbol *);
diff --git a/usr/src/tools/smatch/src/graph.c b/usr/src/tools/smatch/src/graph.c
index 22c90be936..8cbc220273 100644
--- a/usr/src/tools/smatch/src/graph.c
+++ b/usr/src/tools/smatch/src/graph.c
@@ -1,4 +1,4 @@
-/* Copyright © International Business Machines Corp., 2006
+/* Copyright © International Business Machines Corp., 2006
* Adelard LLP, 2007
*
* Author: Josh Triplett <josh@freedesktop.org>
diff --git a/usr/src/tools/smatch/src/smatch.c b/usr/src/tools/smatch/src/smatch.c
index 450caeef40..e0fb1bd818 100644
--- a/usr/src/tools/smatch/src/smatch.c
+++ b/usr/src/tools/smatch/src/smatch.c
@@ -21,6 +21,7 @@
#include <unistd.h>
#include <libgen.h>
#include "smatch.h"
+#include "smatch_slist.h"
#include "check_list.h"
char *option_debug_check = (char *)"";
@@ -38,7 +39,6 @@ int option_call_tree = 0;
int option_no_db = 0;
int option_enable = 0;
int option_disable = 0;
-int option_debug_related;
int option_file_output;
int option_time;
int option_mem;
@@ -231,8 +231,6 @@ void parse_args(int *argcp, char ***argvp)
OPTION(spammy);
OPTION(info);
OPTION(debug);
- OPTION(debug_implied);
- OPTION(debug_related);
OPTION(assume_loops);
OPTION(no_data);
OPTION(two_passes);
@@ -322,6 +320,7 @@ static char *get_data_dir(char *arg0)
int main(int argc, char **argv)
{
+ struct string_list *filelist = NULL;
int i;
reg_func func;
@@ -343,8 +342,12 @@ int main(int argc, char **argv)
data_dir = get_data_dir(argv[0]);
allocate_hook_memory();
+ allocate_dynamic_states_array(num_checks);
create_function_hook_hash();
open_smatch_db(option_db_file);
+ sparse_initialize(argc, argv, &filelist);
+ alloc_valid_ptr_rl();
+
for (i = 1; i < ARRAY_SIZE(reg_funcs); i++) {
func = reg_funcs[i].func;
/* The script IDs start at 1.
@@ -355,7 +358,7 @@ int main(int argc, char **argv)
func(i);
}
- smatch(argc, argv);
+ smatch(filelist);
free_string(data_dir);
if (option_succeed)
diff --git a/usr/src/tools/smatch/src/smatch.h b/usr/src/tools/smatch/src/smatch.h
index 285321b039..3b94e6577d 100644
--- a/usr/src/tools/smatch/src/smatch.h
+++ b/usr/src/tools/smatch/src/smatch.h
@@ -79,8 +79,6 @@ struct sm_state {
struct symbol *sym;
unsigned short owner;
unsigned short merged:1;
- unsigned short skip_implications:1;
- unsigned int nr_children;
unsigned int line;
struct smatch_state *state;
struct stree *pool;
@@ -102,6 +100,11 @@ struct constraint {
};
DECLARE_PTR_LIST(constraint_list, struct constraint);
+struct bit_info {
+ unsigned long long set;
+ unsigned long long possible;
+};
+
enum hook_type {
EXPR_HOOK,
STMT_HOOK,
@@ -175,6 +178,8 @@ void add_macro_assign_hook_extra(const char *look_for, func_hook *call_back,
void *info);
void return_implies_state(const char *look_for, long long start, long long end,
implication_hook *call_back, void *info);
+void return_implies_state_sval(const char *look_for, sval_t start, sval_t end,
+ implication_hook *call_back, void *info);
void select_return_states_hook(int type, return_implies_hook *callback);
void select_return_states_before(void (*fn)(void));
void select_return_states_after(void (*fn)(void));
@@ -207,6 +212,7 @@ extern char *trace_variable;
extern struct stree *global_states;
int is_skipped_function(void);
int is_silenced_function(void);
+extern bool implications_off;
/* smatch_impossible.c */
int is_impossible_path(void);
@@ -366,6 +372,7 @@ void append(char *dest, const char *data, int buff_len);
void remove_parens(char *str);
struct smatch_state *alloc_state_num(int num);
struct smatch_state *alloc_state_str(const char *name);
+struct smatch_state *merge_str_state(struct smatch_state *s1, struct smatch_state *s2);
struct smatch_state *alloc_state_expr(struct expression *expr);
struct expression *get_argument_from_call_expr(struct expression_list *args,
int num);
@@ -393,7 +400,7 @@ int get_fuzzy_max(struct expression *expr, sval_t *max);
int get_absolute_min(struct expression *expr, sval_t *sval);
int get_absolute_max(struct expression *expr, sval_t *sval);
int parse_call_math(struct expression *expr, char *math, sval_t *val);
-int parse_call_math_rl(struct expression *call, char *math, struct range_list **rl);
+int parse_call_math_rl(struct expression *call, const char *math, struct range_list **rl);
char *get_value_in_terms_of_parameter_math(struct expression *expr);
char *get_value_in_terms_of_parameter_math_var_sym(const char *var, struct symbol *sym);
int is_zero(struct expression *expr);
@@ -429,6 +436,7 @@ int ms_since(struct timeval *start);
int parent_is_gone_var_sym(const char *name, struct symbol *sym);
int parent_is_gone(struct expression *expr);
int invert_op(int op);
+int op_remove_assign(int op);
int expr_equiv(struct expression *one, struct expression *two);
void push_int(struct int_stack **stack, int num);
int pop_int(struct int_stack **stack);
@@ -506,7 +514,7 @@ extern int __in_fake_assign;
extern int __in_fake_parameter_assign;
extern int __in_fake_struct_assign;
extern int in_fake_env;
-void smatch (int argc, char **argv);
+void smatch (struct string_list *filelist);
int inside_loop(void);
int definitely_inside_loop(void);
struct expression *get_switch_expr(void);
@@ -536,6 +544,7 @@ extern struct statement *__next_stmt;
void init_fake_env(void);
void end_fake_env(void);
int time_parsing_function(void);
+bool taking_too_long(void);
/* smatch_struct_assignment.c */
struct expression *get_faked_expression(void);
@@ -553,8 +562,6 @@ int __handle_select_assigns(struct expression *expr);
int __handle_expr_statement_assigns(struct expression *expr);
/* smatch_implied.c */
-extern int option_debug_implied;
-extern int option_debug_related;
struct range_list_stack;
void param_limit_implications(struct expression *expr, int param, char *key, char *value);
struct stree *__implied_case_stree(struct expression *switch_expr,
@@ -566,7 +573,12 @@ int assume(struct expression *expr);
void end_assume(void);
int impossible_assumption(struct expression *left, int op, sval_t sval);
+/* smatch_slist.h */
+bool has_dynamic_states(unsigned short owner);
+void set_dynamic_states(unsigned short owner);
+
/* smatch_extras.c */
+int in_warn_on_macro(void);
#define SMATCH_EXTRA 5 /* this is my_id from smatch extra set in smatch.c */
extern int RETURN_ID;
@@ -577,79 +589,83 @@ struct data_range {
#define MTAG_ALIAS_BIT (1ULL << 63)
#define MTAG_OFFSET_MASK 0xfffULL
+#define MTAG_SEED 0xdead << 12
-extern long long valid_ptr_min, valid_ptr_max;
-extern sval_t valid_ptr_min_sval, valid_ptr_max_sval;
+const extern unsigned long valid_ptr_min;
+extern unsigned long valid_ptr_max;
+extern const sval_t valid_ptr_min_sval;
+extern sval_t valid_ptr_max_sval;
extern struct range_list *valid_ptr_rl;
+void alloc_valid_ptr_rl(void);
+
static const sval_t array_min_sval = {
.type = &ptr_ctype,
{.value = 100000},
};
static const sval_t array_max_sval = {
.type = &ptr_ctype,
- {.value = 199999},
+ {.value = ULONG_MAX - 4095},
};
static const sval_t text_seg_min = {
.type = &ptr_ctype,
- {.value = 100000000},
+ {.value = 4096},
};
static const sval_t text_seg_max = {
.type = &ptr_ctype,
- {.value = 177777777},
+ {.value = ULONG_MAX - 4095},
};
static const sval_t data_seg_min = {
.type = &ptr_ctype,
- {.value = 200000000},
+ {.value = 4096},
};
static const sval_t data_seg_max = {
.type = &ptr_ctype,
- {.value = 277777777},
+ {.value = ULONG_MAX - 4095},
};
static const sval_t bss_seg_min = {
.type = &ptr_ctype,
- {.value = 300000000},
+ {.value = 4096},
};
static const sval_t bss_seg_max = {
.type = &ptr_ctype,
- {.value = 377777777},
+ {.value = ULONG_MAX - 4095},
};
static const sval_t stack_seg_min = {
.type = &ptr_ctype,
- {.value = 400000000},
+ {.value = 4096},
};
static const sval_t stack_seg_max = {
.type = &ptr_ctype,
- {.value = 477777777},
+ {.value = ULONG_MAX - 4095},
};
static const sval_t kmalloc_seg_min = {
.type = &ptr_ctype,
- {.value = 500000000},
+ {.value = 4096},
};
static const sval_t kmalloc_seg_max = {
.type = &ptr_ctype,
- {.value = 577777777},
+ {.value = ULONG_MAX - 4095},
};
static const sval_t vmalloc_seg_min = {
.type = &ptr_ctype,
- {.value = 600000000},
+ {.value = 4096},
};
static const sval_t vmalloc_seg_max = {
.type = &ptr_ctype,
- {.value = 677777777},
+ {.value = ULONG_MAX - 4095},
};
static const sval_t fn_ptr_min = {
.type = &ptr_ctype,
- {.value = 700000000},
+ {.value = 4096},
};
static const sval_t fn_ptr_max = {
.type = &ptr_ctype,
- {.value = 777777777},
+ {.value = ULONG_MAX - 4095},
};
char *get_other_name_sym(const char *name, struct symbol *sym, struct symbol **new_sym);
char *map_call_to_other_name_sym(const char *name, struct symbol *sym, struct symbol **new_sym);
-char *map_long_to_short_name_sym(const char *name, struct symbol *sym, struct symbol **new_sym);
-char *map_long_to_short_name_sym_nostack(const char *name, struct symbol *sym, struct symbol **new_sym);
+char *map_long_to_short_name_sym(const char *name, struct symbol *sym, struct symbol **new_sym, bool use_stack);
#define STRLEN_MAX_RET 1010101
@@ -783,7 +799,6 @@ enum info_type {
PARAM_VALUE = 1001,
BUF_SIZE = 1002,
- USER_DATA = 1003,
CAPPED_DATA = 1004,
RETURN_VALUE = 1005,
DEREFERENCE = 1006,
@@ -795,6 +810,7 @@ enum info_type {
PARAM_FREED = 1013,
DATA_SOURCE = 1014,
FUZZY_MAX = 1015,
+ HARD_MAX = 2015,
STR_LEN = 1016,
ARRAY_LEN = 1017,
CAPABLE = 1018,
@@ -803,6 +819,7 @@ enum info_type {
CASTED_CALL = 1021,
TYPE_LINK = 1022,
UNTRACKED_PARAM = 1023,
+ LOST_PARAM = 2023,
CULL_PATH = 1024,
PARAM_SET = 1025,
PARAM_USED = 1026,
@@ -812,14 +829,15 @@ enum info_type {
CONSTRAINT = 1031,
PASSES_TYPE = 1032,
CONSTRAINT_REQUIRED = 1033,
+ BIT_INFO = 1034,
NOSPEC = 1035,
NOSPEC_WB = 1036,
STMT_CNT = 1037,
TERMINATED = 1038,
/* put random temporary stuff in the 7000-7999 range for testing */
- USER_DATA3 = 8017,
- USER_DATA3_SET = 9017,
+ USER_DATA = 8017,
+ USER_DATA_SET = 9017,
NO_OVERFLOW = 8018,
NO_OVERFLOW_SIMPLE = 8019,
LOCKED = 8020,
@@ -835,6 +853,12 @@ enum info_type {
MEMORY_TAG = 8036,
MTAG_ASSIGN = 8035,
STRING_VALUE = 8041,
+
+ BYTE_COUNT = 8050,
+ ELEM_COUNT = 8051,
+ ELEM_LAST = 8052,
+ USED_LAST = 8053,
+ USED_COUNT = 8054,
};
extern struct sqlite3 *smatch_db;
@@ -859,6 +883,7 @@ const char *get_param_name(struct sm_state *sm);
const char *get_mtag_name_var_sym(const char *state_name, struct symbol *sym);
const char *get_mtag_name_expr(struct expression *expr);
char *get_data_info_name(struct expression *expr);
+int is_recursive_member(const char *param_name);
char *escape_newlines(const char *str);
void sql_exec(struct sqlite3 *db, int (*callback)(void*, int, char**, char**), void *data, const char *sql);
@@ -952,11 +977,12 @@ void sql_copy_constraint_required(const char *new_limit, const char *old_limit);
void sql_insert_fn_ptr_data_link(const char *ptr, const char *data);
void sql_insert_fn_data_link(struct expression *fn, int type, int param, const char *key, const char *value);
void sql_insert_mtag_about(mtag_t tag, const char *left_name, const char *right_name);
-void insert_mtag_data(sval_t sval, struct range_list *rl);
void sql_insert_mtag_map(mtag_t tag, int offset, mtag_t container);
void sql_insert_mtag_alias(mtag_t orig, mtag_t alias);
int mtag_map_select_container(mtag_t tag, int offset, mtag_t *container);
int mtag_map_select_tag(mtag_t container, int offset, mtag_t *tag);
+struct smatch_state *swap_mtag_return(struct expression *expr, struct smatch_state *state);
+struct range_list *swap_mtag_seed(struct expression *expr, struct range_list *rl);
void sql_select_return_states(const char *cols, struct expression *call,
int (*callback)(void*, int, char**, char**), void *info);
@@ -1012,14 +1038,14 @@ int is_capped_var_sym(const char *name, struct symbol *sym);
/* check_user_data.c */
int is_user_macro(struct expression *expr);
-int is_user_data(struct expression *expr);
int is_capped_user_data(struct expression *expr);
int implied_user_data(struct expression *expr, struct range_list **rl);
struct stree *get_user_stree(void);
int get_user_rl(struct expression *expr, struct range_list **rl);
-int get_user_rl_spammy(struct expression *expr, struct range_list **rl);
int is_user_rl(struct expression *expr);
int get_user_rl_var_sym(const char *name, struct symbol *sym, struct range_list **rl);
+bool user_rl_capped(struct expression *expr);
+struct range_list *var_user_rl(struct expression *expr);
/* check_locking.c */
void print_held_locks();
@@ -1055,6 +1081,7 @@ int combine_comparisons(int left_compare, int right_compare);
int state_to_comparison(struct smatch_state *state);
struct smatch_state *merge_compare_states(struct smatch_state *s1, struct smatch_state *s2);
int get_comparison(struct expression *left, struct expression *right);
+int get_comparison_no_extra(struct expression *a, struct expression *b);
int get_comparison_strings(const char *one, const char *two);
int possible_comparison(struct expression *a, int comparison, struct expression *b);
struct state_list *get_all_comparisons(struct expression *expr);
@@ -1109,15 +1136,18 @@ sval_t sval_preop(sval_t sval, int op);
sval_t sval_binop(sval_t left, int op, sval_t right);
int sval_binop_overflows(sval_t left, int op, sval_t right);
int sval_binop_overflows_no_sign(sval_t left, int op, sval_t right);
+int find_first_zero_bit(unsigned long long uvalue);
+int sm_fls64(unsigned long long uvalue);
unsigned long long fls_mask(unsigned long long uvalue);
unsigned long long sval_fls_mask(sval_t sval);
const char *sval_to_str(sval_t sval);
+const char *sval_to_str_or_err_ptr(sval_t sval);
const char *sval_to_numstr(sval_t sval);
sval_t ll_to_sval(long long val);
/* smatch_string_list.c */
int list_has_string(struct string_list *str_list, const char *str);
-void insert_string(struct string_list **str_list, const char *str);
+int insert_string(struct string_list **str_list, const char *str);
struct string_list *clone_str_list(struct string_list *orig);
struct string_list *combine_string_lists(struct string_list *one, struct string_list *two);
@@ -1138,6 +1168,7 @@ struct sm_state *stored_condition_implication_hook(struct expression *expr,
/* check_string_len.c */
int get_formatted_string_size(struct expression *call, int arg);
+int get_formatted_string_min_size(struct expression *call, int arg);
/* smatch_param_set.c */
int param_was_set(struct expression *expr);
@@ -1154,12 +1185,15 @@ void store_link(int link_id, const char *name, struct symbol *sym, const char *l
void set_auto_copy(int owner);
/* check_buf_comparison */
-struct expression *get_size_variable(struct expression *buf);
+const char *limit_type_str(unsigned int limit_type);
+struct expression *get_size_variable(struct expression *buf, int *limit_type);
struct expression *get_array_variable(struct expression *size);
+int buf_comparison_index_ok(struct expression *expr);
/* smatch_untracked_param.c */
void mark_untracked(struct expression *expr, int param, const char *key, const char *value);
void add_untracked_param_hook(void (func)(struct expression *call, int param));
+void add_lost_param_hook(void (func)(struct expression *call, int param));
void mark_all_params_untracked(int return_id, char *return_ranges, struct expression *expr);
/* smatch_strings.c */
@@ -1194,53 +1228,61 @@ char *get_required_constraint(const char *data_str);
/* smatch_container_of.c */
int get_param_from_container_of(struct expression *expr);
int get_offset_from_container_of(struct expression *expr);
+char *get_container_name(struct expression *container, struct expression *expr);
/* smatch_mtag.c */
int get_string_mtag(struct expression *expr, mtag_t *tag);
int get_toplevel_mtag(struct symbol *sym, mtag_t *tag);
-int get_mtag(struct expression *expr, mtag_t *tag);
-int get_mtag_offset(struct expression *expr, mtag_t *tag, int *offset);
int create_mtag_alias(mtag_t tag, struct expression *expr, mtag_t *new);
int expr_to_mtag_offset(struct expression *expr, mtag_t *tag, int *offset);
void update_mtag_data(struct expression *expr);
int get_mtag_sval(struct expression *expr, sval_t *sval);
-int get_mtag_addr_sval(struct expression *expr, sval_t *sval);
/* Trinity fuzzer stuff */
const char *get_syscall_arg_type(struct symbol *sym);
+/* smatch_bit_info.c */
+struct bit_info *get_bit_info(struct expression *expr);
+struct bit_info *get_bit_info_var_sym(const char *name, struct symbol *sym);
/* smatch_mem_tracker.c */
extern int option_mem;
+unsigned long get_mem_kb(void);
unsigned long get_max_memory(void);
/* check_is_nospec.c */
bool is_nospec(struct expression *expr);
+long get_stmt_cnt(void);
/* smatch_nul_terminator.c */
bool is_nul_terminated(struct expression *expr);
+/* check_kernel.c */
+bool is_ignored_kernel_data(const char *name);
+
+static inline bool type_is_ptr(struct symbol *type)
+{
+ return type &&
+ (type->type == SYM_PTR ||
+ type->type == SYM_ARRAY ||
+ type->type == SYM_FN);
+}
static inline int type_bits(struct symbol *type)
{
if (!type)
return 0;
- if (type->type == SYM_PTR) /* Sparse doesn't set this for &pointers */
- return bits_in_pointer;
- if (type->type == SYM_ARRAY)
+ if (type_is_ptr(type))
return bits_in_pointer;
if (!type->examined)
examine_symbol_type(type);
return type->bit_size;
}
-static inline bool type_is_ptr(struct symbol *type)
-{
- return type && (type->type == SYM_PTR || type->type == SYM_ARRAY);
-}
-
static inline int type_unsigned(struct symbol *base_type)
{
if (!base_type)
return 0;
+ if (is_ptr_type(base_type))
+ return 1;
if (base_type->ctype.modifiers & MOD_UNSIGNED)
return 1;
return 0;
@@ -1250,8 +1292,8 @@ static inline int type_positive_bits(struct symbol *type)
{
if (!type)
return 0;
- if (type->type == SYM_ARRAY)
- return bits_in_pointer - 1;
+ if (is_ptr_type(type))
+ return bits_in_pointer;
if (type_unsigned(type))
return type_bits(type);
return type_bits(type) - 1;
diff --git a/usr/src/tools/smatch/src/smatch_about_fn_ptr_arg.c b/usr/src/tools/smatch/src/smatch_about_fn_ptr_arg.c
index 347833f7d2..cbf0355603 100644
--- a/usr/src/tools/smatch/src/smatch_about_fn_ptr_arg.c
+++ b/usr/src/tools/smatch/src/smatch_about_fn_ptr_arg.c
@@ -139,7 +139,7 @@ static char *get_data_member(char *fn_member, struct expression *expr, struct sy
}
strncpy(buf, fn_str, sizeof(buf));
- snprintf(buf + len_str, sizeof(buf) - len_str, end_type);
+ snprintf(buf + len_str, sizeof(buf) - len_str, "%s", end_type);
*sym = tmp_sym;
return alloc_string(buf);
}
diff --git a/usr/src/tools/smatch/src/smatch_address.c b/usr/src/tools/smatch/src/smatch_address.c
index 5c48e05fdb..539492a023 100644
--- a/usr/src/tools/smatch/src/smatch_address.c
+++ b/usr/src/tools/smatch/src/smatch_address.c
@@ -62,22 +62,53 @@ static bool is_non_null_array(struct expression *expr)
return 0;
}
+static bool matches_anonymous_union(struct symbol *sym, const char *member_name)
+{
+ struct symbol *type, *tmp;
+
+ if (sym->ident)
+ return false;
+ type = get_real_base_type(sym);
+ if (!type || type->type != SYM_UNION)
+ return false;
+
+ FOR_EACH_PTR(type->symbol_list, tmp) {
+ if (tmp->ident &&
+ strcmp(member_name, tmp->ident->name) == 0) {
+ return true;
+ }
+ } END_FOR_EACH_PTR(tmp);
+
+ return false;
+}
+
int get_member_offset(struct symbol *type, const char *member_name)
{
struct symbol *tmp;
int offset;
+ int bits;
if (!type || type->type != SYM_STRUCT)
return -1;
+ bits = 0;
offset = 0;
FOR_EACH_PTR(type->symbol_list, tmp) {
+ if (bits_to_bytes(bits + type_bits(tmp)) > tmp->ctype.alignment) {
+ offset += bits_to_bytes(bits);
+ bits = 0;
+ }
offset = ALIGN(offset, tmp->ctype.alignment);
if (tmp->ident &&
strcmp(member_name, tmp->ident->name) == 0) {
return offset;
}
- offset += type_bytes(tmp);
+ if (matches_anonymous_union(tmp, member_name))
+ return offset;
+ if (!(type_bits(tmp) % 8) && type_bits(tmp) / 8 == type_bytes(tmp))
+ offset += type_bytes(tmp);
+ else
+ bits += type_bits(tmp);
} END_FOR_EACH_PTR(tmp);
return -1;
}
@@ -99,6 +130,8 @@ int get_member_offset_from_deref(struct expression *expr)
return -1;
type = get_type(expr->deref);
+ if (type_is_ptr(type))
+ type = get_real_base_type(type);
if (!type || type->type != SYM_STRUCT)
return -1;
@@ -108,23 +141,6 @@ int get_member_offset_from_deref(struct expression *expr)
return offset;
}
-static struct range_list *filter_unknown_negatives(struct range_list *rl)
-{
- struct data_range *first;
- struct range_list *filter = NULL;
-
- first = first_ptr_list((struct ptr_list *)rl);
-
- if (sval_is_min(first->min) &&
- sval_is_negative(first->max) &&
- first->max.value == -1) {
- add_ptr_list(&filter, first);
- return rl_filter(rl, filter);
- }
-
- return rl;
-}
-
static void add_offset_to_pointer(struct range_list **rl, int offset)
{
sval_t min, max, remove, sval;
@@ -138,6 +154,9 @@ static void add_offset_to_pointer(struct range_list **rl, int offset)
if (offset == 0)
return;
+ if (is_unknown_ptr(orig))
+ return;
+
/*
* This function doesn't necessarily work how you might expect...
*
@@ -164,16 +183,6 @@ static void add_offset_to_pointer(struct range_list **rl, int offset)
return;
}
- orig = filter_unknown_negatives(orig);
- /*
- * FIXME: This is not really accurate but we're a bit screwed anyway
- * when we start doing pointer math with error pointers so it's probably
- * not important.
- *
- */
- if (sval_is_negative(rl_min(orig)))
- return;
-
/* no wrap around */
max.uvalue = rl_max(orig).uvalue;
if (max.uvalue > sval_type_max(&ptr_ctype).uvalue - offset) {
@@ -193,52 +202,94 @@ static struct range_list *where_allocated_rl(struct symbol *sym)
if (!sym)
return NULL;
- if (sym->ctype.modifiers & (MOD_TOPLEVEL | MOD_STATIC)) {
- if (sym->initializer)
- return alloc_rl(data_seg_min, data_seg_max);
- else
- return alloc_rl(bss_seg_min, bss_seg_max);
- }
- return alloc_rl(stack_seg_min, stack_seg_max);
+ return alloc_rl(valid_ptr_min_sval, valid_ptr_max_sval);
}
int get_address_rl(struct expression *expr, struct range_list **rl)
{
+ struct expression *unop;
+
expr = strip_expr(expr);
if (!expr)
return 0;
if (expr->type == EXPR_STRING) {
- *rl = alloc_rl(text_seg_min, text_seg_max);
+ *rl = alloc_rl(valid_ptr_min_sval, valid_ptr_max_sval);
return 1;
}
- if (expr->type == EXPR_PREOP && expr->op == '&') {
- struct expression *unop;
+ if (expr->type == EXPR_PREOP && expr->op == '&')
+ expr = strip_expr(expr->unop);
+ else {
+ struct symbol *type;
- unop = strip_expr(expr->unop);
- if (unop->type == EXPR_SYMBOL) {
- *rl = where_allocated_rl(unop->symbol);
+ type = get_type(expr);
+ if (!type || type->type != SYM_ARRAY)
+ return 0;
+ }
+
+ if (expr->type == EXPR_SYMBOL) {
+ *rl = where_allocated_rl(expr->symbol);
+ return 1;
+ }
+
+ if (is_array(expr)) {
+ struct expression *array;
+ struct expression *offset_expr;
+ struct range_list *array_rl, *offset_rl, *bytes_rl, *res;
+ struct symbol *type;
+ sval_t bytes;
+
+ array = get_array_base(expr);
+ offset_expr = get_array_offset(expr);
+
+ type = get_type(array);
+ type = get_real_base_type(type);
+ bytes.type = ssize_t_ctype;
+ bytes.uvalue = type_bytes(type);
+ bytes_rl = alloc_rl(bytes, bytes);
+
+ get_absolute_rl(array, &array_rl);
+ get_absolute_rl(offset_expr, &offset_rl);
+
+ if (type_bytes(type)) {
+ res = rl_binop(offset_rl, '*', bytes_rl);
+ res = rl_binop(res, '+', array_rl);
+ *rl = res;
+ return true;
+ }
+
+ if (implied_not_equal(array, 0) ||
+ implied_not_equal(offset_expr, 0)) {
+ *rl = alloc_rl(valid_ptr_min_sval, valid_ptr_max_sval);
return 1;
}
- if (unop->type == EXPR_DEREF) {
- int offset = get_member_offset_from_deref(unop);
+ return 0;
+ }
+
+ if (expr->type == EXPR_DEREF && expr->member) {
+ struct range_list *unop_rl;
+ int offset;
+ offset = get_member_offset_from_deref(expr);
+ unop = strip_expr(expr->unop);
+ if (unop->type == EXPR_PREOP && unop->op == '*')
unop = strip_expr(unop->unop);
- if (unop->type == EXPR_SYMBOL) {
- *rl = where_allocated_rl(unop->symbol);
- } else if (unop->type == EXPR_PREOP && unop->op == '*') {
- unop = strip_expr(unop->unop);
- get_absolute_rl(unop, rl);
- } else {
- return 0;
- }
+ if (offset >= 0 &&
+ get_implied_rl(unop, &unop_rl) &&
+ !is_whole_rl(unop_rl)) {
+ *rl = unop_rl;
add_offset_to_pointer(rl, offset);
return 1;
}
+ if (implied_not_equal(unop, 0) || offset > 0) {
+ *rl = alloc_rl(valid_ptr_min_sval, valid_ptr_max_sval);
+ return 1;
+ }
+
return 0;
}
diff --git a/usr/src/tools/smatch/src/smatch_array_values.c b/usr/src/tools/smatch/src/smatch_array_values.c
index 7627cebc2f..3f9f73383e 100644
--- a/usr/src/tools/smatch/src/smatch_array_values.c
+++ b/usr/src/tools/smatch/src/smatch_array_values.c
@@ -163,7 +163,7 @@ static void match_assign(struct expression *expr)
struct symbol *type;
char *name;
- type = get_type(expr->right);
+ type = get_type(expr->left);
if (!type || type->type != SYM_BASETYPE)
return;
@@ -176,7 +176,8 @@ static void match_assign(struct expression *expr)
return;
if (expr->op != '=') {
- rl = alloc_whole_rl(type);
+ rl = alloc_whole_rl(get_type(expr->right));
+ rl = cast_rl(type, rl);
} else {
get_absolute_rl(expr->right, &rl);
rl = cast_rl(type, rl);
diff --git a/usr/src/tools/smatch/src/smatch_assigned_expr.c b/usr/src/tools/smatch/src/smatch_assigned_expr.c
index b0c2c4f767..188577e42c 100644
--- a/usr/src/tools/smatch/src/smatch_assigned_expr.c
+++ b/usr/src/tools/smatch/src/smatch_assigned_expr.c
@@ -28,8 +28,12 @@ int check_assigned_expr_id;
static int my_id;
static int link_id;
+static struct expression *skip_mod;
+
static void undef(struct sm_state *sm, struct expression *mod_expr)
{
+ if (mod_expr == skip_mod)
+ return;
set_state(my_id, sm->name, sm->sym, &undefined);
}
@@ -55,6 +59,7 @@ struct expression *get_assigned_expr_name_sym(const char *name, struct symbol *s
static void match_assignment(struct expression *expr)
{
+ static struct expression *ignored_expr;
struct symbol *left_sym, *right_sym;
char *left_name = NULL;
char *right_name = NULL;
@@ -72,6 +77,12 @@ static void match_assignment(struct expression *expr)
return;
}
+ if (expr->left == ignored_expr)
+ return;
+ ignored_expr = NULL;
+ if (__in_fake_parameter_assign)
+ ignored_expr = expr->left;
+
left_name = expr_to_var_sym(expr->left, &left_sym);
if (!left_name || !left_sym)
goto free;
@@ -118,6 +129,7 @@ static void record_param_assignment(struct expression *expr, int param, char *ke
if (!name || !sym)
goto free;
+ skip_mod = expr;
set_state(my_id, name, sym, alloc_state_expr(right));
free:
free_string(name);
@@ -126,6 +138,7 @@ free:
void register_assigned_expr(int id)
{
my_id = check_assigned_expr_id = id;
+ set_dynamic_states(check_assigned_expr_id);
add_hook(&match_assignment, ASSIGNMENT_HOOK_AFTER);
add_modification_hook(my_id, &undef);
select_return_states_hook(PARAM_SET, &record_param_assignment);
@@ -134,6 +147,7 @@ void register_assigned_expr(int id)
void register_assigned_expr_links(int id)
{
link_id = id;
+ set_dynamic_states(link_id);
db_ignore_states(link_id);
set_up_link_functions(my_id, link_id);
}
diff --git a/usr/src/tools/smatch/src/smatch_bits.c b/usr/src/tools/smatch/src/smatch_bits.c
new file mode 100644
index 0000000000..0492203836
--- /dev/null
+++ b/usr/src/tools/smatch/src/smatch_bits.c
@@ -0,0 +1,450 @@
+/*
+ * Copyright (C) 2015 Oracle.
+ *
+ * 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 program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
+ */
+
+/*
+ * This is to track when variables are masked away.
+ *
+ */
+
+#include "smatch.h"
+#include "smatch_extra.h"
+#include "smatch_slist.h"
+
+static int my_id;
+
+static const struct bit_info unknown_bit_info = {
+ .possible = -1ULL,
+};
+
+ALLOCATOR(bit_info, "bit data");
+static struct bit_info *alloc_bit_info(unsigned long long set, unsigned long long possible)
+{
+ struct bit_info *bit_info = __alloc_bit_info(0);
+
+ bit_info->set = set;
+ bit_info->possible = possible;
+
+ return bit_info;
+}
+
+static struct smatch_state *alloc_bstate(unsigned long long set, unsigned long long possible)
+{
+ struct smatch_state *state;
+ char buf[64];
+
+ state = __alloc_smatch_state(0);
+ snprintf(buf, sizeof(buf), "0x%llx + 0x%llx", set, possible);
+ state->name = alloc_sname(buf);
+ state->data = alloc_bit_info(set, possible);
+
+ return state;
+}
+
+static struct bit_info *rl_to_binfo(struct range_list *rl)
+{
+ struct bit_info *ret = __alloc_bit_info(0);
+ sval_t sval;
+
+ if (rl_to_sval(rl, &sval)) {
+ ret->set = sval.uvalue;
+ ret->possible = sval.uvalue;
+
+ return ret;
+ }
+
+ ret->set = 0;
+ ret->possible = sval_fls_mask(rl_max(rl));
+ // FIXME: what about negatives?
+
+ return ret;
+}
+
+static int is_unknown_binfo(struct symbol *type, struct bit_info *binfo)
+{
+ if (!type)
+ type = &ullong_ctype;
+
+ if (binfo->set != 0)
+ return 0;
+ if (binfo->possible < (-1ULL >> (64 - type_bits(type))))
+ return 0;
+
+ return 1;
+}
+
+static struct smatch_state *unmatched_state(struct sm_state *sm)
+{
+ struct smatch_state *estate;
+ struct symbol *type;
+ unsigned long long possible;
+ struct bit_info *p;
+
+ estate = get_state(SMATCH_EXTRA, sm->name, sm->sym);
+ if (estate_rl(estate)) {
+ p = rl_to_binfo(estate_rl(estate));
+ return alloc_bstate(p->set, p->possible);
+ }
+
+ type = estate_type(estate);
+ if (!type)
+ return alloc_bstate(0, -1ULL);
+
+ if (type_bits(type) == 64)
+ possible = -1ULL;
+ else
+ possible = (1ULL << type_bits(type)) - 1;
+
+ return alloc_bstate(0, possible);
+}
+
+static void match_modify(struct sm_state *sm, struct expression *mod_expr)
+{
+ // FIXME: we really need to store the type
+
+ set_state(my_id, sm->name, sm->sym, alloc_bstate(0, -1ULL));
+}
+
+static int binfo_equiv(struct bit_info *one, struct bit_info *two)
+{
+ if (one->set == two->set &&
+ one->possible == two->possible)
+ return 1;
+ return 0;
+}
+
+static struct smatch_state *merge_bstates(struct smatch_state *one_state, struct smatch_state *two_state)
+{
+ struct bit_info *one, *two;
+
+ one = one_state->data;
+ two = two_state->data;
+
+ if (binfo_equiv(one, two))
+ return one_state;
+
+ return alloc_bstate(one->set & two->set, one->possible | two->possible);
+}
+
+/*
+ * The combine_bit_info() takes two bit_infos and takes creates the most
+ * accurate picture we can assuming both are true. Or it returns unknown if
+ * the information is logically impossible.
+ *
+ * Which means that it takes the | of the ->set bits and the & of the possibly
+ * set bits, which is the opposite of what merge_bstates() does.
+ *
+ */
+static struct bit_info *combine_bit_info(struct bit_info *one, struct bit_info *two)
+{
+ struct bit_info *ret = __alloc_bit_info(0);
+
+ if ((one->set & two->possible) != one->set)
+ return alloc_bit_info(0, -1ULL);
+ if ((two->set & one->possible) != two->set)
+ return alloc_bit_info(0, -1ULL);
+
+ ret->set = one->set | two->set;
+ ret->possible = one->possible & two->possible;
+
+ return ret;
+}
+
+static struct bit_info *binfo_AND(struct bit_info *left, struct bit_info *right)
+{
+ unsigned long long set = 0;
+ unsigned long long possible = -1ULL;
+
+ if (!left && !right) {
+ /* nothing */
+ } else if (!left) {
+ possible = right->possible;
+ } else if (!right) {
+ possible = left->possible;
+ } else {
+ set = left->set & right->set;
+ possible = left->possible & right->possible;
+ }
+
+ return alloc_bit_info(set, possible);
+}
+
+static struct bit_info *binfo_OR(struct bit_info *left, struct bit_info *right)
+{
+ unsigned long long set = 0;
+ unsigned long long possible = -1ULL;
+
+ if (!left && !right) {
+ /* nothing */
+ } else if (!left) {
+ set = right->set;
+ } else if (!right) {
+ set = left->set;
+ } else {
+ set = left->set | right->set;
+ possible = left->possible | right->possible;
+ }
+
+ return alloc_bit_info(set, possible);
+}
+
+struct bit_info *get_bit_info(struct expression *expr)
+{
+ struct range_list *rl;
+ struct smatch_state *bstate;
+ struct bit_info tmp;
+ struct bit_info *extra_info;
+ struct bit_info *bit_info;
+ sval_t known;
+
+ expr = strip_parens(expr);
+
+ if (get_implied_value(expr, &known))
+ return alloc_bit_info(known.value, known.value);
+
+ if (expr->type == EXPR_BINOP) {
+ if (expr->op == '&')
+ return binfo_AND(get_bit_info(expr->left),
+ get_bit_info(expr->right));
+ if (expr->op == '|')
+ return binfo_OR(get_bit_info(expr->left),
+ get_bit_info(expr->right));
+ }
+
+ if (get_implied_rl(expr, &rl))
+ extra_info = rl_to_binfo(rl);
+ else {
+ struct symbol *type;
+
+ tmp = unknown_bit_info;
+ extra_info = &tmp;
+
+ type = get_type(expr);
+ if (!type)
+ type = &ullong_ctype;
+ if (type_bits(type) == 64)
+ extra_info->possible = -1ULL;
+ else
+ extra_info->possible = (1ULL << type_bits(type)) - 1;
+ }
+
+ bstate = get_state_expr(my_id, expr);
+ if (bstate)
+ bit_info = bstate->data;
+ else
+ bit_info = (struct bit_info *)&unknown_bit_info;
+
+ return combine_bit_info(extra_info, bit_info);
+}
+
+static int is_single_bit(sval_t sval)
+{
+ int i;
+ int count = 0;
+
+ for (i = 0; i < 64; i++) {
+ if (sval.uvalue & 1ULL << i &&
+ count++)
+ return 0;
+ }
+ if (count == 1)
+ return 1;
+ return 0;
+}
+
+static void match_compare(struct expression *expr)
+{
+ sval_t val;
+
+ if (expr->type != EXPR_COMPARE)
+ return;
+ if (expr->op != SPECIAL_EQUAL &&
+ expr->op != SPECIAL_NOTEQUAL)
+ return;
+
+ if (!get_implied_value(expr->right, &val))
+ return;
+
+ set_true_false_states_expr(my_id, expr->left,
+ (expr->op == SPECIAL_EQUAL) ? alloc_bstate(val.uvalue, val.uvalue) : NULL,
+ (expr->op == SPECIAL_EQUAL) ? NULL : alloc_bstate(val.uvalue, val.uvalue));
+}
+
+static bool is_loop_iterator(struct expression *expr)
+{
+ struct statement *pre_stmt, *loop_stmt;
+
+ pre_stmt = expr_get_parent_stmt(expr);
+ if (!pre_stmt || pre_stmt->type != STMT_EXPRESSION)
+ return false;
+
+ loop_stmt = stmt_get_parent_stmt(pre_stmt);
+ if (!loop_stmt || loop_stmt->type != STMT_ITERATOR)
+ return false;
+ if (loop_stmt->iterator_pre_statement != pre_stmt)
+ return false;
+
+ return true;
+}
+
+static void match_assign(struct expression *expr)
+{
+ struct bit_info *binfo;
+
+ if (expr->op != '=')
+ return;
+ if (__in_fake_assign)
+ return;
+ if (is_loop_iterator(expr))
+ return;
+
+ binfo = get_bit_info(expr->right);
+ if (!binfo)
+ return;
+ if (is_unknown_binfo(get_type(expr->left), binfo))
+ return;
+ set_state_expr(my_id, expr->left, alloc_bstate(binfo->set, binfo->possible));
+}
+
+static void match_condition(struct expression *expr)
+{
+ struct bit_info *orig;
+ struct bit_info true_info;
+ struct bit_info false_info;
+ sval_t right;
+
+ if (expr->type != EXPR_BINOP ||
+ expr->op != '&')
+ return;
+
+ if (!get_value(expr->right, &right))
+ return;
+
+ orig = get_bit_info(expr->left);
+ true_info = *orig;
+ false_info = *orig;
+
+ if (right.uvalue == 0 || is_single_bit(right))
+ true_info.set &= right.uvalue;
+
+ true_info.possible &= right.uvalue;
+ false_info.possible &= ~right.uvalue;
+
+ set_true_false_states_expr(my_id, expr->left,
+ alloc_bstate(true_info.set, true_info.possible),
+ alloc_bstate(false_info.set, false_info.possible));
+}
+
+static void match_call_info(struct expression *expr)
+{
+ struct bit_info *binfo, *rl_binfo;
+ struct expression *arg;
+ struct range_list *rl;
+ char buf[64];
+ int i;
+
+ i = -1;
+ FOR_EACH_PTR(expr->args, arg) {
+ i++;
+ binfo = get_bit_info(arg);
+ if (!binfo)
+ continue;
+ if (is_unknown_binfo(get_type(arg), binfo))
+ continue;
+ if (get_implied_rl(arg, &rl)) {
+ rl_binfo = rl_to_binfo(rl);
+ if (binfo_equiv(rl_binfo, binfo))
+ continue;
+ }
+ // If is just non-negative continue
+ // If ->set == ->possible continue
+ snprintf(buf, sizeof(buf), "0x%llx,0x%llx", binfo->set, binfo->possible);
+ sql_insert_caller_info(expr, BIT_INFO, i, "$", buf);
+ } END_FOR_EACH_PTR(arg);
+}
+
+static void struct_member_callback(struct expression *call, int param, char *printed_name, struct sm_state *sm)
+{
+ struct bit_info *binfo = sm->state->data;
+ struct smatch_state *estate;
+ struct bit_info *implied_binfo;
+ char buf[64];
+
+ if (!binfo)
+ return;
+
+ /* This means it can only be one value, so it's handled by smatch_extra. */
+ if (binfo->set == binfo->possible)
+ return;
+
+ estate = get_state(SMATCH_EXTRA, sm->name, sm->sym);
+ if (is_unknown_binfo(estate_type(estate), binfo))
+ return;
+
+ if (estate_rl(estate)) {
+ sval_t sval;
+
+ if (estate_get_single_value(estate, &sval))
+ return;
+
+ implied_binfo = rl_to_binfo(estate_rl(estate));
+ if (binfo_equiv(implied_binfo, binfo))
+ return;
+ }
+
+ snprintf(buf, sizeof(buf), "0x%llx,0x%llx", binfo->set, binfo->possible);
+ sql_insert_caller_info(call, BIT_INFO, param, printed_name, buf);
+}
+
+static void set_param_bits(const char *name, struct symbol *sym, char *key, char *value)
+{
+ char fullname[256];
+ unsigned long long set, possible;
+
+ if (strcmp(key, "*$") == 0)
+ snprintf(fullname, sizeof(fullname), "*%s", name);
+ else if (strncmp(key, "$", 1) == 0)
+ snprintf(fullname, 256, "%s%s", name, key + 1);
+ else
+ return;
+
+ set = strtoull(value, &value, 16);
+ if (*value != ',')
+ return;
+ value++;
+ possible = strtoull(value, &value, 16);
+
+ set_state(my_id, fullname, sym, alloc_bstate(set, possible));
+}
+
+void register_bits(int id)
+{
+ my_id = id;
+
+ set_dynamic_states(my_id);
+
+ add_unmatched_state_hook(my_id, &unmatched_state);
+ add_merge_hook(my_id, &merge_bstates);
+
+ add_hook(&match_condition, CONDITION_HOOK);
+ add_hook(&match_compare, CONDITION_HOOK);
+ add_hook(&match_assign, ASSIGNMENT_HOOK);
+ add_modification_hook(my_id, &match_modify);
+
+ add_hook(&match_call_info, FUNCTION_CALL_HOOK);
+ add_member_info_callback(my_id, struct_member_callback);
+ select_caller_info_hook(set_param_bits, BIT_INFO);
+}
diff --git a/usr/src/tools/smatch/src/smatch_buf_comparison.c b/usr/src/tools/smatch/src/smatch_buf_comparison.c
index d142817a99..f86b0774e6 100644
--- a/usr/src/tools/smatch/src/smatch_buf_comparison.c
+++ b/usr/src/tools/smatch/src/smatch_buf_comparison.c
@@ -29,24 +29,18 @@ static int size_id;
static int link_id;
/*
- * We need this for code which does:
+ * There is a bunch of code which does this:
*
* if (size)
* foo = malloc(size);
*
- * We want to record that the size of "foo" is "size" even after the merge.
+ * So if "size" is non-zero then the size of "foo" is size. But really it's
+ * also true if size is zero. It's just better to assume to not trample over
+ * the data that we have by merging &undefined states.
*
*/
static struct smatch_state *unmatched_state(struct sm_state *sm)
{
- struct expression *size_expr;
- sval_t sval;
-
- if (!sm->state->data)
- return &undefined;
- size_expr = sm->state->data;
- if (!get_implied_value(size_expr, &sval) || sval.value != 0)
- return &undefined;
return sm->state;
}
@@ -82,15 +76,50 @@ static void match_link_modify(struct sm_state *sm, struct expression *mod_expr)
set_state(link_id, sm->name, sm->sym, &undefined);
}
-static struct smatch_state *alloc_expr_state(struct expression *expr)
+static const char *limit_map[] = {
+ "byte_count",
+ "elem_count",
+ "elem_last",
+ "used_count",
+ "used_last",
+};
+
+int state_to_limit(struct smatch_state *state)
+{
+ int i;
+
+ if (!state || !state->data)
+ return -1;
+
+ for (i = 0; i < ARRAY_SIZE(limit_map); i++) {
+ if (strncmp(state->name, limit_map[i], strlen(limit_map[i])) == 0)
+ return i + BYTE_COUNT;
+ }
+
+ return -1;
+}
+
+const char *limit_type_str(unsigned int limit_type)
+{
+ if (limit_type - BYTE_COUNT >= ARRAY_SIZE(limit_map)) {
+ sm_msg("internal: wrong size type %u", limit_type);
+ return "unknown";
+ }
+
+ return limit_map[limit_type - BYTE_COUNT];
+}
+
+static struct smatch_state *alloc_compare_size(int limit_type, struct expression *expr)
{
struct smatch_state *state;
char *name;
+ char buf[256];
state = __alloc_smatch_state(0);
expr = strip_expr(expr);
name = expr_to_str(expr);
- state->name = alloc_sname(name);
+ snprintf(buf, sizeof(buf), "%s %s", limit_type_str(limit_type), name);
+ state->name = alloc_sname(buf);
free_string(name);
state->data = expr;
return state;
@@ -111,20 +140,21 @@ static int bytes_per_element(struct expression *expr)
return type_bytes(type);
}
-static void db_save_type_links(struct expression *array, struct expression *size)
+static void db_save_type_links(struct expression *array, int type_limit, struct expression *size)
{
const char *array_name;
array_name = get_data_info_name(array);
if (!array_name)
array_name = "";
- sql_insert_data_info(size, ARRAY_LEN, array_name);
+ sql_insert_data_info(size, type_limit, array_name);
}
static void match_alloc_helper(struct expression *pointer, struct expression *size)
{
struct expression *tmp;
struct sm_state *sm;
+ int limit_type = ELEM_COUNT;
sval_t sval;
int cnt = 0;
@@ -159,11 +189,17 @@ static void match_alloc_helper(struct expression *pointer, struct expression *si
if (get_value(size, &sval))
return;
- db_save_type_links(pointer, size);
- sm = set_state_expr(size_id, pointer, alloc_expr_state(size));
+ if (size->type == EXPR_BINOP && size->op == '+' &&
+ get_value(size->right, &sval) && sval.value == 1) {
+ size = size->left;
+ limit_type = ELEM_LAST;
+ }
+
+ db_save_type_links(pointer, limit_type, size);
+ sm = set_state_expr(size_id, pointer, alloc_compare_size(limit_type, size));
if (!sm)
return;
- set_state_expr(link_id, size, alloc_expr_state(pointer));
+ set_state_expr(link_id, size, alloc_state_expr(pointer));
}
static void match_alloc(const char *fn, struct expression *expr, void *_size_arg)
@@ -182,6 +218,7 @@ static void match_calloc(const char *fn, struct expression *expr, void *_start_a
int start_arg = PTR_INT(_start_arg);
struct expression *pointer, *call, *arg;
struct sm_state *tmp;
+ int limit_type = ELEM_COUNT;
sval_t sval;
pointer = strip_expr(expr->left);
@@ -191,21 +228,28 @@ static void match_calloc(const char *fn, struct expression *expr, void *_start_a
sval.value == bytes_per_element(pointer))
arg = get_argument_from_call_expr(call->args, start_arg + 1);
- db_save_type_links(pointer, arg);
- tmp = set_state_expr(size_id, pointer, alloc_expr_state(arg));
+ if (arg->type == EXPR_BINOP && arg->op == '+' &&
+ get_value(arg->right, &sval) && sval.value == 1) {
+ arg = arg->left;
+ limit_type = ELEM_LAST;
+ }
+
+ db_save_type_links(pointer, limit_type, arg);
+ tmp = set_state_expr(size_id, pointer, alloc_compare_size(limit_type, arg));
if (!tmp)
return;
- set_state_expr(link_id, arg, alloc_expr_state(pointer));
+ set_state_expr(link_id, arg, alloc_state_expr(pointer));
}
-struct expression *get_size_variable(struct expression *buf)
+struct expression *get_size_variable(struct expression *buf, int *limit_type)
{
struct smatch_state *state;
state = get_state_expr(size_id, buf);
- if (state)
- return state->data;
- return NULL;
+ if (!state)
+ return NULL;
+ *limit_type = state_to_limit(state);
+ return state->data;
}
struct expression *get_array_variable(struct expression *size)
@@ -224,15 +268,18 @@ static void array_check(struct expression *expr)
struct expression *size;
struct expression *offset;
char *array_str, *offset_str;
+ int limit_type;
expr = strip_expr(expr);
if (!is_array(expr))
return;
array = get_array_base(expr);
- size = get_size_variable(array);
+ size = get_size_variable(array, &limit_type);
if (!size)
return;
+ if (limit_type != ELEM_COUNT)
+ return;
offset = get_array_offset(expr);
if (!possible_comparison(size, SPECIAL_EQUAL, offset))
return;
@@ -317,20 +364,30 @@ int db_var_is_array_limit(struct expression *array, const char *name, struct var
return db_info.ret;
}
-static int known_access_ok_comparison(struct expression *expr)
+int buf_comparison_index_ok(struct expression *expr)
{
struct expression *array;
struct expression *size;
struct expression *offset;
+ int limit_type;
int comparison;
array = get_array_base(expr);
- size = get_size_variable(array);
+ size = get_size_variable(array, &limit_type);
if (!size)
return 0;
offset = get_array_offset(expr);
- comparison = get_comparison(size, offset);
- if (comparison == '>' || comparison == SPECIAL_UNSIGNED_GT)
+ comparison = get_comparison(offset, size);
+ if (!comparison)
+ return 0;
+
+ if ((limit_type == ELEM_COUNT || limit_type == ELEM_LAST) &&
+ (comparison == '<' || comparison == SPECIAL_UNSIGNED_LT))
+ return 1;
+ if (limit_type == ELEM_LAST &&
+ (comparison == SPECIAL_LTE ||
+ comparison == SPECIAL_UNSIGNED_LTE ||
+ comparison == SPECIAL_EQUAL))
return 1;
return 0;
@@ -372,7 +429,7 @@ static void array_check_data_info(struct expression *expr)
if (known_access_ok_numbers(expr))
return;
- if (known_access_ok_comparison(expr))
+ if (buf_comparison_index_ok(expr))
return;
array = get_array_base(expr);
@@ -416,27 +473,90 @@ static void add_allocation_function(const char *func, void *call_back, int param
add_function_assign_hook(func, call_back, INT_PTR(param));
}
-static char *buf_size_param_comparison(struct expression *array, struct expression_list *args)
+static int is_sizeof(struct expression *expr)
{
- struct expression *arg;
+ const char *name;
+
+ if (expr->type == EXPR_SIZEOF)
+ return 1;
+ name = pos_ident(expr->pos);
+ if (name && strcmp(name, "sizeof") == 0)
+ return 1;
+ return 0;
+}
+
+static int match_size_binop(struct expression *size, struct expression *expr, int *limit_type)
+{
+ int orig_type = *limit_type;
+ struct expression *left;
+ sval_t sval;
+
+ left = expr->left;
+ if (!expr_equiv(size, left))
+ return 0;
+
+ if (expr->op == '-' &&
+ get_value(expr->right, &sval) &&
+ sval.value == 1 &&
+ orig_type == ELEM_COUNT) {
+ *limit_type = ELEM_LAST;
+ return 1;
+ }
+
+ if (expr->op == '+' &&
+ get_value(expr->right, &sval) &&
+ sval.value == 1 &&
+ orig_type == ELEM_LAST) {
+ *limit_type = ELEM_COUNT;
+ return 1;
+ }
+
+ if (expr->op == '*' &&
+ is_sizeof(expr->right) &&
+ orig_type == ELEM_COUNT) {
+ *limit_type = BYTE_COUNT;
+ return 1;
+ }
+
+ if (expr->op == '/' &&
+ is_sizeof(expr->right) &&
+ orig_type == BYTE_COUNT) {
+ *limit_type = ELEM_COUNT;
+ return 1;
+ }
+
+ return 0;
+}
+
+static char *buf_size_param_comparison(struct expression *array, struct expression_list *args, int *limit_type)
+{
+ struct expression *tmp, *arg;
struct expression *size;
static char buf[32];
int i;
- size = get_size_variable(array);
+ size = get_size_variable(array, limit_type);
if (!size)
return NULL;
+ if (*limit_type == USED_LAST)
+ *limit_type = ELEM_LAST;
+ if (*limit_type == USED_COUNT)
+ *limit_type = ELEM_COUNT;
+
i = -1;
- FOR_EACH_PTR(args, arg) {
+ FOR_EACH_PTR(args, tmp) {
i++;
+ arg = tmp;
if (arg == array)
continue;
- if (!expr_equiv(arg, size))
- continue;
- snprintf(buf, sizeof(buf), "==$%d", i);
- return buf;
- } END_FOR_EACH_PTR(arg);
+ if (expr_equiv(arg, size) ||
+ (arg->type == EXPR_BINOP &&
+ match_size_binop(size, arg, limit_type))) {
+ snprintf(buf, sizeof(buf), "==$%d", i);
+ return buf;
+ }
+ } END_FOR_EACH_PTR(tmp);
return NULL;
}
@@ -446,16 +566,19 @@ static void match_call(struct expression *call)
struct expression *arg;
char *compare;
int param;
+ char buf[5];
+ int limit_type;
param = -1;
FOR_EACH_PTR(call->args, arg) {
param++;
if (!is_pointer(arg))
continue;
- compare = buf_size_param_comparison(arg, call->args);
+ compare = buf_size_param_comparison(arg, call->args, &limit_type);
if (!compare)
continue;
- sql_insert_caller_info(call, ARRAY_LEN, param, "$", compare);
+ snprintf(buf, sizeof(buf), "%d", limit_type);
+ sql_insert_caller_info(call, limit_type, param, compare, buf);
} END_FOR_EACH_PTR(arg);
}
@@ -495,40 +618,44 @@ static void set_param_compare(const char *array_name, struct symbol *array_sym,
char *size_name;
long param;
struct sm_state *tmp;
+ int limit_type;
- if (strncmp(value, "==$", 3) != 0)
+ if (strncmp(key, "==$", 3) != 0)
return;
- param = strtol(value + 3, NULL, 10);
+ param = strtol(key + 3, NULL, 10);
if (!get_param(param, &size_name, &size_sym))
return;
array_expr = symbol_expression(array_sym);
size_expr = symbol_expression(size_sym);
+ limit_type = strtol(value, NULL, 10);
- tmp = set_state_expr(size_id, array_expr, alloc_expr_state(size_expr));
+ tmp = set_state_expr(size_id, array_expr, alloc_compare_size(limit_type, size_expr));
if (!tmp)
return;
- set_state_expr(link_id, size_expr, alloc_expr_state(array_expr));
+ set_state_expr(link_id, size_expr, alloc_state_expr(array_expr));
}
-static void set_arraysize_arg(const char *array_name, struct symbol *array_sym, char *key, char *value)
+static void set_implied(struct expression *call, struct expression *array_expr, char *key, char *value)
{
- struct expression *array_expr;
struct expression *size_expr;
struct symbol *size_sym;
char *size_name;
long param;
struct sm_state *tmp;
+ int limit_type;
- param = strtol(key, NULL, 10);
+ if (strncmp(key, "==$", 3) != 0)
+ return;
+ param = strtol(key + 3, NULL, 10);
if (!get_param(param, &size_name, &size_sym))
return;
- array_expr = symbol_expression(array_sym);
size_expr = symbol_expression(size_sym);
- tmp = set_state_expr(size_id, array_expr, alloc_expr_state(size_expr));
+ limit_type = strtol(value, NULL, 10);
+ tmp = set_state_expr(size_id, array_expr, alloc_compare_size(limit_type, size_expr));
if (!tmp)
return;
- set_state_expr(link_id, size_expr, alloc_expr_state(array_expr));
+ set_state_expr(link_id, size_expr, alloc_state_expr(array_expr));
}
static void munge_start_states(struct statement *stmt)
@@ -560,10 +687,120 @@ static void munge_start_states(struct statement *stmt)
free_slist(&slist);
}
+static void set_used(struct expression *expr)
+{
+ struct expression *parent;
+ struct expression *array;
+ struct expression *offset;
+ struct sm_state *tmp;
+ int limit_type;
+
+ if (expr->op != SPECIAL_INCREMENT)
+ return;
+
+ limit_type = USED_LAST;
+ if (expr->type == EXPR_POSTOP)
+ limit_type = USED_COUNT;
+
+ parent = expr_get_parent_expr(expr);
+ if (!parent || parent->type != EXPR_BINOP)
+ return;
+ parent = expr_get_parent_expr(parent);
+ if (!parent || !is_array(parent))
+ return;
+
+ array = get_array_base(parent);
+ offset = get_array_offset(parent);
+ if (offset != expr)
+ return;
+
+ tmp = set_state_expr(size_id, array, alloc_compare_size(limit_type, offset->unop));
+ if (!tmp)
+ return;
+ set_state_expr(link_id, offset->unop, alloc_state_expr(array));
+}
+
+static int match_assign_array(struct expression *expr)
+{
+ // FIXME: implement
+ return 0;
+}
+
+static int match_assign_size(struct expression *expr)
+{
+ struct expression *right, *size, *array;
+ struct smatch_state *state;
+ struct sm_state *tmp;
+ int limit_type;
+
+ right = expr->right;
+ size = right;
+ if (size->type == EXPR_BINOP)
+ size = size->left;
+
+ array = get_array_variable(size);
+ if (!array)
+ return 0;
+ state = get_state_expr(size_id, array);
+ if (!state || !state->data)
+ return 0;
+
+ limit_type = state_to_limit(state);
+ if (limit_type < 0)
+ return 0;
+
+ if (right->type == EXPR_BINOP && !match_size_binop(size, right, &limit_type))
+ return 0;
+
+ tmp = set_state_expr(size_id, array, alloc_compare_size(limit_type, expr->left));
+ if (!tmp)
+ return 0;
+ set_state_expr(link_id, expr->left, alloc_state_expr(array));
+ return 1;
+}
+
+static void match_assign(struct expression *expr)
+{
+ if (expr->op != '=')
+ return;
+
+ if (match_assign_array(expr))
+ return;
+ match_assign_size(expr);
+}
+
+static void match_copy(const char *fn, struct expression *expr, void *unused)
+{
+ struct expression *src, *size;
+ int src_param, size_param;
+
+ src = get_argument_from_call_expr(expr->args, 1);
+ size = get_argument_from_call_expr(expr->args, 2);
+ src = strip_expr(src);
+ size = strip_expr(size);
+ if (!src || !size)
+ return;
+ if (src->type != EXPR_SYMBOL || size->type != EXPR_SYMBOL)
+ return;
+
+ src_param = get_param_num_from_sym(src->symbol);
+ size_param = get_param_num_from_sym(size->symbol);
+ if (src_param < 0 || size_param < 0)
+ return;
+
+ sql_insert_cache(call_implies, "'%s', '%s', 0, %d, %d, %d, '==$%d', '%d'",
+ get_base_file(), get_function(), fn_static(),
+ BYTE_COUNT, src_param, size_param, BYTE_COUNT);
+}
+
void register_buf_comparison(int id)
{
+ int i;
+
size_id = id;
+ set_dynamic_states(size_id);
+
add_unmatched_state_hook(size_id, &unmatched_state);
add_allocation_function("malloc", &match_alloc, 0);
@@ -586,20 +823,31 @@ void register_buf_comparison(int id)
add_allocation_function("devm_kcalloc", &match_calloc, 1);
add_allocation_function("kmalloc_array", &match_calloc, 0);
add_allocation_function("krealloc", &match_alloc, 1);
+
+ add_function_hook("copy_from_user", &match_copy, NULL);
+ add_function_hook("__copy_from_user", &match_copy, NULL);
}
add_hook(&array_check, OP_HOOK);
add_hook(&array_check_data_info, OP_HOOK);
+ add_hook(&set_used, OP_HOOK);
add_hook(&match_call, FUNCTION_CALL_HOOK);
- select_caller_info_hook(set_param_compare, ARRAY_LEN);
- select_caller_info_hook(set_arraysize_arg, ARRAYSIZE_ARG);
add_hook(&munge_start_states, AFTER_DEF_HOOK);
+
+ add_hook(&match_assign, ASSIGNMENT_HOOK);
+
+ for (i = BYTE_COUNT; i <= USED_COUNT; i++) {
+ select_call_implies_hook(i, &set_implied);
+ select_caller_info_hook(set_param_compare, i);
+ select_return_implies_hook(i, &set_implied);
+ }
}
void register_buf_comparison_links(int id)
{
link_id = id;
+ set_dynamic_states(link_id);
add_merge_hook(link_id, &merge_links);
add_modification_hook(link_id, &match_link_modify);
}
diff --git a/usr/src/tools/smatch/src/smatch_buf_size.c b/usr/src/tools/smatch/src/smatch_buf_size.c
index 0c7f34947b..b7bad47254 100644
--- a/usr/src/tools/smatch/src/smatch_buf_size.c
+++ b/usr/src/tools/smatch/src/smatch_buf_size.c
@@ -330,8 +330,6 @@ static int get_bytes_from_address(struct expression *expr)
struct symbol *type;
int ret;
- if (!option_spammy)
- return 0;
if (expr->type != EXPR_PREOP || expr->op != '&')
return 0;
type = get_type(expr);
@@ -506,6 +504,10 @@ struct range_list *get_array_size_bytes_rl(struct expression *expr)
return alloc_int_rl(size - offset.value);
}
+ size = get_stored_size_end_struct_bytes(expr);
+ if (size)
+ return alloc_int_rl(size);
+
/* buf[4] */
size = get_real_array_size(expr);
if (size)
@@ -516,10 +518,6 @@ struct range_list *get_array_size_bytes_rl(struct expression *expr)
if (ret)
return ret;
- size = get_stored_size_end_struct_bytes(expr);
- if (size)
- return alloc_int_rl(size);
-
/* char *foo = "BAR" */
size = get_size_from_initializer(expr);
if (size)
@@ -711,17 +709,15 @@ static void match_alloc(const char *fn, struct expression *expr, void *_size_arg
static void match_calloc(const char *fn, struct expression *expr, void *unused)
{
struct expression *right;
- struct expression *arg;
- sval_t elements;
- sval_t size;
+ struct expression *size, *nr, *mult;
+ struct range_list *rl;
right = strip_expr(expr->right);
- arg = get_argument_from_call_expr(right->args, 0);
- if (!get_implied_value(arg, &elements))
- return; // FIXME!!!
- arg = get_argument_from_call_expr(right->args, 1);
- if (get_implied_value(arg, &size))
- store_alloc(expr->left, size_to_rl(elements.value * size.value));
+ nr = get_argument_from_call_expr(right->args, 0);
+ size = get_argument_from_call_expr(right->args, 1);
+ mult = binop_expression(nr, '*', size);
+ if (get_implied_rl(mult, &rl))
+ store_alloc(expr->left, rl);
else
store_alloc(expr->left, size_to_rl(-1));
}
@@ -873,6 +869,8 @@ void register_buf_size(int id)
{
my_size_id = id;
+ set_dynamic_states(my_size_id);
+
add_unmatched_state_hook(my_size_id, &unmatched_size_state);
select_caller_info_hook(set_param_buf_size, BUF_SIZE);
@@ -908,6 +906,9 @@ void register_buf_size(int id)
add_allocation_function("alloc_bootmem", &match_alloc, 0);
add_allocation_function("kmap", &match_page, 0);
add_allocation_function("get_zeroed_page", &match_page, 0);
+ add_allocation_function("alloc_page", &match_page, 0);
+ add_allocation_function("page_address", &match_page, 0);
+ add_allocation_function("lowmem_page_address", &match_page, 0);
add_allocation_function("alloc_pages", &match_alloc_pages, 1);
add_allocation_function("alloc_pages_current", &match_alloc_pages, 1);
add_allocation_function("__get_free_pages", &match_alloc_pages, 1);
diff --git a/usr/src/tools/smatch/src/smatch_capped.c b/usr/src/tools/smatch/src/smatch_capped.c
index a42303d4b7..1b25c4795e 100644
--- a/usr/src/tools/smatch/src/smatch_capped.c
+++ b/usr/src/tools/smatch/src/smatch_capped.c
@@ -42,7 +42,7 @@ static struct smatch_state *unmatched_state(struct sm_state *sm)
{
struct smatch_state *state;
- state = get_state(SMATCH_EXTRA, sm->name, sm->sym);
+ state = __get_state(SMATCH_EXTRA, sm->name, sm->sym);
if (state && !estate_is_whole(state))
return &capped;
return &uncapped;
@@ -68,6 +68,7 @@ static int is_capped_macro(struct expression *expr)
int is_capped(struct expression *expr)
{
+ struct symbol *type;
sval_t dummy;
expr = strip_expr(expr);
@@ -77,6 +78,14 @@ int is_capped(struct expression *expr)
if (!expr)
return 0;
+ type = get_type(expr);
+ if (is_ptr_type(type))
+ return 0;
+ if (type == &bool_ctype)
+ return 0;
+ if (type_bits(type) >= 0 && type_bits(type) <= 2)
+ return 0;
+
if (get_hard_max(expr, &dummy))
return 1;
@@ -90,8 +99,8 @@ int is_capped(struct expression *expr)
return 1;
if (expr->op == SPECIAL_RIGHTSHIFT)
return 1;
- if (expr->op == '%')
- return is_capped(expr->right);
+ if (expr->op == '%' && is_capped(expr->right))
+ return 1;
if (!is_capped(expr->left))
return 0;
if (expr->op == '/')
@@ -131,15 +140,28 @@ void set_param_capped_data(const char *name, struct symbol *sym, char *key, char
static void match_condition(struct expression *expr)
{
+ struct expression *left, *right;
struct smatch_state *left_true = NULL;
struct smatch_state *left_false = NULL;
struct smatch_state *right_true = NULL;
struct smatch_state *right_false = NULL;
+ sval_t sval;
if (expr->type != EXPR_COMPARE)
return;
+ left = strip_expr(expr->left);
+ right = strip_expr(expr->right);
+
+ while (left->type == EXPR_ASSIGNMENT)
+ left = strip_expr(left->left);
+
+ /* If we're dealing with known expressions, that's for smatch_extra.c */
+ if (get_implied_value(left, &sval) ||
+ get_implied_value(right, &sval))
+ return;
+
switch (expr->op) {
case '<':
case SPECIAL_LTE:
@@ -168,12 +190,22 @@ static void match_condition(struct expression *expr)
return;
}
- set_true_false_states_expr(my_id, expr->left, left_true, left_false);
- set_true_false_states_expr(my_id, expr->right, right_true, right_false);
+ set_true_false_states_expr(my_id, left, left_true, left_false);
+ set_true_false_states_expr(my_id, right, right_true, right_false);
}
static void match_assign(struct expression *expr)
{
+ struct symbol *type;
+
+ type = get_type(expr);
+ if (is_ptr_type(type))
+ return;
+ if (type == &bool_ctype)
+ return;
+ if (type_bits(type) >= 0 && type_bits(type) <= 2)
+ return;
+
if (is_capped(expr->right)) {
set_state_expr(my_id, expr->left, &capped);
} else {
@@ -206,7 +238,7 @@ static void struct_member_callback(struct expression *call, int param, char *pri
if (sm->state != &capped)
return;
- estate = get_state(SMATCH_EXTRA, sm->name, sm->sym);
+ estate = __get_state(SMATCH_EXTRA, sm->name, sm->sym);
if (estate_get_single_value(estate, &sval))
return;
sql_insert_caller_info(call, CAPPED_DATA, param, printed_name, "1");
@@ -235,12 +267,12 @@ static void print_return_implies_capped(int return_id, char *return_ranges, stru
if (param < 0)
continue;
- estate = get_state(SMATCH_EXTRA, sm->name, sm->sym);
+ estate = __get_state(SMATCH_EXTRA, sm->name, sm->sym);
if (estate_get_single_value(estate, &sval))
continue;
orig = get_state_stree(get_start_states(), my_id, sm->name, sm->sym);
- if (orig == &capped)
+ if (orig == &capped && !param_was_set_var_sym(sm->name, sm->sym))
continue;
param_name = get_param_name(sm);
@@ -254,9 +286,15 @@ static void print_return_implies_capped(int return_id, char *return_ranges, stru
FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
if (!ret_sym)
break;
+ if (sm->state != &capped)
+ continue;
if (ret_sym != sm->sym)
continue;
+ estate = __get_state(SMATCH_EXTRA, sm->name, sm->sym);
+ if (estate_get_single_value(estate, &sval))
+ continue;
+
param_name = state_name_to_param_name(sm->name, return_str);
if (!param_name)
continue;
diff --git a/usr/src/tools/smatch/src/smatch_comparison.c b/usr/src/tools/smatch/src/smatch_comparison.c
index 51b4a45487..44e6717b2c 100644
--- a/usr/src/tools/smatch/src/smatch_comparison.c
+++ b/usr/src/tools/smatch/src/smatch_comparison.c
@@ -641,7 +641,7 @@ static void save_link_var_sym(const char *var, struct symbol *sym, const char *l
set_state(link_id, var, sym, new_state);
}
-static void match_inc(struct sm_state *sm)
+static void match_inc(struct sm_state *sm, bool preserve)
{
struct string_list *links;
struct smatch_state *state, *new;
@@ -673,6 +673,8 @@ static void match_inc(struct sm_state *sm)
case SPECIAL_UNSIGNED_GTE:
case '>':
case SPECIAL_UNSIGNED_GT:
+ if (preserve)
+ break;
new = alloc_compare_state(
data->left, data->left_var, data->left_vsl,
flip ? '<' : '>',
@@ -693,7 +695,7 @@ static void match_inc(struct sm_state *sm)
} END_FOR_EACH_PTR(tmp);
}
-static void match_dec(struct sm_state *sm)
+static void match_dec(struct sm_state *sm, bool preserve)
{
struct string_list *links;
struct smatch_state *state;
@@ -713,6 +715,9 @@ static void match_dec(struct sm_state *sm)
struct compare_data *data = state->data;
struct smatch_state *new;
+ if (preserve)
+ break;
+
new = alloc_compare_state(
data->left, data->left_var, data->left_vsl,
'<',
@@ -726,6 +731,42 @@ static void match_dec(struct sm_state *sm)
} END_FOR_EACH_PTR(tmp);
}
+static void reset_sm(struct sm_state *sm)
+{
+ struct string_list *links;
+ char *tmp;
+
+ links = sm->state->data;
+
+ FOR_EACH_PTR(links, tmp) {
+ set_state(compare_id, tmp, NULL, &undefined);
+ } END_FOR_EACH_PTR(tmp);
+ set_state(link_id, sm->name, sm->sym, &undefined);
+}
+
+static bool match_add_sub_assign(struct sm_state *sm, struct expression *expr)
+{
+ struct range_list *rl;
+ sval_t zero = { .type = &int_ctype };
+
+ if (!expr || expr->type != EXPR_ASSIGNMENT)
+ return false;
+ if (expr->op != SPECIAL_ADD_ASSIGN && expr->op != SPECIAL_SUB_ASSIGN)
+ return false;
+
+ get_absolute_rl(expr->right, &rl);
+ if (sval_is_negative(rl_min(rl))) {
+ reset_sm(sm);
+ return false;
+ }
+
+ if (expr->op == SPECIAL_ADD_ASSIGN)
+ match_inc(sm, rl_has_sval(rl, zero));
+ else
+ match_dec(sm, rl_has_sval(rl, zero));
+ return true;
+}
+
static void match_inc_dec(struct sm_state *sm, struct expression *mod_expr)
{
/*
@@ -733,13 +774,15 @@ static void match_inc_dec(struct sm_state *sm, struct expression *mod_expr)
*/
if (!mod_expr)
return;
+ if (match_add_sub_assign(sm, mod_expr))
+ return;
if (mod_expr->type != EXPR_PREOP && mod_expr->type != EXPR_POSTOP)
return;
if (mod_expr->op == SPECIAL_INCREMENT)
- match_inc(sm);
+ match_inc(sm, false);
else if (mod_expr->op == SPECIAL_DECREMENT)
- match_dec(sm);
+ match_dec(sm, false);
}
static int is_self_assign(struct expression *expr)
@@ -751,9 +794,6 @@ static int is_self_assign(struct expression *expr)
static void match_modify(struct sm_state *sm, struct expression *mod_expr)
{
- struct string_list *links;
- char *tmp;
-
if (mod_expr && is_self_assign(mod_expr))
return;
@@ -762,13 +802,11 @@ static void match_modify(struct sm_state *sm, struct expression *mod_expr)
((mod_expr->type == EXPR_PREOP || mod_expr->type == EXPR_POSTOP) &&
(mod_expr->op == SPECIAL_INCREMENT || mod_expr->op == SPECIAL_DECREMENT)))
return;
+ if (mod_expr && mod_expr->type == EXPR_ASSIGNMENT &&
+ (mod_expr->op == SPECIAL_ADD_ASSIGN || mod_expr->op == SPECIAL_SUB_ASSIGN))
+ return;
- links = sm->state->data;
-
- FOR_EACH_PTR(links, tmp) {
- set_state(compare_id, tmp, NULL, &undefined);
- } END_FOR_EACH_PTR(tmp);
- set_state(link_id, sm->name, sm->sym, &undefined);
+ reset_sm(sm);
}
static void match_preop(struct expression *expr)
@@ -1604,7 +1642,7 @@ int get_comparison_strings(const char *one, const char *two)
return ret;
}
-int get_comparison(struct expression *a, struct expression *b)
+static int get_comparison_helper(struct expression *a, struct expression *b, bool use_extra)
{
char *one = NULL;
char *two = NULL;
@@ -1653,11 +1691,21 @@ free:
free_string(one);
free_string(two);
- if (!ret)
+ if (!ret && use_extra)
return comparison_from_extra(a, b);
return ret;
}
+int get_comparison(struct expression *a, struct expression *b)
+{
+ return get_comparison_helper(a, b, true);
+}
+
+int get_comparison_no_extra(struct expression *a, struct expression *b)
+{
+ return get_comparison_helper(a, b, false);
+}
+
int possible_comparison(struct expression *a, int comparison, struct expression *b)
{
char *one = NULL;
@@ -2327,7 +2375,7 @@ static int split_op_param_key(char *value, int *op, int *param, char **key)
if (!parse_comparison(&value, op))
return 0;
- snprintf(buf, sizeof(buf), value);
+ snprintf(buf, sizeof(buf), "%s", value);
p = buf;
if (*p++ != '$')
@@ -2495,6 +2543,7 @@ static void free_data(struct symbol *sym)
void register_comparison(int id)
{
compare_id = id;
+ set_dynamic_states(compare_id);
add_hook(&save_start_states, AFTER_DEF_HOOK);
add_unmatched_state_hook(compare_id, unmatched_comparison);
add_pre_merge_hook(compare_id, &pre_merge_hook);
@@ -2515,6 +2564,8 @@ void register_comparison_late(int id)
void register_comparison_links(int id)
{
link_id = id;
+ db_ignore_states(link_id);
+ set_dynamic_states(link_id);
add_merge_hook(link_id, &merge_links);
add_modification_hook(link_id, &match_modify);
add_modification_hook_late(link_id, match_inc_dec);
@@ -2531,6 +2582,7 @@ void register_comparison_inc_dec(int id)
void register_comparison_inc_dec_links(int id)
{
inc_dec_link_id = id;
+ set_dynamic_states(inc_dec_link_id);
set_up_link_functions(inc_dec_id, inc_dec_link_id);
}
diff --git a/usr/src/tools/smatch/src/smatch_conditions.c b/usr/src/tools/smatch/src/smatch_conditions.c
index 79f89bdd56..3127b13f46 100644
--- a/usr/src/tools/smatch/src/smatch_conditions.c
+++ b/usr/src/tools/smatch/src/smatch_conditions.c
@@ -420,6 +420,8 @@ static void split_conditions(struct expression *expr)
* too complicated to deal with.
*/
if (expr->type == EXPR_BINOP && expr->op == '|') {
+ expr_set_parent_expr(expr->left, expr);
+ expr_set_parent_expr(expr->right, expr);
handle_logical(expr);
return;
}
diff --git a/usr/src/tools/smatch/src/smatch_constraints.c b/usr/src/tools/smatch/src/smatch_constraints.c
index b026e90383..7350cfe096 100644
--- a/usr/src/tools/smatch/src/smatch_constraints.c
+++ b/usr/src/tools/smatch/src/smatch_constraints.c
@@ -196,6 +196,7 @@ char *get_constraint_str(struct expression *expr)
{
char *name;
+ expr = strip_expr(expr);
if (!expr)
return NULL;
if (expr->type == EXPR_CALL)
@@ -341,9 +342,8 @@ free_data:
struct string_list *saved_constraints;
static void save_new_constraint(const char *con)
{
- if (list_has_string(saved_constraints, con))
+ if (!insert_string(&saved_constraints, con))
return;
- insert_string(&saved_constraints, con);
sql_save_constraint(con);
}
@@ -360,17 +360,10 @@ static void handle_comparison(struct expression *left, int op, struct expression
if (get_value(left, &sval) || get_value(right, &sval))
return;
- if (local_debug)
- sm_msg("COMPARE: %s %s %s", expr_to_str(left), show_special(op), expr_to_str(right));
-
constraint = get_constraint_str(right);
if (!constraint)
return;
- if (local_debug)
- sm_msg("EXPR: %s CONSTRAINT %s", expr_to_str(right), constraint);
constraint_id = constraint_str_to_id(constraint);
- if (local_debug)
- sm_msg("CONSTRAINT ID %d", constraint_id);
if (constraint_id < 0)
save_new_constraint(constraint);
free_string(constraint);
@@ -383,16 +376,10 @@ static void handle_comparison(struct expression *left, int op, struct expression
add_constraint(&constraints, remove_unsigned_from_comparison(op), constraint_id);
state = alloc_constraint_state(constraints);
- if (op == orig_op) {
- if (local_debug)
- sm_msg("SETTING %s true %s", expr_to_str(left), state->name);
+ if (op == orig_op)
set_true_false_states_expr(my_id, left, state, NULL);
- } else {
- if (local_debug)
- sm_msg("SETTING %s false %s", expr_to_str(left), state->name);
-
+ else
set_true_false_states_expr(my_id, left, NULL, state);
- }
}
static void match_condition(struct expression *expr)
@@ -529,6 +516,7 @@ void register_constraints(int id)
{
my_id = id;
+ set_dynamic_states(my_id);
add_merge_hook(my_id, &merge_func);
add_hook(&match_condition, CONDITION_HOOK);
diff --git a/usr/src/tools/smatch/src/smatch_constraints_required.c b/usr/src/tools/smatch/src/smatch_constraints_required.c
index 3708938586..8b8009bf80 100644
--- a/usr/src/tools/smatch/src/smatch_constraints_required.c
+++ b/usr/src/tools/smatch/src/smatch_constraints_required.c
@@ -281,14 +281,17 @@ free_data:
static void match_assign_has_buf_comparison(struct expression *expr)
{
struct expression *size;
+ int limit_type;
if (expr->op != '=')
return;
if (expr->right->type == EXPR_CALL)
return;
- size = get_size_variable(expr->right);
+ size = get_size_variable(expr->right, &limit_type);
if (!size)
return;
+ if (limit_type != ELEM_COUNT)
+ return;
match_alloc_helper(expr->left, size, 1);
}
@@ -455,6 +458,7 @@ void register_constraints_required(int id)
{
my_id = id;
+ set_dynamic_states(my_id);
add_hook(&match_assign_size, ASSIGNMENT_HOOK);
add_hook(&match_assign_data, ASSIGNMENT_HOOK);
add_hook(&match_assign_has_buf_comparison, ASSIGNMENT_HOOK);
diff --git a/usr/src/tools/smatch/src/smatch_container_of.c b/usr/src/tools/smatch/src/smatch_container_of.c
index 7399726917..a832aee15b 100644
--- a/usr/src/tools/smatch/src/smatch_container_of.c
+++ b/usr/src/tools/smatch/src/smatch_container_of.c
@@ -112,7 +112,7 @@ static int get_container_offset(struct symbol *sym)
return offset;
}
-static char *get_container_name(struct sm_state *sm, int offset)
+static char *get_container_name_sm(struct sm_state *sm, int offset)
{
static char buf[256];
const char *name;
@@ -173,7 +173,7 @@ static void process_states(void)
offset = get_container_offset(tmp->sym);
if (arg < 0 || offset < 0)
continue;
- name = get_container_name(tmp, offset);
+ name = get_container_name_sm(tmp, offset);
if (!name)
continue;
sql_insert_return_implies(CONTAINER, arg, name, "");
@@ -249,73 +249,150 @@ static void returns_container_of(struct expression *expr, int param, char *key,
sql_insert_return_implies(CONTAINER, param, buf, "");
}
-static int get_shared_cnt(const char *one, const char *two)
+static int get_deref_count(struct expression *expr)
{
- int i;
- int on_end = false;
+ int cnt = 0;
+
+ while (expr && expr->type == EXPR_DEREF) {
+ expr = expr->deref;
+ if (expr->type == EXPR_PREOP && expr->op == '*')
+ expr = expr->unop;
+ cnt++;
+ if (cnt > 100)
+ return -1;
+ }
+ return cnt;
+}
- i = 0;
- while (true) {
- if (!one[i] || !two[i]) {
- on_end = true;
- break;
- }
- if (one[i] != two[i])
- break;
- i++;
+static struct expression *get_partial_deref(struct expression *expr, int cnt)
+{
+ while (--cnt >= 0) {
+ if (!expr || expr->type != EXPR_DEREF)
+ return expr;
+ expr = expr->deref;
+ if (expr->type == EXPR_PREOP && expr->op == '*')
+ expr = expr->unop;
}
- if (i == 0)
- return 0;
- i--;
- while (i > 0 && (one[i] == '>' || one[i] == '-' || one[i] == '.')) {
- on_end = true;
- i--;
+ return expr;
+}
+
+static int partial_deref_to_offset_str(struct expression *expr, int cnt, char op, char *buf, int size)
+{
+ int n, offset;
+
+ if (cnt == 0)
+ return snprintf(buf, size, "%c0", op);
+
+ n = 0;
+ while (--cnt >= 0) {
+ offset = get_member_offset_from_deref(expr);
+ if (offset < 0)
+ return -1;
+ n += snprintf(buf + n, size - n, "%c%d", op, offset);
+ if (expr->type != EXPR_DEREF)
+ return -1;
+ expr = expr->deref;
+ if (expr->type == EXPR_PREOP && expr->op == '*')
+ expr = expr->unop;
}
- if (!on_end)
- return 0;
- return i + 1;
+ return n;
}
-static int build_offset_str(struct expression *expr, const char *name,
- int shared, char *buf, int size, int op)
+static char *get_shared_str(struct expression *container, struct expression *expr)
{
- int chop = 0;
- int offset;
- int i;
+ struct expression *one, *two;
+ int cont, exp, min, ret, n;
+ static char buf[48];
- i = shared;
- while (name[i]) {
- if (name[i] == '.' || name[i] == '-')
- chop++;
- i++;
+ cont = get_deref_count(container);
+ exp = get_deref_count(expr);
+ if (cont < 0 || exp < 0)
+ return NULL;
+
+ min = (cont < exp) ? cont : exp;
+ while (min >= 0) {
+ one = get_partial_deref(container, cont - min);
+ two = get_partial_deref(expr, exp - min);
+ if (expr_equiv(one, two))
+ goto found;
+ min--;
}
- // FIXME: Handle more chops
- if (chop > 1)
- return 0;
+ return NULL;
- if (chop == 0) {
- offset = 0;
- } else {
- offset = get_member_offset_from_deref(expr);
- if (offset < 0)
- return 0;
+found:
+ ret = partial_deref_to_offset_str(container, cont - min, '-', buf, sizeof(buf));
+ if (ret < 0)
+ return NULL;
+ n = ret;
+ ret = partial_deref_to_offset_str(expr, exp - min, '+', buf + ret, sizeof(buf) - ret);
+ if (ret < 0)
+ return NULL;
+ n += ret;
+ if (n >= sizeof(buf))
+ return NULL;
+
+ return buf;
+}
+
+char *get_container_name(struct expression *container, struct expression *expr)
+{
+ struct symbol *container_sym, *sym;
+ struct expression *tmp;
+ static char buf[64];
+ char *shared;
+ bool star;
+ int cnt;
+
+ container_sym = expr_to_sym(container);
+ sym = expr_to_sym(expr);
+ if (container_sym && container_sym == sym)
+ goto found;
+
+ cnt = 0;
+ while ((tmp = get_assigned_expr(expr))) {
+ expr = tmp;
+ if (cnt++ > 3)
+ break;
+ }
+
+ cnt = 0;
+ while ((tmp = get_assigned_expr(container))) {
+ container = tmp;
+ if (cnt++ > 3)
+ break;
}
- snprintf(buf, size, "%c%d", (op == '+') ? '+' : '-', offset);
- return 1;
+found:
+ expr = strip_expr(expr);
+ star = true;
+ if (expr->type == EXPR_PREOP && expr->op == '&') {
+ expr = strip_expr(expr->unop);
+ star = false;
+ }
+
+ container_sym = expr_to_sym(container);
+ if (!container_sym)
+ return NULL;
+ sym = expr_to_sym(expr);
+ if (!sym || container_sym != sym)
+ return NULL;
+
+ shared = get_shared_str(container, expr);
+ if (star)
+ snprintf(buf, sizeof(buf), "*(%s)", shared);
+ else
+ snprintf(buf, sizeof(buf), "%s", shared);
+
+ return buf;
}
static void match_call(struct expression *call)
{
struct expression *fn, *arg;
- char *fn_name, *arg_name;
- int param, shared;
- char minus_str[64];
- char plus_str[64];
- char offset_str[64];
- bool star;
+ char *name;
+ int param;
/*
* We're trying to link the function with the parameter. There are a
@@ -332,72 +409,22 @@ static void match_call(struct expression *call)
* otherwise it is. Starred means dereferenced.
*/
fn = strip_expr(call->fn);
- fn_name = expr_to_var(fn);
- if (!fn_name)
- return;
param = -1;
FOR_EACH_PTR(call->args, arg) {
param++;
- arg = strip_expr(arg);
- star = true;
- if (arg->type == EXPR_PREOP && arg->op == '&') {
- arg = strip_expr(arg->unop);
- star = false;
- }
-
- arg_name = expr_to_var(arg);
- if (!arg_name)
+ name = get_container_name(fn, arg);
+ if (!name)
continue;
- shared = get_shared_cnt(fn_name, arg_name);
- if (!shared)
- goto free_arg_name;
- if (!build_offset_str(fn, fn_name, shared, minus_str, sizeof(minus_str), '-'))
- goto free_arg_name;
- if (!build_offset_str(arg, arg_name, shared, plus_str, sizeof(plus_str), '+'))
- goto free_arg_name;
- if (star)
- snprintf(offset_str, sizeof(offset_str), "*(%s%s)", minus_str, plus_str);
- else
- snprintf(offset_str, sizeof(offset_str), "%s%s", minus_str, plus_str);
- sql_insert_caller_info(call, CONTAINER, param, offset_str, "$(-1)");
-free_arg_name:
- free_string(arg_name);
- } END_FOR_EACH_PTR(arg);
- free_string(fn_name);
+ sql_insert_caller_info(call, CONTAINER, param, name, "$(-1)");
+ } END_FOR_EACH_PTR(arg);
}
static void db_passed_container(const char *name, struct symbol *sym, char *key, char *value)
{
- sval_t offset = {
- .type = &int_ctype,
- };
- const char *arg_offset;
- int star = 0;
- int val;
-
- if (key[0] == '*') {
- star = 1;
- key += 2;
- }
-
- val = atoi(key);
- if (val < -4095 || val > 0)
- return;
- offset.value = -val;
- arg_offset = strchr(key, '+');
- if (!arg_offset)
- return;
- val = atoi(arg_offset + 1);
- if (val > 4095 || val < 0)
- return;
- offset.value |= val << 16;
- if (star)
- offset.value |= 1ULL << 31;
-
- set_state(param_id, name, sym, alloc_estate_sval(offset));
+ set_state(param_id, name, sym, alloc_state_str(key));
}
struct db_info {
@@ -574,35 +601,49 @@ static struct stree *load_tag_info_sym(mtag_t tag, struct symbol *arg, int arg_o
return db_info.stree;
}
-static void handle_passed_container(struct symbol *sym)
+static void load_container_data(struct symbol *arg, const char *info)
{
- struct symbol *arg;
- struct smatch_state *state;
+ mtag_t cur_tag, container_tag, arg_tag;
+ int container_offset, arg_offset;
+ char *p = (char *)info;
struct sm_state *sm;
struct stree *stree;
- mtag_t fn_tag, container_tag, arg_tag;
- sval_t offset;
- int container_offset, arg_offset;
- int star;
+ bool star = 0;
- FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, arg) {
- state = get_state(param_id, arg->ident->name, arg);
- if (state)
- goto found;
- } END_FOR_EACH_PTR(arg);
+ if (p[0] == '*') {
+ star = 1;
+ p += 2;
+ }
- return;
-found:
- if (!estate_get_single_value(state, &offset))
+ if (!get_toplevel_mtag(cur_func_sym, &cur_tag))
return;
- container_offset = -(offset.value & 0xffff);
- arg_offset = (offset.value & 0xfff0000) >> 16;
- star = !!(offset.value & (1ULL << 31));
- if (!get_toplevel_mtag(cur_func_sym, &fn_tag))
+ while (true) {
+ container_offset = strtoul(p, &p, 0);
+ if (local_debug)
+ sm_msg("%s: cur_tag = %llu container_offset = %d",
+ __func__, cur_tag, container_offset);
+ if (!mtag_map_select_container(cur_tag, container_offset, &container_tag))
+ return;
+ cur_tag = container_tag;
+ if (local_debug)
+ sm_msg("%s: container_tag = %llu p = '%s'",
+ __func__, container_tag, p);
+ if (!p)
+ return;
+ if (p[0] != '-')
+ break;
+ p++;
+ }
+
+ if (p[0] != '+')
return;
- if (!mtag_map_select_container(fn_tag, container_offset, &container_tag))
+
+ p++;
+ arg_offset = strtoul(p, &p, 0);
+ if (p && *p && *p != ')')
return;
+
if (!arg_offset || star) {
arg_tag = container_tag;
} else {
@@ -617,6 +658,19 @@ found:
free_stree(&stree);
}
+static void handle_passed_container(struct symbol *sym)
+{
+ struct symbol *arg;
+ struct smatch_state *state;
+
+ FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, arg) {
+ state = get_state(param_id, arg->ident->name, arg);
+ if (!state || state == &merged)
+ continue;
+ load_container_data(arg, state->name);
+ } END_FOR_EACH_PTR(arg);
+}
+
void register_container_of(int id)
{
my_id = id;
@@ -637,18 +691,13 @@ void register_container_of(int id)
add_hook(&match_call, FUNCTION_CALL_HOOK);
}
-static struct smatch_state *unmatched_state(struct sm_state *sm)
-{
- return alloc_estate_whole(estate_type(sm->state));
-}
-
void register_container_of2(int id)
{
param_id = id;
+ set_dynamic_states(param_id);
select_caller_info_hook(db_passed_container, CONTAINER);
+ add_merge_hook(param_id, &merge_str_state);
add_hook(&handle_passed_container, AFTER_DEF_HOOK);
- add_unmatched_state_hook(param_id, &unmatched_state);
- add_merge_hook(param_id, &merge_estates);
}
diff --git a/usr/src/tools/smatch/src/smatch_data/db/apply_return_fixes.sh b/usr/src/tools/smatch/src/smatch_data/db/apply_return_fixes.sh
new file mode 100755
index 0000000000..c663a0d214
--- /dev/null
+++ b/usr/src/tools/smatch/src/smatch_data/db/apply_return_fixes.sh
@@ -0,0 +1,20 @@
+#!/bin/bash
+
+if echo $1 | grep -q '^-p' ; then
+ PROJ=$(echo $1 | cut -d = -f 2)
+ shift
+fi
+
+bin_dir=$(dirname $0)
+db_file=$1
+if [ "$db_file" == "" ] ; then
+ echo "usage: $0 -p=<project> <db_file>"
+ exit
+fi
+
+test -e ${bin_dir}/${PROJ}.return_fixes && \
+cat ${bin_dir}/${PROJ}.return_fixes | \
+while read func old new ; do
+ echo "update return_states set return = '$new' where function = '$func' and return = '$old';" | sqlite3 $db_file
+done
+
diff --git a/usr/src/tools/smatch/src/smatch_data/db/create_db.sh b/usr/src/tools/smatch/src/smatch_data/db/create_db.sh
index 42c1524d15..37ff637650 100755
--- a/usr/src/tools/smatch/src/smatch_data/db/create_db.sh
+++ b/usr/src/tools/smatch/src/smatch_data/db/create_db.sh
@@ -44,15 +44,12 @@ if [ "$PROJ" != "" ] ; then
fi
${bin_dir}/remove_mixed_up_pointer_params.pl $db_file
+${bin_dir}/delete_too_common_fn_ptr.sh $db_file
${bin_dir}/mark_function_ptrs_searchable.pl $db_file
# delete duplicate entrees and speed things up
echo "delete from function_ptr where rowid not in (select min(rowid) from function_ptr group by file, function, ptr, searchable);" | sqlite3 $db_file
-test -e ${bin_dir}/${PROJ}.return_fixes && \
-cat ${bin_dir}/${PROJ}.return_fixes | \
-while read func old new ; do
- echo "update return_states set return = '$new' where function = '$func' and return = '$old';" | sqlite3 $db_file
-done
+${bin_dir}/apply_return_fixes.sh -p=${PROJ} $db_file
mv $db_file smatch_db.sqlite
diff --git a/usr/src/tools/smatch/src/smatch_data/db/delete_too_common_fn_ptr.sh b/usr/src/tools/smatch/src/smatch_data/db/delete_too_common_fn_ptr.sh
new file mode 100755
index 0000000000..5f050f3c59
--- /dev/null
+++ b/usr/src/tools/smatch/src/smatch_data/db/delete_too_common_fn_ptr.sh
@@ -0,0 +1,14 @@
+#!/bin/bash
+
+db_file=$1
+
+IFS="|"
+echo "select count(function), function from function_ptr group by function;" | \
+ sqlite3 $db_file | sort -n | tail -n 100 | \
+
+while read cnt func ; do
+ if [ $cnt -lt 200 ] ; then
+ continue
+ fi
+ echo "delete from function_ptr where function = '$func';" | sqlite3 $db_file
+done
diff --git a/usr/src/tools/smatch/src/smatch_data/db/fixup_kernel.sh b/usr/src/tools/smatch/src/smatch_data/db/fixup_kernel.sh
index 0a323cf374..8a52d2585f 100755
--- a/usr/src/tools/smatch/src/smatch_data/db/fixup_kernel.sh
+++ b/usr/src/tools/smatch/src/smatch_data/db/fixup_kernel.sh
@@ -23,18 +23,8 @@ delete from caller_info where function = '(struct irq_router)->set' and type !=
delete from caller_info where function = '(struct net_device_ops)->ndo_change_mtu' and caller = 'i40e_dbg_netdev_ops_write';
delete from caller_info where function = '(struct timer_list)->function' and type != 0;
-/* type 1003 is USER_DATA */
-delete from caller_info where caller = 'hid_input_report' and type = 1003;
-delete from caller_info where caller = 'nes_process_iwarp_aeqe' and type = 1003;
-delete from caller_info where caller = 'oz_process_ep0_urb' and type = 1003;
-delete from caller_info where function = 'dev_hard_start_xmit' and key = '\$' and type = 1003;
-delete from caller_info where function like '%->ndo_start_xmit' and key = '\$' and type = 1003;
-delete from caller_info where caller = 'packet_rcv_fanout' and function = '(struct packet_type)->func' and parameter = 1 and type = 1003;
-delete from caller_info where caller = 'hptiop_probe' and type = 1003;
-delete from caller_info where caller = 'p9_fd_poll' and function = '(struct file_operations)->poll' and type = 1003;
-delete from caller_info where caller = 'proc_reg_poll' and function = 'proc_reg_poll ptr poll' and type = 1003;
-delete from caller_info where function = 'blkdev_ioctl' and type = 1003 and parameter = 0 and key = '\$';
-/* 9017 is USER_DATA3_SET */
+/* 8017 is USER_DATA and 9017 is USER_DATA_SET */
+delete from caller_info where function = 'dev_hard_start_xmit' and type = 8017;
delete from return_states where function='vscnprintf' and type = 9017;
delete from return_states where function='scnprintf' and type = 9017;
delete from return_states where function='vsnprintf' and type = 9017;
@@ -49,6 +39,10 @@ delete from return_states where function='sprintf' and type = 8017;
/* because of recursion it gets passed to everything and is impossible to debug */
delete from caller_info where function = '__dev_queue_xmit' and type = 8017;
delete from caller_info where function = '__netdev_start_xmit' and type = 8017;
+delete from caller_info where function = '(struct packet_type)->func' and type = 8017;
+delete from caller_info where function = '(struct bio)->bi_end_io' and type = 8017;
+delete from caller_info where caller = 'NF_HOOK_COND' and type = 8017;
+delete from caller_info where caller = 'NF_HOOK' and type = 8017;
/* comparison doesn't deal with chunks, I guess. */
delete from return_states where function='get_tty_driver' and type = 8017;
delete from caller_info where caller = 'snd_ctl_elem_write' and function = '(struct snd_kcontrol)->put' and type = 8017;
@@ -57,9 +51,9 @@ delete from caller_info where function = 'nf_tables_newexpr' and type = 8017 and
delete from caller_info where caller = 'fb_set_var' and function = '(struct fb_ops)->fb_set_par' and type = 8017 and parameter = 0;
delete from return_states where function = 'tty_lookup_driver' and parameter = 2 and type = 8017;
-insert into caller_info values ('userspace', '', 'compat_sys_ioctl', 0, 0, 1003, 0, '\$', '1');
-insert into caller_info values ('userspace', '', 'compat_sys_ioctl', 0, 0, 1003, 1, '\$', '1');
-insert into caller_info values ('userspace', '', 'compat_sys_ioctl', 0, 0, 1003, 2, '\$', '1');
+insert into caller_info values ('userspace', '', 'compat_sys_ioctl', 0, 0, 8017, 0, '\$', '1');
+insert into caller_info values ('userspace', '', 'compat_sys_ioctl', 0, 0, 8017, 1, '\$', '1');
+insert into caller_info values ('userspace', '', 'compat_sys_ioctl', 0, 0, 8017, 2, '\$', '1');
delete from caller_info where function = '(struct timer_list)->function' and parameter = 0;
@@ -76,36 +70,15 @@ insert into return_states values ('faked', 'rw_verify_area', 0, 2, '(-4095)-(-1)
delete from return_states where function = 'is_kernel_rodata';
insert into return_states values ('faked', 'is_kernel_rodata', 0, 1, '1', 0, 0, -1, '', '');
-insert into return_states values ('faked', 'is_kernel_rodata', 0, 1, '1', 0, 103, 0, '\$', '100000000-177777777');
+insert into return_states values ('faked', 'is_kernel_rodata', 0, 1, '1', 0, 103, 0, '\$', '4096-ptr_max');
insert into return_states values ('faked', 'is_kernel_rodata', 0, 2, '0', 0, 0, -1, '', '');
/*
- * I am a bad person for doing this to __kmalloc() which is a very deep function
- * and can easily be removed instead of to kmalloc(). But kmalloc() is an
- * inline function so it ends up being recorded thousands of times in the
- * database. Doing this is easier.
- *
- */
-delete from return_states where function = '__kmalloc';
-insert into return_states values ('faked', '__kmalloc', 0, 1, '16', 0, 0, -1, '', '');
-insert into return_states values ('faked', '__kmalloc', 0, 1, '16', 0, 103, 0, '\$', '0');
-insert into return_states values ('faked', '__kmalloc', 0, 2, '0,500000000-577777777', 0, 0, -1, '', '');
-insert into return_states values ('faked', '__kmalloc', 0, 2, '0,500000000-577777777', 0, 103, 0, '\$', '1-4000000');
-insert into return_states values ('faked', '__kmalloc', 0, 2, '0,500000000-577777777', 0, 1037, -1, '', 400);
-insert into return_states values ('faked', '__kmalloc', 0, 3, '0', 0, 0, -1, '', '');
-insert into return_states values ('faked', '__kmalloc', 0, 3, '0', 0, 103, 0, '\$', '4000000-long_max');
-
-/*
* Other kmalloc hacking.
*/
-update return_states set return = '0,500000000-577777777' where function = 'kmalloc_slab' and return = 's64min-s64max';
-update return_states set return = '0,500000000-577777777' where function = 'slab_alloc_node' and return = 's64min-s64max';
-update return_states set return = '0,500000000-577777777' where function = 'kmalloc_large' and return != '0';
-update return_states set return = '0,500000000-577777777' where function = 'kmalloc_order_trace' and return != '0';
-
delete from return_states where function = 'vmalloc';
-insert into return_states values ('faked', 'vmalloc', 0, 1, '0,600000000-677777777', 0, 0, -1, '', '');
-insert into return_states values ('faked', 'vmalloc', 0, 1, '0,600000000-677777777', 0, 103, 0, '\$', '1-128000000');
+insert into return_states values ('faked', 'vmalloc', 0, 1, '4096-ptr_max', 0, 0, -1, '', '');
+insert into return_states values ('faked', 'vmalloc', 0, 1, '4096-ptr_max', 0, 103, 0, '\$', '1-128000000');
insert into return_states values ('faked', 'vmalloc', 0, 2, '0', 0, 0, -1, '', '');
delete from return_states where function = 'ksize';
@@ -141,9 +114,6 @@ delete from return_states where function = 'bitmap_allocate_region' and return =
/* Just delete a lot of returns that everyone ignores */
delete from return_states where file = 'drivers/pci/access.c' and (return >= 129 and return <= 137);
-update return_states set return = '(-4095)-s32max[<=\$1]' where function = 'get_user_pages' and return = 's32min-s32max';
-update return_states set return = '(-4095)-s64max[<=\$1]' where function = 'get_user_pages' and return = 's64min-s64max';
-
/* Smatch can't parse wait_for_completion() */
update return_states set return = '(-108),(-22),0' where function = '__spi_sync' and return = '(-115),(-108),(-22)';
@@ -155,9 +125,9 @@ update caller_info set value = 4096 where caller='kernfs_file_direct_read' and f
delete from caller_info where caller='init_fw_attribute_group' and function='(struct device_attribute)->show';
/* and let's fake the next dev_attr_show() call entirely */
delete from caller_info where caller='sysfs_kf_seq_show' and function='(struct sysfs_ops)->show';
-insert into caller_info values ('fake', 'sysfs_kf_seq_show', '(struct sysfs_ops)->show', 0, 0, 1001, 0, '\$', '4096-2117777777777777777');
+insert into caller_info values ('fake', 'sysfs_kf_seq_show', '(struct sysfs_ops)->show', 0, 0, 1001, 0, '\$', '4096-ptr_max');
insert into caller_info values ('fake', 'sysfs_kf_seq_show', '(struct sysfs_ops)->show', 0, 0, 1002, 2, '\$', '4096');
-insert into caller_info values ('fake', 'sysfs_kf_seq_show', '(struct sysfs_ops)->show', 0, 0, 1001, 2, '\$', '4096-2117777777777777777');
+insert into caller_info values ('fake', 'sysfs_kf_seq_show', '(struct sysfs_ops)->show', 0, 0, 1001, 2, '\$', '4096-ptr_max');
insert into caller_info values ('fake', 'sysfs_kf_seq_show', '(struct sysfs_ops)->show', 0, 0, 0, -1, '' , '');
/* config fs confuses smatch a little */
update caller_info set value = 4096 where caller='fill_read_buffer' and function='(struct configfs_item_operations)->show_attribute' and type = 1002 and parameter = 2;
@@ -198,12 +168,18 @@ delete from caller_info where function = '(struct i2c_algorithm)->master_xfer' a
/* this if from READ_ONCE(). We can't know anything about the data. */
delete from type_info where key = '(union anonymous)->__val';
+/* This is RIO_BAD_SIZE */
+delete from return_states where file = 'drivers/rapidio/rio-access.c' and return = '129';
+
+/* Smatch sucks at loops */
+delete from return_states where function = 'ata_dev_next' and type = 103;
+
EOF
# fixme: this is totally broken
call_id=$(echo "select distinct call_id from caller_info where function = '__kernel_write';" | sqlite3 $db_file)
for id in $call_id ; do
- echo "insert into caller_info values ('fake', '', '__kernel_write', $id, 0, 1003, 1, '*\$', '');" | sqlite3 $db_file
+ echo "insert into caller_info values ('fake', '', '__kernel_write', $id, 0, 8017, 1, '*\$', '');" | sqlite3 $db_file
done
for i in $(echo "select distinct return from return_states where function = 'clear_user';" | sqlite3 $db_file ) ; do
@@ -227,3 +203,17 @@ echo "select distinct file, function from function_ptr where ptr='(struct rtl_ha
| sqlite3 $db_file
done
+
+for func in __kmalloc __kmalloc_track_caller ; do
+
+ cat << EOF | sqlite3 $db_file
+delete from return_states where function = '$func';
+insert into return_states values ('faked', '$func', 0, 1, '16', 0, 0, -1, '', '');
+insert into return_states values ('faked', '$func', 0, 1, '16', 0, 103, 0, '\$', '0');
+insert into return_states values ('faked', '$func', 0, 2, '4096-ptr_max', 0, 0, -1, '', '');
+insert into return_states values ('faked', '$func', 0, 2, '4096-ptr_max', 0, 103, 0, '\$', '1-4000000');
+insert into return_states values ('faked', '$func', 0, 2, '4096-ptr_max', 0, 1037, -1, '', 400);
+insert into return_states values ('faked', '$func', 0, 3, '0', 0, 0, -1, '', '');
+insert into return_states values ('faked', '$func', 0, 3, '0', 0, 103, 0, '\$', '1-long_max');
+EOF
+done
diff --git a/usr/src/tools/smatch/src/smatch_data/db/function_ptr.schema b/usr/src/tools/smatch/src/smatch_data/db/function_ptr.schema
index 20227b24e9..3ad777de4c 100644
--- a/usr/src/tools/smatch/src/smatch_data/db/function_ptr.schema
+++ b/usr/src/tools/smatch/src/smatch_data/db/function_ptr.schema
@@ -1 +1,9 @@
-CREATE TABLE function_ptr (file varchar(128), function varchar(64), ptr varchar(256), searchable integer);
+CREATE TABLE function_ptr (
+ file varchar(128),
+ function varchar(64),
+ ptr varchar(256),
+ searchable integer,
+
+ CONSTRAINT function_ptr_constraint UNIQUE (file, function, ptr)
+);
+
diff --git a/usr/src/tools/smatch/src/smatch_data/db/init_constraints.pl b/usr/src/tools/smatch/src/smatch_data/db/init_constraints.pl
index d1db7d03a8..e2bc868553 100755
--- a/usr/src/tools/smatch/src/smatch_data/db/init_constraints.pl
+++ b/usr/src/tools/smatch/src/smatch_data/db/init_constraints.pl
@@ -46,6 +46,10 @@ sub load_manual_constraints($$)
my $project = shift;
my $dir = dirname($full_path);
+ if ($project =~ /^$/) {
+ return;
+ }
+
open(FILE, "$dir/$project.constraints");
while (<FILE>) {
s/\n//;
diff --git a/usr/src/tools/smatch/src/smatch_data/db/init_constraints_required.pl b/usr/src/tools/smatch/src/smatch_data/db/init_constraints_required.pl
index e7a4057544..15ce19b2c2 100755
--- a/usr/src/tools/smatch/src/smatch_data/db/init_constraints_required.pl
+++ b/usr/src/tools/smatch/src/smatch_data/db/init_constraints_required.pl
@@ -34,6 +34,10 @@ sub load_manual_constraints($$)
my $dir = dirname($full_path);
my ($data, $op, $limit);
+ if ($project =~ /^$/) {
+ return;
+ }
+
open(FILE, "$dir/$project.constraints_required");
while (<FILE>) {
($data, $op, $limit) = split(/,/);
diff --git a/usr/src/tools/smatch/src/smatch_data/db/kernel.return_fixes b/usr/src/tools/smatch/src/smatch_data/db/kernel.return_fixes
index 03d2e00d05..66fe421030 100644
--- a/usr/src/tools/smatch/src/smatch_data/db/kernel.return_fixes
+++ b/usr/src/tools/smatch/src/smatch_data/db/kernel.return_fixes
@@ -11,7 +11,9 @@ scnprintf 0-s32max 0-s32max[<$1]
vscnprintf s32min-(-2),0-s32max[<$1] 0-s32max[<$1]
down_interruptible s32min-s32max (-62),(-4)
__sock_create s32min-(-1),1-s32max (-4095)-(-1)
+__sock_create s32min-(-90),(-88)-(-1),1-s32max (-4095)-(-90),(-88)-(-1)
sock_create_kern s32min-(-1),1-s32max (-4095)-(-1)
+sock_create_kern s32min-(-90),(-88)-(-1),1-s32max (-4095)-(-90),(-88)-(-1)
nilfs_cpfile_get_checkpoint_block s32min-(-18),(-16)-s32max (-4095)-(-18),(-16)-(-1)
nilfs_cpfile_get_checkpoint_block s32min-(-18),(-16)-(-3),(-1),1-s32max (-4095)-(-18),(-16)-(-3),(-1)
nilfs_mdt_insert_new_block s32min-(-23),(-21)-(-1),1-s32max (-4095)-(-23),(-21)-(-1)
@@ -19,16 +21,35 @@ simple_write_to_buffer s64min-s64max 0-s32max[<=$1]
atomic_read s32min-s32max s32min-s32max[==$0->counter]
notifier_to_errno (-2147483646)-(-1) (-4095)-(-1)
mc_status_to_error s32min-s32max (-4095)-0
-dma_fence_wait_timeout s64min-s64max (-4095)-s64max
-dma_fence_wait_timeout s32min-s32max (-4095)-s32max
fls s32min-s32max 0-32
fls64 s64min-s64max 0-64
__bitmap_weight s32min-s32max 0-s32max[<=$1]
__bitmap_weight 0-s32max 0-s32max[<=$1]
__ffs 0-u64max 0-63
__ffs 0-u32max 0-31
+find_last_bit 0-u64max 0-u32max[<=$1]
__spi_sync (-524),(-115),(-108),(-22) (-4095)-0
tpm_tis_spi_read_bytes s32min-s32max (-4095)-0
__irq_domain_activate_irq s32min-s32max (-4095)-0
-get_user_pages_fast s32min-s32max 1-s32max[<$1]
+get_user_pages_fast s32min-s32max 1-s32max[<=$1]
+get_user_pages s32min-s32max (-4095)-s32max[<=$1]
+get_user_pages s64min-s64max (-4095)-s64max[<=$1]
+get_user_pages_remote 1-s64max 1-s64max[<=$3]
+get_user_pages_remote (-133),(-14),(-12),1-s64max (-133),(-14),(-12),1-s64max[<=$3]
__nci_request s32min-s32max (-4095)-0
+wait_for_common s64min-s64max 0-s64max[<=$1]
+wait_for_common 64min-(-1),1-s64max 1-s64max[<=$1]
+dma_fence_wait_timeout s64min-(-1),1-s64max (-4095)-(-1),1-s32max[<=2]
+dma_fence_wait_timeout s64min-s64max (-4095)-s32max
+dma_fence_wait_timeout s32min-s32max (-4095)-s32max
+__fw_state_wait_common s32min-s32max (-4095)-(-1)
+__ilog2_u32 s32min-s32max 0-31
+__ilog2_u64 s32min-s32max 0-63
+driver_attach s32min-s32max (-4095)-0
+mbox_post_sync_cmd 255 0-255
+mmc_io_rw_extended s32min-(-1),1-s32max (-4095)-(-1)
+kernel_read s64min-s64max (-4095)-1000000000
+security_kernel_post_read_file s32min-(-1),1-s32max (-4095)-(-1)
+array_index_mask_nospec 0-u64max u64max
+array_index_mask_nospec 0-u32max u32max
+nla_len (-4)-65531[$0->nla_len\ -\ 4] 0-65531[$0->nla_len\ -\ 4]
diff --git a/usr/src/tools/smatch/src/smatch_data/db/smdb.py b/usr/src/tools/smatch/src/smatch_data/db/smdb.py
index 1dcad2e94e..c0b310b13b 100755
--- a/usr/src/tools/smatch/src/smatch_data/db/smdb.py
+++ b/usr/src/tools/smatch/src/smatch_data/db/smdb.py
@@ -17,6 +17,7 @@ except sqlite3.Error, e:
def usage():
print "%s" %(sys.argv[0])
print "<function> - how a function is called"
+ print "info <type> - how a function is called, filtered by type"
print "return_states <function> - what a function returns"
print "call_tree <function> - show the call tree"
print "where <struct_type> <member> - where a struct member is set"
@@ -55,7 +56,6 @@ db_types = { 0: "INTERNAL",
104: "PARAM_FILTER",
1001: "PARAM_VALUE",
1002: "BUF_SIZE",
- 1003: "USER_DATA",
1004: "CAPPED_DATA",
1005: "RETURN_VALUE",
1006: "DEREFERENCE",
@@ -79,7 +79,22 @@ db_types = { 0: "INTERNAL",
1027: "BYTE_UNITS",
1028: "COMPARE_LIMIT",
1029: "PARAM_COMPARE",
- 8017: "USER_DATA2",
+ 1030: "EXPECTS_TYPE",
+ 1031: "CONSTRAINT",
+ 1032: "PASSES_TYPE",
+ 1033: "CONSTRAINT_REQUIRED",
+ 1034: "BIT_INFO",
+ 1035: "NOSPEC",
+ 1036: "NOSPEC_WB",
+ 1037: "STMT_CNT",
+ 1038: "TERMINATED",
+ 1039: "SLEEP",
+ 1040: "NO_SLEEP_CNT",
+ 1041: "SMALLISH",
+ 1042: "FRESH_MTAG",
+
+ 8017: "USER_DATA",
+ 9017: "USER_DATA_SET",
8018: "NO_OVERFLOW",
8019: "NO_OVERFLOW_SIMPLE",
8020: "LOCKED",
@@ -197,6 +212,8 @@ def txt_to_val(txt):
return 2**15 - 1
elif txt == "u64max":
return 2**64 - 1
+ elif txt == "ptr_max":
+ return 2**64 - 1
elif txt == "u32max":
return 2**32 - 1
elif txt == "u16max":
@@ -589,6 +606,12 @@ if len(sys.argv) < 2:
if len(sys.argv) == 2:
func = sys.argv[1]
print_caller_info("", func)
+elif sys.argv[1] == "info":
+ my_type = ""
+ if len(sys.argv) == 4:
+ my_type = sys.argv[3]
+ func = sys.argv[2]
+ print_caller_info("", func, my_type)
elif sys.argv[1] == "call_info":
if len(sys.argv) != 4:
usage()
@@ -596,12 +619,6 @@ elif sys.argv[1] == "call_info":
func = sys.argv[3]
caller_info_values(filename, func)
print_caller_info(filename, func)
-elif sys.argv[1] == "user_data":
- func = sys.argv[2]
- print_caller_info(filename, func, "USER_DATA")
-elif sys.argv[1] == "param_value":
- func = sys.argv[2]
- print_caller_info(filename, func, "PARAM_VALUE")
elif sys.argv[1] == "function_ptr" or sys.argv[1] == "fn_ptr":
func = sys.argv[2]
print_fn_ptrs(func)
diff --git a/usr/src/tools/smatch/src/smatch_data/db/vim_smdb b/usr/src/tools/smatch/src/smatch_data/db/vim_smdb
index 5760066110..c169c9c5d9 100755
--- a/usr/src/tools/smatch/src/smatch_data/db/vim_smdb
+++ b/usr/src/tools/smatch/src/smatch_data/db/vim_smdb
@@ -25,7 +25,7 @@ fi
next=$(($i + 1))
rm -f $DIR/$next
-rm $DIR/.${i}.swp
+rm -f $DIR/.${i}.swp
smdb $* > $DIR/$i
echo "$DIR/$i" > $DIR/cur
diff --git a/usr/src/tools/smatch/src/smatch_data/illumos_kernel.skipped_functions b/usr/src/tools/smatch/src/smatch_data/illumos_kernel.skipped_functions
index 452d7f5871..3617b9b806 100644
--- a/usr/src/tools/smatch/src/smatch_data/illumos_kernel.skipped_functions
+++ b/usr/src/tools/smatch/src/smatch_data/illumos_kernel.skipped_functions
@@ -1,8 +1,13 @@
/* These are "too hairy" for smatch. */
+ECDSA_VerifyDigest
dtrace_disx86
elf32exec
elfexec
iscsi_ioctl
lm_idle_chk
+ld64_sym_validate
+luaV_settable
+nostore_generate_key_pair
+sadb_common_add
segvn_fault_vnodepages
tcp_input_data
diff --git a/usr/src/tools/smatch/src/smatch_data/illumos_user.skipped_functions b/usr/src/tools/smatch/src/smatch_data/illumos_user.skipped_functions
index ce1c807d97..f82ff4f38a 100644
--- a/usr/src/tools/smatch/src/smatch_data/illumos_user.skipped_functions
+++ b/usr/src/tools/smatch/src/smatch_data/illumos_user.skipped_functions
@@ -24,8 +24,12 @@ sqliteVdbeExec
AslCompilerparse
/* cmd/fs.d/autofs */
nfsmount
+/* cmd/mdb */
+iob_doprnt
/* cmd/pppd */
lcp_nakci
+/* cmd/cmd-crypto */
+execute_cmd
/* generated code */
ipf_yyparse
diff --git a/usr/src/tools/smatch/src/smatch_data/kernel.allocation_funcs_gfp.remove b/usr/src/tools/smatch/src/smatch_data/kernel.allocation_funcs_gfp.remove
index 78c093f6f8..4e99631377 100644
--- a/usr/src/tools/smatch/src/smatch_data/kernel.allocation_funcs_gfp.remove
+++ b/usr/src/tools/smatch/src/smatch_data/kernel.allocation_funcs_gfp.remove
@@ -1,2 +1,3 @@
+acquire_group
acquire_group 2
acquire_group X
diff --git a/usr/src/tools/smatch/src/smatch_data/kernel.ignore_casted_params b/usr/src/tools/smatch/src/smatch_data/kernel.ignore_casted_params
new file mode 100644
index 0000000000..4981799f70
--- /dev/null
+++ b/usr/src/tools/smatch/src/smatch_data/kernel.ignore_casted_params
@@ -0,0 +1,15 @@
+set_bit
+clear_bit
+__clear_bit
+__set_bit
+test_and_set_bit
+find_last_bit
+change_bit
+xfs_next_bit
+find_next_bit
+find_first_bit
+__test_and_set_bit
+sync_set_bit
+bitmap_weight
+bitmap_intersects
+bitmap_empty
diff --git a/usr/src/tools/smatch/src/smatch_data/kernel.ignore_side_effects b/usr/src/tools/smatch/src/smatch_data/kernel.ignore_side_effects
index e94fa1e605..b4237017c0 100644
--- a/usr/src/tools/smatch/src/smatch_data/kernel.ignore_side_effects
+++ b/usr/src/tools/smatch/src/smatch_data/kernel.ignore_side_effects
@@ -53,12 +53,16 @@ RADEON_WAIT_UNTIL_IDLE
RCU_INIT_POINTER
READ64
rtnl_dereference
+SK_REUSEPORT_LOAD_SKB_FIELD
+SK_REUSEPORT_LOAD_SK_FIELD_SIZE_OFF
send_bits
send_code
SOCK_ADDR_LOAD_NESTED_FIELD
SOCK_ADDR_LOAD_NESTED_FIELD_SIZE_OFF
SOCK_ADDR_LOAD_OR_STORE_NESTED_FIELD_SIZE_OFF
SOCK_ADDR_LOAD_OR_STORE_NESTED_FIELD
+SOCK_OPS_GET_FIELD
+SOCK_OPS_GET_OR_SET_FIELD
SOCK_OPS_GET_TCP32
unsafe_get_user
unsafe_put_user
diff --git a/usr/src/tools/smatch/src/smatch_data/kernel.ignore_uninitialized_param b/usr/src/tools/smatch/src/smatch_data/kernel.ignore_uninitialized_param
index f76216cfff..16825e753a 100644
--- a/usr/src/tools/smatch/src/smatch_data/kernel.ignore_uninitialized_param
+++ b/usr/src/tools/smatch/src/smatch_data/kernel.ignore_uninitialized_param
@@ -102,3 +102,10 @@ read_current_timer 0
pwrap_read 2
dibusb_read_eeprom_byte 2
of_fdt_unflatten_tree 2
+pci_user_read_config_byte 2
+gen11_gu_misc_irq_ack 2
+vsc73xx_read 4
+smb_hc_read 2
+smb_word_op 5
+atl1c_read_phy_reg 2
+adf7242_read_reg 2
diff --git a/usr/src/tools/smatch/src/smatch_data/kernel.ignored_warnings b/usr/src/tools/smatch/src/smatch_data/kernel.ignored_warnings
new file mode 100644
index 0000000000..758066bc22
--- /dev/null
+++ b/usr/src/tools/smatch/src/smatch_data/kernel.ignored_warnings
@@ -0,0 +1 @@
+check_shift_to_zero overflows_type
diff --git a/usr/src/tools/smatch/src/smatch_data/kernel.no_inline_functions b/usr/src/tools/smatch/src/smatch_data/kernel.no_inline_functions
index 149bc0deaa..388824e15f 100644
--- a/usr/src/tools/smatch/src/smatch_data/kernel.no_inline_functions
+++ b/usr/src/tools/smatch/src/smatch_data/kernel.no_inline_functions
@@ -10,3 +10,5 @@ __arch_hweight32
__arch_hweight64
__write_once_size
atomic_set
+atomic_read
+notifier_to_errno
diff --git a/usr/src/tools/smatch/src/smatch_data/kernel.no_return_funcs.add b/usr/src/tools/smatch/src/smatch_data/kernel.no_return_funcs.add
new file mode 100644
index 0000000000..db33514776
--- /dev/null
+++ b/usr/src/tools/smatch/src/smatch_data/kernel.no_return_funcs.add
@@ -0,0 +1,2 @@
+YY_FATAL_ERROR
+malformed_line
diff --git a/usr/src/tools/smatch/src/smatch_data/kernel.silenced_functions b/usr/src/tools/smatch/src/smatch_data/kernel.silenced_functions
index e23ef2635f..6ff3b95a86 100644
--- a/usr/src/tools/smatch/src/smatch_data/kernel.silenced_functions
+++ b/usr/src/tools/smatch/src/smatch_data/kernel.silenced_functions
@@ -4,7 +4,6 @@ atomic_inc_and_test
atomic64_dec_and_test
atomic_sub_and_test
test_and_clear_bit
-test_and_set_bit
__copy_to_user_nocheck
__copy_from_user_nocheck
arch_static_branch
diff --git a/usr/src/tools/smatch/src/smatch_data_source.c b/usr/src/tools/smatch/src/smatch_data_source.c
index 7ada921cdb..e63c27a89f 100644
--- a/usr/src/tools/smatch/src/smatch_data_source.c
+++ b/usr/src/tools/smatch/src/smatch_data_source.c
@@ -24,12 +24,14 @@ static int my_id;
static char *get_source_parameter(struct expression *expr)
{
struct expression *tmp;
+ const char *param_name;
struct symbol *sym;
char *name;
int param;
char *ret = NULL;
char buf[32];
int cnt = 0;
+ bool modified = false;
tmp = expr;
while ((tmp = get_assigned_expr(tmp))) {
@@ -48,10 +50,14 @@ static char *get_source_parameter(struct expression *expr)
param = get_param_num_from_sym(sym);
if (param < 0)
goto free;
- if (param_was_set(expr))
+ param_name = get_param_name_var_sym(name, sym);
+ if (!param_name)
goto free;
+ if (param_was_set_var_sym(name, sym))
+ modified = true;
- snprintf(buf, sizeof(buf), "p %d", param);
+ snprintf(buf, sizeof(buf), "$%d%s%s", param, param_name + 1,
+ modified ? " [m]" : "");
ret = alloc_string(buf);
free:
diff --git a/usr/src/tools/smatch/src/smatch_db.c b/usr/src/tools/smatch/src/smatch_db.c
index e9e1eab24b..d96c9ace99 100644
--- a/usr/src/tools/smatch/src/smatch_db.c
+++ b/usr/src/tools/smatch/src/smatch_db.c
@@ -79,7 +79,7 @@ char *escape_newlines(const char *str)
int i, j;
for (i = 0, j = 0; str[i] != '\0' && j != sizeof(buf); i++, j++) {
- if (str[i] != '\n') {
+ if (str[i] != '\r' && str[i] != '\n') {
buf[j] = str[i];
continue;
}
@@ -252,8 +252,8 @@ void sql_insert_caller_info(struct expression *call, int type,
void sql_insert_function_ptr(const char *fn, const char *struct_name)
{
- sql_insert(function_ptr, "'%s', '%s', '%s', 0", get_base_file(), fn,
- struct_name);
+ sql_insert_or_ignore(function_ptr, "'%s', '%s', '%s', 0",
+ get_base_file(), fn, struct_name);
}
void sql_insert_return_implies(int type, int param, const char *key, const char *value)
@@ -331,7 +331,7 @@ void sql_save_constraint(const char *con)
if (!option_info)
return;
- sm_msg("SQL: insert or ignore into constraints (str) values('%s');", con);
+ sm_msg("SQL: insert or ignore into constraints (str) values('%s');", escape_newlines(con));
}
void sql_save_constraint_required(const char *data, int op, const char *limit)
@@ -372,11 +372,6 @@ void sql_insert_mtag_about(mtag_t tag, const char *left_name, const char *right_
tag, get_filename(), get_function(), get_lineno(), left_name, right_name);
}
-void sql_insert_mtag_data(mtag_t tag, const char *var, int offset, int type, const char *value)
-{
- sql_insert(mtag_data, "%lld, '%s', %d, %d, '%s'", tag, var, offset, type, value);
-}
-
void sql_insert_mtag_map(mtag_t tag, int offset, mtag_t container)
{
sql_insert(mtag_map, "%lld, %d, %lld", tag, offset, container);
@@ -750,29 +745,58 @@ static char *show_offset(int offset)
return buf;
}
+int is_recursive_member(const char *name)
+{
+ char buf[256];
+ const char *p, *next;
+ int size;
+
+ p = strchr(name, '>');
+ if (!p)
+ return 0;
+ p++;
+ while (true) {
+ next = strchr(p, '>');
+ if (!next)
+ return 0;
+ next++;
+
+ size = next - p;
+ if (size >= sizeof(buf))
+ return 0;
+ memcpy(buf, p, size);
+ buf[size] = '\0';
+ if (strstr(next, buf))
+ return 1;
+ p = next;
+ }
+}
+
static void print_struct_members(struct expression *call, struct expression *expr, int param, int offset, struct stree *stree,
void (*callback)(struct expression *call, int param, char *printed_name, struct sm_state *sm))
{
struct sm_state *sm;
+ const char *sm_name;
char *name;
struct symbol *sym;
int len;
char printed_name[256];
int is_address = 0;
+ bool add_star;
struct symbol *type;
expr = strip_expr(expr);
if (!expr)
return;
+ type = get_type(expr);
+ if (type && type_bits(type) < type_bits(&ulong_ctype))
+ return;
+
if (expr->type == EXPR_PREOP && expr->op == '&') {
expr = strip_expr(expr->unop);
is_address = 1;
}
- type = get_type(expr);
- if (type && type_bits(type) < type_bits(&ulong_ctype))
- return;
-
name = expr_to_var_sym(expr, &sym);
if (!name || !sym)
goto free;
@@ -781,23 +805,37 @@ static void print_struct_members(struct expression *call, struct expression *exp
FOR_EACH_SM(stree, sm) {
if (sm->sym != sym)
continue;
- if (strcmp(name, sm->name) == 0) {
+ sm_name = sm->name;
+ add_star = false;
+ if (sm_name[0] == '*') {
+ add_star = true;
+ sm_name++;
+ }
+ // FIXME: simplify?
+ if (!add_star && strcmp(name, sm_name) == 0) {
if (is_address)
snprintf(printed_name, sizeof(printed_name), "*$%s", show_offset(offset));
else /* these are already handled. fixme: handle them here */
continue;
- } else if (sm->name[0] == '*' && strcmp(name, sm->name + 1) == 0) {
- snprintf(printed_name, sizeof(printed_name), "*$%s", show_offset(offset));
- } else if (strncmp(name, sm->name, len) == 0) {
- if (isalnum(sm->name[len]))
+ } else if (add_star && strcmp(name, sm_name) == 0) {
+ snprintf(printed_name, sizeof(printed_name), "%s*$%s",
+ is_address ? "*" : "", show_offset(offset));
+ } else if (strncmp(name, sm_name, len) == 0) {
+ if (sm_name[len] != '.' && sm_name[len] != '-')
continue;
if (is_address)
- snprintf(printed_name, sizeof(printed_name), "$%s->%s", show_offset(offset), sm->name + len + 1);
+ snprintf(printed_name, sizeof(printed_name),
+ "%s$%s->%s", add_star ? "*" : "",
+ show_offset(offset), sm_name + len + 1);
else
- snprintf(printed_name, sizeof(printed_name), "$%s%s", show_offset(offset), sm->name + len);
+ snprintf(printed_name, sizeof(printed_name),
+ "%s$%s%s", add_star ? "*" : "",
+ show_offset(offset), sm_name + len);
} else {
continue;
}
+ if (is_recursive_member(printed_name))
+ continue;
callback(call, param, printed_name, sm);
} END_FOR_EACH_SM(sm);
free:
@@ -1009,9 +1047,8 @@ static char *get_next_ptr_name(void)
char *ptr;
FOR_EACH_PTR(ptr_names, ptr) {
- if (list_has_string(ptr_names_done, ptr))
+ if (!insert_string(&ptr_names_done, ptr))
continue;
- insert_string(&ptr_names_done, ptr);
return ptr;
} END_FOR_EACH_PTR(ptr);
return NULL;
@@ -1224,53 +1261,97 @@ static void match_call_implies(struct symbol *sym)
call_implies_callbacks);
}
-static void print_initializer_list(struct expression_list *expr_list,
- struct symbol *struct_type)
+static char *get_return_compare_is_param(struct expression *expr)
{
- struct expression *expr;
- struct symbol *base_type;
- char struct_name[256];
+ char *var;
+ char buf[256];
+ int comparison;
+ int param;
- FOR_EACH_PTR(expr_list, expr) {
- if (expr->type == EXPR_INDEX && expr->idx_expression && expr->idx_expression->type == EXPR_INITIALIZER) {
- print_initializer_list(expr->idx_expression->expr_list, struct_type);
- continue;
- }
- if (expr->type != EXPR_IDENTIFIER)
- continue;
- if (!expr->expr_ident)
- continue;
- if (!expr->ident_expression || !expr->ident_expression->symbol_name)
- continue;
- base_type = get_type(expr->ident_expression);
- if (!base_type || base_type->type != SYM_FN)
- continue;
- snprintf(struct_name, sizeof(struct_name), "(struct %s)->%s",
- struct_type->ident->name, expr->expr_ident->name);
- sql_insert_function_ptr(expr->ident_expression->symbol_name->name,
- struct_name);
- } END_FOR_EACH_PTR(expr);
+ param = get_param_num(expr);
+ if (param < 0)
+ return NULL;
+
+ var = expr_to_var(expr);
+ if (!var)
+ return NULL;
+ snprintf(buf, sizeof(buf), "%s orig", var);
+ comparison = get_comparison_strings(var, buf);
+ free_string(var);
+
+ if (!comparison)
+ return NULL;
+
+ snprintf(buf, sizeof(buf), "[%s$%d]", show_special(comparison), param);
+ return alloc_sname(buf);
}
-static void global_variable(struct symbol *sym)
+static char *get_return_compare_str(struct expression *expr)
{
- struct symbol *struct_type;
+ char *compare_str;
- if (!sym->ident)
- return;
- if (!sym->initializer || sym->initializer->type != EXPR_INITIALIZER)
- return;
- struct_type = get_base_type(sym);
- if (!struct_type)
- return;
- if (struct_type->type == SYM_ARRAY) {
- struct_type = get_base_type(struct_type);
- if (!struct_type)
- return;
+ compare_str = get_return_compare_is_param(expr);
+ if (compare_str)
+ return compare_str;
+
+ compare_str = expr_lte_to_param(expr, -1);
+ if (compare_str)
+ return compare_str;
+
+ return expr_param_comparison(expr, -1);
+}
+
+static const char *get_return_ranges_str(struct expression *expr, struct range_list **rl_p)
+{
+ struct range_list *rl;
+ char *return_ranges;
+ sval_t sval;
+ char *compare_str;
+ char *math_str;
+ char buf[128];
+
+ *rl_p = NULL;
+
+ if (!expr)
+ return alloc_sname("");
+
+ if (get_implied_value(expr, &sval)) {
+ sval = sval_cast(cur_func_return_type(), sval);
+ *rl_p = alloc_rl(sval, sval);
+ return sval_to_str_or_err_ptr(sval);
}
- if (struct_type->type != SYM_STRUCT || !struct_type->ident)
- return;
- print_initializer_list(sym->initializer->expr_list, struct_type);
+
+ compare_str = expr_equal_to_param(expr, -1);
+ math_str = get_value_in_terms_of_parameter_math(expr);
+
+ if (get_implied_rl(expr, &rl) && !is_whole_rl(rl)) {
+ rl = cast_rl(cur_func_return_type(), rl);
+ return_ranges = show_rl(rl);
+ } else if (get_imaginary_absolute(expr, &rl)){
+ rl = cast_rl(cur_func_return_type(), rl);
+ return alloc_sname(show_rl(rl));
+ } else {
+ get_absolute_rl(expr, &rl);
+ rl = cast_rl(cur_func_return_type(), rl);
+ return_ranges = show_rl(rl);
+ }
+ *rl_p = rl;
+
+ if (compare_str) {
+ snprintf(buf, sizeof(buf), "%s%s", return_ranges, compare_str);
+ return alloc_sname(buf);
+ }
+ if (math_str) {
+ snprintf(buf, sizeof(buf), "%s[%s]", return_ranges, math_str);
+ return alloc_sname(buf);
+ }
+ compare_str = get_return_compare_str(expr);
+ if (compare_str) {
+ snprintf(buf, sizeof(buf), "%s%s", return_ranges, compare_str);
+ return alloc_sname(buf);
+ }
+
+ return return_ranges;
}
static void match_return_info(int return_id, char *return_ranges, struct expression *expr)
@@ -1282,7 +1363,7 @@ static void call_return_state_hooks_conditional(struct expression *expr)
{
struct returned_state_callback *cb;
struct range_list *rl;
- char *return_ranges;
+ const char *return_ranges;
int final_pass_orig = final_pass;
__push_fake_cur_stree();
@@ -1291,31 +1372,24 @@ static void call_return_state_hooks_conditional(struct expression *expr)
__split_whole_condition(expr->conditional);
final_pass = final_pass_orig;
- if (get_implied_rl(expr->cond_true, &rl))
- rl = cast_rl(cur_func_return_type(), rl);
- else
- rl = cast_rl(cur_func_return_type(), alloc_whole_rl(get_type(expr->cond_true)));
- return_ranges = show_rl(rl);
+ return_ranges = get_return_ranges_str(expr->cond_true ?: expr->conditional, &rl);
+
set_state(RETURN_ID, "return_ranges", NULL, alloc_estate_rl(rl));
return_id++;
FOR_EACH_PTR(returned_state_callbacks, cb) {
- cb->callback(return_id, return_ranges, expr->cond_true);
+ cb->callback(return_id, (char *)return_ranges, expr->cond_true);
} END_FOR_EACH_PTR(cb);
__push_true_states();
__use_false_states();
- if (get_implied_rl(expr->cond_false, &rl))
- rl = cast_rl(cur_func_return_type(), rl);
- else
- rl = cast_rl(cur_func_return_type(), alloc_whole_rl(get_type(expr->cond_false)));
- return_ranges = show_rl(rl);
+ return_ranges = get_return_ranges_str(expr->cond_false, &rl);
set_state(RETURN_ID, "return_ranges", NULL, alloc_estate_rl(rl));
return_id++;
FOR_EACH_PTR(returned_state_callbacks, cb) {
- cb->callback(return_id, return_ranges, expr->cond_false);
+ cb->callback(return_id, (char *)return_ranges, expr->cond_false);
} END_FOR_EACH_PTR(cb);
__merge_true_states();
@@ -1380,35 +1454,6 @@ static int ptr_in_list(struct sm_state *sm, struct state_list *slist)
return 0;
}
-static char *get_return_compare_str(struct expression *expr)
-{
- char *compare_str;
- char *var;
- char buf[256];
- int comparison;
- int param;
-
- compare_str = expr_lte_to_param(expr, -1);
- if (compare_str)
- return compare_str;
- param = get_param_num(expr);
- if (param < 0)
- return NULL;
-
- var = expr_to_var(expr);
- if (!var)
- return NULL;
- snprintf(buf, sizeof(buf), "%s orig", var);
- comparison = get_comparison_strings(var, buf);
- free_string(var);
-
- if (!comparison)
- return NULL;
-
- snprintf(buf, sizeof(buf), "[%s$%d]", show_special(comparison), param);
- return alloc_sname(buf);
-}
-
static int split_possible_helper(struct sm_state *sm, struct expression *expr)
{
struct returned_state_callback *cb;
@@ -1417,9 +1462,10 @@ static int split_possible_helper(struct sm_state *sm, struct expression *expr)
struct sm_state *tmp;
int ret = 0;
int nr_possible, nr_states;
- char *compare_str = NULL;
+ char *compare_str;
char buf[128];
struct state_list *already_handled = NULL;
+ sval_t sval;
if (!sm || !sm->merged)
return 0;
@@ -1428,7 +1474,12 @@ static int split_possible_helper(struct sm_state *sm, struct expression *expr)
return 0;
/* bail if it gets too complicated */
- nr_possible = ptr_list_size((struct ptr_list *)sm->possible);
+ nr_possible = 0;
+ FOR_EACH_PTR(sm->possible, tmp) {
+ if (tmp->merged)
+ continue;
+ nr_possible++;
+ } END_FOR_EACH_PTR(tmp);
nr_states = get_db_state_count();
if (nr_states * nr_possible >= 2000)
return 0;
@@ -1448,10 +1499,12 @@ static int split_possible_helper(struct sm_state *sm, struct expression *expr)
rl = cast_rl(cur_func_return_type(), estate_rl(tmp->state));
return_ranges = show_rl(rl);
set_state(RETURN_ID, "return_ranges", NULL, alloc_estate_rl(clone_rl(rl)));
- compare_str = get_return_compare_str(expr);
- if (compare_str) {
- snprintf(buf, sizeof(buf), "%s%s", return_ranges, compare_str);
- return_ranges = alloc_sname(buf);
+ if (!rl_to_sval(rl, &sval)) {
+ compare_str = get_return_compare_str(expr);
+ if (compare_str) {
+ snprintf(buf, sizeof(buf), "%s%s", return_ranges, compare_str);
+ return_ranges = alloc_sname(buf);
+ }
}
return_id++;
@@ -1478,58 +1531,6 @@ static int call_return_state_hooks_split_possible(struct expression *expr)
return split_possible_helper(sm, expr);
}
-static const char *get_return_ranges_str(struct expression *expr, struct range_list **rl_p)
-{
- struct range_list *rl;
- char *return_ranges;
- sval_t sval;
- char *compare_str;
- char *math_str;
- char buf[128];
-
- *rl_p = NULL;
-
- if (!expr)
- return alloc_sname("");
-
- if (get_implied_value(expr, &sval)) {
- sval = sval_cast(cur_func_return_type(), sval);
- *rl_p = alloc_rl(sval, sval);
- return sval_to_str(sval);
- }
-
- compare_str = expr_equal_to_param(expr, -1);
- math_str = get_value_in_terms_of_parameter_math(expr);
-
- if (get_implied_rl(expr, &rl)) {
- rl = cast_rl(cur_func_return_type(), rl);
- return_ranges = show_rl(rl);
- } else if (get_imaginary_absolute(expr, &rl)){
- rl = cast_rl(cur_func_return_type(), rl);
- return alloc_sname(show_rl(rl));
- } else {
- rl = cast_rl(cur_func_return_type(), alloc_whole_rl(get_type(expr)));
- return_ranges = show_rl(rl);
- }
- *rl_p = rl;
-
- if (compare_str) {
- snprintf(buf, sizeof(buf), "%s%s", return_ranges, compare_str);
- return alloc_sname(buf);
- }
- if (math_str) {
- snprintf(buf, sizeof(buf), "%s[%s]", return_ranges, math_str);
- return alloc_sname(buf);
- }
- compare_str = get_return_compare_str(expr);
- if (compare_str) {
- snprintf(buf, sizeof(buf), "%s%s", return_ranges, compare_str);
- return alloc_sname(buf);
- }
-
- return return_ranges;
-}
-
static bool has_possible_negative(struct sm_state *sm)
{
struct sm_state *tmp;
@@ -1568,6 +1569,7 @@ static int split_positive_from_negative(struct expression *expr)
const char *return_ranges;
struct range_list *ret_rl;
int undo;
+ bool has_zero;
/* We're going to print the states 3 times */
if (get_db_state_count() > 10000 / 3)
@@ -1588,8 +1590,9 @@ static int split_positive_from_negative(struct expression *expr)
return 0;
if (!has_possible_negative(sm))
return 0;
+ has_zero = has_possible_zero_null(sm);
- if (!assume(compare_expression(expr, '>', zero_expr())))
+ if (!assume(compare_expression(expr, has_zero ? '>' : SPECIAL_GTE, zero_expr())))
return 0;
return_id++;
@@ -1601,7 +1604,7 @@ static int split_positive_from_negative(struct expression *expr)
end_assume();
- if (rl_has_sval(rl, sval_type_val(rl_type(rl), 0))) {
+ if (has_zero) {
undo = assume(compare_expression(expr, SPECIAL_EQUAL, zero_expr()));
return_id++;
@@ -1630,7 +1633,7 @@ static int split_positive_from_negative(struct expression *expr)
return 1;
}
-static int call_return_state_hooks_split_null_non_null(struct expression *expr)
+static int call_return_state_hooks_split_null_non_null_zero(struct expression *expr)
{
struct returned_state_callback *cb;
struct range_list *rl;
@@ -1647,8 +1650,6 @@ static int call_return_state_hooks_split_null_non_null(struct expression *expr)
return 0;
if (expr->type == EXPR_CALL)
return 0;
- if (!is_pointer(expr))
- return 0;
sm = get_sm_state_expr(SMATCH_EXTRA, expr);
if (!sm)
@@ -1992,14 +1993,14 @@ static void call_return_state_hooks(struct expression *expr)
return;
} else if (call_return_state_hooks_split_possible(expr)) {
return;
- } else if (call_return_state_hooks_split_null_non_null(expr)) {
+ } else if (split_positive_from_negative(expr)) {
+ return;
+ } else if (call_return_state_hooks_split_null_non_null_zero(expr)) {
return;
} else if (call_return_state_hooks_split_success_fail(expr)) {
return;
} else if (splitable_function_call(expr)) {
return;
- } else if (split_positive_from_negative(expr)) {
- return;
} else if (split_by_bool_param(expr)) {
} else if (split_by_null_nonnull_param(expr)) {
return;
@@ -2208,7 +2209,7 @@ static int save_cache_data(void *_table, int argc, char **argv, char **azColName
for (i = 0; i < argc; i++) {
if (i)
p += snprintf(p, 4096 - (p - buf), ", ");
- sqlite3_snprintf(sizeof(tmp), tmp, "%q", argv[i]);
+ sqlite3_snprintf(sizeof(tmp), tmp, "%q", escape_newlines(argv[i]));
p += snprintf(p, 4096 - (p - buf), "'%s'", tmp);
}
@@ -2361,8 +2362,6 @@ static void register_return_replacements(void)
void register_definition_db_callbacks(int id)
{
add_hook(&match_call_info, FUNCTION_CALL_HOOK);
- add_hook(&global_variable, BASE_HOOK);
- add_hook(&global_variable, DECLARATION_HOOK);
add_split_return_callback(match_return_info);
add_split_return_callback(print_returned_struct_members);
add_hook(&call_return_state_hooks, RETURN_HOOK);
@@ -2397,6 +2396,8 @@ char *return_state_to_var_sym(struct expression *expr, int param, const char *ke
if (expr->type != EXPR_ASSIGNMENT)
return NULL;
+ if (get_type(expr->left) == &int_ctype && strcmp(key, "$") != 0)
+ return NULL;
name = expr_to_var_sym(expr->left, sym);
if (!name)
return NULL;
@@ -2427,6 +2428,7 @@ char *get_variable_from_key(struct expression *arg, const char *key, struct symb
{
char buf[256];
char *tmp;
+ bool add_star = false;
if (!arg)
return NULL;
@@ -2450,19 +2452,25 @@ char *get_variable_from_key(struct expression *arg, const char *key, struct symb
}
}
+ if (key[0] == '*') {
+ add_star = true;
+ key++;
+ }
+
if (arg->type == EXPR_PREOP && arg->op == '&') {
arg = strip_expr(arg->unop);
tmp = expr_to_var_sym(arg, sym);
if (!tmp)
return NULL;
- snprintf(buf, sizeof(buf), "%s.%s", tmp, key + 3);
+ snprintf(buf, sizeof(buf), "%s%s.%s",
+ add_star ? "*" : "", tmp, key + 3);
return alloc_string(buf);
}
tmp = expr_to_var_sym(arg, sym);
if (!tmp)
return NULL;
- snprintf(buf, sizeof(buf), "%s%s", tmp, key + 1);
+ snprintf(buf, sizeof(buf), "%s%s%s", add_star ? "*" : "", tmp, key + 1);
free_string(tmp);
return alloc_string(buf);
}
@@ -2480,17 +2488,25 @@ const char *state_name_to_param_name(const char *state_name, const char *param_n
{
int name_len;
static char buf[256];
+ bool add_star = false;
name_len = strlen(param_name);
+ if (state_name[0] == '*') {
+ add_star = true;
+ state_name++;
+ }
+
if (strcmp(state_name, param_name) == 0) {
- return "$";
- } else if (state_name[name_len] == '-' && /* check for '-' from "->" */
+ snprintf(buf, sizeof(buf), "%s$", add_star ? "*" : "");
+ return buf;
+ }
+
+ if (state_name[name_len] == '-' && /* check for '-' from "->" */
strncmp(state_name, param_name, name_len) == 0) {
- snprintf(buf, sizeof(buf), "$%s", state_name + name_len);
+ snprintf(buf, sizeof(buf), "%s$%s",
+ add_star ? "*" : "", state_name + name_len);
return buf;
- } else if (state_name[0] == '*' && strcmp(state_name + 1, param_name) == 0) {
- return "*$";
}
return NULL;
}
diff --git a/usr/src/tools/smatch/src/smatch_equiv.c b/usr/src/tools/smatch/src/smatch_equiv.c
index e00b6f2a6a..4e99c37a83 100644
--- a/usr/src/tools/smatch/src/smatch_equiv.c
+++ b/usr/src/tools/smatch/src/smatch_equiv.c
@@ -102,21 +102,6 @@ struct related_list *get_shared_relations(struct related_list *one,
return ret;
}
-static void debug_addition(struct related_list *rlist, const char *name)
-{
- struct relation *tmp;
-
- if (!option_debug_related)
- return;
-
- sm_prefix();
- sm_printf("(");
- FOR_EACH_PTR(rlist, tmp) {
- sm_printf("%s ", tmp->name);
- } END_FOR_EACH_PTR(tmp);
- sm_printf(") <-- %s\n", name);
-}
-
static void add_related(struct related_list **rlist, const char *name, struct symbol *sym)
{
struct relation *rel;
@@ -126,8 +111,6 @@ static void add_related(struct related_list **rlist, const char *name, struct sy
.sym = sym
};
- debug_addition(*rlist, name);
-
FOR_EACH_PTR(*rlist, rel) {
if (cmp_relation(rel, &tmp) < 0)
continue;
@@ -212,19 +195,28 @@ void set_related(struct smatch_state *estate, struct related_list *rlist)
*/
void set_equiv(struct expression *left, struct expression *right)
{
- struct sm_state *right_sm, *left_sm;
+ struct sm_state *right_sm, *left_sm, *other_sm;
struct relation *rel;
char *left_name;
struct symbol *left_sym;
struct related_list *rlist;
+ char *other_name;
+ struct symbol *other_sym;
left_name = expr_to_var_sym(left, &left_sym);
if (!left_name || !left_sym)
goto free;
+ other_name = get_other_name_sym(left_name, left_sym, &other_sym);
+
right_sm = get_sm_state_expr(SMATCH_EXTRA, right);
- if (!right_sm)
- right_sm = set_state_expr(SMATCH_EXTRA, right, alloc_estate_whole(get_type(right)));
+ if (!right_sm) {
+ struct range_list *rl;
+
+ if (!get_implied_rl(right, &rl))
+ rl = alloc_whole_rl(get_type(right));
+ right_sm = set_state_expr(SMATCH_EXTRA, right, alloc_estate_rl(rl));
+ }
if (!right_sm)
goto free;
@@ -233,12 +225,24 @@ void set_equiv(struct expression *left, struct expression *right)
left_sm->name = alloc_string(left_name);
left_sm->sym = left_sym;
left_sm->state = clone_estate_cast(get_type(left), right_sm->state);
+ /* FIXME: The expression we're passing is wrong */
set_extra_mod_helper(left_name, left_sym, left, left_sm->state);
__set_sm(left_sm);
+ if (other_name && other_sym) {
+ other_sm = clone_sm(right_sm);
+ other_sm->name = alloc_string(other_name);
+ other_sm->sym = other_sym;
+ other_sm->state = clone_estate_cast(get_type(left), left_sm->state);
+ set_extra_mod_helper(other_name, other_sym, NULL, other_sm->state);
+ __set_sm(other_sm);
+ }
+
rlist = clone_related_list(estate_related(right_sm->state));
add_related(&rlist, right_sm->name, right_sm->sym);
add_related(&rlist, left_name, left_sym);
+ if (other_name && other_sym)
+ add_related(&rlist, other_name, other_sym);
FOR_EACH_PTR(rlist, rel) {
struct sm_state *old_sm, *new_sm;
diff --git a/usr/src/tools/smatch/src/smatch_estate.c b/usr/src/tools/smatch/src/smatch_estate.c
index 61a8fd347a..533cd2d9e0 100644
--- a/usr/src/tools/smatch/src/smatch_estate.c
+++ b/usr/src/tools/smatch/src/smatch_estate.c
@@ -43,11 +43,16 @@ struct smatch_state *merge_estates(struct smatch_state *s1, struct smatch_state
tmp = alloc_estate_rl(value_ranges);
rlist = get_shared_relations(estate_related(s1), estate_related(s2));
set_related(tmp, rlist);
- if (estate_has_hard_max(s1) && estate_has_hard_max(s2))
+
+ if ((estate_has_hard_max(s1) && (!estate_rl(s2) || estate_has_hard_max(s2))) ||
+ (estate_has_hard_max(s2) && (!estate_rl(s1) || estate_has_hard_max(s1))))
estate_set_hard_max(tmp);
estate_set_fuzzy_max(tmp, sval_max(estate_get_fuzzy_max(s1), estate_get_fuzzy_max(s2)));
+ if (estate_capped(s1) && estate_capped(s2))
+ estate_set_capped(tmp);
+
return tmp;
}
@@ -134,6 +139,21 @@ int estate_get_hard_max(struct smatch_state *state, sval_t *sval)
return 1;
}
+bool estate_capped(struct smatch_state *state)
+{
+ if (!state)
+ return false;
+ /* impossible states are capped */
+ if (!estate_rl(state))
+ return true;
+ return get_dinfo(state)->capped;
+}
+
+void estate_set_capped(struct smatch_state *state)
+{
+ get_dinfo(state)->capped = true;
+}
+
sval_t estate_min(struct smatch_state *state)
{
return rl_min(estate_rl(state));
@@ -182,6 +202,8 @@ int estates_equiv(struct smatch_state *one, struct smatch_state *two)
return 1;
if (!rlists_equiv(estate_related(one), estate_related(two)))
return 0;
+ if (estate_capped(one) != estate_capped(two))
+ return 0;
if (strcmp(one->name, two->name) == 0)
return 1;
return 0;
@@ -272,6 +294,25 @@ struct smatch_state *clone_estate(struct smatch_state *state)
return ret;
}
+struct smatch_state *clone_partial_estate(struct smatch_state *state, struct range_list *rl)
+{
+ struct smatch_state *ret;
+
+ if (!state)
+ return NULL;
+
+ rl = cast_rl(estate_type(state), rl);
+
+ ret = alloc_estate_rl(rl);
+ set_related(ret, clone_related_list(estate_related(state)));
+ if (estate_has_hard_max(state))
+ estate_set_hard_max(ret);
+ if (estate_has_fuzzy_max(state))
+ estate_set_fuzzy_max(ret, estate_get_fuzzy_max(state));
+
+ return ret;
+}
+
struct smatch_state *alloc_estate_empty(void)
{
struct smatch_state *state;
@@ -365,29 +406,6 @@ struct smatch_state *get_implied_estate(struct expression *expr)
return alloc_estate_rl(rl);
}
-struct smatch_state *estate_filter_range(struct smatch_state *orig,
- sval_t filter_min, sval_t filter_max)
-{
- struct range_list *rl;
- struct smatch_state *state;
-
- if (!orig)
- orig = alloc_estate_whole(filter_min.type);
-
- rl = remove_range(estate_rl(orig), filter_min, filter_max);
- state = alloc_estate_rl(rl);
- if (estate_has_hard_max(orig))
- estate_set_hard_max(state);
- if (estate_has_fuzzy_max(orig))
- estate_set_fuzzy_max(state, estate_get_fuzzy_max(orig));
- return state;
-}
-
-struct smatch_state *estate_filter_sval(struct smatch_state *orig, sval_t sval)
-{
- return estate_filter_range(orig, sval, sval);
-}
-
/*
* One of the complications is that smatch tries to free a bunch of data at the
* end of every function.
diff --git a/usr/src/tools/smatch/src/smatch_expressions.c b/usr/src/tools/smatch/src/smatch_expressions.c
index 9900342b89..a0d05ed8cb 100644
--- a/usr/src/tools/smatch/src/smatch_expressions.c
+++ b/usr/src/tools/smatch/src/smatch_expressions.c
@@ -165,7 +165,7 @@ struct expression *string_expression(char *str)
struct expression *gen_expression_from_key(struct expression *arg, const char *key)
{
struct expression *ret;
- struct token *token, *end;
+ struct token *token, *prev, *end;
const char *p = key;
char buf[4095];
char *alloc;
@@ -189,12 +189,15 @@ struct expression *gen_expression_from_key(struct expression *arg, const char *k
ret = arg;
while (token_type(token) == TOKEN_SPECIAL &&
- token->special == SPECIAL_DEREFERENCE) {
+ (token->special == SPECIAL_DEREFERENCE || token->special == '.')) {
+ prev = token;
token = token->next;
if (token_type(token) != TOKEN_IDENT)
return NULL;
ret = deref_expression(ret);
- ret = member_expression(ret, '*', token->ident);
+ ret = member_expression(ret,
+ (prev->special == SPECIAL_DEREFERENCE) ? '*' : '.',
+ token->ident);
token = token->next;
}
diff --git a/usr/src/tools/smatch/src/smatch_extra.c b/usr/src/tools/smatch/src/smatch_extra.c
index 0633cffc6d..c756182355 100644
--- a/usr/src/tools/smatch/src/smatch_extra.c
+++ b/usr/src/tools/smatch/src/smatch_extra.c
@@ -36,11 +36,12 @@
static int my_id;
static int link_id;
+extern int check_assigned_expr_id;
static void match_link_modify(struct sm_state *sm, struct expression *mod_expr);
struct string_list *__ignored_macros = NULL;
-static int in_warn_on_macro(void)
+int in_warn_on_macro(void)
{
struct statement *stmt;
char *tmp;
@@ -134,62 +135,123 @@ static char *get_pointed_at(const char *name, struct symbol *sym, struct symbol
return expr_to_var_sym(assigned->unop, new_sym);
}
-char *get_other_name_sym(const char *name, struct symbol *sym, struct symbol **new_sym)
+char *get_other_name_sym_from_chunk(const char *name, const char *chunk, int len, struct symbol *sym, struct symbol **new_sym)
{
struct expression *assigned;
char *orig_name = NULL;
char buf[256];
- char *ret = NULL;
- int skip;
-
- *new_sym = NULL;
-
- if (!sym || !sym->ident)
- return NULL;
-
- ret = get_pointed_at(name, sym, new_sym);
- if (ret)
- return ret;
+ char *ret;
- skip = strlen(sym->ident->name);
- if (name[skip] != '-' || name[skip + 1] != '>')
- return NULL;
- skip += 2;
-
- assigned = get_assigned_expr_name_sym(sym->ident->name, sym);
+ assigned = get_assigned_expr_name_sym(chunk, sym);
if (!assigned)
return NULL;
if (assigned->type == EXPR_CALL)
return map_call_to_other_name_sym(name, sym, new_sym);
- if (assigned->type == EXPR_PREOP || assigned->op == '&') {
+ if (assigned->type == EXPR_PREOP && assigned->op == '&') {
orig_name = expr_to_var_sym(assigned, new_sym);
if (!orig_name || !*new_sym)
goto free;
- snprintf(buf, sizeof(buf), "%s.%s", orig_name + 1, name + skip);
+ snprintf(buf, sizeof(buf), "%s.%s", orig_name + 1, name + len);
ret = alloc_string(buf);
free_string(orig_name);
return ret;
}
- if (assigned->type != EXPR_DEREF)
- goto free;
-
orig_name = expr_to_var_sym(assigned, new_sym);
if (!orig_name || !*new_sym)
goto free;
- snprintf(buf, sizeof(buf), "%s->%s", orig_name, name + skip);
+ snprintf(buf, sizeof(buf), "%s->%s", orig_name, name + len);
ret = alloc_string(buf);
free_string(orig_name);
return ret;
-
free:
free_string(orig_name);
return NULL;
}
+static char *get_long_name_sym(const char *name, struct symbol *sym, struct symbol **new_sym)
+{
+ struct expression *tmp;
+ struct sm_state *sm;
+ char buf[256];
+
+ /*
+ * Just prepend the name with a different name/sym and return that.
+ * For example, if we set "foo->bar = bar;" then we clamp "bar->baz",
+ * that also clamps "foo->bar->baz".
+ *
+ */
+
+ FOR_EACH_MY_SM(check_assigned_expr_id, __get_cur_stree(), sm) {
+ tmp = sm->state->data;
+ if (!tmp || tmp->type != EXPR_SYMBOL)
+ continue;
+ if (tmp->symbol == sym)
+ goto found;
+ } END_FOR_EACH_SM(sm);
+
+ return NULL;
+
+found:
+ snprintf(buf, sizeof(buf), "%s%s", sm->name, name + tmp->symbol->ident->len);
+ *new_sym = sm->sym;
+ return alloc_string(buf);
+}
+
+char *get_other_name_sym_helper(const char *name, struct symbol *sym, struct symbol **new_sym, bool use_stack)
+{
+ char buf[256];
+ char *ret;
+ int len;
+
+ *new_sym = NULL;
+
+ if (!sym || !sym->ident)
+ return NULL;
+
+ ret = get_pointed_at(name, sym, new_sym);
+ if (ret)
+ return ret;
+
+ ret = map_long_to_short_name_sym(name, sym, new_sym, use_stack);
+ if (ret)
+ return ret;
+
+ len = snprintf(buf, sizeof(buf), "%s", name);
+ if (len >= sizeof(buf) - 2)
+ return NULL;
+
+ while (len >= 1) {
+ if (buf[len] == '>' && buf[len - 1] == '-') {
+ len--;
+ buf[len] = '\0';
+ ret = get_other_name_sym_from_chunk(name, buf, len + 2, sym, new_sym);
+ if (ret)
+ return ret;
+ }
+ len--;
+ }
+
+ ret = get_long_name_sym(name, sym, new_sym);
+ if (ret)
+ return ret;
+
+ return NULL;
+}
+
+char *get_other_name_sym(const char *name, struct symbol *sym, struct symbol **new_sym)
+{
+ return get_other_name_sym_helper(name, sym, new_sym, true);
+}
+
+char *get_other_name_sym_nostack(const char *name, struct symbol *sym, struct symbol **new_sym)
+{
+ return get_other_name_sym_helper(name, sym, new_sym, false);
+}
+
void set_extra_mod(const char *name, struct symbol *sym, struct expression *expr, struct smatch_state *state)
{
char *new_name;
@@ -301,8 +363,6 @@ void set_extra_nomod(const char *name, struct symbol *sym, struct expression *ex
FOR_EACH_PTR(estate_related(orig_state), rel) {
struct smatch_state *estate;
- if (option_debug_related)
- sm_msg("%s updating related %s to %s", name, rel->name, state->name);
estate = get_state(SMATCH_EXTRA, rel->name, rel->sym);
if (!estate)
continue;
@@ -484,6 +544,7 @@ static struct sm_state *handle_canonical_while_count_down(struct statement *loop
{
struct expression *iter_var;
struct expression *condition, *unop;
+ struct symbol *type;
struct sm_state *sm;
struct smatch_state *estate;
int op;
@@ -507,6 +568,11 @@ static struct sm_state *handle_canonical_while_count_down(struct statement *loop
if (sval_cmp(estate_min(sm->state), right) < 0)
return NULL;
start = estate_max(sm->state);
+
+ type = get_type(iter_var);
+ right = sval_cast(type, right);
+ start = sval_cast(type, start);
+
if (sval_cmp(start, right) <= 0)
return NULL;
if (!sval_is_max(start))
@@ -540,6 +606,7 @@ static struct sm_state *handle_canonical_for_inc(struct expression *iter_expr,
struct sm_state *sm;
struct smatch_state *estate;
sval_t start, end, max;
+ struct symbol *type;
iter_var = iter_expr->unop;
sm = get_sm_state_expr(SMATCH_EXTRA, iter_var);
@@ -547,10 +614,8 @@ static struct sm_state *handle_canonical_for_inc(struct expression *iter_expr,
return NULL;
if (!estate_get_single_value(sm->state, &start))
return NULL;
- if (get_implied_max(condition->right, &end))
- end = sval_cast(get_type(iter_var), end);
- else
- end = sval_type_max(get_type(iter_var));
+ if (!get_implied_value(condition->right, &end))
+ return NULL;
if (get_sm_state_expr(SMATCH_EXTRA, condition->left) != sm)
return NULL;
@@ -570,13 +635,18 @@ static struct sm_state *handle_canonical_for_inc(struct expression *iter_expr,
}
if (sval_cmp(end, start) < 0)
return NULL;
+ type = get_type(iter_var);
+ start = sval_cast(type, start);
+ end = sval_cast(type, end);
estate = alloc_estate_range(start, end);
if (get_hard_max(condition->right, &max)) {
- estate_set_hard_max(estate);
+ if (!get_macro_name(condition->pos))
+ estate_set_hard_max(estate);
if (condition->op == '<' ||
condition->op == SPECIAL_UNSIGNED_LT ||
condition->op == SPECIAL_NOTEQUAL)
max.value--;
+ max = sval_cast(type, max);
estate_set_fuzzy_max(estate, max);
}
set_extra_expr_mod(iter_var, estate);
@@ -599,13 +669,14 @@ static struct sm_state *handle_canonical_for_dec(struct expression *iter_expr,
return NULL;
if (!get_implied_min(condition->right, &end))
end = sval_type_min(get_type(iter_var));
+ end = sval_cast(estate_type(sm->state), end);
if (get_sm_state_expr(SMATCH_EXTRA, condition->left) != sm)
return NULL;
switch (condition->op) {
case SPECIAL_NOTEQUAL:
case '>':
- if (!sval_is_min(end) && !sval_is_max(end))
+ if (!sval_is_max(end))
end.value++;
break;
case SPECIAL_GTE:
@@ -714,6 +785,7 @@ void __extra_pre_loop_hook_after(struct sm_state *sm,
limit = sval_binop(estate_min(sm->state), '-',
sval_type_val(estate_type(sm->state), 1));
}
+ limit = sval_cast(estate_type(sm->state), limit);
if (!estate_has_hard_max(sm->state) && !__has_breaks()) {
if (iter_expr->op == SPECIAL_INCREMENT)
state = alloc_estate_range(estate_min(sm->state), limit);
@@ -738,10 +810,24 @@ void __extra_pre_loop_hook_after(struct sm_state *sm,
set_extra_mod(sm->name, sm->sym, iter_expr, state);
}
+static bool get_global_rl(const char *name, struct symbol *sym, struct range_list **rl)
+{
+ struct expression *expr;
+
+ if (!sym || !(sym->ctype.modifiers & MOD_TOPLEVEL) || !sym->ident)
+ return false;
+ if (strcmp(sym->ident->name, name) != 0)
+ return false;
+
+ expr = symbol_expression(sym);
+ return get_implied_rl(expr, rl);
+}
+
static struct stree *unmatched_stree;
static struct smatch_state *unmatched_state(struct sm_state *sm)
{
struct smatch_state *state;
+ struct range_list *rl;
if (unmatched_stree) {
state = get_state_stree(unmatched_stree, SMATCH_EXTRA, sm->name, sm->sym);
@@ -750,6 +836,8 @@ static struct smatch_state *unmatched_state(struct sm_state *sm)
}
if (parent_is_gone_var_sym(sm->name, sm->sym))
return alloc_estate_empty();
+ if (get_global_rl(sm->name, sm->sym, &rl))
+ return alloc_estate_rl(rl);
return alloc_estate_whole(estate_type(sm->state));
}
@@ -815,7 +903,7 @@ static void match_function_call(struct expression *expr)
} END_FOR_EACH_PTR(arg);
}
-static int values_fit_type(struct expression *left, struct expression *right)
+int values_fit_type(struct expression *left, struct expression *right)
{
struct range_list *rl;
struct symbol *type;
@@ -824,6 +912,8 @@ static int values_fit_type(struct expression *left, struct expression *right)
if (!type)
return 0;
get_absolute_rl(right, &rl);
+ if (type == rl_type(rl))
+ return 1;
if (type_unsigned(type) && sval_is_negative(rl_min(rl)))
return 0;
if (sval_cmp(sval_type_min(type), rl_min(rl)) > 0)
@@ -951,7 +1041,7 @@ static void match_vanilla_assign(struct expression *left, struct expression *rig
goto done;
}
- comparison = get_comparison(left, right);
+ comparison = get_comparison_no_extra(left, right);
if (comparison) {
comparison = flip_comparison(comparison);
get_implied_rl(left, &orig_rl);
@@ -980,34 +1070,6 @@ free:
free_string(right_name);
}
-static int op_remove_assign(int op)
-{
- switch (op) {
- case SPECIAL_ADD_ASSIGN:
- return '+';
- case SPECIAL_SUB_ASSIGN:
- return '-';
- case SPECIAL_MUL_ASSIGN:
- return '*';
- case SPECIAL_DIV_ASSIGN:
- return '/';
- case SPECIAL_MOD_ASSIGN:
- return '%';
- case SPECIAL_AND_ASSIGN:
- return '&';
- case SPECIAL_OR_ASSIGN:
- return '|';
- case SPECIAL_XOR_ASSIGN:
- return '^';
- case SPECIAL_SHL_ASSIGN:
- return SPECIAL_LEFTSHIFT;
- case SPECIAL_SHR_ASSIGN:
- return SPECIAL_RIGHTSHIFT;
- default:
- return op;
- }
-}
-
static void match_assign(struct expression *expr)
{
struct range_list *rl = NULL;
@@ -1017,9 +1079,6 @@ static void match_assign(struct expression *expr)
struct symbol *left_type;
struct symbol *sym;
char *name;
- sval_t left_min, left_max;
- sval_t right_min, right_max;
- sval_t res_min, res_max;
left = strip_expr(expr->left);
@@ -1044,45 +1103,9 @@ static void match_assign(struct expression *expr)
left_type = get_type(left);
- res_min = sval_type_min(left_type);
- res_max = sval_type_max(left_type);
-
switch (expr->op) {
case SPECIAL_ADD_ASSIGN:
- get_absolute_max(left, &left_max);
- get_absolute_max(right, &right_max);
- if (sval_binop_overflows(left_max, '+', sval_cast(left_type, right_max)))
- break;
- if (get_implied_min(left, &left_min) &&
- !sval_is_negative_min(left_min) &&
- get_implied_min(right, &right_min) &&
- !sval_is_negative_min(right_min)) {
- res_min = sval_binop(left_min, '+', right_min);
- res_min = sval_cast(left_type, res_min);
- }
- if (inside_loop()) /* we are assuming loops don't lead to wrapping */
- break;
- res_max = sval_binop(left_max, '+', right_max);
- res_max = sval_cast(left_type, res_max);
- break;
case SPECIAL_SUB_ASSIGN:
- if (get_implied_max(left, &left_max) &&
- !sval_is_max(left_max) &&
- get_implied_min(right, &right_min) &&
- !sval_is_min(right_min)) {
- res_max = sval_binop(left_max, '-', right_min);
- res_max = sval_cast(left_type, res_max);
- }
- if (inside_loop())
- break;
- if (get_implied_min(left, &left_min) &&
- !sval_is_min(left_min) &&
- get_implied_max(right, &right_max) &&
- !sval_is_max(right_max)) {
- res_min = sval_binop(left_min, '-', right_max);
- res_min = sval_cast(left_type, res_min);
- }
- break;
case SPECIAL_AND_ASSIGN:
case SPECIAL_MOD_ASSIGN:
case SPECIAL_SHL_ASSIGN:
@@ -1094,15 +1117,23 @@ static void match_assign(struct expression *expr)
binop_expr = binop_expression(expr->left,
op_remove_assign(expr->op),
expr->right);
- if (get_absolute_rl(binop_expr, &rl)) {
- rl = cast_rl(left_type, rl);
- set_extra_mod(name, sym, left, alloc_estate_rl(rl));
- goto free;
+ get_absolute_rl(binop_expr, &rl);
+ rl = cast_rl(left_type, rl);
+ if (inside_loop()) {
+ if (expr->op == SPECIAL_ADD_ASSIGN)
+ add_range(&rl, rl_max(rl), sval_type_max(rl_type(rl)));
+
+ if (expr->op == SPECIAL_SUB_ASSIGN &&
+ !sval_is_negative(rl_min(rl))) {
+ sval_t zero = { .type = rl_type(rl) };
+
+ add_range(&rl, rl_min(rl), zero);
+ }
}
- break;
+ set_extra_mod(name, sym, left, alloc_estate_rl(rl));
+ goto free;
}
- rl = cast_rl(left_type, alloc_rl(res_min, res_max));
- set_extra_mod(name, sym, left, alloc_estate_rl(rl));
+ set_extra_mod(name, sym, left, alloc_estate_whole(left_type));
free:
free_string(name);
}
@@ -1234,7 +1265,14 @@ static void check_dereference(struct expression *expr)
return;
set_extra_expr_nomod(expr, alloc_estate_rl(rl));
} else {
- set_extra_expr_nomod(expr, alloc_estate_range(valid_ptr_min_sval, valid_ptr_max_sval));
+ struct range_list *rl;
+
+ if (get_mtag_rl(expr, &rl))
+ rl = rl_intersection(rl, valid_ptr_rl);
+ else
+ rl = clone_rl(valid_ptr_rl);
+
+ set_extra_expr_nomod(expr, alloc_estate_rl(rl));
}
}
@@ -1302,6 +1340,7 @@ static int handle_postop_inc(struct expression *left, int op, struct expression
struct statement *stmt;
struct expression *cond;
struct smatch_state *true_state, *false_state;
+ struct symbol *type;
sval_t start;
sval_t limit;
@@ -1333,7 +1372,8 @@ static int handle_postop_inc(struct expression *left, int op, struct expression
return 0;
if (!get_implied_value(right, &limit))
return 0;
-
+ type = get_type(left->unop);
+ limit = sval_cast(type, limit);
if (sval_cmp(start, limit) > 0)
return 0;
@@ -1371,6 +1411,17 @@ bool is_impossible_variable(struct expression *expr)
return false;
}
+static bool in_macro(struct expression *left, struct expression *right)
+{
+ if (!left || !right)
+ return 0;
+ if (left->pos.line != right->pos.line || left->pos.pos != right->pos.pos)
+ return 0;
+ if (get_macro_name(left->pos))
+ return 1;
+ return 0;
+}
+
static void handle_comparison(struct symbol *type, struct expression *left, int op, struct expression *right)
{
struct range_list *left_orig;
@@ -1453,18 +1504,18 @@ static void handle_comparison(struct symbol *type, struct expression *left, int
case SPECIAL_UNSIGNED_LT:
case SPECIAL_UNSIGNED_LTE:
case SPECIAL_LTE:
- if (get_hard_max(right, &dummy))
+ if (get_implied_value(right, &dummy) && !in_macro(left, right))
estate_set_hard_max(left_true_state);
- if (get_hard_max(left, &dummy))
+ if (get_implied_value(left, &dummy) && !in_macro(left, right))
estate_set_hard_max(right_false_state);
break;
case '>':
case SPECIAL_UNSIGNED_GT:
case SPECIAL_UNSIGNED_GTE:
case SPECIAL_GTE:
- if (get_hard_max(left, &dummy))
+ if (get_implied_value(left, &dummy) && !in_macro(left, right))
estate_set_hard_max(right_true_state);
- if (get_hard_max(right, &dummy))
+ if (get_implied_value(right, &dummy) && !in_macro(left, right))
estate_set_hard_max(left_false_state);
break;
}
@@ -1598,6 +1649,45 @@ static int is_simple_math(struct expression *expr)
return 0;
}
+static int flip_op(int op)
+{
+ /* We only care about simple math */
+ switch (op) {
+ case '+':
+ return '-';
+ case '-':
+ return '+';
+ case '*':
+ return '/';
+ }
+ return 0;
+}
+
+static void move_known_to_rl(struct expression **expr_p, struct range_list **rl_p)
+{
+ struct expression *expr = *expr_p;
+ struct range_list *rl = *rl_p;
+ sval_t sval;
+
+ if (!is_simple_math(expr))
+ return;
+
+ if (get_implied_value(expr->right, &sval)) {
+ *expr_p = expr->left;
+ *rl_p = rl_binop(rl, flip_op(expr->op), alloc_rl(sval, sval));
+ move_known_to_rl(expr_p, rl_p);
+ return;
+ }
+ if (expr->op == '-')
+ return;
+ if (get_implied_value(expr->left, &sval)) {
+ *expr_p = expr->right;
+ *rl_p = rl_binop(rl, flip_op(expr->op), alloc_rl(sval, sval));
+ move_known_to_rl(expr_p, rl_p);
+ return;
+ }
+}
+
static void move_known_values(struct expression **left_p, struct expression **right_p)
{
struct expression *left = *left_p;
@@ -1706,29 +1796,8 @@ static int match_func_comparison(struct expression *expr)
{
struct expression *left = strip_expr(expr->left);
struct expression *right = strip_expr(expr->right);
- sval_t sval;
-
- /*
- * fixme: think about this harder. We should always be trying to limit
- * the non-call side as well. If we can't determine the limitter does
- * that mean we aren't querying the database and are missing important
- * information?
- */
- if (left->type == EXPR_CALL) {
- if (get_implied_value(left, &sval)) {
- handle_comparison(get_type(expr), left, expr->op, right);
- return 1;
- }
- function_comparison(left, expr->op, right);
- return 1;
- }
-
- if (right->type == EXPR_CALL) {
- if (get_implied_value(right, &sval)) {
- handle_comparison(get_type(expr), left, expr->op, right);
- return 1;
- }
+ if (left->type == EXPR_CALL || right->type == EXPR_CALL) {
function_comparison(left, expr->op, right);
return 1;
}
@@ -1772,6 +1841,10 @@ static int handle_integer_overflow_test(struct expression *expr)
get_absolute_min(left->right, &right_min);
min = sval_binop(left_min, '+', right_min);
+ type = get_type(left);
+ min = sval_cast(type, min);
+ max = sval_cast(type, max);
+
set_extra_chunk_true_false(left, NULL, alloc_estate_range(min, max));
return 1;
}
@@ -1870,6 +1943,51 @@ static sval_t get_high_mask(sval_t known)
return ret;
}
+static bool handle_bit_test(struct expression *expr)
+{
+ struct range_list *orig_rl, *rl;
+ struct expression *shift, *mask, *var;
+ struct bit_info *bit_info;
+ sval_t sval;
+ sval_t high = { .type = &int_ctype };
+ sval_t low = { .type = &int_ctype };
+
+ shift = strip_expr(expr->right);
+ mask = strip_expr(expr->left);
+ if (shift->type != EXPR_BINOP || shift->op != SPECIAL_LEFTSHIFT) {
+ shift = strip_expr(expr->left);
+ mask = strip_expr(expr->right);
+ if (shift->type != EXPR_BINOP || shift->op != SPECIAL_LEFTSHIFT)
+ return false;
+ }
+ if (!get_implied_value(shift->left, &sval) || sval.value != 1)
+ return false;
+ var = strip_expr(shift->right);
+
+ bit_info = get_bit_info(mask);
+ if (!bit_info)
+ return false;
+ if (!bit_info->possible)
+ return false;
+
+ get_absolute_rl(var, &orig_rl);
+ if (sval_is_negative(rl_min(orig_rl)) ||
+ rl_max(orig_rl).uvalue > type_bits(get_type(shift->left)))
+ return false;
+
+ low.value = ffsll(bit_info->possible);
+ high.value = sm_fls64(bit_info->possible);
+ rl = alloc_rl(low, high);
+ rl = cast_rl(get_type(var), rl);
+ rl = rl_intersection(orig_rl, rl);
+ if (!rl)
+ return false;
+
+ set_extra_expr_true_false(shift->right, alloc_estate_rl(rl), NULL);
+
+ return true;
+}
+
static void handle_AND_op(struct expression *var, sval_t known)
{
struct range_list *orig_rl;
@@ -1916,6 +2034,9 @@ static void handle_AND_condition(struct expression *expr)
{
sval_t known;
+ if (handle_bit_test(expr))
+ return;
+
if (get_implied_value(expr->left, &known))
handle_AND_op(expr->right, known);
else if (get_implied_value(expr->right, &known))
@@ -1928,7 +2049,7 @@ static void handle_MOD_condition(struct expression *expr)
struct range_list *true_rl;
struct range_list *false_rl = NULL;
sval_t right;
- sval_t zero;
+ sval_t zero = { 0, };
if (!get_implied_value(expr->right, &right) || right.value == 0)
return;
@@ -1988,11 +2109,6 @@ static void handle_MOD_condition(struct expression *expr)
/* this is actually hooked from smatch_implied.c... it's hacky, yes */
void __extra_match_condition(struct expression *expr)
{
- struct smatch_state *pre_state;
- struct smatch_state *true_state;
- struct smatch_state *false_state;
- struct range_list *pre_rl;
-
expr = strip_expr(expr);
switch (expr->type) {
case EXPR_CALL:
@@ -2000,27 +2116,9 @@ void __extra_match_condition(struct expression *expr)
return;
case EXPR_PREOP:
case EXPR_SYMBOL:
- case EXPR_DEREF: {
- sval_t zero;
-
- zero = sval_blank(expr);
- zero.value = 0;
-
- pre_state = get_extra_state(expr);
- if (estate_is_empty(pre_state))
- return;
- if (pre_state)
- pre_rl = estate_rl(pre_state);
- else
- get_absolute_rl(expr, &pre_rl);
- if (possibly_true_rl(pre_rl, SPECIAL_EQUAL, rl_zero()))
- false_state = alloc_estate_sval(zero);
- else
- false_state = alloc_estate_empty();
- true_state = alloc_estate_rl(remove_range(pre_rl, zero, zero));
- set_extra_expr_true_false(expr, true_state, false_state);
+ case EXPR_DEREF:
+ handle_comparison(get_type(expr), expr, SPECIAL_NOTEQUAL, zero_expr());
return;
- }
case EXPR_COMPARE:
match_comparison(expr);
return;
@@ -2153,9 +2251,45 @@ static int param_used_callback(void *found, int argc, char **argv, char **azColN
return 0;
}
-static int filter_unused_kzalloc_info(struct expression *call, int param, char *printed_name, struct sm_state *sm)
+static int is_kzalloc_info(struct sm_state *sm)
{
sval_t sval;
+
+ /*
+ * kzalloc() information is treated as special because so there is just
+ * a lot of stuff initialized to zero and it makes building the database
+ * take hours and hours.
+ *
+ * In theory, we should just remove this line and not pass any unused
+ * information, but I'm not sure enough that this code works so I want
+ * to hold off on that for now.
+ */
+ if (!estate_get_single_value(sm->state, &sval))
+ return 0;
+ if (sval.value != 0)
+ return 0;
+ return 1;
+}
+
+static int is_really_long(struct sm_state *sm)
+{
+ const char *p;
+ int cnt = 0;
+
+ p = sm->name;
+ while ((p = strstr(p, "->"))) {
+ p += 2;
+ cnt++;
+ }
+
+ if (cnt < 3 ||
+ strlen(sm->name) < 40)
+ return 0;
+ return 1;
+}
+
+static int filter_unused_param_value_info(struct expression *call, int param, char *printed_name, struct sm_state *sm)
+{
int found = 0;
/* for function pointers assume everything is used */
@@ -2170,16 +2304,7 @@ static int filter_unused_kzalloc_info(struct expression *call, int param, char *
if (!call->fn->symbol)
return 0;
- /*
- * kzalloc() information is treated as special because so there is just
- * a lot of stuff initialized to zero and it makes building the database
- * take hours and hours.
- *
- * In theory, we should just remove this line and not pass any unused
- * information, but I'm not sure enough that this code works so I want
- * to hold off on that for now.
- */
- if (!estate_get_single_value(sm->state, &sval) || sval.value != 0)
+ if (!is_kzalloc_info(sm) && !is_really_long(sm))
return 0;
run_sql(&param_used_callback, &found,
@@ -2246,50 +2371,68 @@ struct range_list *intersect_with_real_abs_expr(struct expression *expr, struct
static void struct_member_callback(struct expression *call, int param, char *printed_name, struct sm_state *sm)
{
struct range_list *rl;
+ sval_t dummy;
if (estate_is_whole(sm->state))
return;
- if (filter_unused_kzalloc_info(call, param, printed_name, sm))
+ if (filter_unused_param_value_info(call, param, printed_name, sm))
return;
rl = estate_rl(sm->state);
rl = intersect_with_real_abs_var_sym(sm->name, sm->sym, rl);
sql_insert_caller_info(call, PARAM_VALUE, param, printed_name, show_rl(rl));
- if (estate_has_fuzzy_max(sm->state))
- sql_insert_caller_info(call, FUZZY_MAX, param, printed_name,
- sval_to_str(estate_get_fuzzy_max(sm->state)));
+ if (!estate_get_single_value(sm->state, &dummy)) {
+ if (estate_has_hard_max(sm->state))
+ sql_insert_caller_info(call, HARD_MAX, param, printed_name,
+ sval_to_str(estate_max(sm->state)));
+ if (estate_has_fuzzy_max(sm->state))
+ sql_insert_caller_info(call, FUZZY_MAX, param, printed_name,
+ sval_to_str(estate_get_fuzzy_max(sm->state)));
+ }
}
static void returned_struct_members(int return_id, char *return_ranges, struct expression *expr)
{
struct symbol *returned_sym;
+ char *returned_name;
struct sm_state *sm;
- const char *param_name;
char *compare_str;
- char buf[256];
+ char name_buf[256];
+ char val_buf[256];
+ int len;
- returned_sym = expr_to_sym(expr);
- if (!returned_sym)
+ // FIXME handle *$
+
+ if (!is_pointer(expr))
return;
+ returned_name = expr_to_var_sym(expr, &returned_sym);
+ if (!returned_name || !returned_sym)
+ goto free;
+ len = strlen(returned_name);
+
FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
if (!estate_rl(sm->state))
continue;
if (returned_sym != sm->sym)
continue;
-
- param_name = get_param_name(sm);
- if (!param_name)
+ if (strncmp(returned_name, sm->name, len) != 0)
continue;
- if (strcmp(param_name, "$") == 0)
+ if (sm->name[len] != '-')
continue;
+
+ snprintf(name_buf, sizeof(name_buf), "$%s", sm->name + len);
+
compare_str = name_sym_to_param_comparison(sm->name, sm->sym);
if (!compare_str && estate_is_whole(sm->state))
continue;
- snprintf(buf, sizeof(buf), "%s%s", sm->state->name, compare_str ?: "");
+ snprintf(val_buf, sizeof(val_buf), "%s%s", sm->state->name, compare_str ?: "");
sql_insert_return_states(return_id, return_ranges, PARAM_VALUE,
- -1, param_name, buf);
+ -1, name_buf, val_buf);
} END_FOR_EACH_SM(sm);
+
+free:
+ free_string(returned_name);
}
static void db_limited_before(void)
@@ -2302,18 +2445,6 @@ static void db_limited_after(void)
free_stree(&unmatched_stree);
}
-static int rl_fits_in_type(struct range_list *rl, struct symbol *type)
-{
- if (type_bits(rl_type(rl)) <= type_bits(type))
- return 1;
- if (sval_cmp(rl_max(rl), sval_type_max(type)) > 0)
- return 0;
- if (sval_is_negative(rl_min(rl)) &&
- sval_cmp(rl_min(rl), sval_type_min(type)) < 0)
- return 0;
- return 1;
-}
-
static int basically_the_same(struct range_list *orig, struct range_list *new)
{
if (rl_equiv(orig, new))
@@ -2363,8 +2494,8 @@ static void db_param_limit_filter(struct expression *expr, int param, char *key,
struct range_list *rl;
struct range_list *limit;
struct range_list *new;
- char *tmp_name;
- struct symbol *tmp_sym;
+ char *other_name;
+ struct symbol *other_sym;
while (expr->type == EXPR_ASSIGNMENT)
expr = strip_expr(expr->right);
@@ -2375,17 +2506,20 @@ static void db_param_limit_filter(struct expression *expr, int param, char *key,
if (!arg)
return;
+ if (strcmp(key, "$") == 0)
+ compare_type = get_arg_type(expr->fn, param);
+ else
+ compare_type = get_member_type_from_key(arg, key);
+
+ call_results_to_rl(expr, compare_type, value, &limit);
+ if (strcmp(key, "$") == 0)
+ move_known_to_rl(&arg, &limit);
name = get_chunk_from_key(arg, key, &sym, &vsl);
if (!name)
return;
if (op != PARAM_LIMIT && !sym)
goto free;
- if (strcmp(key, "$") == 0)
- compare_type = get_arg_type(expr->fn, param);
- else
- compare_type = get_member_type_from_key(arg, key);
-
sm = get_sm_state(SMATCH_EXTRA, name, sym);
if (sm)
rl = estate_rl(sm->state);
@@ -2395,27 +2529,28 @@ static void db_param_limit_filter(struct expression *expr, int param, char *key,
if (op == PARAM_LIMIT && !rl_fits_in_type(rl, compare_type))
goto free;
- call_results_to_rl(expr, compare_type, value, &limit);
new = rl_intersection(rl, limit);
var_type = get_member_type_from_key(arg, key);
new = cast_rl(var_type, new);
/* We want to preserve the implications here */
- if (sm && basically_the_same(estate_rl(sm->state), new))
+ if (sm && basically_the_same(rl, new))
goto free;
- tmp_name = map_long_to_short_name_sym(name, sym, &tmp_sym);
- if (tmp_name && tmp_sym) {
- free_string(name);
- name = tmp_name;
- sym = tmp_sym;
- }
+ other_name = get_other_name_sym(name, sym, &other_sym);
if (op == PARAM_LIMIT)
set_extra_nomod_vsl(name, sym, vsl, NULL, alloc_estate_rl(new));
else
set_extra_mod(name, sym, NULL, alloc_estate_rl(new));
+ if (other_name && other_sym) {
+ if (op == PARAM_LIMIT)
+ set_extra_nomod_vsl(other_name, other_sym, vsl, NULL, alloc_estate_rl(new));
+ else
+ set_extra_mod(other_name, other_sym, NULL, alloc_estate_rl(new));
+ }
+
if (op == PARAM_LIMIT && arg->type == EXPR_BINOP)
db_param_limit_binops(arg, key, new);
free:
@@ -2435,8 +2570,9 @@ static void db_param_filter(struct expression *expr, int param, char *key, char
static void db_param_add_set(struct expression *expr, int param, char *key, char *value, enum info_type op)
{
struct expression *arg;
- char *name, *tmp_name;
- struct symbol *sym, *tmp_sym;
+ char *name;
+ char *other_name = NULL;
+ struct symbol *sym, *other_sym;
struct symbol *param_type, *arg_type;
struct smatch_state *state;
struct range_list *new = NULL;
@@ -2468,14 +2604,12 @@ static void db_param_add_set(struct expression *expr, int param, char *key, char
else
new = rl_union(new, added);
- tmp_name = map_long_to_short_name_sym_nostack(name, sym, &tmp_sym);
- if (tmp_name && tmp_sym) {
- free_string(name);
- name = tmp_name;
- sym = tmp_sym;
- }
+ other_name = get_other_name_sym_nostack(name, sym, &other_sym);
set_extra_mod(name, sym, NULL, alloc_estate_rl(new));
+ if (other_name && other_sym)
+ set_extra_mod(other_name, other_sym, NULL, alloc_estate_rl(new));
free:
+ free_string(other_name);
free_string(name);
}
@@ -2493,6 +2627,24 @@ static void db_param_set(struct expression *expr, int param, char *key, char *va
in_param_set = false;
}
+static void match_lost_param(struct expression *call, int param)
+{
+ struct expression *arg;
+
+ if (is_const_param(call->fn, param))
+ return;
+
+ arg = get_argument_from_call_expr(call->args, param);
+ if (!arg)
+ return;
+
+ arg = strip_expr(arg);
+ if (arg->type == EXPR_PREOP && arg->op == '&')
+ set_extra_expr_mod(arg->unop, alloc_estate_whole(get_type(arg->unop)));
+ else
+ ; /* if pointer then set struct members, maybe?*/
+}
+
static void db_param_value(struct expression *expr, int param, char *key, char *value)
{
struct expression *call;
@@ -2528,6 +2680,7 @@ static void match_call_info(struct expression *expr)
struct range_list *rl = NULL;
struct expression *arg;
struct symbol *type;
+ sval_t dummy;
int i = 0;
FOR_EACH_PTR(expr->args, arg) {
@@ -2541,6 +2694,10 @@ static void match_call_info(struct expression *expr)
sql_insert_caller_info(expr, PARAM_VALUE, i, "$", show_rl(rl));
}
state = get_state_expr(SMATCH_EXTRA, arg);
+ if (!estate_get_single_value(state, &dummy) && estate_has_hard_max(state)) {
+ sql_insert_caller_info(expr, HARD_MAX, i, "$",
+ sval_to_str(estate_max(state)));
+ }
if (estate_has_fuzzy_max(state)) {
sql_insert_caller_info(expr, FUZZY_MAX, i, "$",
sval_to_str(estate_get_fuzzy_max(state)));
@@ -2551,20 +2708,24 @@ static void match_call_info(struct expression *expr)
static void set_param_value(const char *name, struct symbol *sym, char *key, char *value)
{
+ struct expression *expr;
struct range_list *rl = NULL;
struct smatch_state *state;
struct symbol *type;
char fullname[256];
+ char *key_orig = key;
+ bool add_star = false;
sval_t dummy;
- if (strcmp(key, "*$") == 0)
- snprintf(fullname, sizeof(fullname), "*%s", name);
- else if (strncmp(key, "$", 1) == 0)
- snprintf(fullname, 256, "%s%s", name, key + 1);
- else
- return;
+ if (key[0] == '*') {
+ add_star = true;
+ key++;
+ }
+
+ snprintf(fullname, 256, "%s%s%s", add_star ? "*" : "", name, key + 1);
- type = get_member_type_from_key(symbol_expression(sym), key);
+ expr = symbol_expression(sym);
+ type = get_member_type_from_key(expr, key_orig);
str_to_rl(type, value, &rl);
state = alloc_estate_rl(rl);
if (estate_get_single_value(state, &dummy))
@@ -2572,7 +2733,7 @@ static void set_param_value(const char *name, struct symbol *sym, char *key, cha
set_state(SMATCH_EXTRA, fullname, sym, state);
}
-static void set_param_hard_max(const char *name, struct symbol *sym, char *key, char *value)
+static void set_param_fuzzy_max(const char *name, struct symbol *sym, char *key, char *value)
{
struct range_list *rl = NULL;
struct smatch_state *state;
@@ -2590,13 +2751,31 @@ static void set_param_hard_max(const char *name, struct symbol *sym, char *key,
state = get_state(SMATCH_EXTRA, fullname, sym);
if (!state)
return;
- type = get_member_type_from_key(symbol_expression(sym), key);
+ type = estate_type(state);
str_to_rl(type, value, &rl);
if (!rl_to_sval(rl, &max))
return;
estate_set_fuzzy_max(state, max);
}
+static void set_param_hard_max(const char *name, struct symbol *sym, char *key, char *value)
+{
+ struct smatch_state *state;
+ char fullname[256];
+
+ if (strcmp(key, "*$") == 0)
+ snprintf(fullname, sizeof(fullname), "*%s", name);
+ else if (strncmp(key, "$", 1) == 0)
+ snprintf(fullname, 256, "%s%s", name, key + 1);
+ else
+ return;
+
+ state = get_state(SMATCH_EXTRA, fullname, sym);
+ if (!state)
+ return;
+ estate_set_hard_max(state);
+}
+
struct sm_state *get_extra_sm_state(struct expression *expr)
{
char *name;
@@ -2627,15 +2806,18 @@ void register_smatch_extra(int id)
{
my_id = id;
+ set_dynamic_states(my_id);
add_merge_hook(my_id, &merge_estates);
add_unmatched_state_hook(my_id, &unmatched_state);
select_caller_info_hook(set_param_value, PARAM_VALUE);
- select_caller_info_hook(set_param_hard_max, FUZZY_MAX);
+ select_caller_info_hook(set_param_fuzzy_max, FUZZY_MAX);
+ select_caller_info_hook(set_param_hard_max, HARD_MAX);
select_return_states_before(&db_limited_before);
select_return_states_hook(PARAM_LIMIT, &db_param_limit);
select_return_states_hook(PARAM_FILTER, &db_param_filter);
select_return_states_hook(PARAM_ADD, &db_param_add);
select_return_states_hook(PARAM_SET, &db_param_set);
+ add_lost_param_hook(&match_lost_param);
select_return_states_hook(PARAM_VALUE, &db_param_value);
select_return_states_after(&db_limited_after);
}
@@ -2663,6 +2845,7 @@ static void match_link_modify(struct sm_state *sm, struct expression *mod_expr)
void register_smatch_extra_links(int id)
{
link_id = id;
+ set_dynamic_states(link_id);
}
void register_smatch_extra_late(int id)
diff --git a/usr/src/tools/smatch/src/smatch_extra.h b/usr/src/tools/smatch/src/smatch_extra.h
index d48cdf1f79..6877053f86 100644
--- a/usr/src/tools/smatch/src/smatch_extra.h
+++ b/usr/src/tools/smatch/src/smatch_extra.h
@@ -30,6 +30,7 @@ struct data_info {
struct range_list *value_ranges;
sval_t fuzzy_max;
unsigned int hard_max:1;
+ unsigned int capped:1;
};
DECLARE_ALLOCATOR(data_info);
@@ -41,11 +42,13 @@ struct range_list *rl_one(void);
char *show_rl(struct range_list *list);
int str_to_comparison_arg(const char *c, struct expression *call, int *comparison, struct expression **arg);
void str_to_rl(struct symbol *type, char *value, struct range_list **rl);
-void call_results_to_rl(struct expression *call, struct symbol *type, char *value, struct range_list **rl);
+void call_results_to_rl(struct expression *call, struct symbol *type, const char *value, struct range_list **rl);
struct data_range *alloc_range(sval_t min, sval_t max);
struct data_range *alloc_range_perm(sval_t min, sval_t max);
+int rl_fits_in_type(struct range_list *rl, struct symbol *type);
+
struct range_list *alloc_rl(sval_t min, sval_t max);
struct range_list *clone_rl(struct range_list *list);
struct range_list *clone_rl_permanent(struct range_list *list);
@@ -72,6 +75,7 @@ int ranges_equiv(struct data_range *one, struct data_range *two);
int rl_equiv(struct range_list *one, struct range_list *two);
int is_whole_rl(struct range_list *rl);
+int is_unknown_ptr(struct range_list *rl);
int is_whole_rl_non_zero(struct range_list *rl);
int estate_is_unknown(struct smatch_state *state);
@@ -80,7 +84,6 @@ sval_t rl_max(struct range_list *rl);
int rl_to_sval(struct range_list *rl, sval_t *sval);
struct symbol *rl_type(struct range_list *rl);
-struct range_list *rl_invert(struct range_list *orig);
struct range_list *rl_filter(struct range_list *rl, struct range_list *filter);
struct range_list *rl_intersection(struct range_list *one, struct range_list *two);
struct range_list *rl_union(struct range_list *one, struct range_list *two);
@@ -117,6 +120,7 @@ struct smatch_state *alloc_estate_rl(struct range_list *rl);
struct smatch_state *alloc_estate_whole(struct symbol *type);
struct smatch_state *clone_estate(struct smatch_state *state);
struct smatch_state *clone_estate_cast(struct symbol *type, struct smatch_state *state);
+struct smatch_state *clone_partial_estate(struct smatch_state *state, struct range_list *rl);
struct smatch_state *merge_estates(struct smatch_state *s1, struct smatch_state *s2);
@@ -140,12 +144,13 @@ int estate_has_hard_max(struct smatch_state *state);
void estate_set_hard_max(struct smatch_state *state);
void estate_clear_hard_max(struct smatch_state *state);
int estate_get_hard_max(struct smatch_state *state, sval_t *sval);
+bool estate_capped(struct smatch_state *state);
+void estate_set_capped(struct smatch_state *state);
int estate_get_single_value(struct smatch_state *state, sval_t *sval);
struct smatch_state *get_implied_estate(struct expression *expr);
struct smatch_state *estate_filter_sval(struct smatch_state *orig, sval_t filter);
-struct smatch_state *estate_filter_range(struct smatch_state *orig, sval_t filter_min, sval_t filter_max);
struct data_info *clone_dinfo_perm(struct data_info *dinfo);
struct smatch_state *clone_estate_perm(struct smatch_state *state);
diff --git a/usr/src/tools/smatch/src/smatch_flow.c b/usr/src/tools/smatch/src/smatch_flow.c
index 5c4d64bc02..11a70bdd70 100644
--- a/usr/src/tools/smatch/src/smatch_flow.c
+++ b/usr/src/tools/smatch/src/smatch_flow.c
@@ -76,30 +76,23 @@ int option_two_passes = 0;
struct symbol *cur_func_sym = NULL;
struct stree *global_states;
-long long valid_ptr_min = 4096;
-long long valid_ptr_max = 2117777777;
-sval_t valid_ptr_min_sval = {
+const unsigned long valid_ptr_min = 4096;
+unsigned long valid_ptr_max = ULONG_MAX & ~(MTAG_OFFSET_MASK);
+const sval_t valid_ptr_min_sval = {
.type = &ptr_ctype,
{.value = 4096},
};
sval_t valid_ptr_max_sval = {
.type = &ptr_ctype,
- {.value = LONG_MAX - 100000},
+ {.value = ULONG_MAX & ~(MTAG_OFFSET_MASK)},
};
struct range_list *valid_ptr_rl;
-static void set_valid_ptr_max(void)
+void alloc_valid_ptr_rl(void)
{
- if (type_bits(&ptr_ctype) == 32)
- valid_ptr_max = 2117777777;
- else if (type_bits(&ptr_ctype) == 64)
- valid_ptr_max = 2117777777777777777LL;
-
+ valid_ptr_max = sval_type_max(&ulong_ctype).value & ~(MTAG_OFFSET_MASK);
valid_ptr_max_sval.value = valid_ptr_max;
-}
-static void alloc_valid_ptr_rl(void)
-{
valid_ptr_rl = alloc_rl(valid_ptr_min_sval, valid_ptr_max_sval);
valid_ptr_rl = cast_rl(&ptr_ctype, valid_ptr_rl);
valid_ptr_rl = clone_rl_permanent(valid_ptr_rl);
@@ -504,7 +497,6 @@ void __split_expr(struct expression *expr)
break;
case EXPR_OFFSETOF:
case EXPR_ALIGNOF:
- evaluate_expression(expr);
break;
case EXPR_CONDITIONAL:
case EXPR_SELECT:
@@ -878,9 +870,14 @@ int time_parsing_function(void)
return ms_since(&fn_start_time) / 1000;
}
-static int taking_too_long(void)
+/*
+ * This defaults to 60 * 5 == 5 minutes, so we'll just multiply
+ * whatever we're given by 5.
+ */
+bool taking_too_long(void)
{
- if ((ms_since(&outer_fn_start_time) / 1000) > 60 * 5) /* five minutes */
+ if (option_timeout &&
+ (ms_since(&outer_fn_start_time) / 1000) > option_timeout * 5)
return 1;
return 0;
}
@@ -1908,9 +1905,8 @@ static void open_output_files(char *base_file)
sm_fatal("Error: Cannot open %s", buf);
}
-void smatch(int argc, char **argv)
+void smatch(struct string_list *filelist)
{
- struct string_list *filelist = NULL;
struct symbol_list *sym_list;
struct timeval stop, start;
char *path;
@@ -1918,9 +1914,6 @@ void smatch(int argc, char **argv)
gettimeofday(&start, NULL);
- sparse_initialize(argc, argv, &filelist);
- set_valid_ptr_max();
- alloc_valid_ptr_rl();
FOR_EACH_PTR_NOTAG(filelist, base_file) {
path = getcwd(NULL, 0);
free(full_base_file);
@@ -1940,6 +1933,7 @@ void smatch(int argc, char **argv)
gettimeofday(&stop, NULL);
set_position(last_pos);
+ final_pass = 1;
if (option_time)
sm_msg("time: %lu", stop.tv_sec - start.tv_sec);
if (option_mem)
diff --git a/usr/src/tools/smatch/src/smatch_function_hooks.c b/usr/src/tools/smatch/src/smatch_function_hooks.c
index 9aa51c319b..983befeac1 100644
--- a/usr/src/tools/smatch/src/smatch_function_hooks.c
+++ b/usr/src/tools/smatch/src/smatch_function_hooks.c
@@ -139,6 +139,16 @@ void return_implies_state(const char *look_for, long long start, long long end,
add_callback(func_hash, look_for, cb);
}
+void return_implies_state_sval(const char *look_for, sval_t start, sval_t end,
+ implication_hook *call_back, void *info)
+{
+ struct fcall_back *cb;
+
+ cb = alloc_fcall_back(RANGED_CALL, call_back, info);
+ cb->range = alloc_range_perm(start, end);
+ add_callback(func_hash, look_for, cb);
+}
+
void select_return_states_hook(int type, return_implies_hook *callback)
{
struct return_implies_callback *cb = __alloc_return_implies_callback(0);
@@ -246,6 +256,7 @@ static int assign_ranged_funcs(const char *fn, struct expression *expr,
struct stree *final_states = NULL;
struct range_list *handled_ranges = NULL;
struct call_back_list *same_range_call_backs = NULL;
+ struct range_list *rl;
int handled = 0;
if (!call_backs)
@@ -268,7 +279,9 @@ static int assign_ranged_funcs(const char *fn, struct expression *expr,
call_ranged_call_backs(same_range_call_backs, fn, expr->right, expr);
__free_ptr_list((struct ptr_list **)&same_range_call_backs);
- estate = alloc_estate_range(tmp->range->min, tmp->range->max);
+ rl = alloc_rl(tmp->range->min, tmp->range->max);
+ rl = cast_rl(get_type(expr->left), rl);
+ estate = alloc_estate_rl(rl);
set_extra_mod(var_name, sym, expr->left, estate);
tmp_stree = __pop_fake_cur_stree();
@@ -362,7 +375,7 @@ static void store_return_state(struct db_callback_info *db_info, const char *ret
static bool fake_a_param_assignment(struct expression *expr, const char *return_str)
{
- struct expression *arg, *left, *right, *fake_assign;
+ struct expression *arg, *left, *right, *tmp, *fake_assign;
char *p;
int param;
char buf[256];
@@ -402,6 +415,12 @@ static bool fake_a_param_assignment(struct expression *expr, const char *return_
arg = get_argument_from_call_expr(right->args, param);
if (!arg)
return false;
+
+ /* There should be a get_other_name() function which returns an expr */
+ tmp = get_assigned_expr(arg);
+ if (tmp)
+ arg = tmp;
+
/*
* This is a sanity check to prevent side effects from evaluating stuff
* twice.
@@ -421,8 +440,9 @@ static bool fake_a_param_assignment(struct expression *expr, const char *return_
return true;
}
-static void set_return_state(struct expression *expr, struct db_callback_info *db_info)
+static void set_return_assign_state(struct db_callback_info *db_info)
{
+ struct expression *expr = db_info->expr->left;
struct smatch_state *state;
if (!db_info->ret_state)
@@ -435,6 +455,20 @@ static void set_return_state(struct expression *expr, struct db_callback_info *d
db_info->ret_str = NULL;
}
+static void set_other_side_state(struct db_callback_info *db_info)
+{
+ struct expression *expr = db_info->var_expr;
+ struct smatch_state *state;
+
+ if (!db_info->ret_state)
+ return;
+
+ state = alloc_estate_rl(cast_rl(get_type(expr), clone_rl(estate_rl(db_info->ret_state))));
+ set_extra_expr_nomod(expr, state);
+ db_info->ret_state = NULL;
+ db_info->ret_str = NULL;
+}
+
static void handle_ret_equals_param(char *ret_string, struct range_list *rl, struct expression *call)
{
char *str;
@@ -561,7 +595,7 @@ static int db_compare_callback(void *_info, int argc, char **argv, char **azColN
struct range_list *var_rl = db_info->rl;
struct range_list *ret_range;
int type, param;
- char *key, *value;
+ char *ret_str, *key, *value;
struct return_implies_callback *tmp;
struct stree *stree;
int return_id;
@@ -571,6 +605,7 @@ static int db_compare_callback(void *_info, int argc, char **argv, char **azColN
return 0;
return_id = atoi(argv[0]);
+ ret_str = argv[1];
type = atoi(argv[2]);
param = atoi(argv[3]);
key = argv[4];
@@ -578,7 +613,7 @@ static int db_compare_callback(void *_info, int argc, char **argv, char **azColN
db_info->has_states = 1;
if (db_info->prev_return_id != -1 && type == INTERNAL) {
- set_return_state(db_info->var_expr, db_info);
+ set_other_side_state(db_info);
stree = __pop_fake_cur_stree();
if (!db_info->cull)
@@ -603,7 +638,7 @@ static int db_compare_callback(void *_info, int argc, char **argv, char **azColN
return 0;
}
- call_results_to_rl(db_info->expr, get_type(strip_expr(db_info->expr)), argv[1], &ret_range);
+ call_results_to_rl(db_info->expr, get_type(strip_expr(db_info->expr)), ret_str, &ret_range);
ret_range = cast_rl(get_type(db_info->expr), ret_range);
if (!ret_range)
ret_range = alloc_whole_rl(get_type(db_info->expr));
@@ -628,13 +663,13 @@ static int db_compare_callback(void *_info, int argc, char **argv, char **azColN
filter_by_comparison(&ret_range, flip_comparison(negate_comparison(comparison)), var_rl);
}
- handle_ret_equals_param(argv[1], ret_range, db_info->expr);
+ handle_ret_equals_param(ret_str, ret_range, db_info->expr);
if (type == INTERNAL) {
set_state(-1, "unnull_path", NULL, &true_state);
- __add_return_comparison(strip_expr(db_info->expr), argv[1]);
- __add_return_to_param_mapping(db_info->expr, argv[1]);
- store_return_state(db_info, argv[1], alloc_estate_rl(clone_rl(var_rl)));
+ __add_return_comparison(strip_expr(db_info->expr), ret_str);
+ __add_return_to_param_mapping(db_info->expr, ret_str);
+ store_return_state(db_info, ret_str, alloc_estate_rl(clone_rl(var_rl)));
}
FOR_EACH_PTR(db_info->callbacks, tmp) {
@@ -687,12 +722,10 @@ static void compare_db_return_states_callbacks(struct expression *left, int comp
__push_fake_cur_stree();
sql_select_return_states("return_id, return, type, parameter, key, value",
call_expr, db_compare_callback, &db_info);
- set_return_state(db_info.var_expr, &db_info);
+ set_other_side_state(&db_info);
stree = __pop_fake_cur_stree();
- if (!db_info.cull) {
- set_return_state(db_info.var_expr, &db_info);
+ if (!db_info.cull)
merge_fake_stree(&db_info.stree, stree);
- }
free_stree(&stree);
true_states = db_info.stree;
if (!true_states && db_info.has_states) {
@@ -714,11 +747,10 @@ static void compare_db_return_states_callbacks(struct expression *left, int comp
__push_fake_cur_stree();
sql_select_return_states("return_id, return, type, parameter, key, value", call_expr,
db_compare_callback, &db_info);
+ set_other_side_state(&db_info);
stree = __pop_fake_cur_stree();
- if (!db_info.cull) {
- set_return_state(db_info.var_expr, &db_info);
+ if (!db_info.cull)
merge_fake_stree(&db_info.stree, stree);
- }
free_stree(&stree);
false_states = db_info.stree;
if (!false_states && db_info.has_states) {
@@ -806,18 +838,14 @@ static void call_ranged_return_hooks(struct db_callback_info *db_info)
call_backs = search_callback(func_hash, fn);
FOR_EACH_PTR(call_backs, tmp) {
- struct range_list *range_rl = NULL;
+ struct range_list *range_rl;
if (tmp->type != RANGED_CALL)
continue;
- add_range(&range_rl, tmp->range->min, tmp->range->max);
+ range_rl = alloc_rl(tmp->range->min, tmp->range->max);
range_rl = cast_rl(estate_type(db_info->ret_state), range_rl);
- if (possibly_true_rl(range_rl, SPECIAL_EQUAL, estate_rl(db_info->ret_state))) {
- if (!possibly_true_rl(rl_invert(range_rl), SPECIAL_EQUAL, estate_rl(db_info->ret_state)))
- (tmp->u.ranged)(fn, expr, db_info->expr, tmp->info);
- else
- db_info->handled = -1;
- }
+ if (possibly_true_rl(range_rl, SPECIAL_EQUAL, estate_rl(db_info->ret_state)))
+ (tmp->u.ranged)(fn, expr, db_info->expr, tmp->info);
} END_FOR_EACH_PTR(tmp);
}
@@ -826,7 +854,7 @@ static int db_assign_return_states_callback(void *_info, int argc, char **argv,
struct db_callback_info *db_info = _info;
struct range_list *ret_range;
int type, param;
- char *key, *value;
+ char *ret_str, *key, *value;
struct return_implies_callback *tmp;
struct stree *stree;
int return_id;
@@ -835,6 +863,7 @@ static int db_assign_return_states_callback(void *_info, int argc, char **argv,
return 0;
return_id = atoi(argv[0]);
+ ret_str = argv[1];
type = atoi(argv[2]);
param = atoi(argv[3]);
key = argv[4];
@@ -842,7 +871,7 @@ static int db_assign_return_states_callback(void *_info, int argc, char **argv,
if (db_info->prev_return_id != -1 && type == INTERNAL) {
call_ranged_return_hooks(db_info);
- set_return_state(db_info->expr->left, db_info);
+ set_return_assign_state(db_info);
stree = __pop_fake_cur_stree();
if (!db_info->cull)
merge_fake_stree(&db_info->stree, stree);
@@ -869,17 +898,17 @@ static int db_assign_return_states_callback(void *_info, int argc, char **argv,
param_limit_implications(db_info->expr, param, key, value);
db_info->handled = 1;
- call_results_to_rl(db_info->expr->right, get_type(strip_expr(db_info->expr->right)), argv[1], &ret_range);
+ call_results_to_rl(db_info->expr->right, get_type(strip_expr(db_info->expr->right)), ret_str, &ret_range);
if (!ret_range)
ret_range = alloc_whole_rl(get_type(strip_expr(db_info->expr->right)));
ret_range = cast_rl(get_type(db_info->expr->right), ret_range);
if (type == INTERNAL) {
set_state(-1, "unnull_path", NULL, &true_state);
- __add_return_comparison(strip_expr(db_info->expr->right), argv[1]);
- __add_comparison_info(db_info->expr->left, strip_expr(db_info->expr->right), argv[1]);
- __add_return_to_param_mapping(db_info->expr, argv[1]);
- store_return_state(db_info, argv[1], alloc_estate_rl(ret_range));
+ __add_return_comparison(strip_expr(db_info->expr->right), ret_str);
+ __add_comparison_info(db_info->expr->left, strip_expr(db_info->expr->right), ret_str);
+ __add_return_to_param_mapping(db_info->expr, ret_str);
+ store_return_state(db_info, ret_str, alloc_estate_rl(ret_range));
}
FOR_EACH_PTR(db_return_states_list, tmp) {
@@ -917,7 +946,7 @@ static int db_return_states_assign(struct expression *expr)
}
if (db_info.handled)
call_ranged_return_hooks(&db_info);
- set_return_state(db_info.expr->left, &db_info);
+ set_return_assign_state(&db_info);
stree = __pop_fake_cur_stree();
if (!db_info.cull)
merge_fake_stree(&db_info.stree, stree);
@@ -1011,7 +1040,7 @@ static int db_return_states_callback(void *_info, int argc, char **argv, char **
struct db_callback_info *db_info = _info;
struct range_list *ret_range;
int type, param;
- char *key, *value;
+ char *ret_str, *key, *value;
struct return_implies_callback *tmp;
struct stree *stree;
int return_id;
@@ -1021,6 +1050,7 @@ static int db_return_states_callback(void *_info, int argc, char **argv, char **
return 0;
return_id = atoi(argv[0]);
+ ret_str = argv[1];
type = atoi(argv[2]);
param = atoi(argv[3]);
key = argv[4];
@@ -1053,13 +1083,13 @@ static int db_return_states_callback(void *_info, int argc, char **argv, char **
if (type == PARAM_LIMIT)
param_limit_implications(db_info->expr, param, key, value);
- call_results_to_rl(db_info->expr, get_type(strip_expr(db_info->expr)), argv[1], &ret_range);
+ call_results_to_rl(db_info->expr, get_type(strip_expr(db_info->expr)), ret_str, &ret_range);
ret_range = cast_rl(get_type(db_info->expr), ret_range);
if (type == INTERNAL) {
set_state(-1, "unnull_path", NULL, &true_state);
- __add_return_comparison(strip_expr(db_info->expr), argv[1]);
- __add_return_to_param_mapping(db_info->expr, argv[1]);
+ __add_return_comparison(strip_expr(db_info->expr), ret_str);
+ __add_return_to_param_mapping(db_info->expr, ret_str);
}
diff --git a/usr/src/tools/smatch/src/smatch_function_ptrs.c b/usr/src/tools/smatch/src/smatch_function_ptrs.c
index 9a897f9cb4..e8b616425b 100644
--- a/usr/src/tools/smatch/src/smatch_function_ptrs.c
+++ b/usr/src/tools/smatch/src/smatch_function_ptrs.c
@@ -141,6 +141,9 @@ char *get_fnptr_name(struct expression *expr)
{
char *name;
+ if (is_zero(expr))
+ return NULL;
+
expr = strip_expr(expr);
/* (*ptrs[0])(a, b, c) is the same as ptrs[0](a, b, c); */
@@ -345,6 +348,57 @@ static void match_returns_function_pointer(struct expression *expr)
sql_insert_function_ptr(fn_name, ptr_name);
}
+static void print_initializer_list(struct expression_list *expr_list,
+ struct symbol *struct_type)
+{
+ struct expression *expr;
+ struct symbol *base_type;
+ char struct_name[256];
+
+ FOR_EACH_PTR(expr_list, expr) {
+ if (expr->type == EXPR_INDEX && expr->idx_expression && expr->idx_expression->type == EXPR_INITIALIZER) {
+ print_initializer_list(expr->idx_expression->expr_list, struct_type);
+ continue;
+ }
+ if (expr->type != EXPR_IDENTIFIER)
+ continue;
+ if (!expr->expr_ident)
+ continue;
+ if (!expr->ident_expression ||
+ expr->ident_expression->type != EXPR_SYMBOL ||
+ !expr->ident_expression->symbol_name)
+ continue;
+ base_type = get_type(expr->ident_expression);
+ if (!base_type || base_type->type != SYM_FN)
+ continue;
+ snprintf(struct_name, sizeof(struct_name), "(struct %s)->%s",
+ struct_type->ident->name, expr->expr_ident->name);
+ sql_insert_function_ptr(expr->ident_expression->symbol_name->name,
+ struct_name);
+ } END_FOR_EACH_PTR(expr);
+}
+
+static void global_variable(struct symbol *sym)
+{
+ struct symbol *struct_type;
+
+ if (!sym->ident)
+ return;
+ if (!sym->initializer || sym->initializer->type != EXPR_INITIALIZER)
+ return;
+ struct_type = get_base_type(sym);
+ if (!struct_type)
+ return;
+ if (struct_type->type == SYM_ARRAY) {
+ struct_type = get_base_type(struct_type);
+ if (!struct_type)
+ return;
+ }
+ if (struct_type->type != SYM_STRUCT || !struct_type->ident)
+ return;
+ print_initializer_list(sym->initializer->expr_list, struct_type);
+}
+
void register_function_ptrs(int id)
{
my_id = id;
@@ -352,6 +406,8 @@ void register_function_ptrs(int id)
if (!option_info)
return;
+ add_hook(&global_variable, BASE_HOOK);
+ add_hook(&global_variable, DECLARATION_HOOK);
add_hook(&match_passes_function_pointer, FUNCTION_CALL_HOOK);
add_hook(&match_returns_function_pointer, RETURN_HOOK);
add_hook(&match_function_assign, ASSIGNMENT_HOOK);
diff --git a/usr/src/tools/smatch/src/smatch_helper.c b/usr/src/tools/smatch/src/smatch_helper.c
index 81d4e2dd78..81125ad308 100644
--- a/usr/src/tools/smatch/src/smatch_helper.c
+++ b/usr/src/tools/smatch/src/smatch_helper.c
@@ -81,14 +81,26 @@ struct smatch_state *alloc_state_str(const char *name)
return state;
}
+struct smatch_state *merge_str_state(struct smatch_state *s1, struct smatch_state *s2)
+{
+ if (!s1->name || !s2->name)
+ return &merged;
+ if (strcmp(s1->name, s2->name) == 0)
+ return s1;
+ return &merged;
+}
+
struct smatch_state *alloc_state_expr(struct expression *expr)
{
struct smatch_state *state;
char *name;
- state = __alloc_smatch_state(0);
expr = strip_expr(expr);
name = expr_to_str(expr);
+ if (!name)
+ return NULL;
+
+ state = __alloc_smatch_state(0);
state->name = alloc_sname(name);
free_string(name);
state->data = expr;
@@ -166,16 +178,16 @@ static void __get_variable_from_expr(struct symbol **sym_ptr, char *buf,
deref = expr->deref;
op = deref->op;
- if (op == '*') {
+ if (deref->type == EXPR_PREOP && op == '*') {
struct expression *unop = strip_expr(deref->unop);
if (unop->type == EXPR_PREOP && unop->op == '&') {
deref = unop->unop;
op = '.';
} else {
- deref = deref->unop;
- if (!is_pointer(deref))
+ if (!is_pointer(deref) && !is_pointer(deref->unop))
op = '.';
+ deref = deref->unop;
}
}
@@ -527,7 +539,7 @@ char *expr_to_chunk_helper(struct expression *expr, struct symbol **sym, struct
if (sym)
*sym = tmp;
if (vsl)
- *vsl = expr_to_vsl(expr);
+ add_var_sym(vsl, name, tmp);
return name;
}
free_string(name);
@@ -869,8 +881,52 @@ char *get_member_name(struct expression *expr)
expr->member->name);
return alloc_string(buf);
}
- if (!sym->ident)
- return NULL;
+ if (!sym->ident) {
+ struct expression *deref;
+ char *full, *outer;
+ int len;
+
+ /*
+ * If we're in an anonymous struct then maybe we can find an
+ * outer struct name to use as a name. This code should be
+ * recursive and cleaner. I am not very proud of it.
+ *
+ */
+
+ deref = expr->deref;
+ if (deref->type != EXPR_DEREF || !deref->member)
+ return NULL;
+ sym = get_type(deref->deref);
+ if (!sym || sym->type != SYM_STRUCT || !sym->ident)
+ return NULL;
+
+ full = expr_to_str(expr);
+ if (!full)
+ return NULL;
+ deref = deref->deref;
+ if (deref->type == EXPR_PREOP && deref->op == '*')
+ deref = deref->unop;
+ outer = expr_to_str(deref);
+ if (!outer) {
+ free_string(full);
+ return NULL;
+ }
+ len = strlen(outer);
+ if (strncmp(outer, full, len) != 0) {
+ free_string(full);
+ free_string(outer);
+ return NULL;
+ }
+ if (full[len] == '-' && full[len + 1] == '>')
+ len += 2;
+ if (full[len] == '.')
+ len++;
+ snprintf(buf, sizeof(buf), "(struct %s)->%s", sym->ident->name, full + len);
+ free_string(outer);
+ free_string(full);
+
+ return alloc_string(buf);
+ }
snprintf(buf, sizeof(buf), "(struct %s)->%s", sym->ident->name, expr->member->name);
return alloc_string(buf);
}
@@ -1054,6 +1110,34 @@ int invert_op(int op)
return 0;
}
+int op_remove_assign(int op)
+{
+ switch (op) {
+ case SPECIAL_ADD_ASSIGN:
+ return '+';
+ case SPECIAL_SUB_ASSIGN:
+ return '-';
+ case SPECIAL_MUL_ASSIGN:
+ return '*';
+ case SPECIAL_DIV_ASSIGN:
+ return '/';
+ case SPECIAL_MOD_ASSIGN:
+ return '%';
+ case SPECIAL_AND_ASSIGN:
+ return '&';
+ case SPECIAL_OR_ASSIGN:
+ return '|';
+ case SPECIAL_XOR_ASSIGN:
+ return '^';
+ case SPECIAL_SHL_ASSIGN:
+ return SPECIAL_LEFTSHIFT;
+ case SPECIAL_SHR_ASSIGN:
+ return SPECIAL_RIGHTSHIFT;
+ default:
+ return op;
+ }
+}
+
int expr_equiv(struct expression *one, struct expression *two)
{
struct symbol *one_sym = NULL;
diff --git a/usr/src/tools/smatch/src/smatch_ignore.c b/usr/src/tools/smatch/src/smatch_ignore.c
index eb06a0512a..fa2b564bab 100644
--- a/usr/src/tools/smatch/src/smatch_ignore.c
+++ b/usr/src/tools/smatch/src/smatch_ignore.c
@@ -20,6 +20,7 @@
STATE(ignore);
static struct stree *ignored;
+static struct stree *ignored_from_file;
void add_ignore(int owner, const char *name, struct symbol *sym)
{
@@ -54,7 +55,18 @@ int is_ignored_expr(int owner, struct expression *expr)
return 0;
ret = is_ignored(owner, name, sym);
free_string(name);
- return ret;
+ if (ret)
+ return true;
+
+ name = get_macro_name(expr->pos);
+ if (name && get_state_stree(ignored_from_file, owner, name, NULL))
+ return true;
+
+ name = get_function();
+ if (name && get_state_stree(ignored_from_file, owner, name, NULL))
+ return true;
+
+ return false;
}
static void clear_ignores(void)
@@ -64,7 +76,39 @@ static void clear_ignores(void)
free_stree(&ignored);
}
+static void load_ignores(void)
+{
+ struct token *token;
+ const char *name, *str;
+ int owner;
+ char buf[64];
+
+ snprintf(buf, sizeof(buf), "%s.ignored_warnings", option_project_str);
+ token = get_tokens_file(buf);
+ if (!token)
+ return;
+ if (token_type(token) != TOKEN_STREAMBEGIN)
+ return;
+ token = token->next;
+ while (token_type(token) != TOKEN_STREAMEND) {
+ if (token_type(token) != TOKEN_IDENT)
+ break;
+ name = show_ident(token->ident);
+ token = token->next;
+ owner = id_from_name(name);
+
+ if (token_type(token) != TOKEN_IDENT)
+ break;
+ str = show_ident(token->ident);
+ token = token->next;
+
+ set_state_stree_perm(&ignored_from_file, owner, str, NULL, &ignore);
+ }
+ clear_token_alloc();
+}
+
void register_smatch_ignore(int id)
{
add_hook(&clear_ignores, AFTER_FUNC_HOOK);
+ load_ignores();
}
diff --git a/usr/src/tools/smatch/src/smatch_imaginary_absolute.c b/usr/src/tools/smatch/src/smatch_imaginary_absolute.c
index 6532dfc397..3b401bd965 100644
--- a/usr/src/tools/smatch/src/smatch_imaginary_absolute.c
+++ b/usr/src/tools/smatch/src/smatch_imaginary_absolute.c
@@ -53,6 +53,8 @@ static void reset(struct sm_state *sm, struct expression *mod_expr)
void __save_imaginary_state(struct expression *expr, struct range_list *true_rl, struct range_list *false_rl)
{
+ if (__in_pre_condition)
+ return;
set_true_false_states_expr(my_id, expr, alloc_estate_rl(true_rl), alloc_estate_rl(false_rl));
}
@@ -74,6 +76,7 @@ void register_imaginary_absolute(int id)
{
my_id = id;
+ set_dynamic_states(my_id);
add_unmatched_state_hook(my_id, &empty_state);
add_merge_hook(my_id, &merge_is_empty);
add_modification_hook(my_id, &reset);
diff --git a/usr/src/tools/smatch/src/smatch_implied.c b/usr/src/tools/smatch/src/smatch_implied.c
index ae5ff1dc4c..86f682f851 100644
--- a/usr/src/tools/smatch/src/smatch_implied.c
+++ b/usr/src/tools/smatch/src/smatch_implied.c
@@ -65,9 +65,11 @@
#include "smatch_extra.h"
char *implied_debug_msg;
-#define DIMPLIED(msg...) do { if (option_debug_implied || option_debug) printf(msg); } while (0)
-int option_debug_implied = 0;
+bool implications_off;
+
+#define implied_debug 0
+#define DIMPLIED(msg...) do { if (implied_debug) printf(msg); } while (0)
/*
* tmp_range_list():
@@ -87,7 +89,7 @@ static struct range_list *tmp_range_list(struct symbol *type, long long num)
static void print_debug_tf(struct sm_state *sm, int istrue, int isfalse)
{
- if (!option_debug_implied && !option_debug)
+ if (!implied_debug && !option_debug)
return;
if (istrue && isfalse) {
@@ -143,18 +145,18 @@ static int create_fake_history(struct sm_state *sm, int comparison, struct range
return 0;
}
- if (option_debug)
- sm_info("fake_history: %s vs %s. %s %s %s. --> T: %s F: %s",
+ if (implied_debug)
+ sm_msg("fake_history: %s vs %s. %s %s %s. --> T: %s F: %s",
sm->name, show_rl(rl), sm->state->name, show_special(comparison), show_rl(rl),
show_rl(true_rl), show_rl(false_rl));
true_sm = clone_sm(sm);
false_sm = clone_sm(sm);
- true_sm->state = alloc_estate_rl(cast_rl(estate_type(sm->state), true_rl));
+ true_sm->state = clone_partial_estate(sm->state, true_rl);
free_slist(&true_sm->possible);
add_possible_sm(true_sm, true_sm);
- false_sm->state = alloc_estate_rl(cast_rl(estate_type(sm->state), false_rl));
+ false_sm->state = clone_partial_estate(sm->state, false_rl);
free_slist(&false_sm->possible);
add_possible_sm(false_sm, false_sm);
@@ -266,7 +268,6 @@ static void do_compare(struct sm_state *sm, int comparison, struct range_list *r
add_pool(false_stack, sm);
else
add_pool(maybe_stack, sm);
-
}
static int is_checked(struct state_list *checked, struct sm_state *sm)
@@ -292,34 +293,24 @@ static void __separate_pools(struct sm_state *sm, int comparison, struct range_l
struct state_list **true_stack,
struct state_list **maybe_stack,
struct state_list **false_stack,
- struct state_list **checked, int *mixed, struct sm_state *gate_sm)
+ struct state_list **checked, int *mixed, struct sm_state *gate_sm,
+ struct timeval *start_time)
{
int free_checked = 0;
struct state_list *checked_states = NULL;
+ struct timeval now;
if (!sm)
return;
- /*
- * If it looks like this is going to take too long as-is, then don't
- * create even more fake history.
- */
- if (mixed && sm->nr_children > 100)
- *mixed = 1;
-
- /*
- Sometimes the implications are just too big to deal with
- so we bail. Theoretically, bailing out here can cause more false
- positives but won't hide actual bugs.
- */
- if (sm->nr_children > 4000) {
- if (option_debug || option_debug_implied) {
- static char buf[1028];
- snprintf(buf, sizeof(buf), "debug: %s: nr_children over 4000 (%d). (%s %s)",
- __func__, sm->nr_children, sm->name, show_state(sm->state));
- implied_debug_msg = buf;
+ gettimeofday(&now, NULL);
+ if (now.tv_usec - start_time->tv_usec > 1000000) {
+ if (implied_debug) {
+ sm_msg("debug: %s: implications taking too long. (%s %s %s)",
+ __func__, sm->state->name, show_special(comparison), show_rl(rl));
}
- return;
+ if (mixed)
+ *mixed = 1;
}
if (checked == NULL) {
@@ -332,8 +323,8 @@ static void __separate_pools(struct sm_state *sm, int comparison, struct range_l
do_compare(sm, comparison, rl, true_stack, maybe_stack, false_stack, mixed, gate_sm);
- __separate_pools(sm->left, comparison, rl, true_stack, maybe_stack, false_stack, checked, mixed, gate_sm);
- __separate_pools(sm->right, comparison, rl, true_stack, maybe_stack, false_stack, checked, mixed, gate_sm);
+ __separate_pools(sm->left, comparison, rl, true_stack, maybe_stack, false_stack, checked, mixed, gate_sm, start_time);
+ __separate_pools(sm->right, comparison, rl, true_stack, maybe_stack, false_stack, checked, mixed, gate_sm, start_time);
if (free_checked)
free_slist(checked);
}
@@ -345,10 +336,13 @@ static void separate_pools(struct sm_state *sm, int comparison, struct range_lis
{
struct state_list *maybe_stack = NULL;
struct sm_state *tmp;
+ struct timeval start_time;
+
- __separate_pools(sm, comparison, rl, true_stack, &maybe_stack, false_stack, checked, mixed, sm);
+ gettimeofday(&start_time, NULL);
+ __separate_pools(sm, comparison, rl, true_stack, &maybe_stack, false_stack, checked, mixed, sm, &start_time);
- if (option_debug) {
+ if (implied_debug) {
struct sm_state *sm;
FOR_EACH_PTR(*true_stack, sm) {
@@ -356,7 +350,8 @@ static void separate_pools(struct sm_state *sm, int comparison, struct range_lis
} END_FOR_EACH_PTR(sm);
FOR_EACH_PTR(maybe_stack, sm) {
- sm_msg("MAYBE %s [stree %d]", show_sm(sm), get_stree_id(sm->pool));
+ sm_msg("MAYBE %s %s[stree %d]",
+ show_sm(sm), sm->merged ? "(merged) ": "", get_stree_id(sm->pool));
} END_FOR_EACH_PTR(sm);
FOR_EACH_PTR(*false_stack, sm) {
@@ -392,24 +387,52 @@ static int sm_in_keep_leafs(struct sm_state *sm, const struct state_list *keep_g
return 0;
}
-static int taking_too_long(void)
+static int going_too_slow(void)
{
static void *printed;
- if (out_of_memory())
+ if (out_of_memory()) {
+ implications_off = true;
return 1;
+ }
- if (time_parsing_function() < option_timeout)
+ if (!option_timeout || time_parsing_function() < option_timeout) {
+ implications_off = false;
return 0;
+ }
if (!__inline_fn && printed != cur_func_sym) {
if (!is_skipped_function())
- sm_perror("turning off implications after 60 seconds");
+ sm_perror("turning off implications after %d seconds", option_timeout);
printed = cur_func_sym;
}
+ implications_off = true;
return 1;
}
+static char *sm_state_info(struct sm_state *sm)
+{
+ static char buf[512];
+ int n = 0;
+
+ n += snprintf(buf + n, sizeof(buf) - n, "[stree %d line %d] ",
+ get_stree_id(sm->pool), sm->line);
+ if (n >= sizeof(buf))
+ return buf;
+ n += snprintf(buf + n, sizeof(buf) - n, "%s ", show_sm(sm));
+ if (n >= sizeof(buf))
+ return buf;
+ n += snprintf(buf + n, sizeof(buf) - n, "left = %s [stree %d] ",
+ sm->left ? sm->left->state->name : "<none>",
+ sm->left ? get_stree_id(sm->left->pool) : -1);
+ if (n >= sizeof(buf))
+ return buf;
+ n += snprintf(buf + n, sizeof(buf) - n, "right = %s [stree %d]",
+ sm->right ? sm->right->state->name : "<none>",
+ sm->right ? get_stree_id(sm->right->pool) : -1);
+ return buf;
+}
+
/*
* NOTE: If a state is in both the keep stack and the remove stack then that is
* a bug. Only add states which are definitely true or definitely false. If
@@ -417,11 +440,12 @@ static int taking_too_long(void)
* split history where one side is true and one side is false. Otherwise, if
* you can't do that, then don't add it to either list.
*/
+#define RECURSE_LIMIT 300
struct sm_state *filter_pools(struct sm_state *sm,
const struct state_list *remove_stack,
const struct state_list *keep_stack,
int *modified, int *recurse_cnt,
- struct timeval *start)
+ struct timeval *start, int *skip, int *bail)
{
struct sm_state *ret = NULL;
struct sm_state *left;
@@ -431,51 +455,46 @@ struct sm_state *filter_pools(struct sm_state *sm,
if (!sm)
return NULL;
- if (sm->skip_implications)
- return sm;
- if (taking_too_long())
- return sm;
-
+ if (*bail)
+ return NULL;
gettimeofday(&now, NULL);
- if ((*recurse_cnt)++ > 1000 || now.tv_sec - start->tv_sec > 5) {
- if (local_debug || option_debug_implied) {
- static char buf[1028];
- snprintf(buf, sizeof(buf), "debug: %s: nr_children over 4000 (%d). (%s %s)",
- __func__, sm->nr_children, sm->name, show_state(sm->state));
- implied_debug_msg = buf;
- }
- sm->skip_implications = 1;
- return sm;
+ if (now.tv_usec - start->tv_usec > 3000000) {
+ DIMPLIED("%s: implications taking too long: %s\n", __func__, sm_state_info(sm));
+ *bail = 1;
+ return NULL;
+ }
+ if ((*recurse_cnt)++ > RECURSE_LIMIT) {
+ DIMPLIED("%s: recursed too far: %s\n", __func__, sm_state_info(sm));
+ *skip = 1;
+ return NULL;
}
if (pool_in_pools(sm->pool, remove_stack)) {
- DIMPLIED("removed [stree %d] %s from %d\n", get_stree_id(sm->pool), show_sm(sm), sm->line);
+ DIMPLIED("%s: remove: %s\n", __func__, sm_state_info(sm));
*modified = 1;
return NULL;
}
if (!is_merged(sm) || pool_in_pools(sm->pool, keep_stack) || sm_in_keep_leafs(sm, keep_stack)) {
- DIMPLIED("kept [stree %d] %s from %d. %s. %s. %s.\n", get_stree_id(sm->pool), show_sm(sm), sm->line,
+ DIMPLIED("%s: keep %s (%s, %s, %s): %s\n", __func__, sm->state->name,
is_merged(sm) ? "merged" : "not merged",
pool_in_pools(sm->pool, keep_stack) ? "not in keep pools" : "in keep pools",
- sm_in_keep_leafs(sm, keep_stack) ? "reachable keep leaf" : "no keep leaf");
+ sm_in_keep_leafs(sm, keep_stack) ? "reachable keep leaf" : "no keep leaf",
+ sm_state_info(sm));
return sm;
}
- DIMPLIED("checking [stree %d] %s from %d (%d) left = %s [stree %d] right = %s [stree %d]\n",
- get_stree_id(sm->pool),
- show_sm(sm), sm->line, sm->nr_children,
- sm->left ? sm->left->state->name : "<none>", sm->left ? get_stree_id(sm->left->pool) : -1,
- sm->right ? sm->right->state->name : "<none>", sm->right ? get_stree_id(sm->right->pool) : -1);
- left = filter_pools(sm->left, remove_stack, keep_stack, &removed, recurse_cnt, start);
- right = filter_pools(sm->right, remove_stack, keep_stack, &removed, recurse_cnt, start);
+ left = filter_pools(sm->left, remove_stack, keep_stack, &removed, recurse_cnt, start, skip, bail);
+ right = filter_pools(sm->right, remove_stack, keep_stack, &removed, recurse_cnt, start, skip, bail);
+ if (*bail || *skip)
+ return NULL;
if (!removed) {
- DIMPLIED("kept [stree %d] %s from %d\n", get_stree_id(sm->pool), show_sm(sm), sm->line);
+ DIMPLIED("%s: kept all: %s\n", __func__, sm_state_info(sm));
return sm;
}
*modified = 1;
if (!left && !right) {
- DIMPLIED("removed [stree %d] %s from %d <none>\n", get_stree_id(sm->pool), show_sm(sm), sm->line);
+ DIMPLIED("%s: removed all: %s\n", __func__, sm_state_info(sm));
return NULL;
}
@@ -505,8 +524,7 @@ struct sm_state *filter_pools(struct sm_state *sm,
ret->pool = sm->pool;
- DIMPLIED("partial %s => ", show_sm(sm));
- DIMPLIED("%s from %d [stree %d]\n", show_sm(ret), sm->line, get_stree_id(sm->pool));
+ DIMPLIED("%s: partial: %s\n", __func__, sm_state_info(sm));
return ret;
}
@@ -521,33 +539,32 @@ static struct stree *filter_stack(struct sm_state *gate_sm,
int modified;
int recurse_cnt;
struct timeval start;
+ int skip;
+ int bail = 0;
if (!remove_stack)
return NULL;
- if (taking_too_long())
- return NULL;
-
+ gettimeofday(&start, NULL);
FOR_EACH_SM(pre_stree, tmp) {
- if (option_debug)
- sm_msg("%s: %s", __func__, show_sm(tmp));
- if (!tmp->merged)
- continue;
- if (sm_in_keep_leafs(tmp, keep_stack))
+ if (!tmp->merged || sm_in_keep_leafs(tmp, keep_stack))
continue;
modified = 0;
recurse_cnt = 0;
- gettimeofday(&start, NULL);
- filtered_sm = filter_pools(tmp, remove_stack, keep_stack, &modified, &recurse_cnt, &start);
- if (!filtered_sm || !modified)
+ skip = 0;
+ filtered_sm = filter_pools(tmp, remove_stack, keep_stack, &modified, &recurse_cnt, &start, &skip, &bail);
+ if (going_too_slow())
+ return NULL;
+ if (bail)
+ return ret; /* Return the implications we figured out before time ran out. */
+
+
+ if (skip || !filtered_sm || !modified)
continue;
/* the assignments here are for borrowed implications */
filtered_sm->name = tmp->name;
filtered_sm->sym = tmp->sym;
avl_insert(&ret, filtered_sm);
- if (out_of_memory() || taking_too_long())
- return NULL;
-
} END_FOR_EACH_SM(tmp);
return ret;
}
@@ -566,16 +583,14 @@ static void separate_and_filter(struct sm_state *sm, int comparison, struct rang
gettimeofday(&time_before, NULL);
+ DIMPLIED("checking implications: (%s (%s) %s %s)\n",
+ sm->name, sm->state->name, show_special(comparison), show_rl(rl));
+
if (!is_merged(sm)) {
- DIMPLIED("%d '%s' is not merged.\n", get_lineno(), sm->name);
+ DIMPLIED("%d '%s' from line %d is not merged.\n", get_lineno(), sm->name, sm->line);
return;
}
- if (option_debug_implied || option_debug) {
- sm_msg("checking implications: (%s %s %s)",
- sm->name, show_special(comparison), show_rl(rl));
- }
-
separate_pools(sm, comparison, rl, &true_stack, &false_stack, NULL, mixed);
DIMPLIED("filtering true stack.\n");
@@ -584,19 +599,18 @@ static void separate_and_filter(struct sm_state *sm, int comparison, struct rang
*false_states = filter_stack(sm, pre_stree, true_stack, false_stack);
free_slist(&true_stack);
free_slist(&false_stack);
- if (option_debug_implied || option_debug) {
- printf("These are the implied states for the true path: (%s %s %s)\n",
- sm->name, show_special(comparison), show_rl(rl));
+ if (implied_debug) {
+ printf("These are the implied states for the true path: (%s (%s) %s %s)\n",
+ sm->name, sm->state->name, show_special(comparison), show_rl(rl));
__print_stree(*true_states);
- printf("These are the implied states for the false path: (%s %s %s)\n",
- sm->name, show_special(comparison), show_rl(rl));
+ printf("These are the implied states for the false path: (%s (%s) %s %s)\n",
+ sm->name, sm->state->name, show_special(comparison), show_rl(rl));
__print_stree(*false_states);
}
gettimeofday(&time_after, NULL);
sec = time_after.tv_sec - time_before.tv_sec;
- if (sec > option_timeout) {
- sm->nr_children = 4000;
+ if (option_timeout && sec > option_timeout) {
sm_perror("Function too hairy. Ignoring implications after %d seconds.", sec);
}
}
@@ -814,7 +828,6 @@ static int handled_by_stored_conditions(struct expression *expr,
return 1;
}
-static int found_implications;
static struct stree *saved_implied_true;
static struct stree *saved_implied_false;
static struct stree *extra_saved_implied_true;
@@ -848,24 +861,20 @@ static void get_tf_states(struct expression *expr,
struct stree **implied_false)
{
if (handled_by_comparison_hook(expr, implied_true, implied_false))
- goto found;
+ return;
if (handled_by_extra_states(expr, implied_true, implied_false)) {
separate_extra_states(implied_true, implied_false);
- goto found;
+ return;
}
if (handled_by_stored_conditions(expr, implied_true, implied_false))
- goto found;
-
- return;
-found:
- found_implications = 1;
+ return;
}
static void save_implications_hook(struct expression *expr)
{
- if (taking_too_long())
+ if (going_too_slow())
return;
get_tf_states(expr, &saved_implied_true, &saved_implied_false);
}
@@ -906,6 +915,9 @@ void param_limit_implications(struct expression *expr, int param, char *key, cha
struct stree *implied_false = NULL;
struct range_list *orig, *limit;
+ if (time_parsing_function() > 40)
+ return;
+
while (expr->type == EXPR_ASSIGNMENT)
expr = strip_expr(expr->right);
if (expr->type != EXPR_CALL)
@@ -1072,7 +1084,6 @@ int assume(struct expression *expr)
in_fake_env++;
final_pass = 0;
__push_fake_cur_stree();
- found_implications = 0;
__split_whole_condition(expr);
final_pass = orig_final_pass;
in_fake_env--;
diff --git a/usr/src/tools/smatch/src/smatch_integer_overflow.c b/usr/src/tools/smatch/src/smatch_integer_overflow.c
new file mode 100644
index 0000000000..e164598aff
--- /dev/null
+++ b/usr/src/tools/smatch/src/smatch_integer_overflow.c
@@ -0,0 +1,292 @@
+/*
+ * Copyright (C) 2015 Oracle.
+ *
+ * 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 program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see http://www.gnu.org/copyleft/gpl.txt
+ */
+
+#include "smatch.h"
+#include "smatch_slist.h"
+#include "smatch_extra.h"
+
+static int my_id;
+static int link_id;
+
+static struct smatch_state *safe_state(struct expression *expr)
+{
+ struct smatch_state *state;
+
+ state = __alloc_smatch_state(0);
+ expr = strip_expr(expr);
+ state->name = alloc_sname("safe");
+ state->data = expr;
+ return state;
+}
+
+static char *save_links(struct expression *expr, struct symbol **sym, struct var_sym_list **vsl)
+{
+ struct var_sym *vs;
+ char *name;
+
+ name = expr_to_chunk_sym_vsl(expr, sym, vsl);
+ if (!name || !*vsl) {
+ free_string(name);
+ return NULL;
+ }
+
+ FOR_EACH_PTR(*vsl, vs) {
+ store_link(link_id, vs->var, vs->sym, name, *sym);
+ } END_FOR_EACH_PTR(vs);
+
+ return name;
+}
+
+static void match_divide(struct expression *expr)
+{
+ struct expression *left, *right, *binop;
+ struct symbol *type;
+ char *name;
+ struct symbol *sym;
+ struct var_sym_list *vsl;
+ sval_t max;
+
+ if (expr->type != EXPR_COMPARE)
+ return;
+ if (expr->op != '>' && expr->op != SPECIAL_UNSIGNED_GT &&
+ expr->op != SPECIAL_GTE && expr->op != SPECIAL_UNSIGNED_GTE)
+ return;
+
+ left = strip_parens(expr->left);
+ right = strip_parens(expr->right);
+
+ if (right->type != EXPR_BINOP || right->op != '/')
+ return;
+ if (!get_value(right->left, &max))
+ return;
+ if (max.value != INT_MAX && max.value != UINT_MAX &&
+ max.value != LLONG_MAX && max.uvalue != ULLONG_MAX)
+ return;
+
+ type = get_type(expr);
+ if (!type)
+ return;
+ if (type_bits(type) != 32 && type_bits(type) != 64)
+ return;
+
+
+ binop = binop_expression(left, '*', right->right);
+
+ name = save_links(binop, &sym, &vsl);
+ if (!name)
+ return;
+ set_true_false_states(my_id, name, sym, NULL, safe_state(binop));
+ free_string(name);
+}
+
+static void match_overflow_to_less_than(struct expression *expr)
+{
+ struct expression *left, *right;
+ struct symbol *type;
+ char *name;
+ struct symbol *sym;
+ struct var_sym_list *vsl;
+
+ if (expr->type != EXPR_COMPARE)
+ return;
+ if (expr->op != '<' && expr->op != SPECIAL_UNSIGNED_LT)
+ return;
+
+ left = strip_parens(expr->left);
+ right = strip_parens(expr->right);
+
+ if (left->op != '+')
+ return;
+
+ type = get_type(expr);
+ if (!type)
+ return;
+ if (type_bits(type) != 32 && type_bits(type) != 64)
+ return;
+
+ if (!expr_equiv(left->left, right) && !expr_equiv(left->right, right))
+ return;
+
+ name = save_links(left, &sym, &vsl);
+ if (!name)
+ return;
+ set_true_false_states(my_id, name, sym, NULL, safe_state(left));
+ free_string(name);
+}
+
+static void match_condition(struct expression *expr)
+{
+ match_overflow_to_less_than(expr);
+ match_divide(expr);
+}
+
+int can_integer_overflow(struct symbol *type, struct expression *expr)
+{
+ int op;
+ sval_t lmax, rmax, res;
+
+ if (!type)
+ type = &int_ctype;
+
+ expr = strip_expr(expr);
+
+ if (expr->type == EXPR_ASSIGNMENT) {
+ switch(expr->op) {
+ case SPECIAL_MUL_ASSIGN:
+ op = '*';
+ break;
+ case SPECIAL_ADD_ASSIGN:
+ op = '+';
+ break;
+ case SPECIAL_SHL_ASSIGN:
+ op = SPECIAL_LEFTSHIFT;
+ break;
+ default:
+ return 0;
+ }
+ } else if (expr->type == EXPR_BINOP) {
+ if (expr->op != '*' && expr->op != '+' && expr->op != SPECIAL_LEFTSHIFT)
+ return 0;
+ op = expr->op;
+ } else {
+ return 0;
+ }
+
+ get_absolute_max(expr->left, &lmax);
+ get_absolute_max(expr->right, &rmax);
+
+ if (sval_binop_overflows(lmax, op, rmax))
+ return 1;
+
+ res = sval_binop(lmax, op, rmax);
+ if (sval_cmp(res, sval_type_max(type)) > 0)
+ return 1;
+ return 0;
+}
+
+int can_integer_overflow_expr(struct expression *expr)
+{
+ struct symbol *type;
+ struct smatch_state *state;
+ char *name;
+ struct symbol *sym;
+ int ret;
+
+ type = get_type(expr);
+ if (!type)
+ return 0;
+
+ if (!can_integer_overflow(type, expr))
+ return 0;
+
+ name = expr_to_known_chunk_sym(expr, &sym);
+ if (!name || !sym)
+ goto free;
+
+ state = get_state(my_id, name, sym);
+ if (state && state->data)
+ ret = 0;
+free:
+ free_string(name);
+ return ret;
+}
+
+static int get_arg_nr(struct expression *call, struct expression *expr)
+{
+ struct expression *arg;
+ int i;
+
+ i = -1;
+ FOR_EACH_PTR(call->args, arg) {
+ i++;
+ if (expr_equiv(arg, expr))
+ return i;
+ } END_FOR_EACH_PTR(arg);
+
+ return -1;
+}
+
+static void check_links(struct expression *call, struct expression *arg, int nr, struct sm_state *sm, void *_vsl)
+{
+ struct var_sym_list *vsl = _vsl;
+ struct var_sym *vs;
+ struct smatch_state *state;
+ struct expression *expr;
+ int left = -1;
+ int right = -1;
+
+ FOR_EACH_PTR(vsl, vs) {
+ state = get_state(my_id, vs->var, vs->sym);
+ if (!state || !state->data)
+ continue;
+
+ expr = state->data;
+
+ if (expr_equiv(arg, expr->left)) {
+ left = nr;
+ right = get_arg_nr(call, expr->right);
+ } else if (expr_equiv(arg, expr->right)) {
+ left = get_arg_nr(call, expr->left);
+ right = nr;
+ }
+
+ if (left == -1 || right == -1)
+ continue;
+
+ left = -1;
+ right = -1;
+ } END_FOR_EACH_PTR(vs);
+}
+
+static void match_call_info(struct expression *call)
+{
+ struct expression *arg;
+ struct sm_state *link;
+ struct stree *done = NULL;
+ int i;
+
+ i = -1;
+ FOR_EACH_PTR(call->args, arg) {
+ i++;
+
+ link = get_sm_state_expr(link_id, arg);
+ if (!link)
+ continue;
+
+ if (get_state_stree(done, my_id, link->state->name, NULL))
+ continue;
+// set_state_stree(&done, my_id, link->state->name, NULL, &undefined);
+
+ check_links(call, arg, i, link, link->state->data);
+ } END_FOR_EACH_PTR(arg);
+
+ free_stree(&done);
+}
+
+void register_integer_overflow(int id)
+{
+ my_id = id;
+ set_dynamic_states(my_id);
+ add_hook(&match_condition, CONDITION_HOOK);
+ add_hook(&match_call_info, FUNCTION_CALL_HOOK);
+}
+
+void register_integer_overflow_links(int id)
+{
+ link_id = id;
+ set_up_link_functions(my_id, link_id);
+}
diff --git a/usr/src/tools/smatch/src/smatch_kernel_user_data.c b/usr/src/tools/smatch/src/smatch_kernel_user_data.c
index 709958a666..dac5bf5208 100644
--- a/usr/src/tools/smatch/src/smatch_kernel_user_data.c
+++ b/usr/src/tools/smatch/src/smatch_kernel_user_data.c
@@ -32,7 +32,7 @@ static int my_call_id;
STATE(called);
static bool func_gets_user_data;
-static const char * kstr_funcs[] = {
+static const char *kstr_funcs[] = {
"kstrtoull", "kstrtoll", "kstrtoul", "kstrtol", "kstrtouint",
"kstrtoint", "kstrtou64", "kstrtos64", "kstrtou32", "kstrtos32",
"kstrtou16", "kstrtos16", "kstrtou8", "kstrtos8", "kstrtoull_from_user"
@@ -45,8 +45,11 @@ static const char * kstr_funcs[] = {
static const char *returns_user_data[] = {
"simple_strtol", "simple_strtoll", "simple_strtoul", "simple_strtoull",
- "kvm_register_read", "nlmsg_data", "nla_data", "memdup_user",
- "kmap_atomic", "skb_network_header",
+ "kvm_register_read",
+};
+
+static const char *returns_pointer_to_user_data[] = {
+ "nlmsg_data", "nla_data", "memdup_user", "kmap_atomic", "skb_network_header",
};
static void set_points_to_user_data(struct expression *expr);
@@ -84,6 +87,7 @@ static void pre_merge_hook(struct sm_state *sm)
{
struct smatch_state *user;
struct smatch_state *extra;
+ struct smatch_state *state;
struct range_list *rl;
sval_t dummy;
sval_t sval_100;
@@ -91,52 +95,90 @@ static void pre_merge_hook(struct sm_state *sm)
sval_100.value = 100;
sval_100.type = &int_ctype;
- user = get_state(my_id, sm->name, sm->sym);
- if (!user)
- return;
- if (!__in_function_def && !estate_rl(sm->state)) {
- /*
- * If the one side is capped and the other side is empty then
- * let's just mark it as not-user data because the information
- * isn't going to be useful. How this looks is:
- *
- * if (user_var > trusted)
- * user_var = trusted; <-- empty state
- * else
- * <-- capped
- *
- * The problem is that sometimes things are capped to a literal
- * and we'd like to keep the state in that case... Ugh. I've
- * added a check which assumes that everything less than 100 is
- * probably capped against a literal.
- *
- */
- if (is_capped_var_sym(sm->name, sm->sym) &&
- sval_cmp(estate_max(user), sval_100) > 0)
- set_state(my_id, sm->name, sm->sym, alloc_estate_empty());
+ user = __get_state(my_id, sm->name, sm->sym);
+ if (!user || !estate_rl(user))
return;
- }
- extra = get_state(SMATCH_EXTRA, sm->name, sm->sym);
- if (!extra || !estate_rl(extra))
+ extra = __get_state(SMATCH_EXTRA, sm->name, sm->sym);
+ if (!extra)
return;
rl = rl_intersection(estate_rl(user), estate_rl(extra));
if (rl_to_sval(rl, &dummy))
rl = NULL;
- set_state(my_id, sm->name, sm->sym, alloc_estate_rl(clone_rl(rl)));
+ state = alloc_estate_rl(clone_rl(rl));
+ if (estate_capped(user) || is_capped_var_sym(sm->name, sm->sym))
+ estate_set_capped(state);
+ set_state(my_id, sm->name, sm->sym, state);
}
static void extra_nomod_hook(const char *name, struct symbol *sym, struct expression *expr, struct smatch_state *state)
{
- struct smatch_state *user;
+ struct smatch_state *user, *new;
struct range_list *rl;
- user = get_state(my_id, name, sym);
+ user = __get_state(my_id, name, sym);
if (!user)
return;
rl = rl_intersection(estate_rl(user), estate_rl(state));
if (rl_equiv(rl, estate_rl(user)))
return;
- set_state(my_id, name, sym, alloc_estate_rl(rl));
+ new = alloc_estate_rl(rl);
+ if (estate_capped(user))
+ estate_set_capped(new);
+ set_state(my_id, name, sym, new);
+}
+
+static bool binop_capped(struct expression *expr)
+{
+ struct range_list *left_rl;
+ int comparison;
+
+ if (expr->op == '-' && get_user_rl(expr->left, &left_rl)) {
+ if (user_rl_capped(expr->left))
+ return true;
+ comparison = get_comparison(expr->left, expr->right);
+ if (comparison && show_special(comparison)[0] == '>')
+ return true;
+ return false;
+ }
+
+ if (expr->op == '&' || expr->op == '%') {
+ if (is_capped(expr->left) || is_capped(expr->right))
+ return true;
+ if (user_rl_capped(expr->left) || user_rl_capped(expr->right))
+ return true;
+ return false;
+ }
+
+ if (user_rl_capped(expr->left) &&
+ user_rl_capped(expr->right))
+ return true;
+ return false;
+}
+
+bool user_rl_capped(struct expression *expr)
+{
+ struct smatch_state *state;
+ struct range_list *rl;
+ sval_t sval;
+
+ expr = strip_expr(expr);
+ if (!expr)
+ return false;
+ if (get_value(expr, &sval))
+ return true;
+ if (expr->type == EXPR_BINOP)
+ return binop_capped(expr);
+ if ((expr->type == EXPR_PREOP || expr->type == EXPR_POSTOP) &&
+ (expr->op == SPECIAL_INCREMENT || expr->op == SPECIAL_DECREMENT))
+ return user_rl_capped(expr->unop);
+ state = get_state_expr(my_id, expr);
+ if (state)
+ return estate_capped(state);
+
+ if (get_user_rl(expr, &rl))
+ return false; /* uncapped user data */
+
+ return true; /* not actually user data */
}
static void tag_inner_struct_members(struct expression *expr, struct symbol *member)
@@ -347,6 +389,22 @@ static int is_skb_data(struct expression *expr)
return 1;
}
+static bool is_points_to_user_data_fn(struct expression *expr)
+{
+ int i;
+
+ expr = strip_expr(expr);
+ if (expr->type != EXPR_CALL || expr->fn->type != EXPR_SYMBOL ||
+ !expr->fn->symbol)
+ return false;
+ expr = expr->fn;
+ for (i = 0; i < ARRAY_SIZE(returns_pointer_to_user_data); i++) {
+ if (sym_name_is(returns_pointer_to_user_data[i], expr))
+ return true;
+ }
+ return false;
+}
+
static int get_rl_from_function(struct expression *expr, struct range_list **rl)
{
int i;
@@ -378,6 +436,8 @@ int points_to_user_data(struct expression *expr)
return 0;
if (is_skb_data(expr))
return 1;
+ if (is_points_to_user_data_fn(expr))
+ return 1;
if (get_rl_from_function(expr, &rl))
return 1;
@@ -393,7 +453,7 @@ int points_to_user_data(struct expression *expr)
if (!name || !sym)
goto free;
snprintf(buf, sizeof(buf), "*%s", name);
- state = get_state(my_id, buf, sym);
+ state = __get_state(my_id, buf, sym);
if (state && estate_rl(state))
ret = 1;
free:
@@ -406,12 +466,18 @@ static void set_points_to_user_data(struct expression *expr)
char *name;
struct symbol *sym;
char buf[256];
+ struct symbol *type;
name = expr_to_var_sym(expr, &sym);
if (!name || !sym)
goto free;
snprintf(buf, sizeof(buf), "*%s", name);
- set_state(my_id, buf, sym, alloc_estate_whole(&llong_ctype));
+ type = get_type(expr);
+ if (type && type->type == SYM_PTR)
+ type = get_real_base_type(type);
+ if (!type || type->type != SYM_BASETYPE)
+ type = &llong_ctype;
+ set_state(my_id, buf, sym, alloc_estate_whole(type));
free:
free_string(name);
}
@@ -489,24 +555,77 @@ free:
return ret;
}
+static bool handle_op_assign(struct expression *expr)
+{
+ struct expression *binop_expr;
+ struct smatch_state *state;
+ struct range_list *rl;
+
+ switch (expr->op) {
+ case SPECIAL_ADD_ASSIGN:
+ case SPECIAL_SUB_ASSIGN:
+ case SPECIAL_AND_ASSIGN:
+ case SPECIAL_MOD_ASSIGN:
+ case SPECIAL_SHL_ASSIGN:
+ case SPECIAL_SHR_ASSIGN:
+ case SPECIAL_OR_ASSIGN:
+ case SPECIAL_XOR_ASSIGN:
+ case SPECIAL_MUL_ASSIGN:
+ case SPECIAL_DIV_ASSIGN:
+ binop_expr = binop_expression(expr->left,
+ op_remove_assign(expr->op),
+ expr->right);
+ if (!get_user_rl(binop_expr, &rl))
+ return true;
+
+ rl = cast_rl(get_type(expr->left), rl);
+ state = alloc_estate_rl(rl);
+ if (user_rl_capped(binop_expr))
+ estate_set_capped(state);
+ set_state_expr(my_id, expr->left, state);
+ return true;
+ }
+ return false;
+}
+
static void match_assign(struct expression *expr)
{
struct range_list *rl;
+ static struct expression *handled;
+ struct smatch_state *state;
+ struct expression *faked;
+ faked = get_faked_expression();
+ if (faked && faked == handled)
+ return;
if (is_fake_call(expr->right))
goto clear_old_state;
if (handle_get_user(expr))
return;
- if (points_to_user_data(expr->right))
+ if (points_to_user_data(expr->right)) {
+ handled = expr;
set_points_to_user_data(expr->left);
+ }
if (handle_struct_assignment(expr))
return;
+ if (handle_op_assign(expr))
+ return;
+ if (expr->op != '=')
+ goto clear_old_state;
+
+ /* Handled by DB code */
+ if (expr->right->type == EXPR_CALL || __in_fake_parameter_assign)
+ return;
+
if (!get_user_rl(expr->right, &rl))
goto clear_old_state;
rl = cast_rl(get_type(expr->left), rl);
- set_state_expr(my_id, expr->left, alloc_estate_rl(rl));
+ state = alloc_estate_rl(rl);
+ if (user_rl_capped(expr->right))
+ estate_set_capped(state);
+ set_state_expr(my_id, expr->left, state);
return;
@@ -538,61 +657,115 @@ static void handle_eq_noteq(struct expression *expr)
}
}
-static void handle_unsigned_lt_gt(struct expression *expr)
+static struct range_list *strip_negatives(struct range_list *rl)
{
+ sval_t min = rl_min(rl);
+ sval_t minus_one;
+ sval_t over;
+ sval_t max = sval_type_max(rl_type(rl));
+
+ minus_one.type = rl_type(rl);
+ minus_one.value = INT_MAX + 1ULL;
+ over.type = rl_type(rl);
+ over.value = -1;
+
+ if (!rl)
+ return NULL;
+
+ if (type_unsigned(rl_type(rl)) && type_bits(rl_type(rl)) > 31)
+ return remove_range(rl, over, max);
+
+ return remove_range(rl, min, minus_one);
+}
+
+static void handle_compare(struct expression *expr)
+{
+ struct expression *left, *right;
+ struct range_list *left_rl = NULL;
+ struct range_list *right_rl = NULL;
+ struct range_list *user_rl;
+ struct smatch_state *capped_state;
+ struct smatch_state *left_true = NULL;
+ struct smatch_state *left_false = NULL;
+ struct smatch_state *right_true = NULL;
+ struct smatch_state *right_false = NULL;
struct symbol *type;
- struct range_list *left;
- struct range_list *right;
- struct range_list *non_negative;
- sval_t min, minus_one;
+ sval_t sval;
+
+ left = strip_expr(expr->left);
+ right = strip_expr(expr->right);
+
+ while (left->type == EXPR_ASSIGNMENT)
+ left = strip_expr(left->left);
/*
- * conditions are mostly handled by smatch_extra.c. The special case
- * here is that say you have if (user_int < unknown_u32) {
- * In Smatch extra we say that, We have no idea what value
- * unknown_u32 is so the only thin we can say for sure is that
- * user_int is not -1 (UINT_MAX). But in check_user_data2.c we should
- * assume that unless unknown_u32 is user data, it's probably less than
- * INT_MAX.
+ * Conditions are mostly handled by smatch_extra.c, but there are some
+ * times where the exact values are not known so we can't do that.
+ *
+ * Normally, we might consider using smatch_capped.c to supliment smatch
+ * extra but that doesn't work when we merge unknown uncapped kernel
+ * data with unknown capped user data. The result is uncapped user
+ * data. We need to keep it separate and say that the user data is
+ * capped. In the past, I would have marked this as just regular
+ * kernel data (not user data) but we can't do that these days because
+ * we need to track user data for Spectre.
+ *
+ * The other situation which we have to handle is when we do have an
+ * int and we compare against an unknown unsigned kernel variable. In
+ * that situation we assume that the kernel data is less than INT_MAX.
+ * Otherwise then we get all sorts of array underflow false positives.
*
*/
- type = get_type(expr);
- if (!type_unsigned(type))
+ /* Handled in smatch_extra.c */
+ if (get_implied_value(left, &sval) ||
+ get_implied_value(right, &sval))
return;
- /*
- * Assume if (user < trusted) { ... because I am lazy and because this
- * is the correct way to write code.
- */
- if (!get_user_rl(expr->left, &left))
+ get_user_rl(left, &left_rl);
+ get_user_rl(right, &right_rl);
+
+ /* nothing to do */
+ if (!left_rl && !right_rl)
return;
- if (get_user_rl(expr->right, &right))
+ /* if both sides are user data that's not a good limit */
+ if (left_rl && right_rl)
return;
- if (!sval_is_negative(rl_min(left)))
- return;
- min = rl_min(left);
- minus_one.type = rl_type(left);
- minus_one.value = -1;
- non_negative = remove_range(left, min, minus_one);
+ if (left_rl)
+ user_rl = left_rl;
+ else
+ user_rl = right_rl;
+
+ type = get_type(expr);
+ if (type_unsigned(type))
+ user_rl = strip_negatives(user_rl);
+ capped_state = alloc_estate_rl(user_rl);
+ estate_set_capped(capped_state);
switch (expr->op) {
case '<':
case SPECIAL_UNSIGNED_LT:
case SPECIAL_LTE:
case SPECIAL_UNSIGNED_LTE:
- set_true_false_states_expr(my_id, expr->left,
- alloc_estate_rl(non_negative), NULL);
+ if (left_rl)
+ left_true = capped_state;
+ else
+ right_false = capped_state;
break;
case '>':
case SPECIAL_UNSIGNED_GT:
case SPECIAL_GTE:
case SPECIAL_UNSIGNED_GTE:
- set_true_false_states_expr(my_id, expr->left,
- NULL, alloc_estate_rl(non_negative));
+ if (left_rl)
+ left_false = capped_state;
+ else
+ right_true = capped_state;
break;
}
+
+ set_true_false_states_expr(my_id, left, left_true, left_false);
+ set_true_false_states_expr(my_id, right, right_true, right_false);
}
static void match_condition(struct expression *expr)
@@ -606,7 +779,7 @@ static void match_condition(struct expression *expr)
return;
}
- handle_unsigned_lt_gt(expr);
+ handle_compare(expr);
}
static void match_user_assign_function(const char *fn, struct expression *expr, void *unused)
@@ -654,38 +827,6 @@ static int get_user_macro_rl(struct expression *expr, struct range_list **rl)
return 0;
}
-struct db_info {
- struct range_list *rl;
- struct expression *call;
-};
-static int returned_rl_callback(void *_info, int argc, char **argv, char **azColName)
-{
- struct db_info *db_info = _info;
- struct range_list *rl;
- char *return_ranges = argv[0];
- char *user_ranges = argv[1];
- struct expression *arg;
- int comparison;
-
- if (argc != 2)
- return 0;
-
- call_results_to_rl(db_info->call, get_type(db_info->call), user_ranges, &rl);
- if (str_to_comparison_arg(return_ranges, db_info->call, &comparison, &arg) &&
- comparison == SPECIAL_EQUAL) {
- struct range_list *orig_rl;
-
- if (!get_user_rl(arg, &orig_rl))
- return 0;
- rl = rl_intersection(rl, orig_rl);
- if (!rl)
- return 0;
- }
- db_info->rl = rl_union(db_info->rl, rl);
-
- return 0;
-}
-
static int has_user_data(struct symbol *sym)
{
struct sm_state *tmp;
@@ -715,35 +856,17 @@ static int we_pass_user_data(struct expression *call)
static int db_returned_user_rl(struct expression *call, struct range_list **rl)
{
- struct db_info db_info = {};
+ struct smatch_state *state;
+ char buf[48];
- /* for function pointers assume everything is used */
- if (call->fn->type != EXPR_SYMBOL)
- return 0;
if (is_fake_call(call))
return 0;
-
- db_info.call = call;
- run_sql(&returned_rl_callback, &db_info,
- "select return, value from return_states where %s and type = %d and parameter = -1 and key = '$';",
- get_static_filter(call->fn->symbol), USER_DATA3_SET);
- if (db_info.rl) {
- func_gets_user_data = true;
- *rl = db_info.rl;
- return 1;
- }
-
- run_sql(&returned_rl_callback, &db_info,
- "select return, value from return_states where %s and type = %d and parameter = -1 and key = '$';",
- get_static_filter(call->fn->symbol), USER_DATA3);
- if (db_info.rl) {
- if (!we_pass_user_data(call))
- return 0;
- *rl = db_info.rl;
- return 1;
- }
-
- return 0;
+ snprintf(buf, sizeof(buf), "return %p", call);
+ state = get_state(my_id, buf, NULL);
+ if (!state || !estate_rl(state))
+ return 0;
+ *rl = estate_rl(state);
+ return 1;
}
struct stree *get_user_stree(void)
@@ -753,12 +876,17 @@ struct stree *get_user_stree(void)
static int user_data_flag;
static int no_user_data_flag;
-static struct range_list *var_user_rl(struct expression *expr)
+struct range_list *var_user_rl(struct expression *expr)
{
struct smatch_state *state;
struct range_list *rl;
struct range_list *absolute_rl;
+ if (expr->type == EXPR_PREOP && expr->op == '&') {
+ no_user_data_flag = 1;
+ return NULL;
+ }
+
if (expr->type == EXPR_BINOP && expr->op == '%') {
struct range_list *left, *right;
@@ -769,7 +897,7 @@ static struct range_list *var_user_rl(struct expression *expr)
goto found;
}
- if (!option_spammy && expr->type == EXPR_BINOP && expr->op == '/') {
+ if (expr->type == EXPR_BINOP && expr->op == '/') {
struct range_list *left = NULL;
struct range_list *right = NULL;
struct range_list *abs_right;
@@ -839,8 +967,23 @@ found:
return clone_rl(rl_intersection(rl, absolute_rl));
}
+static bool is_ptr_subtract(struct expression *expr)
+{
+ expr = strip_expr(expr);
+ if (!expr)
+ return false;
+ if (expr->type == EXPR_BINOP && expr->op == '-' &&
+ type_is_ptr(get_type(expr->left))) {
+ return true;
+ }
+ return false;
+}
+
int get_user_rl(struct expression *expr, struct range_list **rl)
{
+ if (is_ptr_subtract(expr))
+ return 0;
+
user_data_flag = 0;
no_user_data_flag = 0;
custom_get_absolute_rl(expr, &var_user_rl, rl);
@@ -850,22 +993,11 @@ int get_user_rl(struct expression *expr, struct range_list **rl)
return !!*rl;
}
-int get_user_rl_spammy(struct expression *expr, struct range_list **rl)
-{
- int ret;
-
- option_spammy++;
- ret = get_user_rl(expr, rl);
- option_spammy--;
-
- return ret;
-}
-
int is_user_rl(struct expression *expr)
{
struct range_list *tmp;
- return get_user_rl_spammy(expr, &tmp);
+ return !!get_user_rl(expr, &tmp);
}
int get_user_rl_var_sym(const char *name, struct symbol *sym, struct range_list **rl)
@@ -880,23 +1012,35 @@ int get_user_rl_var_sym(const char *name, struct symbol *sym, struct range_list
return 0;
}
-static void match_call_info(struct expression *expr)
+static char *get_user_rl_str(struct expression *expr, struct symbol *type)
{
struct range_list *rl;
+ static char buf[64];
+
+ if (!get_user_rl(expr, &rl))
+ return NULL;
+ rl = cast_rl(type, rl);
+ snprintf(buf, sizeof(buf), "%s%s",
+ show_rl(rl), user_rl_capped(expr) ? "[c]" : "");
+ return buf;
+}
+
+static void match_call_info(struct expression *expr)
+{
struct expression *arg;
struct symbol *type;
- int i = 0;
+ char *str;
+ int i;
i = -1;
FOR_EACH_PTR(expr->args, arg) {
i++;
type = get_arg_type(expr->fn, i);
-
- if (!get_user_rl(arg, &rl))
+ str = get_user_rl_str(arg, type);
+ if (!str)
continue;
- rl = cast_rl(type, rl);
- sql_insert_caller_info(expr, USER_DATA3, i, "$", show_rl(rl));
+ sql_insert_caller_info(expr, USER_DATA, i, "$", str);
} END_FOR_EACH_PTR(arg);
}
@@ -920,6 +1064,7 @@ static void struct_member_callback(struct expression *call, int param, char *pri
struct smatch_state *state;
struct range_list *rl;
struct symbol *type;
+ char buf[64];
/*
* Smatch uses a hack where if we get an unsigned long we say it's
@@ -939,41 +1084,102 @@ static void struct_member_callback(struct expression *call, int param, char *pri
is_struct_ptr(sm->sym))
return;
- state = get_state(SMATCH_EXTRA, sm->name, sm->sym);
+ state = __get_state(SMATCH_EXTRA, sm->name, sm->sym);
if (!state || !estate_rl(state))
rl = estate_rl(sm->state);
else
rl = rl_intersection(estate_rl(sm->state), estate_rl(state));
- sql_insert_caller_info(call, USER_DATA3, param, printed_name, show_rl(rl));
+ if (!rl)
+ return;
+
+ snprintf(buf, sizeof(buf), "%s%s", show_rl(rl),
+ estate_capped(sm->state) ? "[c]" : "");
+ sql_insert_caller_info(call, USER_DATA, param, printed_name, buf);
+}
+
+static void db_param_set(struct expression *expr, int param, char *key, char *value)
+{
+ struct expression *arg;
+ char *name;
+ struct symbol *sym;
+ struct smatch_state *state;
+
+ while (expr->type == EXPR_ASSIGNMENT)
+ expr = strip_expr(expr->right);
+ if (expr->type != EXPR_CALL)
+ return;
+
+ arg = get_argument_from_call_expr(expr->args, param);
+ if (!arg)
+ return;
+ name = get_variable_from_key(arg, key, &sym);
+ if (!name || !sym)
+ goto free;
+
+ state = get_state(my_id, name, sym);
+ if (!state)
+ goto free;
+
+ set_state(my_id, name, sym, alloc_estate_empty());
+free:
+ free_string(name);
+}
+
+static bool param_data_capped(const char *value)
+{
+ if (strstr(value, ",c") || strstr(value, "[c"))
+ return true;
+ return false;
}
static void set_param_user_data(const char *name, struct symbol *sym, char *key, char *value)
{
struct range_list *rl = NULL;
struct smatch_state *state;
+ struct expression *expr;
struct symbol *type;
char fullname[256];
+ char *key_orig = key;
+ bool add_star = false;
- if (strcmp(key, "*$") == 0)
- snprintf(fullname, sizeof(fullname), "*%s", name);
- else if (strncmp(key, "$", 1) == 0)
- snprintf(fullname, 256, "%s%s", name, key + 1);
- else
- return;
+ if (strcmp(key, "**$") == 0) {
+ snprintf(fullname, sizeof(fullname), "**%s", name);
+ } else {
+ if (key[0] == '*') {
+ add_star = true;
+ key++;
+ }
- type = get_member_type_from_key(symbol_expression(sym), key);
+ snprintf(fullname, 256, "%s%s%s", add_star ? "*" : "", name, key + 1);
+ }
- /* if the caller passes a void pointer with user data */
- if (strcmp(key, "*$") == 0 && type && type != &void_ctype) {
- struct expression *expr = symbol_expression(sym);
+ expr = symbol_expression(sym);
+ type = get_member_type_from_key(expr, key_orig);
- tag_as_user_data(expr);
- set_points_to_user_data(expr);
- return;
+ /*
+ * Say this function takes a struct ponter but the caller passes
+ * this_function(skb->data). We have two options, we could pass *$
+ * as user data or we could pass foo->bar, foo->baz as user data.
+ * The second option is easier to implement so we do that.
+ *
+ */
+ if (strcmp(key_orig, "*$") == 0) {
+ struct symbol *tmp = type;
+
+ while (tmp && tmp->type == SYM_PTR)
+ tmp = get_real_base_type(tmp);
+
+ if (tmp && (tmp->type == SYM_STRUCT || tmp->type == SYM_UNION)) {
+ tag_as_user_data(symbol_expression(sym));
+ return;
+ }
}
+
str_to_rl(type, value, &rl);
state = alloc_estate_rl(rl);
+ if (param_data_capped(value) || is_capped(expr))
+ estate_set_capped(state);
set_state(my_id, fullname, sym, state);
}
@@ -1012,8 +1218,25 @@ static void match_syscall_definition(struct symbol *sym)
} END_FOR_EACH_PTR(arg);
}
+static void store_user_data_return(struct expression *expr, char *key, char *value)
+{
+ struct range_list *rl;
+ struct symbol *type;
+ char buf[48];
+
+ if (strcmp(key, "$") != 0)
+ return;
+
+ type = get_type(expr);
+ snprintf(buf, sizeof(buf), "return %p", expr);
+ call_results_to_rl(expr, type, value, &rl);
+
+ set_state(my_id, buf, NULL, alloc_estate_rl(rl));
+}
+
static void set_to_user_data(struct expression *expr, char *key, char *value)
{
+ struct smatch_state *state;
char *name;
struct symbol *sym;
struct symbol *type;
@@ -1026,10 +1249,12 @@ static void set_to_user_data(struct expression *expr, char *key, char *value)
call_results_to_rl(expr, type, value, &rl);
- set_state(my_id, name, sym, alloc_estate_rl(rl));
+ state = alloc_estate_rl(rl);
+ if (param_data_capped(value))
+ estate_set_capped(state);
+ set_state(my_id, name, sym, state);
free:
free_string(name);
-
}
static void returns_param_user_data(struct expression *expr, int param, char *key, char *value)
@@ -1047,8 +1272,10 @@ static void returns_param_user_data(struct expression *expr, int param, char *ke
return;
if (param == -1) {
- if (expr->type != EXPR_ASSIGNMENT)
+ if (expr->type != EXPR_ASSIGNMENT) {
+ store_user_data_return(expr, key, value);
return;
+ }
set_to_user_data(expr->left, key, value);
return;
}
@@ -1066,8 +1293,10 @@ static void returns_param_user_data_set(struct expression *expr, int param, char
func_gets_user_data = true;
if (param == -1) {
- if (expr->type != EXPR_ASSIGNMENT)
+ if (expr->type != EXPR_ASSIGNMENT) {
+ store_user_data_return(expr, key, value);
return;
+ }
if (strcmp(key, "*$") == 0) {
set_points_to_user_data(expr->left);
tag_as_user_data(expr->left);
@@ -1088,18 +1317,6 @@ static void returns_param_user_data_set(struct expression *expr, int param, char
set_to_user_data(arg, key, value);
}
-static int has_empty_state(struct sm_state *sm)
-{
- struct sm_state *tmp;
-
- FOR_EACH_PTR(sm->possible, tmp) {
- if (!estate_rl(tmp->state))
- return 1;
- } END_FOR_EACH_PTR(tmp);
-
- return 0;
-}
-
static void param_set_to_user_data(int return_id, char *return_ranges, struct expression *expr)
{
struct sm_state *sm;
@@ -1110,19 +1327,21 @@ static void param_set_to_user_data(int return_id, char *return_ranges, struct ex
const char *param_name;
struct symbol *ret_sym;
bool return_found = false;
+ bool pointed_at_found = false;
+ char buf[64];
expr = strip_expr(expr);
return_str = expr_to_str(expr);
ret_sym = expr_to_sym(expr);
FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
- if (has_empty_state(sm))
- continue;
-
param = get_param_num_from_sym(sm->sym);
if (param < 0)
continue;
+ if (!param_was_set_var_sym(sm->name, sm->sym))
+ continue;
+
/* The logic here was that if we were passed in a user data then
* we don't record that. It's like the difference between
* param_filter and param_set. When I think about it, I'm not
@@ -1140,20 +1359,15 @@ static void param_set_to_user_data(int return_id, char *return_ranges, struct ex
if (strcmp(param_name, "$") == 0) /* The -1 param is handled after the loop */
continue;
+ snprintf(buf, sizeof(buf), "%s%s",
+ show_rl(estate_rl(sm->state)),
+ estate_capped(sm->state) ? "[c]" : "");
sql_insert_return_states(return_id, return_ranges,
- func_gets_user_data ? USER_DATA3_SET : USER_DATA3,
- param, param_name, show_rl(estate_rl(sm->state)));
+ func_gets_user_data ? USER_DATA_SET : USER_DATA,
+ param, param_name, buf);
} END_FOR_EACH_SM(sm);
- if (points_to_user_data(expr)) {
- sql_insert_return_states(return_id, return_ranges,
- (is_skb_data(expr) || !func_gets_user_data) ?
- USER_DATA3_SET : USER_DATA3,
- -1, "*$", "");
- goto free_string;
- }
-
-
+ /* This if for "return foo;" where "foo->bar" is user data. */
FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
if (!ret_sym)
break;
@@ -1165,23 +1379,61 @@ static void param_set_to_user_data(int return_id, char *return_ranges, struct ex
continue;
if (strcmp(param_name, "$") == 0)
return_found = true;
+ if (strcmp(param_name, "*$") == 0)
+ pointed_at_found = true;
+ snprintf(buf, sizeof(buf), "%s%s",
+ show_rl(estate_rl(sm->state)),
+ estate_capped(sm->state) ? "[c]" : "");
sql_insert_return_states(return_id, return_ranges,
- func_gets_user_data ? USER_DATA3_SET : USER_DATA3,
- -1, param_name, show_rl(estate_rl(sm->state)));
+ func_gets_user_data ? USER_DATA_SET : USER_DATA,
+ -1, param_name, buf);
} END_FOR_EACH_SM(sm);
-
+ /* This if for "return ntohl(foo);" */
if (!return_found && get_user_rl(expr, &rl)) {
+ snprintf(buf, sizeof(buf), "%s%s",
+ show_rl(rl), user_rl_capped(expr) ? "[c]" : "");
sql_insert_return_states(return_id, return_ranges,
- func_gets_user_data ? USER_DATA3_SET : USER_DATA3,
- -1, "$", show_rl(rl));
- goto free_string;
+ func_gets_user_data ? USER_DATA_SET : USER_DATA,
+ -1, "$", buf);
+ }
+
+ /*
+ * This is to handle things like return skb->data where we don't set a
+ * state for that.
+ */
+ if (!pointed_at_found && points_to_user_data(expr)) {
+ sql_insert_return_states(return_id, return_ranges,
+ (is_skb_data(expr) || func_gets_user_data) ?
+ USER_DATA_SET : USER_DATA,
+ -1, "*$", "s64min-s64max");
}
-free_string:
free_string(return_str);
}
+static void returns_param_capped(struct expression *expr, int param, char *key, char *value)
+{
+ struct smatch_state *state, *new;
+ struct symbol *sym;
+ char *name;
+
+ name = return_state_to_var_sym(expr, param, key, &sym);
+ if (!name || !sym)
+ goto free;
+
+ state = get_state(my_id, name, sym);
+ if (!state || estate_capped(state))
+ goto free;
+
+ new = clone_estate(state);
+ estate_set_capped(new);
+
+ set_state(my_id, name, sym, new);
+free:
+ free_string(name);
+}
+
static struct int_stack *gets_data_stack;
static void match_function_def(struct symbol *sym)
{
@@ -1198,7 +1450,7 @@ static void match_inline_end(struct expression *expr)
func_gets_user_data = pop_int(&gets_data_stack);
}
-void register_kernel_user_data2(int id)
+void register_kernel_user_data(int id)
{
int i;
@@ -1207,6 +1459,8 @@ void register_kernel_user_data2(int id)
if (option_project != PROJ_KERNEL)
return;
+ set_dynamic_states(my_id);
+
add_hook(&match_function_def, FUNC_DEF_HOOK);
add_hook(&match_inline_start, INLINE_FN_START);
add_hook(&match_inline_end, INLINE_FN_END);
@@ -1238,17 +1492,19 @@ void register_kernel_user_data2(int id)
add_hook(&match_syscall_definition, AFTER_DEF_HOOK);
add_hook(&match_assign, ASSIGNMENT_HOOK);
+ select_return_states_hook(PARAM_SET, &db_param_set);
add_hook(&match_condition, CONDITION_HOOK);
add_hook(&match_call_info, FUNCTION_CALL_HOOK);
add_member_info_callback(my_id, struct_member_callback);
- select_caller_info_hook(set_param_user_data, USER_DATA3);
- select_return_states_hook(USER_DATA3, &returns_param_user_data);
- select_return_states_hook(USER_DATA3_SET, &returns_param_user_data_set);
+ select_caller_info_hook(set_param_user_data, USER_DATA);
+ select_return_states_hook(USER_DATA, &returns_param_user_data);
+ select_return_states_hook(USER_DATA_SET, &returns_param_user_data_set);
+ select_return_states_hook(CAPPED_DATA, &returns_param_capped);
add_split_return_callback(&param_set_to_user_data);
}
-void register_kernel_user_data3(int id)
+void register_kernel_user_data2(int id)
{
my_call_id = id;
@@ -1256,4 +1512,3 @@ void register_kernel_user_data3(int id)
return;
select_caller_info_hook(set_called, INTERNAL);
}
-
diff --git a/usr/src/tools/smatch/src/smatch_links.c b/usr/src/tools/smatch/src/smatch_links.c
index c24f0c220b..ba467224e0 100644
--- a/usr/src/tools/smatch/src/smatch_links.c
+++ b/usr/src/tools/smatch/src/smatch_links.c
@@ -102,6 +102,7 @@ void set_up_link_functions(int id, int link_id)
if (id + 1 != link_id)
sm_fatal("FATAL ERROR: links need to be registered directly after the check");
+ set_dynamic_states(link_id);
add_merge_hook(link_id, &merge_link_states);
add_modification_hook(link_id, &match_link_modify);
// free link at the end of function
diff --git a/usr/src/tools/smatch/src/smatch_local_values.c b/usr/src/tools/smatch/src/smatch_local_values.c
index cffc206612..da0fcc4055 100644
--- a/usr/src/tools/smatch/src/smatch_local_values.c
+++ b/usr/src/tools/smatch/src/smatch_local_values.c
@@ -234,6 +234,7 @@ void register_local_values(int id)
if (!option_info)
return;
+ set_dynamic_states(my_id);
add_extra_mod_hook(&extra_mod_hook);
add_unmatched_state_hook(my_id, &unmatched_state);
add_merge_hook(my_id, &merge_estates);
diff --git a/usr/src/tools/smatch/src/smatch_math.c b/usr/src/tools/smatch/src/smatch_math.c
index 04d3c0a4b4..9fb3429dd5 100644
--- a/usr/src/tools/smatch/src/smatch_math.c
+++ b/usr/src/tools/smatch/src/smatch_math.c
@@ -20,11 +20,12 @@
#include "smatch_slist.h"
#include "smatch_extra.h"
-static struct range_list *_get_rl(struct expression *expr, int implied, int *recurse_cnt);
-static struct range_list *handle_variable(struct expression *expr, int implied, int *recurse_cnt);
+static bool get_rl_sval(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *sval_res);
+static bool get_rl_internal(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res);
+static bool handle_variable(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval);
static struct range_list *(*custom_handle_variable)(struct expression *expr);
-static int get_implied_value_internal(struct expression *expr, sval_t *sval, int *recurse_cnt);
+static bool get_implied_value_internal(struct expression *expr, int *recurse_cnt, sval_t *res_sval);
static int get_absolute_rl_internal(struct expression *expr, struct range_list **rl, int *recurse_cnt);
static sval_t zero = {.type = &int_ctype, {.value = 0} };
@@ -58,12 +59,12 @@ enum {
RL_REAL_ABSOLUTE,
};
-static struct range_list *last_stmt_rl(struct statement *stmt, int implied, int *recurse_cnt)
+static bool last_stmt_rl(struct statement *stmt, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval)
{
struct expression *expr;
if (!stmt)
- return NULL;
+ return false;
stmt = last_ptr_list((struct ptr_list *)stmt->stmts);
if (stmt->type == STMT_LABEL) {
@@ -71,116 +72,224 @@ static struct range_list *last_stmt_rl(struct statement *stmt, int implied, int
stmt->label_statement->type == STMT_EXPRESSION)
expr = stmt->label_statement->expression;
else
- return NULL;
+ return false;
} else if (stmt->type == STMT_EXPRESSION) {
expr = stmt->expression;
} else {
- return NULL;
+ return false;
}
- return _get_rl(expr, implied, recurse_cnt);
+ return get_rl_sval(expr, implied, recurse_cnt, res, res_sval);
}
-static struct range_list *handle_expression_statement_rl(struct expression *expr, int implied, int *recurse_cnt)
+static bool handle_expression_statement_rl(struct expression *expr, int implied,
+ int *recurse_cnt, struct range_list **res, sval_t *res_sval)
{
- return last_stmt_rl(get_expression_statement(expr), implied, recurse_cnt);
+ return last_stmt_rl(get_expression_statement(expr), implied, recurse_cnt, res, res_sval);
}
-static struct range_list *handle_ampersand_rl(struct expression *expr, int implied, int *recurse_cnt)
+static bool handle_address(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval)
{
struct range_list *rl;
+ static int recursed;
sval_t sval;
- if (implied == RL_EXACT || implied == RL_HARD)
- return NULL;
- if (get_mtag_sval(expr, &sval))
- return alloc_rl(sval, sval);
- if (get_address_rl(expr, &rl))
- return rl;
- return alloc_rl(valid_ptr_min_sval, valid_ptr_max_sval);
+ if (recursed > 10)
+ return false;
+ if (implied == RL_EXACT)
+ return false;
+
+ if (custom_handle_variable) {
+ rl = custom_handle_variable(expr);
+ if (rl) {
+ *res = rl;
+ return true;
+ }
+ }
+
+ recursed++;
+ if (get_mtag_sval(expr, &sval)) {
+ recursed--;
+ *res_sval = sval;
+ return true;
+ }
+
+ if (get_address_rl(expr, res)) {
+ recursed--;
+ return true;
+ }
+ recursed--;
+ return 0;
+}
+
+static bool handle_ampersand_rl(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval)
+{
+ return handle_address(expr, implied, recurse_cnt, res, res_sval);
}
-static struct range_list *handle_negate_rl(struct expression *expr, int implied, int *recurse_cnt)
+static bool handle_negate_rl(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval)
{
- if (known_condition_true(expr->unop))
- return rl_zero();
- if (known_condition_false(expr->unop))
- return rl_one();
+ if (known_condition_true(expr->unop)) {
+ *res_sval = zero;
+ return true;
+ }
+ if (known_condition_false(expr->unop)) {
+ *res_sval = one;
+ return true;
+ }
if (implied == RL_EXACT)
- return NULL;
+ return false;
- if (implied_condition_true(expr->unop))
- return rl_zero();
- if (implied_condition_false(expr->unop))
- return rl_one();
- return alloc_rl(zero, one);
+ if (implied_condition_true(expr->unop)) {
+ *res_sval = zero;
+ return true;
+ }
+ if (implied_condition_false(expr->unop)) {
+ *res_sval = one;
+ return true;
+ }
+
+ *res = alloc_rl(zero, one);
+ return true;
}
-static struct range_list *handle_bitwise_negate(struct expression *expr, int implied, int *recurse_cnt)
+static bool handle_bitwise_negate(struct expression *expr, int implied, int *recurse_cnt, sval_t *res_sval)
{
struct range_list *rl;
- sval_t sval;
+ sval_t sval = {};
- rl = _get_rl(expr->unop, implied, recurse_cnt);
- if (!rl_to_sval(rl, &sval))
- return NULL;
+ if (!get_rl_sval(expr->unop, implied, recurse_cnt, &rl, &sval))
+ return false;
+ if (!sval.type && !rl_to_sval(rl, &sval))
+ return false;
sval = sval_preop(sval, '~');
sval_cast(get_type(expr->unop), sval);
- return alloc_rl(sval, sval);
+ *res_sval = sval;
+ return true;
}
-static struct range_list *handle_minus_preop(struct expression *expr, int implied, int *recurse_cnt)
+static bool untrusted_type_min(struct expression *expr)
{
struct range_list *rl;
- sval_t min, max;
- rl = _get_rl(expr->unop, implied, recurse_cnt);
- min = sval_preop(rl_max(rl), '-');
- max = sval_preop(rl_min(rl), '-');
- return alloc_rl(min, max);
+ rl = var_user_rl(expr);
+ return rl && sval_is_min(rl_min(rl));
}
-static struct range_list *handle_preop_rl(struct expression *expr, int implied, int *recurse_cnt)
+static bool handle_minus_preop(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval)
+{
+ struct range_list *rl;
+ struct range_list *ret = NULL;
+ struct symbol *type;
+ sval_t neg_one = { 0 };
+ sval_t zero = { 0 };
+ sval_t sval = {};
+
+ neg_one.value = -1;
+ zero.value = 0;
+
+ if (!get_rl_sval(expr->unop, implied, recurse_cnt, &rl, &sval))
+ return false;
+ if (sval.type) {
+ *res_sval = sval_preop(sval, '-');
+ return true;
+ }
+ /*
+ * One complication is that -INT_MIN is still INT_MIN because of integer
+ * overflows... But how many times do we set a time out to INT_MIN?
+ * So normally when we call abs() then it does return a positive value.
+ *
+ */
+ type = rl_type(rl);
+ neg_one.type = zero.type = type;
+
+ if (sval_is_negative(rl_min(rl))) {
+ struct range_list *neg;
+ struct data_range *drange;
+ sval_t new_min, new_max;
+
+ neg = alloc_rl(sval_type_min(type), neg_one);
+ neg = rl_intersection(rl, neg);
+
+ if (sval_is_min(rl_min(neg)) && !sval_is_min(rl_max(neg)))
+ neg = remove_range(neg, sval_type_min(type), sval_type_min(type));
+
+ FOR_EACH_PTR(neg, drange) {
+ new_min = drange->max;
+ new_min.value = -new_min.value;
+ new_max = drange->min;
+ new_max.value = -new_max.value;
+ add_range(&ret, new_min, new_max);
+ } END_FOR_EACH_PTR(drange);
+
+ if (untrusted_type_min(expr))
+ add_range(&ret, sval_type_min(type), sval_type_min(type));
+ }
+
+ if (!sval_is_negative(rl_max(rl))) {
+ struct range_list *pos;
+ struct data_range *drange;
+ sval_t new_min, new_max;
+
+ pos = alloc_rl(zero, sval_type_max(type));
+ pos = rl_intersection(rl, pos);
+
+ FOR_EACH_PTR(pos, drange) {
+ new_min = drange->max;
+ new_min.value = -new_min.value;
+ new_max = drange->min;
+ new_max.value = -new_max.value;
+ add_range(&ret, new_min, new_max);
+ } END_FOR_EACH_PTR(drange);
+ }
+
+ *res = ret;
+ return true;
+}
+
+static bool handle_preop_rl(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval)
{
switch (expr->op) {
case '&':
- return handle_ampersand_rl(expr, implied, recurse_cnt);
+ return handle_ampersand_rl(expr, implied, recurse_cnt, res, res_sval);
case '!':
- return handle_negate_rl(expr, implied, recurse_cnt);
+ return handle_negate_rl(expr, implied, recurse_cnt, res, res_sval);
case '~':
- return handle_bitwise_negate(expr, implied, recurse_cnt);
+ return handle_bitwise_negate(expr, implied, recurse_cnt, res_sval);
case '-':
- return handle_minus_preop(expr, implied, recurse_cnt);
+ return handle_minus_preop(expr, implied, recurse_cnt, res, res_sval);
case '*':
- return handle_variable(expr, implied, recurse_cnt);
+ return handle_variable(expr, implied, recurse_cnt, res, res_sval);
case '(':
- return handle_expression_statement_rl(expr, implied, recurse_cnt);
+ return handle_expression_statement_rl(expr, implied, recurse_cnt, res, res_sval);
default:
- return NULL;
+ return false;
}
}
-static struct range_list *handle_divide_rl(struct expression *expr, int implied, int *recurse_cnt)
+static bool handle_divide_rl(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res)
{
- struct range_list *left_rl, *right_rl;
+ struct range_list *left_rl = NULL;
+ struct range_list *right_rl = NULL;
struct symbol *type;
type = get_type(expr);
- left_rl = _get_rl(expr->left, implied, recurse_cnt);
+ get_rl_internal(expr->left, implied, recurse_cnt, &left_rl);
left_rl = cast_rl(type, left_rl);
- right_rl = _get_rl(expr->right, implied, recurse_cnt);
+ get_rl_internal(expr->right, implied, recurse_cnt, &right_rl);
right_rl = cast_rl(type, right_rl);
if (!left_rl || !right_rl)
- return NULL;
+ return false;
if (implied != RL_REAL_ABSOLUTE) {
if (is_whole_rl(left_rl) || is_whole_rl(right_rl))
- return NULL;
+ return false;
}
- return rl_binop(left_rl, '/', right_rl);
+ *res = rl_binop(left_rl, '/', right_rl);
+ return true;
}
static int handle_offset_subtraction(struct expression *expr)
@@ -224,12 +333,12 @@ static int handle_offset_subtraction(struct expression *expr)
return left_offset - right_offset;
}
-static struct range_list *handle_subtract_rl(struct expression *expr, int implied, int *recurse_cnt)
+static bool handle_subtract_rl(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res)
{
struct symbol *type;
struct range_list *left_orig, *right_orig;
struct range_list *left_rl, *right_rl;
- sval_t max, min, tmp;
+ sval_t min, max, tmp;
int comparison;
int offset;
@@ -240,19 +349,22 @@ static struct range_list *handle_subtract_rl(struct expression *expr, int implie
tmp.type = type;
tmp.value = offset;
- return alloc_rl(tmp, tmp);
+ *res = alloc_rl(tmp, tmp);
+ return true;
}
comparison = get_comparison(expr->left, expr->right);
- left_orig = _get_rl(expr->left, implied, recurse_cnt);
+ left_orig = NULL;
+ get_rl_internal(expr->left, implied, recurse_cnt, &left_orig);
left_rl = cast_rl(type, left_orig);
- right_orig = _get_rl(expr->right, implied, recurse_cnt);
+ right_orig = NULL;
+ get_rl_internal(expr->right, implied, recurse_cnt, &right_orig);
right_rl = cast_rl(type, right_orig);
if ((!left_rl || !right_rl) &&
(implied == RL_EXACT || implied == RL_HARD || implied == RL_FUZZY))
- return NULL;
+ return false;
if (!left_rl)
left_rl = alloc_whole_rl(type);
@@ -261,7 +373,7 @@ static struct range_list *handle_subtract_rl(struct expression *expr, int implie
/* negative values complicate everything fix this later */
if (sval_is_negative(rl_min(right_rl)))
- return NULL;
+ return false;
max = rl_max(left_rl);
min = sval_type_min(type);
@@ -290,8 +402,9 @@ static struct range_list *handle_subtract_rl(struct expression *expr, int implie
break;
default:
if (!left_orig || !right_orig)
- return NULL;
- return rl_binop(left_rl, '-', right_rl);
+ return false;
+ *res = rl_binop(left_rl, '-', right_rl);
+ return true;
}
if (!sval_binop_overflows(rl_min(left_rl), '-', rl_max(right_rl))) {
@@ -307,129 +420,75 @@ static struct range_list *handle_subtract_rl(struct expression *expr, int implie
}
if (sval_is_min(min) && sval_is_max(max))
- return NULL;
+ return false;
- return cast_rl(type, alloc_rl(min, max));
+ *res = cast_rl(type, alloc_rl(min, max));
+ return true;
}
-static struct range_list *handle_mod_rl(struct expression *expr, int implied, int *recurse_cnt)
+static bool handle_mod_rl(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res)
{
struct range_list *rl;
sval_t left, right, sval;
if (implied == RL_EXACT) {
if (!get_implied_value(expr->right, &right))
- return NULL;
+ return false;
if (!get_implied_value(expr->left, &left))
- return NULL;
+ return false;
sval = sval_binop(left, '%', right);
- return alloc_rl(sval, sval);
+ *res = alloc_rl(sval, sval);
+ return true;
}
/* if we can't figure out the right side it's probably hopeless */
- if (!get_implied_value_internal(expr->right, &right, recurse_cnt))
- return NULL;
+ if (!get_implied_value_internal(expr->right, recurse_cnt, &right))
+ return false;
right = sval_cast(get_type(expr), right);
right.value--;
- rl = _get_rl(expr->left, implied, recurse_cnt);
- if (rl && rl_max(rl).uvalue < right.uvalue)
+ if (get_rl_internal(expr->left, implied, recurse_cnt, &rl) && rl &&
+ rl_max(rl).uvalue < right.uvalue)
right.uvalue = rl_max(rl).uvalue;
- return alloc_rl(sval_cast(right.type, zero), right);
-}
-
-static sval_t sval_lowest_set_bit(sval_t sval)
-{
- int i;
- int found = 0;
-
- for (i = 0; i < 64; i++) {
- if (sval.uvalue & 1ULL << i) {
- if (!found++)
- continue;
- sval.uvalue &= ~(1ULL << i);
- }
- }
- return sval;
+ *res = alloc_rl(sval_cast(right.type, zero), right);
+ return true;
}
-static struct range_list *handle_bitwise_AND(struct expression *expr, int implied, int *recurse_cnt)
+static bool handle_bitwise_AND(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res)
{
struct symbol *type;
struct range_list *left_rl, *right_rl;
- sval_t known;
int new_recurse;
if (implied != RL_IMPLIED && implied != RL_ABSOLUTE && implied != RL_REAL_ABSOLUTE)
- return NULL;
+ return false;
type = get_type(expr);
- if (get_implied_value_internal(expr->left, &known, recurse_cnt)) {
- sval_t min;
-
- min = sval_lowest_set_bit(known);
- left_rl = alloc_rl(min, known);
- left_rl = cast_rl(type, left_rl);
- add_range(&left_rl, sval_type_val(type, 0), sval_type_val(type, 0));
- } else {
- left_rl = _get_rl(expr->left, implied, recurse_cnt);
- if (left_rl) {
- left_rl = cast_rl(type, left_rl);
- left_rl = alloc_rl(sval_type_val(type, 0), rl_max(left_rl));
- } else {
- if (implied == RL_HARD)
- return NULL;
- left_rl = alloc_whole_rl(type);
- }
- }
+ if (!get_rl_internal(expr->left, implied, recurse_cnt, &left_rl))
+ left_rl = alloc_whole_rl(type);
+ left_rl = cast_rl(type, left_rl);
new_recurse = *recurse_cnt;
if (*recurse_cnt >= 200)
new_recurse = 100; /* Let's try super hard to get the mask */
- if (get_implied_value_internal(expr->right, &known, &new_recurse)) {
- sval_t min, left_max, mod;
-
- *recurse_cnt = new_recurse;
-
- min = sval_lowest_set_bit(known);
- right_rl = alloc_rl(min, known);
- right_rl = cast_rl(type, right_rl);
- add_range(&right_rl, sval_type_val(type, 0), sval_type_val(type, 0));
-
- if (min.value != 0) {
- left_max = rl_max(left_rl);
- mod = sval_binop(left_max, '%', min);
- if (mod.value) {
- left_max = sval_binop(left_max, '-', mod);
- left_max.value++;
- if (left_max.value > 0 && sval_cmp(left_max, rl_max(left_rl)) < 0)
- left_rl = remove_range(left_rl, left_max, rl_max(left_rl));
- }
- }
- } else {
- right_rl = _get_rl(expr->right, implied, recurse_cnt);
- if (right_rl) {
- right_rl = cast_rl(type, right_rl);
- right_rl = alloc_rl(sval_type_val(type, 0), rl_max(right_rl));
- } else {
- if (implied == RL_HARD)
- return NULL;
- right_rl = alloc_whole_rl(type);
- }
- }
+ if (!get_rl_internal(expr->right, implied, &new_recurse, &right_rl))
+ right_rl = alloc_whole_rl(type);
+ right_rl = cast_rl(type, right_rl);
+ *recurse_cnt = new_recurse;
- return rl_intersection(left_rl, right_rl);
+ *res = rl_binop(left_rl, '&', right_rl);
+ return true;
}
-static struct range_list *use_rl_binop(struct expression *expr, int implied, int *recurse_cnt)
+static bool use_rl_binop(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res)
{
struct symbol *type;
struct range_list *left_rl, *right_rl;
if (implied != RL_IMPLIED && implied != RL_ABSOLUTE && implied != RL_REAL_ABSOLUTE)
- return NULL;
+ return false;
type = get_type(expr);
@@ -438,90 +497,78 @@ static struct range_list *use_rl_binop(struct expression *expr, int implied, int
left_rl = cast_rl(type, left_rl);
right_rl = cast_rl(type, right_rl);
if (!left_rl || !right_rl)
- return NULL;
+ return false;
- return rl_binop(left_rl, expr->op, right_rl);
+ *res = rl_binop(left_rl, expr->op, right_rl);
+ return true;
}
-static struct range_list *handle_right_shift(struct expression *expr, int implied, int *recurse_cnt)
+static bool handle_right_shift(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res)
{
- struct range_list *left_rl;
- sval_t right;
+ struct range_list *left_rl, *right_rl;
sval_t min, max;
if (implied == RL_EXACT || implied == RL_HARD)
- return NULL;
+ return false;
- left_rl = _get_rl(expr->left, implied, recurse_cnt);
- if (left_rl) {
+ if (get_rl_internal(expr->left, implied, recurse_cnt, &left_rl)) {
max = rl_max(left_rl);
min = rl_min(left_rl);
} else {
if (implied == RL_FUZZY)
- return NULL;
+ return false;
max = sval_type_max(get_type(expr->left));
min = sval_type_val(get_type(expr->left), 0);
}
- if (get_implied_value_internal(expr->right, &right, recurse_cnt)) {
- min = sval_binop(min, SPECIAL_RIGHTSHIFT, right);
- max = sval_binop(max, SPECIAL_RIGHTSHIFT, right);
+ if (get_rl_internal(expr->right, implied, recurse_cnt, &right_rl) &&
+ !sval_is_negative(rl_min(right_rl))) {
+ min = sval_binop(min, SPECIAL_RIGHTSHIFT, rl_max(right_rl));
+ max = sval_binop(max, SPECIAL_RIGHTSHIFT, rl_min(right_rl));
} else if (!sval_is_negative(min)) {
min.value = 0;
max = sval_type_max(max.type);
} else {
- return NULL;
+ return false;
}
- return alloc_rl(min, max);
+ *res = alloc_rl(min, max);
+ return true;
}
-static struct range_list *handle_left_shift(struct expression *expr, int implied, int *recurse_cnt)
+static bool handle_left_shift(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res)
{
- struct range_list *left_rl, *res;
+ struct range_list *left_rl, *rl;
sval_t right;
- sval_t min, max;
- int add_zero = 0;
if (implied == RL_EXACT || implied == RL_HARD)
- return NULL;
+ return false;
/* this is hopeless without the right side */
- if (!get_implied_value_internal(expr->right, &right, recurse_cnt))
- return NULL;
- left_rl = _get_rl(expr->left, implied, recurse_cnt);
- if (left_rl) {
- max = rl_max(left_rl);
- min = rl_min(left_rl);
- if (min.value == 0) {
- min.value = 1;
- add_zero = 1;
- }
- } else {
+ if (!get_implied_value_internal(expr->right, recurse_cnt, &right))
+ return false;
+ if (!get_rl_internal(expr->left, implied, recurse_cnt, &left_rl)) {
if (implied == RL_FUZZY)
- return NULL;
- max = sval_type_max(get_type(expr->left));
- min = sval_type_val(get_type(expr->left), 1);
- add_zero = 1;
+ return false;
+ left_rl = alloc_whole_rl(get_type(expr->left));
}
- max = sval_binop(max, SPECIAL_LEFTSHIFT, right);
- min = sval_binop(min, SPECIAL_LEFTSHIFT, right);
- res = alloc_rl(min, max);
- if (add_zero)
- res = rl_union(res, rl_zero());
- return res;
+ rl = rl_binop(left_rl, SPECIAL_LEFTSHIFT, alloc_rl(right, right));
+ if (!rl)
+ return false;
+ *res = rl;
+ return true;
}
-static struct range_list *handle_known_binop(struct expression *expr)
+static bool handle_known_binop(struct expression *expr, sval_t *res)
{
sval_t left, right;
if (!get_value(expr->left, &left))
- return NULL;
+ return false;
if (!get_value(expr->right, &right))
- return NULL;
- left = sval_binop(left, expr->op, right);
- return alloc_rl(left, left);
+ return false;
+ *res = sval_binop(left, expr->op, right);
+ return true;
}
static int has_actual_ranges(struct range_list *rl)
@@ -566,74 +613,92 @@ static struct range_list *handle_implied_binop(struct range_list *left_rl, int o
return res_rl;
}
-static struct range_list *handle_binop_rl(struct expression *expr, int implied, int *recurse_cnt)
+static bool handle_binop_rl_helper(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval)
{
- struct smatch_state *state;
struct symbol *type;
- struct range_list *left_rl, *right_rl, *rl;
+ struct range_list *left_rl = NULL;
+ struct range_list *right_rl = NULL;
+ struct range_list *rl;
sval_t min, max;
- rl = handle_known_binop(expr);
- if (rl)
- return rl;
- if (implied == RL_EXACT)
- return NULL;
-
- if (custom_handle_variable) {
- rl = custom_handle_variable(expr);
- if (rl)
- return rl;
- }
-
- state = get_extra_state(expr);
- if (state && !is_whole_rl(estate_rl(state))) {
- if (implied != RL_HARD || estate_has_hard_max(state))
- return clone_rl(estate_rl(state));
- }
-
- type = get_type(expr);
- left_rl = _get_rl(expr->left, implied, recurse_cnt);
+ type = get_promoted_type(get_type(expr->left), get_type(expr->right));
+ get_rl_internal(expr->left, implied, recurse_cnt, &left_rl);
left_rl = cast_rl(type, left_rl);
- right_rl = _get_rl(expr->right, implied, recurse_cnt);
+ get_rl_internal(expr->right, implied, recurse_cnt, &right_rl);
right_rl = cast_rl(type, right_rl);
-
if (!left_rl && !right_rl)
- return NULL;
+ return false;
rl = handle_implied_binop(left_rl, expr->op, right_rl);
- if (rl)
- return rl;
+ if (rl) {
+ *res = rl;
+ return true;
+ }
switch (expr->op) {
case '%':
- return handle_mod_rl(expr, implied, recurse_cnt);
+ return handle_mod_rl(expr, implied, recurse_cnt, res);
case '&':
- return handle_bitwise_AND(expr, implied, recurse_cnt);
+ return handle_bitwise_AND(expr, implied, recurse_cnt, res);
case '|':
case '^':
- return use_rl_binop(expr, implied, recurse_cnt);
+ return use_rl_binop(expr, implied, recurse_cnt, res);
case SPECIAL_RIGHTSHIFT:
- return handle_right_shift(expr, implied, recurse_cnt);
+ return handle_right_shift(expr, implied, recurse_cnt, res);
case SPECIAL_LEFTSHIFT:
- return handle_left_shift(expr, implied, recurse_cnt);
+ return handle_left_shift(expr, implied, recurse_cnt, res);
case '-':
- return handle_subtract_rl(expr, implied, recurse_cnt);
+ return handle_subtract_rl(expr, implied, recurse_cnt, res);
case '/':
- return handle_divide_rl(expr, implied, recurse_cnt);
+ return handle_divide_rl(expr, implied, recurse_cnt, res);
}
if (!left_rl || !right_rl)
- return NULL;
+ return false;
if (sval_binop_overflows(rl_min(left_rl), expr->op, rl_min(right_rl)))
- return NULL;
+ return false;
if (sval_binop_overflows(rl_max(left_rl), expr->op, rl_max(right_rl)))
- return NULL;
+ return false;
min = sval_binop(rl_min(left_rl), expr->op, rl_min(right_rl));
max = sval_binop(rl_max(left_rl), expr->op, rl_max(right_rl));
- return alloc_rl(min, max);
+ *res = alloc_rl(min, max);
+ return true;
+
+}
+
+static bool handle_binop_rl(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval)
+{
+ struct smatch_state *state;
+ struct range_list *rl;
+ sval_t val;
+
+ if (handle_known_binop(expr, &val)) {
+ *res_sval = val;
+ return true;
+ }
+ if (implied == RL_EXACT)
+ return false;
+
+ if (custom_handle_variable) {
+ rl = custom_handle_variable(expr);
+ if (rl) {
+ *res = rl;
+ return true;
+ }
+ }
+
+ state = get_extra_state(expr);
+ if (state && !is_whole_rl(estate_rl(state))) {
+ if (implied != RL_HARD || estate_has_hard_max(state)) {
+ *res = clone_rl(estate_rl(state));
+ return true;
+ }
+ }
+
+ return handle_binop_rl_helper(expr, implied, recurse_cnt, res, res_sval);
}
static int do_comparison(struct expression *expr)
@@ -662,19 +727,25 @@ static int do_comparison(struct expression *expr)
return 0x3;
}
-static struct range_list *handle_comparison_rl(struct expression *expr, int implied, int *recurse_cnt)
+static bool handle_comparison_rl(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval)
{
sval_t left, right;
- int res;
+ int cmp;
if (expr->op == SPECIAL_EQUAL && expr->left->type == EXPR_TYPE) {
struct symbol *left, *right;
+ if (expr->right->type != EXPR_TYPE)
+ return false;
+
left = get_real_base_type(expr->left->symbol);
- right = get_real_base_type(expr->left->symbol);
- if (left == right)
- return rl_one();
- return rl_zero();
+ right = get_real_base_type(expr->right->symbol);
+ if (type_bits(left) == type_bits(right) &&
+ type_positive_bits(left) == type_positive_bits(right))
+ *res_sval = one;
+ else
+ *res_sval = zero;
+ return true;
}
if (get_value(expr->left, &left) && get_value(expr->right, &right)) {
@@ -685,23 +756,30 @@ static struct range_list *handle_comparison_rl(struct expression *expr, int impl
tmp_right.min = right;
tmp_right.max = right;
if (true_comparison_range(&tmp_left, expr->op, &tmp_right))
- return rl_one();
- return rl_zero();
+ *res_sval = one;
+ else
+ *res_sval = zero;
+ return true;
}
if (implied == RL_EXACT)
- return NULL;
+ return false;
- res = do_comparison(expr);
- if (res == 1)
- return rl_one();
- if (res == 2)
- return rl_zero();
+ cmp = do_comparison(expr);
+ if (cmp == 1) {
+ *res_sval = one;
+ return true;
+ }
+ if (cmp == 2) {
+ *res_sval = zero;
+ return true;
+ }
- return alloc_rl(zero, one);
+ *res = alloc_rl(zero, one);
+ return true;
}
-static struct range_list *handle_logical_rl(struct expression *expr, int implied, int *recurse_cnt)
+static bool handle_logical_rl(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval)
{
sval_t left, right;
int left_known = 0;
@@ -713,39 +791,47 @@ static struct range_list *handle_logical_rl(struct expression *expr, int implied
if (get_value(expr->right, &right))
right_known = 1;
} else {
- if (get_implied_value_internal(expr->left, &left, recurse_cnt))
+ if (get_implied_value_internal(expr->left, recurse_cnt, &left))
left_known = 1;
- if (get_implied_value_internal(expr->right, &right, recurse_cnt))
+ if (get_implied_value_internal(expr->right, recurse_cnt, &right))
right_known = 1;
}
switch (expr->op) {
case SPECIAL_LOGICAL_OR:
if (left_known && left.value)
- return rl_one();
+ goto one;
if (right_known && right.value)
- return rl_one();
+ goto one;
if (left_known && right_known)
- return rl_zero();
+ goto zero;
break;
case SPECIAL_LOGICAL_AND:
if (left_known && right_known) {
if (left.value && right.value)
- return rl_one();
- return rl_zero();
+ goto one;
+ goto zero;
}
break;
default:
- return NULL;
+ return false;
}
if (implied == RL_EXACT)
- return NULL;
+ return false;
- return alloc_rl(zero, one);
+ *res = alloc_rl(zero, one);
+ return true;
+
+zero:
+ *res_sval = zero;
+ return true;
+one:
+ *res_sval = one;
+ return true;
}
-static struct range_list *handle_conditional_rl(struct expression *expr, int implied, int *recurse_cnt)
+static bool handle_conditional_rl(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval)
{
struct expression *cond_true;
struct range_list *true_rl, *false_rl;
@@ -757,79 +843,81 @@ static struct range_list *handle_conditional_rl(struct expression *expr, int imp
cond_true = expr->conditional;
if (known_condition_true(expr->conditional))
- return _get_rl(cond_true, implied, recurse_cnt);
+ return get_rl_sval(cond_true, implied, recurse_cnt, res, res_sval);
if (known_condition_false(expr->conditional))
- return _get_rl(expr->cond_false, implied, recurse_cnt);
+ return get_rl_sval(expr->cond_false, implied, recurse_cnt, res, res_sval);
if (implied == RL_EXACT)
- return NULL;
+ return false;
if (implied_condition_true(expr->conditional))
- return _get_rl(cond_true, implied, recurse_cnt);
+ return get_rl_sval(cond_true, implied, recurse_cnt, res, res_sval);
if (implied_condition_false(expr->conditional))
- return _get_rl(expr->cond_false, implied, recurse_cnt);
-
+ return get_rl_sval(expr->cond_false, implied, recurse_cnt, res, res_sval);
/* this becomes a problem with deeply nested conditional statements */
if (low_on_memory())
- return NULL;
+ return false;
type = get_type(expr);
__push_fake_cur_stree();
final_pass = 0;
__split_whole_condition(expr->conditional);
- true_rl = _get_rl(cond_true, implied, recurse_cnt);
+ true_rl = NULL;
+ get_rl_internal(cond_true, implied, recurse_cnt, &true_rl);
__push_true_states();
__use_false_states();
- false_rl = _get_rl(expr->cond_false, implied, recurse_cnt);
+ false_rl = NULL;
+ get_rl_internal(expr->cond_false, implied, recurse_cnt, &false_rl);
__merge_true_states();
__free_fake_cur_stree();
final_pass = final_pass_orig;
if (!true_rl || !false_rl)
- return NULL;
+ return false;
true_rl = cast_rl(type, true_rl);
false_rl = cast_rl(type, false_rl);
- return rl_union(true_rl, false_rl);
+ *res = rl_union(true_rl, false_rl);
+ return true;
}
-static int get_fuzzy_max_helper(struct expression *expr, sval_t *max)
+static bool get_fuzzy_max_helper(struct expression *expr, sval_t *max)
{
struct smatch_state *state;
sval_t sval;
if (get_hard_max(expr, &sval)) {
*max = sval;
- return 1;
+ return true;
}
state = get_extra_state(expr);
if (!state || !estate_has_fuzzy_max(state))
- return 0;
+ return false;
*max = sval_cast(get_type(expr), estate_get_fuzzy_max(state));
- return 1;
+ return true;
}
-static int get_fuzzy_min_helper(struct expression *expr, sval_t *min)
+static bool get_fuzzy_min_helper(struct expression *expr, sval_t *min)
{
struct smatch_state *state;
sval_t sval;
state = get_extra_state(expr);
if (!state || !estate_rl(state))
- return 0;
+ return false;
sval = estate_min(state);
if (sval_is_negative(sval) && sval_is_min(sval))
- return 0;
+ return false;
if (sval_is_max(sval))
- return 0;
+ return false;
*min = sval_cast(get_type(expr), sval);
- return 1;
+ return true;
}
int get_const_value(struct expression *expr, sval_t *sval)
@@ -873,54 +961,67 @@ struct range_list *var_to_absolute_rl(struct expression *expr)
return clone_rl(estate_rl(state));
}
-static struct range_list *handle_variable(struct expression *expr, int implied, int *recurse_cnt)
+static bool handle_variable(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval)
{
struct smatch_state *state;
struct range_list *rl;
sval_t sval, min, max;
struct symbol *type;
- if (get_const_value(expr, &sval))
- return alloc_rl(sval, sval);
+ if (get_const_value(expr, &sval)) {
+ *res_sval = sval;
+ return true;
+ }
+
+ if (implied == RL_EXACT)
+ return false;
if (custom_handle_variable) {
rl = custom_handle_variable(expr);
- if (!rl)
- return var_to_absolute_rl(expr);
- return rl;
+ if (rl) {
+ if (!rl_to_sval(rl, res_sval))
+ *res = rl;
+ } else {
+ *res = var_to_absolute_rl(expr);
+ }
+ return true;
}
- if (implied == RL_EXACT)
- return NULL;
-
- if (get_mtag_sval(expr, &sval))
- return alloc_rl(sval, sval);
+ if (get_mtag_sval(expr, &sval)) {
+ *res_sval = sval;
+ return true;
+ }
type = get_type(expr);
- if (type && type->type == SYM_FN)
- return alloc_rl(fn_ptr_min, fn_ptr_max);
+ if (type &&
+ (type->type == SYM_ARRAY ||
+ type->type == SYM_FN))
+ return handle_address(expr, implied, recurse_cnt, res, res_sval);
+
+ /* FIXME: call rl_to_sval() on the results */
switch (implied) {
case RL_HARD:
case RL_IMPLIED:
case RL_ABSOLUTE:
state = get_extra_state(expr);
- if (!state || !state->data) {
+ if (!state) {
if (implied == RL_HARD)
- return NULL;
- if (get_local_rl(expr, &rl))
- return rl;
- if (get_mtag_rl(expr, &rl))
- return rl;
- if (get_db_type_rl(expr, &rl))
- return rl;
- if (is_array(expr) && get_array_rl(expr, &rl))
- return rl;
- return NULL;
+ return false;
+ if (get_local_rl(expr, res))
+ return true;
+ if (get_mtag_rl(expr, res))
+ return true;
+ if (get_db_type_rl(expr, res))
+ return true;
+ if (is_array(expr) && get_array_rl(expr, res))
+ return true;
+ return false;
}
if (implied == RL_HARD && !estate_has_hard_max(state))
- return NULL;
- return clone_rl(estate_rl(state));
+ return false;
+ *res = clone_rl(estate_rl(state));
+ return true;
case RL_REAL_ABSOLUTE: {
struct smatch_state *abs_state;
@@ -928,10 +1029,12 @@ static struct range_list *handle_variable(struct expression *expr, int implied,
abs_state = get_real_absolute_state(expr);
if (estate_rl(state) && estate_rl(abs_state)) {
- return clone_rl(rl_intersection(estate_rl(state),
+ *res = clone_rl(rl_intersection(estate_rl(state),
estate_rl(abs_state)));
+ return true;
} else if (estate_rl(state)) {
- return clone_rl(estate_rl(state));
+ *res = clone_rl(estate_rl(state));
+ return true;
} else if (estate_is_empty(state)) {
/*
* FIXME: we don't handle empty extra states correctly.
@@ -951,35 +1054,37 @@ static struct range_list *handle_variable(struct expression *expr, int implied,
* get_real_absolute_rl().
*
*/
- return NULL;
+ return false;
} else if (estate_rl(abs_state)) {
- return clone_rl(estate_rl(abs_state));
+ *res = clone_rl(estate_rl(abs_state));
+ return true;
}
- if (get_local_rl(expr, &rl))
- return rl;
- if (get_mtag_rl(expr, &rl))
- return rl;
- if (get_db_type_rl(expr, &rl))
- return rl;
- if (is_array(expr) && get_array_rl(expr, &rl))
- return rl;
- return NULL;
+ if (get_local_rl(expr, res))
+ return true;
+ if (get_mtag_rl(expr, res))
+ return true;
+ if (get_db_type_rl(expr, res))
+ return true;
+ if (is_array(expr) && get_array_rl(expr, res))
+ return true;
+ return false;
}
case RL_FUZZY:
if (!get_fuzzy_min_helper(expr, &min))
min = sval_type_min(get_type(expr));
if (!get_fuzzy_max_helper(expr, &max))
- return NULL;
+ return false;
/* fuzzy ranges are often inverted */
if (sval_cmp(min, max) > 0) {
sval = min;
min = max;
max = sval;
}
- return alloc_rl(min, max);
+ *res = alloc_rl(min, max);
+ return true;
}
- return NULL;
+ return false;
}
static sval_t handle_sizeof(struct expression *expr)
@@ -1026,52 +1131,55 @@ static sval_t handle_sizeof(struct expression *expr)
return ret;
}
-static struct range_list *handle_strlen(struct expression *expr, int implied, int *recurse_cnt)
+static bool handle_strlen(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval)
{
- struct range_list *rl;
struct expression *arg, *tmp;
sval_t tag;
sval_t ret = { .type = &ulong_ctype };
-
- if (implied == RL_EXACT)
- return NULL;
+ struct range_list *rl;
arg = get_argument_from_call_expr(expr->args, 0);
if (!arg)
- return NULL;
+ return false;
if (arg->type == EXPR_STRING) {
ret.value = arg->string->length - 1;
- return alloc_rl(ret, ret);
+ *res_sval = ret;
+ return true;
}
+ if (implied == RL_EXACT)
+ return false;
if (get_implied_value(arg, &tag) &&
(tmp = fake_string_from_mtag(tag.uvalue))) {
ret.value = tmp->string->length - 1;
- return alloc_rl(ret, ret);
+ *res_sval = ret;
+ return true;
}
if (implied == RL_HARD || implied == RL_FUZZY)
- return NULL;
+ return false;
- if (get_implied_return(expr, &rl))
- return rl;
+ if (get_implied_return(expr, &rl)) {
+ *res = rl;
+ return true;
+ }
- return NULL;
+ return false;
}
-static struct range_list *handle_builtin_constant_p(struct expression *expr, int implied, int *recurse_cnt)
+static bool handle_builtin_constant_p(struct expression *expr, int implied, int *recurse_cnt, sval_t *res_sval)
{
struct expression *arg;
struct range_list *rl;
- sval_t sval;
arg = get_argument_from_call_expr(expr->args, 0);
- rl = _get_rl(arg, RL_EXACT, recurse_cnt);
- if (rl_to_sval(rl, &sval))
- return rl_one();
- return rl_zero();
+ if (get_rl_internal(arg, RL_EXACT, recurse_cnt, &rl))
+ *res_sval = one;
+ else
+ *res_sval = zero;
+ return true;
}
-static struct range_list *handle__builtin_choose_expr(struct expression *expr, int implied, int *recurse_cnt)
+static bool handle__builtin_choose_expr(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval)
{
struct expression *const_expr, *expr1, *expr2;
sval_t sval;
@@ -1081,21 +1189,22 @@ static struct range_list *handle__builtin_choose_expr(struct expression *expr, i
expr2 = get_argument_from_call_expr(expr->args, 2);
if (!get_value(const_expr, &sval) || !expr1 || !expr2)
- return NULL;
+ return false;
if (sval.value)
- return _get_rl(expr1, implied, recurse_cnt);
- return _get_rl(expr2, implied, recurse_cnt);
+ return get_rl_sval(expr1, implied, recurse_cnt, res, res_sval);
+ else
+ return get_rl_sval(expr2, implied, recurse_cnt, res, res_sval);
}
-static struct range_list *handle_call_rl(struct expression *expr, int implied, int *recurse_cnt)
+static bool handle_call_rl(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval)
{
struct range_list *rl;
if (sym_name_is("__builtin_constant_p", expr->fn))
- return handle_builtin_constant_p(expr, implied, recurse_cnt);
+ return handle_builtin_constant_p(expr, implied, recurse_cnt, res_sval);
if (sym_name_is("__builtin_choose_expr", expr->fn))
- return handle__builtin_choose_expr(expr, implied, recurse_cnt);
+ return handle__builtin_choose_expr(expr, implied, recurse_cnt, res, res_sval);
if (sym_name_is("__builtin_expect", expr->fn) ||
sym_name_is("__builtin_bswap16", expr->fn) ||
@@ -1104,121 +1213,301 @@ static struct range_list *handle_call_rl(struct expression *expr, int implied, i
struct expression *arg;
arg = get_argument_from_call_expr(expr->args, 0);
- return _get_rl(arg, implied, recurse_cnt);
+ return get_rl_sval(arg, implied, recurse_cnt, res, res_sval);
}
if (sym_name_is("strlen", expr->fn))
- return handle_strlen(expr, implied, recurse_cnt);
+ return handle_strlen(expr, implied, recurse_cnt, res, res_sval);
if (implied == RL_EXACT || implied == RL_HARD || implied == RL_FUZZY)
- return NULL;
+ return false;
if (custom_handle_variable) {
rl = custom_handle_variable(expr);
- if (rl)
- return rl;
+ if (rl) {
+ *res = rl;
+ return true;
+ }
}
- if (get_implied_return(expr, &rl))
- return rl;
- return db_return_vals(expr);
+ /* Ugh... get_implied_return() sets *rl to NULL on failure */
+ if (get_implied_return(expr, &rl)) {
+ *res = rl;
+ return true;
+ }
+ rl = db_return_vals(expr);
+ if (rl) {
+ *res = rl;
+ return true;
+ }
+ return false;
}
-static struct range_list *handle_cast(struct expression *expr, int implied, int *recurse_cnt)
+static bool handle_cast(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval)
{
struct range_list *rl;
struct symbol *type;
+ sval_t sval = {};
type = get_type(expr);
- rl = _get_rl(expr->cast_expression, implied, recurse_cnt);
- if (rl)
- return cast_rl(type, rl);
- if (implied == RL_ABSOLUTE || implied == RL_REAL_ABSOLUTE)
- return alloc_whole_rl(type);
+ if (get_rl_sval(expr->cast_expression, implied, recurse_cnt, &rl, &sval)) {
+ if (sval.type)
+ *res_sval = sval_cast(type, sval);
+ else
+ *res = cast_rl(type, rl);
+ return true;
+ }
+ if (implied == RL_ABSOLUTE || implied == RL_REAL_ABSOLUTE) {
+ *res = alloc_whole_rl(type);
+ return true;
+ }
if (implied == RL_IMPLIED && type &&
- type_bits(type) > 0 && type_bits(type) < 32)
- return alloc_whole_rl(type);
- return NULL;
+ type_bits(type) > 0 && type_bits(type) < 32) {
+ *res = alloc_whole_rl(type);
+ return true;
+ }
+ return false;
}
-static struct range_list *_get_rl(struct expression *expr, int implied, int *recurse_cnt)
+static bool get_offset_from_down(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval)
{
+ struct expression *index;
+ struct symbol *type = expr->in;
struct range_list *rl;
+ struct symbol *field;
+ int offset = 0;
+ sval_t sval = { .type = ssize_t_ctype };
+ sval_t tmp_sval = {};
+
+ /*
+ * FIXME: I don't really know what I'm doing here. I wish that I
+ * could just get rid of the __builtin_offset() function and use:
+ * "&((struct bpf_prog *)NULL)->insns[fprog->len]" instead...
+ * Anyway, I have done the minimum ammount of work to get that
+ * expression to work.
+ *
+ */
+
+ if (expr->op != '.' || !expr->down ||
+ expr->down->type != EXPR_OFFSETOF ||
+ expr->down->op != '[' ||
+ !expr->down->index)
+ return false;
+
+ index = expr->down->index;
+
+ examine_symbol_type(type);
+ type = get_real_base_type(type);
+ if (!type)
+ return false;
+ field = find_identifier(expr->ident, type->symbol_list, &offset);
+ if (!field)
+ return false;
+
+ type = get_real_base_type(field);
+ if (!type || type->type != SYM_ARRAY)
+ return false;
+ type = get_real_base_type(type);
+
+ if (get_implied_value_internal(index, recurse_cnt, &sval)) {
+ res_sval->type = ssize_t_ctype;
+ res_sval->value = offset + sval.value * type_bytes(type);
+ return true;
+ }
+
+ if (!get_rl_sval(index, implied, recurse_cnt, &rl, &tmp_sval))
+ return false;
+
+ /*
+ * I'm not sure why get_rl_sval() would return an sval when
+ * get_implied_value_internal() failed but it does when I
+ * parse drivers/net/ethernet/mellanox/mlx5/core/en/monitor_stats.c
+ *
+ */
+ if (tmp_sval.type) {
+ res_sval->type = ssize_t_ctype;
+ res_sval->value = offset + sval.value * type_bytes(type);
+ return true;
+ }
+
+ sval.value = type_bytes(type);
+ rl = rl_binop(rl, '*', alloc_rl(sval, sval));
+ sval.value = offset;
+ *res = rl_binop(rl, '+', alloc_rl(sval, sval));
+ return true;
+}
+
+static bool get_offset_from_in(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval)
+{
+ struct symbol *type = get_real_base_type(expr->in);
+ struct symbol *field;
+ int offset = 0;
+
+ if (expr->op != '.' || !type || !expr->ident)
+ return false;
+
+ field = find_identifier(expr->ident, type->symbol_list, &offset);
+ if (!field)
+ return false;
+
+ res_sval->type = size_t_ctype;
+ res_sval->value = offset;
+
+ return true;
+}
+
+static bool handle_offsetof_rl(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *res_sval)
+{
+ if (get_offset_from_down(expr, implied, recurse_cnt, res, res_sval))
+ return true;
+
+ if (get_offset_from_in(expr, implied, recurse_cnt, res, res_sval))
+ return true;
+
+ evaluate_expression(expr);
+ if (expr->type == EXPR_VALUE) {
+ *res_sval = sval_from_val(expr, expr->value);
+ return true;
+ }
+ return false;
+}
+
+static bool get_rl_sval(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res, sval_t *sval_res)
+{
+ struct range_list *rl = (void *)-1UL;
struct symbol *type;
- sval_t sval;
+ sval_t sval = {};
type = get_type(expr);
expr = strip_parens(expr);
if (!expr)
- return NULL;
+ return false;
if (++(*recurse_cnt) >= 200)
- return NULL;
+ return false;
switch(expr->type) {
case EXPR_CAST:
case EXPR_FORCE_CAST:
case EXPR_IMPLIED_CAST:
- rl = handle_cast(expr, implied, recurse_cnt);
+ handle_cast(expr, implied, recurse_cnt, &rl, &sval);
goto out_cast;
}
expr = strip_expr(expr);
if (!expr)
- return NULL;
+ return false;
switch (expr->type) {
case EXPR_VALUE:
sval = sval_from_val(expr, expr->value);
- rl = alloc_rl(sval, sval);
break;
case EXPR_PREOP:
- rl = handle_preop_rl(expr, implied, recurse_cnt);
+ handle_preop_rl(expr, implied, recurse_cnt, &rl, &sval);
break;
case EXPR_POSTOP:
- rl = _get_rl(expr->unop, implied, recurse_cnt);
+ get_rl_sval(expr->unop, implied, recurse_cnt, &rl, &sval);
break;
case EXPR_BINOP:
- rl = handle_binop_rl(expr, implied, recurse_cnt);
+ handle_binop_rl(expr, implied, recurse_cnt, &rl, &sval);
break;
case EXPR_COMPARE:
- rl = handle_comparison_rl(expr, implied, recurse_cnt);
+ handle_comparison_rl(expr, implied, recurse_cnt, &rl, &sval);
break;
case EXPR_LOGICAL:
- rl = handle_logical_rl(expr, implied, recurse_cnt);
+ handle_logical_rl(expr, implied, recurse_cnt, &rl, &sval);
break;
case EXPR_PTRSIZEOF:
case EXPR_SIZEOF:
sval = handle_sizeof(expr);
- rl = alloc_rl(sval, sval);
break;
case EXPR_SELECT:
case EXPR_CONDITIONAL:
- rl = handle_conditional_rl(expr, implied, recurse_cnt);
+ handle_conditional_rl(expr, implied, recurse_cnt, &rl, &sval);
break;
case EXPR_CALL:
- rl = handle_call_rl(expr, implied, recurse_cnt);
+ handle_call_rl(expr, implied, recurse_cnt, &rl, &sval);
break;
case EXPR_STRING:
- rl = NULL;
if (get_mtag_sval(expr, &sval))
- rl = alloc_rl(sval, sval);
+ break;
+ if (implied == RL_EXACT)
+ break;
+ rl = alloc_rl(valid_ptr_min_sval, valid_ptr_max_sval);
+ break;
+ case EXPR_OFFSETOF:
+ handle_offsetof_rl(expr, implied, recurse_cnt, &rl, &sval);
+ break;
+ case EXPR_ALIGNOF:
+ evaluate_expression(expr);
+ if (expr->type == EXPR_VALUE)
+ sval = sval_from_val(expr, expr->value);
break;
default:
- rl = handle_variable(expr, implied, recurse_cnt);
+ handle_variable(expr, implied, recurse_cnt, &rl, &sval);
}
out_cast:
- if (rl)
- return rl;
- if (type && (implied == RL_ABSOLUTE || implied == RL_REAL_ABSOLUTE))
- return alloc_whole_rl(type);
- return NULL;
+ if (rl == (void *)-1UL)
+ rl = NULL;
+
+ if (sval.type || (rl && rl_to_sval(rl, &sval))) {
+ *sval_res = sval;
+ return true;
+ }
+ if (implied == RL_EXACT)
+ return false;
+
+ if (rl) {
+ *res = rl;
+ return true;
+ }
+ if (type && (implied == RL_ABSOLUTE || implied == RL_REAL_ABSOLUTE)) {
+ *res = alloc_whole_rl(type);
+ return true;
+ }
+ return false;
+}
+
+static bool get_rl_internal(struct expression *expr, int implied, int *recurse_cnt, struct range_list **res)
+{
+ struct range_list *rl = NULL;
+ sval_t sval = {};
+
+ if (!get_rl_sval(expr, implied, recurse_cnt, &rl, &sval))
+ return false;
+
+ if (sval.type)
+ *res = alloc_rl(sval, sval);
+ else
+ *res = rl;
+ return true;
+}
+
+static bool get_rl_helper(struct expression *expr, int implied, struct range_list **res)
+{
+ struct range_list *rl = NULL;
+ sval_t sval = {};
+ int recurse_cnt = 0;
+
+ if (get_value(expr, &sval)) {
+ *res = alloc_rl(sval, sval);
+ return true;
+ }
+
+ if (!get_rl_sval(expr, implied, &recurse_cnt, &rl, &sval))
+ return false;
+
+ if (sval.type)
+ *res = alloc_rl(sval, sval);
+ else
+ *res = rl;
+ return true;
}
struct {
struct expression *expr;
- struct range_list *rl;
+ sval_t sval;
} cached_results[24];
static int cache_idx;
@@ -1227,59 +1516,83 @@ void clear_math_cache(void)
memset(cached_results, 0, sizeof(cached_results));
}
+/*
+ * Don't cache EXPR_VALUE because values are fast already.
+ *
+ */
+static bool get_value_literal(struct expression *expr, sval_t *res_sval)
+{
+ struct expression *tmp;
+ int recurse_cnt = 0;
+
+ tmp = strip_expr(expr);
+ if (!tmp || tmp->type != EXPR_VALUE)
+ return false;
+
+ return get_rl_sval(expr, RL_EXACT, &recurse_cnt, NULL, res_sval);
+}
+
/* returns 1 if it can get a value literal or else returns 0 */
-int get_value(struct expression *expr, sval_t *sval)
+int get_value(struct expression *expr, sval_t *res_sval)
{
struct range_list *(*orig_custom_fn)(struct expression *expr);
- struct range_list *rl;
int recurse_cnt = 0;
- sval_t tmp;
+ sval_t sval = {};
int i;
+ if (get_value_literal(expr, res_sval))
+ return 1;
+
/*
* This only handles RL_EXACT because other expr statements can be
* different at different points. Like the list iterator, for example.
*/
for (i = 0; i < ARRAY_SIZE(cached_results); i++) {
- if (expr == cached_results[i].expr)
- return rl_to_sval(cached_results[i].rl, sval);
+ if (expr == cached_results[i].expr) {
+ if (cached_results[i].sval.type) {
+ *res_sval = cached_results[i].sval;
+ return true;
+ }
+ return false;
+ }
}
orig_custom_fn = custom_handle_variable;
custom_handle_variable = NULL;
- rl = _get_rl(expr, RL_EXACT, &recurse_cnt);
- if (!rl_to_sval(rl, &tmp))
- rl = NULL;
+ get_rl_sval(expr, RL_EXACT, &recurse_cnt, NULL, &sval);
+
custom_handle_variable = orig_custom_fn;
cached_results[cache_idx].expr = expr;
- cached_results[cache_idx].rl = rl;
+ cached_results[cache_idx].sval = sval;
cache_idx = (cache_idx + 1) % ARRAY_SIZE(cached_results);
- if (!rl)
+ if (!sval.type)
return 0;
- *sval = tmp;
+ *res_sval = sval;
return 1;
}
-static int get_implied_value_internal(struct expression *expr, sval_t *sval, int *recurse_cnt)
+static bool get_implied_value_internal(struct expression *expr, int *recurse_cnt, sval_t *res_sval)
{
struct range_list *rl;
- rl = _get_rl(expr, RL_IMPLIED, recurse_cnt);
- if (!rl_to_sval(rl, sval))
- return 0;
- return 1;
+ res_sval->type = NULL;
+
+ if (!get_rl_sval(expr, RL_IMPLIED, recurse_cnt, &rl, res_sval))
+ return false;
+ if (!res_sval->type && !rl_to_sval(rl, res_sval))
+ return false;
+ return true;
}
int get_implied_value(struct expression *expr, sval_t *sval)
{
struct range_list *rl;
- int recurse_cnt = 0;
- rl = _get_rl(expr, RL_IMPLIED, &recurse_cnt);
- if (!rl_to_sval(rl, sval))
+ if (!get_rl_helper(expr, RL_IMPLIED, &rl) ||
+ !rl_to_sval(rl, sval))
return 0;
return 1;
}
@@ -1287,10 +1600,8 @@ int get_implied_value(struct expression *expr, sval_t *sval)
int get_implied_min(struct expression *expr, sval_t *sval)
{
struct range_list *rl;
- int recurse_cnt = 0;
- rl = _get_rl(expr, RL_IMPLIED, &recurse_cnt);
- if (!rl)
+ if (!get_rl_helper(expr, RL_IMPLIED, &rl) || !rl)
return 0;
*sval = rl_min(rl);
return 1;
@@ -1299,10 +1610,8 @@ int get_implied_min(struct expression *expr, sval_t *sval)
int get_implied_max(struct expression *expr, sval_t *sval)
{
struct range_list *rl;
- int recurse_cnt = 0;
- rl = _get_rl(expr, RL_IMPLIED, &recurse_cnt);
- if (!rl)
+ if (!get_rl_helper(expr, RL_IMPLIED, &rl) || !rl)
return 0;
*sval = rl_max(rl);
return 1;
@@ -1310,17 +1619,15 @@ int get_implied_max(struct expression *expr, sval_t *sval)
int get_implied_rl(struct expression *expr, struct range_list **rl)
{
- int recurse_cnt = 0;
-
- *rl = _get_rl(expr, RL_IMPLIED, &recurse_cnt);
- if (*rl)
- return 1;
- return 0;
+ if (!get_rl_helper(expr, RL_IMPLIED, rl) || !*rl)
+ return 0;
+ return 1;
}
static int get_absolute_rl_internal(struct expression *expr, struct range_list **rl, int *recurse_cnt)
{
- *rl = _get_rl(expr, RL_ABSOLUTE, recurse_cnt);
+ *rl = NULL;
+ get_rl_internal(expr, RL_ABSOLUTE, recurse_cnt, rl);
if (!*rl)
*rl = alloc_whole_rl(get_type(expr));
return 1;
@@ -1328,9 +1635,8 @@ static int get_absolute_rl_internal(struct expression *expr, struct range_list *
int get_absolute_rl(struct expression *expr, struct range_list **rl)
{
- int recurse_cnt = 0;
-
- *rl = _get_rl(expr, RL_ABSOLUTE, &recurse_cnt);
+ *rl = NULL;
+ get_rl_helper(expr, RL_ABSOLUTE, rl);
if (!*rl)
*rl = alloc_whole_rl(get_type(expr));
return 1;
@@ -1338,9 +1644,8 @@ int get_absolute_rl(struct expression *expr, struct range_list **rl)
int get_real_absolute_rl(struct expression *expr, struct range_list **rl)
{
- int recurse_cnt = 0;
-
- *rl = _get_rl(expr, RL_REAL_ABSOLUTE, &recurse_cnt);
+ *rl = NULL;
+ get_rl_helper(expr, RL_REAL_ABSOLUTE, rl);
if (!*rl)
*rl = alloc_whole_rl(get_type(expr));
return 1;
@@ -1350,13 +1655,13 @@ int custom_get_absolute_rl(struct expression *expr,
struct range_list *(*fn)(struct expression *expr),
struct range_list **rl)
{
- int recurse_cnt = 0;
+ int ret;
*rl = NULL;
custom_handle_variable = fn;
- *rl = _get_rl(expr, RL_REAL_ABSOLUTE, &recurse_cnt);
+ ret = get_rl_helper(expr, RL_REAL_ABSOLUTE, rl);
custom_handle_variable = NULL;
- return 1;
+ return ret;
}
int get_implied_rl_var_sym(const char *var, struct symbol *sym, struct range_list **rl)
@@ -1373,10 +1678,8 @@ int get_implied_rl_var_sym(const char *var, struct symbol *sym, struct range_lis
int get_hard_max(struct expression *expr, sval_t *sval)
{
struct range_list *rl;
- int recurse_cnt = 0;
- rl = _get_rl(expr, RL_HARD, &recurse_cnt);
- if (!rl)
+ if (!get_rl_helper(expr, RL_HARD, &rl) || !rl)
return 0;
*sval = rl_max(rl);
return 1;
@@ -1386,10 +1689,8 @@ int get_fuzzy_min(struct expression *expr, sval_t *sval)
{
struct range_list *rl;
sval_t tmp;
- int recurse_cnt = 0;
- rl = _get_rl(expr, RL_FUZZY, &recurse_cnt);
- if (!rl)
+ if (!get_rl_helper(expr, RL_FUZZY, &rl) || !rl)
return 0;
tmp = rl_min(rl);
if (sval_is_negative(tmp) && sval_is_min(tmp))
@@ -1402,10 +1703,8 @@ int get_fuzzy_max(struct expression *expr, sval_t *sval)
{
struct range_list *rl;
sval_t max;
- int recurse_cnt = 0;
- rl = _get_rl(expr, RL_FUZZY, &recurse_cnt);
- if (!rl)
+ if (!get_rl_helper(expr, RL_FUZZY, &rl) || !rl)
return 0;
max = rl_max(rl);
if (max.uvalue > INT_MAX - 10000)
@@ -1418,12 +1717,12 @@ int get_absolute_min(struct expression *expr, sval_t *sval)
{
struct range_list *rl;
struct symbol *type;
- int recurse_cnt = 0;
type = get_type(expr);
if (!type)
type = &llong_ctype; // FIXME: this is wrong but places assume get type can't fail.
- rl = _get_rl(expr, RL_REAL_ABSOLUTE, &recurse_cnt);
+ rl = NULL;
+ get_rl_helper(expr, RL_REAL_ABSOLUTE, &rl);
if (rl)
*sval = rl_min(rl);
else
@@ -1438,12 +1737,12 @@ int get_absolute_max(struct expression *expr, sval_t *sval)
{
struct range_list *rl;
struct symbol *type;
- int recurse_cnt = 0;
type = get_type(expr);
if (!type)
type = &llong_ctype;
- rl = _get_rl(expr, RL_REAL_ABSOLUTE, &recurse_cnt);
+ rl = NULL;
+ get_rl_helper(expr, RL_REAL_ABSOLUTE, &rl);
if (rl)
*sval = rl_max(rl);
else
@@ -1552,46 +1851,4 @@ int implied_condition_false(struct expression *expr)
return 0;
}
-int can_integer_overflow(struct symbol *type, struct expression *expr)
-{
- int op;
- sval_t lmax, rmax, res;
-
- if (!type)
- type = &int_ctype;
-
- expr = strip_expr(expr);
-
- if (expr->type == EXPR_ASSIGNMENT) {
- switch(expr->op) {
- case SPECIAL_MUL_ASSIGN:
- op = '*';
- break;
- case SPECIAL_ADD_ASSIGN:
- op = '+';
- break;
- case SPECIAL_SHL_ASSIGN:
- op = SPECIAL_LEFTSHIFT;
- break;
- default:
- return 0;
- }
- } else if (expr->type == EXPR_BINOP) {
- if (expr->op != '*' && expr->op != '+' && expr->op != SPECIAL_LEFTSHIFT)
- return 0;
- op = expr->op;
- } else {
- return 0;
- }
-
- get_absolute_max(expr->left, &lmax);
- get_absolute_max(expr->right, &rmax);
- if (sval_binop_overflows(lmax, op, rmax))
- return 1;
-
- res = sval_binop(lmax, op, rmax);
- if (sval_cmp(res, sval_type_max(type)) > 0)
- return 1;
- return 0;
-}
diff --git a/usr/src/tools/smatch/src/smatch_mem_tracker.c b/usr/src/tools/smatch/src/smatch_mem_tracker.c
index 31081139f1..c10ee90587 100644
--- a/usr/src/tools/smatch/src/smatch_mem_tracker.c
+++ b/usr/src/tools/smatch/src/smatch_mem_tracker.c
@@ -22,7 +22,7 @@ static int my_id;
static unsigned long max_size;
-static void match_end_func(struct symbol *sym)
+unsigned long get_mem_kb(void)
{
FILE *file;
char buf[1024];
@@ -30,14 +30,24 @@ static void match_end_func(struct symbol *sym)
file = fopen("/proc/self/statm", "r");
if (!file)
- return;
+ return 0;
fread(buf, 1, sizeof(buf), file);
fclose(file);
size = strtoul(buf, NULL, 10);
size = size * sysconf(_SC_PAGESIZE) / 1024;
- if (size > max_size)
- max_size = size;
+ return size;
+}
+
+static void match_end_func(struct symbol *sym)
+{
+ unsigned long size;
+
+ if (option_mem) {
+ size = get_mem_kb();
+ if (size > max_size)
+ max_size = size;
+ }
}
unsigned long get_max_memory(void)
diff --git a/usr/src/tools/smatch/src/smatch_modification_hooks.c b/usr/src/tools/smatch/src/smatch_modification_hooks.c
index b4f9e62fe3..07a32cdfbc 100644
--- a/usr/src/tools/smatch/src/smatch_modification_hooks.c
+++ b/usr/src/tools/smatch/src/smatch_modification_hooks.c
@@ -52,9 +52,12 @@ static struct smatch_state *alloc_my_state(struct expression *expr, struct smatc
struct modification_data *data;
char *name;
- state = __alloc_smatch_state(0);
expr = strip_expr(expr);
name = expr_to_str(expr);
+ if (!name)
+ return NULL;
+
+ state = __alloc_smatch_state(0);
state->name = alloc_sname(name);
free_string(name);
@@ -178,7 +181,7 @@ static void db_param_add(struct expression *expr, int param, char *key, char *va
call_modification_hooks_name_sym(name, sym, expr, BOTH);
__in_fake_assign--;
- other_name = map_long_to_short_name_sym(name, sym, &other_sym);
+ other_name = get_other_name_sym(name, sym, &other_sym);
if (other_name) {
__in_fake_assign++;
call_modification_hooks_name_sym(other_name, other_sym, expr, BOTH);
@@ -279,6 +282,8 @@ void register_modification_hooks(int id)
{
my_id = id;
+ set_dynamic_states(my_id);
+
hooks = malloc((num_checks + 1) * sizeof(*hooks));
memset(hooks, 0, (num_checks + 1) * sizeof(*hooks));
hooks_late = malloc((num_checks + 1) * sizeof(*hooks));
diff --git a/usr/src/tools/smatch/src/smatch_mtag.c b/usr/src/tools/smatch/src/smatch_mtag.c
index c499c8f923..b30e51bc2d 100644
--- a/usr/src/tools/smatch/src/smatch_mtag.c
+++ b/usr/src/tools/smatch/src/smatch_mtag.c
@@ -50,20 +50,6 @@
static int my_id;
-static struct smatch_state *alloc_tag_state(mtag_t tag)
-{
- struct smatch_state *state;
- char buf[64];
-
- state = __alloc_smatch_state(0);
- snprintf(buf, sizeof(buf), "%lld", tag);
- state->name = alloc_sname(buf);
- state->data = malloc(sizeof(mtag_t));
- *(mtag_t *)state->data = tag;
-
- return state;
-}
-
static mtag_t str_to_tag(const char *str)
{
unsigned char c[MD5_DIGEST_LENGTH];
@@ -82,40 +68,84 @@ static mtag_t str_to_tag(const char *str)
return *tag;
}
-static void alloc_assign(const char *fn, struct expression *expr, void *unused)
+const struct {
+ const char *name;
+ int size_arg;
+} allocator_info[] = {
+ { "kmalloc", 0 },
+ { "kzalloc", 0 },
+ { "devm_kmalloc", 1},
+ { "devm_kzalloc", 1},
+};
+
+static bool is_mtag_call(struct expression *expr)
+{
+ struct expression *arg;
+ int i;
+ sval_t sval;
+
+ if (expr->type != EXPR_CALL ||
+ expr->fn->type != EXPR_SYMBOL ||
+ !expr->fn->symbol)
+ return false;
+
+ for (i = 0; i < ARRAY_SIZE(allocator_info); i++) {
+ if (strcmp(expr->fn->symbol->ident->name, allocator_info[i].name) == 0)
+ break;
+ }
+ if (i == ARRAY_SIZE(allocator_info))
+ return false;
+
+ arg = get_argument_from_call_expr(expr->args, allocator_info[i].size_arg);
+ if (!get_implied_value(arg, &sval))
+ return false;
+
+ return true;
+}
+
+struct smatch_state *swap_mtag_return(struct expression *expr, struct smatch_state *state)
{
struct expression *left, *right;
char *left_name, *right_name;
struct symbol *left_sym;
+ struct range_list *rl;
char buf[256];
mtag_t tag;
+ sval_t tag_sval;
+ if (!expr || expr->type != EXPR_ASSIGNMENT || expr->op != '=')
+ return state;
- // FIXME: This should only happen when the size is not a paramter of
- // the caller
- return;
+ if (!estate_rl(state) || strcmp(state->name, "0,4096-ptr_max") != 0)
+ return state;
- if (expr->type != EXPR_ASSIGNMENT || expr->op != '=')
- return;
left = strip_expr(expr->left);
right = strip_expr(expr->right);
- if (right->type != EXPR_CALL || right->fn->type != EXPR_SYMBOL)
- return;
+
+ if (!is_mtag_call(right))
+ return state;
left_name = expr_to_str_sym(left, &left_sym);
+ if (!left_name || !left_sym)
+ return state;
right_name = expr_to_str(right);
snprintf(buf, sizeof(buf), "%s %s %s %s", get_filename(), get_function(),
left_name, right_name);
tag = str_to_tag(buf);
+ tag_sval.type = estate_type(state);
+ tag_sval.uvalue = tag;
- sql_insert_mtag_about(tag, left_name, right_name);
+ rl = rl_filter(estate_rl(state), valid_ptr_rl);
+ rl = clone_rl(rl);
+ add_range(&rl, tag_sval, tag_sval);
- if (left_name && left_sym)
- set_state(my_id, left_name, left_sym, alloc_tag_state(tag));
+ sql_insert_mtag_about(tag, left_name, buf);
free_string(left_name);
free_string(right_name);
+
+ return alloc_estate_rl(rl);
}
int get_string_mtag(struct expression *expr, mtag_t *tag)
@@ -151,31 +181,23 @@ int get_toplevel_mtag(struct symbol *sym, mtag_t *tag)
return 1;
}
-int get_deref_mtag(struct expression *expr, mtag_t *tag)
+bool get_symbol_mtag(struct symbol *sym, mtag_t *tag)
{
- mtag_t container_tag, member_tag;
- int offset;
-
- /*
- * I'm not totally sure what I'm doing...
- *
- * This is supposed to get something like "global_var->ptr", but I don't
- * feel like it's complete at all.
- *
- */
+ char buf[256];
- if (!get_mtag(expr->unop, &container_tag))
- return 0;
+ if (!sym || !sym->ident)
+ return false;
- offset = get_member_offset_from_deref(expr);
- if (offset < 0)
- return 0;
+ if (get_toplevel_mtag(sym, tag))
+ return true;
- if (!mtag_map_select_tag(container_tag, -offset, &member_tag))
- return 0;
+ if (get_param_num_from_sym(sym) >= 0)
+ return false;
- *tag = member_tag;
- return 1;
+ snprintf(buf, sizeof(buf), "%s %s %s",
+ get_filename(), get_function(), sym->ident->name);
+ *tag = str_to_tag(buf);
+ return true;
}
static void global_variable(struct symbol *sym)
@@ -190,87 +212,12 @@ static void global_variable(struct symbol *sym)
(sym->ctype.modifiers & MOD_STATIC) ? get_filename() : "extern");
}
-static void db_returns_buf_size(struct expression *expr, int param, char *unused, char *math)
-{
- struct expression *call;
- struct range_list *rl;
-
- if (expr->type != EXPR_ASSIGNMENT)
- return;
- call = strip_expr(expr->right);
-
- if (!parse_call_math_rl(call, math, &rl))
- return;
-// rl = cast_rl(&int_ctype, rl);
-// set_state_expr(my_size_id, expr->left, alloc_estate_rl(rl));
-}
-
-static void db_returns_memory_tag(struct expression *expr, int param, char *key, char *value)
-{
- struct expression *call, *arg;
- mtag_t tag, alias;
- char *name;
- struct symbol *sym;
-
- call = strip_expr(expr);
- while (call->type == EXPR_ASSIGNMENT)
- call = strip_expr(call->right);
- if (call->type != EXPR_CALL)
- return;
-
- tag = strtoul(value, NULL, 10);
-
- if (!create_mtag_alias(tag, call, &alias))
- return;
-
- arg = get_argument_from_call_expr(call->args, param);
- if (!arg)
- return;
-
- name = get_variable_from_key(arg, key, &sym);
- if (!name || !sym)
- goto free;
-
- set_state(my_id, name, sym, alloc_tag_state(alias));
-free:
- free_string(name);
-}
-
-static void match_call_info(struct expression *expr)
-{
- struct smatch_state *state;
- struct expression *arg;
- int i = -1;
-
- FOR_EACH_PTR(expr->args, arg) {
- i++;
- state = get_state_expr(my_id, arg);
- if (!state || !state->data)
- continue;
- sql_insert_caller_info(expr, MEMORY_TAG, i, "$", state->name);
- } END_FOR_EACH_PTR(arg);
-}
-
-static void save_caller_info(const char *name, struct symbol *sym, char *key, char *value)
-{
- struct smatch_state *state;
- char fullname[256];
- mtag_t tag;
-
- if (strncmp(key, "$", 1) != 0)
- return;
-
- tag = atoll(value);
- snprintf(fullname, 256, "%s%s", name, key + 1);
- state = alloc_tag_state(tag);
- set_state(my_id, fullname, sym, state);
-}
-
static int get_array_mtag_offset(struct expression *expr, mtag_t *tag, int *offset)
{
struct expression *array, *offset_expr;
struct symbol *type;
sval_t sval;
+ int start_offset;
if (!is_array(expr))
return 0;
@@ -285,107 +232,35 @@ static int get_array_mtag_offset(struct expression *expr, mtag_t *tag, int *offs
if (!type_bytes(type))
return 0;
- if (!get_mtag(array, tag))
+ if (!expr_to_mtag_offset(array, tag, &start_offset))
return 0;
offset_expr = get_array_offset(expr);
if (!get_value(offset_expr, &sval))
return 0;
- *offset = sval.value * type_bytes(type);
+ *offset = start_offset + sval.value * type_bytes(type);
return 1;
}
-static int get_implied_mtag_offset(struct expression *expr, mtag_t *tag, int *offset)
+struct range_list *swap_mtag_seed(struct expression *expr, struct range_list *rl)
{
- struct smatch_state *state;
- struct symbol *type;
+ char buf[256];
+ char *name;
sval_t sval;
+ mtag_t tag;
- type = get_type(expr);
- if (!type_is_ptr(type))
- return 0;
- state = get_extra_state(expr);
- if (!state || !estate_get_single_value(state, &sval) || sval.value == 0)
- return 0;
-
- *tag = sval.uvalue & ~MTAG_OFFSET_MASK;
- *offset = sval.uvalue & MTAG_OFFSET_MASK;
- return 1;
-}
-
-static int get_mtag_cnt;
-int get_mtag(struct expression *expr, mtag_t *tag)
-{
- struct smatch_state *state;
- int ret = 0;
-
- expr = strip_expr(expr);
- if (!expr)
- return 0;
-
- if (get_mtag_cnt > 0)
- return 0;
-
- get_mtag_cnt++;
-
- switch (expr->type) {
- case EXPR_STRING:
- if (get_string_mtag(expr, tag)) {
- ret = 1;
- goto dec_cnt;
- }
- break;
- case EXPR_SYMBOL:
- if (get_toplevel_mtag(expr->symbol, tag)) {
- ret = 1;
- goto dec_cnt;
- }
- break;
- case EXPR_DEREF:
- if (get_deref_mtag(expr, tag)) {
- ret = 1;
- goto dec_cnt;
- }
- break;
- }
-
- state = get_state_expr(my_id, expr);
- if (!state)
- goto dec_cnt;
- if (state->data) {
- *tag = *(mtag_t *)state->data;
- ret = 1;
- goto dec_cnt;
- }
-
-dec_cnt:
- get_mtag_cnt--;
- return ret;
-}
-
-int get_mtag_offset(struct expression *expr, mtag_t *tag, int *offset)
-{
- int val;
+ if (!rl_to_sval(rl, &sval))
+ return rl;
+ if (sval.type->type != SYM_PTR || sval.uvalue != MTAG_SEED)
+ return rl;
- if (!expr)
- return 0;
- if (expr->type == EXPR_PREOP && expr->op == '*')
- return get_mtag_offset(expr->unop, tag, offset);
- if (get_implied_mtag_offset(expr, tag, offset))
- return 1;
- if (!get_mtag(expr, tag))
- return 0;
- expr = strip_expr(expr);
- if (expr->type == EXPR_SYMBOL) {
- *offset = 0;
- return 1;
- }
- val = get_member_offset_from_deref(expr);
- if (val < 0)
- return 0;
- *offset = val;
- return 1;
+ name = expr_to_str(expr);
+ snprintf(buf, sizeof(buf), "%s %s %s", get_filename(), get_function(), name);
+ free_string(name);
+ tag = str_to_tag(buf);
+ sval.value = tag;
+ return alloc_rl(sval, sval);
}
int create_mtag_alias(mtag_t tag, struct expression *expr, mtag_t *new)
@@ -415,10 +290,45 @@ int create_mtag_alias(mtag_t tag, struct expression *expr, mtag_t *new)
return 1;
}
+static int get_implied_mtag_offset(struct expression *expr, mtag_t *tag, int *offset)
+{
+ struct smatch_state *state;
+ struct symbol *type;
+ sval_t sval;
+
+ type = get_type(expr);
+ if (!type_is_ptr(type))
+ return 0;
+ state = get_extra_state(expr);
+ if (!state || !estate_get_single_value(state, &sval) || sval.value == 0)
+ return 0;
+
+ *tag = sval.uvalue & ~MTAG_OFFSET_MASK;
+ *offset = sval.uvalue & MTAG_OFFSET_MASK;
+ return 1;
+}
+
+/*
+ * The point of this function is to give you the mtag and the offset so
+ * you can look up the data in the DB. It takes an expression.
+ *
+ * So say you give it "foo->bar". Then it would give you the offset of "bar"
+ * and the implied value of "foo". Or if you lookup "*foo" then the offset is
+ * zero and we look up the implied value of "foo. But if the expression is
+ * foo, then if "foo" is a global variable, then we get the mtag and the offset
+ * is zero. If "foo" is a local variable, then there is nothing to look up in
+ * the mtag_data table because that's handled by smatch_extra.c to this returns
+ * false.
+ *
+ */
int expr_to_mtag_offset(struct expression *expr, mtag_t *tag, int *offset)
{
+ *tag = 0;
*offset = 0;
+ if (bits_in_pointer != 64)
+ return 0;
+
expr = strip_expr(expr);
if (!expr)
return 0;
@@ -426,19 +336,54 @@ int expr_to_mtag_offset(struct expression *expr, mtag_t *tag, int *offset)
if (is_array(expr))
return get_array_mtag_offset(expr, tag, offset);
- if (expr->type == EXPR_DEREF) {
- *offset = get_member_offset_from_deref(expr);
- if (*offset < 0)
+ if (expr->type == EXPR_PREOP && expr->op == '*') {
+ expr = strip_expr(expr->unop);
+ return get_implied_mtag_offset(expr, tag, offset);
+ } else if (expr->type == EXPR_DEREF) {
+ int tmp, tmp_offset = 0;
+
+ while (expr->type == EXPR_DEREF) {
+ tmp = get_member_offset_from_deref(expr);
+ if (tmp < 0)
+ return 0;
+ tmp_offset += tmp;
+ expr = expr->deref;
+ }
+ *offset = tmp_offset;
+ if (expr->type == EXPR_PREOP && expr->op == '*') {
+ expr = strip_expr(expr->unop);
+
+ if (get_implied_mtag_offset(expr, tag, &tmp_offset)) {
+ // FIXME: look it up recursively?
+ if (tmp_offset)
+ return 0;
+ return 1;
+ }
return 0;
- return get_mtag(expr->deref, tag);
+ } else if (expr->type == EXPR_SYMBOL) {
+ return get_symbol_mtag(expr->symbol, tag);
+ }
+ return 0;
+ } else if (expr->type == EXPR_SYMBOL) {
+ return get_symbol_mtag(expr->symbol, tag);
}
-
- if (get_implied_mtag_offset(expr, tag, offset))
- return 1;
-
- return get_mtag(expr, tag);
+ return 0;
}
+/*
+ * This function takes an address and returns an sval. Let's take some
+ * example things you might pass to it:
+ * foo->bar:
+ * If we were only called from smatch_math, we wouldn't need to bother with
+ * this because it's already been looked up in smatch_extra.c but this is
+ * also called from other places so we have to check smatch_extra.c.
+ * &foo
+ * If "foo" is global return the mtag for "foo".
+ * &foo.bar
+ * If "foo" is global return the mtag for "foo" + the offset of ".bar".
+ * It also handles string literals.
+ *
+ */
int get_mtag_sval(struct expression *expr, sval_t *sval)
{
struct symbol *type;
@@ -454,81 +399,43 @@ int get_mtag_sval(struct expression *expr, sval_t *sval)
if (!type_is_ptr(type))
return 0;
/*
- * There are only three options:
+ * There are several options:
*
- * 1) An array address:
- * p = array;
- * 2) An address like so:
- * p = &my_struct->member;
- * 3) A pointer:
- * p = pointer;
+ * If the expr is a string literal, that's an address/mtag.
+ * SYM_ARRAY and SYM_FN are mtags. There are "&foo" type addresses.
+ * And there are saved pointers "p = &foo;"
*
*/
if (expr->type == EXPR_STRING && get_string_mtag(expr, &tag))
goto found;
- if (type->type == SYM_ARRAY && get_toplevel_mtag(expr->symbol, &tag))
+ if (expr->type == EXPR_SYMBOL &&
+ (type->type == SYM_ARRAY || type->type == SYM_FN) &&
+ get_toplevel_mtag(expr->symbol, &tag))
goto found;
+ if (expr->type == EXPR_PREOP && expr->op == '&') {
+ expr = strip_expr(expr->unop);
+ if (expr_to_mtag_offset(expr, &tag, &offset))
+ goto found;
+ return 0;
+ }
+
if (get_implied_mtag_offset(expr, &tag, &offset))
goto found;
- if (expr->type != EXPR_PREOP || expr->op != '&')
- return 0;
- expr = strip_expr(expr->unop);
-
- if (!expr_to_mtag_offset(expr, &tag, &offset))
+ return 0;
+found:
+ if (offset >= MTAG_OFFSET_MASK)
return 0;
- if (offset > MTAG_OFFSET_MASK)
- offset = MTAG_OFFSET_MASK;
-found:
sval->type = type;
sval->uvalue = tag | offset;
return 1;
}
-static struct expression *remove_dereference(struct expression *expr)
-{
- expr = strip_expr(expr);
-
- if (expr->type == EXPR_PREOP && expr->op == '*')
- return strip_expr(expr->unop);
- return preop_expression(expr, '&');
-}
-
-int get_mtag_addr_sval(struct expression *expr, sval_t *sval)
-{
- return get_mtag_sval(remove_dereference(expr), sval);
-}
-
-static void print_stored_to_mtag(int return_id, char *return_ranges, struct expression *expr)
-{
- struct sm_state *sm;
- char buf[256];
- const char *param_name;
- int param;
-
- FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
- if (!sm->state->data)
- continue;
-
- param = get_param_num_from_sym(sm->sym);
- if (param < 0)
- continue;
- param_name = get_param_name(sm);
- if (!param_name)
- continue;
- if (strcmp(param_name, "$") == 0)
- continue;
-
- snprintf(buf, sizeof(buf), "%lld", *(mtag_t *)sm->state->data);
- sql_insert_return_states(return_id, return_ranges, MEMORY_TAG, param, param_name, buf);
- } END_FOR_EACH_SM(sm);
-}
-
void register_mtag(int id)
{
my_id = id;
@@ -542,18 +449,6 @@ void register_mtag(int id)
* bit 11-0 : offset
*
*/
- if (bits_in_pointer != 64)
- return;
add_hook(&global_variable, BASE_HOOK);
-
- add_function_assign_hook("kmalloc", &alloc_assign, NULL);
- add_function_assign_hook("kzalloc", &alloc_assign, NULL);
-
- select_return_states_hook(BUF_SIZE, &db_returns_buf_size);
-
- add_hook(&match_call_info, FUNCTION_CALL_HOOK);
- select_caller_info_hook(save_caller_info, MEMORY_TAG);
- add_split_return_callback(&print_stored_to_mtag);
- select_return_states_hook(MEMORY_TAG, db_returns_memory_tag);
}
diff --git a/usr/src/tools/smatch/src/smatch_mtag_data.c b/usr/src/tools/smatch/src/smatch_mtag_data.c
index 0396730390..801542373b 100644
--- a/usr/src/tools/smatch/src/smatch_mtag_data.c
+++ b/usr/src/tools/smatch/src/smatch_mtag_data.c
@@ -36,11 +36,9 @@ static int save_rl(void *_rl, int argc, char **argv, char **azColName)
return 0;
}
-static struct range_list *select_orig_rl(sval_t sval)
+static struct range_list *select_orig(mtag_t tag, int offset)
{
struct range_list *rl = NULL;
- mtag_t tag = sval.uvalue & ~MTAG_OFFSET_MASK;
- int offset = sval.uvalue & MTAG_OFFSET_MASK;
mem_sql(&save_rl, &rl, "select value from mtag_data where tag = %lld and offset = %d;",
tag, offset);
@@ -71,11 +69,8 @@ static int is_kernel_param(const char *name)
return 0;
}
-void insert_mtag_data(sval_t sval, struct range_list *rl)
+static void insert_mtag_data(mtag_t tag, int offset, struct range_list *rl)
{
- mtag_t tag = sval.uvalue & ~MTAG_OFFSET_MASK;
- int offset = sval.uvalue & MTAG_OFFSET_MASK;
-
rl = clone_rl_permanent(rl);
mem_sql(NULL, NULL, "delete from mtag_data where tag = %lld and offset = %d and type = %d",
@@ -87,8 +82,10 @@ void insert_mtag_data(sval_t sval, struct range_list *rl)
void update_mtag_data(struct expression *expr)
{
struct range_list *orig, *new, *rl;
+ struct symbol *type;
char *name;
- sval_t sval;
+ mtag_t tag;
+ int offset;
name = expr_to_var(expr);
if (is_kernel_param(name)) {
@@ -97,20 +94,27 @@ void update_mtag_data(struct expression *expr)
}
free_string(name);
- if (!get_mtag_addr_sval(expr, &sval))
+ if (!expr_to_mtag_offset(expr, &tag, &offset))
+ return;
+
+ type = get_type(expr);
+ if ((offset == 0) &&
+ (!type || type == &void_ctype ||
+ type->type == SYM_STRUCT || type->type == SYM_UNION || type->type == SYM_ARRAY))
return;
get_absolute_rl(expr, &rl);
- orig = select_orig_rl(sval);
+ orig = select_orig(tag, offset);
new = rl_union(orig, rl);
- insert_mtag_data(sval, new);
+ insert_mtag_data(tag, offset, new);
}
static void match_global_assign(struct expression *expr)
{
struct range_list *rl;
- sval_t sval;
+ mtag_t tag;
+ int offset;
char *name;
name = expr_to_var(expr->left);
@@ -120,11 +124,11 @@ static void match_global_assign(struct expression *expr)
}
free_string(name);
- if (!get_mtag_addr_sval(expr->left, &sval))
+ if (!expr_to_mtag_offset(expr->left, &tag, &offset))
return;
get_absolute_rl(expr->right, &rl);
- insert_mtag_data(sval, rl);
+ insert_mtag_data(tag, offset, rl);
}
static int save_mtag_data(void *_unused, int argc, char **argv, char **azColName)
@@ -171,22 +175,25 @@ static int get_vals(void *_db_info, int argc, char **argv, char **azColName)
}
struct db_cache_results {
- sval_t sval;
+ mtag_t tag;
struct range_list *rl;
};
static struct db_cache_results cached_results[8];
-static int get_rl_from_mtag_sval(sval_t sval, struct symbol *type, struct range_list **rl)
+static int get_rl_from_mtag_offset(mtag_t tag, int offset, struct symbol *type, struct range_list **rl)
{
struct db_info db_info = {};
- mtag_t tag;
- int offset;
+ mtag_t merged = tag | offset;
static int idx;
int ret;
int i;
+ if (!type || type == &void_ctype ||
+ (type->type == SYM_STRUCT || type->type == SYM_ARRAY || type->type == SYM_UNION))
+ return 0;
+
for (i = 0; i < ARRAY_SIZE(cached_results); i++) {
- if (sval.uvalue == cached_results[i].sval.uvalue) {
+ if (merged == cached_results[i].tag) {
if (cached_results[i].rl) {
*rl = cached_results[i].rl;
return 1;
@@ -195,12 +202,6 @@ static int get_rl_from_mtag_sval(sval_t sval, struct symbol *type, struct range_
}
}
- tag = sval.uvalue & ~MTAG_OFFSET_MASK;
- offset = sval.uvalue & MTAG_OFFSET_MASK;
- if (offset == MTAG_OFFSET_MASK) {
- ret = 0;
- goto update_cache;
- }
db_info.type = type;
run_sql(get_vals, &db_info,
@@ -216,7 +217,7 @@ static int get_rl_from_mtag_sval(sval_t sval, struct symbol *type, struct range_
ret = 1;
update_cache:
- cached_results[idx].sval = sval;
+ cached_results[idx].tag = merged;
cached_results[idx].rl = db_info.rl;
idx = (idx + 1) % ARRAY_SIZE(cached_results);
@@ -231,16 +232,19 @@ static void clear_cache(struct symbol *sym)
int get_mtag_rl(struct expression *expr, struct range_list **rl)
{
struct symbol *type;
- sval_t sval;
+ mtag_t tag;
+ int offset;
- if (!get_mtag_addr_sval(expr, &sval))
+ if (!expr_to_mtag_offset(expr, &tag, &offset))
+ return 0;
+ if (offset >= MTAG_OFFSET_MASK)
return 0;
type = get_type(expr);
if (!type)
return 0;
- return get_rl_from_mtag_sval(sval, type, rl);
+ return get_rl_from_mtag_offset(tag, offset, type, rl);
}
void register_mtag_data(int id)
diff --git a/usr/src/tools/smatch/src/smatch_mtag_map.c b/usr/src/tools/smatch/src/smatch_mtag_map.c
index 8384a9908f..4ca0e00c08 100644
--- a/usr/src/tools/smatch/src/smatch_mtag_map.c
+++ b/usr/src/tools/smatch/src/smatch_mtag_map.c
@@ -29,8 +29,9 @@ static int my_id;
static void match_assign(struct expression *expr)
{
struct expression *left, *right;
- mtag_t left_tag, right_tag;
+ mtag_t left_tag;
int offset;
+ sval_t sval;
if (expr->op != '=')
return;
@@ -38,19 +39,20 @@ static void match_assign(struct expression *expr)
left = strip_expr(expr->left);
right = strip_expr(expr->right);
- if (left->type != EXPR_DEREF)
+ if (!type_is_ptr(get_type(right)))
return;
-
- offset = get_member_offset_from_deref(left);
- if (offset < 0)
+ if (!get_implied_value(right, &sval))
return;
-
- if (!get_mtag(left->deref, &left_tag))
+ if (sval_cmp(sval, valid_ptr_min_sval) < 0 ||
+ sval_cmp(sval, valid_ptr_max_sval) > 0)
return;
- if (!get_mtag(right, &right_tag))
+ if (sval.uvalue & MTAG_OFFSET_MASK)
+ return;
+
+ if (!expr_to_mtag_offset(left, &left_tag, &offset))
return;
- sql_insert_mtag_map(right_tag, -offset, left_tag);
+ sql_insert_mtag_map(sval.uvalue, -offset, left_tag);
}
void register_mtag_map(int id)
diff --git a/usr/src/tools/smatch/src/smatch_nul_terminator.c b/usr/src/tools/smatch/src/smatch_nul_terminator.c
index 845c75661f..86a3dbd4fb 100644
--- a/usr/src/tools/smatch/src/smatch_nul_terminator.c
+++ b/usr/src/tools/smatch/src/smatch_nul_terminator.c
@@ -247,6 +247,38 @@ bool is_nul_terminated(struct expression *expr)
return 0;
}
+static void match_strnlen_test(struct expression *expr)
+{
+ struct expression *left, *tmp, *arg;
+ int cnt;
+
+ if (expr->type != EXPR_COMPARE)
+ return;
+ if (expr->op != SPECIAL_EQUAL && expr->op != SPECIAL_NOTEQUAL)
+ return;
+
+ left = strip_expr(expr->left);
+ cnt = 0;
+ while ((tmp = get_assigned_expr(left))) {
+ if (cnt++ > 3)
+ break;
+ left = tmp;
+ }
+
+ if (left->type != EXPR_CALL)
+ return;
+ if (!sym_name_is("strnlen", left->fn))
+ return;
+ arg = get_argument_from_call_expr(left->args, 0);
+ set_true_false_states_expr(my_id, arg,
+ (expr->op == SPECIAL_EQUAL) ? &terminated : NULL,
+ (expr->op == SPECIAL_NOTEQUAL) ? &terminated : NULL);
+ if (get_param_num(arg) >= 0)
+ set_true_false_states_expr(param_set_id, arg,
+ (expr->op == SPECIAL_EQUAL) ? &terminated : NULL,
+ (expr->op == SPECIAL_NOTEQUAL) ? &terminated : NULL);
+}
+
void register_nul_terminator(int id)
{
my_id = id;
@@ -260,6 +292,8 @@ void register_nul_terminator(int id)
select_caller_info_hook(caller_info_terminated, TERMINATED);
select_return_states_hook(TERMINATED, return_info_terminated);
+
+ add_hook(&match_strnlen_test, CONDITION_HOOK);
}
void register_nul_terminator_param_set(int id)
diff --git a/usr/src/tools/smatch/src/smatch_param_compare_limit.c b/usr/src/tools/smatch/src/smatch_param_compare_limit.c
index 1539e06249..bca4c89a55 100644
--- a/usr/src/tools/smatch/src/smatch_param_compare_limit.c
+++ b/usr/src/tools/smatch/src/smatch_param_compare_limit.c
@@ -180,8 +180,8 @@ static void print_return_comparison(int return_id, char *return_ranges, struct e
struct compare_data *data;
struct var_sym *left, *right;
int left_param, right_param;
- static char left_buf[256];
- static char right_buf[256];
+ static char left_buf[248];
+ static char right_buf[248];
static char info_buf[256];
const char *tmp_name;
@@ -284,7 +284,7 @@ static int split_op_param_key(char *value, int *op, int *param, char **key)
if (!parse_comparison(&value, op))
return 0;
- snprintf(buf, sizeof(buf), value);
+ snprintf(buf, sizeof(buf), "%s", value);
p = buf;
if (*p++ != '$')
@@ -357,6 +357,7 @@ void register_param_compare_limit(int id)
{
compare_id = id;
+ set_dynamic_states(compare_id);
add_merge_hook(compare_id, &merge_compare_states);
add_split_return_callback(&print_return_comparison);
@@ -367,7 +368,7 @@ void register_param_compare_limit_links(int id)
{
link_id = id;
+ set_dynamic_states(link_id);
add_merge_hook(link_id, &merge_links);
-
}
diff --git a/usr/src/tools/smatch/src/smatch_param_filter.c b/usr/src/tools/smatch/src/smatch_param_filter.c
index 01a9920f57..9b5a04b268 100644
--- a/usr/src/tools/smatch/src/smatch_param_filter.c
+++ b/usr/src/tools/smatch/src/smatch_param_filter.c
@@ -148,6 +148,11 @@ static void print_one_mod_param(int return_id, char *return_ranges,
return;
}
+ if (is_ignored_kernel_data(param_name)) {
+ insert_string(totally_filtered, (char *)sm->name);
+ return;
+ }
+
sql_insert_return_states(return_id, return_ranges, PARAM_FILTER, param,
param_name, show_rl(estate_rl(sm->state)));
}
@@ -198,6 +203,7 @@ void register_param_filter(int id)
{
my_id = id;
+ set_dynamic_states(my_id);
add_hook(&save_start_states, AFTER_DEF_HOOK);
add_hook(&free_start_states, AFTER_FUNC_HOOK);
diff --git a/usr/src/tools/smatch/src/smatch_param_limit.c b/usr/src/tools/smatch/src/smatch_param_limit.c
index 6ed3259b40..3ef8afc3a7 100644
--- a/usr/src/tools/smatch/src/smatch_param_limit.c
+++ b/usr/src/tools/smatch/src/smatch_param_limit.c
@@ -158,6 +158,9 @@ static void print_return_value_param(int return_id, char *return_ranges, struct
if (old && rl_equiv(estate_rl(old), estate_rl(state)))
continue;
+ if (is_ignored_kernel_data(param_name))
+ continue;
+
rl = generify_mtag_range(state);
sql_insert_return_states(return_id, return_ranges, PARAM_LIMIT,
param, param_name, show_rl(rl));
@@ -193,6 +196,7 @@ void register_param_limit(int id)
{
my_id = id;
+ set_dynamic_states(my_id);
add_hook(&save_start_states, AFTER_DEF_HOOK);
add_hook(&free_start_states, AFTER_FUNC_HOOK);
diff --git a/usr/src/tools/smatch/src/smatch_param_set.c b/usr/src/tools/smatch/src/smatch_param_set.c
index 21456057ce..44b6e3e659 100644
--- a/usr/src/tools/smatch/src/smatch_param_set.c
+++ b/usr/src/tools/smatch/src/smatch_param_set.c
@@ -164,7 +164,6 @@ static void print_return_value_param(int return_id, char *return_ranges, struct
struct string_list *set_list = NULL;
char *math_str;
char buf[256];
- sval_t sval;
FOR_EACH_MY_SM(my_id, __get_cur_stree(), sm) {
if (!estate_rl(sm->state))
@@ -188,12 +187,13 @@ static void print_return_value_param(int return_id, char *return_ranges, struct
insert_string(&set_list, (char *)sm->name);
continue;
}
+ if (is_recursive_member(param_name)) {
+ insert_string(&set_list, (char *)sm->name);
+ continue;
+ }
- if (rl_to_sval(rl, &sval)) {
+ if (is_ignored_kernel_data(param_name)) {
insert_string(&set_list, (char *)sm->name);
- sql_insert_return_states(return_id, return_ranges,
- param_has_filter_data(sm) ? PARAM_ADD : PARAM_SET,
- param, param_name, show_rl(rl));
continue;
}
@@ -260,6 +260,7 @@ void register_param_set(int id)
{
my_id = id;
+ set_dynamic_states(my_id);
add_extra_mod_hook(&extra_mod_hook);
add_hook(match_array_assignment, ASSIGNMENT_HOOK);
add_unmatched_state_hook(my_id, &unmatched_state);
diff --git a/usr/src/tools/smatch/src/smatch_param_to_mtag_data.c b/usr/src/tools/smatch/src/smatch_param_to_mtag_data.c
index ec647317e7..a4b000f647 100644
--- a/usr/src/tools/smatch/src/smatch_param_to_mtag_data.c
+++ b/usr/src/tools/smatch/src/smatch_param_to_mtag_data.c
@@ -76,6 +76,18 @@ struct smatch_state *merge_tag_info(struct smatch_state *s1, struct smatch_state
return &merged;
}
+static bool is_local_var(struct expression *expr)
+{
+ struct symbol *sym;
+
+ if (!expr || expr->type != EXPR_SYMBOL)
+ return false;
+ sym = expr->symbol;
+ if (!(sym->ctype.modifiers & MOD_TOPLEVEL))
+ return true;
+ return false;
+}
+
static void match_assign(struct expression *expr)
{
struct expression *left;
@@ -88,6 +100,8 @@ static void match_assign(struct expression *expr)
if (expr->op != '=')
return;
left = strip_expr(expr->left);
+ if (is_local_var(left))
+ return;
right_sym = expr_to_sym(expr->right);
if (!right_sym)
return;
@@ -105,28 +119,6 @@ static void match_assign(struct expression *expr)
free_string(name);
}
-#if 0
-static void save_mtag_to_map(struct expression *expr, mtag_t tag, int offset, int param, char *key, char *value)
-{
- struct expression *arg, *gen_expr;
- mtag_t arg_tag;
-
- arg = get_argument_from_call_expr(expr->args, param);
- if (!arg)
- return;
-
- gen_expr = gen_expression_from_key(arg, key);
- if (!gen_expr)
- return;
-
- if (!get_mtag(gen_expr, &arg_tag))
- arg_tag = 0;
-
- if (local_debug)
- sm_msg("finding mtag for '%s' %lld", expr_to_str(gen_expr), arg_tag);
-}
-#endif
-
static void propogate_assignment(struct expression *expr, mtag_t tag, int offset, int param, char *key)
{
struct expression *arg;
@@ -158,6 +150,7 @@ static void assign_to_alias(struct expression *expr, int param, mtag_t tag, int
struct range_list *rl;
mtag_t arg_tag;
mtag_t alias;
+ int arg_offset;
arg = get_argument_from_call_expr(expr->args, param);
if (!arg)
@@ -174,7 +167,8 @@ static void assign_to_alias(struct expression *expr, int param, mtag_t tag, int
// insert_mtag_data(alias, offset, rl);
- if (get_mtag(gen_expr, &arg_tag))
+ // FIXME: is arg_offset handled correctly?
+ if (expr_to_mtag_offset(gen_expr, &arg_tag, &arg_offset) && arg_offset == 0)
sql_insert_mtag_map(arg_tag, -offset, alias);
}
@@ -229,6 +223,7 @@ void register_param_to_mtag_data(int id)
{
my_id = id;
+ set_dynamic_states(my_id);
add_hook(&match_assign, ASSIGNMENT_HOOK);
select_return_states_hook(MTAG_ASSIGN, &call_does_mtag_assign);
add_merge_hook(my_id, &merge_tag_info);
diff --git a/usr/src/tools/smatch/src/smatch_param_used.c b/usr/src/tools/smatch/src/smatch_param_used.c
index 80d390d359..e81bd8358a 100644
--- a/usr/src/tools/smatch/src/smatch_param_used.c
+++ b/usr/src/tools/smatch/src/smatch_param_used.c
@@ -31,7 +31,7 @@ static void get_state_hook(int owner, const char *name, struct symbol *sym)
if (!option_info)
return;
- if (__in_fake_assign)
+ if (__in_fake_assign || __in_fake_parameter_assign || __in_function_def)
return;
arg = get_param_num_from_sym(sym);
@@ -51,7 +51,7 @@ static void set_param_used(struct expression *call, struct expression *arg, char
arg_nr = get_param_num_from_sym(sym);
if (arg_nr >= 0)
- set_state(my_id, name, sym, &used);
+ set_state_stree(&used_stree, my_id, name, sym, &used);
free:
free_string(name);
}
@@ -69,6 +69,11 @@ static void process_states(void)
name = get_param_name(tmp);
if (!name)
continue;
+ if (is_recursive_member(name))
+ continue;
+
+ if (is_ignored_kernel_data(name))
+ continue;
sql_insert_return_implies(PARAM_USED, arg, name, "");
} END_FOR_EACH_SM(tmp);
diff --git a/usr/src/tools/smatch/src/smatch_parse_call_math.c b/usr/src/tools/smatch/src/smatch_parse_call_math.c
index a84622d941..5f3ed679a4 100644
--- a/usr/src/tools/smatch/src/smatch_parse_call_math.c
+++ b/usr/src/tools/smatch/src/smatch_parse_call_math.c
@@ -114,7 +114,7 @@ static void rl_discard_stacks(void)
pop_rl(&rl_stack);
}
-static int read_rl_from_var(struct expression *call, char *p, char **end, struct range_list **rl)
+static int read_rl_from_var(struct expression *call, const char *p, const char **end, struct range_list **rl)
{
struct expression *arg;
struct smatch_state *state;
@@ -125,7 +125,7 @@ static int read_rl_from_var(struct expression *call, char *p, char **end, struct
int star;
p++;
- param = strtol(p, &p, 10);
+ param = strtol(p, (char **)&p, 10);
arg = get_argument_from_call_expr(call->args, param);
if (!arg)
@@ -165,7 +165,7 @@ static int read_rl_from_var(struct expression *call, char *p, char **end, struct
return 1;
}
-static int read_var_num(struct expression *call, char *p, char **end, struct range_list **rl)
+static int read_var_num(struct expression *call, const char *p, const char **end, struct range_list **rl)
{
sval_t sval;
@@ -176,14 +176,14 @@ static int read_var_num(struct expression *call, char *p, char **end, struct ran
return read_rl_from_var(call, p, end, rl);
sval.type = &llong_ctype;
- sval.value = strtoll(p, end, 10);
+ sval.value = strtoll(p, (char **)end, 10);
if (*end == p)
return 0;
*rl = alloc_rl(sval, sval);
return 1;
}
-static char *read_op(char *p)
+static const char *read_op(const char *p)
{
while (*p == ' ')
p++;
@@ -199,14 +199,14 @@ static char *read_op(char *p)
}
}
-int parse_call_math_rl(struct expression *call, char *math, struct range_list **rl)
+int parse_call_math_rl(struct expression *call, const char *math, struct range_list **rl)
{
struct range_list *tmp;
- char *c;
+ const char *c;
/* try to implement shunting yard algorithm. */
- c = (char *)math;
+ c = math;
while (1) {
if (option_debug)
sm_msg("parsing %s", c);
@@ -344,6 +344,16 @@ static int format_call_to_param_mapping(char *buf, int remaining, struct express
return format_name_sym_helper(buf, remaining, name, sym);
}
+static int is_mtag_sval(sval_t sval)
+{
+ if (!is_ptr_type(sval.type))
+ return 0;
+ if (sval_cmp(sval, valid_ptr_min_sval) >= 0 &&
+ sval_cmp(sval, valid_ptr_max_sval) <= 0)
+ return 1;
+ return 0;
+}
+
static int format_expr_helper(char *buf, int remaining, struct expression *expr)
{
sval_t sval;
@@ -380,7 +390,7 @@ static int format_expr_helper(char *buf, int remaining, struct expression *expr)
return cur - buf;
}
- if (get_implied_value(expr, &sval)) {
+ if (!param_was_set(expr) && get_implied_value(expr, &sval) && !is_mtag_sval(sval)) {
ret = snprintf(cur, remaining, "%s", sval_to_str(sval));
remaining -= ret;
if (remaining <= 0)
@@ -435,6 +445,7 @@ char *get_value_in_terms_of_parameter_math_var_sym(const char *name, struct symb
char buf[256] = "";
int ret;
int cnt = 0;
+ sval_t sval;
expr = get_assigned_expr_name_sym(name, sym);
if (!expr)
@@ -445,6 +456,9 @@ char *get_value_in_terms_of_parameter_math_var_sym(const char *name, struct symb
break;
}
+ if (get_implied_value(expr, &sval))
+ return NULL;
+
ret = format_expr_helper(buf, sizeof(buf), expr);
if (ret == 0)
return NULL;
@@ -493,7 +507,7 @@ static char *swap_format(struct expression *call, char *format)
while (*p) {
if (*p == '$') {
p++;
- param = strtol(p, &p, 10);
+ param = strtol(p, (char **)&p, 10);
arg = get_argument_from_call_expr(call->args, param);
if (!arg)
return NULL;
@@ -643,6 +657,8 @@ void register_parse_call_math(int id)
my_id = id;
+ set_dynamic_states(my_id);
+
for (i = 0; i < ARRAY_SIZE(alloc_functions); i++)
add_function_assign_hook(alloc_functions[i].func, &match_alloc,
INT_PTR(alloc_functions[i].param));
diff --git a/usr/src/tools/smatch/src/smatch_passes_array_size.c b/usr/src/tools/smatch/src/smatch_passes_array_size.c
index cf69c8cdc5..fa17ec3e3b 100644
--- a/usr/src/tools/smatch/src/smatch_passes_array_size.c
+++ b/usr/src/tools/smatch/src/smatch_passes_array_size.c
@@ -39,11 +39,15 @@ static int find_param_eq(struct expression *expr, int size)
static void match_call(struct expression *expr)
{
struct expression *arg;
- struct symbol *type;
+ struct symbol *type, *arg_type;
int size, bytes;
int i, nr;
char buf[16];
+ char elem_count[8];
+ char byte_count[8];
+ snprintf(elem_count, sizeof(elem_count), "%d", ELEM_COUNT);
+ snprintf(byte_count, sizeof(byte_count), "%d", BYTE_COUNT);
i = -1;
FOR_EACH_PTR(expr->args, arg) {
@@ -51,12 +55,16 @@ static void match_call(struct expression *expr)
type = get_type(arg);
if (!type || (type->type != SYM_PTR && type->type != SYM_ARRAY))
continue;
+ arg_type = get_arg_type(expr->fn, i);
+ if (arg_type != type)
+ continue;
+
size = get_array_size(arg);
if (size > 0) {
nr = find_param_eq(expr, size);
if (nr >= 0) {
- snprintf(buf, sizeof(buf), "%d", nr);
- sql_insert_caller_info(expr, ARRAYSIZE_ARG, i, buf, "");
+ snprintf(buf, sizeof(buf), "==$%d", nr);
+ sql_insert_caller_info(expr, ELEM_COUNT, i, buf, elem_count);
continue;
}
}
@@ -64,8 +72,8 @@ static void match_call(struct expression *expr)
if (bytes > 0) {
nr = find_param_eq(expr, bytes);
if (nr >= 0) {
- snprintf(buf, sizeof(buf), "%d", nr);
- sql_insert_caller_info(expr, SIZEOF_ARG, i, buf, "");
+ snprintf(buf, sizeof(buf), "==$%d", nr);
+ sql_insert_caller_info(expr, BYTE_COUNT, i, buf, byte_count);
continue;
}
}
diff --git a/usr/src/tools/smatch/src/smatch_ranges.c b/usr/src/tools/smatch/src/smatch_ranges.c
index fbc93fec7e..d534328476 100644
--- a/usr/src/tools/smatch/src/smatch_ranges.c
+++ b/usr/src/tools/smatch/src/smatch_ranges.c
@@ -26,27 +26,77 @@ __DO_ALLOCATOR(struct data_range, sizeof(struct data_range), __alignof__(struct
"permanent ranges", perm_data_range);
__DECLARE_ALLOCATOR(struct ptr_list, rl_ptrlist);
+static bool is_err_ptr(sval_t sval)
+{
+ if (option_project != PROJ_KERNEL)
+ return false;
+ if (!type_is_ptr(sval.type))
+ return false;
+ if (sval.uvalue < -4095ULL)
+ return false;
+ return true;
+}
+
+static char *get_err_pointer_str(struct data_range *drange)
+{
+ static char buf[20];
+
+ /*
+ * The kernel has error pointers where you do essentially:
+ *
+ * return (void *)(unsigned long)-12;
+ *
+ * But what I want here is to print -12 instead of the unsigned version
+ * of that.
+ *
+ */
+ if (!is_err_ptr(drange->min))
+ return NULL;
+
+ if (drange->min.value == drange->max.value)
+ snprintf(buf, sizeof(buf), "(%lld)", drange->min.value);
+ else
+ snprintf(buf, sizeof(buf), "(%lld)-(%lld)", drange->min.value, drange->max.value);
+ return buf;
+}
+
char *show_rl(struct range_list *list)
{
+ struct data_range *prev_drange = NULL;
struct data_range *tmp;
- char full[512];
+ char full[255];
+ char *p = full;
+ char *prev = full;
+ char *err_ptr;
+ int remain;
int i = 0;
full[0] = '\0';
- full[sizeof(full) - 1] = '\0';
+
FOR_EACH_PTR(list, tmp) {
- if (i++)
- strncat(full, ",", 254 - strlen(full));
- if (sval_cmp(tmp->min, tmp->max) == 0) {
- strncat(full, sval_to_str(tmp->min), 254 - strlen(full));
- continue;
+ remain = full + sizeof(full) - p;
+ if (remain < 48) {
+ snprintf(prev, full + sizeof(full) - prev, ",%s-%s",
+ sval_to_str(prev_drange->min),
+ sval_to_str(sval_type_max(prev_drange->min.type)));
+ break;
+ }
+ prev_drange = tmp;
+ prev = p;
+
+ err_ptr = get_err_pointer_str(tmp);
+ if (err_ptr) {
+ p += snprintf(p, remain, "%s%s", i++ ? "," : "", err_ptr);
+ } else if (sval_cmp(tmp->min, tmp->max) == 0) {
+ p += snprintf(p, remain, "%s%s", i++ ? "," : "",
+ sval_to_str(tmp->min));
+ } else {
+ p += snprintf(p, remain, "%s%s-%s", i++ ? "," : "",
+ sval_to_str(tmp->min),
+ sval_to_str(tmp->max));
}
- strncat(full, sval_to_str(tmp->min), 254 - strlen(full));
- strncat(full, "-", 254 - strlen(full));
- strncat(full, sval_to_str(tmp->max), 254 - strlen(full));
} END_FOR_EACH_PTR(tmp);
- if (strlen(full) == sizeof(full) - 1)
- full[sizeof(full) - 2] = '+';
+
return alloc_sname(full);
}
@@ -79,6 +129,18 @@ static int sval_too_big(struct symbol *type, sval_t sval)
return 0;
}
+static int truncates_nicely(struct symbol *type, sval_t min, sval_t max)
+{
+ unsigned long long mask;
+ int bits = type_bits(type);
+
+ if (bits >= type_bits(min.type))
+ return 0;
+
+ mask = -1ULL << bits;
+ return (min.uvalue & mask) == (max.uvalue & mask);
+}
+
static void add_range_t(struct symbol *type, struct range_list **rl, sval_t min, sval_t max)
{
/* If we're just adding a number, cast it and add it */
@@ -93,11 +155,16 @@ static void add_range_t(struct symbol *type, struct range_list **rl, sval_t min,
return;
}
+ if (truncates_nicely(type, min, max)) {
+ add_range(rl, sval_cast(type, min), sval_cast(type, max));
+ return;
+ }
+
/*
* If the range we are adding has more bits than the range type then
* add the whole range type. Eg:
* 0x8000000000000000 - 0xf000000000000000 -> cast to int
- * This isn't totally the right thing to do. We could be more granular.
+ *
*/
if (sval_too_big(type, min) || sval_too_big(type, max)) {
add_range(rl, sval_type_min(type), sval_type_max(type));
@@ -138,10 +205,10 @@ static void add_range_t(struct symbol *type, struct range_list **rl, sval_t min,
static int str_to_comparison_arg_helper(const char *str,
struct expression *call, int *comparison,
- struct expression **arg, char **endp)
+ struct expression **arg, const char **endp)
{
int param;
- char *c = (char *)str;
+ const char *c = str;
if (*c != '[')
return 0;
@@ -171,6 +238,8 @@ static int str_to_comparison_arg_helper(const char *str,
c++;
c++;
*comparison = SPECIAL_NOTEQUAL;
+ } else if (*c == '$') {
+ *comparison = SPECIAL_EQUAL;
} else {
return 0;
}
@@ -179,8 +248,8 @@ static int str_to_comparison_arg_helper(const char *str,
return 0;
c++;
- param = strtoll(c, &c, 10);
- if (*c == ']')
+ param = strtoll(c, (char **)&c, 10);
+ if (*c == ',' || *c == ']')
c++; /* skip the ']' character */
if (endp)
*endp = (char *)c;
@@ -218,7 +287,7 @@ int str_to_comparison_arg(const char *str, struct expression *call, int *compari
return str_to_comparison_arg_helper(str, call, comparison, arg, NULL);
}
-static int get_val_from_key(int use_max, struct symbol *type, char *c, struct expression *call, char **endp, sval_t *sval)
+static int get_val_from_key(int use_max, struct symbol *type, const char *c, struct expression *call, const char **endp, sval_t *sval)
{
struct expression *arg;
int comparison;
@@ -318,7 +387,7 @@ void filter_by_comparison(struct range_list **rl, int comparison, struct range_l
*rl = cast_rl(rl_type(*rl), ret_rl);
}
-static struct range_list *filter_by_comparison_call(char *c, struct expression *call, char **endp, struct range_list *start_rl)
+static struct range_list *filter_by_comparison_call(const char *c, struct expression *call, const char **endp, struct range_list *start_rl)
{
struct symbol *type;
struct expression *arg;
@@ -344,9 +413,9 @@ static struct range_list *filter_by_comparison_call(char *c, struct expression *
return cast_rl(rl_type(start_rl), casted_start);
}
-static sval_t parse_val(int use_max, struct expression *call, struct symbol *type, char *c, char **endp)
+static sval_t parse_val(int use_max, struct expression *call, struct symbol *type, const char *c, const char **endp)
{
- char *start = c;
+ const char *start = c;
sval_t ret;
if (!strncmp(start, "max", 3)) {
@@ -398,17 +467,17 @@ static sval_t parse_val(int use_max, struct expression *call, struct symbol *typ
/* this parses [==p0] comparisons */
get_val_from_key(1, type, start, call, &c, &ret);
} else if (type_positive_bits(type) == 64) {
- ret = sval_type_val(type, strtoull(start, &c, 0));
+ ret = sval_type_val(type, strtoull(start, (char **)&c, 0));
} else {
- ret = sval_type_val(type, strtoll(start, &c, 0));
+ ret = sval_type_val(type, strtoll(start, (char **)&c, 0));
}
*endp = c;
return ret;
}
-static char *jump_to_call_math(char *value)
+static const char *jump_to_call_math(const char *value)
{
- char *c = value;
+ const char *c = value;
while (*c && *c != '[')
c++;
@@ -422,12 +491,13 @@ static char *jump_to_call_math(char *value)
return c;
}
-static void str_to_rl_helper(struct expression *call, struct symbol *type, char *str, char **endp, struct range_list **rl)
+static void str_to_rl_helper(struct expression *call, struct symbol *type, const char *str, const char **endp, struct range_list **rl)
{
struct range_list *rl_tmp = NULL;
- sval_t min, max;
- char *c;
+ sval_t prev_min, min, max;
+ const char *c;
+ prev_min = sval_type_min(type);
min = sval_type_min(type);
max = sval_type_max(type);
c = str;
@@ -457,8 +527,12 @@ static void str_to_rl_helper(struct expression *call, struct symbol *type, char
continue;
}
if (*c == '+') {
- min = sval_type_max(type);
+ min = prev_min;
+ max = sval_type_max(type);
+ add_range_t(type, &rl_tmp, min, max);
c++;
+ if (*c == '[' || *c == '\0')
+ break;
}
if (*c != '-') {
sm_msg("debug XXX: trouble parsing %s c = %s", str, c);
@@ -472,8 +546,12 @@ static void str_to_rl_helper(struct expression *call, struct symbol *type, char
max = sval_type_max(type);
if (*c == '+') {
max = sval_type_max(type);
+ add_range_t(type, &rl_tmp, min, max);
c++;
+ if (*c == '[' || *c == '\0')
+ break;
}
+ prev_min = max;
add_range_t(type, &rl_tmp, min, max);
if (*c == ')')
c++;
@@ -485,11 +563,11 @@ static void str_to_rl_helper(struct expression *call, struct symbol *type, char
*endp = c;
}
-static void str_to_dinfo(struct expression *call, struct symbol *type, char *value, struct data_info *dinfo)
+static void str_to_dinfo(struct expression *call, struct symbol *type, const char *value, struct data_info *dinfo)
{
struct range_list *math_rl;
- char *call_math;
- char *c;
+ const char *call_math;
+ const char *c;
struct range_list *rl = NULL;
if (!type)
@@ -533,15 +611,35 @@ cast:
dinfo->value_ranges = rl;
}
+static int rl_is_sane(struct range_list *rl)
+{
+ struct data_range *tmp;
+ struct symbol *type;
+
+ type = rl_type(rl);
+ FOR_EACH_PTR(rl, tmp) {
+ if (!sval_fits(type, tmp->min))
+ return 0;
+ if (!sval_fits(type, tmp->max))
+ return 0;
+ if (sval_cmp(tmp->min, tmp->max) > 0)
+ return 0;
+ } END_FOR_EACH_PTR(tmp);
+
+ return 1;
+}
+
void str_to_rl(struct symbol *type, char *value, struct range_list **rl)
{
struct data_info dinfo = {};
str_to_dinfo(NULL, type, value, &dinfo);
+ if (!rl_is_sane(dinfo.value_ranges))
+ dinfo.value_ranges = alloc_whole_rl(type);
*rl = dinfo.value_ranges;
}
-void call_results_to_rl(struct expression *expr, struct symbol *type, char *value, struct range_list **rl)
+void call_results_to_rl(struct expression *expr, struct symbol *type, const char *value, struct range_list **rl)
{
struct data_info dinfo = {};
@@ -561,6 +659,25 @@ int is_whole_rl(struct range_list *rl)
return 0;
}
+int is_unknown_ptr(struct range_list *rl)
+{
+ struct data_range *drange;
+ int cnt = 0;
+
+ if (is_whole_rl(rl))
+ return 1;
+
+ FOR_EACH_PTR(rl, drange) {
+ if (++cnt >= 3)
+ return 0;
+ if (sval_cmp(drange->min, valid_ptr_min_sval) == 0 &&
+ sval_cmp(drange->max, valid_ptr_max_sval) == 0)
+ return 1;
+ } END_FOR_EACH_PTR(drange);
+
+ return 0;
+}
+
int is_whole_rl_non_zero(struct range_list *rl)
{
struct data_range *drange;
@@ -672,6 +789,55 @@ struct range_list *alloc_whole_rl(struct symbol *type)
return alloc_rl(sval_type_min(type), sval_type_max(type));
}
+static bool collapse_pointer_rl(struct range_list **rl, sval_t min, sval_t max)
+{
+ struct range_list *new_rl = NULL;
+ struct data_range *tmp;
+ static bool recurse;
+ bool ret = false;
+ int cnt = 0;
+
+ /*
+ * With the mtag work, then we end up getting huge lists of mtags.
+ * That seems cool, but the problem is that we can only store about
+ * 8-10 mtags in the DB before we truncate the list. Also the mtags
+ * aren't really used at all so it's a waste of resources for now...
+ * In the future, we maybe will revisit this code.
+ *
+ */
+
+ if (recurse)
+ return false;
+ recurse = true;
+ if (!type_is_ptr(min.type))
+ goto out;
+
+ if (ptr_list_size((struct ptr_list *)*rl) < 8)
+ goto out;
+ FOR_EACH_PTR(*rl, tmp) {
+ if (!is_err_ptr(tmp->min))
+ cnt++;
+ } END_FOR_EACH_PTR(tmp);
+ if (cnt < 8)
+ goto out;
+
+ FOR_EACH_PTR(*rl, tmp) {
+ if (sval_cmp(tmp->min, valid_ptr_min_sval) >= 0 &&
+ sval_cmp(tmp->max, valid_ptr_max_sval) <= 0)
+ add_range(&new_rl, valid_ptr_min_sval, valid_ptr_max_sval);
+ else
+ add_range(&new_rl, tmp->min, tmp->max);
+ } END_FOR_EACH_PTR(tmp);
+
+ add_range(&new_rl, min, max);
+
+ *rl = new_rl;
+ ret = true;
+out:
+ recurse = false;
+ return ret;
+}
+
extern int rl_ptrlist_hack;
void add_range(struct range_list **list, sval_t min, sval_t max)
{
@@ -712,6 +878,9 @@ void add_range(struct range_list **list, sval_t min, sval_t max)
max = sval_type_max(min.type);
}
+ if (collapse_pointer_rl(list, min, max))
+ return;
+
/*
* FIXME: This has a problem merging a range_list like: min-0,3-max
* with a range like 1-2. You end up with min-2,3-max instead of
@@ -1219,21 +1388,15 @@ struct range_list *rl_truncate_cast(struct symbol *type, struct range_list *rl)
return ret;
}
-static int rl_is_sane(struct range_list *rl)
+int rl_fits_in_type(struct range_list *rl, struct symbol *type)
{
- struct data_range *tmp;
- struct symbol *type;
-
- type = rl_type(rl);
- FOR_EACH_PTR(rl, tmp) {
- if (!sval_fits(type, tmp->min))
- return 0;
- if (!sval_fits(type, tmp->max))
- return 0;
- if (sval_cmp(tmp->min, tmp->max) > 0)
- return 0;
- } END_FOR_EACH_PTR(tmp);
-
+ if (type_bits(rl_type(rl)) <= type_bits(type))
+ return 1;
+ if (sval_cmp(rl_max(rl), sval_type_max(type)) > 0)
+ return 0;
+ if (sval_is_negative(rl_min(rl)) &&
+ sval_cmp(rl_min(rl), sval_type_min(type)) < 0)
+ return 0;
return 1;
}
@@ -1310,64 +1473,76 @@ struct range_list *cast_rl(struct symbol *type, struct range_list *rl)
return ret;
}
-struct range_list *rl_invert(struct range_list *orig)
+struct range_list *rl_filter(struct range_list *rl, struct range_list *filter)
{
- struct range_list *ret = NULL;
struct data_range *tmp;
- sval_t gap_min, abs_max, sval;
- if (!orig)
- return NULL;
- if (type_bits(rl_type(orig)) < 0) /* void type mostly */
- return NULL;
-
- gap_min = sval_type_min(rl_min(orig).type);
- abs_max = sval_type_max(rl_max(orig).type);
-
- FOR_EACH_PTR(orig, tmp) {
- if (sval_cmp(tmp->min, gap_min) > 0) {
- sval = sval_type_val(tmp->min.type, tmp->min.value - 1);
- add_range(&ret, gap_min, sval);
- }
- if (sval_cmp(tmp->max, abs_max) == 0)
- return ret;
- gap_min = sval_type_val(tmp->max.type, tmp->max.value + 1);
+ FOR_EACH_PTR(filter, tmp) {
+ rl = remove_range(rl, tmp->min, tmp->max);
} END_FOR_EACH_PTR(tmp);
- if (sval_cmp(gap_min, abs_max) <= 0)
- add_range(&ret, gap_min, abs_max);
-
- return ret;
+ return rl;
}
-struct range_list *rl_filter(struct range_list *rl, struct range_list *filter)
+struct range_list *do_intersection(struct range_list *one_rl, struct range_list *two_rl)
{
- struct data_range *tmp;
+ struct data_range *one, *two;
+ struct range_list *ret = NULL;
- FOR_EACH_PTR(filter, tmp) {
- rl = remove_range(rl, tmp->min, tmp->max);
- } END_FOR_EACH_PTR(tmp);
- return rl;
+ PREPARE_PTR_LIST(one_rl, one);
+ PREPARE_PTR_LIST(two_rl, two);
+
+ while (true) {
+ if (!one || !two)
+ break;
+ if (sval_cmp(one->max, two->min) < 0) {
+ NEXT_PTR_LIST(one);
+ continue;
+ }
+ if (sval_cmp(one->min, two->min) < 0 && sval_cmp(one->max, two->max) <= 0) {
+ add_range(&ret, two->min, one->max);
+ NEXT_PTR_LIST(one);
+ continue;
+ }
+ if (sval_cmp(one->min, two->min) >= 0 && sval_cmp(one->max, two->max) <= 0) {
+ add_range(&ret, one->min, one->max);
+ NEXT_PTR_LIST(one);
+ continue;
+ }
+ if (sval_cmp(one->min, two->min) < 0 && sval_cmp(one->max, two->max) > 0) {
+ add_range(&ret, two->min, two->max);
+ NEXT_PTR_LIST(two);
+ continue;
+ }
+ if (sval_cmp(one->min, two->max) <= 0 && sval_cmp(one->max, two->max) > 0) {
+ add_range(&ret, one->min, two->max);
+ NEXT_PTR_LIST(two);
+ continue;
+ }
+ if (sval_cmp(one->min, two->max) <= 0) {
+ sm_fatal("error calculating intersection of '%s' and '%s'", show_rl(one_rl), show_rl(two_rl));
+ return NULL;
+ }
+ NEXT_PTR_LIST(two);
+ }
+
+ FINISH_PTR_LIST(two);
+ FINISH_PTR_LIST(one);
+
+ return ret;
}
struct range_list *rl_intersection(struct range_list *one, struct range_list *two)
{
- struct range_list *one_orig;
- struct range_list *two_orig;
struct range_list *ret;
struct symbol *ret_type;
struct symbol *small_type;
struct symbol *large_type;
- if (!two)
- return NULL;
- if (!one)
+ if (!one || !two)
return NULL;
- one_orig = one;
- two_orig = two;
-
ret_type = rl_type(one);
small_type = rl_type(one);
large_type = rl_type(two);
@@ -1380,23 +1555,7 @@ struct range_list *rl_intersection(struct range_list *one, struct range_list *tw
one = cast_rl(large_type, one);
two = cast_rl(large_type, two);
- ret = one;
- one = rl_invert(one);
- two = rl_invert(two);
-
- ret = rl_filter(ret, one);
- ret = rl_filter(ret, two);
-
- one = cast_rl(small_type, one_orig);
- two = cast_rl(small_type, two_orig);
-
- one = rl_invert(one);
- two = rl_invert(two);
-
- ret = cast_rl(small_type, ret);
- ret = rl_filter(ret, one);
- ret = rl_filter(ret, two);
-
+ ret = do_intersection(one, two);
return cast_rl(ret_type, ret);
}
@@ -1520,10 +1679,39 @@ static struct range_list *handle_divide_rl(struct range_list *left, struct range
return rl_union(ret, pos_pos);
}
+static struct range_list *ptr_add_mult(struct range_list *left, int op, struct range_list *right)
+{
+ struct range_list *ret;
+ sval_t l_sval, r_sval, res;
+
+ /*
+ * This function is sort of the wrong API because it takes two pointer
+ * and adds them together. The caller is expected to figure out
+ * alignment. Neither of those are the correct things to do.
+ *
+ * Really this function is quite bogus...
+ */
+
+ if (rl_to_sval(left, &l_sval) && rl_to_sval(right, &r_sval)) {
+ res = sval_binop(l_sval, op, r_sval);
+ return alloc_rl(res, res);
+ }
+
+ if (rl_min(left).value != 0 || rl_max(right).value != 0) {
+ ret = alloc_rl(valid_ptr_min_sval, valid_ptr_max_sval);
+ return cast_rl(rl_type(left), ret);
+ }
+
+ return alloc_whole_rl(rl_type(left));
+}
+
static struct range_list *handle_add_mult_rl(struct range_list *left, int op, struct range_list *right)
{
sval_t min, max;
+ if (type_is_ptr(rl_type(left)) || type_is_ptr(rl_type(right)))
+ return ptr_add_mult(left, op, right);
+
if (sval_binop_overflows(rl_min(left), op, rl_min(right)))
return NULL;
min = sval_binop(rl_min(left), op, rl_min(right));
@@ -1645,25 +1833,155 @@ static struct range_list *handle_XOR_rl(struct range_list *left, struct range_li
return cast_rl(rl_type(left), alloc_rl(zero, max));
}
+static sval_t sval_lowest_set_bit(sval_t sval)
+{
+ sval_t ret = { .type = sval.type };
+ int i;
+
+ for (i = 0; i < 64; i++) {
+ if (sval.uvalue & 1ULL << i) {
+ ret.uvalue = (1ULL << i);
+ return ret;
+ }
+ }
+ return ret;
+}
+
+static struct range_list *handle_AND_rl_sval(struct range_list *rl, sval_t sval)
+{
+ struct range_list *known_rl;
+ sval_t zero = { 0 };
+ sval_t min;
+
+ zero.type = sval.type;
+ zero.value = 0;
+
+ if (sm_fls64(rl_max(rl).uvalue) < find_first_zero_bit(sval.uvalue) &&
+ sm_fls64(rl_min(rl).uvalue) < find_first_zero_bit(sval.uvalue))
+ return rl;
+
+ min = sval_lowest_set_bit(sval);
+
+ if (min.value != 0) {
+ sval_t max, mod;
+
+ max = rl_max(rl);
+ mod = sval_binop(max, '%', min);
+ if (mod.value) {
+ max = sval_binop(max, '-', mod);
+ max.value++;
+ if (max.value > 0 && sval_cmp(max, rl_max(rl)) < 0)
+ rl = remove_range(rl, max, rl_max(rl));
+ }
+ }
+
+ known_rl = alloc_rl(min, sval);
+
+ rl = rl_intersection(rl, known_rl);
+ zero = rl_min(rl);
+ zero.value = 0;
+ add_range(&rl, zero, zero);
+
+ return rl;
+}
+
+static struct range_list *fudge_AND_rl(struct range_list *rl)
+{
+ struct range_list *ret;
+ sval_t min;
+
+ min = sval_lowest_set_bit(rl_min(rl));
+ ret = clone_rl(rl);
+ add_range(&ret, min, rl_min(rl));
+
+ return ret;
+}
+
static struct range_list *handle_AND_rl(struct range_list *left, struct range_list *right)
{
- unsigned long long left_set, left_maybe;
- unsigned long long right_set, right_maybe;
- sval_t zero, max;
+ sval_t sval, zero;
+ struct range_list *rl;
- return NULL;
+ if (rl_to_sval(left, &sval))
+ return handle_AND_rl_sval(right, sval);
+ if (rl_to_sval(right, &sval))
+ return handle_AND_rl_sval(left, sval);
- left_set = rl_bits_always_set(left);
- left_maybe = rl_bits_maybe_set(left);
+ left = fudge_AND_rl(left);
+ right = fudge_AND_rl(right);
- right_set = rl_bits_always_set(right);
- right_maybe = rl_bits_maybe_set(right);
+ rl = rl_intersection(left, right);
+ zero = rl_min(rl);
+ zero.value = 0;
+ add_range(&rl, zero, zero);
- zero = max = rl_min(left);
- zero.uvalue = 0;
- max.uvalue = fls_mask((left_maybe | right_maybe) ^ (left_set & right_set));
+ return rl;
+}
- return cast_rl(rl_type(left), alloc_rl(zero, max));
+static struct range_list *handle_lshift(struct range_list *left_orig, struct range_list *right_orig)
+{
+ struct range_list *left;
+ struct data_range *tmp;
+ struct range_list *ret = NULL;
+ sval_t zero = { .type = rl_type(left_orig), };
+ sval_t shift, min, max;
+ bool add_zero = false;
+
+ if (!rl_to_sval(right_orig, &shift) || sval_is_negative(shift))
+ return NULL;
+ if (shift.value == 0)
+ return left_orig;
+
+ /* Cast to unsigned for easier left shift math */
+ if (type_positive_bits(rl_type(left_orig)) < 32)
+ left = cast_rl(&uint_ctype, left_orig);
+ else if(type_positive_bits(rl_type(left_orig)) == 63)
+ left = cast_rl(&ullong_ctype, left_orig);
+ else
+ left = left_orig;
+
+ FOR_EACH_PTR(left, tmp) {
+ min = tmp->min;
+ max = tmp->max;
+
+ if (min.value == 0 || max.value > sval_type_max(max.type).uvalue >> shift.uvalue)
+ add_zero = true;
+ if (min.value == 0 && max.value == 0)
+ continue;
+ if (min.value == 0)
+ min.value = 1;
+ min = sval_binop(min, SPECIAL_LEFTSHIFT, shift);
+ max = sval_binop(max, SPECIAL_LEFTSHIFT, shift);
+ add_range(&ret, min, max);
+ } END_FOR_EACH_PTR(tmp);
+
+ if (!rl_fits_in_type(ret, rl_type(left_orig)))
+ add_zero = true;
+ ret = cast_rl(rl_type(left_orig), ret);
+ if (add_zero)
+ add_range(&ret, zero, zero);
+
+ return ret;
+}
+
+static struct range_list *handle_rshift(struct range_list *left_orig, struct range_list *right_orig)
+{
+ struct data_range *tmp;
+ struct range_list *ret = NULL;
+ sval_t shift, min, max;
+
+ if (!rl_to_sval(right_orig, &shift) || sval_is_negative(shift))
+ return NULL;
+ if (shift.value == 0)
+ return left_orig;
+
+ FOR_EACH_PTR(left_orig, tmp) {
+ min = sval_binop(tmp->min, SPECIAL_RIGHTSHIFT, shift);
+ max = sval_binop(tmp->max, SPECIAL_RIGHTSHIFT, shift);
+ add_range(&ret, min, max);
+ } END_FOR_EACH_PTR(tmp);
+
+ return ret;
}
struct range_list *rl_binop(struct range_list *left, int op, struct range_list *right)
@@ -1712,10 +2030,10 @@ struct range_list *rl_binop(struct range_list *left, int op, struct range_list *
case '-':
ret = handle_sub_rl(left, right);
break;
- /* FIXME: Do the rest as well */
case SPECIAL_RIGHTSHIFT:
+ return handle_rshift(left, right);
case SPECIAL_LEFTSHIFT:
- break;
+ return handle_lshift(left, right);
}
return ret;
diff --git a/usr/src/tools/smatch/src/smatch_real_absolute.c b/usr/src/tools/smatch/src/smatch_real_absolute.c
index 96cf6b4aa7..dd6c5581dd 100644
--- a/usr/src/tools/smatch/src/smatch_real_absolute.c
+++ b/usr/src/tools/smatch/src/smatch_real_absolute.c
@@ -103,6 +103,9 @@ static void match_assign(struct expression *expr)
type = get_type(expr->left);
if (!type)
return;
+ if (type->type != SYM_PTR && type->type != SYM_BASETYPE &&
+ type->type != SYM_ENUM)
+ return;
rl = cast_rl(type, rl);
if (is_whole_rl(rl) && !get_state_expr(my_id, expr->left))
@@ -128,6 +131,7 @@ void register_real_absolute(int id)
{
my_id = id;
+ set_dynamic_states(my_id);
add_pre_merge_hook(my_id, &pre_merge_hook);
add_unmatched_state_hook(my_id, &empty_state);
add_merge_hook(my_id, &merge_estates);
diff --git a/usr/src/tools/smatch/src/smatch_return_to_param.c b/usr/src/tools/smatch/src/smatch_return_to_param.c
index 220d24f1f9..ec8e3a9cc5 100644
--- a/usr/src/tools/smatch/src/smatch_return_to_param.c
+++ b/usr/src/tools/smatch/src/smatch_return_to_param.c
@@ -56,7 +56,7 @@ char *map_call_to_other_name_sym(const char *name, struct symbol *sym, struct sy
char buf[256];
/* skip 'foo->'. This was checked in the caller. */
- skip = strlen(sym->ident->name) + 2;
+ skip = sym->ident->len + 2;
state = get_state(my_id, sym->ident->name, sym);
if (!state || !state->data)
@@ -87,46 +87,6 @@ static char *map_my_state_long_to_short(struct sm_state *sm, const char *name, s
return alloc_string(buf);
}
-static char *map_assignment_long_to_short(struct sm_state *sm, const char *name, struct symbol *sym, struct symbol **new_sym, bool stack)
-{
- struct expression *orig_expr;
- struct symbol *orig_sym;
- int len;
- char buf[256];
-
- orig_expr = sm->state->data;
- if (!orig_expr)
- return NULL;
-
- /*
- * Say we have an assignment like:
- * foo->bar->my_ptr = my_ptr;
- * We still expect the function to carry on using "my_ptr" as the
- * shorter name. That's not a long to short mapping.
- *
- */
- if (orig_expr->type == EXPR_SYMBOL)
- return NULL;
-
- orig_sym = expr_to_sym(orig_expr);
- if (!orig_sym)
- return NULL;
- if (sym != orig_sym)
- return NULL;
-
- len = strlen(sm->state->name);
- if (strncmp(name, sm->state->name, len) != 0)
- return NULL;
-
- if (name[len] == '.')
- return NULL;
- if (!stack && name[len] != '-')
- return NULL;
- snprintf(buf, sizeof(buf), "%s%s", sm->name, name + len);
- *new_sym = sm->sym;
- return alloc_string(buf);
-}
-
/*
* Normally, we expect people to consistently refer to variables by the shortest
* name. So they use "b->a" instead of "foo->bar.a" when both point to the
@@ -136,7 +96,7 @@ static char *map_assignment_long_to_short(struct sm_state *sm, const char *name,
* which in turn updates the longer name.
*
*/
-static char *map_long_to_short_name_sym_helper(const char *name, struct symbol *sym, struct symbol **new_sym, bool stack)
+char *map_long_to_short_name_sym(const char *name, struct symbol *sym, struct symbol **new_sym, bool use_stack)
{
char *ret;
struct sm_state *sm;
@@ -145,15 +105,13 @@ static char *map_long_to_short_name_sym_helper(const char *name, struct symbol *
FOR_EACH_SM(__get_cur_stree(), sm) {
if (sm->owner == my_id) {
- ret = map_my_state_long_to_short(sm, name, sym, new_sym, stack);
- if (ret)
- return ret;
- continue;
- }
- if (sm->owner == check_assigned_expr_id) {
- ret = map_assignment_long_to_short(sm, name, sym, new_sym, stack);
- if (ret)
+ ret = map_my_state_long_to_short(sm, name, sym, new_sym, use_stack);
+ if (ret) {
+ if (local_debug)
+ sm_msg("%s: my_state: name = '%s' sm = '%s'",
+ __func__, name, show_sm(sm));
return ret;
+ }
continue;
}
} END_FOR_EACH_SM(sm);
@@ -161,16 +119,6 @@ static char *map_long_to_short_name_sym_helper(const char *name, struct symbol *
return NULL;
}
-char *map_long_to_short_name_sym(const char *name, struct symbol *sym, struct symbol **new_sym)
-{
- return map_long_to_short_name_sym_helper(name, sym, new_sym, 1);
-}
-
-char *map_long_to_short_name_sym_nostack(const char *name, struct symbol *sym, struct symbol **new_sym)
-{
- return map_long_to_short_name_sym_helper(name, sym, new_sym, 0);
-}
-
char *map_call_to_param_name_sym(struct expression *expr, struct symbol **sym)
{
char *name;
@@ -280,6 +228,7 @@ free:
void register_return_to_param(int id)
{
my_id = id;
+ set_dynamic_states(my_id);
add_modification_hook(my_id, &undef);
}
diff --git a/usr/src/tools/smatch/src/smatch_returns.c b/usr/src/tools/smatch/src/smatch_returns.c
index 5c7157cf1f..e04406f225 100644
--- a/usr/src/tools/smatch/src/smatch_returns.c
+++ b/usr/src/tools/smatch/src/smatch_returns.c
@@ -130,6 +130,7 @@ void register_returns_early(int id)
{
RETURN_ID = id;
+ set_dynamic_states(RETURN_ID);
add_split_return_callback(match_return);
}
diff --git a/usr/src/tools/smatch/src/smatch_scripts/build_kernel_data.sh b/usr/src/tools/smatch/src/smatch_scripts/build_kernel_data.sh
index cacf065e0a..9f470738e6 100755
--- a/usr/src/tools/smatch/src/smatch_scripts/build_kernel_data.sh
+++ b/usr/src/tools/smatch/src/smatch_scripts/build_kernel_data.sh
@@ -35,7 +35,8 @@ if [ ! -e smatch_db.sqlite ] ; then
fi
fi
-$SCRIPT_DIR/test_kernel.sh --call-tree --info --param-mapper --spammy --data=$DATA_DIR
+BUILD_STATUS=0
+$SCRIPT_DIR/test_kernel.sh --call-tree --info --param-mapper --spammy --data=$DATA_DIR || BUILD_STATUS=$?
for i in $SCRIPT_DIR/gen_* ; do
$i smatch_warns.txt -p=kernel
@@ -45,3 +46,4 @@ mv ${PROJECT}.* $DATA_DIR
$DATA_DIR/db/create_db.sh -p=kernel smatch_warns.txt
+exit $BUILD_STATUS
diff --git a/usr/src/tools/smatch/src/smatch_scripts/kpatch.sh b/usr/src/tools/smatch/src/smatch_scripts/kpatch.sh
index 1dcbd93061..42b2f31bb9 100755
--- a/usr/src/tools/smatch/src/smatch_scripts/kpatch.sh
+++ b/usr/src/tools/smatch/src/smatch_scripts/kpatch.sh
@@ -4,7 +4,7 @@ TMP_DIR=/tmp
help()
{
- echo "Usage: $0 [--no-compile|--ammend] <filename>"
+ echo "Usage: $0 [--no-compile|--amend] <filename>"
echo "You must be at the base of the kernel tree to run this."
exit 1
}
@@ -37,7 +37,7 @@ while true ; do
if [[ "$1" == "--no-compile" ]] ; then
NO_COMPILE=true
shift
- elif [[ "$1" == "--ammend" ]] ; then
+ elif [[ "$1" == "--amend" ]] ; then
AMEND="--amend"
shift
else
@@ -53,7 +53,11 @@ fullname=$1
filename=$(basename $fullname)
oname=$(echo ${fullname/.c/.o})
-MAIL_FILE=$TMP_DIR/${filename}.msg
+MSG_FILE=$TMP_DIR/${filename}.msg
+MAIL_FILE=$TMP_DIR/${filename}.mail
+
+# heat up the disk cache
+#git log --oneline $fullname | head -n 10 > /dev/null &
echo "QC checklist"
qc "Have you handled all the errors properly?"
@@ -71,15 +75,29 @@ if [ "$NO_COMPILE" != "true" ] ; then
# make C=1 CHECK="scripts/coccicheck" $oname
fi
-grepmail $fullname ~/var/mail/sent* | grep -i ^subject || echo -n ""
+for file in $(grep -l $fullname ~/var/mail/sent-*) ; do
+ grepmail $fullname $file | grep -i ^subject || echo -n ""
+done
qc "Looks OK?"
-git log --oneline $fullname | head -n 10
-echo "Copy and paste one of these subjects?"
-read unused
-
git add $fullname
-git commit --signoff $AMEND
+
+cat /dev/null > $MSG_FILE
+if [ "$AMEND" != "" ] ; then
+ git format-patch HEAD^ --stdout >> $MSG_FILE
+else
+ echo "" >> $MSG_FILE
+ echo "Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>" >> $MSG_FILE
+ echo "" >> $MSG_FILE
+ echo "# $sm_err" >> $MSG_FILE
+fi
+git log -10 --oneline $fullname | sed -e 's/^/# /' >> $MSG_FILE
+vim $MSG_FILE
+
+grep -v '^#' $MSG_FILE > $MSG_FILE.1
+mv $MSG_FILE.1 $MSG_FILE
+
+git commit $AMEND -F $MSG_FILE
to_addr=$(./scripts/get_maintainer.pl -f --noroles --norolestats $fullname | head -n 1)
cc_addr=$(./scripts/get_maintainer.pl -f --noroles --norolestats $fullname | tail -n +2 | \
diff --git a/usr/src/tools/smatch/src/smatch_scripts/test_kernel.sh b/usr/src/tools/smatch/src/smatch_scripts/test_kernel.sh
index 2beaf88e0c..b31c61047c 100755
--- a/usr/src/tools/smatch/src/smatch_scripts/test_kernel.sh
+++ b/usr/src/tools/smatch/src/smatch_scripts/test_kernel.sh
@@ -41,6 +41,10 @@ while true ; do
fi
done
+# receive parameters from environment, which override
+[ -z "${SMATCH_ENV_TARGET:-}" ] || TARGET="$SMATCH_ENV_TARGET"
+[ -z "${SMATCH_ENV_BUILD_PARAM:-}" ] || BUILD_PARAM="$SMATCH_ENV_BUILD_PARAM"
+
SCRIPT_DIR=$(dirname $0)
if [ -e $SCRIPT_DIR/../smatch ] ; then
cp $SCRIPT_DIR/../smatch $SCRIPT_DIR/../bak.smatch
@@ -55,9 +59,11 @@ fi
make clean
find -name \*.c.smatch -exec rm \{\} \;
make -j${NR_CPU} $ENDIAN -k CHECK="$CMD -p=kernel --file-output --succeed $*" \
- C=1 $TARGET 2>&1 | tee $LOG
+ C=1 $BUILD_PARAM $TARGET 2>&1 | tee $LOG
+BUILD_STATUS=${PIPESTATUS[0]}
find -name \*.c.smatch -exec cat \{\} \; -exec rm \{\} \; > $WLOG
find -name \*.c.smatch.sql -exec cat \{\} \; -exec rm \{\} \; > $WLOG.sql
find -name \*.c.smatch.caller_info -exec cat \{\} \; -exec rm \{\} \; > $WLOG.caller_info
-echo "Done. The warnings are saved to $WLOG"
+echo "Done. Build with status $BUILD_STATUS. The warnings are saved to $WLOG"
+exit $BUILD_STATUS
diff --git a/usr/src/tools/smatch/src/smatch_slist.c b/usr/src/tools/smatch/src/smatch_slist.c
index ab0ca19d64..ef00465593 100644
--- a/usr/src/tools/smatch/src/smatch_slist.c
+++ b/usr/src/tools/smatch/src/smatch_slist.c
@@ -96,9 +96,9 @@ int cmp_tracker(const struct sm_state *a, const struct sm_state *b)
if (!a)
return 1;
- if (a->owner > b->owner)
- return -1;
if (a->owner < b->owner)
+ return -1;
+ if (a->owner > b->owner)
return 1;
ret = strcmp(a->name, b->name);
@@ -119,38 +119,67 @@ int cmp_tracker(const struct sm_state *a, const struct sm_state *b)
return 0;
}
-static int cmp_sm_states(const struct sm_state *a, const struct sm_state *b, int preserve)
+int *dynamic_states;
+void allocate_dynamic_states_array(int num_checks)
+{
+ dynamic_states = calloc(num_checks + 1, sizeof(int));
+}
+
+void set_dynamic_states(unsigned short owner)
+{
+ dynamic_states[owner] = true;
+}
+
+bool has_dynamic_states(unsigned short owner)
+{
+ if (owner >= num_checks)
+ return false;
+ return dynamic_states[owner];
+}
+
+static int cmp_possible_sm(const struct sm_state *a, const struct sm_state *b, int preserve)
{
int ret;
- ret = cmp_tracker(a, b);
- if (ret)
- return ret;
+ if (a == b)
+ return 0;
- /* todo: add hook for smatch_extra.c */
- if (a->state > b->state)
- return -1;
- if (a->state < b->state)
- return 1;
- /* This is obviously a massive disgusting hack but we need to preserve
- * the unmerged states for smatch extra because we use them in
- * smatch_db.c. Meanwhile if we preserve all the other unmerged states
- * then it uses a lot of memory and we don't use it. Hence this hack.
- *
- * Also sometimes even just preserving every possible SMATCH_EXTRA state
- * takes too much resources so we have to cap that. Capping is probably
- * not often a problem in real life.
- */
- if (a->owner == SMATCH_EXTRA && preserve) {
- if (a == b)
- return 0;
- if (a->merged == 1 && b->merged == 0)
+ if (!has_dynamic_states(a->owner)) {
+ if (a->state > b->state)
return -1;
- if (a->merged == 0)
+ if (a->state < b->state)
return 1;
+ return 0;
}
- return 0;
+ if (a->owner == SMATCH_EXTRA) {
+ /*
+ * In Smatch extra you can have borrowed implications.
+ *
+ * FIXME: review how borrowed implications work and if they
+ * are the best way. See also smatch_implied.c.
+ *
+ */
+ ret = cmp_tracker(a, b);
+ if (ret)
+ return ret;
+
+ /*
+ * We want to preserve leaf states. They're use to split
+ * returns in smatch_db.c.
+ *
+ */
+ if (preserve) {
+ if (a->merged && !b->merged)
+ return -1;
+ if (!a->merged)
+ return 1;
+ }
+ }
+ if (!a->state->name || !b->state->name)
+ return 0;
+
+ return strcmp(a->state->name, b->state->name);
}
struct sm_state *alloc_sm_state(int owner, const char *name,
@@ -169,7 +198,6 @@ struct sm_state *alloc_sm_state(int owner, const char *name,
sm_state->pool = NULL;
sm_state->left = NULL;
sm_state->right = NULL;
- sm_state->nr_children = 1;
sm_state->possible = NULL;
add_ptr_list(&sm_state->possible, sm_state);
return sm_state;
@@ -197,14 +225,16 @@ void add_possible_sm(struct sm_state *to, struct sm_state *new)
{
struct sm_state *tmp;
int preserve = 1;
+ int cmp;
if (too_many_possible(to))
preserve = 0;
FOR_EACH_PTR(to->possible, tmp) {
- if (cmp_sm_states(tmp, new, preserve) < 0)
+ cmp = cmp_possible_sm(tmp, new, preserve);
+ if (cmp < 0)
continue;
- else if (cmp_sm_states(tmp, new, preserve) == 0) {
+ else if (cmp == 0) {
return;
} else {
INSERT_CURRENT(new, tmp);
@@ -214,11 +244,27 @@ void add_possible_sm(struct sm_state *to, struct sm_state *new)
add_ptr_list(&to->possible, new);
}
-static void copy_possibles(struct sm_state *to, struct sm_state *from)
+static void copy_possibles(struct sm_state *to, struct sm_state *one, struct sm_state *two)
{
+ struct sm_state *large = one;
+ struct sm_state *small = two;
struct sm_state *tmp;
- FOR_EACH_PTR(from->possible, tmp) {
+ /*
+ * We spend a lot of time copying the possible lists. I've tried to
+ * optimize the process a bit.
+ *
+ */
+
+ if (ptr_list_size((struct ptr_list *)two->possible) >
+ ptr_list_size((struct ptr_list *)one->possible)) {
+ large = two;
+ small = one;
+ }
+
+ to->possible = clone_slist(large->possible);
+ add_possible_sm(to, to);
+ FOR_EACH_PTR(small->possible, tmp) {
add_possible_sm(to, tmp);
} END_FOR_EACH_PTR(tmp);
}
@@ -234,8 +280,13 @@ char *alloc_sname(const char *str)
return tmp;
}
+static struct symbol *oom_func;
+static int oom_limit = 3000000; /* Start with a 3GB limit */
int out_of_memory(void)
{
+ if (oom_func)
+ return 1;
+
/*
* I decided to use 50M here based on trial and error.
* It works out OK for the kernel and so it should work
@@ -243,6 +294,25 @@ int out_of_memory(void)
*/
if (sm_state_counter * sizeof(struct sm_state) >= 100000000)
return 1;
+
+ /*
+ * We're reading from statm to figure out how much memory we
+ * are using. The problem is that at the end of the function
+ * we release the memory, so that it can be re-used but it
+ * stays in cache, it's not released to the OS. So then if
+ * we allocate memory for different purposes we can easily
+ * hit the 3GB limit on the next function, so that's why I give
+ * the next function an extra 100MB to work with.
+ *
+ */
+ if (get_mem_kb() > oom_limit) {
+ oom_func = cur_func_sym;
+ final_pass++;
+ sm_perror("OOM: %luKb sm_state_count = %d", get_mem_kb(), sm_state_counter);
+ final_pass--;
+ return 1;
+ }
+
return 0;
}
@@ -297,6 +367,10 @@ void free_every_single_sm_state(void)
free_stack_and_strees(&all_pools);
sm_state_counter = 0;
+ if (oom_func) {
+ oom_limit += 100000;
+ oom_func = NULL;
+ }
}
unsigned long get_pool_count(void)
@@ -316,7 +390,6 @@ struct sm_state *clone_sm(struct sm_state *s)
ret->possible = clone_slist(s->possible);
ret->left = s->left;
ret->right = s->right;
- ret->nr_children = s->nr_children;
return ret;
}
@@ -394,9 +467,8 @@ struct sm_state *merge_sm_states(struct sm_state *one, struct sm_state *two)
result->merged = 1;
result->left = one;
result->right = two;
- result->nr_children = one->nr_children + two->nr_children;
- copy_possibles(result, one);
- copy_possibles(result, two);
+
+ copy_possibles(result, one, two);
/*
* The ->line information is used by deref_check where we complain about
@@ -718,7 +790,7 @@ static void __merge_stree(struct stree **to, struct stree *stree, int add_pool)
struct stree *implied_two = NULL;
AvlIter one_iter;
AvlIter two_iter;
- struct sm_state *tmp_sm;
+ struct sm_state *one, *two, *res;
if (out_of_memory())
return;
@@ -761,28 +833,30 @@ static void __merge_stree(struct stree **to, struct stree *stree, int add_pool)
for (;;) {
if (!one_iter.sm || !two_iter.sm)
break;
- if (cmp_tracker(one_iter.sm, two_iter.sm) < 0) {
- sm_perror(" in %s", __func__);
- avl_iter_next(&one_iter);
- } else if (cmp_tracker(one_iter.sm, two_iter.sm) == 0) {
- if (add_pool && one_iter.sm != two_iter.sm) {
- one_iter.sm->pool = implied_one;
- if (implied_one->base_stree)
- one_iter.sm->pool = implied_one->base_stree;
- two_iter.sm->pool = implied_two;
- if (implied_two->base_stree)
- two_iter.sm->pool = implied_two->base_stree;
- }
- tmp_sm = merge_sm_states(one_iter.sm, two_iter.sm);
- add_possible_sm(tmp_sm, one_iter.sm);
- add_possible_sm(tmp_sm, two_iter.sm);
- avl_insert(&results, tmp_sm);
- avl_iter_next(&one_iter);
- avl_iter_next(&two_iter);
- } else {
- sm_perror(" in %s", __func__);
- avl_iter_next(&two_iter);
+
+ one = one_iter.sm;
+ two = two_iter.sm;
+
+ if (one == two) {
+ avl_insert(&results, one);
+ goto next;
+ }
+
+ if (add_pool) {
+ one->pool = implied_one;
+ if (implied_one->base_stree)
+ one->pool = implied_one->base_stree;
+ two->pool = implied_two;
+ if (implied_two->base_stree)
+ two->pool = implied_two->base_stree;
}
+ res = merge_sm_states(one, two);
+ add_possible_sm(res, one);
+ add_possible_sm(res, two);
+ avl_insert(&results, res);
+next:
+ avl_iter_next(&one_iter);
+ avl_iter_next(&two_iter);
}
free_stree(to);
diff --git a/usr/src/tools/smatch/src/smatch_slist.h b/usr/src/tools/smatch/src/smatch_slist.h
index 358756b25d..f08ed46332 100644
--- a/usr/src/tools/smatch/src/smatch_slist.h
+++ b/usr/src/tools/smatch/src/smatch_slist.h
@@ -96,3 +96,4 @@ void overwrite_stree(struct stree *from, struct stree **to);
void all_return_states_hook(void (*callback)(void));
+void allocate_dynamic_states_array(int num_checks);
diff --git a/usr/src/tools/smatch/src/smatch_statement_count.c b/usr/src/tools/smatch/src/smatch_statement_count.c
index 1bc6383479..282deacb1c 100644
--- a/usr/src/tools/smatch/src/smatch_statement_count.c
+++ b/usr/src/tools/smatch/src/smatch_statement_count.c
@@ -79,6 +79,7 @@ void register_statement_count(int id)
{
my_id = id;
+ set_dynamic_states(my_id);
add_hook(match_statement, STMT_HOOK);
add_merge_hook(my_id, &merge_states);
diff --git a/usr/src/tools/smatch/src/smatch_states.c b/usr/src/tools/smatch/src/smatch_states.c
index c7a9c85d2b..d3656dff5a 100644
--- a/usr/src/tools/smatch/src/smatch_states.c
+++ b/usr/src/tools/smatch/src/smatch_states.c
@@ -84,7 +84,7 @@ struct sm_state *set_state(int owner, const char *name, struct symbol *sym, stru
{
struct sm_state *ret;
- if (!name)
+ if (!name || !state)
return NULL;
if (read_only)
@@ -93,7 +93,7 @@ struct sm_state *set_state(int owner, const char *name, struct symbol *sym, stru
if (option_debug || strcmp(check_name(owner), option_debug_check) == 0) {
struct smatch_state *s;
- s = get_state(owner, name, sym);
+ s = __get_state(owner, name, sym);
if (!s)
sm_msg("%s new [%s] '%s' %s", __func__,
check_name(owner), name, show_state(state));
@@ -196,7 +196,7 @@ void __set_sm(struct sm_state *sm)
strcmp(check_name(sm->owner), option_debug_check) == 0) {
struct smatch_state *s;
- s = get_state(sm->owner, sm->name, sm->sym);
+ s = __get_state(sm->owner, sm->name, sm->sym);
if (!s)
sm_msg("%s new %s", __func__, show_sm(sm));
else
@@ -222,7 +222,7 @@ void __set_sm_cur_stree(struct sm_state *sm)
strcmp(check_name(sm->owner), option_debug_check) == 0) {
struct smatch_state *s;
- s = get_state(sm->owner, sm->name, sm->sym);
+ s = __get_state(sm->owner, sm->name, sm->sym);
if (!s)
sm_msg("%s new %s", __func__, show_sm(sm));
else
@@ -245,7 +245,7 @@ void __set_sm_fake_stree(struct sm_state *sm)
strcmp(check_name(sm->owner), option_debug_check) == 0) {
struct smatch_state *s;
- s = get_state(sm->owner, sm->name, sm->sym);
+ s = __get_state(sm->owner, sm->name, sm->sym);
if (!s)
sm_msg("%s new %s", __func__, show_sm(sm));
else
@@ -477,7 +477,7 @@ void set_true_false_states(int owner, const char *name, struct symbol *sym,
if (option_debug || strcmp(check_name(owner), option_debug_check) == 0) {
struct smatch_state *tmp;
- tmp = get_state(owner, name, sym);
+ tmp = __get_state(owner, name, sym);
sm_msg("%s [%s] '%s'. Was %s. Now T:%s F:%s", __func__,
check_name(owner), name, show_state(tmp),
show_state(true_state), show_state(false_state));
@@ -531,7 +531,7 @@ void __set_true_false_sm(struct sm_state *true_sm, struct sm_state *false_sm)
if (option_debug || strcmp(check_name(owner), option_debug_check) == 0) {
struct smatch_state *tmp;
- tmp = get_state(owner, name, sym);
+ tmp = __get_state(owner, name, sym);
sm_msg("%s [%s] '%s'. Was %s. Now T:%s F:%s", __func__,
check_name(owner), name, show_state(tmp),
show_state(true_sm ? true_sm->state : NULL),
@@ -789,7 +789,6 @@ void __negate_cond_stacks(void)
{
struct stree *old_false, *old_true;
- __use_cond_stack(&cond_false_stack);
old_false = pop_stree(&cond_false_stack);
old_true = pop_stree(&cond_true_stack);
push_stree(&cond_false_stack, old_true);
diff --git a/usr/src/tools/smatch/src/smatch_stored_conditions.c b/usr/src/tools/smatch/src/smatch_stored_conditions.c
index 07f436d416..925b86d4b1 100644
--- a/usr/src/tools/smatch/src/smatch_stored_conditions.c
+++ b/usr/src/tools/smatch/src/smatch_stored_conditions.c
@@ -238,11 +238,14 @@ struct expression_list *get_conditions(struct expression *expr)
void register_stored_conditions(int id)
{
my_id = id;
+ set_dynamic_states(my_id);
}
void register_stored_conditions_links(int id)
{
link_id = id;
+ db_ignore_states(link_id);
+ set_dynamic_states(link_id);
add_merge_hook(link_id, &merge_links);
add_modification_hook(link_id, &match_link_modify);
}
diff --git a/usr/src/tools/smatch/src/smatch_string_list.c b/usr/src/tools/smatch/src/smatch_string_list.c
index 832ef7b938..cf8e21ca00 100644
--- a/usr/src/tools/smatch/src/smatch_string_list.c
+++ b/usr/src/tools/smatch/src/smatch_string_list.c
@@ -20,37 +20,42 @@
int list_has_string(struct string_list *str_list, const char *str)
{
char *tmp;
+ int cmp;
if (!str)
return 0;
FOR_EACH_PTR(str_list, tmp) {
- if (strcmp(tmp, str) < 0)
+ cmp = strcmp(tmp, str);
+ if (cmp < 0)
continue;
- if (strcmp(tmp, str) == 0)
+ if (cmp == 0)
return 1;
return 0;
} END_FOR_EACH_PTR(tmp);
return 0;
}
-void insert_string(struct string_list **str_list, const char *_new)
+int insert_string(struct string_list **str_list, const char *_new)
{
char *new = (char *)_new;
char *tmp;
+ int cmp;
FOR_EACH_PTR(*str_list, tmp) {
- if (strcmp(tmp, new) < 0)
+ cmp = strcmp(tmp, new);
+ if (cmp < 0)
continue;
- else if (strcmp(tmp, new) == 0) {
- return;
+ else if (cmp == 0) {
+ return 0;
} else {
INSERT_CURRENT(alloc_string(new), tmp);
- return;
+ return 1;
}
} END_FOR_EACH_PTR(tmp);
new = alloc_string(new);
add_ptr_list(str_list, new);
+ return 1;
}
struct string_list *clone_str_list(struct string_list *orig)
diff --git a/usr/src/tools/smatch/src/smatch_strlen.c b/usr/src/tools/smatch/src/smatch_strlen.c
index 145d32ad39..b69faf4bad 100644
--- a/usr/src/tools/smatch/src/smatch_strlen.c
+++ b/usr/src/tools/smatch/src/smatch_strlen.c
@@ -333,6 +333,8 @@ void register_strlen(int id)
{
my_strlen_id = id;
+ set_dynamic_states(my_strlen_id);
+
add_unmatched_state_hook(my_strlen_id, &unmatched_strlen_state);
select_caller_info_hook(set_param_strlen, STR_LEN);
@@ -354,6 +356,7 @@ void register_strlen(int id)
void register_strlen_equiv(int id)
{
my_equiv_id = id;
+ set_dynamic_states(my_equiv_id);
add_function_assign_hook("strlen", &match_strlen, NULL);
add_modification_hook(my_equiv_id, &set_strlen_equiv_undefined);
}
diff --git a/usr/src/tools/smatch/src/smatch_struct_assignment.c b/usr/src/tools/smatch/src/smatch_struct_assignment.c
index 414f5af770..7fcd631e3e 100644
--- a/usr/src/tools/smatch/src/smatch_struct_assignment.c
+++ b/usr/src/tools/smatch/src/smatch_struct_assignment.c
@@ -445,6 +445,23 @@ static void match_memcpy(const char *fn, struct expression *expr, void *_arg)
__struct_members_copy(COPY_MEMCPY, expr, remove_addr(dest), remove_addr(src));
}
+static void match_memdup(const char *fn, struct expression *call_expr,
+ struct expression *expr, void *_unused)
+{
+ struct expression *left, *right, *arg;
+
+ if (!expr || expr->type != EXPR_ASSIGNMENT)
+ return;
+
+ left = strip_expr(expr->left);
+ right = strip_expr(expr->right);
+
+ if (right->type != EXPR_CALL)
+ return;
+ arg = get_argument_from_call_expr(right->args, 0);
+ __struct_members_copy(COPY_MEMCPY, expr, left, arg);
+}
+
static void match_memcpy_unknown(const char *fn, struct expression *expr, void *_arg)
{
struct expression *dest;
@@ -548,6 +565,9 @@ void register_struct_assignment(int id)
add_function_hook("__memcpy", &match_memcpy, INT_PTR(0));
add_function_hook("__memmove", &match_memcpy, INT_PTR(0));
+ if (option_project == PROJ_KERNEL)
+ return_implies_state_sval("kmemdup", valid_ptr_min_sval, valid_ptr_max_sval, &match_memdup, NULL);
+
add_function_hook("sscanf", &match_sscanf, NULL);
add_hook(&unop_expr, OP_HOOK);
diff --git a/usr/src/tools/smatch/src/smatch_sval.c b/usr/src/tools/smatch/src/smatch_sval.c
index a3a5cc7a02..6fe29cdab7 100644
--- a/usr/src/tools/smatch/src/smatch_sval.c
+++ b/usr/src/tools/smatch/src/smatch_sval.c
@@ -67,7 +67,7 @@ sval_t sval_type_val(struct symbol *type, long long val)
sval_t ret;
if (!type)
- type = &int_ctype;
+ type = &llong_ctype;
ret.type = type;
ret.value = val;
@@ -94,6 +94,8 @@ int sval_is_ptr(sval_t sval)
int sval_unsigned(sval_t sval)
{
+ if (is_ptr_type(sval.type))
+ return true;
return type_unsigned(sval.type);
}
@@ -231,7 +233,7 @@ int sval_too_low(struct symbol *type, sval_t sval)
{
if (sval_is_negative(sval) && type_unsigned(type))
return 1;
- if (type_signed(type) && sval_unsigned(sval))
+ if (type_signed(type) && sval_unsigned(sval))
return 0;
if (type_signed(sval.type) &&
sval.value < sval_type_min(type).value)
@@ -458,6 +460,8 @@ static sval_t ptr_binop(struct symbol *type, sval_t left, int op, sval_t right)
}
}
+ if (op == '-')
+ ret.type = ssize_t_ctype;
return ret;
}
@@ -583,15 +587,34 @@ int sval_binop_overflows_no_sign(sval_t left, int op, sval_t right)
return sval_binop_overflows(left, op, right);
}
-unsigned long long fls_mask(unsigned long long uvalue)
+int find_first_zero_bit(unsigned long long uvalue)
{
- unsigned long long high_bit = 0;
+ int i;
+
+ for (i = 0; i < 64; i++) {
+ if (!(uvalue & (1ULL << i)))
+ return i;
+ }
+ return i;
+}
+
+int sm_fls64(unsigned long long uvalue)
+{
+ int high_bit = 0;
while (uvalue) {
uvalue >>= 1;
high_bit++;
}
+ return high_bit;
+}
+
+unsigned long long fls_mask(unsigned long long uvalue)
+{
+ int high_bit = 0;
+
+ high_bit = sm_fls64(uvalue);
if (high_bit == 0)
return 0;
@@ -607,6 +630,8 @@ const char *sval_to_str(sval_t sval)
{
char buf[30];
+ if (sval_is_ptr(sval) && sval.value == valid_ptr_max)
+ return "ptr_max";
if (sval_unsigned(sval) && sval.value == ULLONG_MAX)
return "u64max";
if (sval_unsigned(sval) && sval.value == UINT_MAX)
@@ -638,6 +663,22 @@ const char *sval_to_str(sval_t sval)
return alloc_sname(buf);
}
+const char *sval_to_str_or_err_ptr(sval_t sval)
+{
+ char buf[12];
+
+ if (option_project != PROJ_KERNEL ||
+ !is_ptr_type(sval.type))
+ return sval_to_str(sval);
+
+ if (sval.uvalue >= -4905ULL) {
+ snprintf(buf, sizeof(buf), "(%lld)", sval.value);
+ return alloc_sname(buf);
+ }
+
+ return sval_to_str(sval);
+}
+
const char *sval_to_numstr(sval_t sval)
{
char buf[30];
diff --git a/usr/src/tools/smatch/src/smatch_type.c b/usr/src/tools/smatch/src/smatch_type.c
index 23763b9f13..fca1fb8bac 100644
--- a/usr/src/tools/smatch/src/smatch_type.c
+++ b/usr/src/tools/smatch/src/smatch_type.c
@@ -29,6 +29,8 @@ struct symbol *get_real_base_type(struct symbol *sym)
if (!sym)
return NULL;
+ if (sym->type == SYM_BASETYPE)
+ return sym;
ret = get_base_type(sym);
if (!ret)
return NULL;
@@ -75,6 +77,10 @@ static struct symbol *get_binop_type(struct expression *expr)
if (!right)
return NULL;
+ if (expr->op == '-' &&
+ (is_ptr_type(left) && is_ptr_type(right)))
+ return ssize_t_ctype;
+
if (left->type == SYM_PTR || left->type == SYM_ARRAY)
return left;
if (right->type == SYM_PTR || right->type == SYM_ARRAY)
@@ -269,6 +275,9 @@ static struct symbol *get_type_helper(struct expression *expr)
case EXPR_LOGICAL:
ret = &int_ctype;
break;
+ case EXPR_OFFSETOF:
+ ret = &ulong_ctype;
+ break;
default:
return NULL;
}
@@ -283,16 +292,10 @@ static struct symbol *get_type_helper(struct expression *expr)
static struct symbol *get_final_type_helper(struct expression *expr)
{
/*
- * I'm not totally positive I understand types...
- *
- * So, when you're doing pointer math, and you do a subtraction, then
- * the sval_binop() and whatever need to know the type of the pointer
- * so they can figure out the alignment. But the result is going to be
- * and ssize_t. So get_operation_type() gives you the pointer type
- * and get_type() gives you ssize_t.
- *
- * Most of the time the operation type and the final type are the same
- * but this just handles the few places where they are different.
+ * The problem is that I wrote a bunch of Smatch to think that
+ * you could do get_type() on an expression and it would give
+ * you what the comparison was type promoted to. This is wrong
+ * but fixing it is a big of work... Hence this horrible hack.
*
*/
@@ -300,21 +303,8 @@ static struct symbol *get_final_type_helper(struct expression *expr)
if (!expr)
return NULL;
- switch (expr->type) {
- case EXPR_COMPARE:
+ if (expr->type == EXPR_COMPARE)
return &int_ctype;
- case EXPR_BINOP: {
- struct symbol *left, *right;
-
- if (expr->op != '-')
- return NULL;
-
- left = get_type(expr->left);
- right = get_type(expr->right);
- if (type_is_ptr(left) || type_is_ptr(right))
- return ssize_t_ctype;
- }
- }
return NULL;
}
@@ -397,16 +387,7 @@ int returns_unsigned(struct symbol *sym)
int is_pointer(struct expression *expr)
{
- struct symbol *sym;
-
- sym = get_type(expr);
- if (!sym)
- return 0;
- if (sym == &string_ctype)
- return 0;
- if (sym->type == SYM_PTR)
- return 1;
- return 0;
+ return type_is_ptr(get_type(expr));
}
int returns_pointer(struct symbol *sym)
@@ -442,7 +423,7 @@ sval_t sval_type_min(struct symbol *base_type)
base_type = &llong_ctype;
ret.type = base_type;
- if (type_unsigned(base_type)) {
+ if (type_unsigned(base_type) || is_ptr_type(base_type)) {
ret.value = 0;
return ret;
}
@@ -604,7 +585,7 @@ static struct symbol *get_member_from_string(struct symbol_list *symbol_list, co
if (strncmp(name, ".", 1) == 0)
name += 1;
- if (strncmp(name, "->", 2) == 0)
+ else if (strncmp(name, "->", 2) == 0)
name += 2;
FOR_EACH_PTR(symbol_list, tmp) {
@@ -619,10 +600,12 @@ static struct symbol *get_member_from_string(struct symbol_list *symbol_list, co
if (strcmp(tmp->ident->name, name) == 0)
return tmp;
- chunk_len = strlen(tmp->ident->name);
+ chunk_len = tmp->ident->len;
if (strncmp(tmp->ident->name, name, chunk_len) == 0 &&
(name[chunk_len] == '.' || name[chunk_len] == '-')) {
sub = get_real_base_type(tmp);
+ if (sub->type == SYM_PTR)
+ sub = get_real_base_type(sub);
return get_member_from_string(sub->symbol_list, name + chunk_len);
}
@@ -741,7 +724,7 @@ static int type_str_helper(char *buf, int size, struct symbol *type)
return snprintf(buf, size, "<unknown>");
if (type->type == SYM_BASETYPE) {
- return snprintf(buf, size, base_type_str(type));
+ return snprintf(buf, size, "%s", base_type_str(type));
} else if (type->type == SYM_PTR) {
type = get_real_base_type(type);
n = type_str_helper(buf, size, type);
@@ -795,6 +778,8 @@ static int type_str_helper(char *buf, int size, struct symbol *type)
if (n > size)
return n;
return n + snprintf(buf + n, size - n, "}");
+ } else if (type->type == SYM_ENUM) {
+ return snprintf(buf, size, "enum %s", type->ident ? type->ident->name : "<unknown>");
} else {
return snprintf(buf, size, "<type %d>", type->type);
}
diff --git a/usr/src/tools/smatch/src/smatch_type_val.c b/usr/src/tools/smatch/src/smatch_type_val.c
index 6baa2f50dd..89be79e679 100644
--- a/usr/src/tools/smatch/src/smatch_type_val.c
+++ b/usr/src/tools/smatch/src/smatch_type_val.c
@@ -396,9 +396,6 @@ static void match_assign_value(struct expression *expr)
return;
type = get_type(expr->left);
- if (type && type->type == SYM_STRUCT)
- return;
-
member = get_member_name(expr->left);
if (!member)
return;
diff --git a/usr/src/tools/smatch/src/smatch_untracked_param.c b/usr/src/tools/smatch/src/smatch_untracked_param.c
index 7f07d9894d..d6ff0e7010 100644
--- a/usr/src/tools/smatch/src/smatch_untracked_param.c
+++ b/usr/src/tools/smatch/src/smatch_untracked_param.c
@@ -39,10 +39,12 @@ static int my_id;
static int tracked;
STATE(untracked);
+STATE(lost);
typedef void (untracked_hook)(struct expression *call, int param);
DECLARE_PTR_LIST(untracked_hook_list, untracked_hook *);
static struct untracked_hook_list *untracked_hooks;
+static struct untracked_hook_list *lost_hooks;
struct int_stack *tracked_stack;
@@ -62,12 +64,45 @@ static void call_untracked_callbacks(struct expression *expr, int param)
} END_FOR_EACH_PTR(fn);
}
+void add_lost_param_hook(void (func)(struct expression *call, int param))
+{
+ untracked_hook **p = malloc(sizeof(untracked_hook *));
+ *p = func;
+ add_ptr_list(&lost_hooks, p);
+}
+
+static void call_lost_callbacks(struct expression *expr, int param)
+{
+ untracked_hook **fn;
+
+ FOR_EACH_PTR(lost_hooks, fn) {
+ (*fn)(expr, param);
+ } END_FOR_EACH_PTR(fn);
+}
+
static void assume_tracked(struct expression *call_expr, int param, char *key, char *value)
{
tracked = 1;
}
-void mark_untracked(struct expression *expr, int param, const char *key, const char *value)
+static char *get_array_from_key(struct expression *expr, int param, const char *key, struct symbol **sym)
+{
+ struct expression *arg;
+
+ arg = get_argument_from_call_expr(expr->args, param);
+ if (!arg)
+ return NULL;
+ if (arg->type != EXPR_PREOP || arg->op != '&')
+ return NULL;
+ arg = arg->unop;
+ if (!is_array(arg))
+ return NULL;
+ arg = get_array_base(arg);
+
+ return expr_to_var_sym(arg, sym);
+}
+
+static void mark_untracked_lost(struct expression *expr, int param, const char *key, int type)
{
char *name;
struct symbol *sym;
@@ -78,13 +113,29 @@ void mark_untracked(struct expression *expr, int param, const char *key, const c
return;
name = return_state_to_var_sym(expr, param, key, &sym);
- if (!name || !sym)
- goto free;
+ if (!name || !sym) {
+ name = get_array_from_key(expr, param, key, &sym);
+ if (!name || !sym)
+ goto free;
+ }
+ if (type == LOST_PARAM)
+ call_lost_callbacks(expr, param);
call_untracked_callbacks(expr, param);
set_state(my_id, name, sym, &untracked);
free:
free_string(name);
+
+}
+
+void mark_untracked(struct expression *expr, int param, const char *key, const char *value)
+{
+ mark_untracked_lost(expr, param, key, UNTRACKED_PARAM);
+}
+
+void mark_lost(struct expression *expr, int param, const char *key, const char *value)
+{
+ mark_untracked_lost(expr, param, key, LOST_PARAM);
}
static int lost_in_va_args(struct expression *expr)
@@ -133,7 +184,8 @@ static void match_after_call(struct expression *expr)
} END_FOR_EACH_PTR(arg);
}
-void mark_all_params_untracked(int return_id, char *return_ranges, struct expression *expr)
+
+static void mark_all_params(int return_id, char *return_ranges, int type)
{
struct symbol *arg;
int param;
@@ -145,14 +197,27 @@ void mark_all_params_untracked(int return_id, char *return_ranges, struct expres
if (!arg->ident)
continue;
sql_insert_return_states(return_id, return_ranges,
- UNTRACKED_PARAM, param, "$", "");
+ type, param, "$", "");
} END_FOR_EACH_PTR(arg);
}
+
+void mark_all_params_untracked(int return_id, char *return_ranges, struct expression *expr)
+{
+ mark_all_params(return_id, return_ranges, UNTRACKED_PARAM);
+}
+
+void mark_all_params_lost(int return_id, char *return_ranges, struct expression *expr)
+{
+ mark_all_params(return_id, return_ranges, LOST_PARAM);
+}
+
static void print_untracked_params(int return_id, char *return_ranges, struct expression *expr)
{
+ struct sm_state *sm;
struct symbol *arg;
int param;
+ int type;
param = -1;
FOR_EACH_PTR(cur_func_sym->ctype.base_type->arguments, arg) {
@@ -160,12 +225,21 @@ static void print_untracked_params(int return_id, char *return_ranges, struct ex
if (!arg->ident)
continue;
- if (!get_state(my_id, arg->ident->name, arg) &&
- !__bail_on_rest_of_function) /* hairy functions are untrackable */
+
+ if (__bail_on_rest_of_function) {
+ /* hairy functions are lost */
+ type = LOST_PARAM;
+ } else if ((sm = get_sm_state(my_id, arg->ident->name, arg))) {
+ if (slist_has_state(sm->possible, &lost))
+ type = LOST_PARAM;
+ else
+ type = UNTRACKED_PARAM;
+ } else {
continue;
+ }
sql_insert_return_states(return_id, return_ranges,
- UNTRACKED_PARAM, param, "$", "");
+ type, param, "$", "");
} END_FOR_EACH_PTR(arg);
}
@@ -237,6 +311,7 @@ void register_untracked_param(int id)
select_return_states_hook(INTERNAL, &assume_tracked);
select_return_states_hook(UNTRACKED_PARAM, &mark_untracked);
+ select_return_states_hook(LOST_PARAM, &mark_lost);
add_hook(&match_after_call, FUNCTION_CALL_HOOK_AFTER_DB);
add_split_return_callback(&print_untracked_params);
diff --git a/usr/src/tools/smatch/src/validation/sm_bitwise1.c b/usr/src/tools/smatch/src/validation/sm_bitwise1.c
index e36da4b075..dbd2f873bf 100644
--- a/usr/src/tools/smatch/src/validation/sm_bitwise1.c
+++ b/usr/src/tools/smatch/src/validation/sm_bitwise1.c
@@ -17,6 +17,6 @@ void test(void)
sm_bitwise1.c:6 test() implied: x & 1 = '0-1'
sm_bitwise1.c:7 test() implied: x & 2 = '0,2'
sm_bitwise1.c:8 test() implied: x & ~(255) = '0,256-4294967040'
-sm_bitwise1.c:9 test() implied: x & ~(255) = '0-4294967040'
+sm_bitwise1.c:9 test() implied: x & ~(255) = '0,256-4294967040'
* check-output-end
*/
diff --git a/usr/src/tools/smatch/src/validation/sm_equiv1.c b/usr/src/tools/smatch/src/validation/sm_equiv1.c
index 8bd7e57500..b8db9507eb 100644
--- a/usr/src/tools/smatch/src/validation/sm_equiv1.c
+++ b/usr/src/tools/smatch/src/validation/sm_equiv1.c
@@ -30,11 +30,11 @@ int func(void)
* check-output-start
sm_equiv1.c:13 func() one = 1
sm_equiv1.c:14 func() two = 1
-sm_equiv1.c:16 func() one = s64min-s64max
-sm_equiv1.c:17 func() two = s64min-s64max
+sm_equiv1.c:16 func() one = 0-u64max
+sm_equiv1.c:17 func() two = 0-u64max
sm_equiv1.c:19 func() one = 2
sm_equiv1.c:20 func() two = 2
-sm_equiv1.c:22 func() one = s64min-s64max
-sm_equiv1.c:23 func() two = s64min-s64max
+sm_equiv1.c:22 func() one = 0-u64max
+sm_equiv1.c:23 func() two = 0-u64max
* check-output-end
*/
diff --git a/usr/src/tools/smatch/src/validation/sm_implied.c b/usr/src/tools/smatch/src/validation/sm_implied.c
index 9e318effa5..957ed4223f 100644
--- a/usr/src/tools/smatch/src/validation/sm_implied.c
+++ b/usr/src/tools/smatch/src/validation/sm_implied.c
@@ -26,5 +26,6 @@ x:
*
* check-output-start
sm_implied.c:20 func() error: potentially dereferencing uninitialized 'aa'.
+sm_implied.c:20 func() error: potentially dereferencing uninitialized 'aa'.
* check-output-end
*/
diff --git a/usr/src/tools/smatch/src/validation/sm_implied10.c b/usr/src/tools/smatch/src/validation/sm_implied10.c
index b52f01195f..d699d9883b 100644
--- a/usr/src/tools/smatch/src/validation/sm_implied10.c
+++ b/usr/src/tools/smatch/src/validation/sm_implied10.c
@@ -11,7 +11,7 @@ void func(int *y)
else
__smatch_value("y");
- if (({int test2 = !!(offset >= 10 || x[offset] == 1); frob(); frob(); frob(); test2;}))
+ if (({int test2 = !!(offset >= 10u || x[offset] == 1); frob(); frob(); frob(); test2;}))
__smatch_value("offset");
else
__smatch_value("offset");
@@ -22,9 +22,9 @@ void func(int *y)
* check-command: smatch -I.. -m64 sm_implied10.c
*
* check-output-start
-sm_implied10.c:10 func() y = 0,4096-2117777777777777777
-sm_implied10.c:12 func() y = 4096-2117777777777777777
-sm_implied10.c:15 func() offset = 0-s32max
+sm_implied10.c:10 func() y = 0,4096-ptr_max
+sm_implied10.c:12 func() y = 4096-ptr_max
+sm_implied10.c:15 func() offset = s32min-s32max
sm_implied10.c:17 func() offset = 0-9
* check-output-end
*/
diff --git a/usr/src/tools/smatch/src/validation/sm_implied11.c b/usr/src/tools/smatch/src/validation/sm_implied11.c
index 5a8b02b5c3..7536fed355 100644
--- a/usr/src/tools/smatch/src/validation/sm_implied11.c
+++ b/usr/src/tools/smatch/src/validation/sm_implied11.c
@@ -29,6 +29,6 @@ static void ad_agg_selection_logic(void)
* check-command: smatch -I.. -m64 sm_implied11.c
*
* check-output-start
-sm_implied11.c:25 ad_agg_selection_logic() implied: foo = '0,4096-2117777777777777777'
+sm_implied11.c:25 ad_agg_selection_logic() implied: foo = '0,4096-ptr_max'
* check-output-end
*/
diff --git a/usr/src/tools/smatch/src/validation/sm_implied12.c b/usr/src/tools/smatch/src/validation/sm_implied12.c
index ad9e49487d..a35f1b9c6b 100644
--- a/usr/src/tools/smatch/src/validation/sm_implied12.c
+++ b/usr/src/tools/smatch/src/validation/sm_implied12.c
@@ -33,6 +33,6 @@ static void ad_agg_selection_logic(void)
* check-command: smatch -I.. -m64 sm_implied12.c
*
* check-output-start
-sm_implied12.c:28 ad_agg_selection_logic() implied: foo = '0,4096-2117777777777777777'
+sm_implied12.c:28 ad_agg_selection_logic() implied: foo = '0,4096-ptr_max'
* check-output-end
*/
diff --git a/usr/src/tools/smatch/src/validation/sm_implied2.c b/usr/src/tools/smatch/src/validation/sm_implied2.c
index c25e3567c2..b40aa811fc 100644
--- a/usr/src/tools/smatch/src/validation/sm_implied2.c
+++ b/usr/src/tools/smatch/src/validation/sm_implied2.c
@@ -37,5 +37,6 @@ void func (void)
*
* check-output-start
sm_implied2.c:28 func() error: potentially dereferencing uninitialized 'aa'.
+sm_implied2.c:28 func() error: potentially dereferencing uninitialized 'aa'.
* check-output-end
*/
diff --git a/usr/src/tools/smatch/src/validation/sm_implied5.c b/usr/src/tools/smatch/src/validation/sm_implied5.c
index 09b4a13ac9..0fe213537c 100644
--- a/usr/src/tools/smatch/src/validation/sm_implied5.c
+++ b/usr/src/tools/smatch/src/validation/sm_implied5.c
@@ -23,5 +23,6 @@ void func (void)
*
* check-output-start
sm_implied5.c:18 func() error: potentially dereferencing uninitialized 'aa'.
+sm_implied5.c:18 func() error: potentially dereferencing uninitialized 'aa'.
* check-output-end
*/
diff --git a/usr/src/tools/smatch/src/validation/sm_memory.c b/usr/src/tools/smatch/src/validation/sm_memory.c
index 145b1c0b49..402c23fcbc 100644
--- a/usr/src/tools/smatch/src/validation/sm_memory.c
+++ b/usr/src/tools/smatch/src/validation/sm_memory.c
@@ -30,6 +30,5 @@ void func (void)
*
* check-output-start
sm_memory.c:22 func() warn: possible memory leak of 'ac'
-sm_memory.c:22 func() error: memory leak of 'ac'
* check-output-end
*/
diff --git a/usr/src/tools/smatch/src/validation/sm_null_deref.c b/usr/src/tools/smatch/src/validation/sm_null_deref.c
index df399e6cc5..5734d21a5b 100644
--- a/usr/src/tools/smatch/src/validation/sm_null_deref.c
+++ b/usr/src/tools/smatch/src/validation/sm_null_deref.c
@@ -44,6 +44,7 @@ static void func (void)
*
* check-output-start
sm_null_deref.c:18 func() error: potentially dereferencing uninitialized 'aa'.
+sm_null_deref.c:18 func() error: potentially dereferencing uninitialized 'aa'.
sm_null_deref.c:23 func() error: we previously assumed 'a' could be null (see line 20)
sm_null_deref.c:25 func() warn: variable dereferenced before check 'a' (see line 23)
sm_null_deref.c:30 func() error: we previously assumed 'b' could be null (see line 25)
diff --git a/usr/src/tools/smatch/src/validation/sm_select5.c b/usr/src/tools/smatch/src/validation/sm_select5.c
index cce93b30c2..05e3dec8db 100644
--- a/usr/src/tools/smatch/src/validation/sm_select5.c
+++ b/usr/src/tools/smatch/src/validation/sm_select5.c
@@ -25,7 +25,7 @@ void test(void)
*
* check-output-start
sm_select5.c:15 test() implied: ret = '(-12)'
-sm_select5.c:16 test() implied: a = 's32min-s32max'
+sm_select5.c:16 test() implied: a = 's32min-(-1),4-s32max'
sm_select5.c:18 test() implied: a = '0-3'
* check-output-end
*/
diff --git a/usr/src/uts/i86pc/unix/Makefile b/usr/src/uts/i86pc/unix/Makefile
index 9eedb1bf67..fbd7976548 100644
--- a/usr/src/uts/i86pc/unix/Makefile
+++ b/usr/src/uts/i86pc/unix/Makefile
@@ -21,7 +21,7 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# Copyright (c) 2018, Joyent, Inc.
+# Copyright 2019 Joyent, Inc.
# Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
#
@@ -149,6 +149,9 @@ $(OBJS_DIR)/fmsmb.o := SMOFF += indenting
$(OBJS_DIR)/zutil.o := SMOFF += indenting
$(OBJS_DIR)/bootrd_cpio.o := SMOFF += allocating_enough_data
+# too hairy
+$(OBJS_DIR)/inflate.o := SMATCH=off
+
#
# Default build targets.
#
diff --git a/usr/src/uts/intel/emlxs/Makefile b/usr/src/uts/intel/emlxs/Makefile
index 4910ca9fdd..e29f1762ca 100644
--- a/usr/src/uts/intel/emlxs/Makefile
+++ b/usr/src/uts/intel/emlxs/Makefile
@@ -22,7 +22,7 @@
# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
# Copyright (c) 2011 Bayard G. Bell. All rights reserved.
-# Copyright (c) 2018, Joyent, Inc.
+# Copyright 2019 Joyent, Inc.
#
# This makefile drives the production of the emlxs driver kernel module.
#
@@ -36,7 +36,6 @@ COMMON_BASE = ../../../common
#
MODULE = emlxs
OBJECTS = $(EMLXS_OBJS:%=$(OBJS_DIR)/%)
-LINTS = $(EMLXS_OBJS:%.o=$(LINTS_DIR)/%.ln)
ROOTMODULE = $(ROOT_DRV_DIR)/$(MODULE)
CONF_SRCDIR = $(UTSBASE)/common/io/fibre-channel/fca/emlxs
@@ -50,7 +49,6 @@ include ../Makefile.$(ARCHDIR)
# Define targets
#
ALL_TARGET = $(BINARY) $(SRC_CONFILE)
-LINT_TARGET = $(MODULE).lint
INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
EMLXS_FLAGS = -DEMLXS_I386
@@ -60,7 +58,6 @@ EMLXS_FLAGS += -DMACH=\"$(MACH)\"
EMLXS_CFLAGS = $(EMLXS_FLAGS)
EMLXS_LFLAGS = $(EMLXS_FLAGS)
CFLAGS += $(EMLXS_CFLAGS) -DEMLXS_ARCH=\"$(CLASS)\"
-LINTTAGS += $(EMLXS_LFLAGS) -DEMLXS_ARCH=\"$(CLASS)\"
#
@@ -82,21 +79,12 @@ INC_PATH += -I$(UTSBASE)/common/sys/fibre-channel/ulp
LDFLAGS += -dy -Nmisc/md5 -Nmisc/sha1
LDFLAGS += -Nmisc/bignum -Nmisc/fctl
-#
-# For now, disable these lint checks; maintainers should endeavor
-# to investigate and remove these for maximum lint coverage.
-#
-LINTTAGS += -erroff=E_BAD_PTR_CAST_ALIGN
-LINTTAGS += -erroff=E_STATIC_UNUSED
-LINTTAGS += -erroff=E_ASSIGN_NARROW_CONV
-LINTTAGS += -erroff=E_SUSPICIOUS_COMPARISON
-LINTTAGS += -erroff=E_INCONS_VAL_TYPE_DECL2
-
CERRWARN += -_gcc=-Wno-parentheses
CERRWARN += -_gcc=-Wno-unused-label
CERRWARN += -_gcc=-Wno-uninitialized
-SMOFF += indenting,deref_check,all_func_returns
+# needs work
+SMOFF += indenting,deref_check,all_func_returns,index_overflow
# seems definitely wrong
$(OBJS_DIR)/emlxs_fcf.o := SMOFF += logical_instead_of_bitwise
@@ -114,12 +102,6 @@ clean: $(CLEAN_DEPS)
clobber: $(CLOBBER_DEPS)
-lint: $(LINT_DEPS)
-
-modlintlib: $(MODLINTLIB_DEPS)
-
-clean.lint: $(CLEAN_LINT_DEPS)
-
install: $(INSTALL_DEPS)
#
diff --git a/usr/src/uts/intel/genunix/Makefile b/usr/src/uts/intel/genunix/Makefile
index 04a0279b01..58a50d801a 100644
--- a/usr/src/uts/intel/genunix/Makefile
+++ b/usr/src/uts/intel/genunix/Makefile
@@ -23,13 +23,7 @@
# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# Copyright (c) 2018, Joyent, Inc.
-
-#
-# This makefile drives the production of the generic
-# unix kernel module.
-#
-# x86 implementation architecture dependent
+# Copyright 2019 Joyent, Inc.
#
#
@@ -46,9 +40,6 @@ GENUNIX = $(OBJS_DIR)/$(MODULE)
OBJECTS = $(GENUNIX_OBJS:%=$(OBJS_DIR)/%) \
$(NOT_YET_KMODS:%=$(OBJS_DIR)/%)
-LINTS = $(GENUNIX_OBJS:%.o=$(LINTS_DIR)/%.ln) \
- $(NOT_YET_KMODS:%.o=$(LINTS_DIR)/%.ln)
-
ROOTMODULE = $(ROOT_KERN_DIR)/$(MODULE)
LIBGEN = $(OBJS_DIR)/libgenunix.so
@@ -63,7 +54,6 @@ include $(UTSBASE)/intel/Makefile.intel
# Define targets
#
ALL_TARGET = $(LIBGEN) $(GENUNIX)
-LINT_TARGET = $(MODULE).lint
INSTALL_TARGET = $(LIBGEN) $(GENUNIX) $(ROOTMODULE)
#
@@ -88,18 +78,6 @@ CPPFLAGS += -I$(SRC)/uts/common/fs/zfs
CPPFLAGS += -I$(UTSBASE)/i86pc
-#
-# For now, disable these lint checks; maintainers should endeavor
-# to investigate and remove these for maximum lint coverage.
-# Please do not carry these forward to new Makefiles.
-#
-LINTTAGS += -erroff=E_SUSPICIOUS_COMPARISON
-LINTTAGS += -erroff=E_BAD_PTR_CAST_ALIGN
-LINTTAGS += -erroff=E_SUPPRESSION_DIRECTIVE_UNUSED
-LINTTAGS += -erroff=E_STATIC_UNUSED
-LINTTAGS += -erroff=E_PTRDIFF_OVERFLOW
-LINTTAGS += -erroff=E_ASSIGN_NARROW_CONV
-
CERRWARN += -_gcc=-Wno-unused-label
CERRWARN += -_gcc=-Wno-unused-variable
CERRWARN += -_gcc=-Wno-unused-value
@@ -111,6 +89,9 @@ CERRWARN += -_gcc=-Wno-uninitialized
CERRWARN += -_gcc=-Wno-clobbered
CERRWARN += -_gcc=-Wno-empty-body
+# very hairy
+$(OBJS_DIR)/u8_textprep.o := SMATCH=off
+
# false positives
SMOFF += index_overflow
$(OBJS_DIR)/seg_vn.o := SMOFF += deref_check
@@ -130,12 +111,6 @@ $(OBJS_DIR)/timers.o := SMOFF += signed_integer_overflow_check
$(OBJS_DIR)/acl_common.o := SMOFF += or_vs_and
#
-# Ensure that lint sees 'struct cpu' containing a fully declared
-# embedded 'struct machcpu'
-#
-LINTFLAGS += -D_MACHDEP -I../../i86pc
-
-#
# Default build targets.
#
.KEEP_STATE:
@@ -148,12 +123,6 @@ clean: $(CLEAN_DEPS)
clobber: $(CLOBBER_DEPS)
-lint: $(LINT_DEPS)
-
-modlintlib: $(MODLINTLIB_DEPS)
-
-clean.lint: $(CLEAN_LINT_DEPS)
-
install: $(INSTALL_DEPS)
# Due to what seems to be an issue in GCC 4 generated DWARF containing
@@ -190,8 +159,3 @@ include $(UTSBASE)/intel/Makefile.targ
include $(UTSBASE)/i86pc/Makefile.workarounds
ALL_DEFS += $(WORKAROUND_DEFS)
-
-#
-# Override.
-#
-$(MODULE).lint := GEN_LINT_LIB =
diff --git a/usr/src/uts/intel/mega_sas/Makefile b/usr/src/uts/intel/mega_sas/Makefile
index 3011ffa0f9..916b2350ab 100644
--- a/usr/src/uts/intel/mega_sas/Makefile
+++ b/usr/src/uts/intel/mega_sas/Makefile
@@ -21,14 +21,7 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# Copyright (c) 2018, Joyent, Inc.
-
-#
-# uts/intel/mega_sas/Makefile
-#
-# This makefile drives the production of the mega_sas driver kernel module.
-#
-# intel implementation architecture dependent
+# Copyright 2019 Joyent, Inc.
#
#
@@ -41,7 +34,6 @@ UTSBASE = ../..
#
MODULE = mega_sas
OBJECTS = $(MEGA_SAS_OBJS:%=$(OBJS_DIR)/%)
-LINTS = $(MEGA_SAS_OBJS:%.o=$(LINTS_DIR)/%.ln)
ROOTMODULE = $(ROOT_DRV_DIR)/$(MODULE)
CONF_SRCDIR = $(UTSBASE)/common/io/mega_sas
@@ -54,18 +46,17 @@ include $(UTSBASE)/intel/Makefile.intel
# Define targets
#
ALL_TARGET = $(BINARY) $(CONFMOD)
-LINT_TARGET = $(MODULE).lint
INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
#
-# Kernel Module Dependencies
+# Kernel Module Dependencies
#
LDFLAGS += -dy -Nmisc/scsi
CERRWARN += -_gcc=-Wno-uninitialized
# needs work
-$(OBJS_DIR)/megaraid_sas.o := SMOFF += snprintf_overflow,all_func_returns
+$(OBJS_DIR)/megaraid_sas.o := SMOFF += snprintf_overflow,all_func_returns,index_overflow
#
# Default build targets.
@@ -80,12 +71,6 @@ clean: $(CLEAN_DEPS)
clobber: $(CLOBBER_DEPS)
-lint: $(LINT_DEPS)
-
-modlintlib: $(MODLINTLIB_DEPS)
-
-clean.lint: $(CLEAN_LINT_DEPS)
-
install: $(INSTALL_DEPS)
#
diff --git a/usr/src/uts/intel/simnet/Makefile b/usr/src/uts/intel/simnet/Makefile
index c3f41026a3..c056a38128 100644
--- a/usr/src/uts/intel/simnet/Makefile
+++ b/usr/src/uts/intel/simnet/Makefile
@@ -22,6 +22,9 @@
# Copyright 2009 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
+# Copyright 2019 Joyent, Inc.
+#
+
#
# Path to the base of the uts directory tree (usually /usr/src/uts).
#
@@ -32,7 +35,6 @@ UTSBASE = ../..
#
MODULE = simnet
OBJECTS = $(SIMNET_OBJS:%=$(OBJS_DIR)/%)
-LINTS = $(SIMNET_OBJS:%.o=$(LINTS_DIR)/%.ln)
ROOTMODULE = $(ROOT_DRV_DIR)/$(MODULE)
CONF_SRCDIR = $(UTSBASE)/common/io/$(MODULE)
@@ -45,7 +47,6 @@ include $(UTSBASE)/intel/Makefile.intel
# Define targets
#
ALL_TARGET = $(BINARY) $(SRC_CONFILE)
-LINT_TARGET = $(MODULE).lint
INSTALL_TARGET = $(BINARY) $(ROOTMODULE) $(ROOT_CONFFILE)
#
@@ -56,6 +57,9 @@ LDFLAGS += -dy -Ndrv/dld -Nmisc/mac -Nmisc/dls -Ndrv/random
CERRWARN += -_gcc=-Wno-switch
+# needs work
+$(OBJS_DIR)/simnet.o := SMOFF += index_overflow
+
#
# Default build targets.
#
@@ -69,12 +73,6 @@ clean: $(CLEAN_DEPS)
clobber: $(CLOBBER_DEPS)
-lint: $(LINT_DEPS)
-
-modlintlib: $(MODLINTLIB_DEPS)
-
-clean.lint: $(CLEAN_LINT_DEPS)
-
install: $(INSTALL_DEPS)
#
diff --git a/usr/src/uts/intel/spppcomp/Makefile b/usr/src/uts/intel/spppcomp/Makefile
index 1d3d2b3918..30f6bb387f 100644
--- a/usr/src/uts/intel/spppcomp/Makefile
+++ b/usr/src/uts/intel/spppcomp/Makefile
@@ -25,7 +25,8 @@
# Use is subject to license terms.
# Copyright (c) 2011 Bayard G. Bell. All rights reserved.
#
-# Copyright (c) 2018, Joyent, Inc.
+# Copyright 2019 Joyent, Inc.
+#
#
# Path to the base of the uts directory tree (usually /usr/src/uts).
@@ -37,7 +38,6 @@ UTSBASE = ../..
#
MODULE = spppcomp
OBJECTS = $(SPPPCOMP_OBJS:%=$(OBJS_DIR)/%)
-LINTS = $(SPPPCOMP_OBJS:%.o=$(LINTS_DIR)/%.ln)
ROOTMODULE = $(USR_STRMOD_DIR)/$(MODULE)
#
@@ -49,7 +49,6 @@ include $(UTSBASE)/intel/Makefile.intel
# Define targets
#
ALL_TARGET = $(BINARY)
-LINT_TARGET = $(MODULE).lint
INSTALL_TARGET = $(BINARY) $(ROOTMODULE)
#
@@ -57,25 +56,16 @@ INSTALL_TARGET = $(BINARY) $(ROOTMODULE)
#
CPPFLAGS += -DINTERNAL_BUILD -DSOL2 -DMUX_FRAME
-#
-# Additional compiler definitions
-#
-INC_PATH += -I$(UTSBASE)/common/io/ppp/common
-
#
-# For now, disable these lint checks; maintainers should endeavor
-# to investigate and remove these for maximum lint coverage.
-# Please do not carry these forward to new Makefiles.
+# Additional compiler definitions
#
-LINTTAGS += -erroff=E_BAD_PTR_CAST_ALIGN
-LINTTAGS += -erroff=E_PTRDIFF_OVERFLOW
-LINTTAGS += -erroff=E_ASSIGN_NARROW_CONV
+INC_PATH += -I$(UTSBASE)/common/io/ppp/common
CERRWARN += -_gcc=-Wno-parentheses
CERRWARN += -_gcc=-Wno-uninitialized
# needs work
-SMOFF += indenting
+SMOFF += indenting,index_overflow
#
# Depends on sppp
@@ -95,17 +85,8 @@ clean: $(CLEAN_DEPS)
clobber: $(CLOBBER_DEPS)
-lint: $(LINT_DEPS)
-
-modlintlib: $(MODLINTLIB_DEPS)
-
-clean.lint: $(CLEAN_LINT_DEPS)
-
install: $(INSTALL_DEPS)
-$(LINTS_DIR)/%.ln: $(UTSBASE)/common/io/ppp/spppcomp/%.c
- @($(LHEAD) $(LINT.c) $< $(LTAIL))
-
$(OBJS_DIR)/%.o: $(UTSBASE)/common/io/ppp/spppcomp/%.c
$(COMPILE.c) -o $@ $<
$(CTFCONVERT_O)
diff --git a/usr/src/uts/intel/xge/Makefile b/usr/src/uts/intel/xge/Makefile
index 1c9b0e2e2b..c0407c1984 100644
--- a/usr/src/uts/intel/xge/Makefile
+++ b/usr/src/uts/intel/xge/Makefile
@@ -23,7 +23,8 @@
# Copyright 2008 Sun Microsystems, Inc. All rights reserved.
# Use is subject to license terms.
#
-# Copyright (c) 2018, Joyent, Inc.
+# Copyright 2019 Joyent, Inc.
+#
#
# Paths to the base of the uts directory trees
@@ -35,7 +36,6 @@ UTSBASE = ../..
#
MODULE = xge
OBJECTS = $(XGE_HAL_OBJS:%=$(OBJS_DIR)/%) $(XGE_OBJS:%=$(OBJS_DIR)/%)
-LINTS = $(XGE_HAL_OBJS:%.o=$(LINTS_DIR)/%.ln) $(XGE_OBJS:%.o=$(LINTS_DIR)/%.ln)
ROOTMODULE = $(ROOT_DRV_DIR)/$(MODULE)
#
@@ -47,7 +47,6 @@ include $(UTSBASE)/intel/Makefile.intel
# Define targets
#
ALL_TARGET = $(BINARY)
-LINT_TARGET = $(MODULE).lint
INSTALL_TARGET = $(BINARY) $(ROOTMODULE)
#
@@ -74,7 +73,7 @@ HAL_CFLAGS = -DXGE_HAL_USE_MGMT_AUX
#TRACE_CFLAGS = -DXGE_DEBUG_MODULE_MASK=0xffffffff \
# -DXGE_DEBUG_TRACE_MASK=0xffffffff \
# -DXGE_DEBUG_ERR_MASK=0xffffffff
-TRACE_CFLAGS = -DXGE_DEBUG_MODULE_MASK=0x00003010 \
+TRACE_CFLAGS = -DXGE_DEBUG_MODULE_MASK=0x00003010 \
-DXGE_DEBUG_TRACE_MASK=0x00000000 \
-DXGE_DEBUG_ERR_MASK=0x00003010
@@ -91,19 +90,6 @@ CFLAGS64 += $(XGE_CFLAGS) -xO4 -xcrossfile
#
LDFLAGS += -dy -N misc/mac -N drv/ip
-# Lint flag
-#
-LINTFLAGS += $(XGE_CFLAGS) -Xc99=%all
-
-#
-# For now, disable these lint checks; maintainers should endeavor
-# to investigate and remove these for maximum lint coverage.
-# Please do not carry these forward to new Makefiles.
-#
-LINTTAGS += -erroff=E_BAD_PTR_CAST_ALIGN
-LINTTAGS += -erroff=E_STATIC_UNUSED
-LINTTAGS += -erroff=E_PTRDIFF_OVERFLOW
-
CERRWARN += -_gcc=-Wno-parentheses
CERRWARN += -_gcc=-Wno-unused-variable
CERRWARN += -_gcc=-Wno-unused-label
@@ -111,7 +97,10 @@ CERRWARN += -_gcc=-Wno-empty-body
CERRWARN += -_gcc=-Wno-uninitialized
# needs work
-SMOFF += indenting,all_func_returns,no_if_block
+SMOFF += indenting
+SMOFF += all_func_returns
+SMOFF += no_if_block
+SMOFF += allocating_enough_data
#
#
@@ -127,12 +116,6 @@ clean: $(CLEAN_DEPS)
clobber: $(CLOBBER_DEPS)
-lint: $(LINT_DEPS)
-
-modlintlib: $(MODLINTLIB_DEPS)
-
-clean.lint: $(CLEAN_LINT_DEPS)
-
install: $(INSTALL_DEPS)
#