mirror of
https://github.com/golang/go.git
synced 2026-01-30 07:32:05 +03:00
Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f75aafdf56 | ||
|
|
b261730e56 | ||
|
|
40712a9625 | ||
|
|
24f46bd34f | ||
|
|
c24b5d43a6 | ||
|
|
dc3612e0d1 | ||
|
|
6f12826a86 | ||
|
|
3129c67db7 | ||
|
|
bb8706890b | ||
|
|
287be1e42d | ||
|
|
308bdd0256 | ||
|
|
9b4e323e88 | ||
|
|
a5add8c726 | ||
|
|
e464c08bef | ||
|
|
c0f5de1ad2 | ||
|
|
1861ac159e | ||
|
|
759c2c48ea | ||
|
|
09fa0b8e95 | ||
|
|
0d81858868 | ||
|
|
681a667ced | ||
|
|
806a84d3f1 | ||
|
|
87d4bd1997 | ||
|
|
1e933ed7c0 | ||
|
|
78d024a588 | ||
|
|
09fc3cc5df | ||
|
|
17a48e0a00 |
@@ -34,6 +34,7 @@ We encourage all Go users to subscribe to
|
||||
<p>A <a href="/doc/devel/release.html">summary</a> of the changes between Go releases. Notes for the major releases:</p>
|
||||
|
||||
<ul>
|
||||
<li><a href="/doc/go1.7">Go 1.7</a> <small>(August 2016)</small></li>
|
||||
<li><a href="/doc/go1.6">Go 1.6</a> <small>(February 2016)</small></li>
|
||||
<li><a href="/doc/go1.5">Go 1.5</a> <small>(August 2015)</small></li>
|
||||
<li><a href="/doc/go1.4">Go 1.4</a> <small>(December 2014)</small></li>
|
||||
|
||||
@@ -30,6 +30,25 @@ to fix critical security problems in both Go 1.4 and Go 1.5 as they arise.
|
||||
See the <a href="/security">security policy</a> for more details.
|
||||
</p>
|
||||
|
||||
<h2 id="go1.7">go1.7 (released 2016/08/15)</h2>
|
||||
|
||||
<p>
|
||||
Go 1.7 is a major release of Go.
|
||||
Read the <a href="/doc/go1.7">Go 1.7 Release Notes</a> for more information.
|
||||
</p>
|
||||
|
||||
<h3 id="go1.7.minor">Minor revisions</h3>
|
||||
|
||||
<p>
|
||||
go1.7.1 (released 2016/09/07) includes fixes to the compiler, runtime,
|
||||
documentation, and the <code>compress/flate</code>, <code>hash/crc32</code>,
|
||||
<code>io</code> <code>net</code>, <code>net/http</code>,
|
||||
<code>path/filepath</code>, <code>reflect</code>, and <code>syscall</code>
|
||||
packages.
|
||||
See the <a href="https://github.com/golang/go/issues?q=milestone%3AGo1.7.1">Go
|
||||
1.7.1 milestone</a> on our issue tracker for details.
|
||||
</p>
|
||||
|
||||
<h2 id="go1.6">go1.6 (released 2016/02/17)</h2>
|
||||
|
||||
<p>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<!--{
|
||||
"Title": "Go 1.7 Release Notes DRAFT",
|
||||
"Title": "Go 1.7 Release Notes",
|
||||
"Path": "/doc/go1.7",
|
||||
"Template": true
|
||||
}-->
|
||||
@@ -25,15 +25,6 @@ Do not send CLs removing the interior tags from such phrases.
|
||||
ul li { margin: 0.5em 0; }
|
||||
</style>
|
||||
|
||||
<p>
|
||||
<!-- TODO: REMOVE THIS COMMENT -->
|
||||
<!-- TODO: Also remove "DRAFT" in the "Title" at the top of this file. -->
|
||||
<i>NOTE: This is a DRAFT of the Go 1.7 release notes, prepared for the Go 1.7 beta.
|
||||
Go 1.7 has NOT yet been released.
|
||||
By our regular schedule, it is expected some time in August 2016.
|
||||
</i>
|
||||
</p>
|
||||
|
||||
<h2 id="introduction">Introduction to Go 1.7</h2>
|
||||
|
||||
<p>
|
||||
@@ -919,7 +910,7 @@ For example, the address on which a request received is
|
||||
<p>
|
||||
The server's <a href="/pkg/net/http/#Server.Serve"><code>Serve</code></a> method
|
||||
now only enables HTTP/2 support if the <code>Server.TLSConfig</code> field is <code>nil</code>
|
||||
or includes <code>"h2"</code> in its <code>TLSConfig.NextProto</code>.
|
||||
or includes <code>"h2"</code> in its <code>TLSConfig.NextProtos</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
||||
238
doc/gopher/favicon.svg
Normal file
238
doc/gopher/favicon.svg
Normal file
@@ -0,0 +1,238 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="32"
|
||||
height="32"
|
||||
viewBox="0 0 32 32.000001"
|
||||
id="svg4416"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="favicon.svg"
|
||||
inkscape:export-filename="../../favicon.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90">
|
||||
<defs
|
||||
id="defs4418" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="15.839192"
|
||||
inkscape:cx="17.966652"
|
||||
inkscape:cy="9.2991824"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
units="px"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:snap-bbox-edge-midpoints="false"
|
||||
inkscape:bbox-nodes="true"
|
||||
showguides="false"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1018"
|
||||
inkscape:window-x="1912"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:object-nodes="true"
|
||||
inkscape:snap-smooth-nodes="true"
|
||||
inkscape:snap-global="false">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid5148" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata4421">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="icon"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(0,-1020.3622)">
|
||||
<ellipse
|
||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#384e54;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
id="ellipse4216"
|
||||
cx="-907.35657"
|
||||
cy="479.90009"
|
||||
rx="3.5793996"
|
||||
ry="3.8207953"
|
||||
transform="matrix(-0.49169095,-0.87076978,-0.87076978,0.49169095,0,0)"
|
||||
inkscape:transform-center-x="0.67794294"
|
||||
inkscape:transform-center-y="-2.3634048" />
|
||||
<ellipse
|
||||
inkscape:transform-center-y="-2.3633882"
|
||||
inkscape:transform-center-x="-0.67793718"
|
||||
transform="matrix(0.49169095,-0.87076978,0.87076978,0.49169095,0,0)"
|
||||
ry="3.8207953"
|
||||
rx="3.5793996"
|
||||
cy="507.8461"
|
||||
cx="-891.57654"
|
||||
id="ellipse4463"
|
||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#384e54;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#384e54;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m 16.091693,1021.3642 c -1.105749,0.01 -2.210341,0.049 -3.31609,0.09 C 6.8422558,1021.6738 2,1026.3942 2,1032.3622 c 0,2.9786 0,13 0,20 l 28,0 c 0,-8 0,-16 0,-20 0,-5.9683 -4.667345,-10.4912 -10.59023,-10.908 -1.10575,-0.078 -2.212328,-0.099 -3.318077,-0.09 z"
|
||||
id="path4465"
|
||||
sodipodi:nodetypes="ccsccscc" />
|
||||
<path
|
||||
inkscape:transform-center-y="-1.3604657"
|
||||
inkscape:transform-center-x="-0.98424303"
|
||||
sodipodi:nodetypes="sssssss"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4469"
|
||||
d="m 4.6078867,1025.0462 c 0.459564,0.2595 1.818262,1.2013 1.980983,1.648 0.183401,0.5035 0.159385,1.0657 -0.114614,1.551 -0.346627,0.6138 -1.005341,0.9487 -1.696421,0.9365 -0.339886,-0.01 -1.720283,-0.6372 -2.042561,-0.8192 -0.97754,-0.5519 -1.350795,-1.7418 -0.833686,-2.6576 0.517109,-0.9158 1.728749,-1.2107 2.706299,-0.6587 z"
|
||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#76e1fe;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate" />
|
||||
<rect
|
||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:0.32850246;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
id="rect4473"
|
||||
width="3.0866659"
|
||||
height="3.5313663"
|
||||
x="14.406213"
|
||||
y="1035.6842"
|
||||
ry="0.62426329" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#76e1fe;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m 16,1023.3622 c -9,0 -12,3.7153 -12,9 l 0,20 24,0 c -0.04889,-7.3562 0,-18 0,-20 0,-5.2848 -3,-9 -12,-9 z"
|
||||
id="path4471"
|
||||
sodipodi:nodetypes="zsccsz" />
|
||||
<path
|
||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#76e1fe;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m 27.074073,1025.0462 c -0.45957,0.2595 -1.818257,1.2013 -1.980979,1.648 -0.183401,0.5035 -0.159384,1.0657 0.114614,1.551 0.346627,0.6138 1.005335,0.9487 1.696415,0.9365 0.33988,-0.01 1.72029,-0.6372 2.04256,-0.8192 0.97754,-0.5519 1.35079,-1.7418 0.83369,-2.6576 -0.51711,-0.9158 -1.72876,-1.2107 -2.7063,-0.6587 z"
|
||||
id="path4481"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="sssssss"
|
||||
inkscape:transform-center-x="0.98424094"
|
||||
inkscape:transform-center-y="-1.3604657" />
|
||||
<circle
|
||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
id="circle4477"
|
||||
cx="21.175734"
|
||||
cy="1030.3542"
|
||||
r="4.6537542"
|
||||
inkscape:export-filename=".\rect4485.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90" />
|
||||
<circle
|
||||
r="4.8316345"
|
||||
cy="1030.3542"
|
||||
cx="10.339486"
|
||||
id="circle4483"
|
||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
inkscape:export-filename=".\rect4485.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90" />
|
||||
<rect
|
||||
inkscape:export-ydpi="90"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-filename=".\rect4485.png"
|
||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:0.32941176;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
id="rect4246"
|
||||
width="3.6673687"
|
||||
height="4.1063409"
|
||||
x="14.115863"
|
||||
y="1035.9174"
|
||||
ry="0.72590536" />
|
||||
<rect
|
||||
ry="0.72590536"
|
||||
y="1035.2253"
|
||||
x="14.115863"
|
||||
height="4.1063409"
|
||||
width="3.6673687"
|
||||
id="rect4485"
|
||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#fffcfb;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
inkscape:export-filename=".\rect4485.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90" />
|
||||
<path
|
||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#000000;fill-opacity:0.32941176;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m 19.999735,1036.5289 c 0,0.838 -0.871228,1.2682 -2.144766,1.1659 -0.02366,0 -0.04795,-0.6004 -0.254147,-0.5832 -0.503669,0.042 -1.095902,-0.02 -1.685964,-0.02 -0.612939,0 -1.206342,0.1826 -1.68549,0.017 -0.110233,-0.038 -0.178298,0.5838 -0.261532,0.5816 -1.243685,-0.033 -2.078803,-0.3383 -2.078803,-1.1618 0,-1.2118 1.815635,-2.1941 4.055351,-2.1941 2.239704,0 4.055351,0.9823 4.055351,2.1941 z"
|
||||
id="path4487"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="sssssssss"
|
||||
inkscape:export-filename=".\rect4485.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90" />
|
||||
<path
|
||||
sodipodi:nodetypes="sssssssss"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4489"
|
||||
d="m 19.977414,1035.7004 c 0,0.5685 -0.433659,0.8554 -1.138091,1.0001 -0.291933,0.06 -0.630371,0.096 -1.003719,0.1166 -0.56405,0.032 -1.207782,0.031 -1.89122,0.031 -0.672834,0 -1.307182,0 -1.864904,-0.029 -0.306268,-0.017 -0.589429,-0.043 -0.843164,-0.084 -0.813833,-0.1318 -1.324962,-0.417 -1.324962,-1.0344 0,-1.1601 1.805642,-2.1006 4.03303,-2.1006 2.227377,0 4.03303,0.9405 4.03303,2.1006 z"
|
||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#c38c74;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
inkscape:export-filename=".\rect4485.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90" />
|
||||
<ellipse
|
||||
cy="1033.8501"
|
||||
cx="15.944382"
|
||||
id="ellipse4491"
|
||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#23201f;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
rx="2.0801733"
|
||||
ry="1.343747"
|
||||
inkscape:export-filename=".\rect4485.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90" />
|
||||
<circle
|
||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#171311;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
id="circle4493"
|
||||
cx="12.414201"
|
||||
cy="1030.3542"
|
||||
r="1.9630634"
|
||||
inkscape:export-filename=".\rect4485.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90" />
|
||||
<circle
|
||||
r="1.9630634"
|
||||
cy="1030.3542"
|
||||
cx="23.110121"
|
||||
id="circle4495"
|
||||
style="color:#000000;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:1;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#171311;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
inkscape:export-filename=".\rect4485.png"
|
||||
inkscape:export-xdpi="90"
|
||||
inkscape:export-ydpi="90" />
|
||||
<path
|
||||
sodipodi:nodetypes="cc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4497"
|
||||
d="m 5.0055377,1027.2727 c -1.170435,-1.0835 -2.026973,-0.7721 -2.044172,-0.7463"
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#384e54;stroke-width:0.39730874;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#384e54;stroke-width:0.39730874;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 4.3852457,1026.9152 c -1.158557,0.036 -1.346704,0.6303 -1.33881,0.6523"
|
||||
id="path4499"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#384e54;stroke-width:0.39730874;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 26.630533,1027.1724 c 1.17043,-1.0835 2.02697,-0.7721 2.04417,-0.7463"
|
||||
id="path4501"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
sodipodi:nodetypes="cc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4503"
|
||||
d="m 27.321773,1026.673 c 1.15856,0.036 1.3467,0.6302 1.3388,0.6522"
|
||||
style="display:inline;fill:none;fill-rule:evenodd;stroke:#384e54;stroke-width:0.39730874;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 17 KiB |
@@ -203,7 +203,7 @@ To build without <code>cgo</code>, set the environment variable
|
||||
Change to the directory that will be its parent
|
||||
and make sure the <code>go</code> directory does not exist.
|
||||
Then clone the repository and check out the latest release tag
|
||||
(<code class="versionTag">go1.6</code>, for example):</p>
|
||||
(<code class="versionTag">go1.7.1</code>, for example):</p>
|
||||
|
||||
<pre>
|
||||
$ git clone https://go.googlesource.com/go
|
||||
@@ -391,7 +391,7 @@ New releases are announced on the
|
||||
<a href="//groups.google.com/group/golang-announce">golang-announce</a>
|
||||
mailing list.
|
||||
Each announcement mentions the latest release tag, for instance,
|
||||
<code class="versionTag">go1.6</code>.
|
||||
<code class="versionTag">go1.7.1</code>.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
|
||||
BIN
favicon.ico
BIN
favicon.ico
Binary file not shown.
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 5.6 KiB |
@@ -14,8 +14,7 @@ func dse(f *Func) {
|
||||
defer f.retSparseSet(loadUse)
|
||||
storeUse := f.newSparseSet(f.NumValues())
|
||||
defer f.retSparseSet(storeUse)
|
||||
shadowed := f.newSparseSet(f.NumValues())
|
||||
defer f.retSparseSet(shadowed)
|
||||
shadowed := newSparseMap(f.NumValues()) // TODO: cache
|
||||
for _, b := range f.Blocks {
|
||||
// Find all the stores in this block. Categorize their uses:
|
||||
// loadUse contains stores which are used by a subsequent load.
|
||||
@@ -81,17 +80,18 @@ func dse(f *Func) {
|
||||
shadowed.clear()
|
||||
}
|
||||
if v.Op == OpStore || v.Op == OpZero {
|
||||
if shadowed.contains(v.Args[0].ID) {
|
||||
sz := v.AuxInt
|
||||
if shadowedSize := int64(shadowed.get(v.Args[0].ID)); shadowedSize != -1 && shadowedSize >= sz {
|
||||
// Modify store into a copy
|
||||
if v.Op == OpStore {
|
||||
// store addr value mem
|
||||
v.SetArgs1(v.Args[2])
|
||||
} else {
|
||||
// zero addr mem
|
||||
sz := v.Args[0].Type.ElemType().Size()
|
||||
if v.AuxInt != sz {
|
||||
typesz := v.Args[0].Type.ElemType().Size()
|
||||
if sz != typesz {
|
||||
f.Fatalf("mismatched zero/store sizes: %d and %d [%s]",
|
||||
v.AuxInt, sz, v.LongString())
|
||||
sz, typesz, v.LongString())
|
||||
}
|
||||
v.SetArgs1(v.Args[1])
|
||||
}
|
||||
@@ -99,7 +99,10 @@ func dse(f *Func) {
|
||||
v.AuxInt = 0
|
||||
v.Op = OpCopy
|
||||
} else {
|
||||
shadowed.add(v.Args[0].ID)
|
||||
if sz > 0x7fffffff { // work around sparseMap's int32 value type
|
||||
sz = 0x7fffffff
|
||||
}
|
||||
shadowed.set(v.Args[0].ID, int32(sz))
|
||||
}
|
||||
}
|
||||
// walk to previous store
|
||||
|
||||
@@ -8,7 +8,7 @@ import "testing"
|
||||
|
||||
func TestDeadStore(t *testing.T) {
|
||||
c := testConfig(t)
|
||||
elemType := &TypeImpl{Size_: 8, Name: "testtype"}
|
||||
elemType := &TypeImpl{Size_: 1, Name: "testtype"}
|
||||
ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr", Elem_: elemType} // dummy for testing
|
||||
fun := Fun(c, "entry",
|
||||
Bloc("entry",
|
||||
@@ -18,7 +18,7 @@ func TestDeadStore(t *testing.T) {
|
||||
Valu("addr1", OpAddr, ptrType, 0, nil, "sb"),
|
||||
Valu("addr2", OpAddr, ptrType, 0, nil, "sb"),
|
||||
Valu("addr3", OpAddr, ptrType, 0, nil, "sb"),
|
||||
Valu("zero1", OpZero, TypeMem, 8, nil, "addr3", "start"),
|
||||
Valu("zero1", OpZero, TypeMem, 1, nil, "addr3", "start"),
|
||||
Valu("store1", OpStore, TypeMem, 1, nil, "addr1", "v", "zero1"),
|
||||
Valu("store2", OpStore, TypeMem, 1, nil, "addr2", "v", "store1"),
|
||||
Valu("store3", OpStore, TypeMem, 1, nil, "addr1", "v", "store2"),
|
||||
@@ -95,3 +95,32 @@ func TestDeadStoreTypes(t *testing.T) {
|
||||
t.Errorf("store %s incorrectly removed", v)
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeadStoreUnsafe(t *testing.T) {
|
||||
// Make sure a narrow store can't shadow a wider one. The test above
|
||||
// covers the case of two different types, but unsafe pointer casting
|
||||
// can get to a point where the size is changed but type unchanged.
|
||||
c := testConfig(t)
|
||||
ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr"} // dummy for testing
|
||||
fun := Fun(c, "entry",
|
||||
Bloc("entry",
|
||||
Valu("start", OpInitMem, TypeMem, 0, nil),
|
||||
Valu("sb", OpSB, TypeInvalid, 0, nil),
|
||||
Valu("v", OpConstBool, TypeBool, 1, nil),
|
||||
Valu("addr1", OpAddr, ptrType, 0, nil, "sb"),
|
||||
Valu("store1", OpStore, TypeMem, 8, nil, "addr1", "v", "start"), // store 8 bytes
|
||||
Valu("store2", OpStore, TypeMem, 1, nil, "addr1", "v", "store1"), // store 1 byte
|
||||
Goto("exit")),
|
||||
Bloc("exit",
|
||||
Exit("store2")))
|
||||
|
||||
CheckFunc(fun.f)
|
||||
cse(fun.f)
|
||||
dse(fun.f)
|
||||
CheckFunc(fun.f)
|
||||
|
||||
v := fun.values["store1"]
|
||||
if v.Op == OpCopy {
|
||||
t.Errorf("store %s incorrectly removed", v)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -724,7 +724,7 @@ func (w *Writer) Close() error {
|
||||
// the result of NewWriter or NewWriterDict called with dst
|
||||
// and w's level and dictionary.
|
||||
func (w *Writer) Reset(dst io.Writer) {
|
||||
if dw, ok := w.d.w.w.(*dictWriter); ok {
|
||||
if dw, ok := w.d.w.writer.(*dictWriter); ok {
|
||||
// w was created with NewWriterDict
|
||||
dw.w = dst
|
||||
w.d.reset(dw)
|
||||
|
||||
@@ -6,6 +6,7 @@ package flate
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"errors"
|
||||
"fmt"
|
||||
"internal/testenv"
|
||||
"io"
|
||||
@@ -631,3 +632,52 @@ func TestBestSpeed(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var errIO = errors.New("IO error")
|
||||
|
||||
// failWriter fails with errIO exactly at the nth call to Write.
|
||||
type failWriter struct{ n int }
|
||||
|
||||
func (w *failWriter) Write(b []byte) (int, error) {
|
||||
w.n--
|
||||
if w.n == -1 {
|
||||
return 0, errIO
|
||||
}
|
||||
return len(b), nil
|
||||
}
|
||||
|
||||
func TestWriterPersistentError(t *testing.T) {
|
||||
d, err := ioutil.ReadFile("../testdata/Mark.Twain-Tom.Sawyer.txt")
|
||||
if err != nil {
|
||||
t.Fatalf("ReadFile: %v", err)
|
||||
}
|
||||
d = d[:10000] // Keep this test short
|
||||
|
||||
zw, err := NewWriter(nil, DefaultCompression)
|
||||
if err != nil {
|
||||
t.Fatalf("NewWriter: %v", err)
|
||||
}
|
||||
|
||||
// Sweep over the threshold at which an error is returned.
|
||||
// The variable i makes it such that the ith call to failWriter.Write will
|
||||
// return errIO. Since failWriter errors are not persistent, we must ensure
|
||||
// that flate.Writer errors are persistent.
|
||||
for i := 0; i < 1000; i++ {
|
||||
fw := &failWriter{i}
|
||||
zw.Reset(fw)
|
||||
|
||||
_, werr := zw.Write(d)
|
||||
cerr := zw.Close()
|
||||
if werr != errIO && werr != nil {
|
||||
t.Errorf("test %d, mismatching Write error: got %v, want %v", i, werr, errIO)
|
||||
}
|
||||
if cerr != errIO && fw.n < 0 {
|
||||
t.Errorf("test %d, mismatching Close error: got %v, want %v", i, cerr, errIO)
|
||||
}
|
||||
if fw.n >= 0 {
|
||||
// At this point, the failure threshold was sufficiently high enough
|
||||
// that we wrote the whole stream without any errors.
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,7 +77,11 @@ var offsetBase = []uint32{
|
||||
var codegenOrder = []uint32{16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}
|
||||
|
||||
type huffmanBitWriter struct {
|
||||
w io.Writer
|
||||
// writer is the underlying writer.
|
||||
// Do not use it directly; use the write method, which ensures
|
||||
// that Write errors are sticky.
|
||||
writer io.Writer
|
||||
|
||||
// Data waiting to be written is bytes[0:nbytes]
|
||||
// and then the low nbits of bits.
|
||||
bits uint64
|
||||
@@ -96,7 +100,7 @@ type huffmanBitWriter struct {
|
||||
|
||||
func newHuffmanBitWriter(w io.Writer) *huffmanBitWriter {
|
||||
return &huffmanBitWriter{
|
||||
w: w,
|
||||
writer: w,
|
||||
literalFreq: make([]int32, maxNumLit),
|
||||
offsetFreq: make([]int32, offsetCodeCount),
|
||||
codegen: make([]uint8, maxNumLit+offsetCodeCount+1),
|
||||
@@ -107,7 +111,7 @@ func newHuffmanBitWriter(w io.Writer) *huffmanBitWriter {
|
||||
}
|
||||
|
||||
func (w *huffmanBitWriter) reset(writer io.Writer) {
|
||||
w.w = writer
|
||||
w.writer = writer
|
||||
w.bits, w.nbits, w.nbytes, w.err = 0, 0, 0, nil
|
||||
w.bytes = [bufferSize]byte{}
|
||||
}
|
||||
@@ -129,11 +133,21 @@ func (w *huffmanBitWriter) flush() {
|
||||
n++
|
||||
}
|
||||
w.bits = 0
|
||||
_, w.err = w.w.Write(w.bytes[:n])
|
||||
w.write(w.bytes[:n])
|
||||
w.nbytes = 0
|
||||
}
|
||||
|
||||
func (w *huffmanBitWriter) write(b []byte) {
|
||||
if w.err != nil {
|
||||
return
|
||||
}
|
||||
_, w.err = w.writer.Write(b)
|
||||
}
|
||||
|
||||
func (w *huffmanBitWriter) writeBits(b int32, nb uint) {
|
||||
if w.err != nil {
|
||||
return
|
||||
}
|
||||
w.bits |= uint64(b) << w.nbits
|
||||
w.nbits += nb
|
||||
if w.nbits >= 48 {
|
||||
@@ -150,7 +164,7 @@ func (w *huffmanBitWriter) writeBits(b int32, nb uint) {
|
||||
bytes[5] = byte(bits >> 40)
|
||||
n += 6
|
||||
if n >= bufferFlushSize {
|
||||
_, w.err = w.w.Write(w.bytes[:n])
|
||||
w.write(w.bytes[:n])
|
||||
n = 0
|
||||
}
|
||||
w.nbytes = n
|
||||
@@ -173,13 +187,10 @@ func (w *huffmanBitWriter) writeBytes(bytes []byte) {
|
||||
n++
|
||||
}
|
||||
if n != 0 {
|
||||
_, w.err = w.w.Write(w.bytes[:n])
|
||||
if w.err != nil {
|
||||
return
|
||||
}
|
||||
w.write(w.bytes[:n])
|
||||
}
|
||||
w.nbytes = 0
|
||||
_, w.err = w.w.Write(bytes)
|
||||
w.write(bytes)
|
||||
}
|
||||
|
||||
// RFC 1951 3.2.7 specifies a special run-length encoding for specifying
|
||||
@@ -341,7 +352,7 @@ func (w *huffmanBitWriter) writeCode(c hcode) {
|
||||
bytes[5] = byte(bits >> 40)
|
||||
n += 6
|
||||
if n >= bufferFlushSize {
|
||||
_, w.err = w.w.Write(w.bytes[:n])
|
||||
w.write(w.bytes[:n])
|
||||
n = 0
|
||||
}
|
||||
w.nbytes = n
|
||||
@@ -572,6 +583,9 @@ func (w *huffmanBitWriter) indexTokens(tokens []token) (numLiterals, numOffsets
|
||||
// writeTokens writes a slice of tokens to the output.
|
||||
// codes for literal and offset encoding must be supplied.
|
||||
func (w *huffmanBitWriter) writeTokens(tokens []token, leCodes, oeCodes []hcode) {
|
||||
if w.err != nil {
|
||||
return
|
||||
}
|
||||
for _, t := range tokens {
|
||||
if t < matchType {
|
||||
w.writeCode(leCodes[t.literal()])
|
||||
@@ -676,9 +690,9 @@ func (w *huffmanBitWriter) writeBlockHuff(eof bool, input []byte) {
|
||||
if n < bufferFlushSize {
|
||||
continue
|
||||
}
|
||||
_, w.err = w.w.Write(w.bytes[:n])
|
||||
w.write(w.bytes[:n])
|
||||
if w.err != nil {
|
||||
return
|
||||
return // Return early in the event of write failures
|
||||
}
|
||||
n = 0
|
||||
}
|
||||
|
||||
@@ -4,14 +4,9 @@
|
||||
|
||||
package crc32
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
vxMinLen = 64
|
||||
vxAlignment = 16
|
||||
vxAlignMask = vxAlignment - 1
|
||||
vxAlignMask = 15 // align to 16 bytes
|
||||
)
|
||||
|
||||
// hasVectorFacility reports whether the machine has the z/Architecture
|
||||
@@ -49,20 +44,13 @@ func genericIEEE(crc uint32, p []byte) uint32 {
|
||||
return update(crc, IEEETable, p)
|
||||
}
|
||||
|
||||
// updateCastagnoli calculates the checksum of p using genericCastagnoli to
|
||||
// align the data appropriately for vectorCastagnoli. It avoids using
|
||||
// vectorCastagnoli entirely if the length of p is less than or equal to
|
||||
// vxMinLen.
|
||||
// updateCastagnoli calculates the checksum of p using
|
||||
// vectorizedCastagnoli if possible and falling back onto
|
||||
// genericCastagnoli as needed.
|
||||
func updateCastagnoli(crc uint32, p []byte) uint32 {
|
||||
// Use vectorized function if vector facility is available and
|
||||
// data length is above threshold.
|
||||
if hasVX && len(p) > vxMinLen {
|
||||
pAddr := uintptr(unsafe.Pointer(&p[0]))
|
||||
if pAddr&vxAlignMask != 0 {
|
||||
prealign := vxAlignment - int(pAddr&vxAlignMask)
|
||||
crc = genericCastagnoli(crc, p[:prealign])
|
||||
p = p[prealign:]
|
||||
}
|
||||
if hasVX && len(p) >= vxMinLen {
|
||||
aligned := len(p) & ^vxAlignMask
|
||||
crc = vectorizedCastagnoli(crc, p[:aligned])
|
||||
p = p[aligned:]
|
||||
@@ -75,19 +63,12 @@ func updateCastagnoli(crc uint32, p []byte) uint32 {
|
||||
return genericCastagnoli(crc, p)
|
||||
}
|
||||
|
||||
// updateIEEE calculates the checksum of p using genericIEEE to align the data
|
||||
// appropriately for vectorIEEE. It avoids using vectorIEEE entirely if the length
|
||||
// of p is less than or equal to vxMinLen.
|
||||
// updateIEEE calculates the checksum of p using vectorizedIEEE if
|
||||
// possible and falling back onto genericIEEE as needed.
|
||||
func updateIEEE(crc uint32, p []byte) uint32 {
|
||||
// Use vectorized function if vector facility is available and
|
||||
// data length is above threshold.
|
||||
if hasVX && len(p) > vxMinLen {
|
||||
pAddr := uintptr(unsafe.Pointer(&p[0]))
|
||||
if pAddr&vxAlignMask != 0 {
|
||||
prealign := vxAlignment - int(pAddr&vxAlignMask)
|
||||
crc = genericIEEE(crc, p[:prealign])
|
||||
p = p[prealign:]
|
||||
}
|
||||
if hasVX && len(p) >= vxMinLen {
|
||||
aligned := len(p) & ^vxAlignMask
|
||||
crc = vectorizedIEEE(crc, p[:aligned])
|
||||
p = p[aligned:]
|
||||
|
||||
@@ -128,6 +128,10 @@ TEXT vectorizedBody<>(SB),NOSPLIT,$0
|
||||
VZERO V0
|
||||
VLVGF $3, R2, V0
|
||||
|
||||
// Crash if the input size is less than 64-bytes.
|
||||
CMP R4, $64
|
||||
BLT crash
|
||||
|
||||
// Load a 64-byte data chunk and XOR with CRC
|
||||
VLM 0(R3), V1, V4 // 64-bytes into V1..V4
|
||||
|
||||
@@ -243,3 +247,6 @@ done:
|
||||
XOR $0xffffffff, R2 // NOTW R2
|
||||
MOVWZ R2, ret + 32(FP)
|
||||
RET
|
||||
|
||||
crash:
|
||||
MOVD $0, (R0) // input size is less than 64-bytes
|
||||
|
||||
@@ -18,15 +18,16 @@ func (mr *multiReader) Read(p []byte) (n int, err error) {
|
||||
}
|
||||
}
|
||||
n, err = mr.readers[0].Read(p)
|
||||
if err == EOF {
|
||||
mr.readers = mr.readers[1:]
|
||||
}
|
||||
if n > 0 || err != EOF {
|
||||
if err == EOF {
|
||||
// Don't return EOF yet. There may be more bytes
|
||||
// in the remaining readers.
|
||||
if err == EOF && len(mr.readers) > 0 {
|
||||
// Don't return EOF yet. More readers remain.
|
||||
err = nil
|
||||
}
|
||||
return
|
||||
}
|
||||
mr.readers = mr.readers[1:]
|
||||
}
|
||||
return 0, EOF
|
||||
}
|
||||
|
||||
@@ -196,3 +196,41 @@ func TestMultiReaderFlatten(t *testing.T) {
|
||||
myDepth+2, readDepth)
|
||||
}
|
||||
}
|
||||
|
||||
// byteAndEOFReader is a Reader which reads one byte (the underlying
|
||||
// byte) and io.EOF at once in its Read call.
|
||||
type byteAndEOFReader byte
|
||||
|
||||
func (b byteAndEOFReader) Read(p []byte) (n int, err error) {
|
||||
if len(p) == 0 {
|
||||
// Read(0 bytes) is useless. We expect no such useless
|
||||
// calls in this test.
|
||||
panic("unexpected call")
|
||||
}
|
||||
p[0] = byte(b)
|
||||
return 1, EOF
|
||||
}
|
||||
|
||||
// In Go 1.7, this yielded bytes forever.
|
||||
func TestMultiReaderSingleByteWithEOF(t *testing.T) {
|
||||
got, err := ioutil.ReadAll(LimitReader(MultiReader(byteAndEOFReader('a'), byteAndEOFReader('b')), 10))
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
const want = "ab"
|
||||
if string(got) != want {
|
||||
t.Errorf("got %q; want %q", got, want)
|
||||
}
|
||||
}
|
||||
|
||||
// Test that a reader returning (n, EOF) at the end of an MultiReader
|
||||
// chain continues to return EOF on its final read, rather than
|
||||
// yielding a (0, EOF).
|
||||
func TestMultiReaderFinalEOF(t *testing.T) {
|
||||
r := MultiReader(bytes.NewReader(nil), byteAndEOFReader('a'))
|
||||
buf := make([]byte, 2)
|
||||
n, err := r.Read(buf)
|
||||
if n != 1 || err != EOF {
|
||||
t.Errorf("got %v, %v; want 1, EOF", n, err)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -141,7 +141,7 @@ func (d *Dialer) dialDNS(ctx context.Context, network, server string) (dnsConn,
|
||||
}
|
||||
|
||||
// exchange sends a query on the connection and hopes for a response.
|
||||
func exchange(ctx context.Context, server, name string, qtype uint16) (*dnsMsg, error) {
|
||||
func exchange(ctx context.Context, server, name string, qtype uint16, timeout time.Duration) (*dnsMsg, error) {
|
||||
d := testHookDNSDialer()
|
||||
out := dnsMsg{
|
||||
dnsMsgHdr: dnsMsgHdr{
|
||||
@@ -152,6 +152,12 @@ func exchange(ctx context.Context, server, name string, qtype uint16) (*dnsMsg,
|
||||
},
|
||||
}
|
||||
for _, network := range []string{"udp", "tcp"} {
|
||||
// TODO(mdempsky): Refactor so defers from UDP-based
|
||||
// exchanges happen before TCP-based exchange.
|
||||
|
||||
ctx, cancel := context.WithDeadline(ctx, time.Now().Add(timeout))
|
||||
defer cancel()
|
||||
|
||||
c, err := d.dialDNS(ctx, network, server)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -180,17 +186,10 @@ func tryOneName(ctx context.Context, cfg *dnsConfig, name string, qtype uint16)
|
||||
return "", nil, &DNSError{Err: "no DNS servers", Name: name}
|
||||
}
|
||||
|
||||
deadline := time.Now().Add(cfg.timeout)
|
||||
if old, ok := ctx.Deadline(); !ok || deadline.Before(old) {
|
||||
var cancel context.CancelFunc
|
||||
ctx, cancel = context.WithDeadline(ctx, deadline)
|
||||
defer cancel()
|
||||
}
|
||||
|
||||
var lastErr error
|
||||
for i := 0; i < cfg.attempts; i++ {
|
||||
for _, server := range cfg.servers {
|
||||
msg, err := exchange(ctx, server, name, qtype)
|
||||
msg, err := exchange(ctx, server, name, qtype, cfg.timeout)
|
||||
if err != nil {
|
||||
lastErr = &DNSError{
|
||||
Err: err.Error(),
|
||||
@@ -338,8 +337,9 @@ func lookup(ctx context.Context, name string, qtype uint16) (cname string, rrs [
|
||||
}
|
||||
|
||||
// avoidDNS reports whether this is a hostname for which we should not
|
||||
// use DNS. Currently this includes only .onion and .local names,
|
||||
// per RFC 7686 and RFC 6762, respectively. See golang.org/issue/13705.
|
||||
// use DNS. Currently this includes only .onion, per RFC 7686. See
|
||||
// golang.org/issue/13705. Does not cover .local names (RFC 6762),
|
||||
// see golang.org/issue/16739.
|
||||
func avoidDNS(name string) bool {
|
||||
if name == "" {
|
||||
return true
|
||||
@@ -347,7 +347,7 @@ func avoidDNS(name string) bool {
|
||||
if name[len(name)-1] == '.' {
|
||||
name = name[:len(name)-1]
|
||||
}
|
||||
return stringsHasSuffixFold(name, ".onion") || stringsHasSuffixFold(name, ".local")
|
||||
return stringsHasSuffixFold(name, ".onion")
|
||||
}
|
||||
|
||||
// nameList returns a list of names for sequential DNS queries.
|
||||
|
||||
@@ -40,9 +40,9 @@ func TestDNSTransportFallback(t *testing.T) {
|
||||
testenv.MustHaveExternalNetwork(t)
|
||||
|
||||
for _, tt := range dnsTransportFallbackTests {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Duration(tt.timeout)*time.Second)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
msg, err := exchange(ctx, tt.server, tt.name, tt.qtype)
|
||||
msg, err := exchange(ctx, tt.server, tt.name, tt.qtype, time.Second)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
@@ -82,9 +82,9 @@ func TestSpecialDomainName(t *testing.T) {
|
||||
|
||||
server := "8.8.8.8:53"
|
||||
for _, tt := range specialDomainNameTests {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
msg, err := exchange(ctx, server, tt.name, tt.qtype)
|
||||
msg, err := exchange(ctx, server, tt.name, tt.qtype, 3*time.Second)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
continue
|
||||
@@ -112,10 +112,11 @@ func TestAvoidDNSName(t *testing.T) {
|
||||
{"foo.ONION", true},
|
||||
{"foo.ONION.", true},
|
||||
|
||||
{"foo.local.", true},
|
||||
{"foo.local", true},
|
||||
{"foo.LOCAL", true},
|
||||
{"foo.LOCAL.", true},
|
||||
// But do resolve *.local address; Issue 16739
|
||||
{"foo.local.", false},
|
||||
{"foo.local", false},
|
||||
{"foo.LOCAL", false},
|
||||
{"foo.LOCAL.", false},
|
||||
|
||||
{"", true}, // will be rejected earlier too
|
||||
|
||||
@@ -500,7 +501,7 @@ func TestErrorForOriginalNameWhenSearching(t *testing.T) {
|
||||
d := &fakeDNSDialer{}
|
||||
testHookDNSDialer = func() dnsDialer { return d }
|
||||
|
||||
d.rh = func(s string, q *dnsMsg) (*dnsMsg, error) {
|
||||
d.rh = func(s string, q *dnsMsg, _ time.Time) (*dnsMsg, error) {
|
||||
r := &dnsMsg{
|
||||
dnsMsgHdr: dnsMsgHdr{
|
||||
id: q.id,
|
||||
@@ -539,14 +540,15 @@ func TestIgnoreLameReferrals(t *testing.T) {
|
||||
}
|
||||
defer conf.teardown()
|
||||
|
||||
if err := conf.writeAndUpdate([]string{"nameserver 192.0.2.1", "nameserver 192.0.2.2"}); err != nil {
|
||||
if err := conf.writeAndUpdate([]string{"nameserver 192.0.2.1", // the one that will give a lame referral
|
||||
"nameserver 192.0.2.2"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
d := &fakeDNSDialer{}
|
||||
testHookDNSDialer = func() dnsDialer { return d }
|
||||
|
||||
d.rh = func(s string, q *dnsMsg) (*dnsMsg, error) {
|
||||
d.rh = func(s string, q *dnsMsg, _ time.Time) (*dnsMsg, error) {
|
||||
t.Log(s, q)
|
||||
r := &dnsMsg{
|
||||
dnsMsgHdr: dnsMsgHdr{
|
||||
@@ -633,28 +635,30 @@ func BenchmarkGoLookupIPWithBrokenNameServer(b *testing.B) {
|
||||
|
||||
type fakeDNSDialer struct {
|
||||
// reply handler
|
||||
rh func(s string, q *dnsMsg) (*dnsMsg, error)
|
||||
rh func(s string, q *dnsMsg, t time.Time) (*dnsMsg, error)
|
||||
}
|
||||
|
||||
func (f *fakeDNSDialer) dialDNS(_ context.Context, n, s string) (dnsConn, error) {
|
||||
return &fakeDNSConn{f.rh, s}, nil
|
||||
return &fakeDNSConn{f.rh, s, time.Time{}}, nil
|
||||
}
|
||||
|
||||
type fakeDNSConn struct {
|
||||
rh func(s string, q *dnsMsg) (*dnsMsg, error)
|
||||
rh func(s string, q *dnsMsg, t time.Time) (*dnsMsg, error)
|
||||
s string
|
||||
t time.Time
|
||||
}
|
||||
|
||||
func (f *fakeDNSConn) Close() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakeDNSConn) SetDeadline(time.Time) error {
|
||||
func (f *fakeDNSConn) SetDeadline(t time.Time) error {
|
||||
f.t = t
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *fakeDNSConn) dnsRoundTrip(q *dnsMsg) (*dnsMsg, error) {
|
||||
return f.rh(f.s, q)
|
||||
return f.rh(f.s, q, f.t)
|
||||
}
|
||||
|
||||
// UDP round-tripper algorithm should ignore invalid DNS responses (issue 13281).
|
||||
@@ -724,3 +728,72 @@ func TestIgnoreDNSForgeries(t *testing.T) {
|
||||
t.Errorf("got address %v, want %v", got, TestAddr)
|
||||
}
|
||||
}
|
||||
|
||||
// Issue 16865. If a name server times out, continue to the next.
|
||||
func TestRetryTimeout(t *testing.T) {
|
||||
origTestHookDNSDialer := testHookDNSDialer
|
||||
defer func() { testHookDNSDialer = origTestHookDNSDialer }()
|
||||
|
||||
conf, err := newResolvConfTest()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer conf.teardown()
|
||||
|
||||
if err := conf.writeAndUpdate([]string{"nameserver 192.0.2.1", // the one that will timeout
|
||||
"nameserver 192.0.2.2"}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
d := &fakeDNSDialer{}
|
||||
testHookDNSDialer = func() dnsDialer { return d }
|
||||
|
||||
var deadline0 time.Time
|
||||
|
||||
d.rh = func(s string, q *dnsMsg, deadline time.Time) (*dnsMsg, error) {
|
||||
t.Log(s, q, deadline)
|
||||
|
||||
if deadline.IsZero() {
|
||||
t.Error("zero deadline")
|
||||
}
|
||||
|
||||
if s == "192.0.2.1:53" {
|
||||
deadline0 = deadline
|
||||
time.Sleep(10 * time.Millisecond)
|
||||
return nil, errTimeout
|
||||
}
|
||||
|
||||
if deadline == deadline0 {
|
||||
t.Error("deadline didn't change")
|
||||
}
|
||||
|
||||
r := &dnsMsg{
|
||||
dnsMsgHdr: dnsMsgHdr{
|
||||
id: q.id,
|
||||
response: true,
|
||||
recursion_available: true,
|
||||
},
|
||||
question: q.question,
|
||||
answer: []dnsRR{
|
||||
&dnsRR_CNAME{
|
||||
Hdr: dnsRR_Header{
|
||||
Name: q.question[0].Name,
|
||||
Rrtype: dnsTypeCNAME,
|
||||
Class: dnsClassINET,
|
||||
},
|
||||
Cname: "golang.org",
|
||||
},
|
||||
},
|
||||
}
|
||||
return r, nil
|
||||
}
|
||||
|
||||
_, err = goLookupCNAME(context.Background(), "www.golang.org")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if deadline0.IsZero() {
|
||||
t.Error("deadline0 still zero", deadline0)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5460,12 +5460,15 @@ func http2bodyAndLength(req *Request) (body io.Reader, contentLen int64) {
|
||||
// We have a body but a zero content length. Test to see if
|
||||
// it's actually zero or just unset.
|
||||
var buf [1]byte
|
||||
n, rerr := io.ReadFull(body, buf[:])
|
||||
n, rerr := body.Read(buf[:])
|
||||
if rerr != nil && rerr != io.EOF {
|
||||
return http2errorReader{rerr}, -1
|
||||
}
|
||||
if n == 1 {
|
||||
|
||||
if rerr == io.EOF {
|
||||
return bytes.NewReader(buf[:]), 1
|
||||
}
|
||||
return io.MultiReader(bytes.NewReader(buf[:]), body), -1
|
||||
}
|
||||
|
||||
@@ -5714,8 +5717,13 @@ func (cs *http2clientStream) writeRequestBody(body io.Reader, bodyCloser io.Clos
|
||||
}
|
||||
}
|
||||
|
||||
if sentEnd {
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var trls []byte
|
||||
if !sentEnd && hasTrailers {
|
||||
if hasTrailers {
|
||||
cc.mu.Lock()
|
||||
defer cc.mu.Unlock()
|
||||
trls = cc.encodeTrailers(req)
|
||||
|
||||
@@ -498,8 +498,9 @@ func (t *Transport) CloseIdleConnections() {
|
||||
// CancelRequest cancels an in-flight request by closing its connection.
|
||||
// CancelRequest should only be called after RoundTrip has returned.
|
||||
//
|
||||
// Deprecated: Use Request.Cancel instead. CancelRequest cannot cancel
|
||||
// HTTP/2 requests.
|
||||
// Deprecated: Use Request.WithContext to create a request with a
|
||||
// cancelable context instead. CancelRequest cannot cancel HTTP/2
|
||||
// requests.
|
||||
func (t *Transport) CancelRequest(req *Request) {
|
||||
t.reqMu.Lock()
|
||||
cancel := t.reqCanceler[req]
|
||||
@@ -589,6 +590,7 @@ var (
|
||||
errReadLoopExiting = errors.New("http: persistConn.readLoop exiting")
|
||||
errServerClosedIdle = errors.New("http: server closed idle connection")
|
||||
errIdleConnTimeout = errors.New("http: idle connection timeout")
|
||||
errNotCachingH2Conn = errors.New("http: not caching alternate protocol's connections")
|
||||
)
|
||||
|
||||
// transportReadFromServerError is used by Transport.readLoop when the
|
||||
@@ -632,6 +634,9 @@ func (t *Transport) tryPutIdleConn(pconn *persistConn) error {
|
||||
if pconn.isBroken() {
|
||||
return errConnBroken
|
||||
}
|
||||
if pconn.alt != nil {
|
||||
return errNotCachingH2Conn
|
||||
}
|
||||
pconn.markReused()
|
||||
key := pconn.cacheKey
|
||||
|
||||
|
||||
@@ -3511,6 +3511,61 @@ func TestTransportIdleConnTimeout(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// Issue 16208: Go 1.7 crashed after Transport.IdleConnTimeout if an
|
||||
// HTTP/2 connection was established but but its caller no longer
|
||||
// wanted it. (Assuming the connection cache was enabled, which it is
|
||||
// by default)
|
||||
//
|
||||
// This test reproduced the crash by setting the IdleConnTimeout low
|
||||
// (to make the test reasonable) and then making a request which is
|
||||
// canceled by the DialTLS hook, which then also waits to return the
|
||||
// real connection until after the RoundTrip saw the error. Then we
|
||||
// know the successful tls.Dial from DialTLS will need to go into the
|
||||
// idle pool. Then we give it a of time to explode.
|
||||
func TestIdleConnH2Crash(t *testing.T) {
|
||||
cst := newClientServerTest(t, h2Mode, HandlerFunc(func(w ResponseWriter, r *Request) {
|
||||
// nothing
|
||||
}))
|
||||
defer cst.close()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
gotErr := make(chan bool, 1)
|
||||
|
||||
cst.tr.IdleConnTimeout = 5 * time.Millisecond
|
||||
cst.tr.DialTLS = func(network, addr string) (net.Conn, error) {
|
||||
cancel()
|
||||
<-gotErr
|
||||
c, err := tls.Dial(network, addr, &tls.Config{
|
||||
InsecureSkipVerify: true,
|
||||
NextProtos: []string{"h2"},
|
||||
})
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return nil, err
|
||||
}
|
||||
if cs := c.ConnectionState(); cs.NegotiatedProtocol != "h2" {
|
||||
t.Errorf("protocol = %q; want %q", cs.NegotiatedProtocol, "h2")
|
||||
c.Close()
|
||||
return nil, errors.New("bogus")
|
||||
}
|
||||
return c, nil
|
||||
}
|
||||
|
||||
req, _ := NewRequest("GET", cst.ts.URL, nil)
|
||||
req = req.WithContext(ctx)
|
||||
res, err := cst.c.Do(req)
|
||||
if err == nil {
|
||||
res.Body.Close()
|
||||
t.Fatal("unexpected success")
|
||||
}
|
||||
gotErr <- true
|
||||
|
||||
// Wait for the explosion.
|
||||
time.Sleep(cst.tr.IdleConnTimeout * 10)
|
||||
}
|
||||
|
||||
type funcConn struct {
|
||||
net.Conn
|
||||
read func([]byte) (int, error)
|
||||
|
||||
@@ -4,4 +4,7 @@
|
||||
|
||||
package filepath
|
||||
|
||||
var ToNorm = toNorm
|
||||
var (
|
||||
ToNorm = toNorm
|
||||
NormBase = normBase
|
||||
)
|
||||
|
||||
@@ -840,7 +840,7 @@ func TestEvalSymlinks(t *testing.T) {
|
||||
if p, err := filepath.EvalSymlinks(path); err != nil {
|
||||
t.Errorf("EvalSymlinks(%q) error: %v", d.path, err)
|
||||
} else if filepath.Clean(p) != filepath.Clean(dest) {
|
||||
t.Errorf("Clean(%q)=%q, want %q", path, p, dest)
|
||||
t.Errorf("EvalSymlinks(%q)=%q, want %q", path, p, dest)
|
||||
}
|
||||
|
||||
// test EvalSymlinks(".")
|
||||
@@ -872,6 +872,34 @@ func TestEvalSymlinks(t *testing.T) {
|
||||
t.Errorf(`EvalSymlinks(".") in %q directory returns %q, want "." or %q`, d.path, p, want)
|
||||
}()
|
||||
|
||||
// test EvalSymlinks(".."+path)
|
||||
func() {
|
||||
defer func() {
|
||||
err := os.Chdir(wd)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
err := os.Chdir(simpleJoin(tmpDir, "test"))
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
return
|
||||
}
|
||||
|
||||
path := simpleJoin("..", d.path)
|
||||
dest := simpleJoin("..", d.dest)
|
||||
if filepath.IsAbs(d.dest) || os.IsPathSeparator(d.dest[0]) {
|
||||
dest = d.dest
|
||||
}
|
||||
|
||||
if p, err := filepath.EvalSymlinks(path); err != nil {
|
||||
t.Errorf("EvalSymlinks(%q) error: %v", d.path, err)
|
||||
} else if filepath.Clean(p) != filepath.Clean(dest) {
|
||||
t.Errorf("EvalSymlinks(%q)=%q, want %q", path, p, dest)
|
||||
}
|
||||
}()
|
||||
|
||||
// test EvalSymlinks where parameter is relative path
|
||||
func() {
|
||||
defer func() {
|
||||
@@ -889,7 +917,7 @@ func TestEvalSymlinks(t *testing.T) {
|
||||
if p, err := filepath.EvalSymlinks(d.path); err != nil {
|
||||
t.Errorf("EvalSymlinks(%q) error: %v", d.path, err)
|
||||
} else if filepath.Clean(p) != filepath.Clean(d.dest) {
|
||||
t.Errorf("Clean(%q)=%q, want %q", d.path, p, d.dest)
|
||||
t.Errorf("EvalSymlinks(%q)=%q, want %q", d.path, p, d.dest)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
@@ -329,9 +329,106 @@ func TestToNorm(t *testing.T) {
|
||||
for _, test := range tests {
|
||||
got, err := filepath.ToNorm(test.arg, stubBase)
|
||||
if err != nil {
|
||||
t.Errorf("unexpected toNorm error, arg: %s, err: %v\n", test.arg, err)
|
||||
t.Errorf("toNorm(%s) failed: %v\n", test.arg, err)
|
||||
} else if got != test.want {
|
||||
t.Errorf("toNorm error, arg: %s, want: %s, got: %s\n", test.arg, test.want, got)
|
||||
t.Errorf("toNorm(%s) returns %s, but %s expected\n", test.arg, got, test.want)
|
||||
}
|
||||
}
|
||||
|
||||
testPath := `{{tmp}}\test\foo\bar`
|
||||
|
||||
testsDir := []struct {
|
||||
wd string
|
||||
arg string
|
||||
want string
|
||||
}{
|
||||
// test absolute paths
|
||||
{".", `{{tmp}}\test\foo\bar`, `{{tmp}}\test\foo\bar`},
|
||||
{".", `{{tmp}}\.\test/foo\bar`, `{{tmp}}\test\foo\bar`},
|
||||
{".", `{{tmp}}\test\..\test\foo\bar`, `{{tmp}}\test\foo\bar`},
|
||||
{".", `{{tmp}}\TEST\FOO\BAR`, `{{tmp}}\test\foo\bar`},
|
||||
|
||||
// test relative paths begin with drive letter
|
||||
{`{{tmp}}\test`, `{{tmpvol}}.`, `{{tmpvol}}.`},
|
||||
{`{{tmp}}\test`, `{{tmpvol}}..`, `{{tmpvol}}..`},
|
||||
{`{{tmp}}\test`, `{{tmpvol}}foo\bar`, `{{tmpvol}}foo\bar`},
|
||||
{`{{tmp}}\test`, `{{tmpvol}}.\foo\bar`, `{{tmpvol}}foo\bar`},
|
||||
{`{{tmp}}\test`, `{{tmpvol}}foo\..\foo\bar`, `{{tmpvol}}foo\bar`},
|
||||
{`{{tmp}}\test`, `{{tmpvol}}FOO\BAR`, `{{tmpvol}}foo\bar`},
|
||||
|
||||
// test relative paths begin with '\'
|
||||
{".", `{{tmpnovol}}\test\foo\bar`, `{{tmpnovol}}\test\foo\bar`},
|
||||
{".", `{{tmpnovol}}\.\test\foo\bar`, `{{tmpnovol}}\test\foo\bar`},
|
||||
{".", `{{tmpnovol}}\test\..\test\foo\bar`, `{{tmpnovol}}\test\foo\bar`},
|
||||
{".", `{{tmpnovol}}\TEST\FOO\BAR`, `{{tmpnovol}}\test\foo\bar`},
|
||||
|
||||
// test relative paths begin without '\'
|
||||
{`{{tmp}}\test`, ".", `.`},
|
||||
{`{{tmp}}\test`, "..", `..`},
|
||||
{`{{tmp}}\test`, `foo\bar`, `foo\bar`},
|
||||
{`{{tmp}}\test`, `.\foo\bar`, `foo\bar`},
|
||||
{`{{tmp}}\test`, `foo\..\foo\bar`, `foo\bar`},
|
||||
{`{{tmp}}\test`, `FOO\BAR`, `foo\bar`},
|
||||
}
|
||||
|
||||
cwd, err := os.Getwd()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
defer func() {
|
||||
err := os.Chdir(cwd)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}()
|
||||
|
||||
tmp, err := ioutil.TempDir("", "testToNorm")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmp)
|
||||
|
||||
// ioutil.TempDir might return "non-canonical" name.
|
||||
tmp, err = filepath.EvalSymlinks(tmp)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = os.MkdirAll(strings.Replace(testPath, "{{tmp}}", tmp, -1), 0777)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
tmpVol := filepath.VolumeName(tmp)
|
||||
tmpNoVol := tmp[len(tmpVol):]
|
||||
|
||||
for _, test := range testsDir {
|
||||
wd := strings.Replace(strings.Replace(strings.Replace(test.wd, "{{tmp}}", tmp, -1), "{{tmpvol}}", tmpVol, -1), "{{tmpnovol}}", tmpNoVol, -1)
|
||||
arg := strings.Replace(strings.Replace(strings.Replace(test.arg, "{{tmp}}", tmp, -1), "{{tmpvol}}", tmpVol, -1), "{{tmpnovol}}", tmpNoVol, -1)
|
||||
want := strings.Replace(strings.Replace(strings.Replace(test.want, "{{tmp}}", tmp, -1), "{{tmpvol}}", tmpVol, -1), "{{tmpnovol}}", tmpNoVol, -1)
|
||||
|
||||
if test.wd == "." {
|
||||
err := os.Chdir(cwd)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
|
||||
continue
|
||||
}
|
||||
} else {
|
||||
err := os.Chdir(wd)
|
||||
if err != nil {
|
||||
t.Error(err)
|
||||
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
got, err := filepath.ToNorm(arg, filepath.NormBase)
|
||||
if err != nil {
|
||||
t.Errorf("toNorm(%s) failed: %v (wd=%s)\n", arg, err, wd)
|
||||
} else if got != want {
|
||||
t.Errorf("toNorm(%s) returns %s, but %s expected (wd=%s)\n", arg, got, want, wd)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@ func normVolumeName(path string) string {
|
||||
return strings.ToUpper(volume)
|
||||
}
|
||||
|
||||
// normBase retruns the last element of path.
|
||||
// normBase returns the last element of path with correct case.
|
||||
func normBase(path string) (string, error) {
|
||||
p, err := syscall.UTF16PtrFromString(path)
|
||||
if err != nil {
|
||||
@@ -40,7 +40,24 @@ func normBase(path string) (string, error) {
|
||||
return syscall.UTF16ToString(data.FileName[:]), nil
|
||||
}
|
||||
|
||||
func toNorm(path string, base func(string) (string, error)) (string, error) {
|
||||
// baseIsDotDot returns whether the last element of path is "..".
|
||||
// The given path should be 'Clean'-ed in advance.
|
||||
func baseIsDotDot(path string) bool {
|
||||
i := strings.LastIndexByte(path, Separator)
|
||||
return path[i+1:] == ".."
|
||||
}
|
||||
|
||||
// toNorm returns the normalized path that is guranteed to be unique.
|
||||
// It should accept the following formats:
|
||||
// * UNC paths (e.g \\server\share\foo\bar)
|
||||
// * absolute paths (e.g C:\foo\bar)
|
||||
// * relative paths begin with drive letter (e.g C:foo\bar, C:..\foo\bar, C:.., C:.)
|
||||
// * relative paths begin with '\' (e.g \foo\bar)
|
||||
// * relative paths begin without '\' (e.g foo\bar, ..\foo\bar, .., .)
|
||||
// The returned normalized path will be in the same form (of 5 listed above) as the input path.
|
||||
// If two paths A and B are indicating the same file with the same format, toNorm(A) should be equal to toNorm(B).
|
||||
// The normBase parameter should be equal to the normBase func, except for in tests. See docs on the normBase func.
|
||||
func toNorm(path string, normBase func(string) (string, error)) (string, error) {
|
||||
if path == "" {
|
||||
return path, nil
|
||||
}
|
||||
@@ -58,7 +75,13 @@ func toNorm(path string, base func(string) (string, error)) (string, error) {
|
||||
var normPath string
|
||||
|
||||
for {
|
||||
name, err := base(volume + path)
|
||||
if baseIsDotDot(path) {
|
||||
normPath = path + `\` + normPath
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
name, err := normBase(volume + path)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
@@ -5720,6 +5720,8 @@ func TestTypeStrings(t *testing.T) {
|
||||
{TypeOf(new(XM)), "*reflect_test.XM"},
|
||||
{TypeOf(new(XM).String), "func() string"},
|
||||
{TypeOf(new(XM)).Method(0).Type, "func(*reflect_test.XM) string"},
|
||||
{ChanOf(3, TypeOf(XM{})), "chan reflect_test.XM"},
|
||||
{MapOf(TypeOf(int(0)), TypeOf(XM{})), "map[int]reflect_test.XM"},
|
||||
}
|
||||
|
||||
for i, test := range stringTests {
|
||||
|
||||
@@ -1848,6 +1848,7 @@ func ChanOf(dir ChanDir, t Type) Type {
|
||||
prototype := *(**chanType)(unsafe.Pointer(&ichan))
|
||||
ch := new(chanType)
|
||||
*ch = *prototype
|
||||
ch.tflag = 0
|
||||
ch.dir = uintptr(dir)
|
||||
ch.str = resolveReflectName(newName(s, "", "", false))
|
||||
ch.hash = fnv1(typ.hash, 'c', byte(dir))
|
||||
@@ -1892,6 +1893,7 @@ func MapOf(key, elem Type) Type {
|
||||
mt := new(mapType)
|
||||
*mt = **(**mapType)(unsafe.Pointer(&imap))
|
||||
mt.str = resolveReflectName(newName(s, "", "", false))
|
||||
mt.tflag = 0
|
||||
mt.hash = fnv1(etyp.hash, 'm', byte(ktyp.hash>>24), byte(ktyp.hash>>16), byte(ktyp.hash>>8), byte(ktyp.hash))
|
||||
mt.key = ktyp
|
||||
mt.elem = etyp
|
||||
|
||||
@@ -917,7 +917,9 @@ func scavengelist(list *mSpanList, now, limit uint64) uintptr {
|
||||
// more memory than we want.)
|
||||
start = (start + sys.PhysPageSize - 1) &^ (sys.PhysPageSize - 1)
|
||||
end &^= sys.PhysPageSize - 1
|
||||
if start == end {
|
||||
if end <= start {
|
||||
// start and end don't span a
|
||||
// whole physical page.
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,28 +7,45 @@
|
||||
package syscall_test
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"syscall"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const MNT_WAIT = 1
|
||||
const MNT_NOWAIT = 2
|
||||
|
||||
func TestGetfsstat(t *testing.T) {
|
||||
n, err := syscall.Getfsstat(nil, MNT_WAIT)
|
||||
const flags = MNT_NOWAIT // see Issue 16937
|
||||
n, err := syscall.Getfsstat(nil, flags)
|
||||
t.Logf("Getfsstat(nil, %d) = (%v, %v)", flags, n, err)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
data := make([]syscall.Statfs_t, n)
|
||||
n, err = syscall.Getfsstat(data, MNT_WAIT)
|
||||
n2, err := syscall.Getfsstat(data, flags)
|
||||
t.Logf("Getfsstat([]syscall.Statfs_t, %d) = (%v, %v)", flags, n2, err)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
empty := syscall.Statfs_t{}
|
||||
for _, stat := range data {
|
||||
if stat == empty {
|
||||
t.Fatal("an empty Statfs_t struct was returned")
|
||||
if n != n2 {
|
||||
t.Errorf("Getfsstat(nil) = %d, but subsequent Getfsstat(slice) = %d", n, n2)
|
||||
}
|
||||
for i, stat := range data {
|
||||
if stat == (syscall.Statfs_t{}) {
|
||||
t.Errorf("index %v is an empty Statfs_t struct", i)
|
||||
}
|
||||
}
|
||||
if t.Failed() {
|
||||
for i, stat := range data[:n2] {
|
||||
t.Logf("data[%v] = %+v", i, stat)
|
||||
}
|
||||
mount, err := exec.Command("mount").CombinedOutput()
|
||||
if err != nil {
|
||||
t.Logf("mount: %v\n%s", err, mount)
|
||||
} else {
|
||||
t.Logf("mount: %s", mount)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user