diff --git a/gcc/analyzer/analyzer.opt b/gcc/analyzer/analyzer.opt
index a3c30caf2ab..d0fe5a43788 100644
--- a/gcc/analyzer/analyzer.opt
+++ b/gcc/analyzer/analyzer.opt
@@ -43,7 +43,7 @@ Common Joined UInteger Var(param_analyzer_max_recursion_depth) Init(2) Param
 The maximum number of times a callsite can appear in a call stack within the analyzer, before terminating analysis of a call that would recurse deeper.
 
 -param=analyzer-max-svalue-depth=
-Common Joined UInteger Var(param_analyzer_max_svalue_depth) Init(12) Param
+Common Joined UInteger Var(param_analyzer_max_svalue_depth) Init(18) Param
 The maximum depth of a symbolic value, before approximating the value as unknown.
 
 -param=analyzer-min-snodes-for-call-summary=
@@ -262,6 +262,10 @@ Wanalyzer-use-of-uninitialized-value
 Common Var(warn_analyzer_use_of_uninitialized_value) Init(1) Warning
 Warn about code paths in which an uninitialized value is used.
 
+Wanalyzer-symbol-too-complex
+Common Var(warn_analyzer_symbol_too_complex) Init(0) Warning
+Warn if expressions are too complicated for the analyzer to fully track.
+
 Wanalyzer-too-complex
 Common Var(warn_analyzer_too_complex) Init(0) Warning
 Warn if the code is too complicated for the analyzer to fully explore.
diff --git a/gcc/analyzer/diagnostic-manager.cc b/gcc/analyzer/diagnostic-manager.cc
index ecd57376b54..38bd308a9a4 100644
--- a/gcc/analyzer/diagnostic-manager.cc
+++ b/gcc/analyzer/diagnostic-manager.cc
@@ -2043,6 +2043,11 @@ struct null_assignment_sm_context : public sm_context
     /* No-op.  */
   }
 
+  void clear_all_per_svalue_state () final override
+  {
+    /* No-op.  */
+  }
+
   void on_custom_transition (custom_transition *) final override
   {
   }
diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc
index 825b3af43fc..d2524e34f58 100644
--- a/gcc/analyzer/engine.cc
+++ b/gcc/analyzer/engine.cc
@@ -474,6 +474,11 @@ public:
     m_new_state->m_checker_states[m_sm_idx]->set_global_state (state);
   }
 
+  void clear_all_per_svalue_state () final override
+  {
+    m_new_state->m_checker_states[m_sm_idx]->clear_all_per_svalue_state ();
+  }
+
   void on_custom_transition (custom_transition *transition) final override
   {
     transition->impl_transition (&m_eg,
diff --git a/gcc/analyzer/program-state.cc b/gcc/analyzer/program-state.cc
index 9bb81e6dddd..78f739ef5ef 100644
--- a/gcc/analyzer/program-state.cc
+++ b/gcc/analyzer/program-state.cc
@@ -526,6 +526,14 @@ sm_state_map::clear_any_state (const svalue *sval)
   m_map.remove (sval);
 }
 
+/* Clear all per-svalue state within this state map.  */
+
+void
+sm_state_map::clear_all_per_svalue_state ()
+{
+  m_map.empty ();
+}
+
 /* Set the "global" state within this state map to STATE.  */
 
 void
diff --git a/gcc/analyzer/program-state.h b/gcc/analyzer/program-state.h
index c9b3aa0cbfc..ef1a2ad54a9 100644
--- a/gcc/analyzer/program-state.h
+++ b/gcc/analyzer/program-state.h
@@ -146,6 +146,7 @@ public:
 		       const svalue *origin,
 		       const extrinsic_state &ext_state);
   void clear_any_state (const svalue *sval);
+  void clear_all_per_svalue_state ();
 
   void set_global_state (state_machine::state_t state);
   state_machine::state_t get_global_state () const;
diff --git a/gcc/analyzer/region-model-manager.cc b/gcc/analyzer/region-model-manager.cc
index 921edc55868..b631bcb04d0 100644
--- a/gcc/analyzer/region-model-manager.cc
+++ b/gcc/analyzer/region-model-manager.cc
@@ -185,6 +185,16 @@ region_model_manager::reject_if_too_complex (svalue *sval)
       return false;
     }
 
+  pretty_printer pp;
+  pp_format_decoder (&pp) = default_tree_printer;
+  sval->dump_to_pp (&pp, true);
+  if (warning_at (input_location, OPT_Wanalyzer_symbol_too_complex,
+		  "symbol too complicated: %qs",
+		  pp_formatted_text (&pp)))
+    inform (input_location,
+	    "max_depth %i exceeds --param=analyzer-max-svalue-depth=%i",
+	    c.m_max_depth, param_analyzer_max_svalue_depth);
+
   delete sval;
   return true;
 }
diff --git a/gcc/analyzer/sm-taint.cc b/gcc/analyzer/sm-taint.cc
index d01e3f03951..6b5d51c62af 100644
--- a/gcc/analyzer/sm-taint.cc
+++ b/gcc/analyzer/sm-taint.cc
@@ -1038,6 +1038,20 @@ taint_state_machine::on_condition (sm_context *sm_ctxt,
   if (stmt == NULL)
     return;
 
+  if (lhs->get_kind () == SK_UNKNOWN
+      || rhs->get_kind () == SK_UNKNOWN)
+    {
+      /* If we have a comparison against UNKNOWN, then
+	 we've presumably hit the svalue complexity limit,
+	 and we don't know what is being sanitized.
+	 Give up on any taint already found on this execution path.  */
+      // TODO: warn about this
+      if (get_logger ())
+	get_logger ()->log ("comparison against UNKNOWN; removing all taint");
+      sm_ctxt->clear_all_per_svalue_state ();
+      return;
+    }
+
   // TODO
   switch (op)
     {
diff --git a/gcc/analyzer/sm.h b/gcc/analyzer/sm.h
index 3ff9c260780..ef63d73a541 100644
--- a/gcc/analyzer/sm.h
+++ b/gcc/analyzer/sm.h
@@ -299,6 +299,8 @@ public:
   virtual state_machine::state_t get_global_state () const = 0;
   virtual void set_global_state (state_machine::state_t) = 0;
 
+  virtual void clear_all_per_svalue_state () = 0;
+
   /* A vfunc for handling custom transitions, such as when registering
      a signal handler.  */
   virtual void on_custom_transition (custom_transition *transition) = 0;
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 332227d71f9..166db887e83 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -490,6 +490,7 @@ Objective-C and Objective-C++ Dialects}.
 -Wno-analyzer-tainted-divisor
 -Wno-analyzer-tainted-offset
 -Wno-analyzer-tainted-size
+-Wanalyzer-symbol-too-complex
 -Wanalyzer-too-complex
 -Wno-analyzer-undefined-behavior-strtok
 -Wno-analyzer-unsafe-call-within-signal-handler
@@ -10526,6 +10527,19 @@ Enabling this option effectively enables the following warnings:
 This option is only available if GCC was configured with analyzer
 support enabled.
 
+@opindex Wanalyzer-symbol-too-complex
+@opindex Wno-analyzer-symbol-too-complex
+@item -Wanalyzer-symbol-too-complex
+If @option{-fanalyzer} is enabled, the analyzer uses various heuristics
+to attempt to track the state of memory, but these can be defeated by
+sufficiently complicated code.
+
+By default, the analysis silently stops tracking values of expressions
+if they exceed the threshold defined by
+@option{--param analyzer-max-svalue-depth=@var{value}}, and falls back
+to an imprecise representation for such expressions.
+The @option{-Wanalyzer-symbol-too-complex} option warns if this occurs.
+
 @opindex Wanalyzer-too-complex
 @opindex Wno-analyzer-too-complex
 @item -Wanalyzer-too-complex
diff --git a/gcc/testsuite/c-c++-common/analyzer/call-summaries-pr107158-2.c b/gcc/testsuite/c-c++-common/analyzer/call-summaries-pr107158-2.c
index 4561e10cafd..b395623ccca 100644
--- a/gcc/testsuite/c-c++-common/analyzer/call-summaries-pr107158-2.c
+++ b/gcc/testsuite/c-c++-common/analyzer/call-summaries-pr107158-2.c
@@ -1,4 +1,4 @@
-/* { dg-additional-options "-fanalyzer-call-summaries -Wno-analyzer-too-complex" } */
+/* { dg-additional-options "-fanalyzer-call-summaries -Wno-analyzer-too-complex -Wno-analyzer-symbol-too-complex" } */
 /* { dg-skip-if "c++98 has no noreturn attribute" { c++98_only } } */
 
 #ifdef __cplusplus
diff --git a/gcc/testsuite/c-c++-common/analyzer/call-summaries-pr107158.c b/gcc/testsuite/c-c++-common/analyzer/call-summaries-pr107158.c
index d4cf079cef8..de705836249 100644
--- a/gcc/testsuite/c-c++-common/analyzer/call-summaries-pr107158.c
+++ b/gcc/testsuite/c-c++-common/analyzer/call-summaries-pr107158.c
@@ -1,4 +1,4 @@
-/* { dg-additional-options "-fanalyzer-call-summaries" } */
+/* { dg-additional-options "-fanalyzer-call-summaries -Wno-analyzer-symbol-too-complex" } */
 
 typedef __SIZE_TYPE__ size_t;
 enum { _ISspace = ((5) < 8 ? ((1 << (5)) << 8) : ((1 << (5)) >> 8)) };
diff --git a/gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr109060-haproxy-cfgparse.c b/gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr109060-haproxy-cfgparse.c
index 1d28e10747c..c4561fcd8a7 100644
--- a/gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr109060-haproxy-cfgparse.c
+++ b/gcc/testsuite/c-c++-common/analyzer/deref-before-check-pr109060-haproxy-cfgparse.c
@@ -1,5 +1,7 @@
 /* Reduced from haproxy-2.7.1's cfgparse.c.  */
 
+/* { dg-additional-options "-Wno-analyzer-too-complex -Wno-analyzer-symbol-too-complex" } */
+
 typedef __SIZE_TYPE__ size_t;
 
 extern int
diff --git a/gcc/testsuite/c-c++-common/analyzer/feasibility-3.c b/gcc/testsuite/c-c++-common/analyzer/feasibility-3.c
index 2fcd064e801..06194f85069 100644
--- a/gcc/testsuite/c-c++-common/analyzer/feasibility-3.c
+++ b/gcc/testsuite/c-c++-common/analyzer/feasibility-3.c
@@ -1,6 +1,8 @@
 /* Reduced and adapted from Linux: fs/proc/inode.c: proc_reg_open
    (GPL v2.0).  */
 
+/* { dg-additional-options "-Wno-analyzer-too-complex -Wno-analyzer-symbol-too-complex" } */
+
 /* Types.  */
 
 typedef unsigned char u8;
diff --git a/gcc/testsuite/c-c++-common/analyzer/flex-with-call-summaries.c b/gcc/testsuite/c-c++-common/analyzer/flex-with-call-summaries.c
index 45edacf0e53..963a84bc9ab 100644
--- a/gcc/testsuite/c-c++-common/analyzer/flex-with-call-summaries.c
+++ b/gcc/testsuite/c-c++-common/analyzer/flex-with-call-summaries.c
@@ -5,6 +5,7 @@
 /* { dg-skip-if "" { "avr-*-*" } } */
 /* { dg-additional-options "-fanalyzer-call-summaries" } */
 /* { dg-additional-options "-Wno-analyzer-too-complex" } */
+/* { dg-additional-options "-Wno-analyzer-symbol-too-complex" } */
 
 /* A lexical scanner generated by flex */
 
@@ -885,8 +886,7 @@ static int yy_get_next_buffer (void)
 				}
 			else
 				/* Can't grow it, we don't own it. */
-				b->yy_ch_buf = NULL;  /* { dg-bogus "leak" "" { xfail *-*-* } } */
-				/* TODO: leak false positive: PR analyzer/103546.  */
+				b->yy_ch_buf = NULL;  /* { dg-bogus "leak" "PR analyzer/103546" } */
 
 			if ( ! b->yy_ch_buf )
 				YY_FATAL_ERROR(
diff --git a/gcc/testsuite/c-c++-common/analyzer/flex-without-call-summaries.c b/gcc/testsuite/c-c++-common/analyzer/flex-without-call-summaries.c
index 5369f7685c2..b1c23312137 100644
--- a/gcc/testsuite/c-c++-common/analyzer/flex-without-call-summaries.c
+++ b/gcc/testsuite/c-c++-common/analyzer/flex-without-call-summaries.c
@@ -886,8 +886,7 @@ static int yy_get_next_buffer (void)
 				}
 			else
 				/* Can't grow it, we don't own it. */
-				b->yy_ch_buf = NULL;  /* { dg-bogus "leak" "" { xfail *-*-* } } */
-				/* TODO: leak false positive: PR analyzer/103546.  */
+				b->yy_ch_buf = NULL;  /* { dg-bogus "leak" "PR analyzer/103546"  */
 
 			if ( ! b->yy_ch_buf )
 				YY_FATAL_ERROR(
diff --git a/gcc/testsuite/c-c++-common/analyzer/infinite-recursion-3.c b/gcc/testsuite/c-c++-common/analyzer/infinite-recursion-3.c
index 68c4fa396ca..2ae20a1108a 100644
--- a/gcc/testsuite/c-c++-common/analyzer/infinite-recursion-3.c
+++ b/gcc/testsuite/c-c++-common/analyzer/infinite-recursion-3.c
@@ -1,4 +1,4 @@
-/* { dg-additional-options "-fno-analyzer-call-summaries -Wno-analyzer-too-complex" } */
+/* { dg-additional-options "-fno-analyzer-call-summaries -Wno-analyzer-too-complex -Wno-analyzer-symbol-too-complex" } */
 
 struct node
 {
diff --git a/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108251-smp_fetch_ssl_fc_has_early-O2.c b/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108251-smp_fetch_ssl_fc_has_early-O2.c
index c46ffe91a6b..c1c8e6f6a39 100644
--- a/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108251-smp_fetch_ssl_fc_has_early-O2.c
+++ b/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108251-smp_fetch_ssl_fc_has_early-O2.c
@@ -1,7 +1,7 @@
 /* Reduced from haproxy's src/ssl_sample.c  */
 
 /* { dg-require-effective-target ptr_eq_long } */
-/* { dg-additional-options "-O2" } */
+/* { dg-additional-options "-O2 -Wno-analyzer-symbol-too-complex" } */
 
 union sample_value {
   long long int sint;
diff --git a/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108251-smp_fetch_ssl_fc_has_early.c b/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108251-smp_fetch_ssl_fc_has_early.c
index ef34a76c50d..c5f1fa42e6f 100644
--- a/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108251-smp_fetch_ssl_fc_has_early.c
+++ b/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108251-smp_fetch_ssl_fc_has_early.c
@@ -1,6 +1,7 @@
 /* Reduced from haproxy's src/ssl_sample.c  */
 
 /* { dg-require-effective-target ptr_eq_long } */
+/* { dg-additional-options "-Wno-analyzer-symbol-too-complex" } */
 
 union sample_value {
   long long int sint;
diff --git a/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108400-SoftEtherVPN-WebUi.c b/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108400-SoftEtherVPN-WebUi.c
index 1151d622519..9dcf7aa31f1 100644
--- a/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108400-SoftEtherVPN-WebUi.c
+++ b/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108400-SoftEtherVPN-WebUi.c
@@ -1,4 +1,6 @@
 /* Reduced from SoftEtherVPN's src/Cedar/WebUI.c.   */
+/* { dg-additional-options "-Wno-analyzer-symbol-too-complex" } */
+
 #include "../../gcc.dg/analyzer/analyzer-decls.h"
 typedef int (COMPARE)(void *p1, void *p2);
 typedef unsigned int UINT;
diff --git a/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108806-qemu.c b/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108806-qemu.c
index f7f6923927f..16ef6574d2f 100644
--- a/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108806-qemu.c
+++ b/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108806-qemu.c
@@ -1,5 +1,7 @@
 /* Reduced from qemu-7.2.0's hw/intc/omap_intc.c */
 
+/* { dg-additional-options "-Wno-analyzer-symbol-too-complex" } */
+
 #include "../../gcc.dg/analyzer/analyzer-decls.h"
 
 typedef unsigned char __uint8_t;
diff --git a/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108830.c b/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108830.c
index 0c95148ebd5..1cb1ebe65f9 100644
--- a/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108830.c
+++ b/gcc/testsuite/c-c++-common/analyzer/null-deref-pr108830.c
@@ -1,6 +1,6 @@
 /* Reduced from apr-1.7.0/tables/apr_hash.c: 'apr_hash_merge' */
 
-/* { dg-additional-options "-Wno-analyzer-too-complex" } */
+/* { dg-additional-options "-Wno-analyzer-too-complex -Wno-analyzer-symbol-too-complex" } */
 
 #include "../../gcc.dg/analyzer/analyzer-decls.h"
 
diff --git a/gcc/testsuite/c-c++-common/analyzer/pr94596.c b/gcc/testsuite/c-c++-common/analyzer/pr94596.c
index 10ea549924e..0d6240941d7 100644
--- a/gcc/testsuite/c-c++-common/analyzer/pr94596.c
+++ b/gcc/testsuite/c-c++-common/analyzer/pr94596.c
@@ -17,6 +17,9 @@
  */
 
 #include "../../gcc.dg/analyzer/analyzer-decls.h"
+
+/* { dg-additional-options "-Wno-analyzer-symbol-too-complex" } */
+
 typedef __SIZE_TYPE__ size_t;
 
 #ifndef __cplusplus
diff --git a/gcc/testsuite/c-c++-common/analyzer/strtok-2.c b/gcc/testsuite/c-c++-common/analyzer/strtok-2.c
index 0336bf0cfe9..f34b4a7198a 100644
--- a/gcc/testsuite/c-c++-common/analyzer/strtok-2.c
+++ b/gcc/testsuite/c-c++-common/analyzer/strtok-2.c
@@ -1,3 +1,5 @@
+/* { dg-additional-options "-Wno-analyzer-symbol-too-complex" } */
+
 #include "../../gcc.dg/analyzer/analyzer-decls.h"
 
 extern char *strtok (char *str, const char *delim)
diff --git a/gcc/testsuite/c-c++-common/analyzer/strtok-4.c b/gcc/testsuite/c-c++-common/analyzer/strtok-4.c
index b6b7d49e3c3..793c7fcb7f4 100644
--- a/gcc/testsuite/c-c++-common/analyzer/strtok-4.c
+++ b/gcc/testsuite/c-c++-common/analyzer/strtok-4.c
@@ -1,3 +1,5 @@
+/* { dg-additional-options "-Wno-analyzer-too-complex -Wno-analyzer-symbol-too-complex" } */
+
 #include "../../gcc.dg/analyzer/analyzer-decls.h"
 
 extern char *strtok (char *str, const char *delim);
diff --git a/gcc/testsuite/c-c++-common/analyzer/strtok-cppreference.c b/gcc/testsuite/c-c++-common/analyzer/strtok-cppreference.c
index a2e912341d6..a396c643f11 100644
--- a/gcc/testsuite/c-c++-common/analyzer/strtok-cppreference.c
+++ b/gcc/testsuite/c-c++-common/analyzer/strtok-cppreference.c
@@ -11,6 +11,8 @@
      should be released under an equivalent license so that everyone could
      benefit from the modified versions. "  */
 
+/* { dg-additional-options " -Wno-analyzer-too-complex -Wno-analyzer-symbol-too-complex" } */
+
 #define __STDC_WANT_LIB_EXT1__ 0
 #include <string.h>
 #include <stdio.h>
diff --git a/gcc/testsuite/gcc.dg/analyzer/analyzer.exp b/gcc/testsuite/gcc.dg/analyzer/analyzer.exp
index cedf3c0466f..ba5aa680fc7 100644
--- a/gcc/testsuite/gcc.dg/analyzer/analyzer.exp
+++ b/gcc/testsuite/gcc.dg/analyzer/analyzer.exp
@@ -30,7 +30,7 @@ if [info exists DEFAULT_CFLAGS] then {
 }
 
 # If a testcase doesn't have special options, use these.
-set DEFAULT_CFLAGS "-fanalyzer -Wanalyzer-too-complex -fanalyzer-call-summaries"
+set DEFAULT_CFLAGS "-fanalyzer -Wanalyzer-too-complex -Wanalyzer-symbol-too-complex -fanalyzer-call-summaries"
 
 if { [istarget "*-*-darwin*" ] } {
   # On macOS, system headers redefine by default some macros (memcpy,
diff --git a/gcc/testsuite/gcc.dg/analyzer/attr-const-3.c b/gcc/testsuite/gcc.dg/analyzer/attr-const-3.c
index fc8527a5d0e..11238a77a65 100644
--- a/gcc/testsuite/gcc.dg/analyzer/attr-const-3.c
+++ b/gcc/testsuite/gcc.dg/analyzer/attr-const-3.c
@@ -1,7 +1,7 @@
 /* Verify that we handle unknown values passed to  __attribute__ ((const))
    (by imposing a complexity limit).  */
 
-/* { dg-additional-options "--param analyzer-max-svalue-depth=4" } */
+/* { dg-additional-options "--param analyzer-max-svalue-depth=4 -Wno-analyzer-symbol-too-complex" } */
 
 #include "analyzer-decls.h"
 
diff --git a/gcc/testsuite/gcc.dg/analyzer/call-summaries-pr107072.c b/gcc/testsuite/gcc.dg/analyzer/call-summaries-pr107072.c
index 6e583d0228f..f59318b428f 100644
--- a/gcc/testsuite/gcc.dg/analyzer/call-summaries-pr107072.c
+++ b/gcc/testsuite/gcc.dg/analyzer/call-summaries-pr107072.c
@@ -1,5 +1,5 @@
 /* { dg-require-effective-target int32plus } */
-/* { dg-additional-options "-fanalyzer-call-summaries --param analyzer-min-snodes-for-call-summary=0" } */
+/* { dg-additional-options "-fanalyzer-call-summaries --param analyzer-min-snodes-for-call-summary=0 -Wno-analyzer-symbol-too-complex" } */
 
 /* There need to be at least two calls to a function for the
    call-summarization code to be used.
diff --git a/gcc/testsuite/gcc.dg/analyzer/doom-s_sound-pr108867.c b/gcc/testsuite/gcc.dg/analyzer/doom-s_sound-pr108867.c
index ae58f03d3b3..fdc21a2bec3 100644
--- a/gcc/testsuite/gcc.dg/analyzer/doom-s_sound-pr108867.c
+++ b/gcc/testsuite/gcc.dg/analyzer/doom-s_sound-pr108867.c
@@ -1,6 +1,6 @@
 /* Reduced from Doom's linuxdoom-1.10/s_sound.c, which is GPLv2 or later.  */
 
-/* { dg-additional-options "-fno-analyzer-call-summaries -Wno-analyzer-too-complex" } */
+/* { dg-additional-options "-fno-analyzer-call-summaries -Wno-analyzer-too-complex -Wno-analyzer-symbol-too-complex" } */
 /* { dg-require-effective-target size32plus } */
 
 typedef struct _IO_FILE FILE;
diff --git a/gcc/testsuite/gcc.dg/analyzer/explode-4.c b/gcc/testsuite/gcc.dg/analyzer/explode-4.c
index 874b1e9c300..a98dfb56bf5 100644
--- a/gcc/testsuite/gcc.dg/analyzer/explode-4.c
+++ b/gcc/testsuite/gcc.dg/analyzer/explode-4.c
@@ -3,7 +3,7 @@
    conjured_svalues whilst handling a long chain of external
    function calls.  */
 
-/* { dg-additional-options "-Wno-implicit-function-declaration -Wno-int-conversion -Wno-analyzer-too-complex" } */
+/* { dg-additional-options "-Wno-implicit-function-declaration -Wno-int-conversion -Wno-analyzer-too-complex -Wno-analyzer-symbol-too-complex" } */
 
 #define NULL ((void *)0)
 typedef unsigned char uint8_t;
diff --git a/gcc/testsuite/gcc.dg/analyzer/null-deref-pr102671-1.c b/gcc/testsuite/gcc.dg/analyzer/null-deref-pr102671-1.c
index 3fe061bdbd8..65c7bac1f7e 100644
--- a/gcc/testsuite/gcc.dg/analyzer/null-deref-pr102671-1.c
+++ b/gcc/testsuite/gcc.dg/analyzer/null-deref-pr102671-1.c
@@ -1,5 +1,5 @@
 /* { dg-require-effective-target ptr_eq_long } */
-/* { dg-additional-options "-O2 -Wno-shift-count-overflow" } */
+/* { dg-additional-options "-O2 -Wno-shift-count-overflow -Wno-analyzer-symbol-too-complex" } */
 
 struct lisp;
 union vectorlike_header { long size; };
diff --git a/gcc/testsuite/gcc.dg/analyzer/null-deref-pr105755.c b/gcc/testsuite/gcc.dg/analyzer/null-deref-pr105755.c
index 2b0ba292e00..5375b4dd6f6 100644
--- a/gcc/testsuite/gcc.dg/analyzer/null-deref-pr105755.c
+++ b/gcc/testsuite/gcc.dg/analyzer/null-deref-pr105755.c
@@ -1,5 +1,5 @@
 /* { dg-require-effective-target int32plus } */
-/* { dg-additional-options "-Wno-analyzer-too-complex -O2" } */
+/* { dg-additional-options "-Wno-analyzer-too-complex -Wno-analyzer-symbol-too-complex -O2" } */
 
 typedef long int ptrdiff_t;
 typedef long int EMACS_INT;
diff --git a/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-curl.c b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-curl.c
index e34b572966e..d14661cbc6a 100644
--- a/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-curl.c
+++ b/gcc/testsuite/gcc.dg/analyzer/out-of-bounds-curl.c
@@ -1,4 +1,4 @@
-/* { dg-additional-options "-O2" } */
+/* { dg-additional-options "-O2 -Wno-analyzer-symbol-too-complex" } */
 #include <string.h>
 
 /* Reduced from curl lib/smb.c.  */
diff --git a/gcc/testsuite/gcc.dg/analyzer/pr101503.c b/gcc/testsuite/gcc.dg/analyzer/pr101503.c
index 16faf6eac2f..cc4d801d8a6 100644
--- a/gcc/testsuite/gcc.dg/analyzer/pr101503.c
+++ b/gcc/testsuite/gcc.dg/analyzer/pr101503.c
@@ -1,4 +1,4 @@
-/* { dg-additional-options "--param analyzer-max-svalue-depth=0" } */
+/* { dg-additional-options "--param analyzer-max-svalue-depth=0 -Wno-analyzer-symbol-too-complex" } */
 
 int val;
 
diff --git a/gcc/testsuite/gcc.dg/analyzer/pr103892.c b/gcc/testsuite/gcc.dg/analyzer/pr103892.c
index d16cd83c472..a17c3b7e119 100644
--- a/gcc/testsuite/gcc.dg/analyzer/pr103892.c
+++ b/gcc/testsuite/gcc.dg/analyzer/pr103892.c
@@ -1,4 +1,4 @@
-/* { dg-additional-options "-O2" } */
+/* { dg-additional-options "-O2 -Wno-analyzer-too-complex -Wno-analyzer-symbol-too-complex" } */
 
 /* C only: C++ FE optimizes argstr_get_word completely away
    and therefore the number of SN diminishes compared to C,
diff --git a/gcc/testsuite/gcc.dg/analyzer/pr94851-4.c b/gcc/testsuite/gcc.dg/analyzer/pr94851-4.c
index 2a15a5d7f5b..a5130c59cb0 100644
--- a/gcc/testsuite/gcc.dg/analyzer/pr94851-4.c
+++ b/gcc/testsuite/gcc.dg/analyzer/pr94851-4.c
@@ -1,4 +1,4 @@
-/* { dg-additional-options "-O2" } */
+/* { dg-additional-options "-O2 -Wno-analyzer-symbol-too-complex" } */
 
 #include <stdlib.h>
 
diff --git a/gcc/testsuite/gcc.dg/analyzer/pr96860-1.c b/gcc/testsuite/gcc.dg/analyzer/pr96860-1.c
index 8f298ec04e7..8be30b3a6da 100644
--- a/gcc/testsuite/gcc.dg/analyzer/pr96860-1.c
+++ b/gcc/testsuite/gcc.dg/analyzer/pr96860-1.c
@@ -1,5 +1,5 @@
 /* { dg-require-effective-target int128 } */
-/* { dg-additional-options "--param analyzer-max-svalue-depth=0" } */
+/* { dg-additional-options "--param analyzer-max-svalue-depth=0 -Wno-analyzer-symbol-too-complex" } */
 
 void x7 (void)
 {
diff --git a/gcc/testsuite/gcc.dg/analyzer/pr96860-2.c b/gcc/testsuite/gcc.dg/analyzer/pr96860-2.c
index 90a818cb283..d12b9a1e1fa 100644
--- a/gcc/testsuite/gcc.dg/analyzer/pr96860-2.c
+++ b/gcc/testsuite/gcc.dg/analyzer/pr96860-2.c
@@ -1,4 +1,4 @@
-/* { dg-additional-options "--param analyzer-max-svalue-depth=0" } */
+/* { dg-additional-options "--param analyzer-max-svalue-depth=0 -Wno-analyzer-symbol-too-complex" } */
 
 void x7 (void)
 {
diff --git a/gcc/testsuite/gcc.dg/analyzer/pr98918.c b/gcc/testsuite/gcc.dg/analyzer/pr98918.c
index ac626ba1f30..c3bbce3e6ec 100644
--- a/gcc/testsuite/gcc.dg/analyzer/pr98918.c
+++ b/gcc/testsuite/gcc.dg/analyzer/pr98918.c
@@ -1,3 +1,5 @@
+/* { dg-additional-options "-Wno-analyzer-symbol-too-complex" } */
+
 #include <stdlib.h>
 
 struct marker {
diff --git a/gcc/testsuite/gcc.dg/analyzer/pr99044-2.c b/gcc/testsuite/gcc.dg/analyzer/pr99044-2.c
index fd71d35d7e4..f7badb92f44 100644
--- a/gcc/testsuite/gcc.dg/analyzer/pr99044-2.c
+++ b/gcc/testsuite/gcc.dg/analyzer/pr99044-2.c
@@ -1,3 +1,5 @@
+/* { dg-additional-options "-Wno-analyzer-symbol-too-complex" } */
+
 struct node
 {
   struct node *next;
diff --git a/gcc/testsuite/gcc.dg/analyzer/uninit-pr108806-qemu.c b/gcc/testsuite/gcc.dg/analyzer/uninit-pr108806-qemu.c
index 34fe802f495..09272011128 100644
--- a/gcc/testsuite/gcc.dg/analyzer/uninit-pr108806-qemu.c
+++ b/gcc/testsuite/gcc.dg/analyzer/uninit-pr108806-qemu.c
@@ -5,6 +5,8 @@
      struct omap_intr_handler_bank_s* bank;
  */
 
+/* { dg-additional-options "-Wno-analyzer-symbol-too-complex" } */
+
 typedef unsigned char __uint8_t;
 typedef unsigned int __uint32_t;
 typedef unsigned long int __uint64_t;
diff --git a/gcc/testsuite/gcc.dg/analyzer/use-after-free.c b/gcc/testsuite/gcc.dg/analyzer/use-after-free.c
index d7e4bc2c6ca..76a85f56335 100644
--- a/gcc/testsuite/gcc.dg/analyzer/use-after-free.c
+++ b/gcc/testsuite/gcc.dg/analyzer/use-after-free.c
@@ -1,3 +1,5 @@
+/* { dg-additional-options "-Wno-analyzer-too-complex -Wno-analyzer-symbol-too-complex" } */
+
 #include <stdlib.h>
 #include "analyzer-decls.h"
 
diff --git a/gcc/testsuite/gcc.dg/plugin/plugin.exp b/gcc/testsuite/gcc.dg/plugin/plugin.exp
index f098a327d31..f0b4bb7a051 100644
--- a/gcc/testsuite/gcc.dg/plugin/plugin.exp
+++ b/gcc/testsuite/gcc.dg/plugin/plugin.exp
@@ -162,7 +162,11 @@ set plugin_test_list [list \
 	  taint-CVE-2011-0521-5.c \
 	  taint-CVE-2011-0521-5-fixed.c \
 	  taint-CVE-2011-0521-6.c \
-	  taint-antipatterns-1.c } \
+	  taint-antipatterns-1.c \
+	  taint-pr112850.c \
+	  taint-pr112850-precise.c \
+	  taint-pr112850-too-complex.c \
+	  taint-pr112850-unsanitized.c } \
     { analyzer_cpython_plugin.c \
 	  cpython-plugin-test-no-Python-h.c \
 	  cpython-plugin-test-PyList_Append.c \
diff --git a/gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-4.c b/gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-4.c
index 06b3468fca5..e268a8eab8f 100644
--- a/gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-4.c
+++ b/gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-4.c
@@ -32,9 +32,9 @@ int test_1(struct file *file, unsigned int cmd, unsigned long arg)
 		if (info->num > 1)
 			return -EINVAL;
 		av7110->ci_slot[info->num].num = info->num; /* { dg-warning "attacker-controlled value" } */
-		av7110->ci_slot[info->num].type = FW_CI_LL_SUPPORT(av7110->arm_app) ? /* { dg-warning "attacker-controlled value" } */
+		av7110->ci_slot[info->num].type = FW_CI_LL_SUPPORT(av7110->arm_app) ?
 							CA_CI_LINK : CA_CI;
-		memcpy(info, &av7110->ci_slot[info->num], sizeof(ca_slot_info_t));  /* { dg-warning "attacker-controlled value" } */
+		memcpy(info, &av7110->ci_slot[info->num], sizeof(ca_slot_info_t));
 	}
 
 	copy_to_user((void __user *)arg, parg, sizeof(sbuf));
diff --git a/gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-5-fixed.c b/gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-5-fixed.c
index 076ada3a20a..b39e693da63 100644
--- a/gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-5-fixed.c
+++ b/gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-5-fixed.c
@@ -39,8 +39,7 @@ int test_1(struct file *file, unsigned int cmd, unsigned long arg)
 		av7110->ci_slot[info->num].num = info->num;
 		av7110->ci_slot[info->num].type = FW_CI_LL_SUPPORT(av7110->arm_app) ?
 							CA_CI_LINK : CA_CI;
-		memcpy(info, &av7110->ci_slot[info->num], sizeof(ca_slot_info_t)); /* { dg-bogus "use of attacker-controlled value in array lookup without bounds checking" "" { xfail *-*-* } } */
-		// FIXME: why the above false +ve?
+		memcpy(info, &av7110->ci_slot[info->num], sizeof(ca_slot_info_t)); /* { dg-bogus "use of attacker-controlled value in array lookup without bounds checking" } */
 	}
 
 	copy_to_user((void __user *)arg, &sbuf, sizeof(sbuf));
diff --git a/gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-5.c b/gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-5.c
index e27ee469df8..fe216c0a3c4 100644
--- a/gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-5.c
+++ b/gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-5.c
@@ -37,9 +37,9 @@ int test_1(struct file *file, unsigned int cmd, unsigned long arg)
 		__analyzer_dump_state ("taint", info->num); /* { dg-warning "has_ub" } */
 
 		av7110->ci_slot[info->num].num = info->num; /* { dg-warning "use of attacker-controlled value '\\*info\\.num' in array lookup without checking for negative" } */
-		av7110->ci_slot[info->num].type = FW_CI_LL_SUPPORT(av7110->arm_app) ? /* { dg-warning "use of attacker-controlled value '\\*info\\.num' in array lookup without checking for negative" } */
+		av7110->ci_slot[info->num].type = FW_CI_LL_SUPPORT(av7110->arm_app) ?
 							CA_CI_LINK : CA_CI;
-		memcpy(info, &av7110->ci_slot[info->num], sizeof(ca_slot_info_t)); /* { dg-warning "use of attacker-controlled value in array lookup without bounds checking" } */
+		memcpy(info, &av7110->ci_slot[info->num], sizeof(ca_slot_info_t));
 	}
 
 	copy_to_user((void __user *)arg, &sbuf, sizeof(sbuf));
diff --git a/gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-6.c b/gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-6.c
index fea70ee5761..5b68de32470 100644
--- a/gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-6.c
+++ b/gcc/testsuite/gcc.dg/plugin/taint-CVE-2011-0521-6.c
@@ -34,9 +34,9 @@ int test_1(struct file *file, unsigned int cmd, unsigned long arg)
 		//__analyzer_break ();
 
 		av7110->ci_slot[info->num].num = info->num; /* { dg-warning "use of attacker-controlled value '\\*info\\.num' in array lookup without bounds checking" } */
-		av7110->ci_slot[info->num].type = FW_CI_LL_SUPPORT(av7110->arm_app) ?  /* { dg-warning "use of attacker-controlled value '\\*info\\.num' in array lookup without bounds checking" } */
+		av7110->ci_slot[info->num].type = FW_CI_LL_SUPPORT(av7110->arm_app) ?
 							CA_CI_LINK : CA_CI;
-		memcpy(info, &av7110->ci_slot[info->num], sizeof(ca_slot_info_t));  /* { dg-warning "use of attacker-controlled value in array lookup without bounds checking" } */
+		memcpy(info, &av7110->ci_slot[info->num], sizeof(ca_slot_info_t));
 	}
 
 	copy_to_user((void __user *)arg, &sbuf, sizeof(sbuf));
diff --git a/gcc/testsuite/gcc.dg/plugin/taint-pr112850-precise.c b/gcc/testsuite/gcc.dg/plugin/taint-pr112850-precise.c
new file mode 100644
index 00000000000..558f0fb1a8a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/plugin/taint-pr112850-precise.c
@@ -0,0 +1,50 @@
+/* Reduced from false positive in Linux kernel in sound/core/rawmidi.c.
+
+   Use a value of --param=analyzer-max-svalue-depth= high enough to avoid
+   UNKNOWN svalues; make sure we don't get false positives with this case.  */
+
+/* { dg-do compile } */
+/* { dg-options "-fanalyzer -O2 -Wanalyzer-symbol-too-complex --param=analyzer-max-svalue-depth=13" } */
+/* { dg-require-effective-target analyzer } */
+
+typedef unsigned long __kernel_ulong_t;
+typedef __kernel_ulong_t __kernel_size_t;
+typedef __kernel_size_t size_t;
+typedef unsigned int gfp_t;
+
+extern unsigned long copy_from_user(void* to, const void* from, unsigned long n);
+
+extern
+__attribute__((__alloc_size__(1)))
+__attribute__((__malloc__)) void*
+kvzalloc(size_t size, gfp_t flags);
+
+struct snd_rawmidi_params
+{
+  int stream;
+  size_t buffer_size;
+};
+
+char *newbuf;
+
+static int
+resize_runtime_buffer(struct snd_rawmidi_params* params)
+{
+  if (params->buffer_size < 32 || params->buffer_size > 1024L * 1024L) /* { dg-bogus "symbol too complicated" } */
+    return -22;
+  newbuf = kvzalloc(params->buffer_size, /* { dg-bogus "use of attacker-controlled value '\\*params.buffer_size' as allocation size without upper-bounds checking" "PR analyzer/112850" } */
+		    (((gfp_t)(0x400u | 0x800u)) | ((gfp_t)0x40u) | ((gfp_t)0x80u)));
+  if (!newbuf)
+    return -12;
+  return 0;
+}
+
+long
+snd_rawmidi_ioctl(unsigned long arg)
+{
+  void* argp = (void*)arg;
+  struct snd_rawmidi_params params;
+  if (copy_from_user(&params, argp, sizeof(struct snd_rawmidi_params)))
+    return -14;
+  return resize_runtime_buffer(&params);
+}
diff --git a/gcc/testsuite/gcc.dg/plugin/taint-pr112850-too-complex.c b/gcc/testsuite/gcc.dg/plugin/taint-pr112850-too-complex.c
new file mode 100644
index 00000000000..2a4ee8197c3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/plugin/taint-pr112850-too-complex.c
@@ -0,0 +1,51 @@
+/* Reduced from false positive in Linux kernel in sound/core/rawmidi.c.
+
+   With --param=analyzer-max-svalue-depth=12, the value being compared
+   at the sanitization is too complex and becomes UNKNOWN; make sure
+   this doesn't lead to a false positive.  */
+
+/* { dg-do compile } */
+/* { dg-options "-fanalyzer -O2 -Wanalyzer-symbol-too-complex --param=analyzer-max-svalue-depth=12" } */
+/* { dg-require-effective-target analyzer } */
+
+typedef unsigned long __kernel_ulong_t;
+typedef __kernel_ulong_t __kernel_size_t;
+typedef __kernel_size_t size_t;
+typedef unsigned int gfp_t;
+
+extern unsigned long copy_from_user(void* to, const void* from, unsigned long n);
+
+extern
+__attribute__((__alloc_size__(1)))
+__attribute__((__malloc__)) void*
+kvzalloc(size_t size, gfp_t flags);
+
+struct snd_rawmidi_params
+{
+  int stream;
+  size_t buffer_size;
+};
+
+char *newbuf;
+
+static int
+resize_runtime_buffer(struct snd_rawmidi_params* params)
+{
+  if (params->buffer_size < 32 || params->buffer_size > 1024L * 1024L) /* { dg-warning "symbol too complicated" } */
+    return -22;
+  newbuf = kvzalloc(params->buffer_size, /* { dg-bogus "use of attacker-controlled value '\\*params.buffer_size' as allocation size without upper-bounds checking" "PR analyzer/112850" } */
+		    (((gfp_t)(0x400u | 0x800u)) | ((gfp_t)0x40u) | ((gfp_t)0x80u)));
+  if (!newbuf)
+    return -12;
+  return 0;
+}
+
+long
+snd_rawmidi_ioctl(unsigned long arg)
+{
+  void* argp = (void*)arg;
+  struct snd_rawmidi_params params;
+  if (copy_from_user(&params, argp, sizeof(struct snd_rawmidi_params)))
+    return -14;
+  return resize_runtime_buffer(&params);
+}
diff --git a/gcc/testsuite/gcc.dg/plugin/taint-pr112850-unsanitized.c b/gcc/testsuite/gcc.dg/plugin/taint-pr112850-unsanitized.c
new file mode 100644
index 00000000000..e46fcb6c8a1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/plugin/taint-pr112850-unsanitized.c
@@ -0,0 +1,50 @@
+/* Reduced from false positive in Linux kernel in sound/core/rawmidi.c,
+   with sanitization removed to make it a true positive.
+
+   Verify that we detect this (with default params).  */
+
+/* { dg-do compile } */
+/* { dg-options "-fanalyzer -O2 -Wanalyzer-too-complex" } */
+/* { dg-require-effective-target analyzer } */
+
+typedef unsigned long __kernel_ulong_t;
+typedef __kernel_ulong_t __kernel_size_t;
+typedef __kernel_size_t size_t;
+typedef unsigned int gfp_t;
+
+extern unsigned long copy_from_user(void* to, const void* from, unsigned long n);
+
+extern
+__attribute__((__alloc_size__(1)))
+__attribute__((__malloc__)) void*
+kvzalloc(size_t size, gfp_t flags);
+
+struct snd_rawmidi_params
+{
+  int stream;
+  size_t buffer_size;
+};
+
+char *newbuf;
+
+static int
+resize_runtime_buffer(struct snd_rawmidi_params* params)
+{
+  /* No sanitization, so we should complain.  */
+  
+  newbuf = kvzalloc(params->buffer_size, /* { dg-warning "use of attacker-controlled value '\\*params.buffer_size' as allocation size without upper-bounds checking" "PR analyzer/112850" } */
+		    (((gfp_t)(0x400u | 0x800u)) | ((gfp_t)0x40u) | ((gfp_t)0x80u)));
+  if (!newbuf)
+    return -12;
+  return 0;
+}
+
+long
+snd_rawmidi_ioctl(unsigned long arg)
+{
+  void* argp = (void*)arg;
+  struct snd_rawmidi_params params;
+  if (copy_from_user(&params, argp, sizeof(struct snd_rawmidi_params)))
+    return -14;
+  return resize_runtime_buffer(&params);
+}
diff --git a/gcc/testsuite/gcc.dg/plugin/taint-pr112850.c b/gcc/testsuite/gcc.dg/plugin/taint-pr112850.c
new file mode 100644
index 00000000000..6fa1d0f9bd4
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/plugin/taint-pr112850.c
@@ -0,0 +1,47 @@
+/* Reduced from false positive in Linux kernel in sound/core/rawmidi.c.  */
+
+/* { dg-do compile } */
+/* { dg-options "-fanalyzer -O2 -Wanalyzer-symbol-too-complex" } */
+/* { dg-require-effective-target analyzer } */
+
+typedef unsigned long __kernel_ulong_t;
+typedef __kernel_ulong_t __kernel_size_t;
+typedef __kernel_size_t size_t;
+typedef unsigned int gfp_t;
+
+extern unsigned long copy_from_user(void* to, const void* from, unsigned long n);
+
+extern
+__attribute__((__alloc_size__(1)))
+__attribute__((__malloc__)) void*
+kvzalloc(size_t size, gfp_t flags);
+
+struct snd_rawmidi_params
+{
+  int stream;
+  size_t buffer_size;
+};
+
+char *newbuf;
+
+static int
+resize_runtime_buffer(struct snd_rawmidi_params* params)
+{
+  if (params->buffer_size < 32 || params->buffer_size > 1024L * 1024L) /* { dg-bogus "symbol too complicated" } */
+    return -22;
+  newbuf = kvzalloc(params->buffer_size, /* { dg-bogus "use of attacker-controlled value '\\*params.buffer_size' as allocation size without upper-bounds checking" "PR analyzer/112850" } */
+		    (((gfp_t)(0x400u | 0x800u)) | ((gfp_t)0x40u) | ((gfp_t)0x80u)));
+  if (!newbuf)
+    return -12;
+  return 0;
+}
+
+long
+snd_rawmidi_ioctl(unsigned long arg)
+{
+  void* argp = (void*)arg;
+  struct snd_rawmidi_params params;
+  if (copy_from_user(&params, argp, sizeof(struct snd_rawmidi_params)))
+    return -14;
+  return resize_runtime_buffer(&params);
+}
