##// END OF EJS Templates
tests: disable test of buffer overflow in parsers.c if --pure...
Yuya Nishihara -
r25859:16195639 stable
parent child Browse files
Show More
@@ -1,378 +1,382 b''
1 1 import os, stat
2 2 import re
3 3 import socket
4 4 import sys
5 5 import tempfile
6 6
7 7 tempprefix = 'hg-hghave-'
8 8
9 9 checks = {
10 10 "true": (lambda: True, "yak shaving"),
11 11 "false": (lambda: False, "nail clipper"),
12 12 }
13 13
14 14 def check(name, desc):
15 15 def decorator(func):
16 16 checks[name] = (func, desc)
17 17 return func
18 18 return decorator
19 19
20 20 def matchoutput(cmd, regexp, ignorestatus=False):
21 21 """Return True if cmd executes successfully and its output
22 22 is matched by the supplied regular expression.
23 23 """
24 24 r = re.compile(regexp)
25 25 fh = os.popen(cmd)
26 26 s = fh.read()
27 27 try:
28 28 ret = fh.close()
29 29 except IOError:
30 30 # Happen in Windows test environment
31 31 ret = 1
32 32 return (ignorestatus or ret is None) and r.search(s)
33 33
34 34 @check("baz", "GNU Arch baz client")
35 35 def has_baz():
36 36 return matchoutput('baz --version 2>&1', r'baz Bazaar version')
37 37
38 38 @check("bzr", "Canonical's Bazaar client")
39 39 def has_bzr():
40 40 try:
41 41 import bzrlib
42 42 return bzrlib.__doc__ is not None
43 43 except ImportError:
44 44 return False
45 45
46 46 @check("bzr114", "Canonical's Bazaar client >= 1.14")
47 47 def has_bzr114():
48 48 try:
49 49 import bzrlib
50 50 return (bzrlib.__doc__ is not None
51 51 and bzrlib.version_info[:2] >= (1, 14))
52 52 except ImportError:
53 53 return False
54 54
55 55 @check("cvs", "cvs client/server")
56 56 def has_cvs():
57 57 re = r'Concurrent Versions System.*?server'
58 58 return matchoutput('cvs --version 2>&1', re) and not has_msys()
59 59
60 60 @check("cvs112", "cvs client/server >= 1.12")
61 61 def has_cvs112():
62 62 re = r'Concurrent Versions System \(CVS\) 1.12.*?server'
63 63 return matchoutput('cvs --version 2>&1', re) and not has_msys()
64 64
65 65 @check("darcs", "darcs client")
66 66 def has_darcs():
67 67 return matchoutput('darcs --version', r'2\.[2-9]', True)
68 68
69 69 @check("mtn", "monotone client (>= 1.0)")
70 70 def has_mtn():
71 71 return matchoutput('mtn --version', r'monotone', True) and not matchoutput(
72 72 'mtn --version', r'monotone 0\.', True)
73 73
74 74 @check("eol-in-paths", "end-of-lines in paths")
75 75 def has_eol_in_paths():
76 76 try:
77 77 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix, suffix='\n\r')
78 78 os.close(fd)
79 79 os.remove(path)
80 80 return True
81 81 except (IOError, OSError):
82 82 return False
83 83
84 84 @check("execbit", "executable bit")
85 85 def has_executablebit():
86 86 try:
87 87 EXECFLAGS = stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH
88 88 fh, fn = tempfile.mkstemp(dir='.', prefix=tempprefix)
89 89 try:
90 90 os.close(fh)
91 91 m = os.stat(fn).st_mode & 0o777
92 92 new_file_has_exec = m & EXECFLAGS
93 93 os.chmod(fn, m ^ EXECFLAGS)
94 94 exec_flags_cannot_flip = ((os.stat(fn).st_mode & 0o777) == m)
95 95 finally:
96 96 os.unlink(fn)
97 97 except (IOError, OSError):
98 98 # we don't care, the user probably won't be able to commit anyway
99 99 return False
100 100 return not (new_file_has_exec or exec_flags_cannot_flip)
101 101
102 102 @check("icasefs", "case insensitive file system")
103 103 def has_icasefs():
104 104 # Stolen from mercurial.util
105 105 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix)
106 106 os.close(fd)
107 107 try:
108 108 s1 = os.stat(path)
109 109 d, b = os.path.split(path)
110 110 p2 = os.path.join(d, b.upper())
111 111 if path == p2:
112 112 p2 = os.path.join(d, b.lower())
113 113 try:
114 114 s2 = os.stat(p2)
115 115 return s2 == s1
116 116 except OSError:
117 117 return False
118 118 finally:
119 119 os.remove(path)
120 120
121 121 @check("fifo", "named pipes")
122 122 def has_fifo():
123 123 if getattr(os, "mkfifo", None) is None:
124 124 return False
125 125 name = tempfile.mktemp(dir='.', prefix=tempprefix)
126 126 try:
127 127 os.mkfifo(name)
128 128 os.unlink(name)
129 129 return True
130 130 except OSError:
131 131 return False
132 132
133 133 @check("killdaemons", 'killdaemons.py support')
134 134 def has_killdaemons():
135 135 return True
136 136
137 137 @check("cacheable", "cacheable filesystem")
138 138 def has_cacheable_fs():
139 139 from mercurial import util
140 140
141 141 fd, path = tempfile.mkstemp(dir='.', prefix=tempprefix)
142 142 os.close(fd)
143 143 try:
144 144 return util.cachestat(path).cacheable()
145 145 finally:
146 146 os.remove(path)
147 147
148 148 @check("lsprof", "python lsprof module")
149 149 def has_lsprof():
150 150 try:
151 151 import _lsprof
152 152 _lsprof.Profiler # silence unused import warning
153 153 return True
154 154 except ImportError:
155 155 return False
156 156
157 157 @check("gettext", "GNU Gettext (msgfmt)")
158 158 def has_gettext():
159 159 return matchoutput('msgfmt --version', 'GNU gettext-tools')
160 160
161 161 @check("git", "git command line client")
162 162 def has_git():
163 163 return matchoutput('git --version 2>&1', r'^git version')
164 164
165 165 @check("docutils", "Docutils text processing library")
166 166 def has_docutils():
167 167 try:
168 168 from docutils.core import publish_cmdline
169 169 publish_cmdline # silence unused import
170 170 return True
171 171 except ImportError:
172 172 return False
173 173
174 174 def getsvnversion():
175 175 m = matchoutput('svn --version --quiet 2>&1', r'^(\d+)\.(\d+)')
176 176 if not m:
177 177 return (0, 0)
178 178 return (int(m.group(1)), int(m.group(2)))
179 179
180 180 @check("svn15", "subversion client and admin tools >= 1.5")
181 181 def has_svn15():
182 182 return getsvnversion() >= (1, 5)
183 183
184 184 @check("svn13", "subversion client and admin tools >= 1.3")
185 185 def has_svn13():
186 186 return getsvnversion() >= (1, 3)
187 187
188 188 @check("svn", "subversion client and admin tools")
189 189 def has_svn():
190 190 return matchoutput('svn --version 2>&1', r'^svn, version') and \
191 191 matchoutput('svnadmin --version 2>&1', r'^svnadmin, version')
192 192
193 193 @check("svn-bindings", "subversion python bindings")
194 194 def has_svn_bindings():
195 195 try:
196 196 import svn.core
197 197 version = svn.core.SVN_VER_MAJOR, svn.core.SVN_VER_MINOR
198 198 if version < (1, 4):
199 199 return False
200 200 return True
201 201 except ImportError:
202 202 return False
203 203
204 204 @check("p4", "Perforce server and client")
205 205 def has_p4():
206 206 return (matchoutput('p4 -V', r'Rev\. P4/') and
207 207 matchoutput('p4d -V', r'Rev\. P4D/'))
208 208
209 209 @check("symlink", "symbolic links")
210 210 def has_symlink():
211 211 if getattr(os, "symlink", None) is None:
212 212 return False
213 213 name = tempfile.mktemp(dir='.', prefix=tempprefix)
214 214 try:
215 215 os.symlink(".", name)
216 216 os.unlink(name)
217 217 return True
218 218 except (OSError, AttributeError):
219 219 return False
220 220
221 221 @check("hardlink", "hardlinks")
222 222 def has_hardlink():
223 223 from mercurial import util
224 224 fh, fn = tempfile.mkstemp(dir='.', prefix=tempprefix)
225 225 os.close(fh)
226 226 name = tempfile.mktemp(dir='.', prefix=tempprefix)
227 227 try:
228 228 util.oslink(fn, name)
229 229 os.unlink(name)
230 230 return True
231 231 except OSError:
232 232 return False
233 233 finally:
234 234 os.unlink(fn)
235 235
236 236 @check("tla", "GNU Arch tla client")
237 237 def has_tla():
238 238 return matchoutput('tla --version 2>&1', r'The GNU Arch Revision')
239 239
240 240 @check("gpg", "gpg client")
241 241 def has_gpg():
242 242 return matchoutput('gpg --version 2>&1', r'GnuPG')
243 243
244 244 @check("unix-permissions", "unix-style permissions")
245 245 def has_unix_permissions():
246 246 d = tempfile.mkdtemp(dir='.', prefix=tempprefix)
247 247 try:
248 248 fname = os.path.join(d, 'foo')
249 249 for umask in (0o77, 0o07, 0o22):
250 250 os.umask(umask)
251 251 f = open(fname, 'w')
252 252 f.close()
253 253 mode = os.stat(fname).st_mode
254 254 os.unlink(fname)
255 255 if mode & 0o777 != ~umask & 0o666:
256 256 return False
257 257 return True
258 258 finally:
259 259 os.rmdir(d)
260 260
261 261 @check("unix-socket", "AF_UNIX socket family")
262 262 def has_unix_socket():
263 263 return getattr(socket, 'AF_UNIX', None) is not None
264 264
265 265 @check("root", "root permissions")
266 266 def has_root():
267 267 return getattr(os, 'geteuid', None) and os.geteuid() == 0
268 268
269 269 @check("pyflakes", "Pyflakes python linter")
270 270 def has_pyflakes():
271 271 return matchoutput("sh -c \"echo 'import re' 2>&1 | pyflakes\"",
272 272 r"<stdin>:1: 're' imported but unused",
273 273 True)
274 274
275 275 @check("pygments", "Pygments source highlighting library")
276 276 def has_pygments():
277 277 try:
278 278 import pygments
279 279 pygments.highlight # silence unused import warning
280 280 return True
281 281 except ImportError:
282 282 return False
283 283
284 284 @check("json", "some json module available")
285 285 def has_json():
286 286 try:
287 287 import json
288 288 json.dumps
289 289 return True
290 290 except ImportError:
291 291 try:
292 292 import simplejson as json
293 293 json.dumps
294 294 return True
295 295 except ImportError:
296 296 pass
297 297 return False
298 298
299 299 @check("outer-repo", "outer repo")
300 300 def has_outer_repo():
301 301 # failing for other reasons than 'no repo' imply that there is a repo
302 302 return not matchoutput('hg root 2>&1',
303 303 r'abort: no repository found', True)
304 304
305 305 @check("ssl", ("(python >= 2.6 ssl module and python OpenSSL) "
306 306 "OR python >= 2.7.9 ssl"))
307 307 def has_ssl():
308 308 try:
309 309 import ssl
310 310 if getattr(ssl, 'create_default_context', False):
311 311 return True
312 312 import OpenSSL
313 313 OpenSSL.SSL.Context
314 314 return True
315 315 except ImportError:
316 316 return False
317 317
318 318 @check("sslcontext", "python >= 2.7.9 ssl")
319 319 def has_sslcontext():
320 320 try:
321 321 import ssl
322 322 ssl.SSLContext
323 323 return True
324 324 except (ImportError, AttributeError):
325 325 return False
326 326
327 327 @check("defaultcacerts", "can verify SSL certs by system's CA certs store")
328 328 def has_defaultcacerts():
329 329 from mercurial import sslutil
330 330 return sslutil._defaultcacerts() != '!'
331 331
332 332 @check("windows", "Windows")
333 333 def has_windows():
334 334 return os.name == 'nt'
335 335
336 336 @check("system-sh", "system() uses sh")
337 337 def has_system_sh():
338 338 return os.name != 'nt'
339 339
340 340 @check("serve", "platform and python can manage 'hg serve -d'")
341 341 def has_serve():
342 342 return os.name != 'nt' # gross approximation
343 343
344 344 @check("test-repo", "running tests from repository")
345 345 def has_test_repo():
346 346 t = os.environ["TESTDIR"]
347 347 return os.path.isdir(os.path.join(t, "..", ".hg"))
348 348
349 349 @check("tic", "terminfo compiler and curses module")
350 350 def has_tic():
351 351 try:
352 352 import curses
353 353 curses.COLOR_BLUE
354 354 return matchoutput('test -x "`which tic`"', '')
355 355 except ImportError:
356 356 return False
357 357
358 358 @check("msys", "Windows with MSYS")
359 359 def has_msys():
360 360 return os.getenv('MSYSTEM')
361 361
362 362 @check("aix", "AIX")
363 363 def has_aix():
364 364 return sys.platform.startswith("aix")
365 365
366 366 @check("osx", "OS X")
367 367 def has_osx():
368 368 return sys.platform == 'darwin'
369 369
370 370 @check("absimport", "absolute_import in __future__")
371 371 def has_absimport():
372 372 import __future__
373 373 from mercurial import util
374 374 return util.safehasattr(__future__, "absolute_import")
375 375
376 376 @check("py3k", "running with Python 3.x")
377 377 def has_py3k():
378 378 return 3 == sys.version_info[0]
379
380 @check("pure", "running with pure Python code")
381 def has_pure():
382 return os.environ.get("HGTEST_RUN_TESTS_PURE") == "--pure"
@@ -1,120 +1,124 b''
1 1 revlog.parseindex must be able to parse the index file even if
2 2 an index entry is split between two 64k blocks. The ideal test
3 3 would be to create an index file with inline data where
4 4 64k < size < 64k + 64 (64k is the size of the read buffer, 64 is
5 5 the size of an index entry) and with an index entry starting right
6 6 before the 64k block boundary, and try to read it.
7 7 We approximate that by reducing the read buffer to 1 byte.
8 8
9 9 $ hg init a
10 10 $ cd a
11 11 $ echo abc > foo
12 12 $ hg add foo
13 13 $ hg commit -m 'add foo'
14 14 $ echo >> foo
15 15 $ hg commit -m 'change foo'
16 16 $ hg log -r 0:
17 17 changeset: 0:7c31755bf9b5
18 18 user: test
19 19 date: Thu Jan 01 00:00:00 1970 +0000
20 20 summary: add foo
21 21
22 22 changeset: 1:26333235a41c
23 23 tag: tip
24 24 user: test
25 25 date: Thu Jan 01 00:00:00 1970 +0000
26 26 summary: change foo
27 27
28 28 $ cat >> test.py << EOF
29 29 > from mercurial import changelog, scmutil
30 30 > from mercurial.node import *
31 31 >
32 32 > class singlebyteread(object):
33 33 > def __init__(self, real):
34 34 > self.real = real
35 35 >
36 36 > def read(self, size=-1):
37 37 > if size == 65536:
38 38 > size = 1
39 39 > return self.real.read(size)
40 40 >
41 41 > def __getattr__(self, key):
42 42 > return getattr(self.real, key)
43 43 >
44 44 > def opener(*args):
45 45 > o = scmutil.opener(*args)
46 46 > def wrapper(*a):
47 47 > f = o(*a)
48 48 > return singlebyteread(f)
49 49 > return wrapper
50 50 >
51 51 > cl = changelog.changelog(opener('.hg/store'))
52 52 > print len(cl), 'revisions:'
53 53 > for r in cl:
54 54 > print short(cl.node(r))
55 55 > EOF
56 56 $ python test.py
57 57 2 revisions:
58 58 7c31755bf9b5
59 59 26333235a41c
60 60
61 61 $ cd ..
62 62
63 63 Test corrupted p1/p2 fields that could cause SEGV at parsers.c:
64 64
65 #if no-pure
66
65 67 $ mkdir invalidparent
66 68 $ cd invalidparent
67 69
68 70 $ hg clone --pull -q --config phases.publish=False ../a limit
69 71 $ hg clone --pull -q --config phases.publish=False ../a segv
70 72 $ rm -R limit/.hg/cache segv/.hg/cache
71 73
72 74 $ python <<EOF
73 75 > data = open("limit/.hg/store/00changelog.i", "rb").read()
74 76 > for n, p in [('limit', '\0\0\0\x02'), ('segv', '\0\x01\0\0')]:
75 77 > # corrupt p1 at rev0 and p2 at rev1
76 78 > d = data[:24] + p + data[28:127 + 28] + p + data[127 + 32:]
77 79 > open(n + "/.hg/store/00changelog.i", "wb").write(d)
78 80 > EOF
79 81
80 82 $ hg debugindex -f1 limit/.hg/store/00changelog.i
81 83 rev flag offset length size base link p1 p2 nodeid
82 84 0 0000 0 63 62 0 0 2 -1 7c31755bf9b5
83 85 1 0000 63 66 65 1 1 0 2 26333235a41c
84 86 $ hg debugindex -f1 segv/.hg/store/00changelog.i
85 87 rev flag offset length size base link p1 p2 nodeid
86 88 0 0000 0 63 62 0 0 65536 -1 7c31755bf9b5
87 89 1 0000 63 66 65 1 1 0 65536 26333235a41c
88 90
89 91 $ cat <<EOF > test.py
90 92 > import sys
91 93 > from mercurial import changelog, scmutil
92 94 > cl = changelog.changelog(scmutil.vfs(sys.argv[1]))
93 95 > n0, n1 = cl.node(0), cl.node(1)
94 96 > ops = [
95 97 > ('compute_phases_map_sets', lambda: cl.computephases([[0], []])),
96 98 > ('index_headrevs', lambda: cl.headrevs()),
97 99 > ('find_gca_candidates', lambda: cl.commonancestorsheads(n0, n1)),
98 100 > ('find_deepest', lambda: cl.ancestor(n0, n1)),
99 101 > ]
100 102 > for l, f in ops:
101 103 > print l + ':',
102 104 > try:
103 105 > f()
104 106 > print 'uncaught buffer overflow?'
105 107 > except ValueError, inst:
106 108 > print inst
107 109 > EOF
108 110
109 111 $ python test.py limit/.hg/store
110 112 compute_phases_map_sets: parent out of range
111 113 index_headrevs: parent out of range
112 114 find_gca_candidates: parent out of range
113 115 find_deepest: parent out of range
114 116 $ python test.py segv/.hg/store
115 117 compute_phases_map_sets: parent out of range
116 118 index_headrevs: parent out of range
117 119 find_gca_candidates: parent out of range
118 120 find_deepest: parent out of range
119 121
120 122 $ cd ..
123
124 #endif
General Comments 0
You need to be logged in to leave comments. Login now