kevinlawler / kona

Open-source implementation of the K programming language
ISC License
1.36k stars 138 forks source link

Floating Point Exception #558

Closed tavmem closed 4 years ago

tavmem commented 4 years ago

This issue was identified by adam.antonik@gmail.com

dop_:{
 l:5=4:x;r:5=4:y
 if[~l|r;:+[x]y];if[l&~r;:@[x;_n;_f[;y]]];if[r&~l;:@[y;_n;_f[x]]]
 a:!x;b:!y;i:a@&a _lin b; j: a _dvl i;k:b _dvl i;
 @[@[@[x;i;:;_f'[x i;y i]];j;_f[;0]];k;:;_f[0]'y k]}

a:.+(`a`b;1 2)
b:.+(`b`c;3 4)
dop_[a;b]

Floating point exception (core dumped)
tavmem commented 4 years ago
$ cat dop.k
dop_:{
 l:5=4:x;r:5=4:y
 if[~l|r;:+[x]y];if[l&~r;:@[x;_n;_f[;y]]];if[r&~l;:@[y;_n;_f[x]]]
 a:!x;b:!y;i:a@&a _lin b; j: a _dvl i;k:b _dvl i;
 @[@[@[x;i;:;_f'[x i;y i]];j;_f[;0]];k;:;_f[0]'y k]}

a:.+(`a`b;1 2)
b:.+(`b`c;3 4)
dop_[a;b]
$ 
$ 
$ 
$ rlwrap -n ./k dop
K 2.8 2000-10-10 Copyright (C) 1993-2000 Kx Systems 
\ for help. \\ to exit.

.((`a;1;)
  (`b;5;)
  (`c;4;))
tavmem commented 4 years ago

This is a regression. It works in the commit 762f5267d4b17dbeda63036620cdaad513e84556 of March 24, 2018, titled "better fix for #491: pointer dereference" and is broken beginning with the commit efb970744d59af34228cf5125b9ce8fe8fd5b689 of March 25, 2018 titled "fix #506: execute"

tavmem commented 4 years ago

Well, not exactly. It does not crash is the commit 762f5267d4b17dbeda63036620cdaad513e84556 of March 24, 2018, but it does not yield the correct result either:

$ rlwrap -n ./k dop
.((`a;;)
  (`b;;)
  (`c;;))

It does crash in (and after) the commit efb970744d59af34228cf5125b9ce8fe8fd5b689 of March 25, 2018.

tavmem commented 4 years ago

Upon closer inspection, this may not have ever worked properly.

tavmem commented 4 years ago

The crash occurs on line 250 of src/v.c in function K at_ref(K *p, K b, K c, K y)

  else if(4==ABS(bt))
  {
    P(5!=pt && 6!=pt,TE)
    DO(atomI(b)?1:n,
      K args=newK(0,argc);U(args)//Cheating 0-type w/ NULLs
      S u = kS(b)[i%bn];
      if(!strlen(u))R DOE;
      kK(args)[0]= ci(*lookupEVOrCreate(p,u)); // ... mm/o? tricky
      if(argc > 1) kK(args)[1] = atomI(b)?ci(y):itemAtIndex(y,i%yn);           //line 250
      K r = specialAmendDot(c,args);
      M(r,args)
      K *v = EVP(DE(*p,u));
      cd(*v);
      *v=r;
      cd(args);
   )
  }

The relevant data items involved are:

argc: 2
sd(b):     0x7f7d35056440 0x7f7d35056458            7-6 -4 1   ,`b
atomI(b): 0
sd(y):     0x7f7d35052480 0x7f7d35052498            4-7 7 0   
i: 0   yn: 0
Floating point exception (core dumped)

The exception occurs because 0 is divided by 0.

The problem may be with function I atomI(K a){R a->t>0?1:0;}

While it is true that its type is -4, it only has 1 element, and is argueably an atom.

tavmem commented 4 years ago

Here is a difference It may (or may not) be relevant.

K 2.8 2000-10-10 Copyright (C) 1993-2000 Kx Systems
\ for help. \\ to exit.

  a: .+(`a`b;1 2)
  b: .+(`b`c;3 4)
  i: ,`b
  a i
,2
  b i
,3
$ rlwrap -n ./k
kona      \ for help. \\ to exit.

  a: .+(`a`b;1 2)
  b: .+(`b`c;3 4)
  i: ,`b
  a i
2
  b i
3

I plan to open this as a separate issue and fix it. Then see if the current issue still crashes.

tavmem commented 4 years ago

After fixing issue #560, this issue no longer crashes ... but it does not give the correct result, either:

$ rlwrap -n ./k dop_
kona      \ for help. \\ to exit.

  .((`a;;)
  (`b;;)
  (`c;;))
tavmem commented 4 years ago

The problem is identified ... but not fixed. If a local variable "t" is inserted in the 1st if-statement of the 2nd line of dop we get the correct result. The revised dop is:

dop_:{
 l:5=4:x;r:5=4:y
 if[~l|r;:t:+[x]y];if[l&~r;:@[x;_n;_f[;y]]];if[r&~l;:@[y;_n;_f[x]]]
 a:!x;b:!y;i:a@&a _lin b; j: a _dvl i;k:b _dvl i;
 @[@[@[x;i;:;_f'[x i;y i]];j;_f[;0]];k;:;_f[0]'y k]}

a:.+(`a`b;1 2)
b:.+(`b`c;3 4)
dop_[a;b]

Running this yields:

kona      \ for help. \\ to exit.

  .((`a;1;)
  (`b;5;)
  (`c;4;))

The local variable "t" should not be necessary. There is some kind of "shadowing" going on in the statement

@[x;i;:;_f'[x i;y i]]

where one copy of the dictionary x is being updated, but not subsequently used.

This exercise has also identified another new issue. After running the above:

  \v
`dop_ `x `y `a `b
  x
  y

x and y are local variables and should not be added to the symbol table as global variables. Their contents is null (which is good).

tavmem commented 4 years ago

The correct result can be gotten w/o using an extra local variable "t". It also works 2 other ways:

For some reason, the phrase :+[x]y is not handled properly (yet).

tavmem commented 4 years ago

Some simple test cases:

kona      \ for help. \\ to exit.

  fa:{:x+y}
  fa[2;3]
5

  fb:{:(+[x]y)}
  fb[2;3]
5

  fc:{:+[x]y}
  fc[2;3]

  _n~fc[2;3]
0

fa and fb work fine. fc does not work.

fc yields no apparent response. It is not null.

  d:fa[2;3]
  #d
1

  d:fc[2;3]
  #d

  #_n
1
tavmem commented 4 years ago

So, if it is not "null", what is the output? If you make the following 2 changes to the codebase:

$ git diff
diff --git a/src/kc.c b/src/kc.c
index a659909..0d1f9f8 100644
--- a/src/kc.c
+++ b/src/kc.c
@@ -256,7 +256,7 @@ I line(FILE*f, S*a, I*n, PDA*p) {  //just starting or just executed: *a=*n=*p=0,
     if(o&&k)O("Elapsed: %.7f\n",d);
   #endif

-  if(o && fam && !feci)show(k);
+  if(o && fam && !feci)sd_(k,2);

   cd(k);
  cleanup:
diff --git a/src/kc.h b/src/kc.h
index d7902c3..0710b1a 100644
--- a/src/kc.h
+++ b/src/kc.h
@@ -1,5 +1,6 @@
 void init_genrand64(unsigned long long seed);
 extern I SEED;
+extern K sd_(K x,I f);
 V alloc(size_t sz);
 K _dot_t();
 K newE(S s,K k);
$

Then, you get:

$ rlwrap -n ./k
kona      \ for help. \\ to exit.

  f:{:+[y]x}
  f [2;3]
     0x7f18260b8380 0x7f18260b8398            2-7 7 0   
     a0:    0x7f18260b8398     .k
     a1:    0x7f18260b83a0     (nil)
     a2:    0x7f18260b83a8     0x7f18260b7340 0x7f18260b7358            1-6 -4 2   0x16 
(nil)  
     a3:    0x7f18260b83b0     0x7f18260b72c0 0x7f18260b72d8            1-6 5 0   
.()
     a4:    0x7f18260b83b8     0x7f18260b7300 0x7f18260b7318            1-6 5 0   
.()
     a5:    0x7f18260b83c0     0x7f18260b8400 0x7f18260b8418            1-7 7 0   
     b0:    0x7f18260b8418     .k
     b1:    0x7f18260b8420     (nil)
     b2:    0x7f18260b8428     0x7f18260b7480 0x7f18260b7498            1-6 -4 2   ` (nil)  
     .2b[0]: 0x7f18260e6ee0     
     b3:    0x7f18260b8430     0x7f18260b73c0 0x7f18260b73d8            1-6 5 0   
.()
     b4:    0x7f18260b8438     0x7f18260b7400 0x7f18260b7418            1-6 5 0   
.()
     b5:    0x7f18260b8440     
     b6:    0x7f18260b8448     
     b7:    0x7f18260b8450     
     a6:    0x7f18260b83c8     
     a7:    0x7f18260b83d0     

The output is a k-structure of type 7-0 (an unexecuted structure). The wiki (Data and Execution) tells us that the 2nd member is the code section. The code section (a2) has 2 elements of type 4 From src/k.c you can find that 0x16 is "dyadic plus" The second element is just a terminator for the code string (nil).

  {0, 0, 0,0,{0}},                      // 0x10
  {0, 0, 0,0,{0}},
  {0, 0, 0,0,{0}},
  {0, 0, 0,0,{0}},
  {0, 0, 0,0,{0}},
  {0, 1, flip,"+",{0}},
  {0, 2, plus,"+",{plus_over,plus_scan}},    //0x16
  {0, 1, negate,"-",{0}},
  {0, 2, minus,"-",{0,0,minus_eachpair}},
  {0, 1, first,"*",{0}},
  {0, 2, times,"*",{times_over}},
  {0, 1, reciprocal,"%%",{0}},
  {0, 2, divide,"%%",{0}},
  {0, 1, reverse,"|",{0}},
  {0, 2, max_or,"|",{max_or_over}},
  {0, 1, where,"&",{0}},
  {0, 2, min_and,"&",{min_and_over}},   // 0x20

I'm a bit surprised that "cache_wd" (a5) also contains a type 7-0 k-structure. It also has a 2 element code member (b2).

tavmem commented 4 years ago

Even simpler test cases:


$ rlwrap -n ./k
kona      \ for help. \\ to exit.

  :+[2]3

  +[2]3
5
  :2+3
5
  :(+[2]3)
5
tavmem commented 4 years ago

Here is another problem (which hopefully gets fixed as a side effect of fixing the current issue):

$ rlwrap -n ./k
kona      \ for help. \\ to exit.

  :2
2
  :+2
:
tavmem commented 4 years ago

Actually, this last example may provide the "key" to the problem. The "result" that is produced is:

  result: 0x7ffdbdeeeaa8     0x7fc127201080 0x7fc127201098            1-7 7 1   :
       a0:    0x7fc127201098     .k
       a1:    0x7fc1272010a0     (nil)
       a2:    0x7fc1272010a8     0x7fc12722b800 0x7fc12722b818            1-6 -4 2   0x3c
  (nil)
       .2a[0]: 0x3c
       a3:    0x7fc1272010b0     0x7fc12722b600 0x7fc12722b618            1-6 5 0
  .()
       a4:    0x7fc1272010b8     0x7fc12722b6c0 0x7fc12722b6d8            1-6 5 0
  .()
       a5:    0x7fc1272010c0
       a6:    0x7fc1272010c8
       a7:    0x7fc1272010d0

From src/k.c

  {0, 2, what,"?",{0}},                // 0x30
  {0, 1, floor_verb,"_",{0}},
  {0, 2, drop_cut,"_",{0}},
  {0, 1, enlist,",",{0}},
  {0, 2, join,",",{join_over}},
  {0, 1, count,"#",{0}},
  {0, 2, take_reshape,"#",{0}},
  {0, 1, format,"$",{0}},
  {0, 2, dollar,"$",{0}},
  {0, 1, dot_monadic,".",{0}},
  {0, 2, dot,".",{0}},
  {0, 1, colon_monadic,":",{0}},
  {0, 2, colon_dyadic,":",{0}},        // 0x3c
  {0, 1, _0m,"0:",{0}},
  {0, 2, _0d,"0:",{0}},
  {0, 1, _1m,"1:",{0}},
  {0, 2, _1d,"1:",{0}},                // 0x40

The colon is being translated by the parser to 0x3c which is colon dyadic, instead of 0x7d (which is "return")

  {0, 2, _dvl,"_dvl",{0}},             // 0x70
  {0, 2, _hat,"_hat",{0}},
  {0, 2, _in,"_in",{0}},
  {0, 2, _lin,"_lin",{0}},
  {0, 2, _lsq,"_lsq",{0}},
  {0, 2, _mul,"_mul",{0}},
  {0, 2, _setenv,"_setenv",{0}},
  {0, 2, _sm,"_sm",{0}},
  {0, 2, _ss,"_ss",{0}},
  {0, 2, _sv,"_sv",{0}},
  {0, 2, _vs,"_vs",{0}},
  {0, 3, _ssr,"_ssr",{0}},
  {0, 1, tr_st," \\",{0}},  //trace_stop
  {0, 1, rtrn,":",{0}},     //return      0x7d

The strange thing is that the colon is being translated to 0x3c in the cases that work, as well as in the cases that fail. It is sort of interesting that any of the cases yield the correct result !

tavmem commented 4 years ago

After the commit 9419b171e1c9e349a131d426979296af70f844ec made on Nov 9, 2019:

kona      \ for help. \\ to exit.

  :+[2]3
5
  :+2
2

However, we still have:

$ rlwrap -n ./k dop_
kona      \ for help. \\ to exit.

  .((`a;;)
  (`b;;)
  (`c;;))

There must still be something else wrong.

tavmem commented 4 years ago

Some simple examples of what's working ... and what's not:

kona      \ for help. \\ to exit.

  :+[2]3
5
  :+5
5
  f:{ if[x;:+[x]y]; y }; f[0;3]
3
  f:{ if[x;:+[x]y]; y }; f[2;3]

  f:{ if[x;:x+y]; y }; f[2;3]
5
  f:{ if[x;:(+[x]y)]; y }; f[2;3]
5