diff --git a/gcc/testsuite/c-c++-common/torture/pr117912-1.c b/gcc/testsuite/c-c++-common/torture/pr117912-1.c
new file mode 100644
index 0000000000000000000000000000000000000000..2750585c7f77a5b88e3e697132c5466c521c9d23
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/pr117912-1.c
@@ -0,0 +1,28 @@
+/* { dg-do run } */
+
+struct S { int a; int b[24]; int c[24]; int d; };
+volatile int *p;
+
+void __attribute__((noipa))
+bar (int *q)
+{
+ p = q;
+}
+
+__SIZE_TYPE__ __attribute__((noipa))
+foo (struct S *p)
+{
+  bar (&p->b[24]);
+  bar (&p->c[0]);
+  return __builtin_object_size (&p->c[0], 1);
+}
+
+int
+main()
+{
+  struct S s;
+  __SIZE_TYPE__ x = foo (&s);
+  if (x < sizeof (int) * 24)
+    __builtin_abort ();
+  return 0;
+}
diff --git a/gcc/testsuite/c-c++-common/torture/pr117912-2.c b/gcc/testsuite/c-c++-common/torture/pr117912-2.c
new file mode 100644
index 0000000000000000000000000000000000000000..a3a6215756351ba97649292f404d4f441aa07d52
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/pr117912-2.c
@@ -0,0 +1,28 @@
+/* { dg-do run } */
+
+struct S { int a; int b[0]; int c[24]; int d; };
+volatile int *p;
+
+void __attribute__((noipa))
+bar (int *q)
+{
+ p = q;
+}
+
+__SIZE_TYPE__ __attribute__((noipa))
+foo (struct S *p)
+{
+  bar (&p->b[0]);
+  bar (&p->c[0]);
+  return __builtin_object_size (&p->c[0], 1);
+}
+
+int
+main()
+{
+  struct S s;
+  __SIZE_TYPE__ x = foo (&s);
+  if (x < sizeof (int) * 24)
+    __builtin_abort ();
+  return 0;
+}
diff --git a/gcc/testsuite/c-c++-common/torture/pr117912-3.c b/gcc/testsuite/c-c++-common/torture/pr117912-3.c
new file mode 100644
index 0000000000000000000000000000000000000000..64e981d2a5e7c16ab79bcaeae8436d162e261b33
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/torture/pr117912-3.c
@@ -0,0 +1,61 @@
+/* { dg-do run } */
+/* { dg-additional-options "-std=gnu++20" { target c++ } } */
+
+struct B {};
+struct A { int a;
+#ifdef __cplusplus
+	   [[no_unique_address]]
+#endif
+	   struct B b;
+	   char c[]; };
+volatile void *p;
+
+void __attribute__((noipa))
+bar (void *q)
+{
+  p = q;
+}
+
+__SIZE_TYPE__ __attribute__((noipa))
+foo (struct A *p)
+{
+  bar (&p->b);
+  bar (&p->c);
+  return __builtin_object_size (&p->c, 1);
+}
+
+__SIZE_TYPE__ __attribute__((noipa))
+baz (void)
+{
+  struct A *p = (struct A *) __builtin_malloc (__builtin_offsetof (struct A, c) + 64);
+  bar (&p->b);
+  bar (&p->c);
+  return __builtin_object_size (&p->c, 1);
+}
+
+__SIZE_TYPE__ __attribute__((noipa))
+qux (struct A *p)
+{
+  bar (&p->b);
+  bar (&p->c);
+  return __builtin_object_size (&p->c, 3);
+}
+
+__SIZE_TYPE__ __attribute__((noipa))
+boo (void)
+{
+  struct A *p = (struct A *) __builtin_malloc (__builtin_offsetof (struct A, c) + 64);
+  bar (&p->b);
+  bar (&p->c);
+  return __builtin_object_size (&p->c, 3);
+}
+
+int
+main ()
+{
+  static struct A a = { .a = 1, .b = {}, .c = { 1, 2, 3, 4, 0 } };
+  if (foo (&a) < 5)
+    __builtin_abort ();
+  if (baz () < 64)
+    __builtin_abort ();
+}
diff --git a/gcc/tree-ssa-sccvn.cc b/gcc/tree-ssa-sccvn.cc
index 8d74731a891cfb76c4b794b92aeae012fec1d632..48819f559c51dd88d87c0180d5ee7fd34e50e6a3 100644
--- a/gcc/tree-ssa-sccvn.cc
+++ b/gcc/tree-ssa-sccvn.cc
@@ -985,11 +985,14 @@ copy_reference_ops_from_ref (tree ref, vec<vn_reference_op_s> *result)
 		    poly_offset_int off
 		      = (wi::to_poly_offset (this_offset)
 			 + (wi::to_offset (bit_offset) >> LOG2_BITS_PER_UNIT));
-		    /* Probibit value-numbering zero offset components
+		    /* Prohibit value-numbering zero offset components
 		       of addresses the same before the pass folding
-		       __builtin_object_size had a chance to run.  */
+		       __builtin_object_size had a chance to run.  Likewise
+		       for components of zero size at arbitrary offset.  */
 		    if (TREE_CODE (orig) != ADDR_EXPR
-			|| maybe_ne (off, 0)
+			|| (TYPE_SIZE (temp.type)
+			    && integer_nonzerop (TYPE_SIZE (temp.type))
+			    && maybe_ne (off, 0))
 			|| (cfun->curr_properties & PROP_objsz))
 		      off.to_shwi (&temp.off);
 		  }
@@ -1010,9 +1013,31 @@ copy_reference_ops_from_ref (tree ref, vec<vn_reference_op_s> *result)
 	    if (! temp.op2)
 	      temp.op2 = size_binop (EXACT_DIV_EXPR, TYPE_SIZE_UNIT (eltype),
 				     size_int (TYPE_ALIGN_UNIT (eltype)));
+	    /* Prohibit value-numbering addresses of one-after-the-last
+	       element ARRAY_REFs the same as addresses of other components
+	       before the pass folding __builtin_object_size had a chance
+	       to run.  */
+	    bool avoid_oob = true;
+	    if (TREE_CODE (orig) != ADDR_EXPR
+		|| cfun->curr_properties & PROP_objsz)
+	      avoid_oob = false;
+	    else if (poly_int_tree_p (temp.op0))
+	      {
+		tree ub = array_ref_up_bound (ref);
+		if (ub
+		    && poly_int_tree_p (ub)
+		    /* ???  The C frontend for T[0] uses [0:] and the
+		       C++ frontend [0:-1U].  See layout_type for how
+		       awkward this is.  */
+		    && !integer_minus_onep (ub)
+		    && known_le (wi::to_poly_offset (temp.op0),
+				 wi::to_poly_offset (ub)))
+		  avoid_oob = false;
+	      }
 	    if (poly_int_tree_p (temp.op0)
 		&& poly_int_tree_p (temp.op1)
-		&& TREE_CODE (temp.op2) == INTEGER_CST)
+		&& TREE_CODE (temp.op2) == INTEGER_CST
+		&& !avoid_oob)
 	      {
 		poly_offset_int off = ((wi::to_poly_offset (temp.op0)
 					- wi::to_poly_offset (temp.op1))
@@ -1754,6 +1779,24 @@ re_valueize:
 	       && poly_int_tree_p (vro->op1)
 	       && TREE_CODE (vro->op2) == INTEGER_CST)
 	{
+	    /* Prohibit value-numbering addresses of one-after-the-last
+	       element ARRAY_REFs the same as addresses of other components
+	       before the pass folding __builtin_object_size had a chance
+	       to run.  */
+	  if (!(cfun->curr_properties & PROP_objsz)
+	      && (*orig)[0].opcode == ADDR_EXPR)
+	    {
+	      tree dom = TYPE_DOMAIN ((*orig)[i + 1].type);
+	      if (!dom
+		  || !TYPE_MAX_VALUE (dom)
+		  || !poly_int_tree_p (TYPE_MAX_VALUE (dom))
+		  || integer_minus_onep (TYPE_MAX_VALUE (dom)))
+		continue;
+	      if (!known_le (wi::to_poly_offset (vro->op0),
+			     wi::to_poly_offset (TYPE_MAX_VALUE (dom))))
+		continue;
+	    }
+
 	  poly_offset_int off = ((wi::to_poly_offset (vro->op0)
 				  - wi::to_poly_offset (vro->op1))
 				 * wi::to_offset (vro->op2)