[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: nodejs 8 terminate called after throwing an instance of 'std::length_error'



Hi,

On 06/01/18 15:20, Jérémy Lal wrote:
> This error happens on mipsel only:
> https://buildd.debian.org/status/fetch.php?pkg=nodejs&arch=mipsel&ver=8.9.3~dfsg-6&stamp=1515132264&raw=0
> 
> Maybe it's related to a bug in another package, is it a known issue ?

I believe you have hit one of the infamous Loongson FPU "bugs" [1].

This is an extract from the disassembly of nodejs in
v8::internal::compiler::Scheduler::ComputeSchedule:
> lwc1   $f1,-392(v0)
> mul.s  $f0,$f0,$f2
> c.le.s $f1,$f0
> bc1t   0x55cd6990

The C code for this is:
>   float node_hint_multiplier = (flags & Scheduler::kSplitNodes) ? 1.1 : 1;
>   size_t node_count_hint = node_hint_multiplier * graph->NodeCount();

After the lwc (which loads INT_MAX as a float) we have this in the float
registers according to gdb:
> f0:  0x44094000 flt: 549               dbl: 3.5336950251869015e+72
> f1:  0x4f000000 flt: 2.14748365e+09
> f2:  0x3f800000 flt: 1                 dbl: 1073742078
> f3:  0x41d00000 flt: 26

But after the multiplication we lose the value in f1:
> f0:  0x44094000 flt: 549               dbl: 5.6395463852218459e-315
> f1:  0x00000000 flt: 0
> f2:  0x3f800000 flt: 1                 dbl: 1073742078
> f3:  0x41d00000 flt: 26

The result of the comparison (c.le.s) then changes and we branch (bc1t)
when we should not. The end result is we end up with node_count_hint
being set to 0x80000000 which later causes the length_error.

In gcc, the Loongson bugs are worked around on mipsel by:
- Disabling fused multiply + add instructions completely
- Enabling FPXX which (as a side effect) disables use of odd FP
  registers for single precision arithmetic.

In nodejs you allow the use of odd FP registers by compiling with FP32.
I think if you add "-mno-odd-spreg" to your CFLAGS (and CXXFLAGS) then
you should be able to avoid these issues in C code (and fix this
specific bug). Unfortunately avoiding them in JITed code is a lot more
complex :/

Yunqiang, should we enable --without-odd-spreg-32 when compiling gcc on
mipsel? I think that will also fix this.

James

---

[1] Extract from Loongson 3A processor manual (google translated from
chinese so forgive the english):

The GS464 is compatible with the MIPS64 Release 2 release and
functionally implements all the FPU instructions specified by the MIPS64
architecture,
However, there are some instructions in the implementation of subtle
compatibility does not affect but more important difference, the
following two points worth the attention of programmers.
(1) multiply plus, multiply minus instruction. When executing the four
instruction sets of MADD.fmt, MSUB.fmt, NMADD.fmt and NMSUB.fmt, the
operation result of GS464 is slightly different from that of MIPS64
processor because GS464 only performs multiply-add operation only at the
final result
Do precision rounding, and the MIPS64 processor carried out after the
operation of a rounding, adding an additional round, resulting in
The final result of a minimum difference of 1.
(2) Single-precision arithmetic instructions. When the FR bit in the
Status control register is 0, abs.s, add.s, ceil.w.d, ceil.w.s, div.s,
floor.w.d, floor.w.s, mul.s, neg.s, round.w.d, round.w.s, sqrt.s, sub.s,
trunc.w.d, trunc.w.s, mov.s, cvt.d.s,
26 instructions such as cvt.d.w, cvt.s.d, cvt.s.w, cvt.w.d, cvt.w.s,
movf.s, movn.s, movt.s, movz.s etc can not be sent by odd numbers
Memory, and MIPS64 architecture processor can, at this point, Godson
follows MIPS R4000 and MIPSR10000 do
Act, slightly different from the provisions of MIPS64. (FR bits in
earlier MIPS processors indicate whether the floating-point registers
were 16 or 32,
The FR bit in MIPS64 indicates whether the floating-point register is
32-bit or 64-bit).

Attachment: signature.asc
Description: OpenPGP digital signature


Reply to: