Perl / perl5

🐪 The Perl programming language
https://dev.perl.org/perl5/
Other
1.98k stars 559 forks source link

Perl's assert macro breaks C/POSIX standards #14187

Closed p5pRT closed 9 years ago

p5pRT commented 10 years ago

Migrated from rt.perl.org#123063 (status was 'resolved')

Searchable as RT123063$

p5pRT commented 10 years ago

From @bulk88

Created by @bulk88

C89 ----------------------------------------------------------------- If NDEBUG is defined as a macro name at the point in the source file where \<assert.h> is included\, the assert macro is defined simply as

#define assert(ignore) ((void)0)

The assert macro shall be implemented as a macro\, not as an actual function. ----------------------------------------------------------------

POSIX

----------------------------------------------------------------- If NDEBUG is defined as a macro name before the inclusion of this header\, the /assert/() \<http​://pubs.opengroup.org/onlinepubs/009695399/functions/assert.html> macro shall be defined simply as​:

#define assert(ignore)((void) 0) ------------------------------------------------

perl.h has ------------------------------------------------

/* Keep the old croak based assert for those who want it\, and as a fallback if   the platform is so heretically non-ANSI that it can't assert. */

#define Perl_assert(what) PERL_DEB( \   ((what) ? ((void) 0) : \   (Perl_croak_nocontext("Assertion %s failed​: file \"" __FILE__ \   "\"\, line %d"\, STRINGIFY(what)\, __LINE__)\, \   (void) 0)))

/* assert() gets defined if DEBUGGING (and I_ASSERT). * If no DEBUGGING\, the \<assert.h> has not been included. */ #ifndef assert # define assert(what) Perl_assert(what) #endif #ifdef DEBUGGING # define assert_(what) assert(what)\, #else # define assert_(what) #endif ------------------------------------------------   cl -c -nologo -GF -W3 -I..\lib\CORE -I.\include -I. -I.. -DWIN32 -D_CONS OLE -DNO_STRICT -DPERLDLL -DPERL_CORE -O1 -MD -Zi -DNDEBUG -G7 -GL -DPERL_EXTE RNAL_GLOB -DPERL_IS_MINIPERL -Fo.\mini\dump.obj ..\dump.c dump.c ..\dump.c(1436) : error C2059​: syntax error : '\,' ------------------------------------------------   void * retval;   retval = (assert(SvSANITY(sv))\,Perl_do_sumthing(aTHX_ sv)); \<\<\<\<\< line 1436

------------------------------------------------ post CPP ------------------------------------------------   void * retval;   retval = (\,Perl_do_sumthing(my_perl\, sv)); ------------------------------------------------

Another variant ------------------------------------------------   void * retval;   retval = ((assert(SvSANITY(sv)))\,Perl_do_sumthing(aTHX_ sv)); ------------------------------------------------   cl -c -nologo -GF -W3 -I..\lib\CORE -I.\include -I. -I.. -DWIN32 -D_CONS OLE -DNO_STRICT -DPERLDLL -DPERL_CORE -O1 -MD -Zi -DNDEBUG -G7 -GL -DPERL_EXTE RNAL_GLOB -DPERL_IS_MINIPERL -Fo.\mini\dump.obj ..\dump.c dump.c ..\dump.c(1436) : error C2059​: syntax error : ')' ------------------------------------------------ post CPP ------------------------------------------------

  retval = (()\,Perl_do_sumthing(my_perl\, sv));

------------------------------------------------ post CPP with DEBUGGING on -----------------------------------------------   retval = (((void)( (SvSANITY(sv)) || (_assert("SvSANITY(sv)"\, "../dump.c"\, 1436)\, 0) ))\,Perl_do_sumthing(my_perl\, sv)); ----------------------------------------------- not a syntax error

The problem is macro PERL_DEB() returns nothing. assert must return "((void)0)" not "" per C/POSIX.

related commits

http​://perl5.git.perl.org/perl.git/commitdiff/de84dc04df54774a9a36117a3e6233130e44a9a3 http​://perl5.git.perl.org/perl.git/commitdiff/2b0572841e170b6dd3ff1e2adc09565a9efdf3f1

PERL_DEB originates from 5 alpha 2 commit from the moment #define assert was added.

http​://perl5.git.perl.org/perl.git/commitdiff/79072805bf63abe5b5978b5928ab00d360ea3e7f

Note Win32 Perl always puts -DNDEBUG on non-DEBUGGING builds on command like\, unix perls never do that for DEBUGGING or non DEBUGGING.

-DNDEBUG has been on win32 Perl since http​://perl5.git.perl.org/perl.git/commitdiff/3e3baf6d63945cb64e829d6e5c70a7d00f3d3d03 or perl-5.003_97e http​://perl5.git.perl.org/perl.git/commitdiff/137443ea0a858c43f5a720730cac6209a7d41948

I can't find p5p mail for patch " Win32 update (four patches)" there probably was no archiving then.

Perl Info ``` Flags: category=core severity=medium Site configuration information for perl 5.21.2: Configured by Owner at Tue Sep 23 02:37:36 2014. Summary of my perl5 (revision 5 version 21 subversion 2) configuration: Derived from: 101c6642b743a0f82b7806d5a14d645731f1509c Ancestor: 8eaff90c13544b96799fc27a09c05dec3d2706c9 Platform: osname=MSWin32, osvers=5.1, archname=MSWin32-x86-multi-thread uname='' config_args='undef' hint=recommended, useposix=true, d_sigaction=undef useithreads=define, usemultiplicity=define use64bitint=undef, use64bitall=undef, uselongdouble=undef usemymalloc=n, bincompat5005=undef Compiler: cc='cl', ccflags ='-nologo -GF -W3 -Od -MD -Zi -DDEBUGGING -DWIN32 -D_CONSOLE -DNO_STRICT -DPERL_TEXTMODE_SCRIPTS -DPERL_HASH_FUNC_ONE_AT_A_TIME -DPERL_IMPLICIT_CONTEXT -DPERL_IMPLICIT_SYS -DUSE_PERLIO -D_USE_32BIT_TIME_T', optimize='-Od -MD -Zi -DDEBUGGING', cppflags='-DWIN32' ccversion='13.10.6030', gccversion='', gccosandvers='' intsize=4, longsize=4, ptrsize=4, doublesize=8, byteorder=1234 d_longlong=undef, longlongsize=8, d_longdbl=define, longdblsize=8 ivtype='long', ivsize=4, nvtype='double', nvsize=8, Off_t='__int64', lseeksize=8 alignbytes=8, prototype=define Linker and Libraries: ld='link', ldflags ='-nologo -nodefaultlib -debug -libpath:"c:\perl521\lib\CORE" -machine:x86' libpth="C:\Program Files\Microsoft Visual Studio .NET 2003\VC7\lib" libs=oldnames.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib netapi32.lib uuid.lib ws2_32.lib mpr.lib winmm.lib version.lib odbc32.lib odbccp32.lib comctl32.lib msvcrt.lib perllibs=oldnames.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib netapi32.lib uuid.lib ws2_32.lib mpr.lib winmm.lib version.lib odbc32.lib odbccp32.lib comctl32.lib msvcrt.lib libc=msvcrt.lib, so=dll, useshrplib=true, libperl=perl521.lib gnulibc_version='' Dynamic Linking: dlsrc=dl_win32.xs, dlext=dll, d_dlsymun=undef, ccdlflags=' ' cccdlflags=' ', lddlflags='-dll -nologo -nodefaultlib -debug -libpath:"c:\perl521\lib\CORE" -machine:x86' Locally applied patches: uncommitted-changes 22eb0703e4f1ca0305ca22390770b019a4b0ec4c ab36ae0a3ee81e650c6775a6e779fd961d14a2df 7374111ae13f4be3f77c384a6ed74d26608a6d94 543c0e688ee3c5a452b9203e04eee8a0f448ecfa 68a4b64dc9a9688bb38aabd2dd076a93805c5d0a 2bfbae23de43234000b13d68be2d6c2e17642f52 d56c627eaf78528a30b6e2e11f11f4a310f6b738 568f0b08dbad76dcd72664e258a9504bcc2b1246 101c6642b743a0f82b7806d5a14d645731f1509c @INC for perl 5.21.2: C:/perl521/site/lib C:/perl521/lib . Environment for perl 5.21.2: HOME (unset) LANG (unset) LANGUAGE (unset) LD_LIBRARY_PATH (unset) LOGDIR (unset) PATH=C:\perl521\bin;C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\IDE;C:\Program Files\Microsoft Visual Studio .NET 2003\VC7\BIN;C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\Tools;C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\Tools\bin\prerelease;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\system32\wbem; PERL_BADLANG (unset) SHELL (unset) ```
p5pRT commented 10 years ago

From @tonycoz

On Sun Oct 26 15​:55​:17 2014\, bulk88 wrote​:

C89 ----------------------------------------------------------------- If NDEBUG is defined as a macro name at the point in the source file where \<assert.h> is included\, the assert macro is defined simply as

#define assert(ignore) ((void)0)

The assert macro shall be implemented as a macro\, not as an actual function.

Possible patch attached.

Tony

p5pRT commented 10 years ago

From @tonycoz

0001-perl-123063-allow-assert-to-be-used-as-an-expression.patch ```diff From 4189b1bdc869c05e3f6b24a8bddf21c04f9df89f Mon Sep 17 00:00:00 2001 From: Tony Cook Date: Wed, 12 Nov 2014 13:53:48 +1100 Subject: [perl #123063] allow assert() to be used as an expression In non-DEBUGGING builds it would be replaced with nothing, producing a syntax error --- ext/XS-APItest/APItest.xs | 7 +++++++ perl.h | 6 ++++-- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/ext/XS-APItest/APItest.xs b/ext/XS-APItest/APItest.xs index 8d3d23a..8cf5e8c 100644 --- a/ext/XS-APItest/APItest.xs +++ b/ext/XS-APItest/APItest.xs @@ -1256,6 +1256,13 @@ INCLUDE: const-xs.inc INCLUDE: numeric.xs +void +assertx(int x) + CODE: + /* this only needs to compile and checks that assert() can be + used this way syntactically */ + (assert(x),1); + MODULE = XS::APItest::utf8 PACKAGE = XS::APItest::utf8 int diff --git a/perl.h b/perl.h index 580ad6a..8b8427f 100644 --- a/perl.h +++ b/perl.h @@ -4004,6 +4004,7 @@ Gid_t getegid (void); # define DEBUG_Pv_TEST DEBUG_Pv_TEST_ # define PERL_DEB(a) a +# define PERL_DEB2(a,b) a # define PERL_DEBUG(a) if (PL_debug) a # define DEBUG_p(a) if (DEBUG_p_TEST) a # define DEBUG_s(a) if (DEBUG_s_TEST) a @@ -4086,6 +4087,7 @@ Gid_t getegid (void); # define DEBUG_Pv_TEST (0) # define PERL_DEB(a) +# define PERL_DEB2(a,b) b # define PERL_DEBUG(a) # define DEBUG_p(a) # define DEBUG_s(a) @@ -4128,11 +4130,11 @@ Gid_t getegid (void); /* Keep the old croak based assert for those who want it, and as a fallback if the platform is so heretically non-ANSI that it can't assert. */ -#define Perl_assert(what) PERL_DEB( \ +#define Perl_assert(what) PERL_DEB2( \ ((what) ? ((void) 0) : \ (Perl_croak_nocontext("Assertion %s failed: file \"" __FILE__ \ "\", line %d", STRINGIFY(what), __LINE__), \ - (void) 0))) + (void) 0)), ((void)0)) /* assert() gets defined if DEBUGGING (and I_ASSERT). * If no DEBUGGING, the has not been included. */ -- 1.7.10.4 ```
p5pRT commented 10 years ago

The RT System itself - Status changed from 'new' to 'open'

p5pRT commented 9 years ago

From @tonycoz

On Tue Nov 11 18​:54​:51 2014\, tonyc wrote​:

On Sun Oct 26 15​:55​:17 2014\, bulk88 wrote​:

C89 ----------------------------------------------------------------- If NDEBUG is defined as a macro name at the point in the source file where \<assert.h> is included\, the assert macro is defined simply as

#define assert(ignore) ((void)0)

The assert macro shall be implemented as a macro\, not as an actual function.

Possible patch attached.

Applied as 11f9ab1a291e36ad40cb66d0bd0aedce897c06c3.

Tony

p5pRT commented 9 years ago

@tonycoz - Status changed from 'open' to 'resolved'