ANNOUNCEMENT: Octave 7.1 RC2 now available!

Octave 7.0.92 is now available for download at GNU Alpha: Index of /gnu/octave

Octave 7.0.92 is the second release candidate (RC2) for the 7.1 release.

Both source and binary installations are available. Please test RC2 for your platform and report your feedback. Bugs should be reported at Savannah: GNU Octave - Bugs: Browse Items [Savannah]

1 Like

Thank you @jwe for providing the second release candidate!

The 64-bit installer works correctly on Windows 11. The test suite passes without any unknown errors or regressions here.

I also tried compiling the tarball natively on Windows with MSYS2/MINGW64. It builds without errors and make check passes without any unknown errors or regressions.
Also, prepared updated build rules for the Octave package for the MSYS2 environments that are currently supported. Interested parties could download the build artifacts from here:
octave: Update to Octave 7.0.92 (RC2) · mmuetzel/MINGW-packages@f0a8589 (github.com)

While trying to come up with some tests for edge cases for range operator tests, I tried to execute intmax('int64') : 2*double(intmin('int64')) : intmin('int64').
That leads to something that looks like an infinite loop that outputs warning: floating point exception repeatedly until I kill the Octave process.

Edit: I added some tests for (integer) ranges here:
octave: cb0a54576eb0 (gnu.org)
I’m not sure if this covers all of the cases @jwe was referring to in the thread for RC1. And some of those tests might not be worth checking. (But I figured better have too much than too less in this case.)
The part of the tests that would lead to the deadlock is commented out currently.

Edit 2: Fwiw, Matlab R2021a doesn’t get that right either (but at least no deadlock for them):

>> intmax('int16') : -2*double(intmax('int16')) : intmin('int16')

ans =

  1×2 int16 row vector

    32767   -32767

>> intmax('int32') : -2*double(intmax('int32')) : intmin('int32')

ans =

  1×2 int32 row vector

    2147483647            -1

>> intmax('int64') : -2*double(intmax('int64')) : intmin('int64')

ans =

  1×2 int64 row vector

    9223372036854775807                     -1

Nice! We (Octave 7.0.92) get this right for int32:

>> intmax('int32') : -2*double(intmax('int32')) : intmin('int32')
ans =

   2147483647  -2147483647

We shouldn’t have an infinite loop, so unless you want to work on that problem, I’ll check to see why it is happening. But isn’t part of the problem that 2*double(intmax('int32')) can be represented exactly in a double but not 2*double(intmax('int64'))?

1 Like

You are right, 2*double(intmax('int64')) cannot be represented exactly in double precision. The tests should probably be adapted for that.
The same infinite loop can also be triggered with intmax('int64') : 2*double(intmin('int64')) : intmin('int64'). (That should probably just return intmax('int64').) IIUC, 2*double(intmin('int64')) should be exactly representable in double precision.

You are probably much more familiar with the range implementation than me. I’d appreciate it if you could take a look.

Edit: I hope I fixed the floating point issues in the tests here: octave: 82c1554c4a64 (gnu.org)

1 Like

@rik: ISTR, you have admin access to our tracker on savannah. Could you please add a tag for “7.0.92”?

@mmuetzel, @rik: I added 7.0.92 to the list of possible releases.

1 Like

Minor thing: the list of versions is getting long (needs more than a screen to get to recent versions). Could they be rearranged from newest to oldest?

No, not easy to reverse the order as far as I know. I hid all of the version IDs older than 5.

2 Likes

compiled 7.1 RC2 (7.0.92) running Slackware64 15.0. Reports:

Summary:

  PASS                            17096
  FAIL                                0
  XFAIL (reported bug)               24
  SKIP (missing feature)             98
  SKIP (run-time condition)          26

The only feature that the configure script did not found (because it is not installed) was the rapidjson.

I know I wrote I wouldn’t look into the infinite loop issue with int64 ranges. But I couldn’t resist. :wink:

Hopefully fixed with this change:
octave: aaf689533e7b (gnu.org)

1 Like

Compiled with clang on Fedora:

test ../test/range.tst
warning: imaginary part of complex colon arguments is ignored
warning: called from
    __test__ at line 2 column 1
    test at line 683 column 11

***** test  # ascending ranges
 types = {"int8", "int16", "int32", "int64"};
 for i_type = 1:numel (types)
   assert (intmin (types{i_type}) : -double (intmin (types{i_type})) : intmax (types{i_type}), ...
           [intmin(types{i_type}), 0]);
   assert (intmin (types{i_type}) : -2*double (intmin (types{i_type})) : intmax (types{i_type}), ...
           intmin (types{i_type}));
   if (! strcmp (types, "int64"))
     ## The increment cannot be represented in double precision for "int64"
     assert (intmin (types{i_type}) : 2*double (intmax (types{i_type})) : intmin (types{i_type}), ...
             [intmin(types{i_type}), intmax(types{i_type})-1]);
   endif
 endfor
!!!!! test failed
ASSERT errors for:  assert (intmin (types {i_type}):-2 * double (intmin (types {i_type})):intmax (types {i_type}),intmin (types {i_type}))

  Location  |  Observed  |  Expected  |  Reason
     .          O(1x2)       E(1x1)      Dimensions don't match
shared variables     mt_row = [](1x0)
    inf = Inf
    nan = NaN
    zero = 0
    pt3 = 0.3000
    pt6 = 0.6000
    pt9 = 0.9000
    one = 1
    epsilon = 1.1921e-07

(see also http://buildbot.octave.org:8010/#/builders/30/builds/534 )

There are warnings like:

../src/libinterp/corefcn/oct-stream.cc:143:17: warning: implicit conversion from 'long' to 'double' changes value from 9223372036854775807 to 9223372036854775808 [-Wimplicit-const-int-float-conversion]
        if (d > std::numeric_limits<octave_idx_type>::max ())
              ~ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<...>
../src/libinterp/corefcn/xpow.cc:79:30: warning: implicit conversion from 'int' to 'float' changes value from 2147483647 to 2147483648 [-Wimplicit-const-int-float-conversion]
          && ((x >= 0 && x < std::numeric_limits<int>::max ())
                           ~ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../src/libinterp/corefcn/xpow.cc:1516:20: note: in instantiation of function template specialization 'octave::xisint<float>' requested here
  if (a < 0.0 && ! xisint (b))
                   ^
1 warning generated.
<...>
/bin/sh ./libtool  --tag=CXX   --mode=compile clang++ -DHAVE_CONFIG_H -I. -I../src  -Iliboctave -I../src/liboctave -I../src/liboctave/array -Iliboctave/numeric -I../src/liboctave/numeric -Iliboctave/operators -I../src/liboctave/operators -I../src/liboctave/system -I../src/liboctave/util -I../src/libinterp/octave-value -Ilibinterp -I../src/libinterp -I../src/libinterp/operators -Ilibinterp/parse-tree -I../src/libinterp/parse-tree -Ilibinterp/corefcn -I../src/libinterp/corefcn -I../src/liboctave/wrappers  -I/usr/include/GraphicsMagick   -I/usr/lib/jvm/java-11-openjdk-11.0.14.1.1-5.fc35.x86_64/include -I/usr/lib/jvm/java-11-openjdk-11.0.14.1.1-5.fc35.x86_64/include/linux  -fPIC -pthread -Wall -W -Wshadow -Woverloaded-virtual -Wold-style-cast -Wformat -Wpointer-arith -Wwrite-strings -Wcast-align -Wcast-qual  -g -O2 -MT libinterp/octave-value/liboctave_value_la-ov-bool.lo -MD -MP -MF libinterp/octave-value/.deps/liboctave_value_la-ov-bool.Tpo -c -o libinterp/octave-value/liboctave_value_la-ov-bool.lo `test -f 'libinterp/octave-value/ov-bool.cc' || echo '../src/'`libinterp/octave-value/ov-bool.cc
../src/libinterp/octave-value/ov-base.cc:496:1: warning: implicit conversion from 'long' to 'double' changes value from 9223372036854775807 to 9223372036854775808 [-Wimplicit-const-int-float-conversion]
INT_CONV_METHOD (long int, long)
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../src/libinterp/octave-value/ov-base.cc:482:18: note: expanded from macro 'INT_CONV_METHOD'
    else if (d > std::numeric_limits<T>::max ())                        \
               ~ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../src/libinterp/octave-value/ov-base.cc:497:1: warning: implicit conversion from 'unsigned long' to 'double' changes value from 18446744073709551615 to 18446744073709551616 [-Wimplicit-const-int-float-conversion]
INT_CONV_METHOD (unsigned long int, ulong)
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../src/libinterp/octave-value/ov-base.cc:482:18: note: expanded from macro 'INT_CONV_METHOD'
    else if (d > std::numeric_limits<T>::max ())                        \
               ~ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../src/libinterp/octave-value/ov-base.cc:499:1: warning: implicit conversion from 'long' to 'double' changes value from 9223372036854775807 to 9223372036854775808 [-Wimplicit-const-int-float-conversion]
INT_CONV_METHOD (int64_t, int64)
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../src/libinterp/octave-value/ov-base.cc:482:18: note: expanded from macro 'INT_CONV_METHOD'
    else if (d > std::numeric_limits<T>::max ())                        \
               ~ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../src/libinterp/octave-value/ov-base.cc:500:1: warning: implicit conversion from 'unsigned long' to 'double' changes value from 18446744073709551615 to 18446744073709551616 [-Wimplicit-const-int-float-conversion]
INT_CONV_METHOD (uint64_t, uint64)
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../src/libinterp/octave-value/ov-base.cc:482:18: note: expanded from macro 'INT_CONV_METHOD'
    else if (d > std::numeric_limits<T>::max ())                        \
               ~ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
4 warnings generated.
<...>
./src/liboctave/numeric/lo-mappers.cc:186:15: warning: implicit conversion from 'long' to 'double' changes value from 9223372036854775807 to 9223372036854775808 [-Wimplicit-const-int-float-conversion]
      if (x > std::numeric_limits<octave_idx_type>::max ())
            ~ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../src/liboctave/numeric/lo-mappers.cc:198:15: warning: implicit conversion from 'long' to 'float' changes value from 9223372036854775807 to 9223372036854775808 [-Wimplicit-const-int-float-conversion]
      if (x > std::numeric_limits<octave_idx_type>::max ())
            ~ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../src/liboctave/numeric/lo-mappers.cc:221:15: warning: implicit conversion from 'int' to 'float' changes value from 2147483647 to 2147483648 [-Wimplicit-const-int-float-conversion]
      if (x > std::numeric_limits<int>::max ())
            ~ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
3 warnings generated.

etc…

Not sure if those are related to the problem.

@dasergatskov: Could you check which two values the range contains when it should only contain one?

Edit: For some reason, the builder with clang on Debian seems to pass that check. So, most likely it would also pass if I tried to test a clang build on Ubuntu.
Edit 2: The Ubuntu runners on GitHub (with gcc and with clang) also pass those tests:
Avoid integer division by zero for int64 ranges with double increment. · gnu-octave/octave@024709f · GitHub

It fails for in64:

octave:5> assert (intmin (types{i_type}) : 2*double (intmax (types{i_type})) : intmin (types{i_type}), ...
             [intmin(types{i_type}), intmax(types{i_type})-1]);
error: ASSERT errors for:  assert (intmin (types {i_type}):2 * double (intmax (types {i_type})):intmin (types {i_type}),[intmin(types {i_type}), intmax(types {i_type}) - 1])

  Location  |  Observed  |  Expected  |  Reason
     .          O(1x1)       E(1x2)      Dimensions don't match
octave:6> types{i_type}
ans = int64
clang -v
clang version 13.0.0 (Fedora 13.0.0-3.fc35)
Target: x86_64-redhat-linux-gnu
intmin ("int64")
ans = -9223372036854775808
intmax ("int64")
ans = 9223372036854775807
double(intmax ("int64"))
ans = 9.223372036854776e+18
format bit
double(intmax ("int64"))
ans = 0100001111100000000000000000000000000000000000000000000000000000

I also got the same errors on Ubuntu 21.10:

ctave:1> test ../test/range.tst
warning: imaginary part of complex colon arguments is ignored
warning: called from
    __test__ at line 2 column 1
    test at line 683 column 11

***** test  # ascending ranges
 types = {"int8", "int16", "int32", "int64"};
 for i_type = 1:numel (types)
   assert (intmin (types{i_type}) : -double (intmin (types{i_type})) : intmax (types{i_type}), ...
           [intmin(types{i_type}), 0]);
   assert (intmin (types{i_type}) : -2*double (intmin (types{i_type})) : intmax (types{i_type}), ...
           intmin (types{i_type}));
   if (! strcmp (types, "int64"))
     ## The increment cannot be represented in double precision for "int64"
     assert (intmin (types{i_type}) : 2*double (intmax (types{i_type})) : intmin (types{i_type}), ...
             [intmin(types{i_type}), intmax(types{i_type})-1]);
   endif
 endfor
!!!!! test failed
ASSERT errors for:  assert (intmin (types {i_type}):-2 * double (intmin (types {i_type})):intmax (types {i_type}),intmin (types {i_type}))

  Location  |  Observed  |  Expected  |  Reason
     .          O(1x2)       E(1x1)      Dimensions don't match
shared variables     mt_row = [](1x0)
    inf = Inf
    nan = NaN
    zero = 0
    pt3 = 0.3000
    pt6 = 0.6000
    pt9 = 0.9000
    one = 1
    epsilon = 1.1921e-07
octave:2> ver
----------------------------------------------------------------------
GNU Octave Version: 7.0.93 (hg id: aaf689533e7b)
GNU Octave License: GNU General Public License
Operating System: Linux 5.13.0-37-generic #42-Ubuntu SMP Tue Mar 15 14:34:06 UTC 2022 x86_64
----------------------------------------------------------------------

So it looks like a clang-13 problem.

@dasergatskov: That assert is expected to fail because of the limitations of double precision floating point numbers. That’s why it is skipped for “int64” in the test.
The assert that is unexpectedly failing in the test suite is this one:

   assert (intmin (types{i_type}) : -2*double (intmin (types{i_type})) : intmax (types{i_type}), ...
           intmin (types{i_type}));

Could you please show which numbers the following range returns on the affected systems?

intmin ("int64") : -2*double (intmin ("int64")) : intmax ("int64")

It should be only the single number -9223372036854775808.

This is on Octave 8 (hg id 1be26e9c07e3) but the behavior for ranges should be the same as for 7.0.92.

Compiled with Clang 13.0.1:

>> intmin ("int64") : -2*double (intmin ("int64")) : intmax ("int64")
ans =

  -9223372036854775808  0

Compiled with GCC 11.2.0:

>> intmin ("int64") : -2*double (intmin ("int64")) : intmax ("int64")
ans = -9223372036854775808

OS Manjaro Linux (rolling release) with kernel 5.15.28.

EDIT: This set of compiler warnings with Clang looks very much related:

../libinterp/octave-value/ov-base.cc:495:1: warning: implicit conversion from 'long' to 'double' changes value from 9223372036854775807 to 9223372036854775808 [-Wimplicit-const-int-float-conversion]
INT_CONV_METHOD (long int, long)
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
../libinterp/octave-value/ov-base.cc:481:18: note: expanded from macro 'INT_CONV_METHOD'
    else if (d > std::numeric_limits<T>::max ())                        \
               ~ ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

EDIT: Changing that behavior in ov-base.cc and elsewhere looks too disruptive to releasing 7.1. GCC has no problems with that part anyway. Do we need to warn users and distro packagers not to use Clang 13 for this?

I don’t think that is necessary. Those tests are for very corner cases. And similar things could probably happen in any other software compiled with clang 13 that casts double to uint64.
Instead it would be enough to open a bug report for this and tag that test with that number imho. If we find out more and maybe can construct a minimal reproducer, maybe someone could report it to the clang guys.

Wrt the warnings: I don’t think they are related. Also, the issue they are warning about isn’t specific to clang. That cast changes the value for any compiler. The only difference is that gcc doesn’t warn about it. (Maybe because it warns about a very corner case issue.)
I’m not even sure if there is any input for which those conditions would end up being wrong…
Edit: Well, they end up being wrong for this very test case. But we already handle that case with the recent changes.

Minimal reproducer:

#include <cmath>
#include <iostream>

int main (void)
{
  double db_large_integer = std::pow (2., 64.);
  std::cout << "db_large_integer: " << db_large_integer << std::endl;
  uint64_t ui64_large_integer = db_large_integer;
  std::cout << "ui64_large_integer: " << ui64_large_integer << std::endl;
  return 0;
}

With Ubuntu 21.10:

$ g++ --version
g++ (Ubuntu 11.2.0-7ubuntu2) 11.2.0
Copyright (C) 2021 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
$ g++ -otest_cast test_cast.cc
$ ./test_cast
db_large_integer: 1.84467e+19
ui64_large_integer: 0
$ clang++ --version
Ubuntu clang version 13.0.0-2
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin
$ clang++ -otest_cast test_cast.cc
$ ./test_cast
db_large_integer: 1.84467e+19
ui64_large_integer: 9223372036854775808

IIUC, the overflow behavior of unsigned integers is defined in the standard. Afaict, gcc gets the correct answer, clang doesn’t.

Edit: Opened a bug report here: bug #62212, Wrong unsigned integer overflow with clang [Savannah]

1 Like

IIUC, the issue uncovered by that test is resolved now (bug #62212).

How should we proceed with the segfaults on ARM (32-bit?) platforms?
bug #62207, segfault in bug-35881/bug-35881.tst in 32-bit ARM and MIPS
bug #61911, testsuite segfaults on Debian armel

IIUC, both seem to indicate issues with deleting invalid objects in the parse-tree.
It’s not clear to me what is causing this or whether this is limited to those platforms. It might also be that these issues just occur more often on those platforms (maybe because they run on less beefy hardware?). But they might point to something more general…

2 Likes

It’s possible that there is an error in what happens when clear is called inside a function. I’ll try to trace what path is taken in that case and see whether I can spot the problem.

3 Likes