After updating go (to 1.8) and gopherjs (to head) my application stopped functioning with the error
Uncaught ReferenceError: timedOut$24ptr is not defined.
I have already tried clearing gopherjs' compile cache, does not make a difference.
After googling i found this gist https://gist.github.com/jancona/441352b86fcd8553fd445adffb2f0a5f
by Jim Ancona, so apparently this is also affecting others.
this is the interesting part of the stack trace:
setRequestCancel @ main_cms.js:84919
send @ client.go:247
$packages.net/http.Client.ptr.send @ client.go:173
$packages.net/http.Client.ptr.Do @ client.go:595
this is the function that is broken:
setRequestCancel = function(req, rt, deadline) {
var $ptr, _tmp, _tmp$1, _tmp$2, _tmp$3, cancel, deadline, didTimeout, doCancel, initialReqCancel, once, req, rt, stopTimer, stopTimerCh, timedOut, timer;
stopTimer = $throwNilPointerError;
didTimeout = $throwNilPointerError;
if ($clone(deadline, time.Time).IsZero()) {
_tmp = nop;
_tmp$1 = alwaysFalse;
stopTimer = _tmp;
didTimeout = _tmp$1;
return [stopTimer, didTimeout];
}
initialReqCancel = req.Cancel;
cancel = new $Chan(structType, 0);
req.Cancel = cancel;
doCancel = (function $b() {
var $ptr, _ref, v, v$1, $s, $r;
/* */ $s = 0; var $f, $c = false; if (this !== undefined && this.$blk !== undefined) { $f = this; $c = true; $ptr = $f.$ptr; _ref = $f._ref; v = $f.v; v$1 = $f.v$1; $s = $f.$s; $r = $f.$r; } s: while (true) { switch ($s) { case 0:
$close(cancel);
_ref = rt;
/* */ if ($assertType(_ref, ptrType$21, true)[1] || $assertType(_ref, ptrType$14, true)[1]) { $s = 1; continue; }
/* */ if ($assertType(_ref, canceler, true)[1]) { $s = 2; continue; }
/* */ $s = 3; continue;
/* if ($assertType(_ref, ptrType$21, true)[1] || $assertType(_ref, ptrType$14, true)[1]) { */ case 1:
v = _ref;
$s = 3; continue;
/* } else if ($assertType(_ref, canceler, true)[1]) { */ case 2:
v$1 = _ref;
$r = v$1.CancelRequest(req); /* */ $s = 4; case 4: if($c) { $c = false; $r = $r.$blk(); } if ($r && $r.$blk !== undefined) { break s; }
/* } */ case 3:
$s = -1; return;
/* */ } return; } if ($f === undefined) { $f = { $blk: $b }; } $f.$ptr = $ptr; $f._ref = _ref; $f.v = v; $f.v$1 = v$1; $f.$s = $s; $f.$r = $r; return $f;
});
stopTimerCh = new $Chan(structType, 0);
once = new sync.Once.ptr(new sync.Mutex.ptr(0, 0), 0);
stopTimer = (function $b() {
var $ptr, $s, $r;
/* */ $s = 0; var $f, $c = false; if (this !== undefined && this.$blk !== undefined) { $f = this; $c = true; $ptr = $f.$ptr; $s = $f.$s; $r = $f.$r; } s: while (true) { switch ($s) { case 0:
$r = once.Do((function() {
var $ptr;
$close(stopTimerCh);
})); /* */ $s = 1; case 1: if($c) { $c = false; $r = $r.$blk(); } if ($r && $r.$blk !== undefined) { break s; }
$s = -1; return;
/* */ } return; } if ($f === undefined) { $f = { $blk: $b }; } $f.$ptr = $ptr; $f.$s = $s; $f.$r = $r; return $f;
});
timer = time.NewTimer(time.Until($clone(deadline, time.Time)));
timedOut = 0;
$go((function $b() {
var $ptr, _r$1, _selection, timedOut$24ptr, $s, $r;
/* */ $s = 0; var $f, $c = false; if (this !== undefined && this.$blk !== undefined) { $f = this; $c = true; $ptr = $f.$ptr; _r$1 = $f._r$1; _selection = $f._selection; timedOut$24ptr = $f.timedOut$24ptr; $s = $f.$s; $r = $f.$r; } s: while (true) { switch ($s) { case 0:
_r$1 = $select([[initialReqCancel], [timer.C], [stopTimerCh]]); /* */ $s = 1; case 1: if($c) { $c = false; _r$1 = _r$1.$blk(); } if (_r$1 && _r$1.$blk !== undefined) { break s; }
_selection = _r$1;
/* */ if (_selection[0] === 0) { $s = 2; continue; }
/* */ if (_selection[0] === 1) { $s = 3; continue; }
/* */ if (_selection[0] === 2) { $s = 4; continue; }
/* */ $s = 5; continue;
/* if (_selection[0] === 0) { */ case 2:
$r = doCancel(); /* */ $s = 6; case 6: if($c) { $c = false; $r = $r.$blk(); } if ($r && $r.$blk !== undefined) { break s; }
timer.Stop();
$s = 5; continue;
/* } else if (_selection[0] === 1) { */ case 3:
(timedOut$24ptr || (timedOut$24ptr = new ptrType$22(function() { return timedOut; }, function($v) { timedOut = $v; }))).setTrue();
$r = doCancel(); /* */ $s = 7; case 7: if($c) { $c = false; $r = $r.$blk(); } if ($r && $r.$blk !== undefined) { break s; }
$s = 5; continue;
/* } else if (_selection[0] === 2) { */ case 4:
timer.Stop();
/* } */ case 5:
$s = -1; return;
/* */ } return; } if ($f === undefined) { $f = { $blk: $b }; } $f.$ptr = $ptr; $f._r$1 = _r$1; $f._selection = _selection; $f.timedOut$24ptr = timedOut$24ptr; $f.$s = $s; $f.$r = $r; return $f;
}), []);
_tmp$2 = stopTimer;
_tmp$3 = $methodVal((timedOut$24ptr || (timedOut$24ptr = new ptrType$22(function() { return timedOut; }, function($v) { timedOut = $v; }))), "isSet");
stopTimer = _tmp$2;
didTimeout = _tmp$3;
return [stopTimer, didTimeout];
};
It looks like timedOut$24ptr is out of scope. It is declared in the $go((function $b() { just above.
Could the issue be related to the deprecation of Cancel in favour of Context in net/http/Request, as in this commit?: https://github.com/gopherjs/gopherjs/commit/0917fa2c47066674e43b89869c341aa9dae28e03
Thanks in advance and cheers, Lex.
my application stopped functioning
Is it possible to extract a snippet that can reproduce the issue?
Hi Dmitri, thanx for responding.
I managed to boil down the issue to this:
package main
import (
"fmt"
"net/http"
"time"
)
func main() {
apireq, _ := http.NewRequest("GET", "http://httpbin.org/get", nil)
client := &http.Client{Timeout: time.Second * 60}
//client := &http.Client{}
resp, _ := client.Do(apireq)
fmt.Println(resp.StatusCode) // 200 OK is what we want
}
The problem occurs when passing a Timeout to the client constructor literal.
Hope that helps.
I can reproduce with that, thanks. Very helpful. We need to investigate the cause and fix this.
I was able to reduce it to an even smaller case:
package main
func main() {
setRequestCancel()
}
func setRequestCancel() (didTimeout func()) {
var timedOut atomicBool
_ = func() {
_ = timedOut.method
}
return timedOut.method
}
type atomicBool int32
func (b *atomicBool) method() {} // Pointer receiver.
Running gopherjs run main.go causes:
$ gopherjs run main.go
/Users/Dmitri/Dropbox/Work/2013/GoLand/src/github.com/shurcooL/play/31/main.go.182659065:2336
didTimeout = $methodVal((timedOut$24ptr || (timedOut$24ptr = new ptrType(function() { return timedOut; }, function($v) { timedOut = $v; }))), "method");
^
ReferenceError: timedOut$24ptr is not defined
at setRequestCancel (/Users/Dmitri/Dropbox/Work/2013/GoLand/src/github.com/shurcooL/play/31/main.go.182659065:2336:28)
at main (/github.com/shurcooL/play/31/main.go:4:3)
...
I couldn't make it smaller than that. timedOut.method must be captured in a closure (passing timedOut either by value or pointer no longer reproduces), and timedOut.method must be returned, or else there's no reproduce. Also, if atomicBool.method has a value receiver instead of pointer receiver, it doesn't reproduce.
@neelance Can you take a look? It looks like a compiler bug related to combination of closures, method values, and pointer receivers.
Hi, is this issue fixed?
Hi. I'm using the colly with gopherjs (Go 1.12)
Here's my code -- I have the same issue:
package main
import (
"github.com/gocolly/colly"
"github.com/gopherjs/gopherjs/js"
)
func main() {
c := colly.NewCollector()
c.OnHTML(`title`, func(element *colly.HTMLElement) {
title := element.Text
//println(title)
js.Global.Get("document").Call("write", title)
})
c.Visit("https://github.com/gopherjs/gopherjs")
}
Most helpful comment
I was able to reduce it to an even smaller case:
Running
gopherjs run main.gocauses:I couldn't make it smaller than that.
timedOut.methodmust be captured in a closure (passingtimedOuteither by value or pointer no longer reproduces), andtimedOut.methodmust be returned, or else there's no reproduce. Also, ifatomicBool.methodhas a value receiver instead of pointer receiver, it doesn't reproduce.@neelance Can you take a look? It looks like a compiler bug related to combination of closures, method values, and pointer receivers.