Hi Jakub,

The patch that is attached now is bootstrapped and regression tested on 
x86_64-pc-linux-gnu.

> 
> This file is used not just in the various tools like binutils or gdb, but
> also in libstdc++, where it used e.g. in the std::terminate handler,
> which I think can't just xmalloc_failed, that function can be called already
> in out of memory situation, where heap allocation is not possible.

Earlier, I was working on libiberty/cplus-dem.c where xmalloc was explicitly 
available. So, I assumed it would be in libiberty/cp-demangle.c as well.

> Why INT_MAX?
> I'd have thought that the allocation size is computed in size_t and
> thus it should be SIZE_MAX, (~(size_t) 0) or similar?

In two separate patches (the first in cplus-dem.c and the second in 
cp-demangle.c) it was decided that we should import limit.h and otherwise 
define INT_MAX, then check against INT_MAX.
However, I removed the overflow check since it is not clear what the behaviour 
should be when the integer actually overflows. Apparently, it can’t abort. 
Still, this remains an unresolved security concern if actually inputs can 
actually be generated that result in overflow.

I also fixed some indentation issues caused by the removal of 
in-the-middle-of-the-method variable declarations.

-  {
-#ifdef CP_DYNAMIC_ARRAYS
-    __extension__ struct d_saved_scope scopes[dpi.num_saved_scopes];
-    __extension__ struct d_print_template temps[dpi.num_copy_templates];

Let me know if there are more concerns. There might be some more formatting 
issues lingering.

Best regards,
- Marcel


Index: ChangeLog
===================================================================
--- ChangeLog   (revision 235941)
+++ ChangeLog   (working copy)
@@ -1,3 +1,14 @@
+2016-05-06  Marcel Böhme  <boehme.mar...@gmail.com>
+
+       PR c++/68159
+       * cp-demangle.c: Allocate arrays of user-defined size on the heap,
+       not on the stack.
+       (CP_DYNAMIC_ARRAYS): Remove redundant definition.
+       (cplus_demangle_print_callback): Allocate memory for two arrays on
+       the heap. Free memory before return / exit.
+       (d_demangle_callback): Likewise.
+       (is_ctor_or_dtor): Likewise. 
+
 2016-05-02  Marcel Böhme  <boehme.mar...@gmail.com>
 
        PR c++/70498
Index: cp-demangle.c
===================================================================
--- cp-demangle.c       (revision 235941)
+++ cp-demangle.c       (working copy)
@@ -186,20 +186,6 @@ static void d_init_info (const char *, int, size_t
 #define CP_STATIC_IF_GLIBCPP_V3
 #endif /* ! defined(IN_GLIBCPP_V3) */
 
-/* See if the compiler supports dynamic arrays.  */
-
-#ifdef __GNUC__
-#define CP_DYNAMIC_ARRAYS
-#else
-#ifdef __STDC__
-#ifdef __STDC_VERSION__
-#if __STDC_VERSION__ >= 199901L
-#define CP_DYNAMIC_ARRAYS
-#endif /* __STDC__VERSION >= 199901L */
-#endif /* defined (__STDC_VERSION__) */
-#endif /* defined (__STDC__) */
-#endif /* ! defined (__GNUC__) */
-
 /* We avoid pulling in the ctype tables, to prevent pulling in
    additional unresolved symbols when this code is used in a library.
    FIXME: Is this really a valid reason?  This comes from the original
@@ -4125,26 +4111,20 @@ cplus_demangle_print_callback (int options,
   struct d_print_info dpi;
 
   d_print_init (&dpi, callback, opaque, dc);
+  
+  dpi.copy_templates = (struct d_print_template *)
+      malloc (dpi.num_copy_templates * sizeof (*dpi.copy_templates));
 
-  {
-#ifdef CP_DYNAMIC_ARRAYS
-    __extension__ struct d_saved_scope scopes[dpi.num_saved_scopes];
-    __extension__ struct d_print_template temps[dpi.num_copy_templates];
+  dpi.saved_scopes = (struct d_saved_scope *) 
+      malloc (dpi.num_saved_scopes * sizeof (*dpi.saved_scopes));
 
-    dpi.saved_scopes = scopes;
-    dpi.copy_templates = temps;
-#else
-    dpi.saved_scopes = alloca (dpi.num_saved_scopes
-                              * sizeof (*dpi.saved_scopes));
-    dpi.copy_templates = alloca (dpi.num_copy_templates
-                                * sizeof (*dpi.copy_templates));
-#endif
+  d_print_comp (&dpi, options, dc);
 
-    d_print_comp (&dpi, options, dc);
-  }
-
   d_print_flush (&dpi);
 
+  free(dpi.copy_templates);
+  free(dpi.saved_scopes);
+
   return ! d_print_saw_error (&dpi);
 }
 
@@ -5945,57 +5925,54 @@ d_demangle_callback (const char *mangled, int opti
 
   cplus_demangle_init_info (mangled, options, strlen (mangled), &di);
 
-  {
-#ifdef CP_DYNAMIC_ARRAYS
-    __extension__ struct demangle_component comps[di.num_comps];
-    __extension__ struct demangle_component *subs[di.num_subs];
+  di.comps = (struct demangle_component *) malloc (di.num_comps 
+                                                   * sizeof (*di.comps));
 
-    di.comps = comps;
-    di.subs = subs;
-#else
-    di.comps = alloca (di.num_comps * sizeof (*di.comps));
-    di.subs = alloca (di.num_subs * sizeof (*di.subs));
-#endif
+  di.subs = (struct demangle_component **) malloc (di.num_subs 
+                                                  * sizeof (*di.subs));
 
-    switch (type)
-      {
-      case DCT_TYPE:
-       dc = cplus_demangle_type (&di);
-       break;
-      case DCT_MANGLED:
-       dc = cplus_demangle_mangled_name (&di, 1);
-       break;
-      case DCT_GLOBAL_CTORS:
-      case DCT_GLOBAL_DTORS:
-       d_advance (&di, 11);
-       dc = d_make_comp (&di,
-                         (type == DCT_GLOBAL_CTORS
-                          ? DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS
-                          : DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS),
-                         d_make_demangle_mangled_name (&di, d_str (&di)),
-                         NULL);
-       d_advance (&di, strlen (d_str (&di)));
-       break;
-      default:
-       abort (); /* We have listed all the cases.  */
-      }
+  switch (type)
+    {
+    case DCT_TYPE:
+      dc = cplus_demangle_type (&di);
+      break;
+    case DCT_MANGLED:
+      dc = cplus_demangle_mangled_name (&di, 1);
+      break;
+    case DCT_GLOBAL_CTORS:
+    case DCT_GLOBAL_DTORS:
+      d_advance (&di, 11);
+      dc = d_make_comp (&di,
+                       (type == DCT_GLOBAL_CTORS
+                        ? DEMANGLE_COMPONENT_GLOBAL_CONSTRUCTORS
+                        : DEMANGLE_COMPONENT_GLOBAL_DESTRUCTORS),
+                       d_make_demangle_mangled_name (&di, d_str (&di)),
+                       NULL);
+      d_advance (&di, strlen (d_str (&di)));
+      break;
+    default:
+      free (di.comps);
+      free (di.subs);
+      abort (); /* We have listed all the cases.  */
+    }
 
-    /* If DMGL_PARAMS is set, then if we didn't consume the entire
-       mangled string, then we didn't successfully demangle it.  If
-       DMGL_PARAMS is not set, we didn't look at the trailing
-       parameters.  */
-    if (((options & DMGL_PARAMS) != 0) && d_peek_char (&di) != '\0')
-      dc = NULL;
+  /* If DMGL_PARAMS is set, then if we didn't consume the entire
+     mangled string, then we didn't successfully demangle it.  If
+     DMGL_PARAMS is not set, we didn't look at the trailing
+     parameters.  */
+  if (((options & DMGL_PARAMS) != 0) && d_peek_char (&di) != '\0')
+    dc = NULL;
 
 #ifdef CP_DEMANGLE_DEBUG
-    d_dump (dc, 0);
+  d_dump (dc, 0);
 #endif
 
-    status = (dc != NULL)
-             ? cplus_demangle_print_callback (options, dc, callback, opaque)
-             : 0;
-  }
-
+  status = (dc != NULL)
+           ? cplus_demangle_print_callback (options, dc, callback, opaque)
+           : 0;
+  
+  free (di.comps);
+  free (di.subs);
   return status;
 }
 
@@ -6226,60 +6203,55 @@ is_ctor_or_dtor (const char *mangled,
 
   cplus_demangle_init_info (mangled, DMGL_GNU_V3, strlen (mangled), &di);
 
-  {
-#ifdef CP_DYNAMIC_ARRAYS
-    __extension__ struct demangle_component comps[di.num_comps];
-    __extension__ struct demangle_component *subs[di.num_subs];
+  di.comps = (struct demangle_component *) malloc (di.num_comps 
+                                                   * sizeof (*di.comps));
 
-    di.comps = comps;
-    di.subs = subs;
-#else
-    di.comps = alloca (di.num_comps * sizeof (*di.comps));
-    di.subs = alloca (di.num_subs * sizeof (*di.subs));
-#endif
+  di.subs = (struct demangle_component **) malloc (di.num_subs 
+                                                  * sizeof (*di.subs));
 
-    dc = cplus_demangle_mangled_name (&di, 1);
+  dc = cplus_demangle_mangled_name (&di, 1);
 
-    /* Note that because we did not pass DMGL_PARAMS, we don't expect
-       to demangle the entire string.  */
+  /* Note that because we did not pass DMGL_PARAMS, we don't expect
+     to demangle the entire string.  */
 
-    ret = 0;
-    while (dc != NULL)
-      {
-       switch (dc->type)
-         {
-           /* These cannot appear on a constructor or destructor.  */
-         case DEMANGLE_COMPONENT_RESTRICT_THIS:
-         case DEMANGLE_COMPONENT_VOLATILE_THIS:
-         case DEMANGLE_COMPONENT_CONST_THIS:
-         case DEMANGLE_COMPONENT_REFERENCE_THIS:
-         case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
-         case DEMANGLE_COMPONENT_TRANSACTION_SAFE:
-         default:
-           dc = NULL;
-           break;
-         case DEMANGLE_COMPONENT_TYPED_NAME:
-         case DEMANGLE_COMPONENT_TEMPLATE:
-           dc = d_left (dc);
-           break;
-         case DEMANGLE_COMPONENT_QUAL_NAME:
-         case DEMANGLE_COMPONENT_LOCAL_NAME:
-           dc = d_right (dc);
-           break;
-         case DEMANGLE_COMPONENT_CTOR:
-           *ctor_kind = dc->u.s_ctor.kind;
-           ret = 1;
-           dc = NULL;
-           break;
-         case DEMANGLE_COMPONENT_DTOR:
-           *dtor_kind = dc->u.s_dtor.kind;
-           ret = 1;
-           dc = NULL;
-           break;
-         }
-      }
-  }
+  ret = 0;
+  while (dc != NULL)
+    {
+      switch (dc->type)
+       {
+         /* These cannot appear on a constructor or destructor.  */
+       case DEMANGLE_COMPONENT_RESTRICT_THIS:
+       case DEMANGLE_COMPONENT_VOLATILE_THIS:
+       case DEMANGLE_COMPONENT_CONST_THIS:
+       case DEMANGLE_COMPONENT_REFERENCE_THIS:
+       case DEMANGLE_COMPONENT_RVALUE_REFERENCE_THIS:
+       case DEMANGLE_COMPONENT_TRANSACTION_SAFE:
+       default:
+         dc = NULL;
+         break;
+       case DEMANGLE_COMPONENT_TYPED_NAME:
+       case DEMANGLE_COMPONENT_TEMPLATE:
+         dc = d_left (dc);
+         break;
+       case DEMANGLE_COMPONENT_QUAL_NAME:
+       case DEMANGLE_COMPONENT_LOCAL_NAME:
+         dc = d_right (dc);
+         break;
+       case DEMANGLE_COMPONENT_CTOR:
+         *ctor_kind = dc->u.s_ctor.kind;
+         ret = 1;
+         dc = NULL;
+         break;
+       case DEMANGLE_COMPONENT_DTOR:
+         *dtor_kind = dc->u.s_dtor.kind;
+         ret = 1;
+         dc = NULL;
+         break;
+       }
+    }
 
+  free (di.comps);
+  free (di.subs);
   return ret;
 }
 
Index: testsuite/demangle-expected
===================================================================
--- testsuite/demangle-expected (revision 235941)
+++ testsuite/demangle-expected (working copy)
@@ -4441,3 +4441,8 @@ __vt_90000000000cafebabe
 
 _Z80800000000000000000000
 _Z80800000000000000000000
+#
+# Tests stack overflow
+
+_ZZN5Eigen9DenseBaseINS_5BlockINS_6MatrixIdLin1ELin1ELi0ELin1ELin1EEELin1ELin1ELb1EEEE10lazyAssignINS_12CwiseUnaryOpIZZN6netops4expr6sampleINS9_12nn6_combinerIN5boost3mpl9vector2_cIiLi0ELi2EEENS9_11rowwise_addINS9_6matmulINS9_12input_matrixINSE_IiLi0ELi0EEENSC_6fusion7vector3INSK_7vector4IN4nnet8mat_sizeIdLi1EEESP_NSO_IiLi0EEENSO_IdLi0EEEEENSK_7vector7ISP_SP_SP_SP_SP_SP_SP_EENSN_11config_dataIN3nn66detail8nn6_modeILb1EEEEEEEEENS9_13weight_matrixINSD_6v_itemIN4mpl_4int_ILi0EEENSD_9vector1_cIiLi2EEELi0EEENSK_7vector6INSK_7vector2ISP_NSN_8vec_sizeIdLi1EEEEES1F_S1F_S1F_S1F_S1F_EEEEEENS13_INS14_INS16_ILi1EEES19_Li0EEES1G_EEEENS9_16logistic_sigmoidINSG_INSH_INS1N_INSG_INSH_INSI_INSE_IiLi0ELi1EEES11_EENS13_INS14_IS17_NS18_IiLi0EEELi0EEES1G_EEEENS13_INS14_IS1J_S1Q_Li0EEES1G_EEEEEENS13_INS14_IS17_NS18_IiLi1EEELi0EEES1G_EEEENS13_INS14_IS1J_S1Y_Li0EEES1G_EEEEEEEEEclINSL_INSM_INS_12SparseMatrixIdLi1EiEENS2_IdLin1ELin1ELi1ELin1ELin1EEENS2_IiLin1ELi1ELi0ELin1ELi1EEENS2_IdLin1ELi1ELi0ELin1ELi1EEEEENST_IS2A_S2A_S2A_S2A_S2A_S2A_S2A_EESZ_EENS1B_INS1C_INS_3MapIS2B_Li1ENS_6StrideILi0ELi0EEEEENS2H_INS2_IdLi1ELin1ELi1ELi1ELin1EEELi1ES2J_EEEES2N_S2N_S2N_S2N_S2N_EEZZNS9_6concatIJNSI_INSE_IiLi0ELi3EEES11_EENS9_7dropoutILb0ES19_NS1N_INS2P_IJNSG_INSH_INSI_INSE_IiLi1ELi0EEES11_EENS13_INS14_IS17_NS18_IiLi3EEELi0EEES1G_EEEENS13_INS14_IS1J_S2V_Li0EEES1G_EEEENSG_INSH_INSI_INSE_IiLi1ELi1EEES11_EES2X_EES30_EENSG_INSH_INSI_INSE_IiLi1ELi2EEES11_EES2X_EES30_EENSG_INSH_INSI_INSE_IiLi1ELi3EEES11_EES2X_EES30_EENSG_INSH_INSI_INSE_IiLi1ELi4EEES11_EES2X_EES30_EENSG_INSH_INSI_INSE_IiLi1ELi5EEES11_EES2X_EES30_EENSG_INSH_INSI_INSE_IiLi1ELi6EEES11_EES2X_EES30_EEEEEEEEES27_EEclIS2G_S2O_ZNS9_6detail11binary_contIS2G_S2O_S3T_NS13_INS14_IS17_NS18_IiLi4EEELi0EEES1G_EEZNSH_IS3T_S3Z_EclIS2G_S2O_ZNS3W_IS2G_S2O_S40_NS13_INS14_IS1J_S3X_Li0EEES1G_EEZNSG_IS40_S43_EclIS2G_S2O_ZNS1N_IS44_EclIS2G_S2O_ZNS9_7concat2IS2R_S46_EclIS2G_S2O_ZNS3W_IS2G_S2O_S49_NS13_INS14_IS17_NS18_IiLi5EEELi0EEES1G_EEZNSH_IS49_S4D_EclIS2G_S2O_ZNS3W_IS2G_S2O_S4E_NS13_INS14_IS1J_S4B_Li0EEES1G_EEZNSG_IS4E_S4H_EclIS2G_S2O_ZNS9_11concat_zeroIS4I_EclIS2G_S2O_ZNS9_20softmax_crossentropyIS4L_EclIS2G_S2O_ZNKS8_11derived_ptrIS4O_E5fpropIS2G_S2O_EEDaRKT_RKT0_EUlOS4T_OS4W_OT1_E_EEDaS4V_S4Y_S52_EUlS4Z_S50_S52_E_EEDaS4V_S4Y_S52_EUlS4Z_S50_S52_E_EEDaS4V_S4Y_S52_EUlS4Z_S50_S52_OT2_E_EEDaRKNS4Q_IS51_EERKNS4Q_IS56_EES4V_S4Y_OKT3_EUlS4Z_S50_S52_E_EEDaS4V_S4Y_S52_EUlS4Z_S50_S52_S57_E_EEDaS5B_S5E_S4V_S4Y_S5H_EUlS4Z_S50_S52_E_EEDaS4V_S4Y_S52_EUlS4Z_S50_S52_E0_EEDaS4V_S4Y_S52_EUlS4Z_S50_S52_E_EEDaS4V_S4Y_S52_EUlS4Z_S50_S52_S57_E_EEDaS5B_S5E_S4V_S4Y_S5H_EUlS4Z_S50_S52_E_EEDaS4V_S4Y_S52_EUlS4Z_S50_S52_S57_E_EEDaS5B_S5E_S4V_S4Y_S5H_EUlS4Z_S50_S52_E_EEDaS4V_S4Y_S52_ENKUlmRS4T_E0_clINS4Q_IS27_EEEEDamS5R_EUlS4Z_S50_S52_E_EEDaS4V_S4Y_S52_ENKUlS4Z_S50_S52_E_clIRKS2G_RKS2O_KNS_22SparseTimeDenseProductIS2A_S2B_EEEEDaS4Z_S50_S52_EUldE_S64_EEEERS4_RKNS0_IS4T_EEE19__PRETTY_FUNCTION__
+_ZZN5Eigen9DenseBaseINS_5BlockINS_6MatrixIdLin1ELin1ELi0ELin1ELin1EEELin1ELin1ELb1EEEE10lazyAssignINS_12CwiseUnaryOpIZZN6netops4expr6sampleINS9_12nn6_combinerIN5boost3mpl9vector2_cIiLi0ELi2EEENS9_11rowwise_addINS9_6matmulINS9_12input_matrixINSE_IiLi0ELi0EEENSC_6fusion7vector3INSK_7vector4IN4nnet8mat_sizeIdLi1EEESP_NSO_IiLi0EEENSO_IdLi0EEEEENSK_7vector7ISP_SP_SP_SP_SP_SP_SP_EENSN_11config_dataIN3nn66detail8nn6_modeILb1EEEEEEEEENS9_13weight_matrixINSD_6v_itemIN4mpl_4int_ILi0EEENSD_9vector1_cIiLi2EEELi0EEENSK_7vector6INSK_7vector2ISP_NSN_8vec_sizeIdLi1EEEEES1F_S1F_S1F_S1F_S1F_EEEEEENS13_INS14_INS16_ILi1EEES19_Li0EEES1G_EEEENS9_16logistic_sigmoidINSG_INSH_INS1N_INSG_INSH_INSI_INSE_IiLi0ELi1EEES11_EENS13_INS14_IS17_NS18_IiLi0EEELi0EEES1G_EEEENS13_INS14_IS1J_S1Q_Li0EEES1G_EEEEEENS13_INS14_IS17_NS18_IiLi1EEELi0EEES1G_EEEENS13_INS14_IS1J_S1Y_Li0EEES1G_EEEEEEEEEclINSL_INSM_INS_12SparseMatrixIdLi1EiEENS2_IdLin1ELin1ELi1ELin1ELin1EEENS2_IiLin1ELi1ELi0ELin1ELi1EEENS2_IdLin1ELi1ELi0ELin1ELi1EEEEENST_IS2A_S2A_S2A_S2A_S2A_S2A_S2A_EESZ_EENS1B_INS1C_INS_3MapIS2B_Li1ENS_6StrideILi0ELi0EEEEENS2H_INS2_IdLi1ELin1ELi1ELi1ELin1EEELi1ES2J_EEEES2N_S2N_S2N_S2N_S2N_EEZZNS9_6concatIJNSI_INSE_IiLi0ELi3EEES11_EENS9_7dropoutILb0ES19_NS1N_INS2P_IJNSG_INSH_INSI_INSE_IiLi1ELi0EEES11_EENS13_INS14_IS17_NS18_IiLi3EEELi0EEES1G_EEEENS13_INS14_IS1J_S2V_Li0EEES1G_EEEENSG_INSH_INSI_INSE_IiLi1ELi1EEES11_EES2X_EES30_EENSG_INSH_INSI_INSE_IiLi1ELi2EEES11_EES2X_EES30_EENSG_INSH_INSI_INSE_IiLi1ELi3EEES11_EES2X_EES30_EENSG_INSH_INSI_INSE_IiLi1ELi4EEES11_EES2X_EES30_EENSG_INSH_INSI_INSE_IiLi1ELi5EEES11_EES2X_EES30_EENSG_INSH_INSI_INSE_IiLi1ELi6EEES11_EES2X_EES30_EEEEEEEEES27_EEclIS2G_S2O_ZNS9_6detail11binary_contIS2G_S2O_S3T_NS13_INS14_IS17_NS18_IiLi4EEELi0EEES1G_EEZNSH_IS3T_S3Z_EclIS2G_S2O_ZNS3W_IS2G_S2O_S40_NS13_INS14_IS1J_S3X_Li0EEES1G_EEZNSG_IS40_S43_EclIS2G_S2O_ZNS1N_IS44_EclIS2G_S2O_ZNS9_7concat2IS2R_S46_EclIS2G_S2O_ZNS3W_IS2G_S2O_S49_NS13_INS14_IS17_NS18_IiLi5EEELi0EEES1G_EEZNSH_IS49_S4D_EclIS2G_S2O_ZNS3W_IS2G_S2O_S4E_NS13_INS14_IS1J_S4B_Li0EEES1G_EEZNSG_IS4E_S4H_EclIS2G_S2O_ZNS9_11concat_zeroIS4I_EclIS2G_S2O_ZNS9_20softmax_crossentropyIS4L_EclIS2G_S2O_ZNKS8_11derived_ptrIS4O_E5fpropIS2G_S2O_EEDaRKT_RKT0_EUlOS4T_OS4W_OT1_E_EEDaS4V_S4Y_S52_EUlS4Z_S50_S52_E_EEDaS4V_S4Y_S52_EUlS4Z_S50_S52_E_EEDaS4V_S4Y_S52_EUlS4Z_S50_S52_OT2_E_EEDaRKNS4Q_IS51_EERKNS4Q_IS56_EES4V_S4Y_OKT3_EUlS4Z_S50_S52_E_EEDaS4V_S4Y_S52_EUlS4Z_S50_S52_S57_E_EEDaS5B_S5E_S4V_S4Y_S5H_EUlS4Z_S50_S52_E_EEDaS4V_S4Y_S52_EUlS4Z_S50_S52_E0_EEDaS4V_S4Y_S52_EUlS4Z_S50_S52_E_EEDaS4V_S4Y_S52_EUlS4Z_S50_S52_S57_E_EEDaS5B_S5E_S4V_S4Y_S5H_EUlS4Z_S50_S52_E_EEDaS4V_S4Y_S52_EUlS4Z_S50_S52_S57_E_EEDaS5B_S5E_S4V_S4Y_S5H_EUlS4Z_S50_S52_E_EEDaS4V_S4Y_S52_ENKUlmRS4T_E0_clINS4Q_IS27_EEEEDamS5R_EUlS4Z_S50_S52_E_EEDaS4V_S4Y_S52_ENKUlS4Z_S50_S52_E_clIRKS2G_RKS2O_KNS_22SparseTimeDenseProductIS2A_S2B_EEEEDaS4Z_S50_S52_EUldE_S64_EEEERS4_RKNS0_IS4T_EEE19__PRETTY_FUNCTION__



Reply via email to