Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Quadmath builds fail porting/libperl.t #15436

Closed
p5pRT opened this issue Jul 11, 2016 · 22 comments
Closed

Quadmath builds fail porting/libperl.t #15436

p5pRT opened this issue Jul 11, 2016 · 22 comments

Comments

@p5pRT
Copy link

p5pRT commented Jul 11, 2016

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

Searchable as RT128598$

@p5pRT
Copy link
Author

p5pRT commented Jul 11, 2016

From @dcollinsn

Greetings,

Configuring blead with​:

  ./Configure -Dusedevel -des -Dusequadmath

Results in a test failure in libperl.t​:

  dcollins@​nightshade64​:~/perlquad$ ./perl -Ilib -V
  Summary of my perl5 (revision 5 version 25 subversion 3) configuration​:
  Commit id​: cf549b9
  Platform​:
  osname=linux
  osvers=4.6.0-1-amd64
  archname=x86_64-linux-quadmath
  uname='linux nightshade64 4.6.0-1-amd64 #1 smp debian 4.6.1-1 (2016-06-06) x86_64 gnulinux '
  config_args='-Dusedevel -des -Dusequadmath'
  hint=recommended
  useposix=true
  d_sigaction=define
  useithreads=undef
  usemultiplicity=undef
  use64bitint=define
  use64bitall=define
  uselongdouble=undef
  usemymalloc=n
  bincompat5005=undef
  Compiler​:
  cc='cc'
  ccflags ='-fwrapv -fno-strict-aliasing -pipe -fstack-protector-strong -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -D_FORTIFY_SOURCE=2'
  optimize='-O2'
  cppflags='-fwrapv -fno-strict-aliasing -pipe -fstack-protector-strong -I/usr/local/include'
  ccversion=''
  gccversion='5.4.0 20160609'
  gccosandvers=''
  intsize=4
  longsize=8
  ptrsize=8
  doublesize=8
  byteorder=12345678
  doublekind=3
  d_longlong=define
  longlongsize=8
  d_longdbl=define
  longdblsize=16
  longdblkind=3
  ivtype='long'
  ivsize=8
  nvtype='__float128'
  nvsize=16
  Off_t='off_t'
  lseeksize=8
  alignbytes=16
  prototype=define
  Linker and Libraries​:
  ld='cc'
  ldflags =' -fstack-protector-strong -L/usr/local/lib'
  libpth=/usr/local/lib /usr/lib/gcc/x86_64-linux-gnu/5/include-fixed /usr/include/x86_64-linux-gnu /usr/lib /lib/x86_64-linux-gnu /lib/../lib /usr/lib/x86_64-linux-gnu /usr/lib/../lib /lib
  libs=-lpthread -lnsl -ldl -lm -lcrypt -lutil -lc -lquadmath
  perllibs=-lpthread -lnsl -ldl -lm -lcrypt -lutil -lc -lquadmath
  libc=libc-2.22.so
  so=so
  useshrplib=false
  libperl=libperl.a
  gnulibc_version='2.22'
  Dynamic Linking​:
  dlsrc=dl_dlopen.xs
  dlext=so
  d_dlsymun=undef
  ccdlflags='-Wl,-E'
  cccdlflags='-fPIC'
  lddlflags='-shared -O2 -L/usr/local/lib -fstack-protector-strong'

  Characteristics of this binary (from libperl)​:
  Compile-time options​:
  HAS_TIMES
  PERLIO_LAYERS
  PERL_COPY_ON_WRITE
  PERL_DONT_CREATE_GVSV
  PERL_HASH_FUNC_ONE_AT_A_TIME_HARD
  PERL_MALLOC_WRAP
  PERL_OP_PARENT
  PERL_PRESERVE_IVUV
  PERL_USE_DEVEL
  USE_64_BIT_ALL
  USE_64_BIT_INT
  USE_LARGE_FILES
  USE_LOCALE
  USE_LOCALE_COLLATE
  USE_LOCALE_CTYPE
  USE_LOCALE_NUMERIC
  USE_LOCALE_TIME
  USE_PERLIO
  USE_PERL_ATOF
  USE_QUADMATH
  Built under linux
  Compiled at Jul 10 2016 22​:46​:13
  %ENV​:
  PERLBREW_BASHRC_VERSION="0.76"
  PERLBREW_HOME="/home/dcollins/.perlbrew"
  PERLBREW_ROOT="/home/dcollins/toolchain/perl5"
  @​INC​:
  lib
  /usr/local/lib/perl5/site_perl/5.25.3/x86_64-linux-quadmath
  /usr/local/lib/perl5/site_perl/5.25.3
  /usr/local/lib/perl5/5.25.3/x86_64-linux-quadmath
  /usr/local/lib/perl5/5.25.3
  .
  dcollins@​nightshade64​:~/perlquad$ ./perl -Ilib t/harness t/porting/libperl.t
  porting/libperl.t .. # Failed test 26 - uses no strcpy (locale.o) at porting/libperl.t line 551
  # got "1"
  # expected "0"
  porting/libperl.t .. Failed 1/35 subtests

  Test Summary Report
  -------------------
  porting/libperl.t (Wstat​: 0 Tests​: 35 Failed​: 1)
  Failed test​: 26
  Files=1, Tests=35, 0 wallclock secs ( 0.00 usr 0.00 sys + 0.03 cusr 0.00 csys = 0.03 CPU)
  Result​: FAIL

If this is relevant, in the locale.o section of `nm libperl.a` I found​:

0000000000000000 t S_stdize_locale
  U __stack_chk_fail
  U stpcpy
  U strchr
  U strcmp
  U strcpy
  U strerror
  U strlen
  U strxfrm

--
Respectfully,
Dan Collins

@p5pRT
Copy link
Author

p5pRT commented Jul 11, 2016

From @tonycoz

On Sun Jul 10 20​:11​:51 2016, dcollinsn@​gmail.com wrote​:

Greetings,

If this is relevant, in the locale.o section of `nm libperl.a` I
found​:

0000000000000000 t S_stdize_locale
U __stack_chk_fail
U stpcpy
U strchr
U strcmp
U strcpy
U strerror
U strlen
U strxfrm

I think it's optimizing this code​:

  *sans_nuls = '\0';

  /* Replace each NUL with the lowest collating control. Loop until have
  * exhausted all the NULs */
  while (s + s_strlen < e) {
  strcat(sans_nuls, s);

  /* Do the actual replacement */
  strcat(sans_nuls, PL_strxfrm_min_char);

  /* Move past the input NUL */
  s += s_strlen + 1;
  s_strlen = strlen(s);
  }

At entry it can assume s points at the end of the string, and replaces
strcat() with a call to stpcpy() (which is like strcpy(), but returns
the address of the final NUL). The second call to strcat() is then
replaced with a call to strcpy(), using the result from stpcpy() as
the destination​:

  movb $0, (%rax)
.LVL87​:
  .loc 1 1585 0
  movq 24(%rsp), %rax
.LVL88​:
  addq %rax, %r15
.LVL89​:
  cmpq %r15, 16(%rsp)
  jbe .L78
  movq %rax, %r15
.LVL90​:
  .p2align 4,,10
  .p2align 3
.L44​:
  movq %rbx, %rdi
  call strlen
.LVL91​:
  leaq (%rbx,%rax), %rdi
.LBB134​:
.LBB135​:
  .loc 2 142 0
  movq %r15, %rsi
.LBE135​:
.LBE134​:
  .loc 1 1592 0
  leaq 1(%r15,%rbp), %r15
.LVL92​:
.LBB137​:
.LBB136​:
  .loc 2 142 0
  call stpcpy
.LVL93​:
.LBE136​:
.LBE137​:
.LBB138​:
.LBB139​:
  movl $PL_strxfrm_min_char, %esi
  movq %rax, %rdi
  call strcpy
.LVL94​:
.LBE139​:
.LBE138​:
  .loc 1 1593 0
  movq %r15, %rdi
  call strlen
.LVL95​:
  movq %rax, %rbp
.LVL96​:
  .loc 1 1585 0
  leaq (%r15,%rax), %rax
.LVL97​:
  cmpq %rax, 16(%rsp)
  ja .L44
  jmp .L43

Building with optimization disabled removes the reference to strcpy().

Tony

@p5pRT
Copy link
Author

p5pRT commented Jul 11, 2016

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

@p5pRT
Copy link
Author

p5pRT commented Jul 14, 2016

From @khwilliamson

On Sun Jul 10 21​:52​:17 2016, tonyc wrote​:

On Sun Jul 10 20​:11​:51 2016, dcollinsn@​gmail.com wrote​:

Greetings,

If this is relevant, in the locale.o section of `nm libperl.a` I
found​:

0000000000000000 t S_stdize_locale
U __stack_chk_fail
U stpcpy
U strchr
U strcmp
U strcpy
U strerror
U strlen
U strxfrm

I think it's optimizing this code​:

*sans_nuls = '\0';

/* Replace each NUL with the lowest collating control. Loop until
have
* exhausted all the NULs */
while (s + s_strlen < e) {
strcat(sans_nuls, s);

/* Do the actual replacement */
strcat(sans_nuls, PL_strxfrm_min_char);

/* Move past the input NUL */
s += s_strlen + 1;
s_strlen = strlen(s);
}

At entry it can assume s points at the end of the string, and replaces
strcat() with a call to stpcpy() (which is like strcpy(), but returns
the address of the final NUL). The second call to strcat() is then
replaced with a call to strcpy(), using the result from stpcpy() as
the destination​:

movb $0, (%rax)
.LVL87​:
.loc 1 1585 0
movq 24(%rsp), %rax
.LVL88​:
addq %rax, %r15
.LVL89​:
cmpq %r15, 16(%rsp)
jbe .L78
movq %rax, %r15
.LVL90​:
.p2align 4,,10
.p2align 3
.L44​:
movq %rbx, %rdi
call strlen
.LVL91​:
leaq (%rbx,%rax), %rdi
.LBB134​:
.LBB135​:
.loc 2 142 0
movq %r15, %rsi
.LBE135​:
.LBE134​:
.loc 1 1592 0
leaq 1(%r15,%rbp), %r15
.LVL92​:
.LBB137​:
.LBB136​:
.loc 2 142 0
call stpcpy
.LVL93​:
.LBE136​:
.LBE137​:
.LBB138​:
.LBB139​:
movl $PL_strxfrm_min_char, %esi
movq %rax, %rdi
call strcpy
.LVL94​:
.LBE139​:
.LBE138​:
.loc 1 1593 0
movq %r15, %rdi
call strlen
.LVL95​:
movq %rax, %rbp
.LVL96​:
.loc 1 1585 0
leaq (%r15,%rax), %rax
.LVL97​:
cmpq %rax, 16(%rsp)
ja .L44
jmp .L43

Building with optimization disabled removes the reference to strcpy().

Tony

It seems to me the best course would be to disable this test if optimization is being done. The point is to catch places in the code where a programmer has made a mistake, and is using unsafe C paradigms. One generally assumes that the optimizer knows what it is doing, and we don't have to check up on it. By skipping the test on optimized builds, we still will get an indication in our smokes that the programmer made a potential mistake, so that is adequate for our purpose.
--
Karl Williamson

@p5pRT
Copy link
Author

p5pRT commented Jul 15, 2016

From @tonycoz

On Thu, Jul 14, 2016 at 03​:17​:46PM -0700, Karl Williamson via RT wrote​:

It seems to me the best course would be to disable this test if optimization is being done. The point is to catch places in the code where a programmer has made a mistake, and is using unsafe C paradigms. One generally assumes that the optimizer knows what it is doing, and we don't have to check up on it. By skipping the test on optimized builds, we still will get an indication in our smokes that the programmer made a potential mistake, so that is adequate for our purpose.

strcat() is about as safe as strcpy().

The test gives locale.c an explicit pass on using strcat(), perhaps it
should get one on strcpy().

Or revoke allowing strcat() in locale.c.

Tony

@p5pRT
Copy link
Author

p5pRT commented Jul 15, 2016

From @dcollinsn

On Thu Jul 14 17​:18​:14 2016, tonyc wrote​:

strcat() is about as safe as strcpy().

The test gives locale.c an explicit pass on using strcat(), perhaps it
should get one on strcpy().

Or revoke allowing strcat() in locale.c.

Tony

locale.c specifically uses strcat, and that's special-cased in porting/libperl.t. Since we see that the optimizer may use the "unsafe" builtins, but does so in a safe way, I think that this new exception shouldn't be explicitly for strcpy in locale.c, but for any such functions under -O2 or higher. Otherwise we will be changing porting/libperl.t whenever the optimizer gets a little bit better, or after unrelated changes elsewhere in the codebase. Is this patch OK with you guys?

--
Respectfully,
Dan Collins

@p5pRT
Copy link
Author

p5pRT commented Jul 15, 2016

From @dcollinsn

0001-RT-128598-libperl.t-optimizer-may-use-any-builtins.patch
From 892c31e4484bf06a42d4bc8dba7258bad33299e9 Mon Sep 17 00:00:00 2001
From: Dan Collins <dcollinsn@gmail.com>
Date: Thu, 14 Jul 2016 19:51:13 -0400
Subject: [PATCH] [RT #128598] libperl.t: optimizer may use any builtins

porting/libperl.t makes sure that programmers don't accidentally
use unsafe builtins like strcpy. However, the optimizer is able
to use these on its own. For example, quadmath builds with -O2
or higher with gcc will use strcpy in locale.c, even though that
function isn't used in the source code.

This would skip those tests only under -O2 or -O3 and only if they
would fail. That way, any errant appearances of these symbols will
be visible in test output, and if those functions are used directly,
the test will still fail under -O0 or -O1.
---
 t/porting/libperl.t | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/t/porting/libperl.t b/t/porting/libperl.t
index 21e7edb..e82cb8a 100644
--- a/t/porting/libperl.t
+++ b/t/porting/libperl.t
@@ -547,6 +547,10 @@ for my $symbol (sort keys %unexpected) {
       SKIP: {
         skip("locale.o legitimately uses strcat");
       }
+    } elsif (@o > 0 && $Config{optimize} =~ /-O[23]/) {
+      SKIP: {
+        skip("uses $symbol (@o), but optimizer may use it legitimately");
+      }
     } else {
         is(@o, 0, "uses no $symbol (@o)");
     }
-- 
2.8.1

@p5pRT
Copy link
Author

p5pRT commented Jul 15, 2016

From @khwilliamson

On 07/14/2016 07​:23 PM, Dan Collins via RT wrote​:

On Thu Jul 14 17​:18​:14 2016, tonyc wrote​:

strcat() is about as safe as strcpy().

The test gives locale.c an explicit pass on using strcat(), perhaps it
should get one on strcpy().

Or revoke allowing strcat() in locale.c.

Tony

locale.c specifically uses strcat, and that's special-cased in porting/libperl.t. Since we see that the optimizer may use the "unsafe" builtins, but does so in a safe way, I think that this new exception shouldn't be explicitly for strcpy in locale.c, but for any such functions under -O2 or higher. Otherwise we will be changing porting/libperl.t whenever the optimizer gets a little bit better, or after unrelated changes elsewhere in the codebase. Is this patch OK with you guys?

I believe we call some compilers on some platforms with just "-O". I
suspect that it's best to skip unless there is an explicit "-O0".

@p5pRT
Copy link
Author

p5pRT commented Jul 15, 2016

From @dcollinsn

Well, we might also call MSVC with /Og or /Ox - but I don't have any
evidence of those compilers failing these tests yet so I'm not sure how far
to go. An even more liberal choice would be m|[-/]O(?![0d])| (/Od is
disable optimzations on MSVC)

On Thu, Jul 14, 2016 at 10​:58 PM, karl williamson via RT <
perlbug-followup@​perl.org> wrote​:

On 07/14/2016 07​:23 PM, Dan Collins via RT wrote​:

On Thu Jul 14 17​:18​:14 2016, tonyc wrote​:

strcat() is about as safe as strcpy().

The test gives locale.c an explicit pass on using strcat(), perhaps it
should get one on strcpy().

Or revoke allowing strcat() in locale.c.

Tony

locale.c specifically uses strcat, and that's special-cased in
porting/libperl.t. Since we see that the optimizer may use the "unsafe"
builtins, but does so in a safe way, I think that this new exception
shouldn't be explicitly for strcpy in locale.c, but for any such functions
under -O2 or higher. Otherwise we will be changing porting/libperl.t
whenever the optimizer gets a little bit better, or after unrelated changes
elsewhere in the codebase. Is this patch OK with you guys?

I believe we call some compilers on some platforms with just "-O". I
suspect that it's best to skip unless there is an explicit "-O0".

@p5pRT
Copy link
Author

p5pRT commented Jul 15, 2016

From @craigberry

On Thu, Jul 14, 2016 at 10​:45 PM, Dan Collins <dcollinsn@​gmail.com> wrote​:

Well, we might also call MSVC with /Og or /Ox - but I don't have any
evidence of those compilers failing these tests yet so I'm not sure how far
to go. An even more liberal choice would be m|[-/]O(?![0d])| (/Od is disable
optimzations on MSVC)

On Thu, Jul 14, 2016 at 10​:58 PM, karl williamson via RT
<perlbug-followup@​perl.org> wrote​:

On 07/14/2016 07​:23 PM, Dan Collins via RT wrote​:

On Thu Jul 14 17​:18​:14 2016, tonyc wrote​:

strcat() is about as safe as strcpy().

The test gives locale.c an explicit pass on using strcat(), perhaps it
should get one on strcpy().

Or revoke allowing strcat() in locale.c.

Tony

locale.c specifically uses strcat, and that's special-cased in
porting/libperl.t. Since we see that the optimizer may use the "unsafe"
builtins, but does so in a safe way, I think that this new exception
shouldn't be explicitly for strcpy in locale.c, but for any such functions
under -O2 or higher. Otherwise we will be changing porting/libperl.t
whenever the optimizer gets a little bit better, or after unrelated changes
elsewhere in the codebase. Is this patch OK with you guys?

I believe we call some compilers on some platforms with just "-O". I
suspect that it's best to skip unless there is an explicit "-O0".

Is there any particular reason to avoid just switching to my_strlcat
for the 3 instances of strcat in locale.c? That seems a whole lot
simpler than trying to divine the optimization level and what
different optimizers do or will do at different levels.

@p5pRT
Copy link
Author

p5pRT commented Jul 16, 2016

From @khwilliamson

On 07/15/2016 07​:23 AM, Craig A. Berry wrote​:

On Thu, Jul 14, 2016 at 10​:45 PM, Dan Collins <dcollinsn@​gmail.com> wrote​:

Well, we might also call MSVC with /Og or /Ox - but I don't have any
evidence of those compilers failing these tests yet so I'm not sure how far
to go. An even more liberal choice would be m|[-/]O(?![0d])| (/Od is disable
optimzations on MSVC)

On Thu, Jul 14, 2016 at 10​:58 PM, karl williamson via RT
<perlbug-followup@​perl.org> wrote​:

On 07/14/2016 07​:23 PM, Dan Collins via RT wrote​:

On Thu Jul 14 17​:18​:14 2016, tonyc wrote​:

strcat() is about as safe as strcpy().

The test gives locale.c an explicit pass on using strcat(), perhaps it
should get one on strcpy().

Or revoke allowing strcat() in locale.c.

Tony

locale.c specifically uses strcat, and that's special-cased in
porting/libperl.t. Since we see that the optimizer may use the "unsafe"
builtins, but does so in a safe way, I think that this new exception
shouldn't be explicitly for strcpy in locale.c, but for any such functions
under -O2 or higher. Otherwise we will be changing porting/libperl.t
whenever the optimizer gets a little bit better, or after unrelated changes
elsewhere in the codebase. Is this patch OK with you guys?

I believe we call some compilers on some platforms with just "-O". I
suspect that it's best to skip unless there is an explicit "-O0".

Is there any particular reason to avoid just switching to my_strlcat
for the 3 instances of strcat in locale.c? That seems a whole lot
simpler than trying to divine the optimization level and what
different optimizers do or will do at different levels.

Sure, I can do that. But our point is that the test is vulnerable to
the optimizer doing things that weren't in the original code. It might
be that the optimizer is clever enough now, or may become so in the
future, to realize that the safety afforded by strlcat is not needed in
this code, and optimize it to something that would fail this test.

Also, I claim that it is sufficient for the test to fail on any single
platform that we smoke regularly and pay attention to the results of.
So, it if only failed on Linux, that would be good enough to draw our
attention to the problem and fix it. So we could skip the test unless
it was -O0, and that would be good enough.

@p5pRT
Copy link
Author

p5pRT commented Aug 9, 2016

From @andk

6696cfa is the first bad commit
commit 6696cfa
Author​: Karl Williamson <khw@​cpan.org>
Date​: Sat Apr 9 15​:52​:05 2016 -0600

  Change mem_collxfrm() algorithm for embedded NULs

diagnostics​:

  porting/libperl.t (Wstat​: 0 Tests​: 35 Failed​: 1)
  Failed test​: 26

Running verbose​:

  not ok 26 - uses no strcpy (locale.o)
  # Failed test 26 - uses no strcpy (locale.o) at porting/libperl.t line 551
  # got "1"
  # expected "0"

% ./perl -Ilib -V
Summary of my perl5 (revision 5 version 25 subversion 2) configuration​:
  Commit id​: 6696cfa
  Platform​:
  osname=linux, osvers=4.6.0-1-amd64, archname=x86_64-linux-quadmath
  uname='linux k93x64sid 4.6.0-1-amd64 #1 smp debian 4.6.2-2 (2016-06-25) x86_64 gnulinux '
  config_args='-Dprefix=/home/sand/src/perl/repoperls/installed-perls/host/k93x64sid/v5.25.1-59-g6696cfa/7fd8 -Dmyhostname=k93x64sid -Dinstallusrbinperl=n -Uversiononly -Dusedevel -des -Ui_db -Dlibswanted=cl pthread socket inet nsl gdbm dbm malloc dl ld sun m crypt sec util c cposix posix ucb BSD gdbm_compat -Uuseithreads -Uuselongdouble -DDEBUGGING=-g -Dusequadmath'
  hint=recommended, useposix=true, d_sigaction=define
  useithreads=undef, usemultiplicity=undef
  use64bitint=define, use64bitall=define, uselongdouble=undef
  usemymalloc=n, bincompat5005=undef
  Compiler​:
  cc='cc', ccflags ='-fwrapv -fno-strict-aliasing -pipe -fstack-protector-strong -I/usr/local/include -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64',
  optimize='-O2 -g',
  cppflags='-fwrapv -fno-strict-aliasing -pipe -fstack-protector-strong -I/usr/local/include'
  ccversion='', gccversion='6.1.1 20160802', gccosandvers=''
  intsize=4, longsize=8, ptrsize=8, doublesize=8, byteorder=12345678, doublekind=3
  d_longlong=define, longlongsize=8, d_longdbl=define, longdblsize=16, longdblkind=3
  ivtype='long', ivsize=8, nvtype='__float128', nvsize=16, Off_t='off_t', lseeksize=8
  alignbytes=16, prototype=define
  Linker and Libraries​:
  ld='cc', ldflags =' -fstack-protector-strong -L/usr/local/lib'
  libpth=/usr/local/lib /usr/lib/gcc/x86_64-linux-gnu/6/include-fixed /usr/include/x86_64-linux-gnu /usr/lib /lib/x86_64-linux-gnu /lib/../lib /usr/lib/x86_64-linux-gnu /usr/lib/../lib /lib
  libs=-lpthread -lnsl -ldl -lm -lcrypt -lutil -lc -lquadmath
  perllibs=-lpthread -lnsl -ldl -lm -lcrypt -lutil -lc -lquadmath
  libc=libc-2.23.so, so=so, useshrplib=false, libperl=libperl.a
  gnulibc_version='2.23'
  Dynamic Linking​:
  dlsrc=dl_dlopen.xs, dlext=so, d_dlsymun=undef, ccdlflags='-Wl,-E'
  cccdlflags='-fPIC', lddlflags='-shared -O2 -g -L/usr/local/lib -fstack-protector-strong'

Characteristics of this binary (from libperl)​:
  Compile-time options​: HAS_TIMES PERLIO_LAYERS PERL_COPY_ON_WRITE
  PERL_DONT_CREATE_GVSV
  PERL_HASH_FUNC_ONE_AT_A_TIME_HARD PERL_MALLOC_WRAP
  PERL_OP_PARENT PERL_PRESERVE_IVUV PERL_USE_DEVEL
  USE_64_BIT_ALL USE_64_BIT_INT USE_LARGE_FILES
  USE_LOCALE USE_LOCALE_COLLATE USE_LOCALE_CTYPE
  USE_LOCALE_NUMERIC USE_LOCALE_TIME USE_PERLIO
  USE_PERL_ATOF USE_QUADMATH
  Built under linux
  Compiled at Aug 9 2016 06​:25​:54
  @​INC​:
  lib
  /home/sand/src/perl/repoperls/installed-perls/host/k93x64sid/v5.25.1-59-g6696cfa/7fd8/lib/site_perl/5.25.2/x86_64-linux-quadmath
  /home/sand/src/perl/repoperls/installed-perls/host/k93x64sid/v5.25.1-59-g6696cfa/7fd8/lib/site_perl/5.25.2
  /home/sand/src/perl/repoperls/installed-perls/host/k93x64sid/v5.25.1-59-g6696cfa/7fd8/lib/5.25.2/x86_64-linux-quadmath
  /home/sand/src/perl/repoperls/installed-perls/host/k93x64sid/v5.25.1-59-g6696cfa/7fd8/lib/5.25.2
  .

--
andreas

@p5pRT
Copy link
Author

p5pRT commented Aug 9, 2016

From @tonycoz

On Mon Aug 08 21​:32​:04 2016, andreas.koenig.7os6VVqR@​franz.ak.mind.de wrote​:

Running verbose​:

not ok 26 - uses no strcpy (locale.o)
# Failed test 26 - uses no strcpy (locale.o) at porting/libperl.t line
551
# got "1"
# expected "0"

Duplicate of 128598, I'll merge them.

Tony

@p5pRT
Copy link
Author

p5pRT commented Aug 9, 2016

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

@p5pRT
Copy link
Author

p5pRT commented Aug 9, 2016

From @tonycoz

On Thu Jul 14 19​:58​:13 2016, public@​khwilliamson.com wrote​:

I believe we call some compilers on some platforms with just "-O". I
suspect that it's best to skip unless there is an explicit "-O0".

I believe the real problem is using strcat() at all, I suspect from this
comment​:

+ * This is one of the few places in the perl core, where we can use
+ * standard functions like strlen() and strcat(). It's because we're
+ * looking for NULs. */

that you misunderstood why we avoid strcpy(), strcat().

We have my_strlcat() and my_strlcpy() that deal with NUL terminated strings
and are used throughout the perl core.

The attached replaces strcat() with my_strlcat() and removes the exception in
libperl.t

Tony

@p5pRT
Copy link
Author

p5pRT commented Aug 9, 2016

From @tonycoz

0001-perl-128598-don-t-use-strcat-even-in-locale.c.patch
From f994a3cf78cfa38658a37e58c7c85278ff609d98 Mon Sep 17 00:00:00 2001
From: Tony Cook <tony@develop-help.com>
Date: Tue, 9 Aug 2016 16:27:16 +1000
Subject: [perl #128598] don't use strcat(), even in locale.c

All the arguments againt strcat() apply even to locale.c
---
 locale.c            | 16 +++++++---------
 t/porting/libperl.t |  7 -------
 2 files changed, 7 insertions(+), 16 deletions(-)

diff --git a/locale.c b/locale.c
index f698377..aa6682d 100644
--- a/locale.c
+++ b/locale.c
@@ -1462,14 +1462,11 @@ Perl__mem_collxfrm(pTHX_ const char *input_string,
      * This will give as good as possible results on strings that don't
      * otherwise contain that character, but otherwise there may be
      * less-than-perfect results with that character and NUL.  This is
-     * unavoidable unless we replace strxfrm with our own implementation.
-     *
-     * This is one of the few places in the perl core, where we can use
-     * standard functions like strlen() and strcat().  It's because we're
-     * looking for NULs. */
+     * unavoidable unless we replace strxfrm with our own implementation. */
     if (s_strlen < len) {
         char * e = s + len;
         char * sans_nuls;
+        STRLEN sans_nuls_size;
         STRLEN cur_min_char_len;
         int try_non_controls;
 
@@ -1576,16 +1573,17 @@ Perl__mem_collxfrm(pTHX_ const char *input_string,
          * character in it is NUL.  Multiply that by the length of each
          * replacement, and allow for a trailing NUL */
         cur_min_char_len = strlen(PL_strxfrm_min_char);
-        Newx(sans_nuls, (len * cur_min_char_len) + 1, char);
+        sans_nuls_size = (len * cur_min_char_len) + 1;
+        Newx(sans_nuls, sans_nuls_size, char);
         *sans_nuls = '\0';
 
         /* Replace each NUL with the lowest collating control.  Loop until have
          * exhausted all the NULs */
         while (s + s_strlen < e) {
-            strcat(sans_nuls, s);
+            my_strlcat(sans_nuls, s, sans_nuls_size);
 
             /* Do the actual replacement */
-            strcat(sans_nuls, PL_strxfrm_min_char);
+            my_strlcat(sans_nuls, PL_strxfrm_min_char, sans_nuls_size);
 
             /* Move past the input NUL */
             s += s_strlen + 1;
@@ -1593,7 +1591,7 @@ Perl__mem_collxfrm(pTHX_ const char *input_string,
         }
 
         /* And add anything that trails the final NUL */
-        strcat(sans_nuls, s);
+        my_strlcat(sans_nuls, s, sans_nuls_size);
 
         /* Switch so below we transform this modified string */
         s = sans_nuls;
diff --git a/t/porting/libperl.t b/t/porting/libperl.t
index 21e7edb..4a3e568 100644
--- a/t/porting/libperl.t
+++ b/t/porting/libperl.t
@@ -540,13 +540,6 @@ for my $symbol (sort keys %unexpected) {
       SKIP: {
         skip("uses sprintf for Gconvert in sv.o");
       }
-    }
-    elsif (   $symbol eq 'strcat'
-           && @o == 1 && $o[0] eq 'locale.o')
-    {
-      SKIP: {
-        skip("locale.o legitimately uses strcat");
-      }
     } else {
         is(@o, 0, "uses no $symbol (@o)");
     }
-- 
2.1.4

@p5pRT
Copy link
Author

p5pRT commented Aug 9, 2016

From @cpansprout

On Mon Aug 08 23​:35​:02 2016, tonyc wrote​:

On Thu Jul 14 19​:58​:13 2016, public@​khwilliamson.com wrote​:

I believe we call some compilers on some platforms with just "-O". I
suspect that it's best to skip unless there is an explicit "-O0".

I believe the real problem is using strcat() at all, I suspect from
this
comment​:

+ * This is one of the few places in the perl core, where we can
use
+ * standard functions like strlen() and strcat(). It's because
we're
+ * looking for NULs. */

that you misunderstood why we avoid strcpy(), strcat().

Can you explain why? Or is it documented somewhere?

--

Father Chrysostomos

@p5pRT
Copy link
Author

p5pRT commented Aug 9, 2016

From @khwilliamson

On 08/09/2016 03​:34 PM, Father Chrysostomos via RT wrote​:

On Mon Aug 08 23​:35​:02 2016, tonyc wrote​:

On Thu Jul 14 19​:58​:13 2016, public@​khwilliamson.com wrote​:

I believe we call some compilers on some platforms with just "-O". I
suspect that it's best to skip unless there is an explicit "-O0".

I believe the real problem is using strcat() at all, I suspect from
this
comment​:

+ * This is one of the few places in the perl core, where we can
use
+ * standard functions like strlen() and strcat(). It's because
we're
+ * looking for NULs. */

that you misunderstood why we avoid strcpy(), strcat().

Can you explain why? Or is it documented somewhere?

Maybe my comment is a little cheeky, but I do believe I understand why
one should be avoiding these.

First, in Perl, they don't generally work as C strings are
NUL-terminated, whereas Perl strings can contain interior NULs.

Second, in general, they are fragile, with the possibility of reading
uninitialized data or writing outside the legal boundaries. This has
caused many a bug. It's better to put some bound on things, like
strncat() does.

If there are other reasons, I don't know them.

In this case, I used them because I was dealing with what they are
designed to do efficiently. I was building a C string by working
through a Perl string, finding the interior NULs, and replacing them
with something else. The data structure is entirely built in this
little code section, and barring a neutrino or other act of God, should
be entirely safe.

It's easiest to fix this ticket by changing to use strlcpy() and
strlcat(), which perl has defined with the prefix 'my_' in each case,
because not every system has them defined. But my point and Dan's was
that the test itself is fragile, because the C optimizer is free to
change any code it wants into using one of the forbidden ones. No one
responded to that point, and so the ticket has languished until today.

@p5pRT
Copy link
Author

p5pRT commented Aug 10, 2016

From @tonycoz

On Tue Aug 09 16​:08​:23 2016, public@​khwilliamson.com wrote​:

On 08/09/2016 03​:34 PM, Father Chrysostomos via RT wrote​:

On Mon Aug 08 23​:35​:02 2016, tonyc wrote​:

On Thu Jul 14 19​:58​:13 2016, public@​khwilliamson.com wrote​:

I believe we call some compilers on some platforms with just "-O". I
suspect that it's best to skip unless there is an explicit "-O0".

I believe the real problem is using strcat() at all, I suspect from
this
comment​:

+ * This is one of the few places in the perl core, where we can
use
+ * standard functions like strlen() and strcat(). It's because
we're
+ * looking for NULs. */

that you misunderstood why we avoid strcpy(), strcat().

Can you explain why? Or is it documented somewhere?

Maybe my comment is a little cheeky, but I do believe I understand why
one should be avoiding these.

First, in Perl, they don't generally work as C strings are
NUL-terminated, whereas Perl strings can contain interior NULs.

Second, in general, they are fragile, with the possibility of reading
uninitialized data or writing outside the legal boundaries. This has
caused many a bug. It's better to put some bound on things, like
strncat() does.

strncat() is probably a bad example, but you've got the right idea.

We could say "we've validated this use and it's safe" and keep using it,
but perl is continually being maintained, introducing both changes in
assumptions we can make and more direct changes that can lead to bugs,
so it might not stay safe.

my_strlcpy() and my_strlcat() (which have saner behaviour than strncpy() and strncat()) mitigate any issues that such changes introduce.

Versions of my_strlcpy() and my_strlcat() that assert on overflow might
be even better (note that the versions in util.c aren't used if the system
provides strlcpy()/strlcat() (Debian Linux stable libc doesn't provide them,
NetBSD and darwin do and presumably other BSDs.)

It's easiest to fix this ticket by changing to use strlcpy() and
strlcat(), which perl has defined with the prefix 'my_' in each case,
because not every system has them defined. But my point and Dan's was
that the test itself is fragile, because the C optimizer is free to
change any code it wants into using one of the forbidden ones. No one
responded to that point, and so the ticket has languished until today.

The test is fragile in both directions - the compiler could define strcpy()
as an inline function, in which case it won't be visible in the nm output.

Strangely, we declare strcat(), strcpy() in some cases (perl.h)​:

#ifndef STANDARD_C
/* All of these are in stdlib.h or time.h for ANSI C */
Time_t time();
struct tm *gmtime(), *localtime();
#if defined(OEMVS)
char *(strchr)(), *(strrchr)();
char *(strcpy)(), *(strcat)();
#else
char *strchr(), *strrchr();
char *strcpy(), *strcat();
#endif
#endif /* ! STANDARD_C */

Tony

@p5pRT
Copy link
Author

p5pRT commented Aug 10, 2016

From jjuran@gmail.com

On Aug 9, 2016, at 7​:07 PM, Karl Williamson <public@​khwilliamson.com> wrote​:

On 08/09/2016 03​:34 PM, Father Chrysostomos via RT wrote​:

On Mon Aug 08 23​:35​:02 2016, tonyc wrote​:

On Thu Jul 14 19​:58​:13 2016, public@​khwilliamson.com wrote​:

I believe we call some compilers on some platforms with just "-O". I
suspect that it's best to skip unless there is an explicit "-O0".

I believe the real problem is using strcat() at all, I suspect from
this
comment​:

+ * This is one of the few places in the perl core, where we can
use
+ * standard functions like strlen() and strcat(). It's because
we're
+ * looking for NULs. */

that you misunderstood why we avoid strcpy(), strcat().

Can you explain why? Or is it documented somewhere?

Maybe my comment is a little cheeky, but I do believe I understand why one should be avoiding these.

First, in Perl, they don't generally work as C strings are NUL-terminated, whereas Perl strings can contain interior NULs.

Second, in general, they are fragile, with the possibility of reading uninitialized data or writing outside the legal boundaries. This has caused many a bug. It's better to put some bound on things, like strncat() does.

If there are other reasons, I don't know them.

In order to avoid buffer overflows with strcat(), you generally need to know the length of the destination string in advance. Since strcat() is basically strlen() + strcpy(), the length measurement is duplicated. If strcat() is called in a loop with the same destination string, the complexity is quadratic, whereas tracking the increasing length and using strcpy() is merely linear.

Of course, since for safety you also have to know the length of the copied string in advance, one may as well use memcpy(), which might be more efficient than strcpy() (since it can potentially copy multiple bytes at once).

Josh

@p5pRT
Copy link
Author

p5pRT commented Aug 27, 2016

From @khwilliamson

Taking the path of least resistance, commit fdc080f
changes to use my_strlcat, as Craig suggested.
I forgot that Tony had already supplied a patch, so basically duplicated his work in that commit
--
Karl Williamson

@p5pRT
Copy link
Author

p5pRT commented Aug 27, 2016

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant