mirror of
https://github.com/golang/go
synced 2024-09-24 07:10:12 -06:00
[dev.ssa] Merge remote-tracking branch 'origin/master' into mergebranch
Semi-regular merge of tip into dev.ssa. Change-Id: I855817c4746237792a2dab6eaf471087a3646be4
This commit is contained in:
commit
efefd11725
20
AUTHORS
20
AUTHORS
@ -105,6 +105,7 @@ Audrey Lim <audreylh@gmail.com>
|
||||
Augusto Roman <aroman@gmail.com>
|
||||
Aulus Egnatius Varialus <varialus@gmail.com>
|
||||
awaw fumin <awawfumin@gmail.com>
|
||||
Ayanamist Yang <ayanamist@gmail.com>
|
||||
Aymerick Jéhanne <aymerick@jehanne.org>
|
||||
Ben Burkert <ben@benburkert.com>
|
||||
Ben Olive <sionide21@gmail.com>
|
||||
@ -147,6 +148,7 @@ Chris Jones <chris@cjones.org>
|
||||
Chris Kastorff <encryptio@gmail.com>
|
||||
Chris Lennert <calennert@gmail.com>
|
||||
Chris McGee <sirnewton_01@yahoo.ca> <newton688@gmail.com>
|
||||
Christian Couder <chriscool@tuxfamily.org>
|
||||
Christian Himpel <chressie@googlemail.com>
|
||||
Christine Hansmann <chhansmann@gmail.com>
|
||||
Christoffer Buchholz <christoffer.buchholz@gmail.com>
|
||||
@ -237,8 +239,10 @@ Eivind Uggedal <eivind@uggedal.com>
|
||||
Elias Naur <elias.naur@gmail.com>
|
||||
Emil Hessman <c.emil.hessman@gmail.com> <emil@hessman.se>
|
||||
Emmanuel Odeke <emm.odeke@gmail.com> <odeke@ualberta.ca>
|
||||
Empirical Interfaces Inc.
|
||||
Eoghan Sherry <ejsherry@gmail.com>
|
||||
Eric Clark <zerohp@gmail.com>
|
||||
Eric Engestrom <eric@engestrom.ch>
|
||||
Eric Lagergren <ericscottlagergren@gmail.com>
|
||||
Eric Milliken <emilliken@gmail.com>
|
||||
Eric Roshan-Eisner <eric.d.eisner@gmail.com>
|
||||
@ -258,6 +262,7 @@ Fastly, Inc.
|
||||
Fatih Arslan <fatih@arslan.io>
|
||||
Fazlul Shahriar <fshahriar@gmail.com>
|
||||
Felix Geisendörfer <haimuiba@gmail.com>
|
||||
Filippo Valsorda <hi@filippo.io>
|
||||
Firmansyah Adiputra <frm.adiputra@gmail.com>
|
||||
Florian Uekermann <florian@uekermann-online.de>
|
||||
Florian Weimer <fw@deneb.enyo.de>
|
||||
@ -290,6 +295,8 @@ Guobiao Mei <meiguobiao@gmail.com>
|
||||
Gustav Paul <gustav.paul@gmail.com>
|
||||
Gustavo Niemeyer <gustavo@niemeyer.net>
|
||||
Gwenael Treguier <gwenn.kahz@gmail.com>
|
||||
Gyu-Ho Lee <gyuhox@gmail.com>
|
||||
H. İbrahim Güngör <igungor@gmail.com>
|
||||
Hajime Hoshi <hajimehoshi@gmail.com>
|
||||
Hari haran <hariharan.uno@gmail.com>
|
||||
Hariharan Srinath <srinathh@gmail.com>
|
||||
@ -321,6 +328,7 @@ Intel Corporation
|
||||
Irieda Noboru <irieda@gmail.com>
|
||||
Isaac Wagner <ibw@isaacwagner.me>
|
||||
Ivan Ukhov <ivan.ukhov@gmail.com>
|
||||
Jacob Hoffman-Andrews <github@hoffman-andrews.com>
|
||||
Jae Kwon <jae@tendermint.com>
|
||||
Jakob Borg <jakob@nym.se>
|
||||
Jakub Ryszard Czarnowicz <j.czarnowicz@gmail.com>
|
||||
@ -342,6 +350,7 @@ Jan Newmarch <jan.newmarch@gmail.com>
|
||||
Jan Ziak <0xe2.0x9a.0x9b@gmail.com>
|
||||
Jani Monoses <jani.monoses@ubuntu.com>
|
||||
Jaroslavas Počepko <jp@webmaster.ms>
|
||||
Jason Barnett <jason.w.barnett@gmail.com>
|
||||
Jason Del Ponte <delpontej@gmail.com>
|
||||
Jason Travis <infomaniac7@gmail.com>
|
||||
Jay Weisskopf <jay@jayschwa.net>
|
||||
@ -359,6 +368,7 @@ Jingcheng Zhang <diogin@gmail.com>
|
||||
Jingguo Yao <yaojingguo@gmail.com>
|
||||
Jiong Du <londevil@gmail.com>
|
||||
Joakim Sernbrant <serbaut@gmail.com>
|
||||
Joe Farrell <joe2farrell@gmail.com>
|
||||
Joe Harrison <joehazzers@gmail.com>
|
||||
Joe Henke <joed.henke@gmail.com>
|
||||
Joe Poirier <jdpoirier@gmail.com>
|
||||
@ -392,6 +402,7 @@ Joshua Chase <jcjoshuachase@gmail.com>
|
||||
Jostein Stuhaug <js@solidsystem.no>
|
||||
JT Olds <jtolds@xnet5.com>
|
||||
Jukka-Pekka Kekkonen <karatepekka@gmail.com>
|
||||
Julian Kornberger <jk+github@digineo.de>
|
||||
Julian Phillips <julian@quantumfyre.co.uk>
|
||||
Julien Schmidt <google@julienschmidt.com>
|
||||
Justin Nuß <nuss.justin@gmail.com>
|
||||
@ -502,6 +513,7 @@ Michael Vetter <g.bluehut@gmail.com>
|
||||
Michal Bohuslávek <mbohuslavek@gmail.com>
|
||||
Michał Derkacz <ziutek@lnet.pl>
|
||||
Miek Gieben <miek@miek.nl>
|
||||
Miguel Mendez <stxmendez@gmail.com>
|
||||
Mihai Borobocea <MihaiBorobocea@gmail.com>
|
||||
Mikael Tillenius <mikti42@gmail.com>
|
||||
Mike Andrews <mra@xoba.com>
|
||||
@ -530,6 +542,7 @@ Netflix, Inc.
|
||||
Nevins Bartolomeo <nevins.bartolomeo@gmail.com>
|
||||
ngmoco, LLC
|
||||
Niall Sheridan <nsheridan@gmail.com>
|
||||
Nic Day <nic.day@me.com>
|
||||
Nicholas Katsaros <nick@nickkatsaros.com>
|
||||
Nicholas Presta <nick@nickpresta.ca> <nick1presta@gmail.com>
|
||||
Nicholas Sullivan <nicholas.sullivan@gmail.com>
|
||||
@ -575,6 +588,7 @@ Paul Rosania <paul.rosania@gmail.com>
|
||||
Paul Sbarra <Sbarra.Paul@gmail.com>
|
||||
Paul Smith <paulsmith@pobox.com> <paulsmith@gmail.com>
|
||||
Paul van Brouwershaven <paul@vanbrouwershaven.com>
|
||||
Paulo Casaretto <pcasaretto@gmail.com>
|
||||
Pavel Paulau <pavel.paulau@gmail.com>
|
||||
Pavel Zinovkin <pavel.zinovkin@gmail.com>
|
||||
Pawel Knap <pawelknap88@gmail.com>
|
||||
@ -591,6 +605,7 @@ Péter Szilágyi <peterke@gmail.com>
|
||||
Peter Waldschmidt <peter@waldschmidt.com>
|
||||
Peter Waller <peter.waller@gmail.com>
|
||||
Peter Williams <pwil3058@gmail.com>
|
||||
Philip Børgesen <philip.borgesen@gmail.com>
|
||||
Philip Hofer <phofer@umich.edu>
|
||||
Philip K. Warren <pkwarren@gmail.com>
|
||||
Pierre Durand <pierredurand@gmail.com>
|
||||
@ -599,6 +614,7 @@ Pieter Droogendijk <pieter@binky.org.uk>
|
||||
Pietro Gagliardi <pietro10@mac.com>
|
||||
Prashant Varanasi <prashant@prashantv.com>
|
||||
Preetam Jinka <pj@preet.am>
|
||||
Quan Tran <qeed.quan@gmail.com>
|
||||
Quan Yong Zhai <qyzhai@gmail.com>
|
||||
Quentin Perez <qperez@ocs.online.net>
|
||||
Quoc-Viet Nguyen <afelion@gmail.com>
|
||||
@ -644,6 +660,7 @@ Salmān Aljammāz <s@0x65.net>
|
||||
Sam Hug <samuel.b.hug@gmail.com>
|
||||
Sam Whited <sam@samwhited.com>
|
||||
Sanjay Menakuru <balasanjay@gmail.com>
|
||||
Sasha Sobol <sasha@scaledinference.com>
|
||||
Scott Barron <scott.barron@github.com>
|
||||
Scott Bell <scott@sctsm.com>
|
||||
Scott Ferguson <scottwferg@gmail.com>
|
||||
@ -654,6 +671,7 @@ Sergei Skorobogatov <skorobo@rambler.ru>
|
||||
Sergey 'SnakE' Gromov <snake.scaly@gmail.com>
|
||||
Sergio Luis O. B. Correia <sergio@correia.cc>
|
||||
Seth Hoenig <seth.a.hoenig@gmail.com>
|
||||
Seth Vargo <sethvargo@gmail.com>
|
||||
Shahar Kohanim <skohanim@gmail.com>
|
||||
Shane Hansen <shanemhansen@gmail.com>
|
||||
Shaozhen Ding <dsz0111@gmail.com>
|
||||
@ -663,6 +681,7 @@ Shinji Tanaka <shinji.tanaka@gmail.com>
|
||||
Shivakumar GN <shivakumar.gn@gmail.com>
|
||||
Silvan Jegen <s.jegen@gmail.com>
|
||||
Simon Jefford <simon.jefford@gmail.com>
|
||||
Simon Thulbourn <simon+github@thulbourn.com>
|
||||
Simon Whitehead <chemnova@gmail.com>
|
||||
Sokolov Yura <funny.falcon@gmail.com>
|
||||
Spencer Nelson <s@spenczar.com>
|
||||
@ -734,6 +753,7 @@ Wei Guangjing <vcc.163@gmail.com>
|
||||
Willem van der Schyff <willemvds@gmail.com>
|
||||
William Josephson <wjosephson@gmail.com>
|
||||
William Orr <will@worrbase.com> <ay1244@gmail.com>
|
||||
Wisdom Omuya <deafgoat@gmail.com>
|
||||
Xia Bin <snyh@snyh.org>
|
||||
Xing Xing <mikespook@gmail.com>
|
||||
Xudong Zhang <felixmelon@gmail.com>
|
||||
|
28
CONTRIBUTORS
28
CONTRIBUTORS
@ -37,6 +37,7 @@ Aaron France <aaron.l.france@gmail.com>
|
||||
Aaron Jacobs <jacobsa@google.com>
|
||||
Aaron Kemp <kemp.aaron@gmail.com>
|
||||
Aaron Torres <tcboox@gmail.com>
|
||||
Aaron Zinman <aaron@azinman.com>
|
||||
Abe Haskins <abeisgreat@abeisgreat.com>
|
||||
Abhinav Gupta <abhinav.g90@gmail.com>
|
||||
Adam Langley <agl@golang.org>
|
||||
@ -141,6 +142,7 @@ Augusto Roman <aroman@gmail.com>
|
||||
Aulus Egnatius Varialus <varialus@gmail.com>
|
||||
Austin Clements <austin@google.com> <aclements@csail.mit.edu>
|
||||
awaw fumin <awawfumin@gmail.com>
|
||||
Ayanamist Yang <ayanamist@gmail.com>
|
||||
Aymerick Jéhanne <aymerick@jehanne.org>
|
||||
Balazs Lecz <leczb@google.com>
|
||||
Ben Burkert <ben@benburkert.com>
|
||||
@ -155,6 +157,7 @@ Benny Siegert <bsiegert@gmail.com>
|
||||
Benoit Sigoure <tsunanet@gmail.com>
|
||||
Berengar Lehr <Berengar.Lehr@gmx.de>
|
||||
Bill Neubauer <wcn@golang.org> <wcn@google.com> <bill.neubauer@gmail.com>
|
||||
Bill O'Farrell <billo@ca.ibm.com>
|
||||
Bill Thiede <couchmoney@gmail.com>
|
||||
Billie Harold Cleek <bhcleek@gmail.com>
|
||||
Bjorn Tillenius <bjorn@tillenius.me>
|
||||
@ -212,6 +215,7 @@ Chris Lennert <calennert@gmail.com>
|
||||
Chris Manghane <cmang@golang.org>
|
||||
Chris McGee <sirnewton_01@yahoo.ca> <newton688@gmail.com>
|
||||
Chris Zou <chriszou@ca.ibm.com>
|
||||
Christian Couder <chriscool@tuxfamily.org>
|
||||
Christian Himpel <chressie@googlemail.com> <chressie@gmail.com>
|
||||
Christine Hansmann <chhansmann@gmail.com>
|
||||
Christoffer Buchholz <christoffer.buchholz@gmail.com>
|
||||
@ -330,6 +334,7 @@ Emil Hessman <c.emil.hessman@gmail.com> <emil@hessman.se>
|
||||
Emmanuel Odeke <emm.odeke@gmail.com> <odeke@ualberta.ca>
|
||||
Eoghan Sherry <ejsherry@gmail.com>
|
||||
Eric Clark <zerohp@gmail.com>
|
||||
Eric Engestrom <eric@engestrom.ch>
|
||||
Eric Garrido <ekg@google.com>
|
||||
Eric Koleda <ekoleda+devrel@google.com>
|
||||
Eric Lagergren <ericscottlagergren@gmail.com>
|
||||
@ -356,6 +361,7 @@ Fatih Arslan <fatih@arslan.io>
|
||||
Fazlul Shahriar <fshahriar@gmail.com>
|
||||
Federico Simoncelli <fsimonce@redhat.com>
|
||||
Felix Geisendörfer <haimuiba@gmail.com>
|
||||
Filippo Valsorda <hi@filippo.io>
|
||||
Firmansyah Adiputra <frm.adiputra@gmail.com>
|
||||
Florian Uekermann <florian@uekermann-online.de> <f1@uekermann-online.de>
|
||||
Florian Weimer <fw@deneb.enyo.de>
|
||||
@ -397,6 +403,8 @@ Gustav Paul <gustav.paul@gmail.com>
|
||||
Gustavo Franco <gustavorfranco@gmail.com>
|
||||
Gustavo Niemeyer <gustavo@niemeyer.net> <n13m3y3r@gmail.com>
|
||||
Gwenael Treguier <gwenn.kahz@gmail.com>
|
||||
Gyu-Ho Lee <gyuhox@gmail.com>
|
||||
H. İbrahim Güngör <igungor@gmail.com>
|
||||
Hajime Hoshi <hajimehoshi@gmail.com>
|
||||
Hallgrimur Gunnarsson <halg@google.com>
|
||||
Han-Wen Nienhuys <hanwen@google.com>
|
||||
@ -435,6 +443,7 @@ Ivan Ukhov <ivan.ukhov@gmail.com>
|
||||
Jaana Burcu Dogan <jbd@google.com> <jbd@golang.org> <burcujdogan@gmail.com>
|
||||
Jacob Baskin <jbaskin@google.com>
|
||||
Jacob H. Haven <jacob@cloudflare.com>
|
||||
Jacob Hoffman-Andrews <github@hoffman-andrews.com>
|
||||
Jae Kwon <jae@tendermint.com>
|
||||
Jakob Borg <jakob@nym.se>
|
||||
Jakub Čajka <jcajka@redhat.com>
|
||||
@ -465,6 +474,7 @@ Jan Newmarch <jan.newmarch@gmail.com>
|
||||
Jan Ziak <0xe2.0x9a.0x9b@gmail.com>
|
||||
Jani Monoses <jani.monoses@ubuntu.com> <jani.monoses@gmail.com>
|
||||
Jaroslavas Počepko <jp@webmaster.ms>
|
||||
Jason Barnett <jason.w.barnett@gmail.com>
|
||||
Jason Del Ponte <delpontej@gmail.com>
|
||||
Jason Hall <jasonhall@google.com>
|
||||
Jason Travis <infomaniac7@gmail.com>
|
||||
@ -489,6 +499,7 @@ Jingcheng Zhang <diogin@gmail.com>
|
||||
Jingguo Yao <yaojingguo@gmail.com>
|
||||
Jiong Du <londevil@gmail.com>
|
||||
Joakim Sernbrant <serbaut@gmail.com>
|
||||
Joe Farrell <joe2farrell@gmail.com>
|
||||
Joe Harrison <joehazzers@gmail.com>
|
||||
Joe Henke <joed.henke@gmail.com>
|
||||
Joe Poirier <jdpoirier@gmail.com>
|
||||
@ -539,6 +550,7 @@ JP Sugarbroad <jpsugar@google.com>
|
||||
JT Olds <jtolds@xnet5.com>
|
||||
Jukka-Pekka Kekkonen <karatepekka@gmail.com>
|
||||
Julia Hansbrough <flowerhack@google.com>
|
||||
Julian Kornberger <jk+github@digineo.de>
|
||||
Julian Phillips <julian@quantumfyre.co.uk>
|
||||
Julien Schmidt <google@julienschmidt.com>
|
||||
Jungho Ahn <jhahn@google.com>
|
||||
@ -548,6 +560,7 @@ Kai Backman <kaib@golang.org>
|
||||
Kamal Aboul-Hosn <aboulhosn@google.com>
|
||||
Kamil Kisiel <kamil@kamilkisiel.net> <kamil.kisiel@gmail.com>
|
||||
Kang Hu <hukangustc@gmail.com>
|
||||
Karan Dhiman <karandhi@ca.ibm.com>
|
||||
Kato Kazuyoshi <kato.kazuyoshi@gmail.com>
|
||||
Katrina Owen <katrina.owen@gmail.com>
|
||||
Kay Zhu <kayzhu@google.com>
|
||||
@ -575,6 +588,7 @@ Kim Shrier <kshrier@racktopsystems.com>
|
||||
Kirklin McDonald <kirklin.mcdonald@gmail.com>
|
||||
Klaus Post <klauspost@gmail.com>
|
||||
Konstantin Shaposhnikov <k.shaposhnikov@gmail.com>
|
||||
Kris Rousey <krousey@google.com>
|
||||
Kristopher Watts <traetox@gmail.com>
|
||||
Kun Li <likunarmstrong@gmail.com>
|
||||
Kyle Consalus <consalus@gmail.com>
|
||||
@ -686,6 +700,7 @@ Michał Derkacz <ziutek@lnet.pl>
|
||||
Michalis Kargakis <michaliskargakis@gmail.com>
|
||||
Michel Lespinasse <walken@google.com>
|
||||
Miek Gieben <miek@miek.nl> <remigius.gieben@gmail.com>
|
||||
Miguel Mendez <stxmendez@gmail.com>
|
||||
Mihai Borobocea <MihaiBorobocea@gmail.com>
|
||||
Mikael Tillenius <mikti42@gmail.com>
|
||||
Mike Andrews <mra@xoba.com>
|
||||
@ -716,6 +731,7 @@ Nathan(yinian) Hu <nathanhu@google.com>
|
||||
Neelesh Chandola <neelesh.c98@gmail.com>
|
||||
Nevins Bartolomeo <nevins.bartolomeo@gmail.com>
|
||||
Niall Sheridan <nsheridan@gmail.com>
|
||||
Nic Day <nic.day@me.com>
|
||||
Nicholas Katsaros <nick@nickkatsaros.com>
|
||||
Nicholas Presta <nick@nickpresta.ca> <nick1presta@gmail.com>
|
||||
Nicholas Sullivan <nicholas.sullivan@gmail.com>
|
||||
@ -769,6 +785,7 @@ Paul Sbarra <Sbarra.Paul@gmail.com>
|
||||
Paul Smith <paulsmith@pobox.com> <paulsmith@gmail.com>
|
||||
Paul van Brouwershaven <paul@vanbrouwershaven.com>
|
||||
Paul Wankadia <junyer@google.com>
|
||||
Paulo Casaretto <pcasaretto@gmail.com>
|
||||
Pavel Paulau <pavel.paulau@gmail.com>
|
||||
Pavel Zinovkin <pavel.zinovkin@gmail.com>
|
||||
Pawel Knap <pawelknap88@gmail.com>
|
||||
@ -793,6 +810,7 @@ Peter Waller <peter.waller@gmail.com>
|
||||
Peter Weinberger <pjw@golang.org>
|
||||
Peter Williams <pwil3058@gmail.com>
|
||||
Phil Pennock <pdp@golang.org>
|
||||
Philip Børgesen <philip.borgesen@gmail.com>
|
||||
Philip Hofer <phofer@umich.edu>
|
||||
Philip K. Warren <pkwarren@gmail.com>
|
||||
Pierre Durand <pierredurand@gmail.com>
|
||||
@ -801,6 +819,7 @@ Pieter Droogendijk <pieter@binky.org.uk>
|
||||
Pietro Gagliardi <pietro10@mac.com>
|
||||
Prashant Varanasi <prashant@prashantv.com>
|
||||
Preetam Jinka <pj@preet.am>
|
||||
Quan Tran <qeed.quan@gmail.com>
|
||||
Quan Yong Zhai <qyzhai@gmail.com>
|
||||
Quentin Perez <qperez@ocs.online.net>
|
||||
Quentin Smith <quentin@golang.org>
|
||||
@ -857,7 +876,9 @@ Ryan Lower <rpjlower@gmail.com>
|
||||
Ryan Seys <ryan@ryanseys.com>
|
||||
Ryan Slade <ryanslade@gmail.com>
|
||||
S.Çağlar Onur <caglar@10ur.org>
|
||||
Sai Cheemalapati <saicheems@google.com>
|
||||
Salmān Aljammāz <s@0x65.net>
|
||||
Sam Ding <samding@ca.ibm.com>
|
||||
Sam Hug <samuel.b.hug@gmail.com>
|
||||
Sam Thorogood <thorogood@google.com> <sam.thorogood@gmail.com>
|
||||
Sam Whited <sam@samwhited.com>
|
||||
@ -865,6 +886,7 @@ Sameer Ajmani <sameer@golang.org> <ajmani@gmail.com>
|
||||
Sami Commerot <samic@google.com>
|
||||
Sanjay Menakuru <balasanjay@gmail.com>
|
||||
Sasha Lionheart <lionhearts@google.com>
|
||||
Sasha Sobol <sasha@scaledinference.com>
|
||||
Scott Barron <scott.barron@github.com>
|
||||
Scott Bell <scott@sctsm.com>
|
||||
Scott Ferguson <scottwferg@gmail.com>
|
||||
@ -882,6 +904,7 @@ Sergey 'SnakE' Gromov <snake.scaly@gmail.com>
|
||||
Sergey Arseev <sergey.arseev@intel.com>
|
||||
Sergio Luis O. B. Correia <sergio@correia.cc>
|
||||
Seth Hoenig <seth.a.hoenig@gmail.com>
|
||||
Seth Vargo <sethvargo@gmail.com>
|
||||
Shahar Kohanim <skohanim@gmail.com>
|
||||
Shane Hansen <shanemhansen@gmail.com>
|
||||
Shaozhen Ding <dsz0111@gmail.com>
|
||||
@ -894,6 +917,7 @@ Shivakumar GN <shivakumar.gn@gmail.com>
|
||||
Shun Fan <sfan@google.com>
|
||||
Silvan Jegen <s.jegen@gmail.com>
|
||||
Simon Jefford <simon.jefford@gmail.com>
|
||||
Simon Thulbourn <simon+github@thulbourn.com>
|
||||
Simon Whitehead <chemnova@gmail.com>
|
||||
Sokolov Yura <funny.falcon@gmail.com>
|
||||
Spencer Nelson <s@spenczar.com>
|
||||
@ -957,6 +981,7 @@ Totoro W <tw19881113@gmail.com>
|
||||
Travis Cline <travis.cline@gmail.com>
|
||||
Trevor Strohman <trevor.strohman@gmail.com>
|
||||
Trey Tacon <ttacon@gmail.com>
|
||||
Tristan Amini <tamini01@ca.ibm.com>
|
||||
Tudor Golubenco <tudor.g@gmail.com>
|
||||
Tyler Bunnell <tylerbunnell@gmail.com>
|
||||
Tyler Treat <ttreat31@gmail.com>
|
||||
@ -986,6 +1011,7 @@ Willem van der Schyff <willemvds@gmail.com>
|
||||
William Chan <willchan@chromium.org>
|
||||
William Josephson <wjosephson@gmail.com>
|
||||
William Orr <will@worrbase.com> <ay1244@gmail.com>
|
||||
Wisdom Omuya <deafgoat@gmail.com>
|
||||
Xia Bin <snyh@snyh.org>
|
||||
Xing Xing <mikespook@gmail.com>
|
||||
Xudong Zhang <felixmelon@gmail.com>
|
||||
@ -999,6 +1025,8 @@ Yissakhar Z. Beck <yissakhar.beck@gmail.com>
|
||||
Yo-An Lin <yoanlin93@gmail.com>
|
||||
Yongjian Xu <i3dmaster@gmail.com>
|
||||
Yoshiyuki Kanno <nekotaroh@gmail.com> <yoshiyuki.kanno@stoic.co.jp>
|
||||
Yu Heng Zhang <annita.zhang@cn.ibm.com>
|
||||
Yu Xuan Zhang <zyxsh@cn.ibm.com>
|
||||
Yuki Yugui Sonoda <yugui@google.com>
|
||||
Yusuke Kagiwada <block.rxckin.beats@gmail.com>
|
||||
Yuusei Kuwana <kuwana@kumama.org>
|
||||
|
@ -329,3 +329,4 @@ pkg syscall (netbsd-arm-cgo), const SizeofIfData = 132
|
||||
pkg syscall (netbsd-arm-cgo), type IfMsghdr struct, Pad_cgo_1 [4]uint8
|
||||
pkg unicode, const Version = "6.3.0"
|
||||
pkg unicode, const Version = "7.0.0"
|
||||
pkg unicode, const Version = "8.0.0"
|
||||
|
@ -274,3 +274,12 @@ pkg syscall (linux-arm-cgo), type SysProcAttr struct, Unshareflags uintptr
|
||||
pkg testing, method (*B) Run(string, func(*B)) bool
|
||||
pkg testing, method (*T) Run(string, func(*T)) bool
|
||||
pkg testing, type InternalExample struct, Unordered bool
|
||||
pkg unicode, const Version = "9.0.0"
|
||||
pkg unicode, var Adlam *RangeTable
|
||||
pkg unicode, var Bhaiksuki *RangeTable
|
||||
pkg unicode, var Marchen *RangeTable
|
||||
pkg unicode, var Newa *RangeTable
|
||||
pkg unicode, var Osage *RangeTable
|
||||
pkg unicode, var Prepended_Concatenation_Mark *RangeTable
|
||||
pkg unicode, var Sentence_Terminal *RangeTable
|
||||
pkg unicode, var Tangut *RangeTable
|
||||
|
@ -2238,13 +2238,12 @@ if str, ok := value.(string); ok {
|
||||
|
||||
<h3 id="generality">Generality</h3>
|
||||
<p>
|
||||
If a type exists only to implement an interface
|
||||
and has no exported methods beyond that interface,
|
||||
there is no need to export the type itself.
|
||||
Exporting just the interface makes it clear that
|
||||
it's the behavior that matters, not the implementation,
|
||||
and that other implementations with different properties
|
||||
can mirror the behavior of the original type.
|
||||
If a type exists only to implement an interface and will
|
||||
never have exported methods beyond that interface, there is
|
||||
no need to export the type itself.
|
||||
Exporting just the interface makes it clear the value has no
|
||||
interesting behavior beyond what is described in the
|
||||
interface.
|
||||
It also avoids the need to repeat the documentation
|
||||
on every instance of a common method.
|
||||
</p>
|
||||
@ -3665,4 +3664,3 @@ var _ image.Color = Black
|
||||
var _ image.Image = Black
|
||||
</pre>
|
||||
-->
|
||||
|
||||
|
@ -288,6 +288,18 @@ To avoid confusion with the new <code>-tests</code> check, the old, unadvertised
|
||||
<code>-test</code> option has been removed; it was equivalent to <code>-all</code> <code>-shadow</code>.
|
||||
</p>
|
||||
|
||||
<p id="vet_lostcancel">
|
||||
The <code>vet</code> command also has a new check,
|
||||
<code>-lostcancel</code>, which detects failure to call the
|
||||
cancelation function returned by the <code>WithCancel</code>,
|
||||
<code>WithTimeout</code>, and <code>WithDeadline</code> functions in
|
||||
Go 1.7's new <code>context</code> package (see <a
|
||||
href='#context'>below</a>).
|
||||
Failure to call the function prevents the new <code>Context</code>
|
||||
from being reclaimed until its parent is cancelled.
|
||||
(The background context is never cancelled.)
|
||||
</p>
|
||||
|
||||
<h3 id="cmd_dist">Go tool dist</h3>
|
||||
|
||||
<p>
|
||||
@ -770,6 +782,30 @@ package.
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl id="math_rand"><dt><a href="/pkg/math/rand/">math/rand</a></dt>
|
||||
|
||||
<dd>
|
||||
<p>
|
||||
The
|
||||
<a href="/pkg/math/rand/#Read"><code>Read</code></a> function and
|
||||
<a href="/pkg/math/rand/#Rand"><code>Rand</code></a>'s
|
||||
<a href="/pkg/math/rand/#Rand.Read"><code>Read</code></a> method
|
||||
now produce a pseudo-random stream of bytes that is consistent and not
|
||||
dependent on the size of the input buffer.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The documentation clarifies that
|
||||
Rand's <a href="/pkg/math/rand/#Rand.Seed"><code>Seed</code></a>
|
||||
and <a href="/pkg/math/rand/#Rand.Read"><code>Read</code></a> methods
|
||||
are not safe to call concurrently, though the global
|
||||
functions <a href="/pkg/math/rand/#Seed"><code>Seed</code></a>
|
||||
and <a href="/pkg/math/rand/#Read"><code>Read</code></a> are (and have
|
||||
always been) safe.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<dl id="mime_multipart"><dt><a href="/pkg/mime/multipart/">mime/multipart</a></dt>
|
||||
|
||||
<dd>
|
||||
@ -855,6 +891,23 @@ so that <code>w.WriteHeader(5)</code> uses the HTTP response
|
||||
status <code>005</code>, not just <code>5</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The server implementation now correctly sends only one "Transfer-Encoding" header when "chunked"
|
||||
is set explicitly, following <a href="https://tools.ietf.org/html/rfc7230#section-3.3.1">RFC 7230</a>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The server implementation is now stricter about rejecting requests with invalid HTTP versions.
|
||||
Invalid requests claiming to be HTTP/0.x are now rejected (HTTP/0.9 was never fully supported),
|
||||
and plaintext HTTP/2 requests other than the "PRI * HTTP/2.0" upgrade request are now rejected as well.
|
||||
The server continues to handle encrypted HTTP/2 requests.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In the server, a 200 status code is sent back by the timeout handler on an empty
|
||||
response body, instead of sending back 0 as the status code.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
In the client, the
|
||||
<a href="/pkg/net/http/#Transport"><code>Transport</code></a> implementation passes the request context
|
||||
@ -1026,7 +1079,7 @@ from URLs with empty query strings (like <code>/search?</code>).
|
||||
|
||||
<dd>
|
||||
<p>
|
||||
<a href="/pkg/os/#IsExists"><code>IsExists</code></a> now returns true for <code>syscall.ENOTEMPTY</code>,
|
||||
<a href="/pkg/os/#IsExist"><code>IsExist</code></a> now returns true for <code>syscall.ENOTEMPTY</code>,
|
||||
on systems where that error exists.
|
||||
</p>
|
||||
|
||||
@ -1186,3 +1239,15 @@ system call before executing the new program.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
|
||||
<dl id="unicode"><dt><a href="/pkg/unicode/">unicode</a></dt>
|
||||
|
||||
<dd>
|
||||
<p>
|
||||
The <a href="/pkg/unicode/"><code>unicode</code></a> package and associated
|
||||
support throughout the system has been upgraded from version 8.0 to
|
||||
<a href="http://www.unicode.org/versions/Unicode9.0.0/">Unicode 9.0</a>.
|
||||
</p>
|
||||
</dd>
|
||||
</dl>
|
||||
|
@ -33,7 +33,7 @@ compiler using the GCC back end, see
|
||||
</p>
|
||||
|
||||
<p>
|
||||
The Go compilers support six instruction sets.
|
||||
The Go compilers support seven instruction sets.
|
||||
There are important differences in the quality of the compilers for the different
|
||||
architectures.
|
||||
</p>
|
||||
@ -43,15 +43,17 @@ architectures.
|
||||
<code>amd64</code> (also known as <code>x86-64</code>)
|
||||
</dt>
|
||||
<dd>
|
||||
A mature implementation. The compiler has an effective
|
||||
optimizer (registerizer) and generates good code (although
|
||||
<code>gccgo</code> can do noticeably better sometimes).
|
||||
A mature implementation. New in 1.7 is its SSA-based back end
|
||||
that generates compact, efficient code.
|
||||
</dd>
|
||||
<dt>
|
||||
<code>386</code> (<code>x86</code> or <code>x86-32</code>)
|
||||
</dt>
|
||||
<dd>
|
||||
Comparable to the <code>amd64</code> port.
|
||||
Comparable to the <code>amd64</code> port, but does
|
||||
not yet use the SSA-based back end. It has an effective
|
||||
optimizer (registerizer) and generates good code (although
|
||||
<code>gccgo</code> can do noticeably better sometimes).
|
||||
</dd>
|
||||
<dt>
|
||||
<code>arm</code> (<code>ARM</code>)
|
||||
@ -77,6 +79,12 @@ architectures.
|
||||
<dd>
|
||||
Supports Linux binaries. New in 1.6 and not as well exercised as other ports.
|
||||
</dd>
|
||||
<dt>
|
||||
<code>s390x</code> (IBM System z)
|
||||
</dt>
|
||||
<dd>
|
||||
Supports Linux binaries. New in 1.7 and not as well exercised as other ports.
|
||||
</dd>
|
||||
</dl>
|
||||
|
||||
<p>
|
||||
|
@ -1,4 +1,4 @@
|
||||
#!/bin/sh
|
||||
#!/bin/bash
|
||||
# Copyright 2012 The Go Authors. All rights reserved.
|
||||
# Use of this source code is governed by a BSD-style
|
||||
# license that can be found in the LICENSE file.
|
||||
@ -8,8 +8,8 @@
|
||||
# Consult http://www.iana.org/time-zones for the latest versions.
|
||||
|
||||
# Versions to use.
|
||||
CODE=2016d
|
||||
DATA=2016d
|
||||
CODE=2016f
|
||||
DATA=2016f
|
||||
|
||||
set -e
|
||||
rm -rf work
|
||||
|
Binary file not shown.
12
misc/cgo/errors/issue16116.go
Normal file
12
misc/cgo/errors/issue16116.go
Normal file
@ -0,0 +1,12 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
// void f(void *p, int x) {}
|
||||
import "C"
|
||||
|
||||
func main() {
|
||||
_ = C.f(1) // ERROR HERE
|
||||
}
|
@ -45,6 +45,7 @@ expect issue13129.go C.ushort
|
||||
check issue13423.go
|
||||
expect issue13635.go C.uchar C.schar C.ushort C.uint C.ulong C.longlong C.ulonglong C.complexfloat C.complexdouble
|
||||
check issue13830.go
|
||||
check issue16116.go
|
||||
|
||||
if ! go build issue14669.go; then
|
||||
exit 1
|
||||
|
@ -597,13 +597,15 @@ func (p *Package) rewriteCalls(f *File) {
|
||||
// rewriteCall rewrites one call to add pointer checks. We replace
|
||||
// each pointer argument x with _cgoCheckPointer(x).(T).
|
||||
func (p *Package) rewriteCall(f *File, call *Call, name *Name) {
|
||||
// Avoid a crash if the number of arguments is
|
||||
// less than the number of parameters.
|
||||
// This will be caught when the generated file is compiled.
|
||||
if len(call.Call.Args) < len(name.FuncType.Params) {
|
||||
return
|
||||
}
|
||||
|
||||
any := false
|
||||
for i, param := range name.FuncType.Params {
|
||||
if len(call.Call.Args) <= i {
|
||||
// Avoid a crash; this will be caught when the
|
||||
// generated file is compiled.
|
||||
return
|
||||
}
|
||||
if p.needsPointerCheck(f, param.Go, call.Call.Args[i]) {
|
||||
any = true
|
||||
break
|
||||
|
@ -122,3 +122,38 @@ NextVar:
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// TestLineNumber checks to make sure the generated assembly has line numbers
|
||||
// see issue #16214
|
||||
func TestLineNumber(t *testing.T) {
|
||||
testenv.MustHaveGoBuild(t)
|
||||
dir, err := ioutil.TempDir("", "TestLineNumber")
|
||||
if err != nil {
|
||||
t.Fatalf("could not create directory: %v", err)
|
||||
}
|
||||
defer os.RemoveAll(dir)
|
||||
|
||||
src := filepath.Join(dir, "x.go")
|
||||
err = ioutil.WriteFile(src, []byte(issue16214src), 0644)
|
||||
if err != nil {
|
||||
t.Fatalf("could not write file: %v", err)
|
||||
}
|
||||
|
||||
cmd := exec.Command("go", "tool", "compile", "-S", "-o", filepath.Join(dir, "out.o"), src)
|
||||
out, err := cmd.CombinedOutput()
|
||||
if err != nil {
|
||||
t.Fatalf("fail to run go tool compile: %v", err)
|
||||
}
|
||||
|
||||
if strings.Contains(string(out), "unknown line number") {
|
||||
t.Errorf("line number missing in assembly:\n%s", out)
|
||||
}
|
||||
}
|
||||
|
||||
var issue16214src = `
|
||||
package main
|
||||
|
||||
func Mod32(x uint32) uint32 {
|
||||
return x % 3 // frontend rewrites it as HMUL with 2863311531, the LITERAL node has Lineno 0
|
||||
}
|
||||
`
|
||||
|
@ -153,7 +153,13 @@ const debugFormat = false // default: false
|
||||
// TODO(gri) disable and remove once there is only one export format again
|
||||
const forceObjFileStability = true
|
||||
|
||||
const exportVersion = "v0"
|
||||
// Supported export format versions.
|
||||
// TODO(gri) Make this more systematic (issue #16244).
|
||||
const (
|
||||
exportVersion0 = "v0"
|
||||
exportVersion1 = "v1"
|
||||
exportVersion = exportVersion1
|
||||
)
|
||||
|
||||
// exportInlined enables the export of inlined function bodies and related
|
||||
// dependencies. The compiler should work w/o any loss of functionality with
|
||||
@ -727,6 +733,14 @@ func (p *exporter) typ(t *Type) {
|
||||
p.paramList(sig.Params(), inlineable)
|
||||
p.paramList(sig.Results(), inlineable)
|
||||
|
||||
// for issue #16243
|
||||
// We make this conditional for 1.7 to avoid consistency problems
|
||||
// with installed packages compiled with an older version.
|
||||
// TODO(gri) Clean up after 1.7 is out (issue #16244)
|
||||
if exportVersion == exportVersion1 {
|
||||
p.bool(m.Nointerface)
|
||||
}
|
||||
|
||||
var f *Func
|
||||
if inlineable {
|
||||
f = mfn.Func
|
||||
|
@ -21,8 +21,9 @@ import (
|
||||
// changes to bimport.go and bexport.go.
|
||||
|
||||
type importer struct {
|
||||
in *bufio.Reader
|
||||
buf []byte // reused for reading strings
|
||||
in *bufio.Reader
|
||||
buf []byte // reused for reading strings
|
||||
version string
|
||||
|
||||
// object lists, in order of deserialization
|
||||
strList []string
|
||||
@ -67,8 +68,9 @@ func Import(in *bufio.Reader) {
|
||||
|
||||
// --- generic export data ---
|
||||
|
||||
if v := p.string(); v != exportVersion {
|
||||
Fatalf("importer: unknown export data version: %s", v)
|
||||
p.version = p.string()
|
||||
if p.version != exportVersion0 && p.version != exportVersion1 {
|
||||
Fatalf("importer: unknown export data version: %s", p.version)
|
||||
}
|
||||
|
||||
// populate typList with predeclared "known" types
|
||||
@ -239,14 +241,20 @@ func (p *importer) pkg() *Pkg {
|
||||
Fatalf("importer: package path %q for pkg index %d", path, len(p.pkgList))
|
||||
}
|
||||
|
||||
// see importimport (export.go)
|
||||
pkg := importpkg
|
||||
if path != "" {
|
||||
pkg = mkpkg(path)
|
||||
}
|
||||
if pkg.Name == "" {
|
||||
pkg.Name = name
|
||||
numImport[name]++
|
||||
} else if pkg.Name != name {
|
||||
Fatalf("importer: conflicting package names %s and %s for path %q", pkg.Name, name, path)
|
||||
Yyerror("importer: conflicting package names %s and %s for path %q", pkg.Name, name, path)
|
||||
}
|
||||
if incannedimport == 0 && myimportpath != "" && path == myimportpath {
|
||||
Yyerror("import %q: package depends on %q (import cycle)", importpkg.Path, path)
|
||||
errorexit()
|
||||
}
|
||||
p.pkgList = append(p.pkgList, pkg)
|
||||
|
||||
@ -426,10 +434,15 @@ func (p *importer) typ() *Type {
|
||||
params := p.paramList()
|
||||
result := p.paramList()
|
||||
|
||||
nointerface := false
|
||||
if p.version == exportVersion1 {
|
||||
nointerface = p.bool()
|
||||
}
|
||||
|
||||
n := methodname1(newname(sym), recv[0].Right)
|
||||
n.Type = functype(recv[0], params, result)
|
||||
checkwidth(n.Type)
|
||||
addmethod(sym, n.Type, tsym.Pkg, false, false)
|
||||
addmethod(sym, n.Type, tsym.Pkg, false, nointerface)
|
||||
p.funcList = append(p.funcList, n)
|
||||
importlist = append(importlist, n)
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
package gc
|
||||
|
||||
const runtimeimport = "" +
|
||||
"cn\x00\x03v0\x01\rruntime\x00\t\x11newobject\x00\x02\x17\"\vtyp·2\x00\x00" +
|
||||
"cn\x00\x03v1\x01\rruntime\x00\t\x11newobject\x00\x02\x17\"\vtyp·2\x00\x00" +
|
||||
"\x01\x17:\x00\t\x13panicindex\x00\x00\x00\t\x13panicslice\x00\x00\x00\t\x15pani" +
|
||||
"cdivide\x00\x00\x00\t\x15throwreturn\x00\x00\x00\t\x11throwinit\x00\x00\x00" +
|
||||
"\t\x11panicwrap\x00\x05 \x00 \x00 \x00\x00\t\rgopanic\x00\x01\x1b\x00\x00\x00\x00\t\x11go" +
|
||||
@ -105,6 +105,6 @@ const runtimeimport = "" +
|
||||
"\x01\x02\v\x00\x01\x00\n$$\n"
|
||||
|
||||
const unsafeimport = "" +
|
||||
"cn\x00\x03v0\x01\vunsafe\x00\x05\r\rPointer\x00\x16\x00\t\x0fOffsetof\x00\x01" +
|
||||
"cn\x00\x03v1\x01\vunsafe\x00\x05\r\rPointer\x00\x16\x00\t\x0fOffsetof\x00\x01" +
|
||||
":\x00\x01\x16\x00\t\vSizeof\x00\x01:\x00\x01\x16\x00\t\rAlignof\x00\x01:\x00\x01\x16\x00\v\b\x00\v" +
|
||||
"\x00\x01\x00\n$$\n"
|
||||
|
@ -166,7 +166,7 @@ func closurename(n *Node) *Sym {
|
||||
prefix := ""
|
||||
if n.Func.Outerfunc == nil {
|
||||
// Global closure.
|
||||
outer = "glob"
|
||||
outer = "glob."
|
||||
|
||||
prefix = "func"
|
||||
closurename_closgen++
|
||||
|
@ -1551,10 +1551,12 @@ func esccall(e *EscState, n *Node, up *Node) {
|
||||
}
|
||||
|
||||
var src *Node
|
||||
note := ""
|
||||
i := 0
|
||||
lls := ll.Slice()
|
||||
for t, it := IterFields(fntype.Params()); i < len(lls); i++ {
|
||||
src = lls[i]
|
||||
note = t.Note
|
||||
if t.Isddd && !n.Isddd {
|
||||
// Introduce ODDDARG node to represent ... allocation.
|
||||
src = Nod(ODDDARG, nil, nil)
|
||||
@ -1566,7 +1568,7 @@ func esccall(e *EscState, n *Node, up *Node) {
|
||||
}
|
||||
|
||||
if haspointers(t.Type) {
|
||||
if escassignfromtag(e, t.Note, nE.Escretval, src) == EscNone && up.Op != ODEFER && up.Op != OPROC {
|
||||
if escassignfromtag(e, note, nE.Escretval, src) == EscNone && up.Op != ODEFER && up.Op != OPROC {
|
||||
a := src
|
||||
for a.Op == OCONVNOP {
|
||||
a = a.Left
|
||||
@ -1596,14 +1598,24 @@ func esccall(e *EscState, n *Node, up *Node) {
|
||||
// This occurs when function parameter type Isddd and n not Isddd
|
||||
break
|
||||
}
|
||||
|
||||
if note == uintptrEscapesTag {
|
||||
escassignSinkNilWhy(e, src, src, "escaping uintptr")
|
||||
}
|
||||
|
||||
t = it.Next()
|
||||
}
|
||||
|
||||
// Store arguments into slice for ... arg.
|
||||
for ; i < len(lls); i++ {
|
||||
if Debug['m'] > 3 {
|
||||
fmt.Printf("%v::esccall:: ... <- %v\n", linestr(lineno), Nconv(lls[i], FmtShort))
|
||||
}
|
||||
escassignNilWhy(e, src, lls[i], "arg to ...") // args to slice
|
||||
if note == uintptrEscapesTag {
|
||||
escassignSinkNilWhy(e, src, lls[i], "arg to uintptrescapes ...")
|
||||
} else {
|
||||
escassignNilWhy(e, src, lls[i], "arg to ...")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1963,9 +1975,20 @@ recurse:
|
||||
// lets us take the address below to get a *string.
|
||||
var unsafeUintptrTag = "unsafe-uintptr"
|
||||
|
||||
// This special tag is applied to uintptr parameters of functions
|
||||
// marked go:uintptrescapes.
|
||||
const uintptrEscapesTag = "uintptr-escapes"
|
||||
|
||||
func esctag(e *EscState, func_ *Node) {
|
||||
func_.Esc = EscFuncTagged
|
||||
|
||||
name := func(s *Sym, narg int) string {
|
||||
if s != nil {
|
||||
return s.Name
|
||||
}
|
||||
return fmt.Sprintf("arg#%d", narg)
|
||||
}
|
||||
|
||||
// External functions are assumed unsafe,
|
||||
// unless //go:noescape is given before the declaration.
|
||||
if func_.Nbody.Len() == 0 {
|
||||
@ -1988,13 +2011,7 @@ func esctag(e *EscState, func_ *Node) {
|
||||
narg++
|
||||
if t.Type.Etype == TUINTPTR {
|
||||
if Debug['m'] != 0 {
|
||||
var name string
|
||||
if t.Sym != nil {
|
||||
name = t.Sym.Name
|
||||
} else {
|
||||
name = fmt.Sprintf("arg#%d", narg)
|
||||
}
|
||||
Warnl(func_.Lineno, "%v assuming %v is unsafe uintptr", funcSym(func_), name)
|
||||
Warnl(func_.Lineno, "%v assuming %v is unsafe uintptr", funcSym(func_), name(t.Sym, narg))
|
||||
}
|
||||
t.Note = unsafeUintptrTag
|
||||
}
|
||||
@ -2003,6 +2020,27 @@ func esctag(e *EscState, func_ *Node) {
|
||||
return
|
||||
}
|
||||
|
||||
if func_.Func.Pragma&UintptrEscapes != 0 {
|
||||
narg := 0
|
||||
for _, t := range func_.Type.Params().Fields().Slice() {
|
||||
narg++
|
||||
if t.Type.Etype == TUINTPTR {
|
||||
if Debug['m'] != 0 {
|
||||
Warnl(func_.Lineno, "%v marking %v as escaping uintptr", funcSym(func_), name(t.Sym, narg))
|
||||
}
|
||||
t.Note = uintptrEscapesTag
|
||||
}
|
||||
|
||||
if t.Isddd && t.Type.Elem().Etype == TUINTPTR {
|
||||
// final argument is ...uintptr.
|
||||
if Debug['m'] != 0 {
|
||||
Warnl(func_.Lineno, "%v marking %v as escaping ...uintptr", funcSym(func_), name(t.Sym, narg))
|
||||
}
|
||||
t.Note = uintptrEscapesTag
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
savefn := Curfn
|
||||
Curfn = func_
|
||||
|
||||
@ -2015,7 +2053,9 @@ func esctag(e *EscState, func_ *Node) {
|
||||
case EscNone, // not touched by escflood
|
||||
EscReturn:
|
||||
if haspointers(ln.Type) { // don't bother tagging for scalars
|
||||
ln.Name.Param.Field.Note = mktag(int(ln.Esc))
|
||||
if ln.Name.Param.Field.Note != uintptrEscapesTag {
|
||||
ln.Name.Param.Field.Note = mktag(int(ln.Esc))
|
||||
}
|
||||
}
|
||||
|
||||
case EscHeap, // touched by escflood, moved to heap
|
||||
|
@ -479,6 +479,10 @@ func pkgtype(s *Sym) *Type {
|
||||
return s.Def.Type
|
||||
}
|
||||
|
||||
// numImport tracks how often a package with a given name is imported.
|
||||
// It is used to provide a better error message (by using the package
|
||||
// path to disambiguate) if a package that appears multiple times with
|
||||
// the same name appears in an error message.
|
||||
var numImport = make(map[string]int)
|
||||
|
||||
func importimport(s *Sym, path string) {
|
||||
|
@ -160,6 +160,14 @@ func moveToHeap(n *Node) {
|
||||
if n.Class == PPARAM {
|
||||
stackcopy.SetNotLiveAtEnd(true)
|
||||
}
|
||||
if n.Class == PPARAMOUT {
|
||||
// Make sure the pointer to the heap copy is kept live throughout the function.
|
||||
// The function could panic at any point, and then a defer could recover.
|
||||
// Thus, we need the pointer to the heap copy always available so the
|
||||
// post-deferreturn code can copy the return value back to the stack.
|
||||
// See issue 16095.
|
||||
heapaddr.setIsOutputParamHeapAddr(true)
|
||||
}
|
||||
n.Name.Param.Stackcopy = stackcopy
|
||||
|
||||
// Substitute the stackcopy into the function variable list so that
|
||||
|
@ -72,6 +72,7 @@ const (
|
||||
Nowritebarrier // emit compiler error instead of write barrier
|
||||
Nowritebarrierrec // error on write barrier in this or recursive callees
|
||||
CgoUnsafeArgs // treat a pointer to one arg as a pointer to them all
|
||||
UintptrEscapes // pointers converted to uintptr escape
|
||||
)
|
||||
|
||||
type lexer struct {
|
||||
@ -930,6 +931,19 @@ func (l *lexer) getlinepragma() rune {
|
||||
l.pragma |= Nowritebarrierrec | Nowritebarrier // implies Nowritebarrier
|
||||
case "go:cgo_unsafe_args":
|
||||
l.pragma |= CgoUnsafeArgs
|
||||
case "go:uintptrescapes":
|
||||
// For the next function declared in the file
|
||||
// any uintptr arguments may be pointer values
|
||||
// converted to uintptr. This directive
|
||||
// ensures that the referenced allocated
|
||||
// object, if any, is retained and not moved
|
||||
// until the call completes, even though from
|
||||
// the types alone it would appear that the
|
||||
// object is no longer needed during the
|
||||
// call. The conversion to uintptr must appear
|
||||
// in the argument list.
|
||||
// Used in syscall/dll_windows.go.
|
||||
l.pragma |= UintptrEscapes
|
||||
}
|
||||
return c
|
||||
}
|
||||
|
@ -373,7 +373,7 @@ func ordercall(n *Node, order *Order) {
|
||||
if t == nil {
|
||||
break
|
||||
}
|
||||
if t.Note == unsafeUintptrTag {
|
||||
if t.Note == unsafeUintptrTag || t.Note == uintptrEscapesTag {
|
||||
xp := n.List.Addr(i)
|
||||
for (*xp).Op == OCONVNOP && !(*xp).Type.IsPtr() {
|
||||
xp = &(*xp).Left
|
||||
@ -385,7 +385,11 @@ func ordercall(n *Node, order *Order) {
|
||||
*xp = x
|
||||
}
|
||||
}
|
||||
t = it.Next()
|
||||
next := it.Next()
|
||||
if next == nil && t.Isddd && t.Note == uintptrEscapesTag {
|
||||
next = t
|
||||
}
|
||||
t = next
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2006,7 +2006,8 @@ func (p *parser) hidden_fndcl() *Node {
|
||||
ss.Type = functype(s2[0], s6, s8)
|
||||
|
||||
checkwidth(ss.Type)
|
||||
addmethod(s4, ss.Type, p.structpkg, false, false)
|
||||
addmethod(s4, ss.Type, p.structpkg, false, p.pragma&Nointerface != 0)
|
||||
p.pragma = 0
|
||||
funchdr(ss)
|
||||
|
||||
// inl.C's inlnode in on a dotmeth node expects to find the inlineable body as
|
||||
|
@ -1175,6 +1175,19 @@ func livenessepilogue(lv *Liveness) {
|
||||
all := bvalloc(nvars)
|
||||
ambig := bvalloc(localswords())
|
||||
|
||||
// Set ambig bit for the pointers to heap-allocated pparamout variables.
|
||||
// These are implicitly read by post-deferreturn code and thus must be
|
||||
// kept live throughout the function (if there is any defer that recovers).
|
||||
if hasdefer {
|
||||
for _, n := range lv.vars {
|
||||
if n.IsOutputParamHeapAddr() {
|
||||
n.Name.Needzero = true
|
||||
xoffset := n.Xoffset + stkptrsize
|
||||
onebitwalktype1(n.Type, &xoffset, ambig)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, bb := range lv.cfg {
|
||||
// Compute avarinitany and avarinitall for entry to block.
|
||||
// This duplicates information known during livenesssolve
|
||||
|
@ -75,7 +75,7 @@ func uncommonSize(t *Type) int { // Sizeof(runtime.uncommontype{})
|
||||
if t.Sym == nil && len(methods(t)) == 0 {
|
||||
return 0
|
||||
}
|
||||
return 4 + 2 + 2
|
||||
return 4 + 2 + 2 + 4 + 4
|
||||
}
|
||||
|
||||
func makefield(name string, t *Type) *Field {
|
||||
@ -604,17 +604,19 @@ func dextratype(s *Sym, ot int, t *Type, dataAdd int) int {
|
||||
|
||||
ot = dgopkgpathOffLSym(Linksym(s), ot, typePkg(t))
|
||||
|
||||
dataAdd += 4 + 2 + 2
|
||||
dataAdd += uncommonSize(t)
|
||||
mcount := len(m)
|
||||
if mcount != int(uint16(mcount)) {
|
||||
Fatalf("too many methods on %s: %d", t, mcount)
|
||||
}
|
||||
if dataAdd != int(uint16(dataAdd)) {
|
||||
if dataAdd != int(uint32(dataAdd)) {
|
||||
Fatalf("methods are too far away on %s: %d", t, dataAdd)
|
||||
}
|
||||
|
||||
ot = duint16(s, ot, uint16(mcount))
|
||||
ot = duint16(s, ot, uint16(dataAdd))
|
||||
ot = duint16(s, ot, 0)
|
||||
ot = duint32(s, ot, uint32(dataAdd))
|
||||
ot = duint32(s, ot, 0)
|
||||
return ot
|
||||
}
|
||||
|
||||
@ -797,6 +799,7 @@ func typeptrdata(t *Type) int64 {
|
||||
const (
|
||||
tflagUncommon = 1 << 0
|
||||
tflagExtraStar = 1 << 1
|
||||
tflagNamed = 1 << 2
|
||||
)
|
||||
|
||||
var dcommontype_algarray *Sym
|
||||
@ -818,14 +821,10 @@ func dcommontype(s *Sym, ot int, t *Type) int {
|
||||
algsym = dalgsym(t)
|
||||
}
|
||||
|
||||
var sptr *Sym
|
||||
tptr := Ptrto(t)
|
||||
if !t.IsPtr() && (t.Sym != nil || methods(tptr) != nil) {
|
||||
sptr := dtypesym(tptr)
|
||||
r := obj.Addrel(Linksym(s))
|
||||
r.Off = 0
|
||||
r.Siz = 0
|
||||
r.Sym = sptr.Lsym
|
||||
r.Type = obj.R_USETYPE
|
||||
sptr = dtypesym(tptr)
|
||||
}
|
||||
|
||||
gcsym, useGCProg, ptrdata := dgcsym(t)
|
||||
@ -843,7 +842,7 @@ func dcommontype(s *Sym, ot int, t *Type) int {
|
||||
// alg *typeAlg
|
||||
// gcdata *byte
|
||||
// str nameOff
|
||||
// _ int32
|
||||
// ptrToThis typeOff
|
||||
// }
|
||||
ot = duintptr(s, ot, uint64(t.Width))
|
||||
ot = duintptr(s, ot, uint64(ptrdata))
|
||||
@ -854,6 +853,9 @@ func dcommontype(s *Sym, ot int, t *Type) int {
|
||||
if uncommonSize(t) != 0 {
|
||||
tflag |= tflagUncommon
|
||||
}
|
||||
if t.Sym != nil && t.Sym.Name != "" {
|
||||
tflag |= tflagNamed
|
||||
}
|
||||
|
||||
exported := false
|
||||
p := Tconv(t, FmtLeft|FmtUnsigned)
|
||||
@ -907,8 +909,12 @@ func dcommontype(s *Sym, ot int, t *Type) int {
|
||||
ot = dsymptr(s, ot, gcsym, 0) // gcdata
|
||||
|
||||
nsym := dname(p, "", nil, exported)
|
||||
ot = dsymptrOffLSym(Linksym(s), ot, nsym, 0)
|
||||
ot = duint32(s, ot, 0)
|
||||
ot = dsymptrOffLSym(Linksym(s), ot, nsym, 0) // str
|
||||
if sptr == nil {
|
||||
ot = duint32(s, ot, 0)
|
||||
} else {
|
||||
ot = dsymptrOffLSym(Linksym(s), ot, Linksym(sptr), 0) // ptrToThis
|
||||
}
|
||||
|
||||
return ot
|
||||
}
|
||||
|
@ -389,6 +389,14 @@ func (s *state) endBlock() *ssa.Block {
|
||||
|
||||
// pushLine pushes a line number on the line number stack.
|
||||
func (s *state) pushLine(line int32) {
|
||||
if line == 0 {
|
||||
// the frontend may emit node with line number missing,
|
||||
// use the parent line number in this case.
|
||||
line = s.peekLine()
|
||||
if Debug['K'] != 0 {
|
||||
Warn("buildssa: line 0")
|
||||
}
|
||||
}
|
||||
s.line = append(s.line, line)
|
||||
}
|
||||
|
||||
@ -1752,7 +1760,7 @@ func (s *state) expr(n *Node) *ssa.Value {
|
||||
addop := ssa.OpAdd64F
|
||||
subop := ssa.OpSub64F
|
||||
pt := floatForComplex(n.Type) // Could be Float32 or Float64
|
||||
wt := Types[TFLOAT64] // Compute in Float64 to minimize cancellation error
|
||||
wt := Types[TFLOAT64] // Compute in Float64 to minimize cancelation error
|
||||
|
||||
areal := s.newValue1(ssa.OpComplexReal, pt, a)
|
||||
breal := s.newValue1(ssa.OpComplexReal, pt, b)
|
||||
@ -1790,7 +1798,7 @@ func (s *state) expr(n *Node) *ssa.Value {
|
||||
subop := ssa.OpSub64F
|
||||
divop := ssa.OpDiv64F
|
||||
pt := floatForComplex(n.Type) // Could be Float32 or Float64
|
||||
wt := Types[TFLOAT64] // Compute in Float64 to minimize cancellation error
|
||||
wt := Types[TFLOAT64] // Compute in Float64 to minimize cancelation error
|
||||
|
||||
areal := s.newValue1(ssa.OpComplexReal, pt, a)
|
||||
breal := s.newValue1(ssa.OpComplexReal, pt, b)
|
||||
|
@ -79,6 +79,7 @@ const (
|
||||
hasBreak = 1 << iota
|
||||
notLiveAtEnd
|
||||
isClosureVar
|
||||
isOutputParamHeapAddr
|
||||
)
|
||||
|
||||
func (n *Node) HasBreak() bool {
|
||||
@ -112,6 +113,17 @@ func (n *Node) setIsClosureVar(b bool) {
|
||||
}
|
||||
}
|
||||
|
||||
func (n *Node) IsOutputParamHeapAddr() bool {
|
||||
return n.flags&isOutputParamHeapAddr != 0
|
||||
}
|
||||
func (n *Node) setIsOutputParamHeapAddr(b bool) {
|
||||
if b {
|
||||
n.flags |= isOutputParamHeapAddr
|
||||
} else {
|
||||
n.flags &^= isOutputParamHeapAddr
|
||||
}
|
||||
}
|
||||
|
||||
// Val returns the Val for the node.
|
||||
func (n *Node) Val() Val {
|
||||
if n.hasVal != +1 {
|
||||
|
@ -441,9 +441,8 @@ func gmove(f *gc.Node, t *gc.Node) {
|
||||
gc.Regfree(&r3)
|
||||
return
|
||||
|
||||
//warn("gmove: convert int to float not implemented: %N -> %N\n", f, t);
|
||||
/*
|
||||
* signed integer to float
|
||||
* integer to float
|
||||
*/
|
||||
case gc.TINT32<<16 | gc.TFLOAT32,
|
||||
gc.TINT32<<16 | gc.TFLOAT64,
|
||||
@ -452,10 +451,42 @@ func gmove(f *gc.Node, t *gc.Node) {
|
||||
gc.TINT16<<16 | gc.TFLOAT32,
|
||||
gc.TINT16<<16 | gc.TFLOAT64,
|
||||
gc.TINT8<<16 | gc.TFLOAT32,
|
||||
gc.TINT8<<16 | gc.TFLOAT64:
|
||||
gc.TINT8<<16 | gc.TFLOAT64,
|
||||
gc.TUINT16<<16 | gc.TFLOAT32,
|
||||
gc.TUINT16<<16 | gc.TFLOAT64,
|
||||
gc.TUINT8<<16 | gc.TFLOAT32,
|
||||
gc.TUINT8<<16 | gc.TFLOAT64,
|
||||
gc.TUINT32<<16 | gc.TFLOAT32,
|
||||
gc.TUINT32<<16 | gc.TFLOAT64,
|
||||
gc.TUINT64<<16 | gc.TFLOAT32,
|
||||
gc.TUINT64<<16 | gc.TFLOAT64:
|
||||
bignodes()
|
||||
|
||||
// The algorithm is:
|
||||
// if small enough, use native int64 -> float64 conversion,
|
||||
// otherwise halve (x -> (x>>1)|(x&1)), convert, and double.
|
||||
// Note: could use FCFIDU instead if target supports it.
|
||||
var r1 gc.Node
|
||||
gc.Regalloc(&r1, gc.Types[gc.TINT64], nil)
|
||||
gmove(f, &r1)
|
||||
if ft == gc.TUINT64 {
|
||||
gc.Nodreg(&r2, gc.Types[gc.TUINT64], ppc64.REGTMP)
|
||||
gmove(&bigi, &r2)
|
||||
gins(ppc64.ACMPU, &r1, &r2)
|
||||
p1 := gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT64]), nil, +1)
|
||||
var r3 gc.Node
|
||||
gc.Regalloc(&r3, gc.Types[gc.TUINT64], nil)
|
||||
p2 := gins(ppc64.AANDCC, nil, &r3) // andi.
|
||||
p2.Reg = r1.Reg
|
||||
p2.From.Type = obj.TYPE_CONST
|
||||
p2.From.Offset = 1
|
||||
p3 := gins(ppc64.ASRD, nil, &r1)
|
||||
p3.From.Type = obj.TYPE_CONST
|
||||
p3.From.Offset = 1
|
||||
gins(ppc64.AOR, &r3, &r1)
|
||||
gc.Regfree(&r3)
|
||||
gc.Patch(p1, gc.Pc)
|
||||
}
|
||||
gc.Regalloc(&r2, gc.Types[gc.TFLOAT64], t)
|
||||
p1 := gins(ppc64.AMOVD, &r1, nil)
|
||||
p1.To.Type = obj.TYPE_MEM
|
||||
@ -467,36 +498,12 @@ func gmove(f *gc.Node, t *gc.Node) {
|
||||
p1.From.Offset = -8
|
||||
gins(ppc64.AFCFID, &r2, &r2)
|
||||
gc.Regfree(&r1)
|
||||
gmove(&r2, t)
|
||||
gc.Regfree(&r2)
|
||||
return
|
||||
|
||||
/*
|
||||
* unsigned integer to float
|
||||
*/
|
||||
case gc.TUINT16<<16 | gc.TFLOAT32,
|
||||
gc.TUINT16<<16 | gc.TFLOAT64,
|
||||
gc.TUINT8<<16 | gc.TFLOAT32,
|
||||
gc.TUINT8<<16 | gc.TFLOAT64,
|
||||
gc.TUINT32<<16 | gc.TFLOAT32,
|
||||
gc.TUINT32<<16 | gc.TFLOAT64,
|
||||
gc.TUINT64<<16 | gc.TFLOAT32,
|
||||
gc.TUINT64<<16 | gc.TFLOAT64:
|
||||
|
||||
var r1 gc.Node
|
||||
gc.Regalloc(&r1, gc.Types[gc.TUINT64], nil)
|
||||
gmove(f, &r1)
|
||||
gc.Regalloc(&r2, gc.Types[gc.TFLOAT64], t)
|
||||
p1 := gins(ppc64.AMOVD, &r1, nil)
|
||||
p1.To.Type = obj.TYPE_MEM
|
||||
p1.To.Reg = ppc64.REGSP
|
||||
p1.To.Offset = -8
|
||||
p1 = gins(ppc64.AFMOVD, nil, &r2)
|
||||
p1.From.Type = obj.TYPE_MEM
|
||||
p1.From.Reg = ppc64.REGSP
|
||||
p1.From.Offset = -8
|
||||
gins(ppc64.AFCFIDU, &r2, &r2)
|
||||
gc.Regfree(&r1)
|
||||
if ft == gc.TUINT64 {
|
||||
p1 := gc.Gbranch(optoas(gc.OLT, gc.Types[gc.TUINT64]), nil, +1) // use CR0 here again
|
||||
gc.Nodreg(&r1, gc.Types[gc.TFLOAT64], ppc64.FREGTWO)
|
||||
gins(ppc64.AFMUL, &r1, &r2)
|
||||
gc.Patch(p1, gc.Pc)
|
||||
}
|
||||
gmove(&r2, t)
|
||||
gc.Regfree(&r2)
|
||||
return
|
||||
|
13
src/cmd/dist/buildgo.go
vendored
13
src/cmd/dist/buildgo.go
vendored
@ -42,10 +42,21 @@ func mkzdefaultcc(dir, file string) {
|
||||
|
||||
// mkzcgo writes zosarch.go for cmd/go.
|
||||
func mkzosarch(dir, file string) {
|
||||
// sort for deterministic zosarch.go file
|
||||
var list []string
|
||||
for plat := range cgoEnabled {
|
||||
list = append(list, plat)
|
||||
}
|
||||
sort.Strings(list)
|
||||
|
||||
var buf bytes.Buffer
|
||||
buf.WriteString("// auto generated by go tool dist\n\n")
|
||||
buf.WriteString("package main\n\n")
|
||||
fmt.Fprintf(&buf, "var osArchSupportsCgo = %#v", cgoEnabled)
|
||||
fmt.Fprintf(&buf, "var osArchSupportsCgo = map[string]bool{\n")
|
||||
for _, plat := range list {
|
||||
fmt.Fprintf(&buf, "\t%q: %v,\n", plat, cgoEnabled[plat])
|
||||
}
|
||||
fmt.Fprintf(&buf, "}\n")
|
||||
writefile(buf.String(), file, writeSkipSame)
|
||||
}
|
||||
|
||||
|
@ -508,8 +508,7 @@
|
||||
// searches for a branch or tag named "go1". If no such version exists it
|
||||
// retrieves the most recent version of the package.
|
||||
//
|
||||
// Unless vendoring support is disabled (see 'go help gopath'),
|
||||
// when go get checks out or updates a Git repository,
|
||||
// When go get checks out or updates a Git repository,
|
||||
// it also updates any git submodules referenced by the repository.
|
||||
//
|
||||
// Get never checks out or updates code stored in vendor directories.
|
||||
@ -1271,10 +1270,9 @@
|
||||
// let package authors make sure the custom import path is used and not a
|
||||
// direct path to the underlying code hosting site.
|
||||
//
|
||||
// If vendoring is enabled (see 'go help gopath'), then import path checking is
|
||||
// disabled for code found within vendor trees. This makes it possible to copy
|
||||
// code into alternate locations in vendor trees without needing to update import
|
||||
// comments.
|
||||
// Import path checking is disabled for code found within vendor trees.
|
||||
// This makes it possible to copy code into alternate locations in vendor trees
|
||||
// without needing to update import comments.
|
||||
//
|
||||
// See https://golang.org/s/go14customimport for details.
|
||||
//
|
||||
|
@ -673,11 +673,6 @@ func init() {
|
||||
goarch = buildContext.GOARCH
|
||||
goos = buildContext.GOOS
|
||||
|
||||
if _, ok := osArchSupportsCgo[goos+"/"+goarch]; !ok {
|
||||
fmt.Fprintf(os.Stderr, "cmd/go: unsupported GOOS/GOARCH pair %s/%s\n", goos, goarch)
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
if goos == "windows" {
|
||||
exeSuffix = ".exe"
|
||||
}
|
||||
@ -1226,6 +1221,11 @@ func allArchiveActions(root *action) []*action {
|
||||
|
||||
// do runs the action graph rooted at root.
|
||||
func (b *builder) do(root *action) {
|
||||
if _, ok := osArchSupportsCgo[goos+"/"+goarch]; !ok && buildContext.Compiler == "gc" {
|
||||
fmt.Fprintf(os.Stderr, "cmd/go: unsupported GOOS/GOARCH pair %s/%s\n", goos, goarch)
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
// Build list of all actions, assigning depth-first post-order priority.
|
||||
// The original implementation here was a true queue
|
||||
// (using a channel) but it had the effect of getting
|
||||
|
@ -14,7 +14,6 @@ import (
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
@ -276,8 +275,8 @@ func isGoGenerate(buf []byte) bool {
|
||||
// single go:generate command.
|
||||
func (g *Generator) setEnv() {
|
||||
g.env = []string{
|
||||
"GOARCH=" + runtime.GOARCH,
|
||||
"GOOS=" + runtime.GOOS,
|
||||
"GOARCH=" + buildContext.GOARCH,
|
||||
"GOOS=" + buildContext.GOOS,
|
||||
"GOFILE=" + g.file,
|
||||
"GOLINE=" + strconv.Itoa(g.lineNum),
|
||||
"GOPACKAGE=" + g.pkg,
|
||||
|
@ -55,8 +55,7 @@ rule is that if the local installation is running version "go1", get
|
||||
searches for a branch or tag named "go1". If no such version exists it
|
||||
retrieves the most recent version of the package.
|
||||
|
||||
Unless vendoring support is disabled (see 'go help gopath'),
|
||||
when go get checks out or updates a Git repository,
|
||||
When go get checks out or updates a Git repository,
|
||||
it also updates any git submodules referenced by the repository.
|
||||
|
||||
Get never checks out or updates code stored in vendor directories.
|
||||
|
@ -489,6 +489,16 @@ func (tg *testgoData) path(name string) string {
|
||||
return filepath.Join(tg.tempdir, name)
|
||||
}
|
||||
|
||||
// mustExist fails if path does not exist.
|
||||
func (tg *testgoData) mustExist(path string) {
|
||||
if _, err := os.Stat(path); err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
tg.t.Fatalf("%s does not exist but should", path)
|
||||
}
|
||||
tg.t.Fatalf("%s stat failed: %v", path, err)
|
||||
}
|
||||
}
|
||||
|
||||
// mustNotExist fails if path exists.
|
||||
func (tg *testgoData) mustNotExist(path string) {
|
||||
if _, err := os.Stat(path); err == nil || !os.IsNotExist(err) {
|
||||
@ -2920,3 +2930,27 @@ func TestAlwaysLinkSysoFiles(t *testing.T) {
|
||||
tg.run("list", "-f", "{{.SysoFiles}}", "syso")
|
||||
tg.grepStdout("a.syso", "missing syso file with CGO_ENABLED=0")
|
||||
}
|
||||
|
||||
// Issue 16120.
|
||||
func TestGenerateUsesBuildContext(t *testing.T) {
|
||||
if runtime.GOOS == "windows" {
|
||||
t.Skip("this test won't run under Windows")
|
||||
}
|
||||
|
||||
tg := testgo(t)
|
||||
defer tg.cleanup()
|
||||
tg.parallel()
|
||||
tg.tempDir("src/gen")
|
||||
tg.tempFile("src/gen/gen.go", "package gen\n//go:generate echo $GOOS $GOARCH\n")
|
||||
tg.setenv("GOPATH", tg.path("."))
|
||||
|
||||
tg.setenv("GOOS", "linux")
|
||||
tg.setenv("GOARCH", "amd64")
|
||||
tg.run("generate", "gen")
|
||||
tg.grepStdout("linux amd64", "unexpected GOOS/GOARCH combination")
|
||||
|
||||
tg.setenv("GOOS", "darwin")
|
||||
tg.setenv("GOARCH", "386")
|
||||
tg.run("generate", "gen")
|
||||
tg.grepStdout("darwin 386", "unexpected GOOS/GOARCH combination")
|
||||
}
|
||||
|
@ -261,10 +261,9 @@ unless it is being referred to by that import path. In this way, import comments
|
||||
let package authors make sure the custom import path is used and not a
|
||||
direct path to the underlying code hosting site.
|
||||
|
||||
If vendoring is enabled (see 'go help gopath'), then import path checking is
|
||||
disabled for code found within vendor trees. This makes it possible to copy
|
||||
code into alternate locations in vendor trees without needing to update import
|
||||
comments.
|
||||
Import path checking is disabled for code found within vendor trees.
|
||||
This makes it possible to copy code into alternate locations in vendor trees
|
||||
without needing to update import comments.
|
||||
|
||||
See https://golang.org/s/go14customimport for details.
|
||||
`,
|
||||
|
@ -383,9 +383,6 @@ func (v *vcsCmd) ping(scheme, repo string) error {
|
||||
// The parent of dir must exist; dir must not.
|
||||
func (v *vcsCmd) create(dir, repo string) error {
|
||||
for _, cmd := range v.createCmd {
|
||||
if strings.Contains(cmd, "submodule") {
|
||||
continue
|
||||
}
|
||||
if err := v.run(".", cmd, "dir", dir, "repo", repo); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -396,9 +393,6 @@ func (v *vcsCmd) create(dir, repo string) error {
|
||||
// download downloads any new changes for the repo in dir.
|
||||
func (v *vcsCmd) download(dir string) error {
|
||||
for _, cmd := range v.downloadCmd {
|
||||
if strings.Contains(cmd, "submodule") {
|
||||
continue
|
||||
}
|
||||
if err := v.run(dir, cmd); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -445,9 +439,6 @@ func (v *vcsCmd) tagSync(dir, tag string) error {
|
||||
|
||||
if tag == "" && v.tagSyncDefault != nil {
|
||||
for _, cmd := range v.tagSyncDefault {
|
||||
if strings.Contains(cmd, "submodule") {
|
||||
continue
|
||||
}
|
||||
if err := v.run(dir, cmd); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -456,9 +447,6 @@ func (v *vcsCmd) tagSync(dir, tag string) error {
|
||||
}
|
||||
|
||||
for _, cmd := range v.tagSyncCmd {
|
||||
if strings.Contains(cmd, "submodule") {
|
||||
continue
|
||||
}
|
||||
if err := v.run(dir, cmd, "tag", tag); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -870,7 +858,6 @@ var vcsPaths = []*vcsPath{
|
||||
re: `^(?P<root>git\.openstack\.org/[A-Za-z0-9_.\-]+/[A-Za-z0-9_.\-]+)(\.git)?(/[A-Za-z0-9_.\-]+)*$`,
|
||||
vcs: "git",
|
||||
repo: "https://{root}",
|
||||
check: noVCSSuffix,
|
||||
},
|
||||
|
||||
// General syntax for any server.
|
||||
|
@ -197,6 +197,7 @@ func TestGetSubmodules(t *testing.T) {
|
||||
tg.setenv("GOPATH", tg.path("."))
|
||||
tg.run("get", "-d", "github.com/rsc/go-get-issue-12612")
|
||||
tg.run("get", "-u", "-d", "github.com/rsc/go-get-issue-12612")
|
||||
tg.mustExist(tg.path("src/github.com/rsc/go-get-issue-12612/vendor/golang.org/x/crypto/.git"))
|
||||
}
|
||||
|
||||
func TestVendorCache(t *testing.T) {
|
||||
|
@ -55,7 +55,6 @@ func report(err error) {
|
||||
func usage() {
|
||||
fmt.Fprintf(os.Stderr, "usage: gofmt [flags] [path ...]\n")
|
||||
flag.PrintDefaults()
|
||||
os.Exit(2)
|
||||
}
|
||||
|
||||
func initParserMode() {
|
||||
|
@ -61,7 +61,7 @@ func decode_inuxi(p []byte, sz int) uint64 {
|
||||
|
||||
func commonsize() int { return 4*SysArch.PtrSize + 8 + 8 } // runtime._type
|
||||
func structfieldSize() int { return 3 * SysArch.PtrSize } // runtime.structfield
|
||||
func uncommonSize() int { return 4 + 2 + 2 } // runtime.uncommontype
|
||||
func uncommonSize() int { return 4 + 2 + 2 + 4 + 4 } // runtime.uncommontype
|
||||
|
||||
// Type.commonType.kind
|
||||
func decodetype_kind(s *LSym) uint8 {
|
||||
@ -362,7 +362,7 @@ func decodetype_methods(s *LSym) []methodsig {
|
||||
}
|
||||
|
||||
mcount := int(decode_inuxi(s.P[off+4:], 2))
|
||||
moff := int(decode_inuxi(s.P[off+4+2:], 2))
|
||||
moff := int(decode_inuxi(s.P[off+4+2+2:], 4))
|
||||
off += moff // offset to array of reflect.method values
|
||||
const sizeofMethod = 4 * 4 // sizeof reflect.method in program
|
||||
return decode_methodsig(s, off, sizeofMethod, mcount)
|
||||
|
@ -9,6 +9,7 @@ import (
|
||||
"debug/gosym"
|
||||
"flag"
|
||||
"fmt"
|
||||
"net/url"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
@ -50,7 +51,16 @@ func symbolize(mode, source string, p *profile.Profile, obj plugin.ObjTool, ui p
|
||||
ui.PrintErr("expecting -symbolize=[local|remote|none][:force]")
|
||||
fallthrough
|
||||
case "", "force":
|
||||
// Ignore these options, -force is recognized by symbolizer.Symbolize
|
||||
// -force is recognized by symbolizer.Symbolize.
|
||||
// If the source is remote, and the mapping file
|
||||
// does not exist, don't use local symbolization.
|
||||
if isRemote(source) {
|
||||
if len(p.Mapping) == 0 {
|
||||
local = false
|
||||
} else if _, err := os.Stat(p.Mapping[0].File); err != nil {
|
||||
local = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -67,6 +77,21 @@ func symbolize(mode, source string, p *profile.Profile, obj plugin.ObjTool, ui p
|
||||
return err
|
||||
}
|
||||
|
||||
// isRemote returns whether source is a URL for a remote source.
|
||||
func isRemote(source string) bool {
|
||||
url, err := url.Parse(source)
|
||||
if err != nil {
|
||||
url, err = url.Parse("http://" + source)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
}
|
||||
if scheme := strings.ToLower(url.Scheme); scheme == "" || scheme == "file" {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// flags implements the driver.FlagPackage interface using the builtin flag package.
|
||||
type flags struct {
|
||||
}
|
||||
@ -117,8 +142,10 @@ func (*objTool) Open(name string, start uint64) (plugin.ObjFile, error) {
|
||||
name: name,
|
||||
file: of,
|
||||
}
|
||||
if load, err := of.LoadAddress(); err == nil {
|
||||
f.offset = start - load
|
||||
if start != 0 {
|
||||
if load, err := of.LoadAddress(); err == nil {
|
||||
f.offset = start - load
|
||||
}
|
||||
}
|
||||
return f, nil
|
||||
}
|
||||
@ -306,6 +333,11 @@ func (f *file) Symbols(r *regexp.Regexp, addr uint64) ([]*plugin.Sym, error) {
|
||||
}
|
||||
var out []*plugin.Sym
|
||||
for _, s := range f.sym {
|
||||
// Ignore a symbol with address 0 and size 0.
|
||||
// An ELF STT_FILE symbol will look like that.
|
||||
if s.Addr == 0 && s.Size == 0 {
|
||||
continue
|
||||
}
|
||||
if (r == nil || r.MatchString(s.Name)) && (addr == 0 || s.Addr <= addr && addr < s.Addr+uint64(s.Size)) {
|
||||
out = append(out, &plugin.Sym{
|
||||
Name: []string{s.Name},
|
||||
|
6
src/cmd/vendor/golang.org/x/arch/x86/x86asm/plan9x.go
generated
vendored
6
src/cmd/vendor/golang.org/x/arch/x86/x86asm/plan9x.go
generated
vendored
@ -49,7 +49,11 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64)) strin
|
||||
|
||||
op := inst.Op.String()
|
||||
if plan9Suffix[inst.Op] {
|
||||
switch inst.DataSize {
|
||||
s := inst.DataSize
|
||||
if inst.MemBytes != 0 {
|
||||
s = inst.MemBytes * 8
|
||||
}
|
||||
switch s {
|
||||
case 8:
|
||||
op += "B"
|
||||
case 16:
|
||||
|
306
src/cmd/vendor/golang.org/x/arch/x86/x86asm/testdata/decode.txt
generated
vendored
306
src/cmd/vendor/golang.org/x/arch/x86/x86asm/testdata/decode.txt
generated
vendored
@ -7,10 +7,10 @@
|
||||
0100|11223344556677885f5f5f5f5f5f 64 intel add dword ptr [rax], eax
|
||||
0100|11223344556677885f5f5f5f5f5f 64 plan9 ADDL AX, 0(AX)
|
||||
0211|223344556677885f5f5f5f5f5f5f 32 intel add dl, byte ptr [ecx]
|
||||
0211|223344556677885f5f5f5f5f5f5f 32 plan9 ADDL 0(CX), DL
|
||||
0211|223344556677885f5f5f5f5f5f5f 32 plan9 ADDB 0(CX), DL
|
||||
0211|223344556677885f5f5f5f5f5f5f 64 gnu add (%rcx),%dl
|
||||
0211|223344556677885f5f5f5f5f5f5f 64 intel add dl, byte ptr [rcx]
|
||||
0211|223344556677885f5f5f5f5f5f5f 64 plan9 ADDL 0(CX), DL
|
||||
0211|223344556677885f5f5f5f5f5f5f 64 plan9 ADDB 0(CX), DL
|
||||
0311|223344556677885f5f5f5f5f5f5f 32 intel add edx, dword ptr [ecx]
|
||||
0311|223344556677885f5f5f5f5f5f5f 32 plan9 ADDL 0(CX), DX
|
||||
0311|223344556677885f5f5f5f5f5f5f 64 gnu add (%rcx),%edx
|
||||
@ -37,20 +37,20 @@
|
||||
07|11223344556677885f5f5f5f5f5f5f 64 intel error: unrecognized instruction
|
||||
07|11223344556677885f5f5f5f5f5f5f 64 plan9 error: unrecognized instruction
|
||||
0811|223344556677885f5f5f5f5f5f5f 32 intel or byte ptr [ecx], dl
|
||||
0811|223344556677885f5f5f5f5f5f5f 32 plan9 ORL DL, 0(CX)
|
||||
0811|223344556677885f5f5f5f5f5f5f 32 plan9 ORB DL, 0(CX)
|
||||
0811|223344556677885f5f5f5f5f5f5f 64 gnu or %dl,(%rcx)
|
||||
0811|223344556677885f5f5f5f5f5f5f 64 intel or byte ptr [rcx], dl
|
||||
0811|223344556677885f5f5f5f5f5f5f 64 plan9 ORL DL, 0(CX)
|
||||
0811|223344556677885f5f5f5f5f5f5f 64 plan9 ORB DL, 0(CX)
|
||||
0911|223344556677885f5f5f5f5f5f5f 32 intel or dword ptr [ecx], edx
|
||||
0911|223344556677885f5f5f5f5f5f5f 32 plan9 ORL DX, 0(CX)
|
||||
0911|223344556677885f5f5f5f5f5f5f 64 gnu or %edx,(%rcx)
|
||||
0911|223344556677885f5f5f5f5f5f5f 64 intel or dword ptr [rcx], edx
|
||||
0911|223344556677885f5f5f5f5f5f5f 64 plan9 ORL DX, 0(CX)
|
||||
0a11|223344556677885f5f5f5f5f5f5f 32 intel or dl, byte ptr [ecx]
|
||||
0a11|223344556677885f5f5f5f5f5f5f 32 plan9 ORL 0(CX), DL
|
||||
0a11|223344556677885f5f5f5f5f5f5f 32 plan9 ORB 0(CX), DL
|
||||
0a11|223344556677885f5f5f5f5f5f5f 64 gnu or (%rcx),%dl
|
||||
0a11|223344556677885f5f5f5f5f5f5f 64 intel or dl, byte ptr [rcx]
|
||||
0a11|223344556677885f5f5f5f5f5f5f 64 plan9 ORL 0(CX), DL
|
||||
0a11|223344556677885f5f5f5f5f5f5f 64 plan9 ORB 0(CX), DL
|
||||
0b11|223344556677885f5f5f5f5f5f5f 32 intel or edx, dword ptr [ecx]
|
||||
0b11|223344556677885f5f5f5f5f5f5f 32 plan9 ORL 0(CX), DX
|
||||
0b11|223344556677885f5f5f5f5f5f5f 64 gnu or (%rcx),%edx
|
||||
@ -1479,10 +1479,10 @@
|
||||
0faf11|223344556677885f5f5f5f5f5f 64 intel imul edx, dword ptr [rcx]
|
||||
0faf11|223344556677885f5f5f5f5f5f 64 plan9 IMULL 0(CX), DX
|
||||
0fb011|223344556677885f5f5f5f5f5f 32 intel cmpxchg byte ptr [ecx], dl
|
||||
0fb011|223344556677885f5f5f5f5f5f 32 plan9 CMPXCHGL DL, 0(CX)
|
||||
0fb011|223344556677885f5f5f5f5f5f 32 plan9 CMPXCHGB DL, 0(CX)
|
||||
0fb011|223344556677885f5f5f5f5f5f 64 gnu cmpxchg %dl,(%rcx)
|
||||
0fb011|223344556677885f5f5f5f5f5f 64 intel cmpxchg byte ptr [rcx], dl
|
||||
0fb011|223344556677885f5f5f5f5f5f 64 plan9 CMPXCHGL DL, 0(CX)
|
||||
0fb011|223344556677885f5f5f5f5f5f 64 plan9 CMPXCHGB DL, 0(CX)
|
||||
0fb111|223344556677885f5f5f5f5f5f 32 intel cmpxchg dword ptr [ecx], edx
|
||||
0fb111|223344556677885f5f5f5f5f5f 32 plan9 CMPXCHGL DX, 0(CX)
|
||||
0fb111|223344556677885f5f5f5f5f5f 64 gnu cmpxchg %edx,(%rcx)
|
||||
@ -1579,10 +1579,10 @@
|
||||
0fbf11|223344556677885f5f5f5f5f5f 64 intel movsx edx, word ptr [rcx]
|
||||
0fbf11|223344556677885f5f5f5f5f5f 64 plan9 MOVSX 0(CX), DX
|
||||
0fc011|223344556677885f5f5f5f5f5f 32 intel xadd byte ptr [ecx], dl
|
||||
0fc011|223344556677885f5f5f5f5f5f 32 plan9 XADDL DL, 0(CX)
|
||||
0fc011|223344556677885f5f5f5f5f5f 32 plan9 XADDB DL, 0(CX)
|
||||
0fc011|223344556677885f5f5f5f5f5f 64 gnu xadd %dl,(%rcx)
|
||||
0fc011|223344556677885f5f5f5f5f5f 64 intel xadd byte ptr [rcx], dl
|
||||
0fc011|223344556677885f5f5f5f5f5f 64 plan9 XADDL DL, 0(CX)
|
||||
0fc011|223344556677885f5f5f5f5f5f 64 plan9 XADDB DL, 0(CX)
|
||||
0fc111|223344556677885f5f5f5f5f5f 32 intel xadd dword ptr [ecx], edx
|
||||
0fc111|223344556677885f5f5f5f5f5f 32 plan9 XADDL DX, 0(CX)
|
||||
0fc111|223344556677885f5f5f5f5f5f 64 gnu xadd %edx,(%rcx)
|
||||
@ -1899,20 +1899,20 @@
|
||||
0ffe11|223344556677885f5f5f5f5f5f 64 intel paddd mmx2, qword ptr [rcx]
|
||||
0ffe11|223344556677885f5f5f5f5f5f 64 plan9 PADDD 0(CX), M2
|
||||
1011|223344556677885f5f5f5f5f5f5f 32 intel adc byte ptr [ecx], dl
|
||||
1011|223344556677885f5f5f5f5f5f5f 32 plan9 ADCL DL, 0(CX)
|
||||
1011|223344556677885f5f5f5f5f5f5f 32 plan9 ADCB DL, 0(CX)
|
||||
1011|223344556677885f5f5f5f5f5f5f 64 gnu adc %dl,(%rcx)
|
||||
1011|223344556677885f5f5f5f5f5f5f 64 intel adc byte ptr [rcx], dl
|
||||
1011|223344556677885f5f5f5f5f5f5f 64 plan9 ADCL DL, 0(CX)
|
||||
1011|223344556677885f5f5f5f5f5f5f 64 plan9 ADCB DL, 0(CX)
|
||||
1111|223344556677885f5f5f5f5f5f5f 32 intel adc dword ptr [ecx], edx
|
||||
1111|223344556677885f5f5f5f5f5f5f 32 plan9 ADCL DX, 0(CX)
|
||||
1111|223344556677885f5f5f5f5f5f5f 64 gnu adc %edx,(%rcx)
|
||||
1111|223344556677885f5f5f5f5f5f5f 64 intel adc dword ptr [rcx], edx
|
||||
1111|223344556677885f5f5f5f5f5f5f 64 plan9 ADCL DX, 0(CX)
|
||||
1211|223344556677885f5f5f5f5f5f5f 32 intel adc dl, byte ptr [ecx]
|
||||
1211|223344556677885f5f5f5f5f5f5f 32 plan9 ADCL 0(CX), DL
|
||||
1211|223344556677885f5f5f5f5f5f5f 32 plan9 ADCB 0(CX), DL
|
||||
1211|223344556677885f5f5f5f5f5f5f 64 gnu adc (%rcx),%dl
|
||||
1211|223344556677885f5f5f5f5f5f5f 64 intel adc dl, byte ptr [rcx]
|
||||
1211|223344556677885f5f5f5f5f5f5f 64 plan9 ADCL 0(CX), DL
|
||||
1211|223344556677885f5f5f5f5f5f5f 64 plan9 ADCB 0(CX), DL
|
||||
1311|223344556677885f5f5f5f5f5f5f 32 intel adc edx, dword ptr [ecx]
|
||||
1311|223344556677885f5f5f5f5f5f5f 32 plan9 ADCL 0(CX), DX
|
||||
1311|223344556677885f5f5f5f5f5f5f 64 gnu adc (%rcx),%edx
|
||||
@ -1939,20 +1939,20 @@
|
||||
17|11223344556677885f5f5f5f5f5f5f 64 intel error: unrecognized instruction
|
||||
17|11223344556677885f5f5f5f5f5f5f 64 plan9 error: unrecognized instruction
|
||||
1811|223344556677885f5f5f5f5f5f5f 32 intel sbb byte ptr [ecx], dl
|
||||
1811|223344556677885f5f5f5f5f5f5f 32 plan9 SBBL DL, 0(CX)
|
||||
1811|223344556677885f5f5f5f5f5f5f 32 plan9 SBBB DL, 0(CX)
|
||||
1811|223344556677885f5f5f5f5f5f5f 64 gnu sbb %dl,(%rcx)
|
||||
1811|223344556677885f5f5f5f5f5f5f 64 intel sbb byte ptr [rcx], dl
|
||||
1811|223344556677885f5f5f5f5f5f5f 64 plan9 SBBL DL, 0(CX)
|
||||
1811|223344556677885f5f5f5f5f5f5f 64 plan9 SBBB DL, 0(CX)
|
||||
1911|223344556677885f5f5f5f5f5f5f 32 intel sbb dword ptr [ecx], edx
|
||||
1911|223344556677885f5f5f5f5f5f5f 32 plan9 SBBL DX, 0(CX)
|
||||
1911|223344556677885f5f5f5f5f5f5f 64 gnu sbb %edx,(%rcx)
|
||||
1911|223344556677885f5f5f5f5f5f5f 64 intel sbb dword ptr [rcx], edx
|
||||
1911|223344556677885f5f5f5f5f5f5f 64 plan9 SBBL DX, 0(CX)
|
||||
1a11|223344556677885f5f5f5f5f5f5f 32 intel sbb dl, byte ptr [ecx]
|
||||
1a11|223344556677885f5f5f5f5f5f5f 32 plan9 SBBL 0(CX), DL
|
||||
1a11|223344556677885f5f5f5f5f5f5f 32 plan9 SBBB 0(CX), DL
|
||||
1a11|223344556677885f5f5f5f5f5f5f 64 gnu sbb (%rcx),%dl
|
||||
1a11|223344556677885f5f5f5f5f5f5f 64 intel sbb dl, byte ptr [rcx]
|
||||
1a11|223344556677885f5f5f5f5f5f5f 64 plan9 SBBL 0(CX), DL
|
||||
1a11|223344556677885f5f5f5f5f5f5f 64 plan9 SBBB 0(CX), DL
|
||||
1b11|223344556677885f5f5f5f5f5f5f 32 intel sbb edx, dword ptr [ecx]
|
||||
1b11|223344556677885f5f5f5f5f5f5f 32 plan9 SBBL 0(CX), DX
|
||||
1b11|223344556677885f5f5f5f5f5f5f 64 gnu sbb (%rcx),%edx
|
||||
@ -1979,20 +1979,20 @@
|
||||
1f|11223344556677885f5f5f5f5f5f5f 64 intel error: unrecognized instruction
|
||||
1f|11223344556677885f5f5f5f5f5f5f 64 plan9 error: unrecognized instruction
|
||||
2011|223344556677885f5f5f5f5f5f5f 32 intel and byte ptr [ecx], dl
|
||||
2011|223344556677885f5f5f5f5f5f5f 32 plan9 ANDL DL, 0(CX)
|
||||
2011|223344556677885f5f5f5f5f5f5f 32 plan9 ANDB DL, 0(CX)
|
||||
2011|223344556677885f5f5f5f5f5f5f 64 gnu and %dl,(%rcx)
|
||||
2011|223344556677885f5f5f5f5f5f5f 64 intel and byte ptr [rcx], dl
|
||||
2011|223344556677885f5f5f5f5f5f5f 64 plan9 ANDL DL, 0(CX)
|
||||
2011|223344556677885f5f5f5f5f5f5f 64 plan9 ANDB DL, 0(CX)
|
||||
2111|223344556677885f5f5f5f5f5f5f 32 intel and dword ptr [ecx], edx
|
||||
2111|223344556677885f5f5f5f5f5f5f 32 plan9 ANDL DX, 0(CX)
|
||||
2111|223344556677885f5f5f5f5f5f5f 64 gnu and %edx,(%rcx)
|
||||
2111|223344556677885f5f5f5f5f5f5f 64 intel and dword ptr [rcx], edx
|
||||
2111|223344556677885f5f5f5f5f5f5f 64 plan9 ANDL DX, 0(CX)
|
||||
2211|223344556677885f5f5f5f5f5f5f 32 intel and dl, byte ptr [ecx]
|
||||
2211|223344556677885f5f5f5f5f5f5f 32 plan9 ANDL 0(CX), DL
|
||||
2211|223344556677885f5f5f5f5f5f5f 32 plan9 ANDB 0(CX), DL
|
||||
2211|223344556677885f5f5f5f5f5f5f 64 gnu and (%rcx),%dl
|
||||
2211|223344556677885f5f5f5f5f5f5f 64 intel and dl, byte ptr [rcx]
|
||||
2211|223344556677885f5f5f5f5f5f5f 64 plan9 ANDL 0(CX), DL
|
||||
2211|223344556677885f5f5f5f5f5f5f 64 plan9 ANDB 0(CX), DL
|
||||
2311|223344556677885f5f5f5f5f5f5f 32 intel and edx, dword ptr [ecx]
|
||||
2311|223344556677885f5f5f5f5f5f5f 32 plan9 ANDL 0(CX), DX
|
||||
2311|223344556677885f5f5f5f5f5f5f 64 gnu and (%rcx),%edx
|
||||
@ -2020,9 +2020,9 @@
|
||||
267011|223344556677885f5f5f5f5f5f 64 plan9 ES JO .+17
|
||||
26a01122334455667788|5f5f5f5f5f5f 64 gnu mov %es:-0x778899aabbccddef,%al
|
||||
26a01122334455667788|5f5f5f5f5f5f 64 intel mov al, byte ptr [0x8877665544332211]
|
||||
26a01122334455667788|5f5f5f5f5f5f 64 plan9 ES MOVL -0x778899aabbccddef, AL
|
||||
26a01122334455667788|5f5f5f5f5f5f 64 plan9 ES MOVB -0x778899aabbccddef, AL
|
||||
26a011223344|556677885f5f5f5f5f5f 32 intel mov al, byte ptr es:[0x44332211]
|
||||
26a011223344|556677885f5f5f5f5f5f 32 plan9 ES MOVL ES:0x44332211, AL
|
||||
26a011223344|556677885f5f5f5f5f5f 32 plan9 ES MOVB ES:0x44332211, AL
|
||||
26|8211223344556677885f5f5f5f5f5f 32 intel es
|
||||
26|8211223344556677885f5f5f5f5f5f 32 plan9 ES Op(0)
|
||||
26|8211223344556677885f5f5f5f5f5f 64 gnu es
|
||||
@ -2034,20 +2034,20 @@
|
||||
27|11223344556677885f5f5f5f5f5f5f 64 intel error: unrecognized instruction
|
||||
27|11223344556677885f5f5f5f5f5f5f 64 plan9 error: unrecognized instruction
|
||||
2811|223344556677885f5f5f5f5f5f5f 32 intel sub byte ptr [ecx], dl
|
||||
2811|223344556677885f5f5f5f5f5f5f 32 plan9 SUBL DL, 0(CX)
|
||||
2811|223344556677885f5f5f5f5f5f5f 32 plan9 SUBB DL, 0(CX)
|
||||
2811|223344556677885f5f5f5f5f5f5f 64 gnu sub %dl,(%rcx)
|
||||
2811|223344556677885f5f5f5f5f5f5f 64 intel sub byte ptr [rcx], dl
|
||||
2811|223344556677885f5f5f5f5f5f5f 64 plan9 SUBL DL, 0(CX)
|
||||
2811|223344556677885f5f5f5f5f5f5f 64 plan9 SUBB DL, 0(CX)
|
||||
2911|223344556677885f5f5f5f5f5f5f 32 intel sub dword ptr [ecx], edx
|
||||
2911|223344556677885f5f5f5f5f5f5f 32 plan9 SUBL DX, 0(CX)
|
||||
2911|223344556677885f5f5f5f5f5f5f 64 gnu sub %edx,(%rcx)
|
||||
2911|223344556677885f5f5f5f5f5f5f 64 intel sub dword ptr [rcx], edx
|
||||
2911|223344556677885f5f5f5f5f5f5f 64 plan9 SUBL DX, 0(CX)
|
||||
2a11|223344556677885f5f5f5f5f5f5f 32 intel sub dl, byte ptr [ecx]
|
||||
2a11|223344556677885f5f5f5f5f5f5f 32 plan9 SUBL 0(CX), DL
|
||||
2a11|223344556677885f5f5f5f5f5f5f 32 plan9 SUBB 0(CX), DL
|
||||
2a11|223344556677885f5f5f5f5f5f5f 64 gnu sub (%rcx),%dl
|
||||
2a11|223344556677885f5f5f5f5f5f5f 64 intel sub dl, byte ptr [rcx]
|
||||
2a11|223344556677885f5f5f5f5f5f5f 64 plan9 SUBL 0(CX), DL
|
||||
2a11|223344556677885f5f5f5f5f5f5f 64 plan9 SUBB 0(CX), DL
|
||||
2b11|223344556677885f5f5f5f5f5f5f 32 intel sub edx, dword ptr [ecx]
|
||||
2b11|223344556677885f5f5f5f5f5f5f 32 plan9 SUBL 0(CX), DX
|
||||
2b11|223344556677885f5f5f5f5f5f5f 64 gnu sub (%rcx),%edx
|
||||
@ -2069,20 +2069,20 @@
|
||||
2f|11223344556677885f5f5f5f5f5f5f 64 intel error: unrecognized instruction
|
||||
2f|11223344556677885f5f5f5f5f5f5f 64 plan9 error: unrecognized instruction
|
||||
3011|223344556677885f5f5f5f5f5f5f 32 intel xor byte ptr [ecx], dl
|
||||
3011|223344556677885f5f5f5f5f5f5f 32 plan9 XORL DL, 0(CX)
|
||||
3011|223344556677885f5f5f5f5f5f5f 32 plan9 XORB DL, 0(CX)
|
||||
3011|223344556677885f5f5f5f5f5f5f 64 gnu xor %dl,(%rcx)
|
||||
3011|223344556677885f5f5f5f5f5f5f 64 intel xor byte ptr [rcx], dl
|
||||
3011|223344556677885f5f5f5f5f5f5f 64 plan9 XORL DL, 0(CX)
|
||||
3011|223344556677885f5f5f5f5f5f5f 64 plan9 XORB DL, 0(CX)
|
||||
3111|223344556677885f5f5f5f5f5f5f 32 intel xor dword ptr [ecx], edx
|
||||
3111|223344556677885f5f5f5f5f5f5f 32 plan9 XORL DX, 0(CX)
|
||||
3111|223344556677885f5f5f5f5f5f5f 64 gnu xor %edx,(%rcx)
|
||||
3111|223344556677885f5f5f5f5f5f5f 64 intel xor dword ptr [rcx], edx
|
||||
3111|223344556677885f5f5f5f5f5f5f 64 plan9 XORL DX, 0(CX)
|
||||
3211|223344556677885f5f5f5f5f5f5f 32 intel xor dl, byte ptr [ecx]
|
||||
3211|223344556677885f5f5f5f5f5f5f 32 plan9 XORL 0(CX), DL
|
||||
3211|223344556677885f5f5f5f5f5f5f 32 plan9 XORB 0(CX), DL
|
||||
3211|223344556677885f5f5f5f5f5f5f 64 gnu xor (%rcx),%dl
|
||||
3211|223344556677885f5f5f5f5f5f5f 64 intel xor dl, byte ptr [rcx]
|
||||
3211|223344556677885f5f5f5f5f5f5f 64 plan9 XORL 0(CX), DL
|
||||
3211|223344556677885f5f5f5f5f5f5f 64 plan9 XORB 0(CX), DL
|
||||
3311|223344556677885f5f5f5f5f5f5f 32 intel xor edx, dword ptr [ecx]
|
||||
3311|223344556677885f5f5f5f5f5f5f 32 plan9 XORL 0(CX), DX
|
||||
3311|223344556677885f5f5f5f5f5f5f 64 gnu xor (%rcx),%edx
|
||||
@ -2120,20 +2120,20 @@
|
||||
37|11223344556677885f5f5f5f5f5f5f 64 intel error: unrecognized instruction
|
||||
37|11223344556677885f5f5f5f5f5f5f 64 plan9 error: unrecognized instruction
|
||||
3811|223344556677885f5f5f5f5f5f5f 32 intel cmp byte ptr [ecx], dl
|
||||
3811|223344556677885f5f5f5f5f5f5f 32 plan9 CMPL DL, 0(CX)
|
||||
3811|223344556677885f5f5f5f5f5f5f 32 plan9 CMPB DL, 0(CX)
|
||||
3811|223344556677885f5f5f5f5f5f5f 64 gnu cmp %dl,(%rcx)
|
||||
3811|223344556677885f5f5f5f5f5f5f 64 intel cmp byte ptr [rcx], dl
|
||||
3811|223344556677885f5f5f5f5f5f5f 64 plan9 CMPL DL, 0(CX)
|
||||
3811|223344556677885f5f5f5f5f5f5f 64 plan9 CMPB DL, 0(CX)
|
||||
3911|223344556677885f5f5f5f5f5f5f 32 intel cmp dword ptr [ecx], edx
|
||||
3911|223344556677885f5f5f5f5f5f5f 32 plan9 CMPL DX, 0(CX)
|
||||
3911|223344556677885f5f5f5f5f5f5f 64 gnu cmp %edx,(%rcx)
|
||||
3911|223344556677885f5f5f5f5f5f5f 64 intel cmp dword ptr [rcx], edx
|
||||
3911|223344556677885f5f5f5f5f5f5f 64 plan9 CMPL DX, 0(CX)
|
||||
3a11|223344556677885f5f5f5f5f5f5f 32 intel cmp dl, byte ptr [ecx]
|
||||
3a11|223344556677885f5f5f5f5f5f5f 32 plan9 CMPL 0(CX), DL
|
||||
3a11|223344556677885f5f5f5f5f5f5f 32 plan9 CMPB 0(CX), DL
|
||||
3a11|223344556677885f5f5f5f5f5f5f 64 gnu cmp (%rcx),%dl
|
||||
3a11|223344556677885f5f5f5f5f5f5f 64 intel cmp dl, byte ptr [rcx]
|
||||
3a11|223344556677885f5f5f5f5f5f5f 64 plan9 CMPL 0(CX), DL
|
||||
3a11|223344556677885f5f5f5f5f5f5f 64 plan9 CMPB 0(CX), DL
|
||||
3b11|223344556677885f5f5f5f5f5f5f 32 intel cmp edx, dword ptr [ecx]
|
||||
3b11|223344556677885f5f5f5f5f5f5f 32 plan9 CMPL 0(CX), DX
|
||||
3b11|223344556677885f5f5f5f5f5f5f 64 gnu cmp (%rcx),%edx
|
||||
@ -2570,13 +2570,14 @@
|
||||
488b11|223344556677885f5f5f5f5f5f 64 plan9 MOVQ 0(CX), DX
|
||||
488c11|223344556677885f5f5f5f5f5f 64 gnu mov %ss,(%rcx)
|
||||
488c11|223344556677885f5f5f5f5f5f 64 intel mov word ptr [rcx], ss
|
||||
488c11|223344556677885f5f5f5f5f5f 64 plan9 MOVQ SS, 0(CX)
|
||||
# MOVQ is probably more correct here (reads 16 bits of segment register, zero extends, writes 64 bits at CX)
|
||||
488c11|223344556677885f5f5f5f5f5f 64 plan9 MOVW SS, 0(CX)
|
||||
488d11|223344556677885f5f5f5f5f5f 64 gnu lea (%rcx),%rdx
|
||||
488d11|223344556677885f5f5f5f5f5f 64 intel lea rdx, ptr [rcx]
|
||||
488d11|223344556677885f5f5f5f5f5f 64 plan9 LEAQ 0(CX), DX
|
||||
488e11|223344556677885f5f5f5f5f5f 64 gnu mov (%rcx),%ss
|
||||
488e11|223344556677885f5f5f5f5f5f 64 intel mov ss, word ptr [rcx]
|
||||
488e11|223344556677885f5f5f5f5f5f 64 plan9 MOVQ 0(CX), SS
|
||||
488e11|223344556677885f5f5f5f5f5f 64 plan9 MOVW 0(CX), SS
|
||||
488f00|11223344556677885f5f5f5f5f 64 gnu popq (%rax)
|
||||
488f00|11223344556677885f5f5f5f5f 64 intel pop qword ptr [rax]
|
||||
488f00|11223344556677885f5f5f5f5f 64 plan9 POPQ 0(AX)
|
||||
@ -2597,13 +2598,13 @@
|
||||
489d|11223344556677885f5f5f5f5f5f 64 plan9 POPFQ
|
||||
48a01122334455667788|5f5f5f5f5f5f 64 gnu mov -0x778899aabbccddef,%al
|
||||
48a01122334455667788|5f5f5f5f5f5f 64 intel mov al, byte ptr [0x8877665544332211]
|
||||
48a01122334455667788|5f5f5f5f5f5f 64 plan9 MOVQ -0x778899aabbccddef, AL
|
||||
48a01122334455667788|5f5f5f5f5f5f 64 plan9 MOVB -0x778899aabbccddef, AL
|
||||
48a11122334455667788|5f5f5f5f5f5f 64 gnu mov -0x778899aabbccddef,%rax
|
||||
48a11122334455667788|5f5f5f5f5f5f 64 intel mov rax, qword ptr [0x8877665544332211]
|
||||
48a11122334455667788|5f5f5f5f5f5f 64 plan9 MOVQ -0x778899aabbccddef, AX
|
||||
48a21122334455667788|5f5f5f5f5f5f 64 gnu mov %al,-0x778899aabbccddef
|
||||
48a21122334455667788|5f5f5f5f5f5f 64 intel mov byte ptr [0x8877665544332211], al
|
||||
48a21122334455667788|5f5f5f5f5f5f 64 plan9 MOVQ AL, -0x778899aabbccddef
|
||||
48a21122334455667788|5f5f5f5f5f5f 64 plan9 MOVB AL, -0x778899aabbccddef
|
||||
48a31122334455667788|5f5f5f5f5f5f 64 gnu mov %rax,-0x778899aabbccddef
|
||||
48a31122334455667788|5f5f5f5f5f5f 64 intel mov qword ptr [0x8877665544332211], rax
|
||||
48a31122334455667788|5f5f5f5f5f5f 64 plan9 MOVQ AX, -0x778899aabbccddef
|
||||
@ -3873,10 +3874,10 @@
|
||||
660fc21122|3344556677885f5f5f5f5f 64 intel cmppd xmm2, xmmword ptr [rcx], 0x22
|
||||
660fc21122|3344556677885f5f5f5f5f 64 plan9 CMPPD $0x22, 0(CX), X2
|
||||
660fc311|223344556677885f5f5f5f5f 32 intel movnti dword ptr [ecx], edx
|
||||
660fc311|223344556677885f5f5f5f5f 32 plan9 MOVNTIW DX, 0(CX)
|
||||
660fc311|223344556677885f5f5f5f5f 32 plan9 MOVNTIL DX, 0(CX)
|
||||
660fc311|223344556677885f5f5f5f5f 64 gnu movnti %edx,(%rcx)
|
||||
660fc311|223344556677885f5f5f5f5f 64 intel movnti dword ptr [rcx], edx
|
||||
660fc311|223344556677885f5f5f5f5f 64 plan9 MOVNTIW DX, 0(CX)
|
||||
660fc311|223344556677885f5f5f5f5f 64 plan9 MOVNTIL DX, 0(CX)
|
||||
660fc41122|3344556677885f5f5f5f5f 32 intel pinsrw xmm2, word ptr [ecx], 0x22
|
||||
660fc41122|3344556677885f5f5f5f5f 32 plan9 PINSRW $0x22, 0(CX), X2
|
||||
660fc41122|3344556677885f5f5f5f5f 64 gnu pinsrw $0x22,(%rcx),%xmm2
|
||||
@ -4665,35 +4666,36 @@
|
||||
66ef|11223344556677885f5f5f5f5f5f 64 intel out dx, ax
|
||||
66ef|11223344556677885f5f5f5f5f5f 64 plan9 OUTW AX, DX
|
||||
66f20f2a11|223344556677885f5f5f5f 32 intel cvtsi2sd xmm2, dword ptr [ecx]
|
||||
66f20f2a11|223344556677885f5f5f5f 32 plan9 REPNE CVTSI2SDW 0(CX), X2
|
||||
66f20f2a11|223344556677885f5f5f5f 32 plan9 REPNE CVTSI2SDL 0(CX), X2
|
||||
66f20f2a11|223344556677885f5f5f5f 64 gnu cvtsi2sdl (%rcx),%xmm2
|
||||
66f20f2a11|223344556677885f5f5f5f 64 intel cvtsi2sd xmm2, dword ptr [rcx]
|
||||
66f20f2a11|223344556677885f5f5f5f 64 plan9 REPNE CVTSI2SDW 0(CX), X2
|
||||
66f20f2a11|223344556677885f5f5f5f 64 plan9 REPNE CVTSI2SDL 0(CX), X2
|
||||
# the Q extension is the size of the source float64 in memory. The destination is L.
|
||||
66f20f2c11|223344556677885f5f5f5f 32 intel cvttsd2si edx, qword ptr [ecx]
|
||||
66f20f2c11|223344556677885f5f5f5f 32 plan9 REPNE CVTTSD2SIW 0(CX), DX
|
||||
66f20f2c11|223344556677885f5f5f5f 32 plan9 REPNE CVTTSD2SIQ 0(CX), DX
|
||||
66f20f2c11|223344556677885f5f5f5f 64 gnu cvttsd2si (%rcx),%dx
|
||||
66f20f2c11|223344556677885f5f5f5f 64 intel cvttsd2si edx, qword ptr [rcx]
|
||||
66f20f2c11|223344556677885f5f5f5f 64 plan9 REPNE CVTTSD2SIW 0(CX), DX
|
||||
66f20f2c11|223344556677885f5f5f5f 64 plan9 REPNE CVTTSD2SIQ 0(CX), DX
|
||||
66f20f2d11|223344556677885f5f5f5f 32 intel cvtsd2si edx, qword ptr [ecx]
|
||||
66f20f2d11|223344556677885f5f5f5f 32 plan9 REPNE CVTSD2SIW 0(CX), DX
|
||||
66f20f2d11|223344556677885f5f5f5f 32 plan9 REPNE CVTSD2SIQ 0(CX), DX
|
||||
66f20f2d11|223344556677885f5f5f5f 64 gnu cvtsd2si (%rcx),%dx
|
||||
66f20f2d11|223344556677885f5f5f5f 64 intel cvtsd2si edx, qword ptr [rcx]
|
||||
66f20f2d11|223344556677885f5f5f5f 64 plan9 REPNE CVTSD2SIW 0(CX), DX
|
||||
66f20f2d11|223344556677885f5f5f5f 64 plan9 REPNE CVTSD2SIQ 0(CX), DX
|
||||
66f20f38f011|223344556677885f5f5f 32 intel crc32 edx, byte ptr [ecx]
|
||||
66f20f38f011|223344556677885f5f5f 32 plan9 REPNE CRC32 0(CX), DX
|
||||
66f20f38f011|223344556677885f5f5f 64 gnu crc32b (%rcx),%edx
|
||||
66f20f38f011|223344556677885f5f5f 64 intel crc32 edx, byte ptr [rcx]
|
||||
66f20f38f011|223344556677885f5f5f 64 plan9 REPNE CRC32 0(CX), DX
|
||||
66f30f2c11|223344556677885f5f5f5f 32 intel cvttss2si edx, dword ptr [ecx]
|
||||
66f30f2c11|223344556677885f5f5f5f 32 plan9 REP CVTTSS2SIW 0(CX), DX
|
||||
66f30f2c11|223344556677885f5f5f5f 32 plan9 REP CVTTSS2SIL 0(CX), DX
|
||||
66f30f2c11|223344556677885f5f5f5f 64 gnu cvttss2si (%rcx),%dx
|
||||
66f30f2c11|223344556677885f5f5f5f 64 intel cvttss2si edx, dword ptr [rcx]
|
||||
66f30f2c11|223344556677885f5f5f5f 64 plan9 REP CVTTSS2SIW 0(CX), DX
|
||||
66f30f2c11|223344556677885f5f5f5f 64 plan9 REP CVTTSS2SIL 0(CX), DX
|
||||
66f30f2d11|223344556677885f5f5f5f 32 intel cvtss2si edx, dword ptr [ecx]
|
||||
66f30f2d11|223344556677885f5f5f5f 32 plan9 REP CVTSS2SIW 0(CX), DX
|
||||
66f30f2d11|223344556677885f5f5f5f 32 plan9 REP CVTSS2SIL 0(CX), DX
|
||||
66f30f2d11|223344556677885f5f5f5f 64 gnu cvtss2si (%rcx),%dx
|
||||
66f30f2d11|223344556677885f5f5f5f 64 intel cvtss2si edx, dword ptr [rcx]
|
||||
66f30f2d11|223344556677885f5f5f5f 64 plan9 REP CVTSS2SIW 0(CX), DX
|
||||
66f30f2d11|223344556677885f5f5f5f 64 plan9 REP CVTSS2SIL 0(CX), DX
|
||||
66f30fae11|223344556677885f5f5f5f 64 gnu wrfsbasel (%rcx)
|
||||
66f30fae11|223344556677885f5f5f5f 64 intel wrfsbase dword ptr [rcx]
|
||||
66f30fae11|223344556677885f5f5f5f 64 plan9 REP WRFSBASE 0(CX)
|
||||
@ -4917,45 +4919,45 @@
|
||||
7f11|223344556677885f5f5f5f5f5f5f 64 intel jnle .+0x11
|
||||
7f11|223344556677885f5f5f5f5f5f5f 64 plan9 JG .+17
|
||||
800011|223344556677885f5f5f5f5f5f 32 intel add byte ptr [eax], 0x11
|
||||
800011|223344556677885f5f5f5f5f5f 32 plan9 ADDL $0x11, 0(AX)
|
||||
800011|223344556677885f5f5f5f5f5f 32 plan9 ADDB $0x11, 0(AX)
|
||||
800011|223344556677885f5f5f5f5f5f 64 gnu addb $0x11,(%rax)
|
||||
800011|223344556677885f5f5f5f5f5f 64 intel add byte ptr [rax], 0x11
|
||||
800011|223344556677885f5f5f5f5f5f 64 plan9 ADDL $0x11, 0(AX)
|
||||
800011|223344556677885f5f5f5f5f5f 64 plan9 ADDB $0x11, 0(AX)
|
||||
800811|223344556677885f5f5f5f5f5f 32 intel or byte ptr [eax], 0x11
|
||||
800811|223344556677885f5f5f5f5f5f 32 plan9 ORL $0x11, 0(AX)
|
||||
800811|223344556677885f5f5f5f5f5f 32 plan9 ORB $0x11, 0(AX)
|
||||
800811|223344556677885f5f5f5f5f5f 64 gnu orb $0x11,(%rax)
|
||||
800811|223344556677885f5f5f5f5f5f 64 intel or byte ptr [rax], 0x11
|
||||
800811|223344556677885f5f5f5f5f5f 64 plan9 ORL $0x11, 0(AX)
|
||||
800811|223344556677885f5f5f5f5f5f 64 plan9 ORB $0x11, 0(AX)
|
||||
801122|3344556677885f5f5f5f5f5f5f 32 intel adc byte ptr [ecx], 0x22
|
||||
801122|3344556677885f5f5f5f5f5f5f 32 plan9 ADCL $0x22, 0(CX)
|
||||
801122|3344556677885f5f5f5f5f5f5f 32 plan9 ADCB $0x22, 0(CX)
|
||||
801122|3344556677885f5f5f5f5f5f5f 64 gnu adcb $0x22,(%rcx)
|
||||
801122|3344556677885f5f5f5f5f5f5f 64 intel adc byte ptr [rcx], 0x22
|
||||
801122|3344556677885f5f5f5f5f5f5f 64 plan9 ADCL $0x22, 0(CX)
|
||||
801122|3344556677885f5f5f5f5f5f5f 64 plan9 ADCB $0x22, 0(CX)
|
||||
801811|223344556677885f5f5f5f5f5f 32 intel sbb byte ptr [eax], 0x11
|
||||
801811|223344556677885f5f5f5f5f5f 32 plan9 SBBL $0x11, 0(AX)
|
||||
801811|223344556677885f5f5f5f5f5f 32 plan9 SBBB $0x11, 0(AX)
|
||||
801811|223344556677885f5f5f5f5f5f 64 gnu sbbb $0x11,(%rax)
|
||||
801811|223344556677885f5f5f5f5f5f 64 intel sbb byte ptr [rax], 0x11
|
||||
801811|223344556677885f5f5f5f5f5f 64 plan9 SBBL $0x11, 0(AX)
|
||||
801811|223344556677885f5f5f5f5f5f 64 plan9 SBBB $0x11, 0(AX)
|
||||
802011|223344556677885f5f5f5f5f5f 32 intel and byte ptr [eax], 0x11
|
||||
802011|223344556677885f5f5f5f5f5f 32 plan9 ANDL $0x11, 0(AX)
|
||||
802011|223344556677885f5f5f5f5f5f 32 plan9 ANDB $0x11, 0(AX)
|
||||
802011|223344556677885f5f5f5f5f5f 64 gnu andb $0x11,(%rax)
|
||||
802011|223344556677885f5f5f5f5f5f 64 intel and byte ptr [rax], 0x11
|
||||
802011|223344556677885f5f5f5f5f5f 64 plan9 ANDL $0x11, 0(AX)
|
||||
802011|223344556677885f5f5f5f5f5f 64 plan9 ANDB $0x11, 0(AX)
|
||||
802811|223344556677885f5f5f5f5f5f 32 intel sub byte ptr [eax], 0x11
|
||||
802811|223344556677885f5f5f5f5f5f 32 plan9 SUBL $0x11, 0(AX)
|
||||
802811|223344556677885f5f5f5f5f5f 32 plan9 SUBB $0x11, 0(AX)
|
||||
802811|223344556677885f5f5f5f5f5f 64 gnu subb $0x11,(%rax)
|
||||
802811|223344556677885f5f5f5f5f5f 64 intel sub byte ptr [rax], 0x11
|
||||
802811|223344556677885f5f5f5f5f5f 64 plan9 SUBL $0x11, 0(AX)
|
||||
802811|223344556677885f5f5f5f5f5f 64 plan9 SUBB $0x11, 0(AX)
|
||||
803011|223344556677885f5f5f5f5f5f 32 intel xor byte ptr [eax], 0x11
|
||||
803011|223344556677885f5f5f5f5f5f 32 plan9 XORL $0x11, 0(AX)
|
||||
803011|223344556677885f5f5f5f5f5f 32 plan9 XORB $0x11, 0(AX)
|
||||
803011|223344556677885f5f5f5f5f5f 64 gnu xorb $0x11,(%rax)
|
||||
803011|223344556677885f5f5f5f5f5f 64 intel xor byte ptr [rax], 0x11
|
||||
803011|223344556677885f5f5f5f5f5f 64 plan9 XORL $0x11, 0(AX)
|
||||
803011|223344556677885f5f5f5f5f5f 64 plan9 XORB $0x11, 0(AX)
|
||||
803811|223344556677885f5f5f5f5f5f 32 intel cmp byte ptr [eax], 0x11
|
||||
803811|223344556677885f5f5f5f5f5f 32 plan9 CMPL $0x11, 0(AX)
|
||||
803811|223344556677885f5f5f5f5f5f 32 plan9 CMPB $0x11, 0(AX)
|
||||
803811|223344556677885f5f5f5f5f5f 64 gnu cmpb $0x11,(%rax)
|
||||
803811|223344556677885f5f5f5f5f5f 64 intel cmp byte ptr [rax], 0x11
|
||||
803811|223344556677885f5f5f5f5f5f 64 plan9 CMPL $0x11, 0(AX)
|
||||
803811|223344556677885f5f5f5f5f5f 64 plan9 CMPB $0x11, 0(AX)
|
||||
810011223344|556677885f5f5f5f5f5f 32 intel add dword ptr [eax], 0x44332211
|
||||
810011223344|556677885f5f5f5f5f5f 32 plan9 ADDL $0x44332211, 0(AX)
|
||||
810011223344|556677885f5f5f5f5f5f 64 gnu addl $0x44332211,(%rax)
|
||||
@ -5037,65 +5039,65 @@
|
||||
833811|223344556677885f5f5f5f5f5f 64 intel cmp dword ptr [rax], 0x11
|
||||
833811|223344556677885f5f5f5f5f5f 64 plan9 CMPL $0x11, 0(AX)
|
||||
8411|223344556677885f5f5f5f5f5f5f 32 intel test byte ptr [ecx], dl
|
||||
8411|223344556677885f5f5f5f5f5f5f 32 plan9 TESTL DL, 0(CX)
|
||||
8411|223344556677885f5f5f5f5f5f5f 32 plan9 TESTB DL, 0(CX)
|
||||
8411|223344556677885f5f5f5f5f5f5f 64 gnu test %dl,(%rcx)
|
||||
8411|223344556677885f5f5f5f5f5f5f 64 intel test byte ptr [rcx], dl
|
||||
8411|223344556677885f5f5f5f5f5f5f 64 plan9 TESTL DL, 0(CX)
|
||||
8411|223344556677885f5f5f5f5f5f5f 64 plan9 TESTB DL, 0(CX)
|
||||
8511|223344556677885f5f5f5f5f5f5f 32 intel test dword ptr [ecx], edx
|
||||
8511|223344556677885f5f5f5f5f5f5f 32 plan9 TESTL DX, 0(CX)
|
||||
8511|223344556677885f5f5f5f5f5f5f 64 gnu test %edx,(%rcx)
|
||||
8511|223344556677885f5f5f5f5f5f5f 64 intel test dword ptr [rcx], edx
|
||||
8511|223344556677885f5f5f5f5f5f5f 64 plan9 TESTL DX, 0(CX)
|
||||
8611|223344556677885f5f5f5f5f5f5f 32 intel xchg byte ptr [ecx], dl
|
||||
8611|223344556677885f5f5f5f5f5f5f 32 plan9 XCHGL DL, 0(CX)
|
||||
8611|223344556677885f5f5f5f5f5f5f 32 plan9 XCHGB DL, 0(CX)
|
||||
8611|223344556677885f5f5f5f5f5f5f 64 gnu xchg %dl,(%rcx)
|
||||
8611|223344556677885f5f5f5f5f5f5f 64 intel xchg byte ptr [rcx], dl
|
||||
8611|223344556677885f5f5f5f5f5f5f 64 plan9 XCHGL DL, 0(CX)
|
||||
8611|223344556677885f5f5f5f5f5f5f 64 plan9 XCHGB DL, 0(CX)
|
||||
8711|223344556677885f5f5f5f5f5f5f 32 intel xchg dword ptr [ecx], edx
|
||||
8711|223344556677885f5f5f5f5f5f5f 32 plan9 XCHGL DX, 0(CX)
|
||||
8711|223344556677885f5f5f5f5f5f5f 64 gnu xchg %edx,(%rcx)
|
||||
8711|223344556677885f5f5f5f5f5f5f 64 intel xchg dword ptr [rcx], edx
|
||||
8711|223344556677885f5f5f5f5f5f5f 64 plan9 XCHGL DX, 0(CX)
|
||||
8811|223344556677885f5f5f5f5f5f5f 32 intel mov byte ptr [ecx], dl
|
||||
8811|223344556677885f5f5f5f5f5f5f 32 plan9 MOVL DL, 0(CX)
|
||||
8811|223344556677885f5f5f5f5f5f5f 32 plan9 MOVB DL, 0(CX)
|
||||
8811|223344556677885f5f5f5f5f5f5f 64 gnu mov %dl,(%rcx)
|
||||
8811|223344556677885f5f5f5f5f5f5f 64 intel mov byte ptr [rcx], dl
|
||||
8811|223344556677885f5f5f5f5f5f5f 64 plan9 MOVL DL, 0(CX)
|
||||
8811|223344556677885f5f5f5f5f5f5f 64 plan9 MOVB DL, 0(CX)
|
||||
8911|223344556677885f5f5f5f5f5f5f 32 intel mov dword ptr [ecx], edx
|
||||
8911|223344556677885f5f5f5f5f5f5f 32 plan9 MOVL DX, 0(CX)
|
||||
8911|223344556677885f5f5f5f5f5f5f 64 gnu mov %edx,(%rcx)
|
||||
8911|223344556677885f5f5f5f5f5f5f 64 intel mov dword ptr [rcx], edx
|
||||
8911|223344556677885f5f5f5f5f5f5f 64 plan9 MOVL DX, 0(CX)
|
||||
8a11|223344556677885f5f5f5f5f5f5f 32 intel mov dl, byte ptr [ecx]
|
||||
8a11|223344556677885f5f5f5f5f5f5f 32 plan9 MOVL 0(CX), DL
|
||||
8a11|223344556677885f5f5f5f5f5f5f 32 plan9 MOVB 0(CX), DL
|
||||
8a11|223344556677885f5f5f5f5f5f5f 64 gnu mov (%rcx),%dl
|
||||
8a11|223344556677885f5f5f5f5f5f5f 64 intel mov dl, byte ptr [rcx]
|
||||
8a11|223344556677885f5f5f5f5f5f5f 64 plan9 MOVL 0(CX), DL
|
||||
8a11|223344556677885f5f5f5f5f5f5f 64 plan9 MOVB 0(CX), DL
|
||||
8b11|223344556677885f5f5f5f5f5f5f 32 intel mov edx, dword ptr [ecx]
|
||||
8b11|223344556677885f5f5f5f5f5f5f 32 plan9 MOVL 0(CX), DX
|
||||
8b11|223344556677885f5f5f5f5f5f5f 64 gnu mov (%rcx),%edx
|
||||
8b11|223344556677885f5f5f5f5f5f5f 64 intel mov edx, dword ptr [rcx]
|
||||
8b11|223344556677885f5f5f5f5f5f5f 64 plan9 MOVL 0(CX), DX
|
||||
8c11|223344556677885f5f5f5f5f5f5f 32 intel mov word ptr [ecx], ss
|
||||
8c11|223344556677885f5f5f5f5f5f5f 32 plan9 MOVL SS, 0(CX)
|
||||
8c11|223344556677885f5f5f5f5f5f5f 32 plan9 MOVW SS, 0(CX)
|
||||
8c11|223344556677885f5f5f5f5f5f5f 64 gnu mov %ss,(%rcx)
|
||||
8c11|223344556677885f5f5f5f5f5f5f 64 intel mov word ptr [rcx], ss
|
||||
8c11|223344556677885f5f5f5f5f5f5f 64 plan9 MOVL SS, 0(CX)
|
||||
8c11|223344556677885f5f5f5f5f5f5f 64 plan9 MOVW SS, 0(CX)
|
||||
8d11|223344556677885f5f5f5f5f5f5f 32 intel lea edx, ptr [ecx]
|
||||
8d11|223344556677885f5f5f5f5f5f5f 32 plan9 LEAL 0(CX), DX
|
||||
8d11|223344556677885f5f5f5f5f5f5f 64 gnu lea (%rcx),%edx
|
||||
8d11|223344556677885f5f5f5f5f5f5f 64 intel lea edx, ptr [rcx]
|
||||
8d11|223344556677885f5f5f5f5f5f5f 64 plan9 LEAL 0(CX), DX
|
||||
8e11|223344556677885f5f5f5f5f5f5f 32 intel mov ss, word ptr [ecx]
|
||||
8e11|223344556677885f5f5f5f5f5f5f 32 plan9 MOVL 0(CX), SS
|
||||
8e11|223344556677885f5f5f5f5f5f5f 32 plan9 MOVW 0(CX), SS
|
||||
8e11|223344556677885f5f5f5f5f5f5f 64 gnu mov (%rcx),%ss
|
||||
8e11|223344556677885f5f5f5f5f5f5f 64 intel mov ss, word ptr [rcx]
|
||||
8e11|223344556677885f5f5f5f5f5f5f 64 plan9 MOVL 0(CX), SS
|
||||
8e11|223344556677885f5f5f5f5f5f5f 64 plan9 MOVW 0(CX), SS
|
||||
8f00|11223344556677885f5f5f5f5f5f 32 intel pop dword ptr [eax]
|
||||
8f00|11223344556677885f5f5f5f5f5f 32 plan9 POPL 0(AX)
|
||||
8f00|11223344556677885f5f5f5f5f5f 64 gnu popq (%rax)
|
||||
8f00|11223344556677885f5f5f5f5f5f 64 intel pop qword ptr [rax]
|
||||
8f00|11223344556677885f5f5f5f5f5f 64 plan9 POPL 0(AX)
|
||||
8f00|11223344556677885f5f5f5f5f5f 64 plan9 POPQ 0(AX)
|
||||
91|11223344556677885f5f5f5f5f5f5f 32 intel xchg ecx, eax
|
||||
91|11223344556677885f5f5f5f5f5f5f 32 plan9 XCHGL AX, CX
|
||||
91|11223344556677885f5f5f5f5f5f5f 64 intel xchg ecx, eax
|
||||
@ -5144,9 +5146,9 @@ a111223344|556677885f5f5f5f5f5f5f 32 intel mov eax, dword ptr [0x44332211]
|
||||
a111223344|556677885f5f5f5f5f5f5f 32 plan9 MOVL 0x44332211, AX
|
||||
a21122334455667788|5f5f5f5f5f5f5f 64 gnu mov %al,-0x778899aabbccddef
|
||||
a21122334455667788|5f5f5f5f5f5f5f 64 intel mov byte ptr [0x8877665544332211], al
|
||||
a21122334455667788|5f5f5f5f5f5f5f 64 plan9 MOVL AL, -0x778899aabbccddef
|
||||
a21122334455667788|5f5f5f5f5f5f5f 64 plan9 MOVB AL, -0x778899aabbccddef
|
||||
a211223344|556677885f5f5f5f5f5f5f 32 intel mov byte ptr [0x44332211], al
|
||||
a211223344|556677885f5f5f5f5f5f5f 32 plan9 MOVL AL, 0x44332211
|
||||
a211223344|556677885f5f5f5f5f5f5f 32 plan9 MOVB AL, 0x44332211
|
||||
a31122334455667788|5f5f5f5f5f5f5f 64 gnu mov %eax,-0x778899aabbccddef
|
||||
a31122334455667788|5f5f5f5f5f5f5f 64 intel mov dword ptr [0x8877665544332211], eax
|
||||
a31122334455667788|5f5f5f5f5f5f5f 64 plan9 MOVL AX, -0x778899aabbccddef
|
||||
@ -5223,40 +5225,40 @@ b811223344|556677885f5f5f5f5f5f5f 64 gnu mov $0x44332211,%eax
|
||||
b811223344|556677885f5f5f5f5f5f5f 64 intel mov eax, 0x44332211
|
||||
b811223344|556677885f5f5f5f5f5f5f 64 plan9 MOVL $0x44332211, AX
|
||||
c00011|223344556677885f5f5f5f5f5f 32 intel rol byte ptr [eax], 0x11
|
||||
c00011|223344556677885f5f5f5f5f5f 32 plan9 ROLL $0x11, 0(AX)
|
||||
c00011|223344556677885f5f5f5f5f5f 32 plan9 ROLB $0x11, 0(AX)
|
||||
c00011|223344556677885f5f5f5f5f5f 64 gnu rolb $0x11,(%rax)
|
||||
c00011|223344556677885f5f5f5f5f5f 64 intel rol byte ptr [rax], 0x11
|
||||
c00011|223344556677885f5f5f5f5f5f 64 plan9 ROLL $0x11, 0(AX)
|
||||
c00011|223344556677885f5f5f5f5f5f 64 plan9 ROLB $0x11, 0(AX)
|
||||
c00811|223344556677885f5f5f5f5f5f 32 intel ror byte ptr [eax], 0x11
|
||||
c00811|223344556677885f5f5f5f5f5f 32 plan9 RORL $0x11, 0(AX)
|
||||
c00811|223344556677885f5f5f5f5f5f 32 plan9 RORB $0x11, 0(AX)
|
||||
c00811|223344556677885f5f5f5f5f5f 64 gnu rorb $0x11,(%rax)
|
||||
c00811|223344556677885f5f5f5f5f5f 64 intel ror byte ptr [rax], 0x11
|
||||
c00811|223344556677885f5f5f5f5f5f 64 plan9 RORL $0x11, 0(AX)
|
||||
c00811|223344556677885f5f5f5f5f5f 64 plan9 RORB $0x11, 0(AX)
|
||||
c01122|3344556677885f5f5f5f5f5f5f 32 intel rcl byte ptr [ecx], 0x22
|
||||
c01122|3344556677885f5f5f5f5f5f5f 32 plan9 RCLL $0x22, 0(CX)
|
||||
c01122|3344556677885f5f5f5f5f5f5f 32 plan9 RCLB $0x22, 0(CX)
|
||||
c01122|3344556677885f5f5f5f5f5f5f 64 gnu rclb $0x22,(%rcx)
|
||||
c01122|3344556677885f5f5f5f5f5f5f 64 intel rcl byte ptr [rcx], 0x22
|
||||
c01122|3344556677885f5f5f5f5f5f5f 64 plan9 RCLL $0x22, 0(CX)
|
||||
c01122|3344556677885f5f5f5f5f5f5f 64 plan9 RCLB $0x22, 0(CX)
|
||||
c01811|223344556677885f5f5f5f5f5f 32 intel rcr byte ptr [eax], 0x11
|
||||
c01811|223344556677885f5f5f5f5f5f 32 plan9 RCRL $0x11, 0(AX)
|
||||
c01811|223344556677885f5f5f5f5f5f 32 plan9 RCRB $0x11, 0(AX)
|
||||
c01811|223344556677885f5f5f5f5f5f 64 gnu rcrb $0x11,(%rax)
|
||||
c01811|223344556677885f5f5f5f5f5f 64 intel rcr byte ptr [rax], 0x11
|
||||
c01811|223344556677885f5f5f5f5f5f 64 plan9 RCRL $0x11, 0(AX)
|
||||
c01811|223344556677885f5f5f5f5f5f 64 plan9 RCRB $0x11, 0(AX)
|
||||
c02011|223344556677885f5f5f5f5f5f 32 intel shl byte ptr [eax], 0x11
|
||||
c02011|223344556677885f5f5f5f5f5f 32 plan9 SHLL $0x11, 0(AX)
|
||||
c02011|223344556677885f5f5f5f5f5f 32 plan9 SHLB $0x11, 0(AX)
|
||||
c02011|223344556677885f5f5f5f5f5f 64 gnu shlb $0x11,(%rax)
|
||||
c02011|223344556677885f5f5f5f5f5f 64 intel shl byte ptr [rax], 0x11
|
||||
c02011|223344556677885f5f5f5f5f5f 64 plan9 SHLL $0x11, 0(AX)
|
||||
c02011|223344556677885f5f5f5f5f5f 64 plan9 SHLB $0x11, 0(AX)
|
||||
c02811|223344556677885f5f5f5f5f5f 32 intel shr byte ptr [eax], 0x11
|
||||
c02811|223344556677885f5f5f5f5f5f 32 plan9 SHRL $0x11, 0(AX)
|
||||
c02811|223344556677885f5f5f5f5f5f 32 plan9 SHRB $0x11, 0(AX)
|
||||
c02811|223344556677885f5f5f5f5f5f 64 gnu shrb $0x11,(%rax)
|
||||
c02811|223344556677885f5f5f5f5f5f 64 intel shr byte ptr [rax], 0x11
|
||||
c02811|223344556677885f5f5f5f5f5f 64 plan9 SHRL $0x11, 0(AX)
|
||||
c02811|223344556677885f5f5f5f5f5f 64 plan9 SHRB $0x11, 0(AX)
|
||||
c03811|223344556677885f5f5f5f5f5f 32 intel sar byte ptr [eax], 0x11
|
||||
c03811|223344556677885f5f5f5f5f5f 32 plan9 SARL $0x11, 0(AX)
|
||||
c03811|223344556677885f5f5f5f5f5f 32 plan9 SARB $0x11, 0(AX)
|
||||
c03811|223344556677885f5f5f5f5f5f 64 gnu sarb $0x11,(%rax)
|
||||
c03811|223344556677885f5f5f5f5f5f 64 intel sar byte ptr [rax], 0x11
|
||||
c03811|223344556677885f5f5f5f5f5f 64 plan9 SARL $0x11, 0(AX)
|
||||
c03811|223344556677885f5f5f5f5f5f 64 plan9 SARB $0x11, 0(AX)
|
||||
c10011|223344556677885f5f5f5f5f5f 32 intel rol dword ptr [eax], 0x11
|
||||
c10011|223344556677885f5f5f5f5f5f 32 plan9 ROLL $0x11, 0(AX)
|
||||
c10011|223344556677885f5f5f5f5f5f 64 gnu roll $0x11,(%rax)
|
||||
@ -5302,10 +5304,10 @@ c411|223344556677885f5f5f5f5f5f5f 32 plan9 LES 0(CX), DX
|
||||
c511|223344556677885f5f5f5f5f5f5f 32 intel lds edx, ptr [ecx]
|
||||
c511|223344556677885f5f5f5f5f5f5f 32 plan9 LDS 0(CX), DX
|
||||
c60011|223344556677885f5f5f5f5f5f 32 intel mov byte ptr [eax], 0x11
|
||||
c60011|223344556677885f5f5f5f5f5f 32 plan9 MOVL $0x11, 0(AX)
|
||||
c60011|223344556677885f5f5f5f5f5f 32 plan9 MOVB $0x11, 0(AX)
|
||||
c60011|223344556677885f5f5f5f5f5f 64 gnu movb $0x11,(%rax)
|
||||
c60011|223344556677885f5f5f5f5f5f 64 intel mov byte ptr [rax], 0x11
|
||||
c60011|223344556677885f5f5f5f5f5f 64 plan9 MOVL $0x11, 0(AX)
|
||||
c60011|223344556677885f5f5f5f5f5f 64 plan9 MOVB $0x11, 0(AX)
|
||||
c6f811|223344556677885f5f5f5f5f5f 32 intel xabort 0x11
|
||||
c6f811|223344556677885f5f5f5f5f5f 32 plan9 XABORT $0x11
|
||||
c6f811|223344556677885f5f5f5f5f5f 64 gnu xabort $0x11
|
||||
@ -5362,40 +5364,40 @@ cf|11223344556677885f5f5f5f5f5f5f 64 gnu iret
|
||||
cf|11223344556677885f5f5f5f5f5f5f 64 intel iretd
|
||||
cf|11223344556677885f5f5f5f5f5f5f 64 plan9 IRETD
|
||||
d000|11223344556677885f5f5f5f5f5f 32 intel rol byte ptr [eax], 0x1
|
||||
d000|11223344556677885f5f5f5f5f5f 32 plan9 ROLL $0x1, 0(AX)
|
||||
d000|11223344556677885f5f5f5f5f5f 32 plan9 ROLB $0x1, 0(AX)
|
||||
d000|11223344556677885f5f5f5f5f5f 64 gnu rolb (%rax)
|
||||
d000|11223344556677885f5f5f5f5f5f 64 intel rol byte ptr [rax], 0x1
|
||||
d000|11223344556677885f5f5f5f5f5f 64 plan9 ROLL $0x1, 0(AX)
|
||||
d000|11223344556677885f5f5f5f5f5f 64 plan9 ROLB $0x1, 0(AX)
|
||||
d008|11223344556677885f5f5f5f5f5f 32 intel ror byte ptr [eax], 0x1
|
||||
d008|11223344556677885f5f5f5f5f5f 32 plan9 RORL $0x1, 0(AX)
|
||||
d008|11223344556677885f5f5f5f5f5f 32 plan9 RORB $0x1, 0(AX)
|
||||
d008|11223344556677885f5f5f5f5f5f 64 gnu rorb (%rax)
|
||||
d008|11223344556677885f5f5f5f5f5f 64 intel ror byte ptr [rax], 0x1
|
||||
d008|11223344556677885f5f5f5f5f5f 64 plan9 RORL $0x1, 0(AX)
|
||||
d008|11223344556677885f5f5f5f5f5f 64 plan9 RORB $0x1, 0(AX)
|
||||
d011|223344556677885f5f5f5f5f5f5f 32 intel rcl byte ptr [ecx], 0x1
|
||||
d011|223344556677885f5f5f5f5f5f5f 32 plan9 RCLL $0x1, 0(CX)
|
||||
d011|223344556677885f5f5f5f5f5f5f 32 plan9 RCLB $0x1, 0(CX)
|
||||
d011|223344556677885f5f5f5f5f5f5f 64 gnu rclb (%rcx)
|
||||
d011|223344556677885f5f5f5f5f5f5f 64 intel rcl byte ptr [rcx], 0x1
|
||||
d011|223344556677885f5f5f5f5f5f5f 64 plan9 RCLL $0x1, 0(CX)
|
||||
d011|223344556677885f5f5f5f5f5f5f 64 plan9 RCLB $0x1, 0(CX)
|
||||
d018|11223344556677885f5f5f5f5f5f 32 intel rcr byte ptr [eax], 0x1
|
||||
d018|11223344556677885f5f5f5f5f5f 32 plan9 RCRL $0x1, 0(AX)
|
||||
d018|11223344556677885f5f5f5f5f5f 32 plan9 RCRB $0x1, 0(AX)
|
||||
d018|11223344556677885f5f5f5f5f5f 64 gnu rcrb (%rax)
|
||||
d018|11223344556677885f5f5f5f5f5f 64 intel rcr byte ptr [rax], 0x1
|
||||
d018|11223344556677885f5f5f5f5f5f 64 plan9 RCRL $0x1, 0(AX)
|
||||
d018|11223344556677885f5f5f5f5f5f 64 plan9 RCRB $0x1, 0(AX)
|
||||
d020|11223344556677885f5f5f5f5f5f 32 intel shl byte ptr [eax], 0x1
|
||||
d020|11223344556677885f5f5f5f5f5f 32 plan9 SHLL $0x1, 0(AX)
|
||||
d020|11223344556677885f5f5f5f5f5f 32 plan9 SHLB $0x1, 0(AX)
|
||||
d020|11223344556677885f5f5f5f5f5f 64 gnu shlb (%rax)
|
||||
d020|11223344556677885f5f5f5f5f5f 64 intel shl byte ptr [rax], 0x1
|
||||
d020|11223344556677885f5f5f5f5f5f 64 plan9 SHLL $0x1, 0(AX)
|
||||
d020|11223344556677885f5f5f5f5f5f 64 plan9 SHLB $0x1, 0(AX)
|
||||
d028|11223344556677885f5f5f5f5f5f 32 intel shr byte ptr [eax], 0x1
|
||||
d028|11223344556677885f5f5f5f5f5f 32 plan9 SHRL $0x1, 0(AX)
|
||||
d028|11223344556677885f5f5f5f5f5f 32 plan9 SHRB $0x1, 0(AX)
|
||||
d028|11223344556677885f5f5f5f5f5f 64 gnu shrb (%rax)
|
||||
d028|11223344556677885f5f5f5f5f5f 64 intel shr byte ptr [rax], 0x1
|
||||
d028|11223344556677885f5f5f5f5f5f 64 plan9 SHRL $0x1, 0(AX)
|
||||
d028|11223344556677885f5f5f5f5f5f 64 plan9 SHRB $0x1, 0(AX)
|
||||
d038|11223344556677885f5f5f5f5f5f 32 intel sar byte ptr [eax], 0x1
|
||||
d038|11223344556677885f5f5f5f5f5f 32 plan9 SARL $0x1, 0(AX)
|
||||
d038|11223344556677885f5f5f5f5f5f 32 plan9 SARB $0x1, 0(AX)
|
||||
d038|11223344556677885f5f5f5f5f5f 64 gnu sarb (%rax)
|
||||
d038|11223344556677885f5f5f5f5f5f 64 intel sar byte ptr [rax], 0x1
|
||||
d038|11223344556677885f5f5f5f5f5f 64 plan9 SARL $0x1, 0(AX)
|
||||
d038|11223344556677885f5f5f5f5f5f 64 plan9 SARB $0x1, 0(AX)
|
||||
d100|11223344556677885f5f5f5f5f5f 32 intel rol dword ptr [eax], 0x1
|
||||
d100|11223344556677885f5f5f5f5f5f 32 plan9 ROLL $0x1, 0(AX)
|
||||
d100|11223344556677885f5f5f5f5f5f 64 gnu roll (%rax)
|
||||
@ -5432,40 +5434,40 @@ d138|11223344556677885f5f5f5f5f5f 64 gnu sarl (%rax)
|
||||
d138|11223344556677885f5f5f5f5f5f 64 intel sar dword ptr [rax], 0x1
|
||||
d138|11223344556677885f5f5f5f5f5f 64 plan9 SARL $0x1, 0(AX)
|
||||
d200|11223344556677885f5f5f5f5f5f 32 intel rol byte ptr [eax], cl
|
||||
d200|11223344556677885f5f5f5f5f5f 32 plan9 ROLL CL, 0(AX)
|
||||
d200|11223344556677885f5f5f5f5f5f 32 plan9 ROLB CL, 0(AX)
|
||||
d200|11223344556677885f5f5f5f5f5f 64 gnu rolb %cl,(%rax)
|
||||
d200|11223344556677885f5f5f5f5f5f 64 intel rol byte ptr [rax], cl
|
||||
d200|11223344556677885f5f5f5f5f5f 64 plan9 ROLL CL, 0(AX)
|
||||
d200|11223344556677885f5f5f5f5f5f 64 plan9 ROLB CL, 0(AX)
|
||||
d208|11223344556677885f5f5f5f5f5f 32 intel ror byte ptr [eax], cl
|
||||
d208|11223344556677885f5f5f5f5f5f 32 plan9 RORL CL, 0(AX)
|
||||
d208|11223344556677885f5f5f5f5f5f 32 plan9 RORB CL, 0(AX)
|
||||
d208|11223344556677885f5f5f5f5f5f 64 gnu rorb %cl,(%rax)
|
||||
d208|11223344556677885f5f5f5f5f5f 64 intel ror byte ptr [rax], cl
|
||||
d208|11223344556677885f5f5f5f5f5f 64 plan9 RORL CL, 0(AX)
|
||||
d208|11223344556677885f5f5f5f5f5f 64 plan9 RORB CL, 0(AX)
|
||||
d211|223344556677885f5f5f5f5f5f5f 32 intel rcl byte ptr [ecx], cl
|
||||
d211|223344556677885f5f5f5f5f5f5f 32 plan9 RCLL CL, 0(CX)
|
||||
d211|223344556677885f5f5f5f5f5f5f 32 plan9 RCLB CL, 0(CX)
|
||||
d211|223344556677885f5f5f5f5f5f5f 64 gnu rclb %cl,(%rcx)
|
||||
d211|223344556677885f5f5f5f5f5f5f 64 intel rcl byte ptr [rcx], cl
|
||||
d211|223344556677885f5f5f5f5f5f5f 64 plan9 RCLL CL, 0(CX)
|
||||
d211|223344556677885f5f5f5f5f5f5f 64 plan9 RCLB CL, 0(CX)
|
||||
d218|11223344556677885f5f5f5f5f5f 32 intel rcr byte ptr [eax], cl
|
||||
d218|11223344556677885f5f5f5f5f5f 32 plan9 RCRL CL, 0(AX)
|
||||
d218|11223344556677885f5f5f5f5f5f 32 plan9 RCRB CL, 0(AX)
|
||||
d218|11223344556677885f5f5f5f5f5f 64 gnu rcrb %cl,(%rax)
|
||||
d218|11223344556677885f5f5f5f5f5f 64 intel rcr byte ptr [rax], cl
|
||||
d218|11223344556677885f5f5f5f5f5f 64 plan9 RCRL CL, 0(AX)
|
||||
d218|11223344556677885f5f5f5f5f5f 64 plan9 RCRB CL, 0(AX)
|
||||
d220|11223344556677885f5f5f5f5f5f 32 intel shl byte ptr [eax], cl
|
||||
d220|11223344556677885f5f5f5f5f5f 32 plan9 SHLL CL, 0(AX)
|
||||
d220|11223344556677885f5f5f5f5f5f 32 plan9 SHLB CL, 0(AX)
|
||||
d220|11223344556677885f5f5f5f5f5f 64 gnu shlb %cl,(%rax)
|
||||
d220|11223344556677885f5f5f5f5f5f 64 intel shl byte ptr [rax], cl
|
||||
d220|11223344556677885f5f5f5f5f5f 64 plan9 SHLL CL, 0(AX)
|
||||
d220|11223344556677885f5f5f5f5f5f 64 plan9 SHLB CL, 0(AX)
|
||||
d228|11223344556677885f5f5f5f5f5f 32 intel shr byte ptr [eax], cl
|
||||
d228|11223344556677885f5f5f5f5f5f 32 plan9 SHRL CL, 0(AX)
|
||||
d228|11223344556677885f5f5f5f5f5f 32 plan9 SHRB CL, 0(AX)
|
||||
d228|11223344556677885f5f5f5f5f5f 64 gnu shrb %cl,(%rax)
|
||||
d228|11223344556677885f5f5f5f5f5f 64 intel shr byte ptr [rax], cl
|
||||
d228|11223344556677885f5f5f5f5f5f 64 plan9 SHRL CL, 0(AX)
|
||||
d228|11223344556677885f5f5f5f5f5f 64 plan9 SHRB CL, 0(AX)
|
||||
d238|11223344556677885f5f5f5f5f5f 32 intel sar byte ptr [eax], cl
|
||||
d238|11223344556677885f5f5f5f5f5f 32 plan9 SARL CL, 0(AX)
|
||||
d238|11223344556677885f5f5f5f5f5f 32 plan9 SARB CL, 0(AX)
|
||||
d238|11223344556677885f5f5f5f5f5f 64 gnu sarb %cl,(%rax)
|
||||
d238|11223344556677885f5f5f5f5f5f 64 intel sar byte ptr [rax], cl
|
||||
d238|11223344556677885f5f5f5f5f5f 64 plan9 SARL CL, 0(AX)
|
||||
d238|11223344556677885f5f5f5f5f5f 64 plan9 SARB CL, 0(AX)
|
||||
d300|11223344556677885f5f5f5f5f5f 32 intel rol dword ptr [eax], cl
|
||||
d300|11223344556677885f5f5f5f5f5f 32 plan9 ROLL CL, 0(AX)
|
||||
d300|11223344556677885f5f5f5f5f5f 64 gnu roll %cl,(%rax)
|
||||
@ -6254,15 +6256,15 @@ f20f2a11|223344556677885f5f5f5f5f 64 gnu cvtsi2sdl (%rcx),%xmm2
|
||||
f20f2a11|223344556677885f5f5f5f5f 64 intel cvtsi2sd xmm2, dword ptr [rcx]
|
||||
f20f2a11|223344556677885f5f5f5f5f 64 plan9 REPNE CVTSI2SDL 0(CX), X2
|
||||
f20f2c11|223344556677885f5f5f5f5f 32 intel cvttsd2si edx, qword ptr [ecx]
|
||||
f20f2c11|223344556677885f5f5f5f5f 32 plan9 REPNE CVTTSD2SIL 0(CX), DX
|
||||
f20f2c11|223344556677885f5f5f5f5f 32 plan9 REPNE CVTTSD2SIQ 0(CX), DX
|
||||
f20f2c11|223344556677885f5f5f5f5f 64 gnu cvttsd2si (%rcx),%edx
|
||||
f20f2c11|223344556677885f5f5f5f5f 64 intel cvttsd2si edx, qword ptr [rcx]
|
||||
f20f2c11|223344556677885f5f5f5f5f 64 plan9 REPNE CVTTSD2SIL 0(CX), DX
|
||||
f20f2c11|223344556677885f5f5f5f5f 64 plan9 REPNE CVTTSD2SIQ 0(CX), DX
|
||||
f20f2d11|223344556677885f5f5f5f5f 32 intel cvtsd2si edx, qword ptr [ecx]
|
||||
f20f2d11|223344556677885f5f5f5f5f 32 plan9 REPNE CVTSD2SIL 0(CX), DX
|
||||
f20f2d11|223344556677885f5f5f5f5f 32 plan9 REPNE CVTSD2SIQ 0(CX), DX
|
||||
f20f2d11|223344556677885f5f5f5f5f 64 gnu cvtsd2si (%rcx),%edx
|
||||
f20f2d11|223344556677885f5f5f5f5f 64 intel cvtsd2si edx, qword ptr [rcx]
|
||||
f20f2d11|223344556677885f5f5f5f5f 64 plan9 REPNE CVTSD2SIL 0(CX), DX
|
||||
f20f2d11|223344556677885f5f5f5f5f 64 plan9 REPNE CVTSD2SIQ 0(CX), DX
|
||||
f20f38f011|223344556677885f5f5f5f 32 intel crc32 edx, byte ptr [ecx]
|
||||
f20f38f011|223344556677885f5f5f5f 32 plan9 REPNE CRC32 0(CX), DX
|
||||
f20f38f011|223344556677885f5f5f5f 64 gnu crc32b (%rcx),%edx
|
||||
@ -6530,10 +6532,10 @@ f3480f2a11|223344556677885f5f5f5f 64 intel cvtsi2ss xmm2, qword ptr [rcx]
|
||||
f3480f2a11|223344556677885f5f5f5f 64 plan9 REP CVTSI2SSQ 0(CX), X2
|
||||
f3480f2c11|223344556677885f5f5f5f 64 gnu cvttss2si (%rcx),%rdx
|
||||
f3480f2c11|223344556677885f5f5f5f 64 intel cvttss2si rdx, dword ptr [rcx]
|
||||
f3480f2c11|223344556677885f5f5f5f 64 plan9 REP CVTTSS2SIQ 0(CX), DX
|
||||
f3480f2c11|223344556677885f5f5f5f 64 plan9 REP CVTTSS2SIL 0(CX), DX
|
||||
f3480f2d11|223344556677885f5f5f5f 64 gnu cvtss2si (%rcx),%rdx
|
||||
f3480f2d11|223344556677885f5f5f5f 64 intel cvtss2si rdx, dword ptr [rcx]
|
||||
f3480f2d11|223344556677885f5f5f5f 64 plan9 REP CVTSS2SIQ 0(CX), DX
|
||||
f3480f2d11|223344556677885f5f5f5f 64 plan9 REP CVTSS2SIL 0(CX), DX
|
||||
f3480fae11|223344556677885f5f5f5f 64 gnu wrfsbaseq (%rcx)
|
||||
f3480fae11|223344556677885f5f5f5f 64 intel wrfsbase qword ptr [rcx]
|
||||
f3480fae11|223344556677885f5f5f5f 64 plan9 REP WRFSBASE 0(CX)
|
||||
@ -6591,40 +6593,40 @@ f5|11223344556677885f5f5f5f5f5f5f 64 gnu cmc
|
||||
f5|11223344556677885f5f5f5f5f5f5f 64 intel cmc
|
||||
f5|11223344556677885f5f5f5f5f5f5f 64 plan9 CMC
|
||||
f60011|223344556677885f5f5f5f5f5f 32 intel test byte ptr [eax], 0x11
|
||||
f60011|223344556677885f5f5f5f5f5f 32 plan9 TESTL $0x11, 0(AX)
|
||||
f60011|223344556677885f5f5f5f5f5f 32 plan9 TESTB $0x11, 0(AX)
|
||||
f60011|223344556677885f5f5f5f5f5f 64 gnu testb $0x11,(%rax)
|
||||
f60011|223344556677885f5f5f5f5f5f 64 intel test byte ptr [rax], 0x11
|
||||
f60011|223344556677885f5f5f5f5f5f 64 plan9 TESTL $0x11, 0(AX)
|
||||
f60011|223344556677885f5f5f5f5f5f 64 plan9 TESTB $0x11, 0(AX)
|
||||
f611|223344556677885f5f5f5f5f5f5f 32 intel not byte ptr [ecx]
|
||||
f611|223344556677885f5f5f5f5f5f5f 32 plan9 NOTL 0(CX)
|
||||
f611|223344556677885f5f5f5f5f5f5f 32 plan9 NOTB 0(CX)
|
||||
f611|223344556677885f5f5f5f5f5f5f 64 gnu notb (%rcx)
|
||||
f611|223344556677885f5f5f5f5f5f5f 64 intel not byte ptr [rcx]
|
||||
f611|223344556677885f5f5f5f5f5f5f 64 plan9 NOTL 0(CX)
|
||||
f611|223344556677885f5f5f5f5f5f5f 64 plan9 NOTB 0(CX)
|
||||
f618|11223344556677885f5f5f5f5f5f 32 intel neg byte ptr [eax]
|
||||
f618|11223344556677885f5f5f5f5f5f 32 plan9 NEGL 0(AX)
|
||||
f618|11223344556677885f5f5f5f5f5f 32 plan9 NEGB 0(AX)
|
||||
f618|11223344556677885f5f5f5f5f5f 64 gnu negb (%rax)
|
||||
f618|11223344556677885f5f5f5f5f5f 64 intel neg byte ptr [rax]
|
||||
f618|11223344556677885f5f5f5f5f5f 64 plan9 NEGL 0(AX)
|
||||
f618|11223344556677885f5f5f5f5f5f 64 plan9 NEGB 0(AX)
|
||||
f620|11223344556677885f5f5f5f5f5f 32 intel mul byte ptr [eax]
|
||||
f620|11223344556677885f5f5f5f5f5f 32 plan9 MULL 0(AX)
|
||||
f620|11223344556677885f5f5f5f5f5f 32 plan9 MULB 0(AX)
|
||||
f620|11223344556677885f5f5f5f5f5f 64 gnu mulb (%rax)
|
||||
f620|11223344556677885f5f5f5f5f5f 64 intel mul byte ptr [rax]
|
||||
f620|11223344556677885f5f5f5f5f5f 64 plan9 MULL 0(AX)
|
||||
f620|11223344556677885f5f5f5f5f5f 64 plan9 MULB 0(AX)
|
||||
f628|11223344556677885f5f5f5f5f5f 32 intel imul byte ptr [eax]
|
||||
f628|11223344556677885f5f5f5f5f5f 32 plan9 IMULL 0(AX)
|
||||
f628|11223344556677885f5f5f5f5f5f 32 plan9 IMULB 0(AX)
|
||||
f628|11223344556677885f5f5f5f5f5f 64 gnu imulb (%rax)
|
||||
f628|11223344556677885f5f5f5f5f5f 64 intel imul byte ptr [rax]
|
||||
f628|11223344556677885f5f5f5f5f5f 64 plan9 IMULL 0(AX)
|
||||
f628|11223344556677885f5f5f5f5f5f 64 plan9 IMULB 0(AX)
|
||||
f630|11223344556677885f5f5f5f5f5f 32 intel div byte ptr [eax]
|
||||
f630|11223344556677885f5f5f5f5f5f 32 plan9 DIVL 0(AX)
|
||||
f630|11223344556677885f5f5f5f5f5f 32 plan9 DIVB 0(AX)
|
||||
f630|11223344556677885f5f5f5f5f5f 64 gnu divb (%rax)
|
||||
f630|11223344556677885f5f5f5f5f5f 64 intel div byte ptr [rax]
|
||||
f630|11223344556677885f5f5f5f5f5f 64 plan9 DIVL 0(AX)
|
||||
f630|11223344556677885f5f5f5f5f5f 64 plan9 DIVB 0(AX)
|
||||
f638|11223344556677885f5f5f5f5f5f 32 intel idiv byte ptr [eax]
|
||||
f638|11223344556677885f5f5f5f5f5f 32 plan9 IDIVL 0(AX)
|
||||
f638|11223344556677885f5f5f5f5f5f 32 plan9 IDIVB 0(AX)
|
||||
f638|11223344556677885f5f5f5f5f5f 64 gnu idivb (%rax)
|
||||
f638|11223344556677885f5f5f5f5f5f 64 intel idiv byte ptr [rax]
|
||||
f638|11223344556677885f5f5f5f5f5f 64 plan9 IDIVL 0(AX)
|
||||
f638|11223344556677885f5f5f5f5f5f 64 plan9 IDIVB 0(AX)
|
||||
f70011223344|556677885f5f5f5f5f5f 32 intel test dword ptr [eax], 0x44332211
|
||||
f70011223344|556677885f5f5f5f5f5f 32 plan9 TESTL $0x44332211, 0(AX)
|
||||
f70011223344|556677885f5f5f5f5f5f 64 gnu testl $0x44332211,(%rax)
|
||||
@ -6691,15 +6693,15 @@ fd|11223344556677885f5f5f5f5f5f5f 64 gnu std
|
||||
fd|11223344556677885f5f5f5f5f5f5f 64 intel std
|
||||
fd|11223344556677885f5f5f5f5f5f5f 64 plan9 STD
|
||||
fe00|11223344556677885f5f5f5f5f5f 32 intel inc byte ptr [eax]
|
||||
fe00|11223344556677885f5f5f5f5f5f 32 plan9 INCL 0(AX)
|
||||
fe00|11223344556677885f5f5f5f5f5f 32 plan9 INCB 0(AX)
|
||||
fe00|11223344556677885f5f5f5f5f5f 64 gnu incb (%rax)
|
||||
fe00|11223344556677885f5f5f5f5f5f 64 intel inc byte ptr [rax]
|
||||
fe00|11223344556677885f5f5f5f5f5f 64 plan9 INCL 0(AX)
|
||||
fe00|11223344556677885f5f5f5f5f5f 64 plan9 INCB 0(AX)
|
||||
fe08|11223344556677885f5f5f5f5f5f 32 intel dec byte ptr [eax]
|
||||
fe08|11223344556677885f5f5f5f5f5f 32 plan9 DECL 0(AX)
|
||||
fe08|11223344556677885f5f5f5f5f5f 32 plan9 DECB 0(AX)
|
||||
fe08|11223344556677885f5f5f5f5f5f 64 gnu decb (%rax)
|
||||
fe08|11223344556677885f5f5f5f5f5f 64 intel dec byte ptr [rax]
|
||||
fe08|11223344556677885f5f5f5f5f5f 64 plan9 DECL 0(AX)
|
||||
fe08|11223344556677885f5f5f5f5f5f 64 plan9 DECB 0(AX)
|
||||
ff00|11223344556677885f5f5f5f5f5f 32 intel inc dword ptr [eax]
|
||||
ff00|11223344556677885f5f5f5f5f5f 32 plan9 INCL 0(AX)
|
||||
ff00|11223344556677885f5f5f5f5f5f 64 gnu incl (%rax)
|
||||
@ -6728,4 +6730,4 @@ ff30|11223344556677885f5f5f5f5f5f 32 intel push dword ptr [eax]
|
||||
ff30|11223344556677885f5f5f5f5f5f 32 plan9 PUSHL 0(AX)
|
||||
ff30|11223344556677885f5f5f5f5f5f 64 gnu pushq (%rax)
|
||||
ff30|11223344556677885f5f5f5f5f5f 64 intel push qword ptr [rax]
|
||||
ff30|11223344556677885f5f5f5f5f5f 64 plan9 PUSHL 0(AX)
|
||||
ff30|11223344556677885f5f5f5f5f5f 64 plan9 PUSHQ 0(AX)
|
||||
|
@ -125,14 +125,10 @@ func checkCopyLocksFunc(f *File, name string, recv *ast.FieldList, typ *ast.Func
|
||||
}
|
||||
}
|
||||
|
||||
if typ.Results != nil {
|
||||
for _, field := range typ.Results.List {
|
||||
expr := field.Type
|
||||
if path := lockPath(f.pkg.typesPkg, f.pkg.types[expr].Type); path != nil {
|
||||
f.Badf(expr.Pos(), "%s returns lock by value: %v", name, path)
|
||||
}
|
||||
}
|
||||
}
|
||||
// Don't check typ.Results. If T has a Lock field it's OK to write
|
||||
// return T{}
|
||||
// because that is returning the zero value. Leave result checking
|
||||
// to the return statement.
|
||||
}
|
||||
|
||||
// checkCopyLocksRange checks whether a range statement
|
||||
@ -194,6 +190,16 @@ func lockPathRhs(f *File, x ast.Expr) typePath {
|
||||
if _, ok := x.(*ast.CompositeLit); ok {
|
||||
return nil
|
||||
}
|
||||
if _, ok := x.(*ast.CallExpr); ok {
|
||||
// A call may return a zero value.
|
||||
return nil
|
||||
}
|
||||
if star, ok := x.(*ast.StarExpr); ok {
|
||||
if _, ok := star.X.(*ast.CallExpr); ok {
|
||||
// A call may return a pointer to a zero value.
|
||||
return nil
|
||||
}
|
||||
}
|
||||
return lockPath(f.pkg.typesPkg, f.pkg.types[x].Type)
|
||||
}
|
||||
|
||||
|
@ -29,6 +29,8 @@ type deadState struct {
|
||||
}
|
||||
|
||||
// checkUnreachable checks a function body for dead code.
|
||||
//
|
||||
// TODO(adonovan): use the new cfg package, which is more precise.
|
||||
func checkUnreachable(f *File, node ast.Node) {
|
||||
var body *ast.BlockStmt
|
||||
switch n := node.(type) {
|
||||
|
@ -91,6 +91,15 @@ Flag: -tests
|
||||
Mistakes involving tests including functions with incorrect names or signatures
|
||||
and example tests that document identifiers not in the package.
|
||||
|
||||
Failure to call the cancelation function returned by context.WithCancel.
|
||||
|
||||
Flag: -lostcancel
|
||||
|
||||
The cancelation function returned by context.WithCancel, WithTimeout,
|
||||
and WithDeadline must be called or the new context will remain live
|
||||
until its parent context is cancelled.
|
||||
(The background context is never cancelled.)
|
||||
|
||||
Methods
|
||||
|
||||
Flag: -methods
|
||||
|
512
src/cmd/vet/internal/cfg/builder.go
Normal file
512
src/cmd/vet/internal/cfg/builder.go
Normal file
@ -0,0 +1,512 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package cfg
|
||||
|
||||
// This file implements the CFG construction pass.
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/token"
|
||||
)
|
||||
|
||||
type builder struct {
|
||||
cfg *CFG
|
||||
mayReturn func(*ast.CallExpr) bool
|
||||
current *Block
|
||||
lblocks map[*ast.Object]*lblock // labeled blocks
|
||||
targets *targets // linked stack of branch targets
|
||||
}
|
||||
|
||||
func (b *builder) stmt(_s ast.Stmt) {
|
||||
// The label of the current statement. If non-nil, its _goto
|
||||
// target is always set; its _break and _continue are set only
|
||||
// within the body of switch/typeswitch/select/for/range.
|
||||
// It is effectively an additional default-nil parameter of stmt().
|
||||
var label *lblock
|
||||
start:
|
||||
switch s := _s.(type) {
|
||||
case *ast.BadStmt,
|
||||
*ast.SendStmt,
|
||||
*ast.IncDecStmt,
|
||||
*ast.GoStmt,
|
||||
*ast.DeferStmt,
|
||||
*ast.EmptyStmt,
|
||||
*ast.AssignStmt:
|
||||
// No effect on control flow.
|
||||
b.add(s)
|
||||
|
||||
case *ast.ExprStmt:
|
||||
b.add(s)
|
||||
if call, ok := s.X.(*ast.CallExpr); ok && !b.mayReturn(call) {
|
||||
// Calls to panic, os.Exit, etc, never return.
|
||||
b.current = b.newUnreachableBlock("unreachable.call")
|
||||
}
|
||||
|
||||
case *ast.DeclStmt:
|
||||
// Treat each var ValueSpec as a separate statement.
|
||||
d := s.Decl.(*ast.GenDecl)
|
||||
if d.Tok == token.VAR {
|
||||
for _, spec := range d.Specs {
|
||||
if spec, ok := spec.(*ast.ValueSpec); ok {
|
||||
b.add(spec)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
case *ast.LabeledStmt:
|
||||
label = b.labeledBlock(s.Label)
|
||||
b.jump(label._goto)
|
||||
b.current = label._goto
|
||||
_s = s.Stmt
|
||||
goto start // effectively: tailcall stmt(g, s.Stmt, label)
|
||||
|
||||
case *ast.ReturnStmt:
|
||||
b.add(s)
|
||||
b.current = b.newUnreachableBlock("unreachable.return")
|
||||
|
||||
case *ast.BranchStmt:
|
||||
var block *Block
|
||||
switch s.Tok {
|
||||
case token.BREAK:
|
||||
if s.Label != nil {
|
||||
if lb := b.labeledBlock(s.Label); lb != nil {
|
||||
block = lb._break
|
||||
}
|
||||
} else {
|
||||
for t := b.targets; t != nil && block == nil; t = t.tail {
|
||||
block = t._break
|
||||
}
|
||||
}
|
||||
|
||||
case token.CONTINUE:
|
||||
if s.Label != nil {
|
||||
if lb := b.labeledBlock(s.Label); lb != nil {
|
||||
block = lb._continue
|
||||
}
|
||||
} else {
|
||||
for t := b.targets; t != nil && block == nil; t = t.tail {
|
||||
block = t._continue
|
||||
}
|
||||
}
|
||||
|
||||
case token.FALLTHROUGH:
|
||||
for t := b.targets; t != nil; t = t.tail {
|
||||
block = t._fallthrough
|
||||
}
|
||||
|
||||
case token.GOTO:
|
||||
if s.Label != nil {
|
||||
block = b.labeledBlock(s.Label)._goto
|
||||
}
|
||||
}
|
||||
if block == nil {
|
||||
block = b.newBlock("undefined.branch")
|
||||
}
|
||||
b.jump(block)
|
||||
b.current = b.newUnreachableBlock("unreachable.branch")
|
||||
|
||||
case *ast.BlockStmt:
|
||||
b.stmtList(s.List)
|
||||
|
||||
case *ast.IfStmt:
|
||||
if s.Init != nil {
|
||||
b.stmt(s.Init)
|
||||
}
|
||||
then := b.newBlock("if.then")
|
||||
done := b.newBlock("if.done")
|
||||
_else := done
|
||||
if s.Else != nil {
|
||||
_else = b.newBlock("if.else")
|
||||
}
|
||||
b.add(s.Cond)
|
||||
b.ifelse(then, _else)
|
||||
b.current = then
|
||||
b.stmt(s.Body)
|
||||
b.jump(done)
|
||||
|
||||
if s.Else != nil {
|
||||
b.current = _else
|
||||
b.stmt(s.Else)
|
||||
b.jump(done)
|
||||
}
|
||||
|
||||
b.current = done
|
||||
|
||||
case *ast.SwitchStmt:
|
||||
b.switchStmt(s, label)
|
||||
|
||||
case *ast.TypeSwitchStmt:
|
||||
b.typeSwitchStmt(s, label)
|
||||
|
||||
case *ast.SelectStmt:
|
||||
b.selectStmt(s, label)
|
||||
|
||||
case *ast.ForStmt:
|
||||
b.forStmt(s, label)
|
||||
|
||||
case *ast.RangeStmt:
|
||||
b.rangeStmt(s, label)
|
||||
|
||||
default:
|
||||
panic(fmt.Sprintf("unexpected statement kind: %T", s))
|
||||
}
|
||||
}
|
||||
|
||||
func (b *builder) stmtList(list []ast.Stmt) {
|
||||
for _, s := range list {
|
||||
b.stmt(s)
|
||||
}
|
||||
}
|
||||
|
||||
func (b *builder) switchStmt(s *ast.SwitchStmt, label *lblock) {
|
||||
if s.Init != nil {
|
||||
b.stmt(s.Init)
|
||||
}
|
||||
if s.Tag != nil {
|
||||
b.add(s.Tag)
|
||||
}
|
||||
done := b.newBlock("switch.done")
|
||||
if label != nil {
|
||||
label._break = done
|
||||
}
|
||||
// We pull the default case (if present) down to the end.
|
||||
// But each fallthrough label must point to the next
|
||||
// body block in source order, so we preallocate a
|
||||
// body block (fallthru) for the next case.
|
||||
// Unfortunately this makes for a confusing block order.
|
||||
var defaultBody *[]ast.Stmt
|
||||
var defaultFallthrough *Block
|
||||
var fallthru, defaultBlock *Block
|
||||
ncases := len(s.Body.List)
|
||||
for i, clause := range s.Body.List {
|
||||
body := fallthru
|
||||
if body == nil {
|
||||
body = b.newBlock("switch.body") // first case only
|
||||
}
|
||||
|
||||
// Preallocate body block for the next case.
|
||||
fallthru = done
|
||||
if i+1 < ncases {
|
||||
fallthru = b.newBlock("switch.body")
|
||||
}
|
||||
|
||||
cc := clause.(*ast.CaseClause)
|
||||
if cc.List == nil {
|
||||
// Default case.
|
||||
defaultBody = &cc.Body
|
||||
defaultFallthrough = fallthru
|
||||
defaultBlock = body
|
||||
continue
|
||||
}
|
||||
|
||||
var nextCond *Block
|
||||
for _, cond := range cc.List {
|
||||
nextCond = b.newBlock("switch.next")
|
||||
b.add(cond) // one half of the tag==cond condition
|
||||
b.ifelse(body, nextCond)
|
||||
b.current = nextCond
|
||||
}
|
||||
b.current = body
|
||||
b.targets = &targets{
|
||||
tail: b.targets,
|
||||
_break: done,
|
||||
_fallthrough: fallthru,
|
||||
}
|
||||
b.stmtList(cc.Body)
|
||||
b.targets = b.targets.tail
|
||||
b.jump(done)
|
||||
b.current = nextCond
|
||||
}
|
||||
if defaultBlock != nil {
|
||||
b.jump(defaultBlock)
|
||||
b.current = defaultBlock
|
||||
b.targets = &targets{
|
||||
tail: b.targets,
|
||||
_break: done,
|
||||
_fallthrough: defaultFallthrough,
|
||||
}
|
||||
b.stmtList(*defaultBody)
|
||||
b.targets = b.targets.tail
|
||||
}
|
||||
b.jump(done)
|
||||
b.current = done
|
||||
}
|
||||
|
||||
func (b *builder) typeSwitchStmt(s *ast.TypeSwitchStmt, label *lblock) {
|
||||
if s.Init != nil {
|
||||
b.stmt(s.Init)
|
||||
}
|
||||
if s.Assign != nil {
|
||||
b.add(s.Assign)
|
||||
}
|
||||
|
||||
done := b.newBlock("typeswitch.done")
|
||||
if label != nil {
|
||||
label._break = done
|
||||
}
|
||||
var default_ *ast.CaseClause
|
||||
for _, clause := range s.Body.List {
|
||||
cc := clause.(*ast.CaseClause)
|
||||
if cc.List == nil {
|
||||
default_ = cc
|
||||
continue
|
||||
}
|
||||
body := b.newBlock("typeswitch.body")
|
||||
var next *Block
|
||||
for _, casetype := range cc.List {
|
||||
next = b.newBlock("typeswitch.next")
|
||||
// casetype is a type, so don't call b.add(casetype).
|
||||
// This block logically contains a type assertion,
|
||||
// x.(casetype), but it's unclear how to represent x.
|
||||
_ = casetype
|
||||
b.ifelse(body, next)
|
||||
b.current = next
|
||||
}
|
||||
b.current = body
|
||||
b.typeCaseBody(cc, done)
|
||||
b.current = next
|
||||
}
|
||||
if default_ != nil {
|
||||
b.typeCaseBody(default_, done)
|
||||
} else {
|
||||
b.jump(done)
|
||||
}
|
||||
b.current = done
|
||||
}
|
||||
|
||||
func (b *builder) typeCaseBody(cc *ast.CaseClause, done *Block) {
|
||||
b.targets = &targets{
|
||||
tail: b.targets,
|
||||
_break: done,
|
||||
}
|
||||
b.stmtList(cc.Body)
|
||||
b.targets = b.targets.tail
|
||||
b.jump(done)
|
||||
}
|
||||
|
||||
func (b *builder) selectStmt(s *ast.SelectStmt, label *lblock) {
|
||||
// First evaluate channel expressions.
|
||||
// TODO(adonovan): fix: evaluate only channel exprs here.
|
||||
for _, clause := range s.Body.List {
|
||||
if comm := clause.(*ast.CommClause).Comm; comm != nil {
|
||||
b.stmt(comm)
|
||||
}
|
||||
}
|
||||
|
||||
done := b.newBlock("select.done")
|
||||
if label != nil {
|
||||
label._break = done
|
||||
}
|
||||
|
||||
var defaultBody *[]ast.Stmt
|
||||
for _, cc := range s.Body.List {
|
||||
clause := cc.(*ast.CommClause)
|
||||
if clause.Comm == nil {
|
||||
defaultBody = &clause.Body
|
||||
continue
|
||||
}
|
||||
body := b.newBlock("select.body")
|
||||
next := b.newBlock("select.next")
|
||||
b.ifelse(body, next)
|
||||
b.current = body
|
||||
b.targets = &targets{
|
||||
tail: b.targets,
|
||||
_break: done,
|
||||
}
|
||||
switch comm := clause.Comm.(type) {
|
||||
case *ast.ExprStmt: // <-ch
|
||||
// nop
|
||||
case *ast.AssignStmt: // x := <-states[state].Chan
|
||||
b.add(comm.Lhs[0])
|
||||
}
|
||||
b.stmtList(clause.Body)
|
||||
b.targets = b.targets.tail
|
||||
b.jump(done)
|
||||
b.current = next
|
||||
}
|
||||
if defaultBody != nil {
|
||||
b.targets = &targets{
|
||||
tail: b.targets,
|
||||
_break: done,
|
||||
}
|
||||
b.stmtList(*defaultBody)
|
||||
b.targets = b.targets.tail
|
||||
b.jump(done)
|
||||
}
|
||||
b.current = done
|
||||
}
|
||||
|
||||
func (b *builder) forStmt(s *ast.ForStmt, label *lblock) {
|
||||
// ...init...
|
||||
// jump loop
|
||||
// loop:
|
||||
// if cond goto body else done
|
||||
// body:
|
||||
// ...body...
|
||||
// jump post
|
||||
// post: (target of continue)
|
||||
// ...post...
|
||||
// jump loop
|
||||
// done: (target of break)
|
||||
if s.Init != nil {
|
||||
b.stmt(s.Init)
|
||||
}
|
||||
body := b.newBlock("for.body")
|
||||
done := b.newBlock("for.done") // target of 'break'
|
||||
loop := body // target of back-edge
|
||||
if s.Cond != nil {
|
||||
loop = b.newBlock("for.loop")
|
||||
}
|
||||
cont := loop // target of 'continue'
|
||||
if s.Post != nil {
|
||||
cont = b.newBlock("for.post")
|
||||
}
|
||||
if label != nil {
|
||||
label._break = done
|
||||
label._continue = cont
|
||||
}
|
||||
b.jump(loop)
|
||||
b.current = loop
|
||||
if loop != body {
|
||||
b.add(s.Cond)
|
||||
b.ifelse(body, done)
|
||||
b.current = body
|
||||
}
|
||||
b.targets = &targets{
|
||||
tail: b.targets,
|
||||
_break: done,
|
||||
_continue: cont,
|
||||
}
|
||||
b.stmt(s.Body)
|
||||
b.targets = b.targets.tail
|
||||
b.jump(cont)
|
||||
|
||||
if s.Post != nil {
|
||||
b.current = cont
|
||||
b.stmt(s.Post)
|
||||
b.jump(loop) // back-edge
|
||||
}
|
||||
b.current = done
|
||||
}
|
||||
|
||||
func (b *builder) rangeStmt(s *ast.RangeStmt, label *lblock) {
|
||||
b.add(s.X)
|
||||
|
||||
if s.Key != nil {
|
||||
b.add(s.Key)
|
||||
}
|
||||
if s.Value != nil {
|
||||
b.add(s.Value)
|
||||
}
|
||||
|
||||
// ...
|
||||
// loop: (target of continue)
|
||||
// if ... goto body else done
|
||||
// body:
|
||||
// ...
|
||||
// jump loop
|
||||
// done: (target of break)
|
||||
|
||||
loop := b.newBlock("range.loop")
|
||||
b.jump(loop)
|
||||
b.current = loop
|
||||
|
||||
body := b.newBlock("range.body")
|
||||
done := b.newBlock("range.done")
|
||||
b.ifelse(body, done)
|
||||
b.current = body
|
||||
|
||||
if label != nil {
|
||||
label._break = done
|
||||
label._continue = loop
|
||||
}
|
||||
b.targets = &targets{
|
||||
tail: b.targets,
|
||||
_break: done,
|
||||
_continue: loop,
|
||||
}
|
||||
b.stmt(s.Body)
|
||||
b.targets = b.targets.tail
|
||||
b.jump(loop) // back-edge
|
||||
b.current = done
|
||||
}
|
||||
|
||||
// -------- helpers --------
|
||||
|
||||
// Destinations associated with unlabeled for/switch/select stmts.
|
||||
// We push/pop one of these as we enter/leave each construct and for
|
||||
// each BranchStmt we scan for the innermost target of the right type.
|
||||
//
|
||||
type targets struct {
|
||||
tail *targets // rest of stack
|
||||
_break *Block
|
||||
_continue *Block
|
||||
_fallthrough *Block
|
||||
}
|
||||
|
||||
// Destinations associated with a labeled block.
|
||||
// We populate these as labels are encountered in forward gotos or
|
||||
// labeled statements.
|
||||
//
|
||||
type lblock struct {
|
||||
_goto *Block
|
||||
_break *Block
|
||||
_continue *Block
|
||||
}
|
||||
|
||||
// labeledBlock returns the branch target associated with the
|
||||
// specified label, creating it if needed.
|
||||
//
|
||||
func (b *builder) labeledBlock(label *ast.Ident) *lblock {
|
||||
lb := b.lblocks[label.Obj]
|
||||
if lb == nil {
|
||||
lb = &lblock{_goto: b.newBlock(label.Name)}
|
||||
if b.lblocks == nil {
|
||||
b.lblocks = make(map[*ast.Object]*lblock)
|
||||
}
|
||||
b.lblocks[label.Obj] = lb
|
||||
}
|
||||
return lb
|
||||
}
|
||||
|
||||
// newBlock appends a new unconnected basic block to b.cfg's block
|
||||
// slice and returns it.
|
||||
// It does not automatically become the current block.
|
||||
// comment is an optional string for more readable debugging output.
|
||||
func (b *builder) newBlock(comment string) *Block {
|
||||
g := b.cfg
|
||||
block := &Block{
|
||||
index: int32(len(g.Blocks)),
|
||||
comment: comment,
|
||||
}
|
||||
block.Succs = block.succs2[:0]
|
||||
g.Blocks = append(g.Blocks, block)
|
||||
return block
|
||||
}
|
||||
|
||||
func (b *builder) newUnreachableBlock(comment string) *Block {
|
||||
block := b.newBlock(comment)
|
||||
block.unreachable = true
|
||||
return block
|
||||
}
|
||||
|
||||
func (b *builder) add(n ast.Node) {
|
||||
b.current.Nodes = append(b.current.Nodes, n)
|
||||
}
|
||||
|
||||
// jump adds an edge from the current block to the target block,
|
||||
// and sets b.current to nil.
|
||||
func (b *builder) jump(target *Block) {
|
||||
b.current.Succs = append(b.current.Succs, target)
|
||||
b.current = nil
|
||||
}
|
||||
|
||||
// ifelse emits edges from the current block to the t and f blocks,
|
||||
// and sets b.current to nil.
|
||||
func (b *builder) ifelse(t, f *Block) {
|
||||
b.current.Succs = append(b.current.Succs, t, f)
|
||||
b.current = nil
|
||||
}
|
142
src/cmd/vet/internal/cfg/cfg.go
Normal file
142
src/cmd/vet/internal/cfg/cfg.go
Normal file
@ -0,0 +1,142 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// This package constructs a simple control-flow graph (CFG) of the
|
||||
// statements and expressions within a single function.
|
||||
//
|
||||
// Use cfg.New to construct the CFG for a function body.
|
||||
//
|
||||
// The blocks of the CFG contain all the function's non-control
|
||||
// statements. The CFG does not contain control statements such as If,
|
||||
// Switch, Select, and Branch, but does contain their subexpressions.
|
||||
// For example, this source code:
|
||||
//
|
||||
// if x := f(); x != nil {
|
||||
// T()
|
||||
// } else {
|
||||
// F()
|
||||
// }
|
||||
//
|
||||
// produces this CFG:
|
||||
//
|
||||
// 1: x := f()
|
||||
// x != nil
|
||||
// succs: 2, 3
|
||||
// 2: T()
|
||||
// succs: 4
|
||||
// 3: F()
|
||||
// succs: 4
|
||||
// 4:
|
||||
//
|
||||
// The CFG does contain Return statements; even implicit returns are
|
||||
// materialized (at the position of the function's closing brace).
|
||||
//
|
||||
// The CFG does not record conditions associated with conditional branch
|
||||
// edges, nor the short-circuit semantics of the && and || operators,
|
||||
// nor abnormal control flow caused by panic. If you need this
|
||||
// information, use golang.org/x/tools/go/ssa instead.
|
||||
//
|
||||
package cfg
|
||||
|
||||
// Although the vet tool has type information, it is often extremely
|
||||
// fragmentary, so for simplicity this package does not depend on
|
||||
// go/types. Consequently control-flow conditions are ignored even
|
||||
// when constant, and "mayReturn" information must be provided by the
|
||||
// client.
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/format"
|
||||
"go/token"
|
||||
)
|
||||
|
||||
// A CFG represents the control-flow graph of a single function.
|
||||
//
|
||||
// The entry point is Blocks[0]; there may be multiple return blocks.
|
||||
type CFG struct {
|
||||
Blocks []*Block // block[0] is entry; order otherwise undefined
|
||||
}
|
||||
|
||||
// A Block represents a basic block: a list of statements and
|
||||
// expressions that are always evaluated sequentially.
|
||||
//
|
||||
// A block may have 0-2 successors: zero for a return block or a block
|
||||
// that calls a function such as panic that never returns; one for a
|
||||
// normal (jump) block; and two for a conditional (if) block.
|
||||
type Block struct {
|
||||
Nodes []ast.Node // statements, expressions, and ValueSpecs
|
||||
Succs []*Block // successor nodes in the graph
|
||||
|
||||
comment string // for debugging
|
||||
index int32 // index within CFG.Blocks
|
||||
unreachable bool // is block of stmts following return/panic/for{}
|
||||
succs2 [2]*Block // underlying array for Succs
|
||||
}
|
||||
|
||||
// New returns a new control-flow graph for the specified function body,
|
||||
// which must be non-nil.
|
||||
//
|
||||
// The CFG builder calls mayReturn to determine whether a given function
|
||||
// call may return. For example, calls to panic, os.Exit, and log.Fatal
|
||||
// do not return, so the builder can remove infeasible graph edges
|
||||
// following such calls. The builder calls mayReturn only for a
|
||||
// CallExpr beneath an ExprStmt.
|
||||
func New(body *ast.BlockStmt, mayReturn func(*ast.CallExpr) bool) *CFG {
|
||||
b := builder{
|
||||
mayReturn: mayReturn,
|
||||
cfg: new(CFG),
|
||||
}
|
||||
b.current = b.newBlock("entry")
|
||||
b.stmt(body)
|
||||
|
||||
// Does control fall off the end of the function's body?
|
||||
// Make implicit return explicit.
|
||||
if b.current != nil && !b.current.unreachable {
|
||||
b.add(&ast.ReturnStmt{
|
||||
Return: body.End() - 1,
|
||||
})
|
||||
}
|
||||
|
||||
return b.cfg
|
||||
}
|
||||
|
||||
func (b *Block) String() string {
|
||||
return fmt.Sprintf("block %d (%s)", b.index, b.comment)
|
||||
}
|
||||
|
||||
// Return returns the return statement at the end of this block if present, nil otherwise.
|
||||
func (b *Block) Return() (ret *ast.ReturnStmt) {
|
||||
if len(b.Nodes) > 0 {
|
||||
ret, _ = b.Nodes[len(b.Nodes)-1].(*ast.ReturnStmt)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// Format formats the control-flow graph for ease of debugging.
|
||||
func (g *CFG) Format(fset *token.FileSet) string {
|
||||
var buf bytes.Buffer
|
||||
for _, b := range g.Blocks {
|
||||
fmt.Fprintf(&buf, ".%d: # %s\n", b.index, b.comment)
|
||||
for _, n := range b.Nodes {
|
||||
fmt.Fprintf(&buf, "\t%s\n", formatNode(fset, n))
|
||||
}
|
||||
if len(b.Succs) > 0 {
|
||||
fmt.Fprintf(&buf, "\tsuccs:")
|
||||
for _, succ := range b.Succs {
|
||||
fmt.Fprintf(&buf, " %d", succ.index)
|
||||
}
|
||||
buf.WriteByte('\n')
|
||||
}
|
||||
buf.WriteByte('\n')
|
||||
}
|
||||
return buf.String()
|
||||
}
|
||||
|
||||
func formatNode(fset *token.FileSet, n ast.Node) string {
|
||||
var buf bytes.Buffer
|
||||
format.Node(&buf, fset, n)
|
||||
// Indent secondary lines by a tab.
|
||||
return string(bytes.Replace(buf.Bytes(), []byte("\n"), []byte("\n\t"), -1))
|
||||
}
|
190
src/cmd/vet/internal/cfg/cfg_test.go
Normal file
190
src/cmd/vet/internal/cfg/cfg_test.go
Normal file
@ -0,0 +1,190 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package cfg
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/parser"
|
||||
"go/token"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const src = `package main
|
||||
|
||||
import "log"
|
||||
|
||||
func f1() {
|
||||
live()
|
||||
return
|
||||
dead()
|
||||
}
|
||||
|
||||
func f2() {
|
||||
for {
|
||||
live()
|
||||
}
|
||||
dead()
|
||||
}
|
||||
|
||||
func f3() {
|
||||
if true { // even known values are ignored
|
||||
return
|
||||
}
|
||||
for true { // even known values are ignored
|
||||
live()
|
||||
}
|
||||
for {
|
||||
live()
|
||||
}
|
||||
dead()
|
||||
}
|
||||
|
||||
func f4(x int) {
|
||||
switch x {
|
||||
case 1:
|
||||
live()
|
||||
fallthrough
|
||||
case 2:
|
||||
live()
|
||||
log.Fatal()
|
||||
default:
|
||||
panic("oops")
|
||||
}
|
||||
dead()
|
||||
}
|
||||
|
||||
func f4(ch chan int) {
|
||||
select {
|
||||
case <-ch:
|
||||
live()
|
||||
return
|
||||
default:
|
||||
live()
|
||||
panic("oops")
|
||||
}
|
||||
dead()
|
||||
}
|
||||
|
||||
func f5(unknown bool) {
|
||||
for {
|
||||
if unknown {
|
||||
break
|
||||
}
|
||||
continue
|
||||
dead()
|
||||
}
|
||||
live()
|
||||
}
|
||||
|
||||
func f6(unknown bool) {
|
||||
outer:
|
||||
for {
|
||||
for {
|
||||
break outer
|
||||
dead()
|
||||
}
|
||||
dead()
|
||||
}
|
||||
live()
|
||||
}
|
||||
|
||||
func f7() {
|
||||
for {
|
||||
break nosuchlabel
|
||||
dead()
|
||||
}
|
||||
dead()
|
||||
}
|
||||
|
||||
func f8() {
|
||||
select{}
|
||||
dead()
|
||||
}
|
||||
|
||||
func f9(ch chan int) {
|
||||
select {
|
||||
case <-ch:
|
||||
return
|
||||
}
|
||||
dead()
|
||||
}
|
||||
|
||||
func f10(ch chan int) {
|
||||
select {
|
||||
case <-ch:
|
||||
return
|
||||
dead()
|
||||
default:
|
||||
}
|
||||
live()
|
||||
}
|
||||
|
||||
func f11() {
|
||||
goto; // mustn't crash
|
||||
dead()
|
||||
}
|
||||
|
||||
`
|
||||
|
||||
func TestDeadCode(t *testing.T) {
|
||||
// We'll use dead code detection to verify the CFG.
|
||||
|
||||
fset := token.NewFileSet()
|
||||
f, err := parser.ParseFile(fset, "dummy.go", src, parser.Mode(0))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, decl := range f.Decls {
|
||||
if decl, ok := decl.(*ast.FuncDecl); ok {
|
||||
g := New(decl.Body, mayReturn)
|
||||
|
||||
// Mark blocks reachable from entry.
|
||||
live := make(map[*Block]bool)
|
||||
var visit func(*Block)
|
||||
visit = func(b *Block) {
|
||||
if !live[b] {
|
||||
live[b] = true
|
||||
for _, succ := range b.Succs {
|
||||
visit(succ)
|
||||
}
|
||||
}
|
||||
}
|
||||
visit(g.Blocks[0])
|
||||
|
||||
// Print statements in unreachable blocks
|
||||
// (in order determined by builder).
|
||||
var buf bytes.Buffer
|
||||
for _, b := range g.Blocks {
|
||||
if !live[b] {
|
||||
for _, n := range b.Nodes {
|
||||
fmt.Fprintf(&buf, "\t%s\n", formatNode(fset, n))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check that the result contains "dead" at least once but not "live".
|
||||
if !bytes.Contains(buf.Bytes(), []byte("dead")) ||
|
||||
bytes.Contains(buf.Bytes(), []byte("live")) {
|
||||
t.Errorf("unexpected dead statements in function %s:\n%s",
|
||||
decl.Name.Name,
|
||||
&buf)
|
||||
t.Logf("control flow graph:\n%s", g.Format(fset))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A trivial mayReturn predicate that looks only at syntax, not types.
|
||||
func mayReturn(call *ast.CallExpr) bool {
|
||||
switch fun := call.Fun.(type) {
|
||||
case *ast.Ident:
|
||||
return fun.Name != "panic"
|
||||
case *ast.SelectorExpr:
|
||||
return fun.Sel.Name != "Fatal"
|
||||
}
|
||||
return true
|
||||
}
|
318
src/cmd/vet/lostcancel.go
Normal file
318
src/cmd/vet/lostcancel.go
Normal file
@ -0,0 +1,318 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"cmd/vet/internal/cfg"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/types"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func init() {
|
||||
register("lostcancel",
|
||||
"check for failure to call cancelation function returned by context.WithCancel",
|
||||
checkLostCancel,
|
||||
funcDecl, funcLit)
|
||||
}
|
||||
|
||||
const debugLostCancel = false
|
||||
|
||||
var contextPackage = "context"
|
||||
|
||||
// checkLostCancel reports a failure to the call the cancel function
|
||||
// returned by context.WithCancel, either because the variable was
|
||||
// assigned to the blank identifier, or because there exists a
|
||||
// control-flow path from the call to a return statement and that path
|
||||
// does not "use" the cancel function. Any reference to the variable
|
||||
// counts as a use, even within a nested function literal.
|
||||
//
|
||||
// checkLostCancel analyzes a single named or literal function.
|
||||
func checkLostCancel(f *File, node ast.Node) {
|
||||
// Fast path: bypass check if file doesn't use context.WithCancel.
|
||||
if !hasImport(f.file, contextPackage) {
|
||||
return
|
||||
}
|
||||
|
||||
// Maps each cancel variable to its defining ValueSpec/AssignStmt.
|
||||
cancelvars := make(map[*types.Var]ast.Node)
|
||||
|
||||
// Find the set of cancel vars to analyze.
|
||||
stack := make([]ast.Node, 0, 32)
|
||||
ast.Inspect(node, func(n ast.Node) bool {
|
||||
switch n.(type) {
|
||||
case *ast.FuncLit:
|
||||
if len(stack) > 0 {
|
||||
return false // don't stray into nested functions
|
||||
}
|
||||
case nil:
|
||||
stack = stack[:len(stack)-1] // pop
|
||||
return true
|
||||
}
|
||||
stack = append(stack, n) // push
|
||||
|
||||
// Look for [{AssignStmt,ValueSpec} CallExpr SelectorExpr]:
|
||||
//
|
||||
// ctx, cancel := context.WithCancel(...)
|
||||
// ctx, cancel = context.WithCancel(...)
|
||||
// var ctx, cancel = context.WithCancel(...)
|
||||
//
|
||||
if isContextWithCancel(f, n) && isCall(stack[len(stack)-2]) {
|
||||
var id *ast.Ident // id of cancel var
|
||||
stmt := stack[len(stack)-3]
|
||||
switch stmt := stmt.(type) {
|
||||
case *ast.ValueSpec:
|
||||
if len(stmt.Names) > 1 {
|
||||
id = stmt.Names[1]
|
||||
}
|
||||
case *ast.AssignStmt:
|
||||
if len(stmt.Lhs) > 1 {
|
||||
id, _ = stmt.Lhs[1].(*ast.Ident)
|
||||
}
|
||||
}
|
||||
if id != nil {
|
||||
if id.Name == "_" {
|
||||
f.Badf(id.Pos(), "the cancel function returned by context.%s should be called, not discarded, to avoid a context leak",
|
||||
n.(*ast.SelectorExpr).Sel.Name)
|
||||
} else if v, ok := f.pkg.uses[id].(*types.Var); ok {
|
||||
cancelvars[v] = stmt
|
||||
} else if v, ok := f.pkg.defs[id].(*types.Var); ok {
|
||||
cancelvars[v] = stmt
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
if len(cancelvars) == 0 {
|
||||
return // no need to build CFG
|
||||
}
|
||||
|
||||
// Tell the CFG builder which functions never return.
|
||||
info := &types.Info{Uses: f.pkg.uses, Selections: f.pkg.selectors}
|
||||
mayReturn := func(call *ast.CallExpr) bool {
|
||||
name := callName(info, call)
|
||||
return !noReturnFuncs[name]
|
||||
}
|
||||
|
||||
// Build the CFG.
|
||||
var g *cfg.CFG
|
||||
var sig *types.Signature
|
||||
switch node := node.(type) {
|
||||
case *ast.FuncDecl:
|
||||
sig, _ = f.pkg.defs[node.Name].Type().(*types.Signature)
|
||||
g = cfg.New(node.Body, mayReturn)
|
||||
case *ast.FuncLit:
|
||||
sig, _ = f.pkg.types[node.Type].Type.(*types.Signature)
|
||||
g = cfg.New(node.Body, mayReturn)
|
||||
}
|
||||
|
||||
// Print CFG.
|
||||
if debugLostCancel {
|
||||
fmt.Println(g.Format(f.fset))
|
||||
}
|
||||
|
||||
// Examine the CFG for each variable in turn.
|
||||
// (It would be more efficient to analyze all cancelvars in a
|
||||
// single pass over the AST, but seldom is there more than one.)
|
||||
for v, stmt := range cancelvars {
|
||||
if ret := lostCancelPath(f, g, v, stmt, sig); ret != nil {
|
||||
lineno := f.fset.Position(stmt.Pos()).Line
|
||||
f.Badf(stmt.Pos(), "the %s function is not used on all paths (possible context leak)", v.Name())
|
||||
f.Badf(ret.Pos(), "this return statement may be reached without using the %s var defined on line %d", v.Name(), lineno)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func isCall(n ast.Node) bool { _, ok := n.(*ast.CallExpr); return ok }
|
||||
|
||||
func hasImport(f *ast.File, path string) bool {
|
||||
for _, imp := range f.Imports {
|
||||
v, _ := strconv.Unquote(imp.Path.Value)
|
||||
if v == path {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// isContextWithCancel reports whether n is one of the qualified identifiers
|
||||
// context.With{Cancel,Timeout,Deadline}.
|
||||
func isContextWithCancel(f *File, n ast.Node) bool {
|
||||
if sel, ok := n.(*ast.SelectorExpr); ok {
|
||||
switch sel.Sel.Name {
|
||||
case "WithCancel", "WithTimeout", "WithDeadline":
|
||||
if x, ok := sel.X.(*ast.Ident); ok {
|
||||
if pkgname, ok := f.pkg.uses[x].(*types.PkgName); ok {
|
||||
return pkgname.Imported().Path() == contextPackage
|
||||
}
|
||||
// Import failed, so we can't check package path.
|
||||
// Just check the local package name (heuristic).
|
||||
return x.Name == "context"
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// lostCancelPath finds a path through the CFG, from stmt (which defines
|
||||
// the 'cancel' variable v) to a return statement, that doesn't "use" v.
|
||||
// If it finds one, it returns the return statement (which may be synthetic).
|
||||
// sig is the function's type, if known.
|
||||
func lostCancelPath(f *File, g *cfg.CFG, v *types.Var, stmt ast.Node, sig *types.Signature) *ast.ReturnStmt {
|
||||
vIsNamedResult := sig != nil && tupleContains(sig.Results(), v)
|
||||
|
||||
// uses reports whether stmts contain a "use" of variable v.
|
||||
uses := func(f *File, v *types.Var, stmts []ast.Node) bool {
|
||||
found := false
|
||||
for _, stmt := range stmts {
|
||||
ast.Inspect(stmt, func(n ast.Node) bool {
|
||||
switch n := n.(type) {
|
||||
case *ast.Ident:
|
||||
if f.pkg.uses[n] == v {
|
||||
found = true
|
||||
}
|
||||
case *ast.ReturnStmt:
|
||||
// A naked return statement counts as a use
|
||||
// of the named result variables.
|
||||
if n.Results == nil && vIsNamedResult {
|
||||
found = true
|
||||
}
|
||||
}
|
||||
return !found
|
||||
})
|
||||
}
|
||||
return found
|
||||
}
|
||||
|
||||
// blockUses computes "uses" for each block, caching the result.
|
||||
memo := make(map[*cfg.Block]bool)
|
||||
blockUses := func(f *File, v *types.Var, b *cfg.Block) bool {
|
||||
res, ok := memo[b]
|
||||
if !ok {
|
||||
res = uses(f, v, b.Nodes)
|
||||
memo[b] = res
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
// Find the var's defining block in the CFG,
|
||||
// plus the rest of the statements of that block.
|
||||
var defblock *cfg.Block
|
||||
var rest []ast.Node
|
||||
outer:
|
||||
for _, b := range g.Blocks {
|
||||
for i, n := range b.Nodes {
|
||||
if n == stmt {
|
||||
defblock = b
|
||||
rest = b.Nodes[i+1:]
|
||||
break outer
|
||||
}
|
||||
}
|
||||
}
|
||||
if defblock == nil {
|
||||
panic("internal error: can't find defining block for cancel var")
|
||||
}
|
||||
|
||||
// Is v "used" in the remainder of its defining block?
|
||||
if uses(f, v, rest) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Does the defining block return without using v?
|
||||
if ret := defblock.Return(); ret != nil {
|
||||
return ret
|
||||
}
|
||||
|
||||
// Search the CFG depth-first for a path, from defblock to a
|
||||
// return block, in which v is never "used".
|
||||
seen := make(map[*cfg.Block]bool)
|
||||
var search func(blocks []*cfg.Block) *ast.ReturnStmt
|
||||
search = func(blocks []*cfg.Block) *ast.ReturnStmt {
|
||||
for _, b := range blocks {
|
||||
if !seen[b] {
|
||||
seen[b] = true
|
||||
|
||||
// Prune the search if the block uses v.
|
||||
if blockUses(f, v, b) {
|
||||
continue
|
||||
}
|
||||
|
||||
// Found path to return statement?
|
||||
if ret := b.Return(); ret != nil {
|
||||
if debugLostCancel {
|
||||
fmt.Printf("found path to return in block %s\n", b)
|
||||
}
|
||||
return ret // found
|
||||
}
|
||||
|
||||
// Recur
|
||||
if ret := search(b.Succs); ret != nil {
|
||||
if debugLostCancel {
|
||||
fmt.Printf(" from block %s\n", b)
|
||||
}
|
||||
return ret
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
return search(defblock.Succs)
|
||||
}
|
||||
|
||||
func tupleContains(tuple *types.Tuple, v *types.Var) bool {
|
||||
for i := 0; i < tuple.Len(); i++ {
|
||||
if tuple.At(i) == v {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
var noReturnFuncs = map[string]bool{
|
||||
"(*testing.common).FailNow": true,
|
||||
"(*testing.common).Fatal": true,
|
||||
"(*testing.common).Fatalf": true,
|
||||
"(*testing.common).Skip": true,
|
||||
"(*testing.common).SkipNow": true,
|
||||
"(*testing.common).Skipf": true,
|
||||
"log.Fatal": true,
|
||||
"log.Fatalf": true,
|
||||
"log.Fatalln": true,
|
||||
"os.Exit": true,
|
||||
"panic": true,
|
||||
"runtime.Goexit": true,
|
||||
}
|
||||
|
||||
// callName returns the canonical name of the builtin, method, or
|
||||
// function called by call, if known.
|
||||
func callName(info *types.Info, call *ast.CallExpr) string {
|
||||
switch fun := call.Fun.(type) {
|
||||
case *ast.Ident:
|
||||
// builtin, e.g. "panic"
|
||||
if obj, ok := info.Uses[fun].(*types.Builtin); ok {
|
||||
return obj.Name()
|
||||
}
|
||||
case *ast.SelectorExpr:
|
||||
if sel, ok := info.Selections[fun]; ok && sel.Kind() == types.MethodVal {
|
||||
// method call, e.g. "(*testing.common).Fatal"
|
||||
meth := sel.Obj()
|
||||
return fmt.Sprintf("(%s).%s",
|
||||
meth.Type().(*types.Signature).Recv().Type(),
|
||||
meth.Name())
|
||||
}
|
||||
if obj, ok := info.Uses[fun.Sel]; ok {
|
||||
// qualified identifier, e.g. "os.Exit"
|
||||
return fmt.Sprintf("%s.%s",
|
||||
obj.Pkg().Path(),
|
||||
obj.Name())
|
||||
}
|
||||
}
|
||||
|
||||
// function with no name, or defined in missing imported package
|
||||
return ""
|
||||
}
|
@ -182,6 +182,9 @@ type File struct {
|
||||
file *ast.File
|
||||
b bytes.Buffer // for use by methods
|
||||
|
||||
// Parsed package "foo" when checking package "foo_test"
|
||||
basePkg *Package
|
||||
|
||||
// The objects that are receivers of a "String() string" method.
|
||||
// This is used by the recursiveStringer method in print.go.
|
||||
stringers map[*ast.Object]bool
|
||||
@ -238,7 +241,7 @@ func main() {
|
||||
}
|
||||
os.Exit(exitCode)
|
||||
}
|
||||
if !doPackage(".", flag.Args()) {
|
||||
if doPackage(".", flag.Args(), nil) == nil {
|
||||
warnf("no files checked")
|
||||
}
|
||||
os.Exit(exitCode)
|
||||
@ -278,12 +281,12 @@ func doPackageDir(directory string) {
|
||||
names = append(names, pkg.TestGoFiles...) // These are also in the "foo" package.
|
||||
names = append(names, pkg.SFiles...)
|
||||
prefixDirectory(directory, names)
|
||||
doPackage(directory, names)
|
||||
basePkg := doPackage(directory, names, nil)
|
||||
// Is there also a "foo_test" package? If so, do that one as well.
|
||||
if len(pkg.XTestGoFiles) > 0 {
|
||||
names = pkg.XTestGoFiles
|
||||
prefixDirectory(directory, names)
|
||||
doPackage(directory, names)
|
||||
doPackage(directory, names, basePkg)
|
||||
}
|
||||
}
|
||||
|
||||
@ -299,8 +302,8 @@ type Package struct {
|
||||
}
|
||||
|
||||
// doPackage analyzes the single package constructed from the named files.
|
||||
// It returns whether any files were checked.
|
||||
func doPackage(directory string, names []string) bool {
|
||||
// It returns the parsed Package or nil if none of the files have been checked.
|
||||
func doPackage(directory string, names []string, basePkg *Package) *Package {
|
||||
var files []*File
|
||||
var astFiles []*ast.File
|
||||
fs := token.NewFileSet()
|
||||
@ -309,7 +312,7 @@ func doPackage(directory string, names []string) bool {
|
||||
if err != nil {
|
||||
// Warn but continue to next package.
|
||||
warnf("%s: %s", name, err)
|
||||
return false
|
||||
return nil
|
||||
}
|
||||
checkBuildTag(name, data)
|
||||
var parsedFile *ast.File
|
||||
@ -317,14 +320,14 @@ func doPackage(directory string, names []string) bool {
|
||||
parsedFile, err = parser.ParseFile(fs, name, data, 0)
|
||||
if err != nil {
|
||||
warnf("%s: %s", name, err)
|
||||
return false
|
||||
return nil
|
||||
}
|
||||
astFiles = append(astFiles, parsedFile)
|
||||
}
|
||||
files = append(files, &File{fset: fs, content: data, name: name, file: parsedFile})
|
||||
}
|
||||
if len(astFiles) == 0 {
|
||||
return false
|
||||
return nil
|
||||
}
|
||||
pkg := new(Package)
|
||||
pkg.path = astFiles[0].Name.Name
|
||||
@ -346,13 +349,14 @@ func doPackage(directory string, names []string) bool {
|
||||
}
|
||||
for _, file := range files {
|
||||
file.pkg = pkg
|
||||
file.basePkg = basePkg
|
||||
file.checkers = chk
|
||||
if file.file != nil {
|
||||
file.walkFile(file.name, file.file)
|
||||
}
|
||||
}
|
||||
asmCheck(pkg)
|
||||
return true
|
||||
return pkg
|
||||
}
|
||||
|
||||
func visit(path string, f os.FileInfo, err error) error {
|
||||
|
12
src/cmd/vet/testdata/copylock_func.go
vendored
12
src/cmd/vet/testdata/copylock_func.go
vendored
@ -12,7 +12,7 @@ import "sync"
|
||||
func OkFunc(*sync.Mutex) {}
|
||||
func BadFunc(sync.Mutex) {} // ERROR "BadFunc passes lock by value: sync.Mutex"
|
||||
func OkRet() *sync.Mutex {}
|
||||
func BadRet() sync.Mutex {} // ERROR "BadRet returns lock by value: sync.Mutex"
|
||||
func BadRet() sync.Mutex {} // Don't warn about results
|
||||
|
||||
var (
|
||||
OkClosure = func(*sync.Mutex) {}
|
||||
@ -28,7 +28,7 @@ func (EmbeddedRWMutex) BadMeth() {} // ERROR "BadMeth passes lock by value: test
|
||||
func OkFunc(e *EmbeddedRWMutex) {}
|
||||
func BadFunc(EmbeddedRWMutex) {} // ERROR "BadFunc passes lock by value: testdata.EmbeddedRWMutex"
|
||||
func OkRet() *EmbeddedRWMutex {}
|
||||
func BadRet() EmbeddedRWMutex {} // ERROR "BadRet returns lock by value: testdata.EmbeddedRWMutex"
|
||||
func BadRet() EmbeddedRWMutex {} // Don't warn about results
|
||||
|
||||
type FieldMutex struct {
|
||||
s sync.Mutex
|
||||
@ -107,6 +107,14 @@ func ReturnViaInterface(x int) (int, interface{}) {
|
||||
}
|
||||
}
|
||||
|
||||
// Some cases that we don't warn about.
|
||||
|
||||
func AcceptedCases() {
|
||||
x := EmbeddedRwMutex{} // composite literal on RHS is OK (#16227)
|
||||
x = BadRet() // function call on RHS is OK (#16227)
|
||||
x = *OKRet() // indirection of function call on RHS is OK (#16227)
|
||||
}
|
||||
|
||||
// TODO: Unfortunate cases
|
||||
|
||||
// Non-ideal error message:
|
||||
|
12
src/cmd/vet/testdata/divergent/buf_test.go
vendored
12
src/cmd/vet/testdata/divergent/buf_test.go
vendored
@ -4,11 +4,11 @@ package buf_test
|
||||
|
||||
func Example() {} // OK because is package-level.
|
||||
|
||||
func Example_suffix() // OK because refers to suffix annotation.
|
||||
func Example_suffix() {} // OK because refers to suffix annotation.
|
||||
|
||||
func Example_BadSuffix() // ERROR "Example_BadSuffix has malformed example suffix: BadSuffix"
|
||||
func Example_BadSuffix() {} // ERROR "Example_BadSuffix has malformed example suffix: BadSuffix"
|
||||
|
||||
func ExampleBuf() // OK because refers to known top-level type.
|
||||
func ExampleBuf() {} // OK because refers to known top-level type.
|
||||
|
||||
func ExampleBuf_Append() {} // OK because refers to known method.
|
||||
|
||||
@ -28,8 +28,8 @@ func ExampleBuf_Len(i int) {} // ERROR "ExampleBuf_Len should be niladic"
|
||||
|
||||
// "Puffer" is German for "Buffer".
|
||||
|
||||
func ExamplePuffer() // ERROR "ExamplePuffer refers to unknown identifier: Puffer"
|
||||
func ExamplePuffer() {} // ERROR "ExamplePuffer refers to unknown identifier: Puffer"
|
||||
|
||||
func ExamplePuffer_Append() // ERROR "ExamplePuffer_Append refers to unknown identifier: Puffer"
|
||||
func ExamplePuffer_Append() {} // ERROR "ExamplePuffer_Append refers to unknown identifier: Puffer"
|
||||
|
||||
func ExamplePuffer_suffix() // ERROR "ExamplePuffer_suffix refers to unknown identifier: Puffer"
|
||||
func ExamplePuffer_suffix() {} // ERROR "ExamplePuffer_suffix refers to unknown identifier: Puffer"
|
||||
|
155
src/cmd/vet/testdata/lostcancel.go
vendored
Normal file
155
src/cmd/vet/testdata/lostcancel.go
vendored
Normal file
@ -0,0 +1,155 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package testdata
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Check the three functions and assignment forms (var, :=, =) we look for.
|
||||
// (Do these early: line numbers are fragile.)
|
||||
func _() {
|
||||
var ctx, cancel = context.WithCancel() // ERROR "the cancel function is not used on all paths \(possible context leak\)"
|
||||
} // ERROR "this return statement may be reached without using the cancel var defined on line 17"
|
||||
|
||||
func _() {
|
||||
ctx, cancel2 := context.WithDeadline() // ERROR "the cancel2 function is not used..."
|
||||
} // ERROR "may be reached without using the cancel2 var defined on line 21"
|
||||
|
||||
func _() {
|
||||
var ctx context.Context
|
||||
var cancel3 func()
|
||||
ctx, cancel3 = context.WithTimeout() // ERROR "function is not used..."
|
||||
} // ERROR "this return statement may be reached without using the cancel3 var defined on line 27"
|
||||
|
||||
func _() {
|
||||
ctx, _ := context.WithCancel() // ERROR "the cancel function returned by context.WithCancel should be called, not discarded, to avoid a context leak"
|
||||
ctx, _ = context.WithTimeout() // ERROR "the cancel function returned by context.WithTimeout should be called, not discarded, to avoid a context leak"
|
||||
ctx, _ = context.WithDeadline() // ERROR "the cancel function returned by context.WithDeadline should be called, not discarded, to avoid a context leak"
|
||||
}
|
||||
|
||||
func _() {
|
||||
ctx, cancel := context.WithCancel()
|
||||
defer cancel() // ok
|
||||
}
|
||||
|
||||
func _() {
|
||||
ctx, cancel := context.WithCancel() // ERROR "not used on all paths"
|
||||
if condition {
|
||||
cancel()
|
||||
}
|
||||
return // ERROR "this return statement may be reached without using the cancel var"
|
||||
}
|
||||
|
||||
func _() {
|
||||
ctx, cancel := context.WithCancel()
|
||||
if condition {
|
||||
cancel()
|
||||
} else {
|
||||
// ok: infinite loop
|
||||
for {
|
||||
print(0)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func _() {
|
||||
ctx, cancel := context.WithCancel() // ERROR "not used on all paths"
|
||||
if condition {
|
||||
cancel()
|
||||
} else {
|
||||
for i := 0; i < 10; i++ {
|
||||
print(0)
|
||||
}
|
||||
}
|
||||
} // ERROR "this return statement may be reached without using the cancel var"
|
||||
|
||||
func _() {
|
||||
ctx, cancel := context.WithCancel()
|
||||
// ok: used on all paths
|
||||
switch someInt {
|
||||
case 0:
|
||||
new(testing.T).FailNow()
|
||||
case 1:
|
||||
log.Fatal()
|
||||
case 2:
|
||||
cancel()
|
||||
case 3:
|
||||
print("hi")
|
||||
fallthrough
|
||||
default:
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func _() {
|
||||
ctx, cancel := context.WithCancel() // ERROR "not used on all paths"
|
||||
switch someInt {
|
||||
case 0:
|
||||
new(testing.T).FailNow()
|
||||
case 1:
|
||||
log.Fatal()
|
||||
case 2:
|
||||
cancel()
|
||||
case 3:
|
||||
print("hi") // falls through to implicit return
|
||||
default:
|
||||
os.Exit(1)
|
||||
}
|
||||
} // ERROR "this return statement may be reached without using the cancel var"
|
||||
|
||||
func _(ch chan int) int {
|
||||
ctx, cancel := context.WithCancel() // ERROR "not used on all paths"
|
||||
select {
|
||||
case <-ch:
|
||||
new(testing.T).FailNow()
|
||||
case y <- ch:
|
||||
print("hi") // falls through to implicit return
|
||||
case ch <- 1:
|
||||
cancel()
|
||||
default:
|
||||
os.Exit(1)
|
||||
}
|
||||
} // ERROR "this return statement may be reached without using the cancel var"
|
||||
|
||||
func _(ch chan int) int {
|
||||
ctx, cancel := context.WithCancel()
|
||||
// A blocking select must execute one of its cases.
|
||||
select {
|
||||
case <-ch:
|
||||
panic()
|
||||
}
|
||||
}
|
||||
|
||||
func _() {
|
||||
go func() {
|
||||
ctx, cancel := context.WithCancel() // ERROR "not used on all paths"
|
||||
print(ctx)
|
||||
}() // ERROR "may be reached without using the cancel var"
|
||||
}
|
||||
|
||||
var condition bool
|
||||
var someInt int
|
||||
|
||||
// Regression test for Go issue 16143.
|
||||
func _() {
|
||||
var x struct{ f func() }
|
||||
x.f()
|
||||
}
|
||||
|
||||
// Regression test for Go issue 16230.
|
||||
func _() (ctx context.Context, cancel func()) {
|
||||
ctx, cancel = context.WithCancel()
|
||||
return // a naked return counts as a load of the named result values
|
||||
}
|
||||
|
||||
// Same as above, but for literal function.
|
||||
var _ = func() (ctx context.Context, cancel func()) {
|
||||
ctx, cancel = context.WithCancel()
|
||||
return
|
||||
}
|
@ -59,23 +59,28 @@ func lookup(name string, scopes []*types.Scope) types.Object {
|
||||
return nil
|
||||
}
|
||||
|
||||
func extendedScope(pkg *Package) []*types.Scope {
|
||||
scopes := []*types.Scope{pkg.typesPkg.Scope()}
|
||||
|
||||
pkgName := pkg.typesPkg.Name()
|
||||
if strings.HasPrefix(pkgName, "_test") {
|
||||
basePkg := strings.TrimSuffix(pkgName, "_test")
|
||||
for _, p := range pkg.typesPkg.Imports() {
|
||||
if p.Name() == basePkg {
|
||||
scopes = append(scopes, p.Scope())
|
||||
break
|
||||
func extendedScope(f *File) []*types.Scope {
|
||||
scopes := []*types.Scope{f.pkg.typesPkg.Scope()}
|
||||
if f.basePkg != nil {
|
||||
scopes = append(scopes, f.basePkg.typesPkg.Scope())
|
||||
} else {
|
||||
// If basePkg is not specified (e.g. when checking a single file) try to
|
||||
// find it among imports.
|
||||
pkgName := f.pkg.typesPkg.Name()
|
||||
if strings.HasSuffix(pkgName, "_test") {
|
||||
basePkgName := strings.TrimSuffix(pkgName, "_test")
|
||||
for _, p := range f.pkg.typesPkg.Imports() {
|
||||
if p.Name() == basePkgName {
|
||||
scopes = append(scopes, p.Scope())
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return scopes
|
||||
}
|
||||
|
||||
func checkExample(fn *ast.FuncDecl, pkg *Package, report reporter) {
|
||||
func checkExample(fn *ast.FuncDecl, f *File, report reporter) {
|
||||
fnName := fn.Name.Name
|
||||
if params := fn.Type.Params; len(params.List) != 0 {
|
||||
report("%s should be niladic", fnName)
|
||||
@ -100,7 +105,7 @@ func checkExample(fn *ast.FuncDecl, pkg *Package, report reporter) {
|
||||
exName = strings.TrimPrefix(fnName, "Example")
|
||||
elems = strings.SplitN(exName, "_", 3)
|
||||
ident = elems[0]
|
||||
obj = lookup(ident, extendedScope(pkg))
|
||||
obj = lookup(ident, extendedScope(f))
|
||||
)
|
||||
if ident != "" && obj == nil {
|
||||
// Check ExampleFoo and ExampleBadFoo.
|
||||
@ -173,7 +178,7 @@ func checkTestFunctions(f *File, node ast.Node) {
|
||||
|
||||
switch {
|
||||
case strings.HasPrefix(fn.Name.Name, "Example"):
|
||||
checkExample(fn, f.pkg, report)
|
||||
checkExample(fn, f, report)
|
||||
case strings.HasPrefix(fn.Name.Name, "Test"):
|
||||
checkTest(fn, "Test", report)
|
||||
case strings.HasPrefix(fn.Name.Name, "Benchmark"):
|
||||
|
@ -102,7 +102,7 @@ func TestVet(t *testing.T) {
|
||||
func TestDivergentPackagesExamples(t *testing.T) {
|
||||
Build(t)
|
||||
// errchk ./testvet
|
||||
Vet(t, []string{"testdata/divergent/buf.go", "testdata/divergent/buf_test.go"})
|
||||
Vet(t, []string{"testdata/divergent"})
|
||||
}
|
||||
|
||||
func TestIncompleteExamples(t *testing.T) {
|
||||
|
@ -683,6 +683,10 @@ outer:
|
||||
levprd[nprod] = 0
|
||||
}
|
||||
|
||||
if TEMPSIZE < ntokens+nnonter+1 {
|
||||
errorf("too many tokens (%d) or non-terminals (%d)", ntokens, nnonter)
|
||||
}
|
||||
|
||||
//
|
||||
// end of all rules
|
||||
// dump out the prefix code
|
||||
|
@ -766,7 +766,7 @@ func (f *decompressor) Reset(r io.Reader, dict []byte) error {
|
||||
dict: f.dict,
|
||||
step: (*decompressor).nextBlock,
|
||||
}
|
||||
f.dict.init(maxMatchOffset, nil)
|
||||
f.dict.init(maxMatchOffset, dict)
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -37,3 +37,33 @@ func TestReset(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestResetDict(t *testing.T) {
|
||||
dict := []byte("the lorem fox")
|
||||
ss := []string{
|
||||
"lorem ipsum izzle fo rizzle",
|
||||
"the quick brown fox jumped over",
|
||||
}
|
||||
|
||||
deflated := make([]bytes.Buffer, len(ss))
|
||||
for i, s := range ss {
|
||||
w, _ := NewWriterDict(&deflated[i], DefaultCompression, dict)
|
||||
w.Write([]byte(s))
|
||||
w.Close()
|
||||
}
|
||||
|
||||
inflated := make([]bytes.Buffer, len(ss))
|
||||
|
||||
f := NewReader(nil)
|
||||
for i := range inflated {
|
||||
f.(Resetter).Reset(&deflated[i], dict)
|
||||
io.Copy(&inflated[i], f)
|
||||
}
|
||||
f.Close()
|
||||
|
||||
for i, s := range ss {
|
||||
if s != inflated[i].String() {
|
||||
t.Errorf("inflated[%d]:\ngot %q\nwant %q", i, inflated[i], s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,24 +6,35 @@
|
||||
// cancelation signals, and other request-scoped values across API boundaries
|
||||
// and between processes.
|
||||
//
|
||||
// Incoming requests to a server should create a Context, and outgoing calls to
|
||||
// servers should accept a Context. The chain of function calls between must
|
||||
// propagate the Context, optionally replacing it with a modified copy created
|
||||
// using WithDeadline, WithTimeout, WithCancel, or WithValue.
|
||||
// Incoming requests to a server should create a Context, and outgoing
|
||||
// calls to servers should accept a Context. The chain of function
|
||||
// calls between them must propagate the Context, optionally replacing
|
||||
// it with a derived Context created using WithCancel, WithDeadline,
|
||||
// WithTimeout, or WithValue. When a Context is canceled, all
|
||||
// Contexts derived from it are also canceled.
|
||||
//
|
||||
// The WithCancel, WithDeadline, and WithTimeout functions take a
|
||||
// Context (the parent) and return a derived Context (the child) and a
|
||||
// CancelFunc. Calling the CancelFunc cancels the child and its
|
||||
// children, removes the parent's reference to the child, and stops
|
||||
// any associated timers. Failing to call the CancelFunc leaks the
|
||||
// child and its children until the parent is canceled or the timer
|
||||
// fires. The go vet tool checks that CancelFuncs are used on all
|
||||
// control-flow paths.
|
||||
//
|
||||
// Programs that use Contexts should follow these rules to keep interfaces
|
||||
// consistent across packages and enable static analysis tools to check context
|
||||
// propagation:
|
||||
//
|
||||
// Do not store Contexts inside a struct type; instead, pass a Context
|
||||
// explicitly to each function that needs it. The Context should be the first
|
||||
// explicitly to each function that needs it. The Context should be the first
|
||||
// parameter, typically named ctx:
|
||||
//
|
||||
// func DoSomething(ctx context.Context, arg Arg) error {
|
||||
// // ... use ctx ...
|
||||
// }
|
||||
//
|
||||
// Do not pass a nil Context, even if a function permits it. Pass context.TODO
|
||||
// Do not pass a nil Context, even if a function permits it. Pass context.TODO
|
||||
// if you are unsure about which Context to use.
|
||||
//
|
||||
// Use context Values only for request-scoped data that transits processes and
|
||||
@ -50,13 +61,13 @@ import (
|
||||
// Context's methods may be called by multiple goroutines simultaneously.
|
||||
type Context interface {
|
||||
// Deadline returns the time when work done on behalf of this context
|
||||
// should be canceled. Deadline returns ok==false when no deadline is
|
||||
// set. Successive calls to Deadline return the same results.
|
||||
// should be canceled. Deadline returns ok==false when no deadline is
|
||||
// set. Successive calls to Deadline return the same results.
|
||||
Deadline() (deadline time.Time, ok bool)
|
||||
|
||||
// Done returns a channel that's closed when work done on behalf of this
|
||||
// context should be canceled. Done may return nil if this context can
|
||||
// never be canceled. Successive calls to Done return the same value.
|
||||
// context should be canceled. Done may return nil if this context can
|
||||
// never be canceled. Successive calls to Done return the same value.
|
||||
//
|
||||
// WithCancel arranges for Done to be closed when cancel is called;
|
||||
// WithDeadline arranges for Done to be closed when the deadline
|
||||
@ -85,24 +96,24 @@ type Context interface {
|
||||
// a Done channel for cancelation.
|
||||
Done() <-chan struct{}
|
||||
|
||||
// Err returns a non-nil error value after Done is closed. Err returns
|
||||
// Err returns a non-nil error value after Done is closed. Err returns
|
||||
// Canceled if the context was canceled or DeadlineExceeded if the
|
||||
// context's deadline passed. No other values for Err are defined.
|
||||
// context's deadline passed. No other values for Err are defined.
|
||||
// After Done is closed, successive calls to Err return the same value.
|
||||
Err() error
|
||||
|
||||
// Value returns the value associated with this context for key, or nil
|
||||
// if no value is associated with key. Successive calls to Value with
|
||||
// if no value is associated with key. Successive calls to Value with
|
||||
// the same key returns the same result.
|
||||
//
|
||||
// Use context values only for request-scoped data that transits
|
||||
// processes and API boundaries, not for passing optional parameters to
|
||||
// functions.
|
||||
//
|
||||
// A key identifies a specific value in a Context. Functions that wish
|
||||
// A key identifies a specific value in a Context. Functions that wish
|
||||
// to store values in Context typically allocate a key in a global
|
||||
// variable then use that key as the argument to context.WithValue and
|
||||
// Context.Value. A key can be any type that supports equality;
|
||||
// Context.Value. A key can be any type that supports equality;
|
||||
// packages should define keys as an unexported type to avoid
|
||||
// collisions.
|
||||
//
|
||||
@ -121,7 +132,7 @@ type Context interface {
|
||||
// // This prevents collisions with keys defined in other packages.
|
||||
// type key int
|
||||
//
|
||||
// // userKey is the key for user.User values in Contexts. It is
|
||||
// // userKey is the key for user.User values in Contexts. It is
|
||||
// // unexported; clients use user.NewContext and user.FromContext
|
||||
// // instead of using this key directly.
|
||||
// var userKey key = 0
|
||||
@ -152,7 +163,7 @@ func (deadlineExceededError) Error() string { return "context deadline exceeded"
|
||||
|
||||
func (deadlineExceededError) Timeout() bool { return true }
|
||||
|
||||
// An emptyCtx is never canceled, has no values, and has no deadline. It is not
|
||||
// An emptyCtx is never canceled, has no values, and has no deadline. It is not
|
||||
// struct{}, since vars of this type must have distinct addresses.
|
||||
type emptyCtx int
|
||||
|
||||
@ -188,17 +199,17 @@ var (
|
||||
)
|
||||
|
||||
// Background returns a non-nil, empty Context. It is never canceled, has no
|
||||
// values, and has no deadline. It is typically used by the main function,
|
||||
// values, and has no deadline. It is typically used by the main function,
|
||||
// initialization, and tests, and as the top-level Context for incoming
|
||||
// requests.
|
||||
func Background() Context {
|
||||
return background
|
||||
}
|
||||
|
||||
// TODO returns a non-nil, empty Context. Code should use context.TODO when
|
||||
// TODO returns a non-nil, empty Context. Code should use context.TODO when
|
||||
// it's unclear which Context to use or it is not yet available (because the
|
||||
// surrounding function has not yet been extended to accept a Context
|
||||
// parameter). TODO is recognized by static analysis tools that determine
|
||||
// parameter). TODO is recognized by static analysis tools that determine
|
||||
// whether Contexts are propagated correctly in a program.
|
||||
func TODO() Context {
|
||||
return todo
|
||||
@ -258,7 +269,7 @@ func propagateCancel(parent Context, child canceler) {
|
||||
}
|
||||
|
||||
// parentCancelCtx follows a chain of parent references until it finds a
|
||||
// *cancelCtx. This function understands how each of the concrete types in this
|
||||
// *cancelCtx. This function understands how each of the concrete types in this
|
||||
// package represents its parent.
|
||||
func parentCancelCtx(parent Context) (*cancelCtx, bool) {
|
||||
for {
|
||||
@ -288,14 +299,14 @@ func removeChild(parent Context, child canceler) {
|
||||
p.mu.Unlock()
|
||||
}
|
||||
|
||||
// A canceler is a context type that can be canceled directly. The
|
||||
// A canceler is a context type that can be canceled directly. The
|
||||
// implementations are *cancelCtx and *timerCtx.
|
||||
type canceler interface {
|
||||
cancel(removeFromParent bool, err error)
|
||||
Done() <-chan struct{}
|
||||
}
|
||||
|
||||
// A cancelCtx can be canceled. When canceled, it also cancels any children
|
||||
// A cancelCtx can be canceled. When canceled, it also cancels any children
|
||||
// that implement canceler.
|
||||
type cancelCtx struct {
|
||||
Context
|
||||
@ -347,8 +358,8 @@ func (c *cancelCtx) cancel(removeFromParent bool, err error) {
|
||||
}
|
||||
|
||||
// WithDeadline returns a copy of the parent context with the deadline adjusted
|
||||
// to be no later than d. If the parent's deadline is already earlier than d,
|
||||
// WithDeadline(parent, d) is semantically equivalent to parent. The returned
|
||||
// to be no later than d. If the parent's deadline is already earlier than d,
|
||||
// WithDeadline(parent, d) is semantically equivalent to parent. The returned
|
||||
// context's Done channel is closed when the deadline expires, when the returned
|
||||
// cancel function is called, or when the parent context's Done channel is
|
||||
// closed, whichever happens first.
|
||||
@ -380,8 +391,8 @@ func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) {
|
||||
return c, func() { c.cancel(true, Canceled) }
|
||||
}
|
||||
|
||||
// A timerCtx carries a timer and a deadline. It embeds a cancelCtx to
|
||||
// implement Done and Err. It implements cancel by stopping its timer then
|
||||
// A timerCtx carries a timer and a deadline. It embeds a cancelCtx to
|
||||
// implement Done and Err. It implements cancel by stopping its timer then
|
||||
// delegating to cancelCtx.cancel.
|
||||
type timerCtx struct {
|
||||
cancelCtx
|
||||
@ -443,7 +454,7 @@ func WithValue(parent Context, key, val interface{}) Context {
|
||||
return &valueCtx{parent, key, val}
|
||||
}
|
||||
|
||||
// A valueCtx carries a key-value pair. It implements Value for that key and
|
||||
// A valueCtx carries a key-value pair. It implements Value for that key and
|
||||
// delegates all other calls to the embedded Context.
|
||||
type valueCtx struct {
|
||||
Context
|
||||
|
@ -13,13 +13,21 @@ import (
|
||||
func ExampleWithTimeout() {
|
||||
// Pass a context with a timeout to tell a blocking function that it
|
||||
// should abandon its work after the timeout elapses.
|
||||
ctx, _ := context.WithTimeout(context.Background(), 50*time.Millisecond)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond)
|
||||
|
||||
select {
|
||||
case <-time.After(1 * time.Second):
|
||||
fmt.Println("overslept")
|
||||
case <-ctx.Done():
|
||||
fmt.Println(ctx.Err()) // prints "context deadline exceeded"
|
||||
}
|
||||
|
||||
// Even though ctx should have expired already, it is good
|
||||
// practice to call its cancelation function in any case.
|
||||
// Failure to do so may keep the context and its parent alive
|
||||
// longer than necessary.
|
||||
cancel()
|
||||
|
||||
// Output:
|
||||
// context deadline exceeded
|
||||
}
|
||||
|
@ -143,10 +143,11 @@ func fermatInverse(k, N *big.Int) *big.Int {
|
||||
|
||||
var errZeroParam = errors.New("zero parameter")
|
||||
|
||||
// Sign signs an arbitrary length hash (which should be the result of hashing a
|
||||
// larger message) using the private key, priv. It returns the signature as a
|
||||
// pair of integers. The security of the private key depends on the entropy of
|
||||
// rand.
|
||||
// Sign signs a hash (which should be the result of hashing a larger message)
|
||||
// using the private key, priv. If the hash is longer than the bit-length of the
|
||||
// private key's curve order, the hash will be truncated to that length. It
|
||||
// returns the signature as a pair of integers. The security of the private key
|
||||
// depends on the entropy of rand.
|
||||
func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) {
|
||||
// Get max(log2(q) / 2, 256) bits of entropy from rand.
|
||||
entropylen := (priv.Curve.Params().BitSize + 7) / 16
|
||||
|
@ -422,6 +422,33 @@ func ticketKeyFromBytes(b [32]byte) (key ticketKey) {
|
||||
return key
|
||||
}
|
||||
|
||||
// clone returns a copy of c. Only the exported fields are copied.
|
||||
func (c *Config) clone() *Config {
|
||||
return &Config{
|
||||
Rand: c.Rand,
|
||||
Time: c.Time,
|
||||
Certificates: c.Certificates,
|
||||
NameToCertificate: c.NameToCertificate,
|
||||
GetCertificate: c.GetCertificate,
|
||||
RootCAs: c.RootCAs,
|
||||
NextProtos: c.NextProtos,
|
||||
ServerName: c.ServerName,
|
||||
ClientAuth: c.ClientAuth,
|
||||
ClientCAs: c.ClientCAs,
|
||||
InsecureSkipVerify: c.InsecureSkipVerify,
|
||||
CipherSuites: c.CipherSuites,
|
||||
PreferServerCipherSuites: c.PreferServerCipherSuites,
|
||||
SessionTicketsDisabled: c.SessionTicketsDisabled,
|
||||
SessionTicketKey: c.SessionTicketKey,
|
||||
ClientSessionCache: c.ClientSessionCache,
|
||||
MinVersion: c.MinVersion,
|
||||
MaxVersion: c.MaxVersion,
|
||||
CurvePreferences: c.CurvePreferences,
|
||||
DynamicRecordSizingDisabled: c.DynamicRecordSizingDisabled,
|
||||
Renegotiation: c.Renegotiation,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Config) serverInit() {
|
||||
if c.SessionTicketsDisabled {
|
||||
return
|
||||
|
@ -124,9 +124,9 @@ func TestCertificateSelection(t *testing.T) {
|
||||
func runDynamicRecordSizingTest(t *testing.T, config *Config) {
|
||||
clientConn, serverConn := net.Pipe()
|
||||
|
||||
serverConfig := *config
|
||||
serverConfig := config.clone()
|
||||
serverConfig.DynamicRecordSizingDisabled = false
|
||||
tlsConn := Server(serverConn, &serverConfig)
|
||||
tlsConn := Server(serverConn, serverConfig)
|
||||
|
||||
recordSizesChan := make(chan []int, 1)
|
||||
go func() {
|
||||
@ -225,19 +225,19 @@ func runDynamicRecordSizingTest(t *testing.T, config *Config) {
|
||||
}
|
||||
|
||||
func TestDynamicRecordSizingWithStreamCipher(t *testing.T) {
|
||||
config := *testConfig
|
||||
config := testConfig.clone()
|
||||
config.CipherSuites = []uint16{TLS_RSA_WITH_RC4_128_SHA}
|
||||
runDynamicRecordSizingTest(t, &config)
|
||||
runDynamicRecordSizingTest(t, config)
|
||||
}
|
||||
|
||||
func TestDynamicRecordSizingWithCBC(t *testing.T) {
|
||||
config := *testConfig
|
||||
config := testConfig.clone()
|
||||
config.CipherSuites = []uint16{TLS_RSA_WITH_AES_256_CBC_SHA}
|
||||
runDynamicRecordSizingTest(t, &config)
|
||||
runDynamicRecordSizingTest(t, config)
|
||||
}
|
||||
|
||||
func TestDynamicRecordSizingWithAEAD(t *testing.T) {
|
||||
config := *testConfig
|
||||
config := testConfig.clone()
|
||||
config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}
|
||||
runDynamicRecordSizingTest(t, &config)
|
||||
runDynamicRecordSizingTest(t, config)
|
||||
}
|
||||
|
@ -509,14 +509,14 @@ func TestHandshakeClientAES256GCMSHA384(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestHandshakeClientCertRSA(t *testing.T) {
|
||||
config := *testConfig
|
||||
config := testConfig.clone()
|
||||
cert, _ := X509KeyPair([]byte(clientCertificatePEM), []byte(clientKeyPEM))
|
||||
config.Certificates = []Certificate{cert}
|
||||
|
||||
test := &clientTest{
|
||||
name: "ClientCert-RSA-RSA",
|
||||
command: []string{"openssl", "s_server", "-cipher", "RC4-SHA", "-verify", "1"},
|
||||
config: &config,
|
||||
config: config,
|
||||
}
|
||||
|
||||
runClientTestTLS10(t, test)
|
||||
@ -525,7 +525,7 @@ func TestHandshakeClientCertRSA(t *testing.T) {
|
||||
test = &clientTest{
|
||||
name: "ClientCert-RSA-ECDSA",
|
||||
command: []string{"openssl", "s_server", "-cipher", "ECDHE-ECDSA-AES128-SHA", "-verify", "1"},
|
||||
config: &config,
|
||||
config: config,
|
||||
cert: testECDSACertificate,
|
||||
key: testECDSAPrivateKey,
|
||||
}
|
||||
@ -536,7 +536,7 @@ func TestHandshakeClientCertRSA(t *testing.T) {
|
||||
test = &clientTest{
|
||||
name: "ClientCert-RSA-AES256-GCM-SHA384",
|
||||
command: []string{"openssl", "s_server", "-cipher", "ECDHE-RSA-AES256-GCM-SHA384", "-verify", "1"},
|
||||
config: &config,
|
||||
config: config,
|
||||
cert: testRSACertificate,
|
||||
key: testRSAPrivateKey,
|
||||
}
|
||||
@ -545,14 +545,14 @@ func TestHandshakeClientCertRSA(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestHandshakeClientCertECDSA(t *testing.T) {
|
||||
config := *testConfig
|
||||
config := testConfig.clone()
|
||||
cert, _ := X509KeyPair([]byte(clientECDSACertificatePEM), []byte(clientECDSAKeyPEM))
|
||||
config.Certificates = []Certificate{cert}
|
||||
|
||||
test := &clientTest{
|
||||
name: "ClientCert-ECDSA-RSA",
|
||||
command: []string{"openssl", "s_server", "-cipher", "RC4-SHA", "-verify", "1"},
|
||||
config: &config,
|
||||
config: config,
|
||||
}
|
||||
|
||||
runClientTestTLS10(t, test)
|
||||
@ -561,7 +561,7 @@ func TestHandshakeClientCertECDSA(t *testing.T) {
|
||||
test = &clientTest{
|
||||
name: "ClientCert-ECDSA-ECDSA",
|
||||
command: []string{"openssl", "s_server", "-cipher", "ECDHE-ECDSA-AES128-SHA", "-verify", "1"},
|
||||
config: &config,
|
||||
config: config,
|
||||
cert: testECDSACertificate,
|
||||
key: testECDSAPrivateKey,
|
||||
}
|
||||
@ -691,7 +691,7 @@ func TestLRUClientSessionCache(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestHandshakeClientALPNMatch(t *testing.T) {
|
||||
config := *testConfig
|
||||
config := testConfig.clone()
|
||||
config.NextProtos = []string{"proto2", "proto1"}
|
||||
|
||||
test := &clientTest{
|
||||
@ -699,7 +699,7 @@ func TestHandshakeClientALPNMatch(t *testing.T) {
|
||||
// Note that this needs OpenSSL 1.0.2 because that is the first
|
||||
// version that supports the -alpn flag.
|
||||
command: []string{"openssl", "s_server", "-alpn", "proto1,proto2"},
|
||||
config: &config,
|
||||
config: config,
|
||||
validate: func(state ConnectionState) error {
|
||||
// The server's preferences should override the client.
|
||||
if state.NegotiatedProtocol != "proto1" {
|
||||
@ -712,7 +712,7 @@ func TestHandshakeClientALPNMatch(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestHandshakeClientALPNNoMatch(t *testing.T) {
|
||||
config := *testConfig
|
||||
config := testConfig.clone()
|
||||
config.NextProtos = []string{"proto3"}
|
||||
|
||||
test := &clientTest{
|
||||
@ -720,7 +720,7 @@ func TestHandshakeClientALPNNoMatch(t *testing.T) {
|
||||
// Note that this needs OpenSSL 1.0.2 because that is the first
|
||||
// version that supports the -alpn flag.
|
||||
command: []string{"openssl", "s_server", "-alpn", "proto1,proto2"},
|
||||
config: &config,
|
||||
config: config,
|
||||
validate: func(state ConnectionState) error {
|
||||
// There's no overlap so OpenSSL will not select a protocol.
|
||||
if state.NegotiatedProtocol != "" {
|
||||
@ -736,7 +736,7 @@ func TestHandshakeClientALPNNoMatch(t *testing.T) {
|
||||
const sctsBase64 = "ABIBaQFnAHUApLkJkLQYWBSHuxOizGdwCjw1mAT5G9+443fNDsgN3BAAAAFHl5nuFgAABAMARjBEAiAcS4JdlW5nW9sElUv2zvQyPoZ6ejKrGGB03gjaBZFMLwIgc1Qbbn+hsH0RvObzhS+XZhr3iuQQJY8S9G85D9KeGPAAdgBo9pj4H2SCvjqM7rkoHUz8cVFdZ5PURNEKZ6y7T0/7xAAAAUeX4bVwAAAEAwBHMEUCIDIhFDgG2HIuADBkGuLobU5a4dlCHoJLliWJ1SYT05z6AiEAjxIoZFFPRNWMGGIjskOTMwXzQ1Wh2e7NxXE1kd1J0QsAdgDuS723dc5guuFCaR+r4Z5mow9+X7By2IMAxHuJeqj9ywAAAUhcZIqHAAAEAwBHMEUCICmJ1rBT09LpkbzxtUC+Hi7nXLR0J+2PmwLp+sJMuqK+AiEAr0NkUnEVKVhAkccIFpYDqHOlZaBsuEhWWrYpg2RtKp0="
|
||||
|
||||
func TestHandshakClientSCTs(t *testing.T) {
|
||||
config := *testConfig
|
||||
config := testConfig.clone()
|
||||
|
||||
scts, err := base64.StdEncoding.DecodeString(sctsBase64)
|
||||
if err != nil {
|
||||
@ -748,7 +748,7 @@ func TestHandshakClientSCTs(t *testing.T) {
|
||||
// Note that this needs OpenSSL 1.0.2 because that is the first
|
||||
// version that supports the -serverinfo flag.
|
||||
command: []string{"openssl", "s_server"},
|
||||
config: &config,
|
||||
config: config,
|
||||
extensions: [][]byte{scts},
|
||||
validate: func(state ConnectionState) error {
|
||||
expectedSCTs := [][]byte{
|
||||
@ -771,11 +771,11 @@ func TestHandshakClientSCTs(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRenegotiationRejected(t *testing.T) {
|
||||
config := *testConfig
|
||||
config := testConfig.clone()
|
||||
test := &clientTest{
|
||||
name: "RenegotiationRejected",
|
||||
command: []string{"openssl", "s_server", "-state"},
|
||||
config: &config,
|
||||
config: config,
|
||||
numRenegotiations: 1,
|
||||
renegotiationExpectedToFail: 1,
|
||||
checkRenegotiationError: func(renegotiationNum int, err error) error {
|
||||
@ -793,13 +793,13 @@ func TestRenegotiationRejected(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRenegotiateOnce(t *testing.T) {
|
||||
config := *testConfig
|
||||
config := testConfig.clone()
|
||||
config.Renegotiation = RenegotiateOnceAsClient
|
||||
|
||||
test := &clientTest{
|
||||
name: "RenegotiateOnce",
|
||||
command: []string{"openssl", "s_server", "-state"},
|
||||
config: &config,
|
||||
config: config,
|
||||
numRenegotiations: 1,
|
||||
}
|
||||
|
||||
@ -807,13 +807,13 @@ func TestRenegotiateOnce(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRenegotiateTwice(t *testing.T) {
|
||||
config := *testConfig
|
||||
config := testConfig.clone()
|
||||
config.Renegotiation = RenegotiateFreelyAsClient
|
||||
|
||||
test := &clientTest{
|
||||
name: "RenegotiateTwice",
|
||||
command: []string{"openssl", "s_server", "-state"},
|
||||
config: &config,
|
||||
config: config,
|
||||
numRenegotiations: 2,
|
||||
}
|
||||
|
||||
@ -821,13 +821,13 @@ func TestRenegotiateTwice(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestRenegotiateTwiceRejected(t *testing.T) {
|
||||
config := *testConfig
|
||||
config := testConfig.clone()
|
||||
config.Renegotiation = RenegotiateOnceAsClient
|
||||
|
||||
test := &clientTest{
|
||||
name: "RenegotiateTwiceRejected",
|
||||
command: []string{"openssl", "s_server", "-state"},
|
||||
config: &config,
|
||||
config: config,
|
||||
numRenegotiations: 2,
|
||||
renegotiationExpectedToFail: 2,
|
||||
checkRenegotiationError: func(renegotiationNum int, err error) error {
|
||||
|
@ -130,11 +130,11 @@ func TestNoRC4ByDefault(t *testing.T) {
|
||||
cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
|
||||
compressionMethods: []uint8{compressionNone},
|
||||
}
|
||||
serverConfig := *testConfig
|
||||
serverConfig := testConfig.clone()
|
||||
// Reset the enabled cipher suites to nil in order to test the
|
||||
// defaults.
|
||||
serverConfig.CipherSuites = nil
|
||||
testClientHelloFailure(t, &serverConfig, clientHello, "no cipher suite supported by both client and server")
|
||||
testClientHelloFailure(t, serverConfig, clientHello, "no cipher suite supported by both client and server")
|
||||
}
|
||||
|
||||
func TestDontSelectECDSAWithRSAKey(t *testing.T) {
|
||||
@ -147,19 +147,19 @@ func TestDontSelectECDSAWithRSAKey(t *testing.T) {
|
||||
supportedCurves: []CurveID{CurveP256},
|
||||
supportedPoints: []uint8{pointFormatUncompressed},
|
||||
}
|
||||
serverConfig := *testConfig
|
||||
serverConfig := testConfig.clone()
|
||||
serverConfig.CipherSuites = clientHello.cipherSuites
|
||||
serverConfig.Certificates = make([]Certificate, 1)
|
||||
serverConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate}
|
||||
serverConfig.Certificates[0].PrivateKey = testECDSAPrivateKey
|
||||
serverConfig.BuildNameToCertificate()
|
||||
// First test that it *does* work when the server's key is ECDSA.
|
||||
testClientHello(t, &serverConfig, clientHello)
|
||||
testClientHello(t, serverConfig, clientHello)
|
||||
|
||||
// Now test that switching to an RSA key causes the expected error (and
|
||||
// not an internal error about a signing failure).
|
||||
serverConfig.Certificates = testConfig.Certificates
|
||||
testClientHelloFailure(t, &serverConfig, clientHello, "no cipher suite supported by both client and server")
|
||||
testClientHelloFailure(t, serverConfig, clientHello, "no cipher suite supported by both client and server")
|
||||
}
|
||||
|
||||
func TestDontSelectRSAWithECDSAKey(t *testing.T) {
|
||||
@ -172,10 +172,10 @@ func TestDontSelectRSAWithECDSAKey(t *testing.T) {
|
||||
supportedCurves: []CurveID{CurveP256},
|
||||
supportedPoints: []uint8{pointFormatUncompressed},
|
||||
}
|
||||
serverConfig := *testConfig
|
||||
serverConfig := testConfig.clone()
|
||||
serverConfig.CipherSuites = clientHello.cipherSuites
|
||||
// First test that it *does* work when the server's key is RSA.
|
||||
testClientHello(t, &serverConfig, clientHello)
|
||||
testClientHello(t, serverConfig, clientHello)
|
||||
|
||||
// Now test that switching to an ECDSA key causes the expected error
|
||||
// (and not an internal error about a signing failure).
|
||||
@ -183,7 +183,7 @@ func TestDontSelectRSAWithECDSAKey(t *testing.T) {
|
||||
serverConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate}
|
||||
serverConfig.Certificates[0].PrivateKey = testECDSAPrivateKey
|
||||
serverConfig.BuildNameToCertificate()
|
||||
testClientHelloFailure(t, &serverConfig, clientHello, "no cipher suite supported by both client and server")
|
||||
testClientHelloFailure(t, serverConfig, clientHello, "no cipher suite supported by both client and server")
|
||||
}
|
||||
|
||||
func TestRenegotiationExtension(t *testing.T) {
|
||||
@ -265,9 +265,9 @@ func TestTLS12OnlyCipherSuites(t *testing.T) {
|
||||
reply, clientErr = cli.readHandshake()
|
||||
c.Close()
|
||||
}()
|
||||
config := *testConfig
|
||||
config := testConfig.clone()
|
||||
config.CipherSuites = clientHello.cipherSuites
|
||||
Server(s, &config).Handshake()
|
||||
Server(s, config).Handshake()
|
||||
s.Close()
|
||||
if clientErr != nil {
|
||||
t.Fatal(clientErr)
|
||||
@ -732,7 +732,7 @@ func TestHandshakeServerAES256GCMSHA384(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestHandshakeServerECDHEECDSAAES(t *testing.T) {
|
||||
config := *testConfig
|
||||
config := testConfig.clone()
|
||||
config.Certificates = make([]Certificate, 1)
|
||||
config.Certificates[0].Certificate = [][]byte{testECDSACertificate}
|
||||
config.Certificates[0].PrivateKey = testECDSAPrivateKey
|
||||
@ -741,14 +741,14 @@ func TestHandshakeServerECDHEECDSAAES(t *testing.T) {
|
||||
test := &serverTest{
|
||||
name: "ECDHE-ECDSA-AES",
|
||||
command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "ECDHE-ECDSA-AES256-SHA"},
|
||||
config: &config,
|
||||
config: config,
|
||||
}
|
||||
runServerTestTLS10(t, test)
|
||||
runServerTestTLS12(t, test)
|
||||
}
|
||||
|
||||
func TestHandshakeServerALPN(t *testing.T) {
|
||||
config := *testConfig
|
||||
config := testConfig.clone()
|
||||
config.NextProtos = []string{"proto1", "proto2"}
|
||||
|
||||
test := &serverTest{
|
||||
@ -756,7 +756,7 @@ func TestHandshakeServerALPN(t *testing.T) {
|
||||
// Note that this needs OpenSSL 1.0.2 because that is the first
|
||||
// version that supports the -alpn flag.
|
||||
command: []string{"openssl", "s_client", "-alpn", "proto2,proto1"},
|
||||
config: &config,
|
||||
config: config,
|
||||
validate: func(state ConnectionState) error {
|
||||
// The server's preferences should override the client.
|
||||
if state.NegotiatedProtocol != "proto1" {
|
||||
@ -769,7 +769,7 @@ func TestHandshakeServerALPN(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestHandshakeServerALPNNoMatch(t *testing.T) {
|
||||
config := *testConfig
|
||||
config := testConfig.clone()
|
||||
config.NextProtos = []string{"proto3"}
|
||||
|
||||
test := &serverTest{
|
||||
@ -777,7 +777,7 @@ func TestHandshakeServerALPNNoMatch(t *testing.T) {
|
||||
// Note that this needs OpenSSL 1.0.2 because that is the first
|
||||
// version that supports the -alpn flag.
|
||||
command: []string{"openssl", "s_client", "-alpn", "proto2,proto1"},
|
||||
config: &config,
|
||||
config: config,
|
||||
validate: func(state ConnectionState) error {
|
||||
// Rather than reject the connection, Go doesn't select
|
||||
// a protocol when there is no overlap.
|
||||
@ -804,7 +804,7 @@ func TestHandshakeServerSNI(t *testing.T) {
|
||||
// TestHandshakeServerSNICertForName is similar to TestHandshakeServerSNI, but
|
||||
// tests the dynamic GetCertificate method
|
||||
func TestHandshakeServerSNIGetCertificate(t *testing.T) {
|
||||
config := *testConfig
|
||||
config := testConfig.clone()
|
||||
|
||||
// Replace the NameToCertificate map with a GetCertificate function
|
||||
nameToCert := config.NameToCertificate
|
||||
@ -816,7 +816,7 @@ func TestHandshakeServerSNIGetCertificate(t *testing.T) {
|
||||
test := &serverTest{
|
||||
name: "SNI-GetCertificate",
|
||||
command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA", "-servername", "snitest.com"},
|
||||
config: &config,
|
||||
config: config,
|
||||
}
|
||||
runServerTestTLS12(t, test)
|
||||
}
|
||||
@ -826,7 +826,7 @@ func TestHandshakeServerSNIGetCertificate(t *testing.T) {
|
||||
// GetCertificate method doesn't return a cert, we fall back to what's in
|
||||
// the NameToCertificate map.
|
||||
func TestHandshakeServerSNIGetCertificateNotFound(t *testing.T) {
|
||||
config := *testConfig
|
||||
config := testConfig.clone()
|
||||
|
||||
config.GetCertificate = func(clientHello *ClientHelloInfo) (*Certificate, error) {
|
||||
return nil, nil
|
||||
@ -834,7 +834,7 @@ func TestHandshakeServerSNIGetCertificateNotFound(t *testing.T) {
|
||||
test := &serverTest{
|
||||
name: "SNI-GetCertificateNotFound",
|
||||
command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA", "-servername", "snitest.com"},
|
||||
config: &config,
|
||||
config: config,
|
||||
}
|
||||
runServerTestTLS12(t, test)
|
||||
}
|
||||
@ -844,7 +844,7 @@ func TestHandshakeServerSNIGetCertificateNotFound(t *testing.T) {
|
||||
func TestHandshakeServerSNIGetCertificateError(t *testing.T) {
|
||||
const errMsg = "TestHandshakeServerSNIGetCertificateError error"
|
||||
|
||||
serverConfig := *testConfig
|
||||
serverConfig := testConfig.clone()
|
||||
serverConfig.GetCertificate = func(clientHello *ClientHelloInfo) (*Certificate, error) {
|
||||
return nil, errors.New(errMsg)
|
||||
}
|
||||
@ -855,7 +855,7 @@ func TestHandshakeServerSNIGetCertificateError(t *testing.T) {
|
||||
compressionMethods: []uint8{compressionNone},
|
||||
serverName: "test",
|
||||
}
|
||||
testClientHelloFailure(t, &serverConfig, clientHello, errMsg)
|
||||
testClientHelloFailure(t, serverConfig, clientHello, errMsg)
|
||||
}
|
||||
|
||||
// TestHandshakeServerEmptyCertificates tests that GetCertificates is called in
|
||||
@ -863,7 +863,7 @@ func TestHandshakeServerSNIGetCertificateError(t *testing.T) {
|
||||
func TestHandshakeServerEmptyCertificates(t *testing.T) {
|
||||
const errMsg = "TestHandshakeServerEmptyCertificates error"
|
||||
|
||||
serverConfig := *testConfig
|
||||
serverConfig := testConfig.clone()
|
||||
serverConfig.GetCertificate = func(clientHello *ClientHelloInfo) (*Certificate, error) {
|
||||
return nil, errors.New(errMsg)
|
||||
}
|
||||
@ -874,7 +874,7 @@ func TestHandshakeServerEmptyCertificates(t *testing.T) {
|
||||
cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
|
||||
compressionMethods: []uint8{compressionNone},
|
||||
}
|
||||
testClientHelloFailure(t, &serverConfig, clientHello, errMsg)
|
||||
testClientHelloFailure(t, serverConfig, clientHello, errMsg)
|
||||
|
||||
// With an empty Certificates and a nil GetCertificate, the server
|
||||
// should always return a “no certificates” error.
|
||||
@ -885,23 +885,23 @@ func TestHandshakeServerEmptyCertificates(t *testing.T) {
|
||||
cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
|
||||
compressionMethods: []uint8{compressionNone},
|
||||
}
|
||||
testClientHelloFailure(t, &serverConfig, clientHello, "no certificates")
|
||||
testClientHelloFailure(t, serverConfig, clientHello, "no certificates")
|
||||
}
|
||||
|
||||
// TestCipherSuiteCertPreferance ensures that we select an RSA ciphersuite with
|
||||
// an RSA certificate and an ECDSA ciphersuite with an ECDSA certificate.
|
||||
func TestCipherSuiteCertPreferenceECDSA(t *testing.T) {
|
||||
config := *testConfig
|
||||
config := testConfig.clone()
|
||||
config.CipherSuites = []uint16{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA}
|
||||
config.PreferServerCipherSuites = true
|
||||
|
||||
test := &serverTest{
|
||||
name: "CipherSuiteCertPreferenceRSA",
|
||||
config: &config,
|
||||
config: config,
|
||||
}
|
||||
runServerTestTLS12(t, test)
|
||||
|
||||
config = *testConfig
|
||||
config = testConfig.clone()
|
||||
config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA}
|
||||
config.Certificates = []Certificate{
|
||||
{
|
||||
@ -914,7 +914,7 @@ func TestCipherSuiteCertPreferenceECDSA(t *testing.T) {
|
||||
|
||||
test = &serverTest{
|
||||
name: "CipherSuiteCertPreferenceECDSA",
|
||||
config: &config,
|
||||
config: config,
|
||||
}
|
||||
runServerTestTLS12(t, test)
|
||||
}
|
||||
@ -940,12 +940,12 @@ func TestResumptionDisabled(t *testing.T) {
|
||||
sessionFilePath := tempFile("")
|
||||
defer os.Remove(sessionFilePath)
|
||||
|
||||
config := *testConfig
|
||||
config := testConfig.clone()
|
||||
|
||||
test := &serverTest{
|
||||
name: "IssueTicketPreDisable",
|
||||
command: []string{"openssl", "s_client", "-cipher", "RC4-SHA", "-sess_out", sessionFilePath},
|
||||
config: &config,
|
||||
config: config,
|
||||
}
|
||||
runServerTestTLS12(t, test)
|
||||
|
||||
@ -954,7 +954,7 @@ func TestResumptionDisabled(t *testing.T) {
|
||||
test = &serverTest{
|
||||
name: "ResumeDisabled",
|
||||
command: []string{"openssl", "s_client", "-cipher", "RC4-SHA", "-sess_in", sessionFilePath},
|
||||
config: &config,
|
||||
config: config,
|
||||
}
|
||||
runServerTestTLS12(t, test)
|
||||
|
||||
@ -963,12 +963,12 @@ func TestResumptionDisabled(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFallbackSCSV(t *testing.T) {
|
||||
serverConfig := &Config{
|
||||
serverConfig := Config{
|
||||
Certificates: testConfig.Certificates,
|
||||
}
|
||||
test := &serverTest{
|
||||
name: "FallbackSCSV",
|
||||
config: serverConfig,
|
||||
config: &serverConfig,
|
||||
// OpenSSL 1.0.1j is needed for the -fallback_scsv option.
|
||||
command: []string{"openssl", "s_client", "-fallback_scsv"},
|
||||
expectHandshakeErrorIncluding: "inappropriate protocol fallback",
|
||||
@ -1053,20 +1053,20 @@ func TestClientAuth(t *testing.T) {
|
||||
defer os.Remove(ecdsaKeyPath)
|
||||
}
|
||||
|
||||
config := *testConfig
|
||||
config := testConfig.clone()
|
||||
config.ClientAuth = RequestClientCert
|
||||
|
||||
test := &serverTest{
|
||||
name: "ClientAuthRequestedNotGiven",
|
||||
command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "RC4-SHA"},
|
||||
config: &config,
|
||||
config: config,
|
||||
}
|
||||
runServerTestTLS12(t, test)
|
||||
|
||||
test = &serverTest{
|
||||
name: "ClientAuthRequestedAndGiven",
|
||||
command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "RC4-SHA", "-cert", certPath, "-key", keyPath},
|
||||
config: &config,
|
||||
config: config,
|
||||
expectedPeerCerts: []string{clientCertificatePEM},
|
||||
}
|
||||
runServerTestTLS12(t, test)
|
||||
@ -1074,7 +1074,7 @@ func TestClientAuth(t *testing.T) {
|
||||
test = &serverTest{
|
||||
name: "ClientAuthRequestedAndECDSAGiven",
|
||||
command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "RC4-SHA", "-cert", ecdsaCertPath, "-key", ecdsaKeyPath},
|
||||
config: &config,
|
||||
config: config,
|
||||
expectedPeerCerts: []string{clientECDSACertificatePEM},
|
||||
}
|
||||
runServerTestTLS12(t, test)
|
||||
|
@ -135,9 +135,9 @@ func DialWithDialer(dialer *net.Dialer, network, addr string, config *Config) (*
|
||||
// from the hostname we're connecting to.
|
||||
if config.ServerName == "" {
|
||||
// Make a copy to avoid polluting argument or default.
|
||||
c := *config
|
||||
c := config.clone()
|
||||
c.ServerName = hostname
|
||||
config = &c
|
||||
config = c
|
||||
}
|
||||
|
||||
conn := Client(rawConn, config)
|
||||
|
@ -6,14 +6,19 @@ package tls
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/x509"
|
||||
"errors"
|
||||
"fmt"
|
||||
"internal/testenv"
|
||||
"io"
|
||||
"math"
|
||||
"math/rand"
|
||||
"net"
|
||||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"testing/quick"
|
||||
"time"
|
||||
)
|
||||
|
||||
@ -236,8 +241,8 @@ func testConnReadNonzeroAndEOF(t *testing.T, delay time.Duration) error {
|
||||
srvCh <- nil
|
||||
return
|
||||
}
|
||||
serverConfig := *testConfig
|
||||
srv := Server(sconn, &serverConfig)
|
||||
serverConfig := testConfig.clone()
|
||||
srv := Server(sconn, serverConfig)
|
||||
if err := srv.Handshake(); err != nil {
|
||||
serr = fmt.Errorf("handshake: %v", err)
|
||||
srvCh <- nil
|
||||
@ -246,8 +251,8 @@ func testConnReadNonzeroAndEOF(t *testing.T, delay time.Duration) error {
|
||||
srvCh <- srv
|
||||
}()
|
||||
|
||||
clientConfig := *testConfig
|
||||
conn, err := Dial("tcp", ln.Addr().String(), &clientConfig)
|
||||
clientConfig := testConfig.clone()
|
||||
conn, err := Dial("tcp", ln.Addr().String(), clientConfig)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -290,8 +295,8 @@ func TestTLSUniqueMatches(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
serverConfig := *testConfig
|
||||
srv := Server(sconn, &serverConfig)
|
||||
serverConfig := testConfig.clone()
|
||||
srv := Server(sconn, serverConfig)
|
||||
if err := srv.Handshake(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -299,9 +304,9 @@ func TestTLSUniqueMatches(t *testing.T) {
|
||||
}
|
||||
}()
|
||||
|
||||
clientConfig := *testConfig
|
||||
clientConfig := testConfig.clone()
|
||||
clientConfig.ClientSessionCache = NewLRUClientSessionCache(1)
|
||||
conn, err := Dial("tcp", ln.Addr().String(), &clientConfig)
|
||||
conn, err := Dial("tcp", ln.Addr().String(), clientConfig)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -310,7 +315,7 @@ func TestTLSUniqueMatches(t *testing.T) {
|
||||
}
|
||||
conn.Close()
|
||||
|
||||
conn, err = Dial("tcp", ln.Addr().String(), &clientConfig)
|
||||
conn, err = Dial("tcp", ln.Addr().String(), clientConfig)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -389,8 +394,8 @@ func TestConnCloseBreakingWrite(t *testing.T) {
|
||||
srvCh <- nil
|
||||
return
|
||||
}
|
||||
serverConfig := *testConfig
|
||||
srv := Server(sconn, &serverConfig)
|
||||
serverConfig := testConfig.clone()
|
||||
srv := Server(sconn, serverConfig)
|
||||
if err := srv.Handshake(); err != nil {
|
||||
serr = fmt.Errorf("handshake: %v", err)
|
||||
srvCh <- nil
|
||||
@ -409,8 +414,8 @@ func TestConnCloseBreakingWrite(t *testing.T) {
|
||||
Conn: cconn,
|
||||
}
|
||||
|
||||
clientConfig := *testConfig
|
||||
tconn := Client(conn, &clientConfig)
|
||||
clientConfig := testConfig.clone()
|
||||
tconn := Client(conn, clientConfig)
|
||||
if err := tconn.Handshake(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@ -453,6 +458,58 @@ func TestConnCloseBreakingWrite(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestClone(t *testing.T) {
|
||||
var c1 Config
|
||||
v := reflect.ValueOf(&c1).Elem()
|
||||
|
||||
rnd := rand.New(rand.NewSource(time.Now().Unix()))
|
||||
typ := v.Type()
|
||||
for i := 0; i < typ.NumField(); i++ {
|
||||
f := v.Field(i)
|
||||
if !f.CanSet() {
|
||||
// unexported field; not cloned.
|
||||
continue
|
||||
}
|
||||
|
||||
// testing/quick can't handle functions or interfaces.
|
||||
fn := typ.Field(i).Name
|
||||
switch fn {
|
||||
case "Rand":
|
||||
f.Set(reflect.ValueOf(io.Reader(os.Stdin)))
|
||||
continue
|
||||
case "Time", "GetCertificate":
|
||||
// DeepEqual can't compare functions.
|
||||
continue
|
||||
case "Certificates":
|
||||
f.Set(reflect.ValueOf([]Certificate{
|
||||
{Certificate: [][]byte{[]byte{'b'}}},
|
||||
}))
|
||||
continue
|
||||
case "NameToCertificate":
|
||||
f.Set(reflect.ValueOf(map[string]*Certificate{"a": nil}))
|
||||
continue
|
||||
case "RootCAs", "ClientCAs":
|
||||
f.Set(reflect.ValueOf(x509.NewCertPool()))
|
||||
continue
|
||||
case "ClientSessionCache":
|
||||
f.Set(reflect.ValueOf(NewLRUClientSessionCache(10)))
|
||||
continue
|
||||
}
|
||||
|
||||
q, ok := quick.Value(f.Type(), rnd)
|
||||
if !ok {
|
||||
t.Fatalf("quick.Value failed on field %s", fn)
|
||||
}
|
||||
f.Set(q)
|
||||
}
|
||||
|
||||
c2 := c1.clone()
|
||||
|
||||
if !reflect.DeepEqual(&c1, c2) {
|
||||
t.Errorf("clone failed to copy a field")
|
||||
}
|
||||
}
|
||||
|
||||
// changeImplConn is a net.Conn which can change its Write and Close
|
||||
// methods.
|
||||
type changeImplConn struct {
|
||||
@ -481,7 +538,12 @@ func throughput(b *testing.B, totalBytes int64, dynamicRecordSizingDisabled bool
|
||||
|
||||
N := b.N
|
||||
|
||||
// Less than 64KB because Windows appears to use a TCP rwin < 64KB.
|
||||
// See Issue #15899.
|
||||
const bufsize = 32 << 10
|
||||
|
||||
go func() {
|
||||
buf := make([]byte, bufsize)
|
||||
for i := 0; i < N; i++ {
|
||||
sconn, err := ln.Accept()
|
||||
if err != nil {
|
||||
@ -489,24 +551,26 @@ func throughput(b *testing.B, totalBytes int64, dynamicRecordSizingDisabled bool
|
||||
// (cannot call b.Fatal in goroutine)
|
||||
panic(fmt.Errorf("accept: %v", err))
|
||||
}
|
||||
serverConfig := *testConfig
|
||||
serverConfig := testConfig.clone()
|
||||
serverConfig.DynamicRecordSizingDisabled = dynamicRecordSizingDisabled
|
||||
srv := Server(sconn, &serverConfig)
|
||||
srv := Server(sconn, serverConfig)
|
||||
if err := srv.Handshake(); err != nil {
|
||||
panic(fmt.Errorf("handshake: %v", err))
|
||||
}
|
||||
io.Copy(srv, srv)
|
||||
if _, err := io.CopyBuffer(srv, srv, buf); err != nil {
|
||||
panic(fmt.Errorf("copy buffer: %v", err))
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
b.SetBytes(totalBytes)
|
||||
clientConfig := *testConfig
|
||||
clientConfig := testConfig.clone()
|
||||
clientConfig.DynamicRecordSizingDisabled = dynamicRecordSizingDisabled
|
||||
|
||||
buf := make([]byte, 1<<14)
|
||||
buf := make([]byte, bufsize)
|
||||
chunks := int(math.Ceil(float64(totalBytes) / float64(len(buf))))
|
||||
for i := 0; i < N; i++ {
|
||||
conn, err := Dial("tcp", ln.Addr().String(), &clientConfig)
|
||||
conn, err := Dial("tcp", ln.Addr().String(), clientConfig)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
@ -577,9 +641,9 @@ func latency(b *testing.B, bps int, dynamicRecordSizingDisabled bool) {
|
||||
// (cannot call b.Fatal in goroutine)
|
||||
panic(fmt.Errorf("accept: %v", err))
|
||||
}
|
||||
serverConfig := *testConfig
|
||||
serverConfig := testConfig.clone()
|
||||
serverConfig.DynamicRecordSizingDisabled = dynamicRecordSizingDisabled
|
||||
srv := Server(&slowConn{sconn, bps}, &serverConfig)
|
||||
srv := Server(&slowConn{sconn, bps}, serverConfig)
|
||||
if err := srv.Handshake(); err != nil {
|
||||
panic(fmt.Errorf("handshake: %v", err))
|
||||
}
|
||||
@ -587,14 +651,14 @@ func latency(b *testing.B, bps int, dynamicRecordSizingDisabled bool) {
|
||||
}
|
||||
}()
|
||||
|
||||
clientConfig := *testConfig
|
||||
clientConfig := testConfig.clone()
|
||||
clientConfig.DynamicRecordSizingDisabled = dynamicRecordSizingDisabled
|
||||
|
||||
buf := make([]byte, 16384)
|
||||
peek := make([]byte, 1)
|
||||
|
||||
for i := 0; i < N; i++ {
|
||||
conn, err := Dial("tcp", ln.Addr().String(), &clientConfig)
|
||||
conn, err := Dial("tcp", ln.Addr().String(), clientConfig)
|
||||
if err != nil {
|
||||
b.Fatal(err)
|
||||
}
|
||||
|
@ -718,6 +718,9 @@ func (db *DB) maybeOpenNewConnections() {
|
||||
for numRequests > 0 {
|
||||
db.numOpen++ // optimistically
|
||||
numRequests--
|
||||
if db.closed {
|
||||
return
|
||||
}
|
||||
db.openerCh <- struct{}{}
|
||||
}
|
||||
}
|
||||
@ -915,6 +918,9 @@ func (db *DB) putConn(dc *driverConn, err error) {
|
||||
// If a connRequest was fulfilled or the *driverConn was placed in the
|
||||
// freeConn list, then true is returned, otherwise false is returned.
|
||||
func (db *DB) putConnDBLocked(dc *driverConn, err error) bool {
|
||||
if db.closed {
|
||||
return false
|
||||
}
|
||||
if db.maxOpen > 0 && db.numOpen > db.maxOpen {
|
||||
return false
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ func closeDB(t testing.TB, db *DB) {
|
||||
count := db.numOpen
|
||||
db.mu.Unlock()
|
||||
if count != 0 {
|
||||
t.Fatalf("%d connections still open after closing DB", db.numOpen)
|
||||
t.Fatalf("%d connections still open after closing DB", count)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1239,7 +1239,7 @@ func TestPendingConnsAfterErr(t *testing.T) {
|
||||
time.Sleep(10 * time.Millisecond) // make extra sure all workers are blocked
|
||||
close(unblock) // let all workers proceed
|
||||
|
||||
const timeout = 100 * time.Millisecond
|
||||
const timeout = 5 * time.Second
|
||||
to := time.NewTimer(timeout)
|
||||
defer to.Stop()
|
||||
|
||||
@ -1615,6 +1615,8 @@ func TestManyErrBadConn(t *testing.T) {
|
||||
}
|
||||
}()
|
||||
|
||||
db.mu.Lock()
|
||||
defer db.mu.Unlock()
|
||||
if db.numOpen != nconn {
|
||||
t.Fatalf("unexpected numOpen %d (was expecting %d)", db.numOpen, nconn)
|
||||
} else if len(db.freeConn) != nconn {
|
||||
|
@ -104,6 +104,41 @@ var fileTests = []fileTest{
|
||||
{".debug_loc", 0x38, 0xf000, 0x200, 0x3a00, 0x0, 0x0, 0x0, 0x0, 0x42100000},
|
||||
},
|
||||
},
|
||||
{
|
||||
file: "testdata/gcc-386-mingw-no-symbols-exec",
|
||||
hdr: FileHeader{0x14c, 0x8, 0x69676572, 0x0, 0x0, 0xe0, 0x30f},
|
||||
opthdr: &OptionalHeader32{0x10b, 0x2, 0x18, 0xe00, 0x1e00, 0x200, 0x1280, 0x1000, 0x2000, 0x400000, 0x1000, 0x200, 0x4, 0x0, 0x1, 0x0, 0x4, 0x0, 0x0, 0x9000, 0x400, 0x5306, 0x3, 0x0, 0x200000, 0x1000, 0x100000, 0x1000, 0x0, 0x10,
|
||||
[16]DataDirectory{
|
||||
{0x0, 0x0},
|
||||
{0x6000, 0x378},
|
||||
{0x0, 0x0},
|
||||
{0x0, 0x0},
|
||||
{0x0, 0x0},
|
||||
{0x0, 0x0},
|
||||
{0x0, 0x0},
|
||||
{0x0, 0x0},
|
||||
{0x0, 0x0},
|
||||
{0x8004, 0x18},
|
||||
{0x0, 0x0},
|
||||
{0x0, 0x0},
|
||||
{0x60b8, 0x7c},
|
||||
{0x0, 0x0},
|
||||
{0x0, 0x0},
|
||||
{0x0, 0x0},
|
||||
},
|
||||
},
|
||||
sections: []*SectionHeader{
|
||||
{".text", 0xc64, 0x1000, 0xe00, 0x400, 0x0, 0x0, 0x0, 0x0, 0x60500060},
|
||||
{".data", 0x10, 0x2000, 0x200, 0x1200, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
|
||||
{".rdata", 0x134, 0x3000, 0x200, 0x1400, 0x0, 0x0, 0x0, 0x0, 0x40300040},
|
||||
{".eh_fram", 0x3a0, 0x4000, 0x400, 0x1600, 0x0, 0x0, 0x0, 0x0, 0x40300040},
|
||||
{".bss", 0x60, 0x5000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc0300080},
|
||||
{".idata", 0x378, 0x6000, 0x400, 0x1a00, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
|
||||
{".CRT", 0x18, 0x7000, 0x200, 0x1e00, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
|
||||
{".tls", 0x20, 0x8000, 0x200, 0x2000, 0x0, 0x0, 0x0, 0x0, 0xc0300040},
|
||||
},
|
||||
hasNoDwarfInfo: true,
|
||||
},
|
||||
{
|
||||
file: "testdata/gcc-amd64-mingw-obj",
|
||||
hdr: FileHeader{0x8664, 0x6, 0x0, 0x198, 0x12, 0x0, 0x4},
|
||||
|
@ -24,6 +24,9 @@ type _StringTable []byte
|
||||
|
||||
func readStringTable(fh *FileHeader, r io.ReadSeeker) (_StringTable, error) {
|
||||
// COFF string table is located right after COFF symbol table.
|
||||
if fh.PointerToSymbolTable <= 0 {
|
||||
return nil, nil
|
||||
}
|
||||
offset := fh.PointerToSymbolTable + COFFSymbolSize*fh.NumberOfSymbols
|
||||
_, err := r.Seek(int64(offset), io.SeekStart)
|
||||
if err != nil {
|
||||
|
BIN
src/debug/pe/testdata/gcc-386-mingw-no-symbols-exec
vendored
Normal file
BIN
src/debug/pe/testdata/gcc-386-mingw-no-symbols-exec
vendored
Normal file
Binary file not shown.
@ -645,10 +645,10 @@ func (dec *Decoder) decodeInterface(ityp reflect.Type, state *decoderState, valu
|
||||
errorf("invalid type name length %d: exceeds input size", nr)
|
||||
}
|
||||
n := int(nr)
|
||||
name := string(state.b.Bytes()[:n])
|
||||
name := state.b.Bytes()[:n]
|
||||
state.b.Drop(n)
|
||||
// Allocate the destination interface value.
|
||||
if name == "" {
|
||||
if len(name) == 0 {
|
||||
// Copy the nil interface value to the target.
|
||||
value.Set(reflect.Zero(value.Type()))
|
||||
return
|
||||
@ -658,7 +658,7 @@ func (dec *Decoder) decodeInterface(ityp reflect.Type, state *decoderState, valu
|
||||
}
|
||||
// The concrete type must be registered.
|
||||
registerLock.RLock()
|
||||
typ, ok := nameToConcreteType[name]
|
||||
typ, ok := nameToConcreteType[string(name)]
|
||||
registerLock.RUnlock()
|
||||
if !ok {
|
||||
errorf("name not registered for interface: %q", name)
|
||||
|
@ -17,7 +17,8 @@ Basics
|
||||
A stream of gobs is self-describing. Each data item in the stream is preceded by
|
||||
a specification of its type, expressed in terms of a small set of predefined
|
||||
types. Pointers are not transmitted, but the things they point to are
|
||||
transmitted; that is, the values are flattened. Recursive types work fine, but
|
||||
transmitted; that is, the values are flattened. Nil pointers are not permitted,
|
||||
as they have no value. Recursive types work fine, but
|
||||
recursive values (data with cycles) are problematic. This may change.
|
||||
|
||||
To use gobs, create an Encoder and present it with a series of data items as
|
||||
|
@ -170,6 +170,7 @@ func (enc *Encoder) sendType(w io.Writer, state *encoderState, origt reflect.Typ
|
||||
|
||||
// Encode transmits the data item represented by the empty interface value,
|
||||
// guaranteeing that all necessary type information has been transmitted first.
|
||||
// Passing a nil pointer to Encoder will panic, as they cannot be transmitted by gob.
|
||||
func (enc *Encoder) Encode(e interface{}) error {
|
||||
return enc.EncodeValue(reflect.ValueOf(e))
|
||||
}
|
||||
@ -212,9 +213,8 @@ func (enc *Encoder) sendTypeId(state *encoderState, ut *userTypeInfo) {
|
||||
|
||||
// EncodeValue transmits the data item represented by the reflection value,
|
||||
// guaranteeing that all necessary type information has been transmitted first.
|
||||
// Passing a nil pointer to EncodeValue will panic, as they cannot be transmitted by gob.
|
||||
func (enc *Encoder) EncodeValue(value reflect.Value) error {
|
||||
// Gobs contain values. They cannot represent nil pointers, which
|
||||
// have no value to encode.
|
||||
if value.Kind() == reflect.Ptr && value.IsNil() {
|
||||
panic("gob: cannot encode nil pointer of type " + value.Type().String())
|
||||
}
|
||||
|
@ -8,6 +8,7 @@ import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
@ -831,30 +832,81 @@ func TestPtrToMapOfMap(t *testing.T) {
|
||||
|
||||
// A top-level nil pointer generates a panic with a helpful string-valued message.
|
||||
func TestTopLevelNilPointer(t *testing.T) {
|
||||
errMsg := topLevelNilPanic(t)
|
||||
if errMsg == "" {
|
||||
var ip *int
|
||||
encodeErr, panicErr := encodeAndRecover(ip)
|
||||
if encodeErr != nil {
|
||||
t.Fatal("error in encode:", encodeErr)
|
||||
}
|
||||
if panicErr == nil {
|
||||
t.Fatal("top-level nil pointer did not panic")
|
||||
}
|
||||
errMsg := panicErr.Error()
|
||||
if !strings.Contains(errMsg, "nil pointer") {
|
||||
t.Fatal("expected nil pointer error, got:", errMsg)
|
||||
}
|
||||
}
|
||||
|
||||
func topLevelNilPanic(t *testing.T) (panicErr string) {
|
||||
func encodeAndRecover(value interface{}) (encodeErr, panicErr error) {
|
||||
defer func() {
|
||||
e := recover()
|
||||
if err, ok := e.(string); ok {
|
||||
panicErr = err
|
||||
if e != nil {
|
||||
switch err := e.(type) {
|
||||
case error:
|
||||
panicErr = err
|
||||
default:
|
||||
panicErr = fmt.Errorf("%v", err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
var ip *int
|
||||
buf := new(bytes.Buffer)
|
||||
if err := NewEncoder(buf).Encode(ip); err != nil {
|
||||
t.Fatal("error in encode:", err)
|
||||
}
|
||||
|
||||
encodeErr = NewEncoder(ioutil.Discard).Encode(value)
|
||||
return
|
||||
}
|
||||
|
||||
func TestNilPointerPanics(t *testing.T) {
|
||||
var (
|
||||
nilStringPtr *string
|
||||
intMap = make(map[int]int)
|
||||
intMapPtr = &intMap
|
||||
nilIntMapPtr *map[int]int
|
||||
zero int
|
||||
nilBoolChannel chan bool
|
||||
nilBoolChannelPtr *chan bool
|
||||
nilStringSlice []string
|
||||
stringSlice = make([]string, 1)
|
||||
nilStringSlicePtr *[]string
|
||||
)
|
||||
|
||||
testCases := []struct {
|
||||
value interface{}
|
||||
mustPanic bool
|
||||
}{
|
||||
{nilStringPtr, true},
|
||||
{intMap, false},
|
||||
{intMapPtr, false},
|
||||
{nilIntMapPtr, true},
|
||||
{zero, false},
|
||||
{nilStringSlice, false},
|
||||
{stringSlice, false},
|
||||
{nilStringSlicePtr, true},
|
||||
{nilBoolChannel, false},
|
||||
{nilBoolChannelPtr, true},
|
||||
}
|
||||
|
||||
for _, tt := range testCases {
|
||||
_, panicErr := encodeAndRecover(tt.value)
|
||||
if tt.mustPanic {
|
||||
if panicErr == nil {
|
||||
t.Errorf("expected panic with input %#v, did not panic", tt.value)
|
||||
}
|
||||
continue
|
||||
}
|
||||
if panicErr != nil {
|
||||
t.Fatalf("expected no panic with input %#v, got panic=%v", tt.value, panicErr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNilPointerInsideInterface(t *testing.T) {
|
||||
var ip *int
|
||||
si := struct {
|
||||
|
@ -22,6 +22,7 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
)
|
||||
@ -1231,15 +1232,14 @@ func dominantField(fields []field) (field, bool) {
|
||||
}
|
||||
|
||||
var fieldCache struct {
|
||||
sync.RWMutex
|
||||
m map[reflect.Type][]field
|
||||
value atomic.Value // map[reflect.Type][]field
|
||||
mu sync.Mutex // used only by writers
|
||||
}
|
||||
|
||||
// cachedTypeFields is like typeFields but uses a cache to avoid repeated work.
|
||||
func cachedTypeFields(t reflect.Type) []field {
|
||||
fieldCache.RLock()
|
||||
f := fieldCache.m[t]
|
||||
fieldCache.RUnlock()
|
||||
m, _ := fieldCache.value.Load().(map[reflect.Type][]field)
|
||||
f := m[t]
|
||||
if f != nil {
|
||||
return f
|
||||
}
|
||||
@ -1251,11 +1251,14 @@ func cachedTypeFields(t reflect.Type) []field {
|
||||
f = []field{}
|
||||
}
|
||||
|
||||
fieldCache.Lock()
|
||||
if fieldCache.m == nil {
|
||||
fieldCache.m = map[reflect.Type][]field{}
|
||||
fieldCache.mu.Lock()
|
||||
m, _ = fieldCache.value.Load().(map[reflect.Type][]field)
|
||||
newM := make(map[reflect.Type][]field, len(m)+1)
|
||||
for k, v := range m {
|
||||
newM[k] = v
|
||||
}
|
||||
fieldCache.m[t] = f
|
||||
fieldCache.Unlock()
|
||||
newM[t] = f
|
||||
fieldCache.value.Store(newM)
|
||||
fieldCache.mu.Unlock()
|
||||
return f
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ const (
|
||||
//
|
||||
// The name for the XML elements is taken from, in order of preference:
|
||||
// - the tag on the XMLName field, if the data is a struct
|
||||
// - the value of the XMLName field of type xml.Name
|
||||
// - the value of the XMLName field of type Name
|
||||
// - the tag of the struct field used to obtain the data
|
||||
// - the name of the struct field used to obtain the data
|
||||
// - the name of the marshalled type
|
||||
|
@ -39,7 +39,7 @@ import (
|
||||
// ",innerxml", Unmarshal accumulates the raw XML nested inside the
|
||||
// element in that field. The rest of the rules still apply.
|
||||
//
|
||||
// * If the struct has a field named XMLName of type xml.Name,
|
||||
// * If the struct has a field named XMLName of type Name,
|
||||
// Unmarshal records the element name in that field.
|
||||
//
|
||||
// * If the XMLName field has an associated tag of the form
|
||||
@ -105,8 +105,8 @@ import (
|
||||
// interpreting the string value in decimal. There is no check for
|
||||
// overflow.
|
||||
//
|
||||
// Unmarshal maps an XML element to an xml.Name by recording the
|
||||
// element name.
|
||||
// Unmarshal maps an XML element to a Name by recording the element
|
||||
// name.
|
||||
//
|
||||
// Unmarshal maps an XML element to a pointer by setting the pointer
|
||||
// to a freshly allocated value and then mapping the element to that value.
|
||||
@ -115,13 +115,13 @@ func Unmarshal(data []byte, v interface{}) error {
|
||||
return NewDecoder(bytes.NewReader(data)).Decode(v)
|
||||
}
|
||||
|
||||
// Decode works like xml.Unmarshal, except it reads the decoder
|
||||
// Decode works like Unmarshal, except it reads the decoder
|
||||
// stream to find the start element.
|
||||
func (d *Decoder) Decode(v interface{}) error {
|
||||
return d.DecodeElement(v, nil)
|
||||
}
|
||||
|
||||
// DecodeElement works like xml.Unmarshal except that it takes
|
||||
// DecodeElement works like Unmarshal except that it takes
|
||||
// a pointer to the start XML element to decode into v.
|
||||
// It is useful when a client reads some raw XML tokens itself
|
||||
// but also wants to defer to Unmarshal for some elements.
|
||||
|
@ -418,7 +418,7 @@ type (
|
||||
)
|
||||
|
||||
// Pos and End implementations for expression/type nodes.
|
||||
//
|
||||
|
||||
func (x *BadExpr) Pos() token.Pos { return x.From }
|
||||
func (x *Ident) Pos() token.Pos { return x.NamePos }
|
||||
func (x *Ellipsis) Pos() token.Pos { return x.Ellipsis }
|
||||
@ -709,7 +709,7 @@ type (
|
||||
)
|
||||
|
||||
// Pos and End implementations for statement nodes.
|
||||
//
|
||||
|
||||
func (s *BadStmt) Pos() token.Pos { return s.From }
|
||||
func (s *DeclStmt) Pos() token.Pos { return s.Decl.Pos() }
|
||||
func (s *EmptyStmt) Pos() token.Pos { return s.Semicolon }
|
||||
@ -854,7 +854,7 @@ type (
|
||||
)
|
||||
|
||||
// Pos and End implementations for spec nodes.
|
||||
//
|
||||
|
||||
func (s *ImportSpec) Pos() token.Pos {
|
||||
if s.Name != nil {
|
||||
return s.Name.Pos()
|
||||
@ -931,7 +931,7 @@ type (
|
||||
)
|
||||
|
||||
// Pos and End implementations for declaration nodes.
|
||||
//
|
||||
|
||||
func (d *BadDecl) Pos() token.Pos { return d.From }
|
||||
func (d *GenDecl) Pos() token.Pos { return d.TokPos }
|
||||
func (d *FuncDecl) Pos() token.Pos { return d.Type.Pos() }
|
||||
|
@ -244,6 +244,7 @@ var stringTests = []struct {
|
||||
{"1e9999", "1e+9999", "0x.f8d4a9da224650a8cb2959e10d985ad92adbd44c62917e608b1f24c0e1b76b6f61edffeb15c135a4b601637315f7662f325f82325422b244286a07663c9415d2p+33216"},
|
||||
{"1e-9999", "1e-9999", "0x.83b01ba6d8c0425eec1b21e96f7742d63c2653ed0a024cf8a2f9686df578d7b07d7a83d84df6a2ec70a921d1f6cd5574893a7eda4d28ee719e13a5dce2700759p-33215"},
|
||||
{"2.71828182845904523536028747135266249775724709369995957496696763", "2.71828", "271828182845904523536028747135266249775724709369995957496696763/100000000000000000000000000000000000000000000000000000000000000"},
|
||||
{"0e9999999999", "0", "0"}, // issue #16176
|
||||
|
||||
// Complex
|
||||
{"0i", "(0 + 0i)", "(0 + 0i)"},
|
||||
|
@ -21,6 +21,7 @@ type importer struct {
|
||||
data []byte
|
||||
path string
|
||||
buf []byte // for reading strings
|
||||
version string
|
||||
|
||||
// object lists
|
||||
strList []string // in order of appearance
|
||||
@ -66,8 +67,9 @@ func BImportData(imports map[string]*types.Package, data []byte, path string) (i
|
||||
|
||||
// --- generic export data ---
|
||||
|
||||
if v := p.string(); v != "v0" {
|
||||
return p.read, nil, fmt.Errorf("unknown export data version: %s", v)
|
||||
p.version = p.string()
|
||||
if p.version != "v0" && p.version != "v1" {
|
||||
return p.read, nil, fmt.Errorf("unknown export data version: %s", p.version)
|
||||
}
|
||||
|
||||
// populate typList with predeclared "known" types
|
||||
@ -304,6 +306,10 @@ func (p *importer) typ(parent *types.Package) types.Type {
|
||||
params, isddd := p.paramList()
|
||||
result, _ := p.paramList()
|
||||
|
||||
if p.version == "v1" {
|
||||
p.int() // nointerface flag - discarded
|
||||
}
|
||||
|
||||
sig := types.NewSignature(recv.At(0), params, result, isddd)
|
||||
t0.AddMethod(types.NewFunc(token.NoPos, parent, name, sig))
|
||||
}
|
||||
|
@ -166,7 +166,7 @@ that would have been produced if {{.}} was a regular string.
|
||||
|
||||
Security Model
|
||||
|
||||
http://js-quasis-libraries-and-repl.googlecode.com/svn/trunk/safetemplate.html#problem_definition defines "safe" as used by this package.
|
||||
https://rawgit.com/mikesamuel/sanitized-jquery-templates/trunk/safetemplate.html#problem_definition defines "safe" as used by this package.
|
||||
|
||||
This package assumes that template authors are trusted, that Execute's data
|
||||
parameter is not, and seeks to preserve the properties below in the face
|
||||
|
@ -60,21 +60,34 @@ const (
|
||||
|
||||
// Parse parses, post-processes and verifies the trace.
|
||||
func Parse(r io.Reader, bin string) ([]*Event, error) {
|
||||
ver, rawEvents, strings, err := readTrace(r)
|
||||
ver, events, err := parse(r, bin)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if ver < 1007 && bin == "" {
|
||||
return nil, fmt.Errorf("for traces produced by go 1.6 or below, the binary argument must be provided")
|
||||
}
|
||||
return events, nil
|
||||
}
|
||||
|
||||
// parse parses, post-processes and verifies the trace. It returns the
|
||||
// trace version and the list of events.
|
||||
func parse(r io.Reader, bin string) (int, []*Event, error) {
|
||||
ver, rawEvents, strings, err := readTrace(r)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
events, stacks, err := parseEvents(ver, rawEvents, strings)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return 0, nil, err
|
||||
}
|
||||
events, err = removeFutile(events)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return 0, nil, err
|
||||
}
|
||||
err = postProcessTrace(ver, events)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return 0, nil, err
|
||||
}
|
||||
// Attach stack traces.
|
||||
for _, ev := range events {
|
||||
@ -84,10 +97,10 @@ func Parse(r io.Reader, bin string) ([]*Event, error) {
|
||||
}
|
||||
if ver < 1007 && bin != "" {
|
||||
if err := symbolize(events, bin); err != nil {
|
||||
return nil, err
|
||||
return 0, nil, err
|
||||
}
|
||||
}
|
||||
return events, nil
|
||||
return ver, events, nil
|
||||
}
|
||||
|
||||
// rawEvent is a helper type used during parsing.
|
||||
|
@ -42,7 +42,9 @@ func TestParseCanned(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Fatalf("failed to read input file: %v", err)
|
||||
}
|
||||
_, err = Parse(bytes.NewReader(data), "")
|
||||
// Instead of Parse that requires a proper binary name for old traces,
|
||||
// we use 'parse' that omits symbol lookup if an empty string is given.
|
||||
_, _, err = parse(bytes.NewReader(data), "")
|
||||
switch {
|
||||
case strings.HasSuffix(f.Name(), "_good"):
|
||||
if err != nil {
|
||||
|
@ -88,6 +88,12 @@ func (z *Rat) SetString(s string) (*Rat, bool) {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
// special-case 0 (see also issue #16176)
|
||||
if len(z.a.abs) == 0 {
|
||||
return z, true
|
||||
}
|
||||
// len(z.a.abs) > 0
|
||||
|
||||
// correct exponent
|
||||
if ecorr < 0 {
|
||||
exp += int64(ecorr)
|
||||
|
@ -48,6 +48,7 @@ var setStringTests = []StringTest{
|
||||
{"53/70893980658822810696", "53/70893980658822810696", true},
|
||||
{"106/141787961317645621392", "53/70893980658822810696", true},
|
||||
{"204211327800791583.81095", "4084226556015831676219/20000", true},
|
||||
{"0e9999999999", "0", true}, // issue #16176
|
||||
{in: "1/0"},
|
||||
}
|
||||
|
||||
|
47
src/math/rand/race_test.go
Normal file
47
src/math/rand/race_test.go
Normal file
@ -0,0 +1,47 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package rand
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// TestConcurrent exercises the rand API concurrently, triggering situations
|
||||
// where the race detector is likely to detect issues.
|
||||
func TestConcurrent(t *testing.T) {
|
||||
const (
|
||||
numRoutines = 10
|
||||
numCycles = 10
|
||||
)
|
||||
var wg sync.WaitGroup
|
||||
defer wg.Wait()
|
||||
wg.Add(numRoutines)
|
||||
for i := 0; i < numRoutines; i++ {
|
||||
go func(i int) {
|
||||
defer wg.Done()
|
||||
buf := make([]byte, 997)
|
||||
for j := 0; j < numCycles; j++ {
|
||||
var seed int64
|
||||
seed += int64(ExpFloat64())
|
||||
seed += int64(Float32())
|
||||
seed += int64(Float64())
|
||||
seed += int64(Intn(Int()))
|
||||
seed += int64(Int31n(Int31()))
|
||||
seed += int64(Int63n(Int63()))
|
||||
seed += int64(NormFloat64())
|
||||
seed += int64(Uint32())
|
||||
for _, p := range Perm(10) {
|
||||
seed += int64(p)
|
||||
}
|
||||
Read(buf)
|
||||
for _, b := range buf {
|
||||
seed += int64(b)
|
||||
}
|
||||
Seed(int64(i*j) * seed)
|
||||
}
|
||||
}(i)
|
||||
}
|
||||
}
|
@ -33,14 +33,32 @@ func NewSource(seed int64) Source {
|
||||
// A Rand is a source of random numbers.
|
||||
type Rand struct {
|
||||
src Source
|
||||
|
||||
// readVal contains remainder of 63-bit integer used for bytes
|
||||
// generation during most recent Read call.
|
||||
// It is saved so next Read call can start where the previous
|
||||
// one finished.
|
||||
readVal int64
|
||||
// readPos indicates the number of low-order bytes of readVal
|
||||
// that are still valid.
|
||||
readPos int8
|
||||
}
|
||||
|
||||
// New returns a new Rand that uses random values from src
|
||||
// to generate other random values.
|
||||
func New(src Source) *Rand { return &Rand{src} }
|
||||
func New(src Source) *Rand { return &Rand{src: src} }
|
||||
|
||||
// Seed uses the provided seed value to initialize the generator to a deterministic state.
|
||||
func (r *Rand) Seed(seed int64) { r.src.Seed(seed) }
|
||||
// Seed should not be called concurrently with any other Rand method.
|
||||
func (r *Rand) Seed(seed int64) {
|
||||
if lk, ok := r.src.(*lockedSource); ok {
|
||||
lk.seedPos(seed, &r.readPos)
|
||||
return
|
||||
}
|
||||
|
||||
r.src.Seed(seed)
|
||||
r.readPos = 0
|
||||
}
|
||||
|
||||
// Int63 returns a non-negative pseudo-random 63-bit integer as an int64.
|
||||
func (r *Rand) Int63() int64 { return r.src.Int63() }
|
||||
@ -160,15 +178,29 @@ func (r *Rand) Perm(n int) []int {
|
||||
|
||||
// Read generates len(p) random bytes and writes them into p. It
|
||||
// always returns len(p) and a nil error.
|
||||
// Read should not be called concurrently with any other Rand method.
|
||||
func (r *Rand) Read(p []byte) (n int, err error) {
|
||||
for i := 0; i < len(p); i += 7 {
|
||||
val := r.src.Int63()
|
||||
for j := 0; i+j < len(p) && j < 7; j++ {
|
||||
p[i+j] = byte(val)
|
||||
val >>= 8
|
||||
}
|
||||
if lk, ok := r.src.(*lockedSource); ok {
|
||||
return lk.read(p, &r.readVal, &r.readPos)
|
||||
}
|
||||
return len(p), nil
|
||||
return read(p, r.Int63, &r.readVal, &r.readPos)
|
||||
}
|
||||
|
||||
func read(p []byte, int63 func() int64, readVal *int64, readPos *int8) (n int, err error) {
|
||||
pos := *readPos
|
||||
val := *readVal
|
||||
for n = 0; n < len(p); n++ {
|
||||
if pos == 0 {
|
||||
val = int63()
|
||||
pos = 7
|
||||
}
|
||||
p[n] = byte(val)
|
||||
val >>= 8
|
||||
pos--
|
||||
}
|
||||
*readPos = pos
|
||||
*readVal = val
|
||||
return
|
||||
}
|
||||
|
||||
/*
|
||||
@ -179,8 +211,9 @@ var globalRand = New(&lockedSource{src: NewSource(1)})
|
||||
|
||||
// Seed uses the provided seed value to initialize the default Source to a
|
||||
// deterministic state. If Seed is not called, the generator behaves as
|
||||
// if seeded by Seed(1). Only uses the bottom 31 bits of seed; the top 33
|
||||
// bits are ignored.
|
||||
// if seeded by Seed(1). Seed values that have the same remainder when
|
||||
// divided by 2^31-1 generate the same pseudo-random sequence.
|
||||
// Seed, unlike the Rand.Seed method, is safe for concurrent use.
|
||||
func Seed(seed int64) { globalRand.Seed(seed) }
|
||||
|
||||
// Int63 returns a non-negative pseudo-random 63-bit integer as an int64
|
||||
@ -227,6 +260,7 @@ func Perm(n int) []int { return globalRand.Perm(n) }
|
||||
|
||||
// Read generates len(p) random bytes from the default Source and
|
||||
// writes them into p. It always returns len(p) and a nil error.
|
||||
// Read, unlike the Rand.Read method, is safe for concurrent use.
|
||||
func Read(p []byte) (n int, err error) { return globalRand.Read(p) }
|
||||
|
||||
// NormFloat64 returns a normally distributed float64 in the range
|
||||
@ -267,3 +301,19 @@ func (r *lockedSource) Seed(seed int64) {
|
||||
r.src.Seed(seed)
|
||||
r.lk.Unlock()
|
||||
}
|
||||
|
||||
// seedPos implements Seed for a lockedSource without a race condiiton.
|
||||
func (r *lockedSource) seedPos(seed int64, readPos *int8) {
|
||||
r.lk.Lock()
|
||||
r.src.Seed(seed)
|
||||
*readPos = 0
|
||||
r.lk.Unlock()
|
||||
}
|
||||
|
||||
// read implements Read for a lockedSource without a race condition.
|
||||
func (r *lockedSource) read(p []byte, readVal *int64, readPos *int8) (n int, err error) {
|
||||
r.lk.Lock()
|
||||
n, err = read(p, r.src.Int63, readVal, readPos)
|
||||
r.lk.Unlock()
|
||||
return
|
||||
}
|
||||
|
@ -5,13 +5,16 @@
|
||||
package rand
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"internal/testenv"
|
||||
"io"
|
||||
"math"
|
||||
"os"
|
||||
"runtime"
|
||||
"testing"
|
||||
"testing/iotest"
|
||||
)
|
||||
|
||||
const (
|
||||
@ -373,7 +376,7 @@ func testReadUniformity(t *testing.T, n int, seed int64) {
|
||||
checkSampleDistribution(t, samples, expected)
|
||||
}
|
||||
|
||||
func TestRead(t *testing.T) {
|
||||
func TestReadUniformity(t *testing.T) {
|
||||
testBufferSizes := []int{
|
||||
2, 4, 7, 64, 1024, 1 << 16, 1 << 20,
|
||||
}
|
||||
@ -394,7 +397,42 @@ func TestReadEmpty(t *testing.T) {
|
||||
if n != 0 {
|
||||
t.Errorf("Read into empty buffer returned unexpected n of %d", n)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadByOneByte(t *testing.T) {
|
||||
r := New(NewSource(1))
|
||||
b1 := make([]byte, 100)
|
||||
_, err := io.ReadFull(iotest.OneByteReader(r), b1)
|
||||
if err != nil {
|
||||
t.Errorf("read by one byte: %v", err)
|
||||
}
|
||||
r = New(NewSource(1))
|
||||
b2 := make([]byte, 100)
|
||||
_, err = r.Read(b2)
|
||||
if err != nil {
|
||||
t.Errorf("read: %v", err)
|
||||
}
|
||||
if !bytes.Equal(b1, b2) {
|
||||
t.Errorf("read by one byte vs single read:\n%x\n%x", b1, b2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReadSeedReset(t *testing.T) {
|
||||
r := New(NewSource(42))
|
||||
b1 := make([]byte, 128)
|
||||
_, err := r.Read(b1)
|
||||
if err != nil {
|
||||
t.Errorf("read: %v", err)
|
||||
}
|
||||
r.Seed(42)
|
||||
b2 := make([]byte, 128)
|
||||
_, err = r.Read(b2)
|
||||
if err != nil {
|
||||
t.Errorf("read: %v", err)
|
||||
}
|
||||
if !bytes.Equal(b1, b2) {
|
||||
t.Errorf("mismatch after re-seed:\n%x\n%x", b1, b2)
|
||||
}
|
||||
}
|
||||
|
||||
// Benchmarks
|
||||
|
@ -342,25 +342,25 @@ var regressGolden = []interface{}{
|
||||
[]int{8, 7, 5, 3, 4, 6, 0, 1, 2}, // Perm(9)
|
||||
[]int{1, 0, 2, 5, 7, 6, 9, 8, 3, 4}, // Perm(10)
|
||||
[]byte{0x1}, // Read([0])
|
||||
[]byte{0xc0, 0x41, 0xd3, 0xff, 0x12, 0x4, 0x5b}, // Read([0 0 0 0 0 0 0])
|
||||
[]byte{0x73, 0xc8, 0x6e, 0x4f, 0xf9, 0x5f, 0xf6, 0x62}, // Read([0 0 0 0 0 0 0 0])
|
||||
[]byte{0x4a, 0x2d, 0xb, 0x75, 0xfb, 0x18, 0xd, 0xaf, 0x48}, // Read([0 0 0 0 0 0 0 0 0])
|
||||
[]byte{0x39, 0x46, 0x51, 0x85, 0xf, 0xd4, 0xa1, 0x78, 0x89, 0x2e}, // Read([0 0 0 0 0 0 0 0 0 0])
|
||||
[]byte{0x51}, // Read([0])
|
||||
[]byte{0x4e, 0xe2, 0xd3, 0xd0, 0xd0, 0xde, 0x6b}, // Read([0 0 0 0 0 0 0])
|
||||
[]byte{0xf8, 0xf9, 0xb4, 0x4c, 0xe8, 0x5f, 0xf0, 0x44}, // Read([0 0 0 0 0 0 0 0])
|
||||
[]byte{0x3b, 0xbf, 0x85, 0x7a, 0xab, 0x99, 0xc5, 0xb2, 0x52}, // Read([0 0 0 0 0 0 0 0 0])
|
||||
[]byte{0xa8, 0xae, 0xb7, 0x9e, 0xf8, 0x56, 0xf6, 0x59, 0xc1, 0x8f}, // Read([0 0 0 0 0 0 0 0 0 0])
|
||||
[]byte{0xc7}, // Read([0])
|
||||
[]byte{0x5f, 0x67, 0xcf, 0xe2, 0x42, 0xcf, 0x3c}, // Read([0 0 0 0 0 0 0])
|
||||
[]byte{0xc3, 0x54, 0xf3, 0xed, 0xe2, 0xd6, 0xbe, 0xcc}, // Read([0 0 0 0 0 0 0 0])
|
||||
[]byte{0x6a, 0x9f, 0x4a, 0x57, 0x8b, 0xcb, 0x9e, 0xf2, 0xd4}, // Read([0 0 0 0 0 0 0 0 0])
|
||||
[]byte{0x6d, 0x29, 0x97, 0x61, 0xea, 0x9e, 0x4f, 0x5a, 0xa6, 0xae}, // Read([0 0 0 0 0 0 0 0 0 0])
|
||||
[]byte{0xaa}, // Read([0])
|
||||
[]byte{0x20, 0xef, 0xcd, 0x6c, 0xea, 0x84, 0xb6}, // Read([0 0 0 0 0 0 0])
|
||||
[]byte{0x92, 0x5e, 0x60, 0x7b, 0xe0, 0x63, 0x71, 0x6f}, // Read([0 0 0 0 0 0 0 0])
|
||||
[]byte{0x4, 0x5c, 0x3f, 0x0, 0xf, 0x8a, 0x79, 0x6b, 0xce}, // Read([0 0 0 0 0 0 0 0 0])
|
||||
[]byte{0xaa, 0xca, 0xee, 0xdf, 0xad, 0x5b, 0x50, 0x66, 0x64, 0xe8}, // Read([0 0 0 0 0 0 0 0 0 0])
|
||||
[]byte{0x94, 0xfd, 0xc2, 0xfa, 0x2f, 0xfc, 0xc0}, // Read([0 0 0 0 0 0 0])
|
||||
[]byte{0x41, 0xd3, 0xff, 0x12, 0x4, 0x5b, 0x73, 0xc8}, // Read([0 0 0 0 0 0 0 0])
|
||||
[]byte{0x6e, 0x4f, 0xf9, 0x5f, 0xf6, 0x62, 0xa5, 0xee, 0xe8}, // Read([0 0 0 0 0 0 0 0 0])
|
||||
[]byte{0x2a, 0xbd, 0xf4, 0x4a, 0x2d, 0xb, 0x75, 0xfb, 0x18, 0xd}, // Read([0 0 0 0 0 0 0 0 0 0])
|
||||
[]byte{0xaf}, // Read([0])
|
||||
[]byte{0x48, 0xa7, 0x9e, 0xe0, 0xb1, 0xd, 0x39}, // Read([0 0 0 0 0 0 0])
|
||||
[]byte{0x46, 0x51, 0x85, 0xf, 0xd4, 0xa1, 0x78, 0x89}, // Read([0 0 0 0 0 0 0 0])
|
||||
[]byte{0x2e, 0xe2, 0x85, 0xec, 0xe1, 0x51, 0x14, 0x55, 0x78}, // Read([0 0 0 0 0 0 0 0 0])
|
||||
[]byte{0x8, 0x75, 0xd6, 0x4e, 0xe2, 0xd3, 0xd0, 0xd0, 0xde, 0x6b}, // Read([0 0 0 0 0 0 0 0 0 0])
|
||||
[]byte{0xf8}, // Read([0])
|
||||
[]byte{0xf9, 0xb4, 0x4c, 0xe8, 0x5f, 0xf0, 0x44}, // Read([0 0 0 0 0 0 0])
|
||||
[]byte{0xc6, 0xb1, 0xf8, 0x3b, 0x8e, 0x88, 0x3b, 0xbf}, // Read([0 0 0 0 0 0 0 0])
|
||||
[]byte{0x85, 0x7a, 0xab, 0x99, 0xc5, 0xb2, 0x52, 0xc7, 0x42}, // Read([0 0 0 0 0 0 0 0 0])
|
||||
[]byte{0x9c, 0x32, 0xf3, 0xa8, 0xae, 0xb7, 0x9e, 0xf8, 0x56, 0xf6}, // Read([0 0 0 0 0 0 0 0 0 0])
|
||||
[]byte{0x59}, // Read([0])
|
||||
[]byte{0xc1, 0x8f, 0xd, 0xce, 0xcc, 0x77, 0xc7}, // Read([0 0 0 0 0 0 0])
|
||||
[]byte{0x5e, 0x7a, 0x81, 0xbf, 0xde, 0x27, 0x5f, 0x67}, // Read([0 0 0 0 0 0 0 0])
|
||||
[]byte{0xcf, 0xe2, 0x42, 0xcf, 0x3c, 0xc3, 0x54, 0xf3, 0xed}, // Read([0 0 0 0 0 0 0 0 0])
|
||||
[]byte{0xe2, 0xd6, 0xbe, 0xcc, 0x4e, 0xa3, 0xae, 0x5e, 0x88, 0x52}, // Read([0 0 0 0 0 0 0 0 0 0])
|
||||
uint32(4059586549), // Uint32()
|
||||
uint32(1052117029), // Uint32()
|
||||
uint32(2817310706), // Uint32()
|
||||
|
@ -972,7 +972,7 @@ func http2terminalReadFrameError(err error) bool {
|
||||
//
|
||||
// If the frame is larger than previously set with SetMaxReadFrameSize, the
|
||||
// returned error is ErrFrameTooLarge. Other errors may be of type
|
||||
// ConnectionError, StreamError, or anything else from from the underlying
|
||||
// ConnectionError, StreamError, or anything else from the underlying
|
||||
// reader.
|
||||
func (fr *http2Framer) ReadFrame() (http2Frame, error) {
|
||||
fr.errDetail = nil
|
||||
@ -1992,6 +1992,29 @@ func http2transportExpectContinueTimeout(t1 *Transport) time.Duration {
|
||||
return t1.ExpectContinueTimeout
|
||||
}
|
||||
|
||||
// isBadCipher reports whether the cipher is blacklisted by the HTTP/2 spec.
|
||||
func http2isBadCipher(cipher uint16) bool {
|
||||
switch cipher {
|
||||
case tls.TLS_RSA_WITH_RC4_128_SHA,
|
||||
tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
|
||||
tls.TLS_RSA_WITH_AES_128_CBC_SHA,
|
||||
tls.TLS_RSA_WITH_AES_256_CBC_SHA,
|
||||
tls.TLS_RSA_WITH_AES_128_GCM_SHA256,
|
||||
tls.TLS_RSA_WITH_AES_256_GCM_SHA384,
|
||||
tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
|
||||
tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
|
||||
tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
|
||||
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
type http2contextContext interface {
|
||||
context.Context
|
||||
}
|
||||
@ -2999,27 +3022,6 @@ func (s *http2Server) ServeConn(c net.Conn, opts *http2ServeConnOpts) {
|
||||
sc.serve()
|
||||
}
|
||||
|
||||
// isBadCipher reports whether the cipher is blacklisted by the HTTP/2 spec.
|
||||
func http2isBadCipher(cipher uint16) bool {
|
||||
switch cipher {
|
||||
case tls.TLS_RSA_WITH_RC4_128_SHA,
|
||||
tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
|
||||
tls.TLS_RSA_WITH_AES_128_CBC_SHA,
|
||||
tls.TLS_RSA_WITH_AES_256_CBC_SHA,
|
||||
tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
|
||||
tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
|
||||
tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
|
||||
tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
|
||||
tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
|
||||
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func (sc *http2serverConn) rejectConn(err http2ErrCode, debug string) {
|
||||
sc.vlogf("http2: server rejecting conn: %v, %s", err, debug)
|
||||
|
||||
@ -4931,6 +4933,7 @@ type http2ClientConn struct {
|
||||
inflow http2flow // peer's conn-level flow control
|
||||
closed bool
|
||||
goAway *http2GoAwayFrame // if non-nil, the GoAwayFrame we received
|
||||
goAwayDebug string // goAway frame's debug data, retained as a string
|
||||
streams map[uint32]*http2clientStream // client-initiated
|
||||
nextStreamID uint32
|
||||
bw *bufio.Writer
|
||||
@ -5266,7 +5269,16 @@ func (t *http2Transport) NewClientConn(c net.Conn) (*http2ClientConn, error) {
|
||||
func (cc *http2ClientConn) setGoAway(f *http2GoAwayFrame) {
|
||||
cc.mu.Lock()
|
||||
defer cc.mu.Unlock()
|
||||
|
||||
old := cc.goAway
|
||||
cc.goAway = f
|
||||
|
||||
if cc.goAwayDebug == "" {
|
||||
cc.goAwayDebug = string(f.DebugData())
|
||||
}
|
||||
if old != nil && old.ErrCode != http2ErrCodeNo {
|
||||
cc.goAway.ErrCode = old.ErrCode
|
||||
}
|
||||
}
|
||||
|
||||
func (cc *http2ClientConn) CanTakeNewRequest() bool {
|
||||
@ -5871,6 +5883,19 @@ func (cc *http2ClientConn) readLoop() {
|
||||
}
|
||||
}
|
||||
|
||||
// GoAwayError is returned by the Transport when the server closes the
|
||||
// TCP connection after sending a GOAWAY frame.
|
||||
type http2GoAwayError struct {
|
||||
LastStreamID uint32
|
||||
ErrCode http2ErrCode
|
||||
DebugData string
|
||||
}
|
||||
|
||||
func (e http2GoAwayError) Error() string {
|
||||
return fmt.Sprintf("http2: server sent GOAWAY and closed the connection; LastStreamID=%v, ErrCode=%v, debug=%q",
|
||||
e.LastStreamID, e.ErrCode, e.DebugData)
|
||||
}
|
||||
|
||||
func (rl *http2clientConnReadLoop) cleanup() {
|
||||
cc := rl.cc
|
||||
defer cc.tconn.Close()
|
||||
@ -5878,10 +5903,18 @@ func (rl *http2clientConnReadLoop) cleanup() {
|
||||
defer close(cc.readerDone)
|
||||
|
||||
err := cc.readerErr
|
||||
if err == io.EOF {
|
||||
err = io.ErrUnexpectedEOF
|
||||
}
|
||||
cc.mu.Lock()
|
||||
if err == io.EOF {
|
||||
if cc.goAway != nil {
|
||||
err = http2GoAwayError{
|
||||
LastStreamID: cc.goAway.LastStreamID,
|
||||
ErrCode: cc.goAway.ErrCode,
|
||||
DebugData: cc.goAwayDebug,
|
||||
}
|
||||
} else {
|
||||
err = io.ErrUnexpectedEOF
|
||||
}
|
||||
}
|
||||
for _, cs := range rl.activeRes {
|
||||
cs.bufPipe.CloseWithError(err)
|
||||
}
|
||||
|
@ -17,11 +17,7 @@ func ExampleResponseRecorder() {
|
||||
http.Error(w, "something failed", http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
req, err := http.NewRequest("GET", "http://example.com/foo", nil)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
req := httptest.NewRequest("GET", "http://example.com/foo", nil)
|
||||
w := httptest.NewRecorder()
|
||||
handler(w, req)
|
||||
|
||||
|
@ -4,8 +4,6 @@
|
||||
|
||||
// Package pprof serves via its HTTP server runtime profiling data
|
||||
// in the format expected by the pprof visualization tool.
|
||||
// For more information about pprof, see
|
||||
// http://code.google.com/p/google-perftools/.
|
||||
//
|
||||
// The package is typically only imported for the side effect of
|
||||
// registering its HTTP handlers.
|
||||
|
@ -213,7 +213,7 @@ func (r *Response) ProtoAtLeast(major, minor int) bool {
|
||||
r.ProtoMajor == major && r.ProtoMinor >= minor
|
||||
}
|
||||
|
||||
// Write writes r to w in the HTTP/1.n server response format,
|
||||
// Write writes r to w in the HTTP/1.x server response format,
|
||||
// including the status line, headers, body, and optional trailer.
|
||||
//
|
||||
// This method consults the following fields of the response r:
|
||||
|
@ -9,6 +9,7 @@ package http_test
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"compress/gzip"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
@ -1106,11 +1107,44 @@ func TestTLSServer(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestAutomaticHTTP2_Serve(t *testing.T) {
|
||||
// Issue 15908
|
||||
func TestAutomaticHTTP2_Serve_NoTLSConfig(t *testing.T) {
|
||||
testAutomaticHTTP2_Serve(t, nil, true)
|
||||
}
|
||||
|
||||
func TestAutomaticHTTP2_Serve_NonH2TLSConfig(t *testing.T) {
|
||||
testAutomaticHTTP2_Serve(t, &tls.Config{}, false)
|
||||
}
|
||||
|
||||
func TestAutomaticHTTP2_Serve_H2TLSConfig(t *testing.T) {
|
||||
testAutomaticHTTP2_Serve(t, &tls.Config{NextProtos: []string{"h2"}}, true)
|
||||
}
|
||||
|
||||
func testAutomaticHTTP2_Serve(t *testing.T, tlsConf *tls.Config, wantH2 bool) {
|
||||
defer afterTest(t)
|
||||
ln := newLocalListener(t)
|
||||
ln.Close() // immediately (not a defer!)
|
||||
var s Server
|
||||
s.TLSConfig = tlsConf
|
||||
if err := s.Serve(ln); err == nil {
|
||||
t.Fatal("expected an error")
|
||||
}
|
||||
gotH2 := s.TLSNextProto["h2"] != nil
|
||||
if gotH2 != wantH2 {
|
||||
t.Errorf("http2 configured = %v; want %v", gotH2, wantH2)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAutomaticHTTP2_Serve_WithTLSConfig(t *testing.T) {
|
||||
defer afterTest(t)
|
||||
ln := newLocalListener(t)
|
||||
ln.Close() // immediately (not a defer!)
|
||||
var s Server
|
||||
// Set the TLSConfig. In reality, this would be the
|
||||
// *tls.Config given to tls.NewListener.
|
||||
s.TLSConfig = &tls.Config{
|
||||
NextProtos: []string{"h2"},
|
||||
}
|
||||
if err := s.Serve(ln); err == nil {
|
||||
t.Fatal("expected an error")
|
||||
}
|
||||
@ -3957,6 +3991,8 @@ func TestServerValidatesHostHeader(t *testing.T) {
|
||||
host string
|
||||
want int
|
||||
}{
|
||||
{"HTTP/0.9", "", 400},
|
||||
|
||||
{"HTTP/1.1", "", 400},
|
||||
{"HTTP/1.1", "Host: \r\n", 200},
|
||||
{"HTTP/1.1", "Host: 1.2.3.4\r\n", 200},
|
||||
@ -3982,6 +4018,11 @@ func TestServerValidatesHostHeader(t *testing.T) {
|
||||
|
||||
// Make an exception for HTTP upgrade requests:
|
||||
{"PRI * HTTP/2.0", "", 200},
|
||||
|
||||
// But not other HTTP/2 stuff:
|
||||
{"PRI / HTTP/2.0", "", 400},
|
||||
{"GET / HTTP/2.0", "", 400},
|
||||
{"GET / HTTP/3.0", "", 400},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
conn := &testConn{closec: make(chan bool, 1)}
|
||||
@ -4200,6 +4241,24 @@ func TestHandlerSetTransferEncodingChunked(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// https://golang.org/issue/16063
|
||||
func TestHandlerSetTransferEncodingGzip(t *testing.T) {
|
||||
defer afterTest(t)
|
||||
ht := newHandlerTest(HandlerFunc(func(w ResponseWriter, r *Request) {
|
||||
w.Header().Set("Transfer-Encoding", "gzip")
|
||||
gz := gzip.NewWriter(w)
|
||||
gz.Write([]byte("hello"))
|
||||
gz.Close()
|
||||
}))
|
||||
resp := ht.rawResponse("GET / HTTP/1.1\nHost: foo")
|
||||
for _, v := range []string{"gzip", "chunked"} {
|
||||
hdr := "Transfer-Encoding: " + v
|
||||
if n := strings.Count(resp, hdr); n != 1 {
|
||||
t.Errorf("want 1 occurrence of %q in response, got %v\nresponse: %v", hdr, n, resp)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkClientServer(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
b.StopTimer()
|
||||
|
@ -771,8 +771,9 @@ func (c *conn) readRequest(ctx context.Context) (w *response, err error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ctx, cancelCtx := context.WithCancel(ctx)
|
||||
req.ctx = ctx
|
||||
if !http1ServerSupportsRequest(req) {
|
||||
return nil, badRequestError("unsupported protocol version")
|
||||
}
|
||||
|
||||
c.lastMethod = req.Method
|
||||
c.r.setInfiniteReadLimit()
|
||||
@ -800,6 +801,8 @@ func (c *conn) readRequest(ctx context.Context) (w *response, err error) {
|
||||
}
|
||||
delete(req.Header, "Host")
|
||||
|
||||
ctx, cancelCtx := context.WithCancel(ctx)
|
||||
req.ctx = ctx
|
||||
req.RemoteAddr = c.remoteAddr
|
||||
req.TLS = c.tlsState
|
||||
if body, ok := req.Body.(*body); ok {
|
||||
@ -828,6 +831,23 @@ func (c *conn) readRequest(ctx context.Context) (w *response, err error) {
|
||||
return w, nil
|
||||
}
|
||||
|
||||
// http1ServerSupportsRequest reports whether Go's HTTP/1.x server
|
||||
// supports the given request.
|
||||
func http1ServerSupportsRequest(req *Request) bool {
|
||||
if req.ProtoMajor == 1 {
|
||||
return true
|
||||
}
|
||||
// Accept "PRI * HTTP/2.0" upgrade requests, so Handlers can
|
||||
// wire up their own HTTP/2 upgrades.
|
||||
if req.ProtoMajor == 2 && req.ProtoMinor == 0 &&
|
||||
req.Method == "PRI" && req.RequestURI == "*" {
|
||||
return true
|
||||
}
|
||||
// Reject HTTP/0.x, and all other HTTP/2+ requests (which
|
||||
// aren't encoded in ASCII anyway).
|
||||
return false
|
||||
}
|
||||
|
||||
func (w *response) Header() Header {
|
||||
if w.cw.header == nil && w.wroteHeader && !w.cw.wroteHeader {
|
||||
// Accessing the header between logically writing it
|
||||
@ -1147,7 +1167,10 @@ func (cw *chunkWriter) writeHeader(p []byte) {
|
||||
// to avoid closing the connection at EOF.
|
||||
cw.chunking = true
|
||||
setHeader.transferEncoding = "chunked"
|
||||
delHeader("Transfer-Encoding")
|
||||
if hasTE && te == "chunked" {
|
||||
// We will send the chunked Transfer-Encoding header later.
|
||||
delHeader("Transfer-Encoding")
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// HTTP version < 1.1: cannot do chunked transfer
|
||||
@ -2198,9 +2221,37 @@ func (srv *Server) ListenAndServe() error {
|
||||
|
||||
var testHookServerServe func(*Server, net.Listener) // used if non-nil
|
||||
|
||||
// shouldDoServeHTTP2 reports whether Server.Serve should configure
|
||||
// automatic HTTP/2. (which sets up the srv.TLSNextProto map)
|
||||
func (srv *Server) shouldConfigureHTTP2ForServe() bool {
|
||||
if srv.TLSConfig == nil {
|
||||
// Compatibility with Go 1.6:
|
||||
// If there's no TLSConfig, it's possible that the user just
|
||||
// didn't set it on the http.Server, but did pass it to
|
||||
// tls.NewListener and passed that listener to Serve.
|
||||
// So we should configure HTTP/2 (to set up srv.TLSNextProto)
|
||||
// in case the listener returns an "h2" *tls.Conn.
|
||||
return true
|
||||
}
|
||||
// The user specified a TLSConfig on their http.Server.
|
||||
// In this, case, only configure HTTP/2 if their tls.Config
|
||||
// explicitly mentions "h2". Otherwise http2.ConfigureServer
|
||||
// would modify the tls.Config to add it, but they probably already
|
||||
// passed this tls.Config to tls.NewListener. And if they did,
|
||||
// it's too late anyway to fix it. It would only be potentially racy.
|
||||
// See Issue 15908.
|
||||
return strSliceContains(srv.TLSConfig.NextProtos, http2NextProtoTLS)
|
||||
}
|
||||
|
||||
// Serve accepts incoming connections on the Listener l, creating a
|
||||
// new service goroutine for each. The service goroutines read requests and
|
||||
// then call srv.Handler to reply to them.
|
||||
//
|
||||
// For HTTP/2 support, srv.TLSConfig should be initialized to the
|
||||
// provided listener's TLS Config before calling Serve. If
|
||||
// srv.TLSConfig is non-nil and doesn't include the string "h2" in
|
||||
// Config.NextProtos, HTTP/2 support is not enabled.
|
||||
//
|
||||
// Serve always returns a non-nil error.
|
||||
func (srv *Server) Serve(l net.Listener) error {
|
||||
defer l.Close()
|
||||
@ -2208,9 +2259,13 @@ func (srv *Server) Serve(l net.Listener) error {
|
||||
fn(srv, l)
|
||||
}
|
||||
var tempDelay time.Duration // how long to sleep on accept failure
|
||||
if err := srv.setupHTTP2(); err != nil {
|
||||
return err
|
||||
|
||||
if srv.shouldConfigureHTTP2ForServe() {
|
||||
if err := srv.setupHTTP2(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: allow changing base context? can't imagine concrete
|
||||
// use cases yet.
|
||||
baseCtx := context.Background()
|
||||
|
@ -845,10 +845,26 @@ func (t *Transport) getConn(treq *transportRequest, cm connectMethod) (*persistC
|
||||
select {
|
||||
case v := <-dialc:
|
||||
// Our dial finished.
|
||||
if trace != nil && trace.GotConn != nil && v.pc != nil && v.pc.alt == nil {
|
||||
trace.GotConn(httptrace.GotConnInfo{Conn: v.pc.conn})
|
||||
if v.pc != nil {
|
||||
if trace != nil && trace.GotConn != nil && v.pc.alt == nil {
|
||||
trace.GotConn(httptrace.GotConnInfo{Conn: v.pc.conn})
|
||||
}
|
||||
return v.pc, nil
|
||||
}
|
||||
return v.pc, v.err
|
||||
// Our dial failed. See why to return a nicer error
|
||||
// value.
|
||||
select {
|
||||
case <-req.Cancel:
|
||||
case <-req.Context().Done():
|
||||
case <-cancelc:
|
||||
default:
|
||||
// It wasn't an error due to cancelation, so
|
||||
// return the original error message:
|
||||
return nil, v.err
|
||||
}
|
||||
// It was an error due to cancelation, so prioritize that
|
||||
// error value. (Issue 16049)
|
||||
return nil, errRequestCanceledConn
|
||||
case pc := <-idleConnCh:
|
||||
// Another request finished first and its net.Conn
|
||||
// became available before our dial. Or somebody
|
||||
|
@ -453,6 +453,10 @@ func TestLookupDotsWithLocalSource(t *testing.T) {
|
||||
t.Skip("IPv4 is required")
|
||||
}
|
||||
|
||||
if testenv.Builder() == "" {
|
||||
testenv.MustHaveExternalNetwork(t)
|
||||
}
|
||||
|
||||
for i, fn := range []func() func(){forceGoDNS, forceCgoDNS} {
|
||||
fixup := fn()
|
||||
if fixup == nil {
|
||||
|
@ -111,6 +111,7 @@ type Cmd struct {
|
||||
closeAfterWait []io.Closer
|
||||
goroutine []func() error
|
||||
errch chan error // one send per goroutine
|
||||
waitDone chan struct{}
|
||||
}
|
||||
|
||||
// Command returns the Cmd struct to execute the named program with
|
||||
@ -326,6 +327,15 @@ func (c *Cmd) Start() error {
|
||||
if c.Process != nil {
|
||||
return errors.New("exec: already started")
|
||||
}
|
||||
if c.ctx != nil {
|
||||
select {
|
||||
case <-c.ctx.Done():
|
||||
c.closeDescriptors(c.closeAfterStart)
|
||||
c.closeDescriptors(c.closeAfterWait)
|
||||
return c.ctx.Err()
|
||||
default:
|
||||
}
|
||||
}
|
||||
|
||||
type F func(*Cmd) (*os.File, error)
|
||||
for _, setupFd := range []F{(*Cmd).stdin, (*Cmd).stdout, (*Cmd).stderr} {
|
||||
@ -361,6 +371,17 @@ func (c *Cmd) Start() error {
|
||||
}(fn)
|
||||
}
|
||||
|
||||
if c.ctx != nil {
|
||||
c.waitDone = make(chan struct{})
|
||||
go func() {
|
||||
select {
|
||||
case <-c.ctx.Done():
|
||||
c.Process.Kill()
|
||||
case <-c.waitDone:
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -410,20 +431,9 @@ func (c *Cmd) Wait() error {
|
||||
}
|
||||
c.finished = true
|
||||
|
||||
var waitDone chan struct{}
|
||||
if c.ctx != nil {
|
||||
waitDone = make(chan struct{})
|
||||
go func() {
|
||||
select {
|
||||
case <-c.ctx.Done():
|
||||
c.Process.Kill()
|
||||
case <-waitDone:
|
||||
}
|
||||
}()
|
||||
}
|
||||
state, err := c.Process.Wait()
|
||||
if waitDone != nil {
|
||||
close(waitDone)
|
||||
if c.waitDone != nil {
|
||||
close(c.waitDone)
|
||||
}
|
||||
c.ProcessState = state
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user