Catching SEGVs with __try/__except is MSVC only, not general C++
Nicholas Clark [Thu, 14 Apr 2011 13:19:15 +0000 (14:19 +0100)]
__try/__except is an MSVC extension to C++ *and* C, and is orthogonal to
"regular" C++ exception handling. As there's no way to catch a SEGV with
C++ exceptions (certainly not portably), and __try/__except is available in C,
there's nothing to be gained from using C++ exceptions, and hence making the
code require a C++ compiler. Hence remove the logic from Makefile.PL to force
compilation with a C++ compiler, which didn't even work well on "both" kinds of
OS, as it assumed that the C compiler was named *exactly* qr/\Ag?cc\z/, and
that the analogous C++ compiler was available and named g++.

[Which isn't true when it's named 'ccache gcc', 'gcc-mp-4.6' etc, or when cc
isn't gcc]

CHANGES
Makefile.PL
README
Size.xs
lib/Devel/Size.pm

diff --git a/CHANGES b/CHANGES
index 2fc570f..32adffb 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,8 @@
 Revision history for Perl extension Devel::Size.
 
 0.72_50 2011-04-14 nicholas
+ * Exception handling is totally MSVC specific, so only use it there
+   - this means that we don't need to use a C++ compiler anywhere
  * Resolve CPAN #49437 (Devel::Size adds magic in Perl 5.10)
 
 0.72 2008-10-14 BrowserUk 70 tests
index 2f441a6..633ab1c 100644 (file)
@@ -1,11 +1,6 @@
 use ExtUtils::MakeMaker;
-use Config;
 
-my %options = (       
+WriteMakefile(
   NAME => 'Devel::Size',
-  LIBS => $Config{cc} eq 'gcc' || $Config{cc} eq 'cc' ? ['-lstdc++'] : '',
   VERSION_FROM => 'lib/Devel/Size.pm',
-  CC => $Config{cc} eq 'cl' ? 'cl' : 'g++',
 );
-
-WriteMakefile(%options);
diff --git a/README b/README
index 15e173c..e6963c5 100644 (file)
--- a/README
+++ b/README
@@ -38,13 +38,6 @@ On Linux, Cygwin, or Unix:
     make test
     sudo make install
     
-On most systems, it is necessary to link to libstdc++. On such systems,
-libstdc++ should be found automatically (by default).
-If libstdc++ is *not* being found automatically (in which case you'll get
-link errors),then instead of running 'perl Makefile.PL', you'll need to run:
-
-    perl Makefile.pl LIBS="-L/path/to/libstdc++ -lstdc++"
-
 On Windows:
 
     perl Makefile.PL
diff --git a/Size.xs b/Size.xs
index 19725a0..e155852 100644 (file)
--- a/Size.xs
+++ b/Size.xs
@@ -2,14 +2,17 @@
 #include "perl.h"
 #include "XSUB.h"
 
-
 #ifdef _MSC_VER 
-#   include <excpt.h>
-#   define try __try
-#   define catch __except
-#   define EXCEPTION EXCEPTION_EXECUTE_HANDLER
+/* "structured exception" handling is a Microsoft extension to C and C++.
+   It's *not* C++ exception handling - C++ exception handling can't capture
+   SEGVs and suchlike, whereas this can. There's no known analagous
+    functionality on other platforms.  */
+#  include <excpt.h>
+#  define TRY_TO_CATCH_SEGV __try
+#  define CAUGHT_EXCEPTION __except(EXCEPTION EXCEPTION_EXECUTE_HANDLER)
 #else
-#   define EXCEPTION ...
+#  define TRY_TO_CATCH_SEGV if(1)
+#  define CAUGHT_EXCEPTION else
 #endif
 
 #ifdef __GNUC__
@@ -50,10 +53,10 @@ IV check_new( TRACKING *tv, void *p ) {
     unsigned int  nop  =  (unsigned long)p & 0x3U;
     
     if (NULL == p || NULL == tv) return FALSE;
-    try { 
+    TRY_TO_CATCH_SEGV { 
         char c = *(char *)p;
     }
-    catch ( EXCEPTION ) {
+    CAUGHT_EXCEPTION {
         if( dangle_whine ) 
             warn( "Devel::Size: Encountered invalid pointer: %p\n", p );
         return FALSE;
@@ -101,7 +104,7 @@ cc_opclass(const OP * const o)
 {
     if (!o)
     return OPc_NULL;
-    try {
+    TRY_TO_CATCH_SEGV {
         if (o->op_type == 0)
         return (o->op_flags & OPf_KIDS) ? OPc_UNOP : OPc_BASEOP;
 
@@ -205,7 +208,7 @@ cc_opclass(const OP * const o)
         warn("Devel::Size: Can't determine class of operator %s, assuming BASEOP\n",
          PL_op_name[o->op_type]);
     }
-    catch( EXCEPTION ) { }
+    CAUGHT_EXCEPTION { }
     return OPc_BASEOP;
 }
 
@@ -235,7 +238,7 @@ IV magic_size(const SV * const thing, TRACKING *tv) {
   while (magic_pointer && check_new(tv, magic_pointer)) {
     total_size += sizeof(MAGIC);
 
-    try {
+    TRY_TO_CATCH_SEGV {
         /* Have we seen the magic vtable? */
         if (magic_pointer->mg_virtual &&
         check_new(tv, magic_pointer->mg_virtual)) {
@@ -245,7 +248,7 @@ IV magic_size(const SV * const thing, TRACKING *tv) {
         /* Get the next in the chain */ // ?try
         magic_pointer = magic_pointer->mg_moremagic;
     }
-    catch( EXCEPTION ) { 
+    CAUGHT_EXCEPTION { 
         if( dangle_whine ) 
             warn( "Devel::Size: Encountered bad magic at: %p\n", magic_pointer );
     }
@@ -276,7 +279,7 @@ UV regex_size(const REGEXP * const baseregex, TRACKING *tv) {
 
 UV op_size(const OP * const baseop, TRACKING *tv) {
   UV total_size = 0;
-  try {
+  TRY_TO_CATCH_SEGV {
       TAG;
       if (check_new(tv, baseop->op_next)) {
            total_size += op_size(baseop->op_next, tv);
@@ -422,7 +425,7 @@ UV op_size(const OP * const baseop, TRACKING *tv) {
         TAG;break;
       }
   }
-  catch( EXCEPTION ) {
+  CAUGHT_EXCEPTION {
       if( dangle_whine ) 
           warn( "Devel::Size: Encountered dangling pointer in opcode at: %p\n", baseop );
   }
index 2355afc..4be6c8a 100644 (file)
@@ -255,9 +255,10 @@ These may be disabled by setting
 Devel::Size has always been vulnerable to trapping when traversing Perl's
 internal data structures, if it encounters uninitialised (dangling) pointers.
 
-Exception handling has been added to deal with this possibility, and Devel::Size
-will now attempt to ignore (or log) them and continue. These messages are mainly
-of interest to Devel::Size and core developers, and so are disabled by default.
+MSVC provides exception handling able to deal with this possibility, and when
+built with MSVC Devel::Size will now attempt to ignore (or log) them and
+continue. These messages are mainly of interest to Devel::Size and core
+developers, and so are disabled by default.
 
 They may be enabled by setting