Compare commits

...
202 Commits
Author SHA1 Message Date
Stanislav Malyshev d6d5fb0aa1 5.5.28 2015-08-04 23:58:00 -07:00
Stanislav Malyshev 2425f88afd Merge branch 'PHP-5.4' into PHP-5.5
* PHP-5.4:
  fix test
2015-08-04 16:45:32 -07:00
Stanislav Malyshev da5321013c fix test 2015-08-04 16:45:20 -07:00
Stanislav Malyshev f2f8ea9ac5 Merge branch 'PHP-5.4' into PHP-5.5
* PHP-5.4:
  __wakeup doesn't have to be final
2015-08-04 16:13:43 -07:00
Stanislav Malyshev f1acac154a __wakeup doesn't have to be final 2015-08-04 16:13:26 -07:00
Stanislav Malyshev d52c485717 update NEWS 2015-08-04 15:22:59 -07:00
Stanislav Malyshev 742c54aecf Merge branch 'PHP-5.4' into PHP-5.5
* PHP-5.4:
  fix test
  update NEWS
2015-08-04 14:46:30 -07:00
Stanislav Malyshev 0a21b5d970 fix test 2015-08-04 14:46:19 -07:00
Stanislav Malyshev ee61c7175f update NEWS 2015-08-04 14:37:28 -07:00
Stanislav Malyshev 69ed3969dd Merge branch 'PHP-5.4' into PHP-5.5
* PHP-5.4:
  Fix bug #70019 - limit extracted files to given directory
  Do not do convert_to_* on unserialize, it messes up references
  Fix #69793 - limit what we accept when unserializing exception
  Fixed bug #70169 (Use After Free Vulnerability in unserialize() with SplDoublyLinkedList)
  Fixed bug #70166 - Use After Free Vulnerability in unserialize() with SPLArrayObject
  ignore signatures for packages too
  Fix bug #70168 - Use After Free Vulnerability in unserialize() with SplObjectStorage
  Fixed bug #69892
  Fix bug #70014 - use RAND_bytes instead of deprecated RAND_pseudo_bytes
  Improved fix for Bug #69441
  Fix bug #70068 (Dangling pointer in the unserialization of ArrayObject items)
  Fix bug #70121 (unserialize() could lead to unexpected methods execution / NULL pointer deref)
  Fix bug #70081: check types for SOAP variables

Conflicts:
	.gitignore
	ext/date/php_date.c
	ext/spl/spl_array.c
	ext/spl/spl_observer.c
2015-08-04 14:10:57 -07:00
Stanislav Malyshev 51f9a00b47 Merge branch 'PHP-5.4' into PHP-5.4.44
* PHP-5.4:
  Fixed bug #69892
  Adjust Git-Rules
2015-08-04 14:04:24 -07:00
Stanislav Malyshev dda81f0505 Fix bug #70019 - limit extracted files to given directory 2015-08-04 14:02:31 -07:00
Stanislav Malyshev 0e09009753 Do not do convert_to_* on unserialize, it messes up references 2015-08-04 13:59:56 -07:00
Stanislav Malyshev 4d2278143a Fix #69793 - limit what we accept when unserializing exception 2015-08-01 22:02:26 -07:00
Stanislav Malyshev 863bf294fe Fixed bug #70169 (Use After Free Vulnerability in unserialize() with SplDoublyLinkedList) 2015-08-01 22:01:51 -07:00
Stanislav Malyshev 7381b6accc Fixed bug #70166 - Use After Free Vulnerability in unserialize() with SPLArrayObject 2015-08-01 22:01:40 -07:00
Stanislav Malyshev c7d3c027d5 ignore signatures for packages too 2015-08-01 22:01:32 -07:00
Stanislav Malyshev c2e197e4ef Fix bug #70168 - Use After Free Vulnerability in unserialize() with SplObjectStorage 2015-08-01 22:01:17 -07:00
Nikita Popov 7fc04937f5 Fixed bug #69892 2015-08-01 20:47:43 -07:00
Julien Pauli 66edc15875 Merge branch 'PHP-5.4' into PHP-5.5
* PHP-5.4:
  Adjust Git-Rules
  5.4.44 next

Conflicts:
	configure.in
	main/php_version.h
2015-07-29 10:04:08 +02:00
Julien Pauli 8f1baa6e1c Adjust Git-Rules 2015-07-29 10:02:39 +02:00
Anatol Belski ce5c4500cd Fixed bug #70002 TS issues with temporary dir handling 2015-07-28 17:41:38 +02:00
Stanislav Malyshev 16023f3e3b Fix bug #70014 - use RAND_bytes instead of deprecated RAND_pseudo_bytes 2015-07-26 17:43:16 -07:00
Stanislav Malyshev 7a4584d3f6 Improved fix for Bug #69441 2015-07-26 17:31:12 -07:00
Stanislav Malyshev b7fa67742c Fix bug #70068 (Dangling pointer in the unserialization of ArrayObject items) 2015-07-26 17:25:25 -07:00
Stanislav Malyshev e488690d95 Fix bug #70121 (unserialize() could lead to unexpected methods execution / NULL pointer deref) 2015-07-26 17:10:24 -07:00
Stanislav Malyshev c96d08b272 Fix bug #70081: check types for SOAP variables 2015-07-26 16:44:18 -07:00
Ferenc Kovacs daa0abaf77 make the travis irc notification a oneliner 2015-07-26 22:06:26 +02:00
Julien Pauli 34b624f122 5.5.27 release 2015-07-08 16:59:44 +02:00
Stanislav Malyshev 496f291f3d 5.4.44 next 2015-07-07 15:07:28 -07:00
Stanislav Malyshev b4b082e63e Merge branch 'PHP-5.4' into PHP-5.5
* PHP-5.4:
  Better fix for bug #69958
  update news
  Fix bug #69669 (mysqlnd is vulnerable to BACKRONYM)
  Fix bug #69923 - Buffer overflow and stack smashing error in phar_fix_filepath
  Fix bug #69958 - Segfault in Phar::convertToData on invalid file

Conflicts:
	ext/mysqlnd/mysqlnd.c
2015-07-07 10:09:34 -07:00
Stanislav Malyshev 545eddba93 Merge branch 'PHP-5.5' of git.php.net:php-src into PHP-5.5
* 'PHP-5.5' of git.php.net:php-src:
  add missing second argument for ucfirst to the proto
2015-07-07 10:08:37 -07:00
Stanislav Malyshev 885edfef0a Better fix for bug #69958 2015-07-07 09:38:31 -07:00
Stanislav Malyshev c8157619ef update news 2015-07-07 09:38:31 -07:00
Stanislav Malyshev 97aa752fee Fix bug #69669 (mysqlnd is vulnerable to BACKRONYM) 2015-07-07 09:38:31 -07:00
Stanislav Malyshev 6dedeb40db Fix bug #69923 - Buffer overflow and stack smashing error in phar_fix_filepath 2015-07-07 09:38:31 -07:00
Stanislav Malyshev bf58162ddf Fix bug #69958 - Segfault in Phar::convertToData on invalid file 2015-07-07 09:38:30 -07:00
Ferenc Kovacs b6f5cb11a4 Merge branch 'PHP-5.4' into PHP-5.5
* PHP-5.4:
  add missing second argument for ucfirst to the proto
2015-07-07 15:49:16 +02:00
Ferenc Kovacs 29533ae528 add missing second argument for ucfirst to the proto 2015-07-07 15:48:55 +02:00
Stanislav Malyshev ed84af4b88 Merge branch 'PHP-5.4' into PHP-5.5
* PHP-5.4:
  Better fix for bug #69958
2015-07-07 00:01:42 -07:00
Stanislav Malyshev eda31f57fb Better fix for bug #69958 2015-07-07 00:01:26 -07:00
Stanislav Malyshev 09de64a58d Merge branch 'PHP-5.4' into PHP-5.5
* PHP-5.4:
  Better fix for bug #69958
2015-07-06 23:03:05 -07:00
Stanislav Malyshev 61b0b80388 Better fix for bug #69958 2015-07-06 22:58:28 -07:00
Stanislav Malyshev 485b7c6981 Merge branch 'PHP-5.4' into PHP-5.5
* PHP-5.4:
  update news
2015-07-06 21:53:02 -07:00
Stanislav Malyshev c938d2f537 update news 2015-07-06 21:52:56 -07:00
Stanislav Malyshev 303d97feda Merge branch 'PHP-5.4' into PHP-5.5
* PHP-5.4:
  Fix bug #69669 (mysqlnd is vulnerable to BACKRONYM)
  Fix bug #69923 - Buffer overflow and stack smashing error in phar_fix_filepath
  Fix bug #69958 - Segfault in Phar::convertToData on invalid file

Conflicts:
	ext/mysqlnd/mysqlnd.c
2015-07-06 21:52:49 -07:00
Stanislav Malyshev 0d2f147d80 Fix bug #69669 (mysqlnd is vulnerable to BACKRONYM) 2015-07-06 21:50:01 -07:00
Stanislav Malyshev 3e88d610e5 Fix bug #69923 - Buffer overflow and stack smashing error in phar_fix_filepath 2015-07-04 23:47:48 -07:00
Stanislav Malyshev 452d30cf7d Fix bug #69958 - Segfault in Phar::convertToData on invalid file 2015-07-04 21:01:50 -07:00
Stanislav Malyshev 8f2e08239f Merge branch 'PHP-5.4' into PHP-5.5
* PHP-5.4:
  Move strlen() check to php_mail_detect_multiple_crlf()
  Fixed Bug #69874 : Can't set empty additional_headers for mail()
2015-06-28 20:23:00 -07:00
Stanislav Malyshev cd9c39d77c Merge branch 'pull-request/1350' into PHP-5.4
* pull-request/1350:
  Move strlen() check to php_mail_detect_multiple_crlf()
  Fixed Bug #69874 : Can't set empty additional_headers for mail()
2015-06-28 20:18:56 -07:00
Anatol Belski 80f9a9725c fix unknown size of void error 2015-06-25 19:12:26 +02:00
Julien Pauli 8e440dc1d7 5.5.28 now - Security Only 2015-06-24 10:41:06 +02:00
Christoph M. Becker cd068b1ed6 Made bug44295-win.phpt locale independent
Formerly it failed on non English installations.
2015-06-24 01:41:33 +02:00
Christoph M. Becker b03f743e7d updated NEWS 2015-06-24 00:31:07 +02:00
Christoph M. Becker 8da8dc04b6 Merge branch 'PHP-5.4' into PHP-5.5
* PHP-5.4:
  updated NEWS
  Fixed bug #69768 (escapeshell*() doesn't cater to !)
  bump API version to 6.8
2015-06-24 00:23:39 +02:00
Christoph M. Becker 921544cad9 updated NEWS 2015-06-24 00:20:32 +02:00
Christoph M. Becker a621781fdb Fixed bug #69768 (escapeshell*() doesn't cater to !)
When delayed variable substitution is enabled (can be set in the
Registry, for instance), !ENV! works similar to %ENV%, and so ! should
be escaped like %.
2015-06-24 00:15:55 +02:00
Christoph M. Becker 1cbcbcbc21 updated NEWS 2015-06-23 19:32:18 +02:00
Christoph M. Becker 23e25f3319 Fixed Bug #53823 (preg_replace: * qualifier on unicode replace garbles the string)
When advancing after empty matches, php_pcre_match_impl() as well as
php_pcre_replace_impl() always have to advance to the next code point when the
u modifier is given, instead of to the next byte.
2015-06-23 19:28:09 +02:00
Christoph M. Becker eef6b10b7c Moved NEWS entry for bug #69864 to proper category 2015-06-23 17:27:21 +02:00
Christoph M. Becker 75b2ce28aa updated NEWS 2015-06-23 13:02:08 +02:00
Christoph M. Becker a39beaa251 Fixed bug #69864 (Segfault in preg_replace_callback)
When preg_replace_callback() is used, cache entries which are in use must not
be removed. We ensure that by deploying a simple refcounting mechanism.
2015-06-23 13:00:17 +02:00
George Wang b0954ebb79 Merge branch 'PHP-5.5' of git.php.net:php-src into PHP-5.5 2015-06-22 23:39:53 -04:00
George Wang 8877feaeec bump API version to 6.8 2015-06-22 23:39:23 -04:00
George Wang fdb580a5ad bump API version to 6.8 2015-06-22 23:38:38 -04:00
Nikita Popov 5fe078abba Fixed bug #69892 2015-06-20 16:40:14 +02:00
Yasuo Ohgaki d263ecd864 Move strlen() check to php_mail_detect_multiple_crlf() 2015-06-19 15:17:56 +09:00
Yasuo Ohgaki dacea3f6fb Fixed Bug #69874 : Can't set empty additional_headers for mail() 2015-06-19 12:19:12 +09:00
Xinchen Hui 6a8db93115 Merge branch 'patch-3' of https://github.com/s0ph1e/php-src into PHP-5.5 2015-06-19 09:35:28 +08:00
Anatol Belski c0119ca7f3 updated NEWS 2015-06-18 22:02:37 +02:00
Christian Wenz a85156db7d fixes bug #69835: phpinfo() does not report many Windows SKUs 2015-06-18 22:01:20 +02:00
Sophia Nepochataya 1edb2e9a10 Remove excess variable in mail.c (5.5 branch) 2015-06-18 20:06:08 +03:00
Lior Kaplan ca33ae3eb2 Merge branch 'PHP-5.4' into PHP-5.5
* PHP-5.4:
  Fixed bug #69689 (Align PCRE_MINOR with current version)
2015-06-18 17:34:53 +03:00
Lior Kaplan cc7194dd10 Fixed bug #69689 (Align PCRE_MINOR with current version) 2015-06-18 17:30:21 +03:00
Lior Kaplan 991b2cc37b Add CVE to bugs #69545, #69646 and #69667 2015-06-18 16:51:20 +03:00
Lior Kaplan 189af22cf0 Merge branch 'PHP-5.4' into PHP-5.5
* PHP-5.4:
  Add CVE to bugs #69545, #69646 and #69667
2015-06-18 15:50:11 +03:00
Lior Kaplan 5f67caad54 Add CVE to bugs #69545, #69646 and #69667 2015-06-18 15:45:10 +03:00
Sara Golemon d241711f44 Fix buffer growth in sockets/conversion.c
memset() the *end* of the new buffer, not the beginning
Copy the pointer to the buffer, not its initial contents

Fixes bug 69619
2015-06-17 13:34:20 -07:00
Christoph M. Becker 61d58f2d9e updated NEWS 2015-06-17 02:17:40 +02:00
Christoph M. Becker 7469c7e7d0 Fixed bug #61221 - imagegammacorrect function loses alpha channel
When applying imagegammacorrect() the alpha channel is now fully retained, instead of being completely lost.
2015-06-17 02:15:59 +02:00
Derick Rethans 558342124e - Updated to version 2015.5 (2015e) 2015-06-15 10:41:29 +01:00
Derick Rethans 9026a66579 - Updated to version 2015.5 (2015e) 2015-06-15 10:28:22 +01:00
Derick Rethans 1d6f4891bd - Updated to version .-96 () 2015-06-15 10:17:23 +01:00
Matteo Beccati 9e4d720825 Fix copy/paste error in test 2015-06-13 08:07:49 +02:00
Stanislav Malyshev 7f4e1a0eef 5.4.43 next 2015-06-11 20:46:47 -07:00
Matteo Beccati b60efdce9f Fix bug #69344 (PDO PgSQL Incorrect binding numeric array with gaps) 2015-06-12 02:05:28 +02:00
Matteo Beccati 7c0b8f872e Fix bug #69362 (PDO-pgsql fails to connect if password contains a leading single quote) 2015-06-12 00:20:33 +02:00
Christoph M. Becker 44b09b80f2 Fixed bug #61574 - No MSI
The information regarding the Windows installers (.msi) in install.txt are
obsolete, so let's remove them.
2015-06-11 22:44:14 +02:00
Anatol Belski a037b6de21 rework that test to allow delta for rounding errors
If this workout doesn't make travis happy, the patch needs to be
reviewed as the leak might still persist.
2015-06-11 17:05:03 +02:00
Anatol Belski dcfd1153ec improve test 2015-06-11 15:36:02 +02:00
Anatol Belski e711325ca6 added test for bug #69646 2015-06-11 12:06:59 +02:00
Stanislav Malyshev cd927cca50 fix bad copypaste 2015-06-11 01:51:55 -07:00
Ferenc Kovacs 72b8a30c1a make it possible to set the re2c and yacc paths via environment variables for genfiles 2015-06-11 00:13:08 +02:00
Anatol Belski 9d5ab7e22f updated NEWS 2015-06-10 16:40:38 +02:00
Philip Hofstetter 9ba3a4c66a fix memory leak in pdo_pgsql closeCursor (bug 69752)
the parent PDO closeCursor method resets the pdo_stmt_t's executed flag
which is used by the postgres driver as a flag to check whether to
allocate memory for the column data or not.

This means that after the parent closeCursor() has been called, the
pdo_pgsql driver will allocate a new buffer for the columns, so the
existing buffer should be freed when the cursor is being closed.
2015-06-10 16:36:00 +02:00
Anatol Belski f14141aca2 regenerated the ini scanner
follow up fix for bug #69551
2015-06-10 13:15:01 +02:00
Anatol Belski 60e181c20a updated NEWS 2015-06-10 11:24:45 +02:00
Christian Wenz 0c8136654d Fix #69781: phpinfo() reports Professional Editions of Windows 7/8/8.1/10 as "Business" 2015-06-10 11:22:30 +02:00
Christian Wenz 82e5260104 Revert "Fix #69781: phpinfo() reports Professional Editions of Windows 7/8/8.1/10 as "Business""
This reverts commit 4a05c81b85336b76d05017cc86372fbd04871e3f.
2015-06-10 11:22:29 +02:00
Christian Wenz 741b949a6f Fix #69781: phpinfo() reports Professional Editions of Windows 7/8/8.1/10 as "Business" 2015-06-10 11:22:28 +02:00
Anatol Belski aef5a02ebb updated NEWS 2015-06-10 10:42:31 +02:00
Christoph M. Becker 36222eb4cc fixed bug, where a linebreak immediately after an opening quote of a value caused a segfault 2015-06-10 10:39:37 +02:00
Christoph M. Becker 2ba9681e8e made failing test more meaningful 2015-06-10 10:39:36 +02:00
Christoph M. Becker 616b932ab0 added failing test 2015-06-10 10:39:35 +02:00
Ferenc Kovacs 2b8ba3e9f8 add missing NEWS entries 2015-06-10 09:35:38 +02:00
Stanislav Malyshev c2d4704744 Merge branch 'PHP-5.4' into PHP-5.5
* PHP-5.4:
  add NEWS
2015-06-09 21:35:31 -07:00
Stanislav Malyshev f1ffb4b1ad add NEWS 2015-06-09 21:35:18 -07:00
Stanislav Malyshev e10af61862 Merge branch 'PHP-5.4' into PHP-5.5
* PHP-5.4:
  Fixed bug #68776
2015-06-09 21:33:38 -07:00
Yasuo Ohgaki 9d168b863e Fixed bug #68776 2015-06-09 21:32:54 -07:00
Stanislav Malyshev 6b53b7cd84 Merge branch 'PHp-5.4' into PHP-5.5
* PHp-5.4:
  fix test
  update NEWS
2015-06-09 17:12:11 -07:00
Stanislav Malyshev eee8b6c33f fix test 2015-06-09 17:11:33 -07:00
Stanislav Malyshev 539738c438 update NEWS 2015-06-09 16:23:05 -07:00
Stanislav Malyshev 4e2fb47092 Merge branch 'PHP-5.4' into PHP-5.5
* PHP-5.4:
  Fix bug #69646	OS command injection vulnerability in escapeshellarg
  Fix #69719 - more checks for nulls in paths
  fix test description
  Fixed Buf #68812 Unchecked return value.

Conflicts:
	ext/dom/document.c
	ext/gd/gd.c
2015-06-09 15:31:27 -07:00
Stanislav Malyshev 8036758491 Fix bug #69646 OS command injection vulnerability in escapeshellarg 2015-06-09 10:52:38 -07:00
Stanislav Malyshev f7d7befae8 Fix #69719 - more checks for nulls in paths 2015-06-09 10:52:38 -07:00
Julien Pauli 5f7c1917e3 5.5.27 now 2015-06-09 10:33:29 +02:00
Remi Collet 531c306fe6 fix test description 2015-06-09 09:18:54 +02:00
Remi Collet b347f2c47a fix test description 2015-06-09 09:12:59 +02:00
George Wang 6bb24823d0 Fixed Buf #68812 Unchecked return value. 2015-06-08 15:46:40 -04:00
George Wang 78d1228ef6 Fixed Buf #68812 Unchecked return value. 2015-06-08 15:38:59 -04:00
Lior Kaplan f5bf7b6b27 NEWS entry for: Upgrade bundled sqlite to 3.8.10.2
Includes fixes for CVE-2015-3414, CVE-2015-3415, CVE-2015-3416
2015-06-08 22:32:29 +03:00
Lior Kaplan eb7c33b204 Merge branch 'PHP-5.4' into PHP-5.5
* PHP-5.4:
  NEWS entry for: Upgrade bundled sqlite to 3.8.10.2
  Upgrade bundled sqlite to 3.8.10.2
  Add CVE used in PHP 5.4.39, 5.4.40, 5.4.41
  Add CVE to #68598
2015-06-08 22:29:35 +03:00
Lior Kaplan b5d1530e4f Upgrade bundled sqlite to 3.8.10.2
Includes fixes for CVE-2015-3414, CVE-2015-3415, CVE-2015-3416 done in 3.8.9
2015-06-08 22:29:10 +03:00
Lior Kaplan 33a9f01d36 NEWS entry for: Upgrade bundled sqlite to 3.8.10.2
Includes fixes for CVE-2015-3414, CVE-2015-3415, CVE-2015-3416
2015-06-08 22:23:22 +03:00
Lior Kaplan 7ced40e24e Upgrade bundled sqlite to 3.8.10.2
Includes fixes for CVE-2015-3414, CVE-2015-3415, CVE-2015-3416 done in 3.8.9
2015-06-08 22:17:06 +03:00
Lior Kaplan 4cc46b2a99 Add CVE used in PHP 5.4.39, 5.4.40, 5.4.41 2015-06-08 22:12:42 +03:00
Lior Kaplan 90a8ea9827 Add CVE to #68598 2015-06-08 22:04:42 +03:00
Anatol Belski 17f2d1e8a7 fixed test related to fix for bug #67805 2015-06-08 13:27:22 +02:00
Anatol Belski b754e3ec4b updated NEWS 2015-06-08 12:11:29 +02:00
Willian Gustavo Veiga b470d9a0d6 Fix bug #67805 - SplFileObject setMaxLineLength. 2015-06-08 12:08:05 +02:00
Anatol Belski 75c2aa9d3a updated NEWS for bug #69642 fix 2015-06-05 17:56:57 +02:00
Xinchen Hui 9a0bdd9069 Fixed invalid read druing apache reload 2015-06-04 21:08:36 +08:00
Stanislav Malyshev 1cbd25ca15 Fix bug #69737 - Segfault when SplMinHeap::compare produces fatal error 2015-06-01 22:07:16 -07:00
Dmitry Stogov 9031a902e3 Fixed bug #69732 (can induce segmentation fault with basic php code). 2015-06-01 11:40:14 +03:00
Stanislav Malyshev 8746163153 Merge branch 'PHP-5.4' into PHP-5.5
* PHP-5.4:
  improve fix for Bug #69545
2015-05-31 17:29:53 -07:00
Stanislav Malyshev 0765623d69 improve fix for Bug #69545 2015-05-31 17:29:00 -07:00
Anatol Belski f029a2856b fix phpize mode for manifest embedding 2015-05-31 23:01:21 +02:00
Christoph M. Becker b24fedbd24 split the original test to check behaviour diff on 32- and 64-bit 2015-05-31 21:28:44 +02:00
Christoph M. Becker e44b040faf recovered original meaning of SXE xpath test 2015-05-31 21:27:02 +02:00
Anatol Belski 1e9522021a backport the basic code to properly recognize win 8.1 and 10 2015-05-31 19:01:58 +02:00
Anatol Belski 31d59bf915 backport the manifest changes for makefile 2015-05-31 18:59:00 +02:00
Anatol Belski 50d4ea90b3 backport the manifest changes in js 2015-05-31 18:53:51 +02:00
Anatol Belski 7e731e4d9d add default manifest 2015-05-31 18:17:58 +02:00
Anatol Belski 05351f9ccb add test 2015-05-31 18:13:33 +02:00
Stanislav Malyshev 930fb8b1f3 Merge branch 'PHP-5.4' into PHP-5.5
* PHP-5.4:
  Update PCRE version (bug #69689)
  move test
  NEWS 5.4
  fix new test
  Fixed Bug #69667 segfault in php_pgsql_meta_data
  5.4.42 next

Conflicts:
	configure.in
	main/php_version.h
2015-05-30 21:18:28 -07:00
Stanislav Malyshev f38ca75a3c Update PCRE version (bug #69689) 2015-05-30 21:17:16 -07:00
Anatol Belski 5683b6fa39 Refactored the fix for bug #66084, by cmb@php.net 2015-05-29 21:16:56 +02:00
Kalle Sommer Nielsen c4e9651b58 Merge the fix for #69703 to 5.5 per request from Julien 2015-05-28 16:54:02 +02:00
Remi Collet 09b92a3a54 Relax a little this test, because random is not reliable
Usual values are 3500-3950, but >4000 can happen.
2015-05-28 10:35:19 +02:00
Ferenc Kovacs 00d8e26d71 empty commit to trigger a github mirror 2015-05-28 02:08:48 +02:00
Xinchen Hui 76a290d0be Fixed C89 2015-05-26 16:24:18 +08:00
Remi Collet 4cab20bbb4 NEWS 2015-05-24 09:39:03 +02:00
Remi Collet e807e07bfa Fixed Bug #69479 GD fails to build with newer libvpx
From upstream https://github.com/libgd/libgd/commit/d41eb72cd4545c394578332e5c102dee69e02ee8

Fix build with latest libvpx 1.4.0

These new constants exist at least since 1.0.0
Compatibility ones have been droped in 1.4.0
2015-05-24 09:37:12 +02:00
Anatol Belski d9c266f4c9 fix test
Sometimes the path is unixified, sometimes not, so better don't
care about the slash in this case.
2015-05-22 21:25:52 +02:00
Lior Kaplan 827d2c1415 Add entry for bug #69354, fixed in 5.5.25 2015-05-22 11:17:01 +03:00
Lior Kaplan 7ecab5d23f Add entry about PCRE upgrade (rev 95fa7279) 2015-05-22 11:02:01 +03:00
Lior Kaplan c9ac441fe8 Add CVE for bugs in 5.5.25 2015-05-22 10:58:28 +03:00
Remi Collet a7de68f98a Fixed bug #69680 (phar symlink in binary directory broken).
Relative symlink are better, as relative to link directory.
2015-05-21 14:05:15 +02:00
ponce c3d983f3af Make the phar symlink relative
or we got a symlink pointing to the build files
thanks also to remicollet
2015-05-21 14:03:18 +02:00
Anatol Belski c507c533bd updated NEWS 2015-05-21 09:47:02 +02:00
Christoph M. Becker 96629091a6 added missing GLOB_BRACE support check 2015-05-21 09:44:18 +02:00
Christoph M. Becker 6895ae4553 added SKIPIF section to test to make sure that GLOB_BRACE is supported 2015-05-21 09:44:17 +02:00
Christoph M. Becker 8c6e8e7870 fix #69628: complex GLOB_BRACE fails on Windows 2015-05-21 09:44:15 +02:00
Christoph M. Becker 90aee01c85 added PHPT to check for bug #69628 2015-05-21 09:44:14 +02:00
Anatol Belski 75286ece1a fix handling VAR vs VAR= in putenv
using _putenv_s eliminates behavior diff in TS/NTS
2015-05-21 08:19:54 +02:00
Remi Collet 88aab478bf move test 2015-05-20 14:03:41 +02:00
Remi Collet 3be4e5d71a move test 2015-05-20 14:02:13 +02:00
Remi Collet 593c4b9b00 NEWS 5.4 2015-05-20 08:47:04 +02:00
Remi Collet 3ee3066bd0 fix new test 2015-05-20 08:46:14 +02:00
Remi Collet f93d24aa67 Fixed Bug #69667 segfault in php_pgsql_meta_data
Incomplete fix for #68741
2015-05-20 08:46:01 +02:00
Remi Collet 716fe10d97 fix new test 2015-05-20 08:30:27 +02:00
Remi Collet 4bda39b81d NEWS 5.5 2015-05-20 08:11:14 +02:00
Remi Collet 2cc4e69cc6 Fixed Bug #69667 segfault in php_pgsql_meta_data
Incomplete fix for #68741
2015-05-20 08:08:41 +02:00
Remi Collet 58e5e006e5 fix test output (32bits) 2015-05-14 10:28:59 +02:00
Julien Pauli dcd230de11 Updated NEWS 2015-05-13 14:29:02 +02:00
Leigh f7952b90ca Close fd at the end, otherwise people complain
Even though it's closed when the process terminates!
2015-05-13 14:18:32 +02:00
Leigh c02c4aca00 Add file descriptor caching to mcrypt_create_iv()
This improves performance for applications that make repeated calls to
mcrypt_create_iv()
2015-05-13 14:18:32 +02:00
Julien Pauli 43c24da166 Updated NEWS 2015-05-13 13:05:46 +02:00
Stanislav Malyshev 4ceb7b46ad 5.4.42 next 2015-05-12 22:30:43 -07:00
Stanislav Malyshev c08f9c2c78 Merge branch 'PHP-5.4' into PHP-5.5
* PHP-5.4:
  fix format
  update NEWS
  Add test for bug #69522
  Update tests
  Fix bug #69522 - do not allow int overflow
  Forgot test file
  Fix bug #69403 and other int overflows
  Fixed bug #69418 - more s->p fixes for filenames
  Fixed bug #69364 - use smart_str to assemble strings
  Fix bug #69453 - don't try to cut empty string
  Fix bug #69545 - avoid overflow when reading list

Conflicts:
	ext/pcntl/pcntl.c
	ext/standard/basic_functions.c
	ext/standard/pack.c
	ext/standard/tests/dir/opendir_variation1-win32.phpt
2015-05-12 14:24:15 -07:00
Stanislav Malyshev f473ea5464 fix format 2015-05-12 12:37:28 -07:00
Stanislav Malyshev 2f83797a0c update NEWS 2015-05-12 12:17:54 -07:00
Julien Pauli c117548ea9 Fix for #66048 2015-05-12 16:12:29 +02:00
Stanislav Malyshev 9c0813fd48 Add test for bug #69522 2015-05-11 01:10:35 -07:00
Stanislav Malyshev 634aa0a2db Update tests 2015-05-11 00:12:39 -07:00
Stanislav Malyshev ba1d9cc4b7 Fix bug #69522 - do not allow int overflow 2015-05-10 23:06:08 -07:00
Stanislav Malyshev e2bbf0a2df Forgot test file 2015-05-10 02:24:29 -07:00
Stanislav Malyshev c591f022f8 Fix bug #69403 and other int overflows 2015-05-10 02:20:08 -07:00
Stanislav Malyshev be9b2a95ad Fixed bug #69418 - more s->p fixes for filenames 2015-05-10 02:09:38 -07:00
Stanislav Malyshev 4605d536d2 Fixed bug #69364 - use smart_str to assemble strings 2015-05-09 23:04:25 -07:00
Stanislav Malyshev 473ec539a1 Fix #48147 - implement manual handling of //IGNORE for broken libc
Conflicts:
	ext/iconv/iconv.c
2015-05-09 18:54:40 -07:00
Dmitry Stogov 8026001943 Fixed bug #69549 (Memory leak with opcache.optimization_level=0xFFFFFFFF) 2015-05-07 12:14:14 +03:00
Remi Collet 33e2aa452d Relax tests failing on i386 with new zic 2015-05-05 11:22:29 +02:00
Xinchen Hui cf3e976c3b Update version 2015-05-05 11:06:04 +08:00
Xinchen Hui 7af9ba23a7 Saving the latter checking in most cases 2015-05-04 19:21:54 +08:00
Xinchen Hui fff921d7a3 Update NEWS 2015-05-04 10:34:39 +08:00
John Boehr 9708378d13 Fix uninitialized value with extension traits 2015-05-04 10:33:39 +08:00
Stanislav Malyshev c27f012b7a Fix bug #69453 - don't try to cut empty string 2015-04-29 22:51:43 -07:00
Stanislav Malyshev ac28329354 Fix bug #69545 - avoid overflow when reading list 2015-04-29 22:50:18 -07:00
Stanislav Malyshev ce6db558f9 Merge branch 'PHP-5.4' into PHP-5.5
* PHP-5.4:
  Upgrade to PCRE 8.37 due to various bugfixes
2015-04-29 22:27:21 -07:00
Stanislav Malyshev 95fa727992 Upgrade to PCRE 8.37 due to various bugfixes 2015-04-29 22:27:07 -07:00
170 changed files with 55864 additions and 4050 deletions

No files matched your search

+3
View File
@@ -20,6 +20,9 @@
*.tar.gz
*.tar.bz2
*.tar.xz
*.tar.gz.asc
*.tar.bz2.asc
*.tar.xz.asc
.FBCIndex
.FBCLockFolder
.deps
+2
View File
@@ -4,6 +4,8 @@ notifications:
email:
on_failure: change
irc:
template:
- "%{repository}#%{build_number} (%{branch} - %{commit} : %{author}): %{message} - Change view : %{compare_url} - Build details : %{build_url}"
channels:
- "irc.efnet.org#php.pecl"
on_success: change
+156 -1
View File
@@ -1,12 +1,153 @@
PHP NEWS
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
?? ??? 2015, PHP 5.5.26
06 Aug 2015, PHP 5.5.28
- Core:
. Fixed bug #69793 (Remotely triggerable stack exhaustion via recursive
method calls). (Stas)
. Fixed bug #69892 (Different arrays compare indentical due to integer key
truncation). (Nikita)
. Fixed bug #70002 (TS issues with temporary dir handling). (Anatol)
. Fixed bug #70121 (unserialize() could lead to unexpected methods execution
/ NULL pointer deref). (Stas)
- OpenSSL:
. Fixed bug #70014 (openssl_random_pseudo_bytes() is not cryptographically
secure). (Stas)
- Phar:
. Improved fix for bug #69441. (Anatol Belski)
. Fixed bug #70019 (Files extracted from archive may be placed outside of
destination directory). (Anatol Belski)
- SOAP:
. Fixed bug #70081 (SoapClient info leak / null pointer dereference via
multiple type confusions). (Stas)
- SPL:
. Fixed bug #70068 (Dangling pointer in the unserialization of ArrayObject
items). (sean.heelan)
. Fixed bug #70166 (Use After Free Vulnerability in unserialize() with
SPLArrayObject). (taoguangchen at icloud dot com)
. Fixed bug #70168 (Use After Free Vulnerability in unserialize() with
SplObjectStorage). (taoguangchen at icloud dot com)
. Fixed bug #70169 (Use After Free Vulnerability in unserialize() with
SplDoublyLinkedList). (taoguangchen at icloud dot com)
9 Jul 2015, PHP 5.5.27
- Core:
. Fixed bug #69768 (escapeshell*() doesn't cater to !). (cmb)
. Fixed bug #69703 (Use __builtin_clzl on PowerPC).
(dja at axtens dot net, Kalle)
. Fixed bug #69732 (can induce segmentation fault with basic php code).
(Dmitry)
. Fixed bug #69642 (Windows 10 reported as Windows 8).
(Christian Wenz, Anatol Belski)
. Fixed bug #69551 (parse_ini_file() and parse_ini_string() segmentation
fault). (Christoph M. Becker)
. Fixed bug #69781 (phpinfo() reports Professional Editions of Windows
7/8/8.1/10 as "Business"). (Christian Wenz)
. Fixed bug #69835 (phpinfo() does not report many Windows SKUs).
(Christian Wenz)
. Fixed bug #69892 (Different arrays compare indentical due to integer key
truncation). (Nikita)
. Fixed bug #69874 (Can't set empty additional_headers for mail()), regression
from fix to bug #68776. (Yasuo)
- GD:
. Fixed bug #61221 (imagegammacorrect function loses alpha channel). (cmb)
- Mysqlnd:
. Fixed bug #69669 (mysqlnd is vulnerable to BACKRONYM) (CVE-2015-3152).
(Andrey)
- PCRE:
. Fixed Bug #53823 (preg_replace: * qualifier on unicode replace garbles the
string). (cmb)
. Fixed bug #69864 (Segfault in preg_replace_callback) (cmb, ab)
- PDO_pgsql:
. Fixed bug #69752 (PDOStatement::execute() leaks memory with DML
Statements when closeCuror() is u). (Philip Hofstetter)
. Fixed bug #69362 (PDO-pgsql fails to connect if password contains a
leading single quote). (Matteo)
. Fixed bug #69344 (PDO PgSQL Incorrect binding numeric array with gaps).
(Matteo)
- Phar:
. Fixed bug #69958 (Segfault in Phar::convertToData on invalid file). (Stas)
. Fixed bug #69923 (Buffer overflow and stack smashing error in
phar_fix_filepath). (Stas)
- SimpleXML:
. Refactored the fix for bug #66084 (simplexml_load_string() mangles empty
node name). (Christoph Michael Becker)
- SPL:
. Fixed bug #69737 (Segfault when SplMinHeap::compare produces fatal error).
(Stas)
. Fixed bug #67805 (SplFileObject setMaxLineLength). (Willian Gustavo Veiga).
11 Jun 2015, PHP 5.5.26
- Core:
. Fixed bug #69566 (Conditional jump or move depends on uninitialised value
in extension trait). (jbboehr at gmail dot com)
. Fixed bug #66048 (temp. directory is cached during multiple requests).
(Julien)
. Fixed bug #69628 (complex GLOB_BRACE fails on Windows).
(Christoph M. Becker)
. Improved fix for bug #69545 (Integer overflow in ftp_genlist() resulting in
heap overflow). (CVE-2015-4643) (Max Spelsberg)
. Fixed bug #69646 (OS command injection vulnerability in escapeshellarg).
(CVE-2015-4642) (Anatol Belski)
. Fixed bug #69719 (Incorrect handling of paths with NULs). (Stas)
- GD:
. Fixed bug #69479 (GD fails to build with newer libvpx). (Remi)
- Iconv:
. Fixed bug #48147 (iconv with //IGNORE cuts the string). (Stas)
- Litespeed SAPI:
. Fixed bug #68812 (Unchecked return value). (George Wang)
- Mail:
. Fixed bug #68776 (mail() does not have mail header injection prevention for
additional headers). (Yasuo)
- MCrypt:
. Added file descriptor caching to mcrypt_create_iv() (Leigh)
- PCRE:
. Upgraded pcrelib to 8.37. (CVE-2015-2325, CVE-2015-2326)
- Phar:
. Fixed bug #69680 (phar symlink in binary directory broken).
(Matteo Bernardini, Remi)
- Postgres:
. Fixed bug #69667 (segfault in php_pgsql_meta_data). (CVE-2015-4644) (Remi)
- Opcache
. Fixed bug #69549 (Memory leak with opcache.optimization_level=0xFFFFFFFF).
(Laruence, Dmitry)
- Sqlite3:
. Upgrade bundled sqlite to 3.8.10.2. (CVE-2015-3414, CVE-2015-3415,
CVE-2015-3416) (Kaplan)
14 May 2015, PHP 5.5.25
- Core:
. Fixed bug #69364 (PHP Multipart/form-data remote dos Vulnerability).
(CVE-2015-4024) (Stas)
. Fixed bug #69403 (str_repeat() sign mismatch based memory corruption).
(Stas)
. Fixed bug #69418 (CVE-2006-7243 fix regressions in 5.4+). (CVE-2015-4025)
(Stas)
. Fixed bug #69522 (heap buffer overflow in unpack()). (Stas)
. Fixed bug #69467 (Wrong checked for the interface by using Trait).
(Laruence)
. Fixed bug #69420 (Invalid read in zend_std_get_method). (Laruence)
@@ -20,7 +161,13 @@ PHP NEWS
. Fixed bug #69472 (php_sys_readlink ignores misc errors from
GetFinalPathNameByHandleA). (Jan Starke)
- FTP:
. Fixed bug #69545 (Integer overflow in ftp_genlist() resulting in heap
overflow). (CVE-2015-4022) (Stas)
- ODBC:
. Fixed bug #69354 (Incorrect use of SQLColAttributes with ODBC 3.0).
(Anatol)
. Fixed bug #69474 (ODBC: Query with same field name from two tables returns
incorrect result). (Anatol)
. Fixed bug #69381 (out of memory with sage odbc driver). (Frederic Marchall,
@@ -30,6 +177,14 @@ PHP NEWS
. Fixed bug #69402 (Reading empty SSL stream hangs until timeout).
(Daniel Lowrey)
- PCNTL:
. Fixed bug #68598 (pcntl_exec() should not allow null char). (CVE-2015-4026)
(Stas)
- Phar:
. Fixed bug #69453 (Memory Corruption in phar_parse_tarfile when entry
filename starts with null). (CVE-2015-4021) (Stas)
16 Apr 2015, PHP 5.5.24
- Apache2handler:
+6 -6
View File
@@ -12,7 +12,7 @@ Collaboration is a Good Thing(tm), and Git lets us do this. Thus, following
some basic rules with regards to Git usage will::
a. Make everybody happier, especially those responsible for maintaining
Git itself.
PHP itself.
b. Keep the changes consistently well documented and easily trackable.
@@ -48,11 +48,11 @@ Currently we have the following branches in use::
PHP-5.6 Is used to release the PHP 5.6.x series. This is a current
stable version and is open for bugfixes only.
PHP-5.5 Is used to release the PHP 5.5.x series. This is a current
stable version and is open for bugfixes only.
PHP-5.5 Is used to release the PHP 5.5.x series. This is an old
stable version and is open for security fixes only.
PHP-5.4 Is used to release the PHP 5.4.x series. This is a current
stable version and is open for bugfixes only.
PHP-5.4 Is used to release the PHP 5.4.x series. This is an old
stable version and is open for security fixes only.
PHP-5.3 This branch is closed.
@@ -67,7 +67,7 @@ Currently we have the following branches in use::
The next few rules are more of a technical nature::
1. All changes should first go to the lowest branch (i.e. 5.4) and then
1. All changes should first go to the lowest branch (i.e. 5.6) and then
get merged up to all other branches. If a change is not needed for
later branches (i.e. fixes for features which where dropped from later
branches) an empty merge should be done.
+16
View File
@@ -0,0 +1,16 @@
--TEST--
Bug #69551 - parse_ini_file() and parse_ini_string() segmentation fault
--FILE--
<?php
$ini = <<<INI
[Network.eth0]
SubnetMask = "
"
INI;
$settings = parse_ini_string($ini, false, INI_SCANNER_RAW);
var_dump($settings);
?>
--EXPECTF--
Warning: syntax error, unexpected '"' in Unknown on line %d
in %s on line %d
bool(false)
+30
View File
@@ -0,0 +1,30 @@
--TEST--
Bug #69732 (can induce segmentation fault with basic php code)
--FILE--
<?php
class wpq {
private $unreferenced;
public function __get($name) {
return $this->$name . "XXX";
}
}
function ret_assoc() {
$x = "XXX";
return array('foo' => 'bar', $x);
}
$wpq = new wpq;
$wpq->interesting =& ret_assoc();
$x = $wpq->interesting;
printf("%s\n", $x);
--EXPECTF--
Notice: Undefined property: wpq::$interesting in %sbug69732.php on line 6
Notice: Indirect modification of overloaded property wpq::$interesting has no effect in %sbug69732.php on line 16
Strict Standards: Only variables should be assigned by reference in %sbug69732.php on line 16
Notice: Undefined property: wpq::$interesting in %sbug69732.php on line 6
XXX
+10
View File
@@ -0,0 +1,10 @@
--TEST--
Bug #69892: Different arrays compare indentical due to integer key truncation
--SKIPIF--
<?php if (PHP_INT_SIZE != 8) die("skip this test is for 64bit platforms only"); ?>
--FILE--
<?php
var_dump([0 => 0] === [0x100000000 => 0]);
?>
--EXPECT--
bool(false)
+9
View File
@@ -0,0 +1,9 @@
--TEST--
Bug #70121 (unserialize() could lead to unexpected methods execution / NULL pointer deref)
--FILE--
<?php
unserialize('O:12:"DateInterval":1:{s:4:"days";O:9:"Exception":7:{s:10:"'."\0".'*'."\0".'message";s:1:"x";s:17:"'."\0".'Exception'."\0".'string";s:1:"A";s:7:"'."\0".'*'."\0".'code";i:0;s:7:"'."\0".'*'."\0".'file";s:1:"a";s:7:"'."\0".'*'."\0".'line";i:1337;s:16:"'."\0".'Exception'."\0".'trace";a:0:{}s:19:"'."\0".'Exception'."\0".'previous";O:8:"stdClass":0:{}}}');
?>
OK
--EXPECT--
OK
+13 -13
View File
@@ -678,7 +678,7 @@ static inline unsigned int zend_mm_high_bit(size_t _size)
__asm {
bsr eax, _size
}
#elif defined(__GNUC__) && (defined(__arm__) || defined(__aarch64__))
#elif defined(__GNUC__) && (defined(__arm__) || defined(__aarch64__) || defined(__powerpc__))
return (8 * SIZEOF_SIZE_T - 1) - __builtin_clzl(_size);
#else
unsigned int n = 0;
@@ -706,7 +706,7 @@ static inline unsigned int zend_mm_low_bit(size_t _size)
__asm {
bsf eax, _size
}
#elif defined(__GNUC__) && (defined(__arm__) || defined(__aarch64__))
#elif defined(__GNUC__) && (defined(__arm__) || defined(__aarch64__) || defined(__powerpc__))
return __builtin_ctzl(_size);
#else
static const int offset[16] = {4,0,1,0,2,0,1,0,3,0,1,0,2,0,1,0};
@@ -984,7 +984,7 @@ static void zend_mm_random(unsigned char *buf, size_t size) /* {{{ */
int has_context = 0;
if (!CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, 0)) {
/* Could mean that the key container does not exist, let try
/* Could mean that the key container does not exist, let try
again by asking for a new one */
if (GetLastError() == NTE_BAD_KEYSET) {
if (CryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET)) {
@@ -1348,7 +1348,7 @@ static int zend_mm_check_ptr(zend_mm_heap *heap, void *ptr, int silent ZEND_FILE
}
if (!silent) {
TSRMLS_FETCH();
zend_message_dispatcher(ZMSG_LOG_SCRIPT_NAME, NULL TSRMLS_CC);
zend_debug_alloc_output("---------------------------------------\n");
zend_debug_alloc_output("%s(%d) : Block "PTR_FMT" status:\n" ZEND_FILE_LINE_RELAY_CC, ptr);
@@ -2175,7 +2175,7 @@ static void *_zend_mm_realloc_int(zend_mm_heap *heap, void *p, size_t size ZEND_
#if ZEND_MM_CACHE
if (ZEND_MM_SMALL_SIZE(true_size)) {
size_t index = ZEND_MM_BUCKET_INDEX(true_size);
if (heap->cache[index] != NULL) {
zend_mm_free_block *best_fit;
zend_mm_free_block **cache;
@@ -2188,7 +2188,7 @@ static void *_zend_mm_realloc_int(zend_mm_heap *heap, void *p, size_t size ZEND_
heap->cache[index] = best_fit->prev_free_block;
ZEND_MM_CHECK_MAGIC(best_fit, MEM_BLOCK_CACHED);
ZEND_MM_SET_DEBUG_INFO(best_fit, size, 1, 0);
ptr = ZEND_MM_DATA_OF(best_fit);
#if ZEND_DEBUG || ZEND_MM_HEAP_PROTECTION
@@ -2470,7 +2470,7 @@ static inline size_t safe_address(size_t nmemb, size_t size, size_t offset)
: "%0"(res),
"rm"(size),
"rm"(offset));
if (UNEXPECTED(overflow)) {
zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", nmemb, size, offset);
return 0;
@@ -2619,7 +2619,7 @@ ZEND_API void *_ecalloc(size_t nmemb, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LI
ZEND_API char *_estrdup(const char *s ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
{
int length;
size_t length;
char *p;
#ifdef ZEND_SIGNALS
TSRMLS_FETCH();
@@ -2627,13 +2627,13 @@ ZEND_API char *_estrdup(const char *s ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
HANDLE_BLOCK_INTERRUPTIONS();
length = strlen(s)+1;
p = (char *) _emalloc(length ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
length = strlen(s);
p = (char *) _emalloc(safe_address(length, 1, 1) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
if (UNEXPECTED(p == NULL)) {
HANDLE_UNBLOCK_INTERRUPTIONS();
return p;
}
memcpy(p, s, length);
memcpy(p, s, length+1);
HANDLE_UNBLOCK_INTERRUPTIONS();
return p;
}
@@ -2647,7 +2647,7 @@ ZEND_API char *_estrndup(const char *s, uint length ZEND_FILE_LINE_DC ZEND_FILE_
HANDLE_BLOCK_INTERRUPTIONS();
p = (char *) _emalloc(length+1 ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
p = (char *) _emalloc(safe_address(length, 1, 1) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
if (UNEXPECTED(p == NULL)) {
HANDLE_UNBLOCK_INTERRUPTIONS();
return p;
@@ -2668,7 +2668,7 @@ ZEND_API char *zend_strndup(const char *s, uint length)
HANDLE_BLOCK_INTERRUPTIONS();
p = (char *) malloc(length+1);
p = (char *) malloc(safe_address(length, 1, 1));
if (UNEXPECTED(p == NULL)) {
HANDLE_UNBLOCK_INTERRUPTIONS();
return p;
+1 -1
View File
@@ -3962,7 +3962,7 @@ static int zend_fixup_trait_method(zend_function *fn, zend_class_entry *ce TSRML
if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) {
ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
}
if (fn->op_array.static_variables) {
if (fn->type == ZEND_USER_FUNCTION && fn->op_array.static_variables) {
ce->ce_flags |= ZEND_HAS_STATIC_IN_METHODS;
}
}
+37 -8
View File
@@ -41,7 +41,7 @@ void zend_exception_set_previous(zval *exception, zval *add_previous TSRMLS_DC)
if (exception == add_previous || !add_previous || !exception) {
return;
}
if (Z_TYPE_P(add_previous) != IS_OBJECT && !instanceof_function(Z_OBJCE_P(add_previous), default_exception_ce TSRMLS_CC)) {
if (Z_TYPE_P(add_previous) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(add_previous), default_exception_ce TSRMLS_CC)) {
zend_error(E_ERROR, "Cannot set non exception as previous exception");
return;
}
@@ -218,6 +218,33 @@ ZEND_METHOD(exception, __construct)
}
/* }}} */
/* {{{ proto Exception::__wakeup()
Exception unserialize checks */
#define CHECK_EXC_TYPE(name, type) \
value = zend_read_property(default_exception_ce, object, name, sizeof(name)-1, 0 TSRMLS_CC); \
if(value && Z_TYPE_P(value) != type) { \
zval *tmp; \
MAKE_STD_ZVAL(tmp); \
ZVAL_STRINGL(tmp, name, sizeof(name)-1, 1); \
Z_OBJ_HANDLER_P(object, unset_property)(object, tmp, 0 TSRMLS_CC); \
zval_ptr_dtor(&tmp); \
}
ZEND_METHOD(exception, __wakeup)
{
zval *value;
zval *object = getThis();
HashTable *intern_ht = zend_std_get_properties(getThis() TSRMLS_CC);
CHECK_EXC_TYPE("message", IS_STRING);
CHECK_EXC_TYPE("string", IS_STRING);
CHECK_EXC_TYPE("code", IS_LONG);
CHECK_EXC_TYPE("file", IS_STRING);
CHECK_EXC_TYPE("line", IS_LONG);
CHECK_EXC_TYPE("trace", IS_ARRAY);
CHECK_EXC_TYPE("previous", IS_OBJECT);
}
/* }}} */
/* {{{ proto ErrorException::__construct(string message, int code, int severity [, string filename [, int lineno [, Exception previous]]])
ErrorException constructor */
ZEND_METHOD(error_exception, __construct)
@@ -586,7 +613,7 @@ ZEND_METHOD(exception, getTraceAsString)
int res_len = 0, *len = &res_len, num = 0;
DEFAULT_0_PARAMS;
trace = zend_read_property(default_exception_ce, getThis(), "trace", sizeof("trace")-1, 1 TSRMLS_CC);
if (Z_TYPE_P(trace) != IS_ARRAY) {
RETURN_FALSE;
@@ -602,8 +629,8 @@ ZEND_METHOD(exception, getTraceAsString)
TRACE_APPEND_STRL(s_tmp, strlen(s_tmp));
efree(s_tmp);
res[res_len] = '\0';
RETURN_STRINGL(res, res_len, 0);
res[res_len] = '\0';
RETURN_STRINGL(res, res_len, 0);
}
/* }}} */
@@ -640,15 +667,15 @@ ZEND_METHOD(exception, __toString)
int len = 0;
zend_fcall_info fci;
zval fname;
DEFAULT_0_PARAMS;
str = estrndup("", 0);
exception = getThis();
ZVAL_STRINGL(&fname, "gettraceasstring", sizeof("gettraceasstring")-1, 1);
while (exception && Z_TYPE_P(exception) == IS_OBJECT) {
while (exception && Z_TYPE_P(exception) == IS_OBJECT && instanceof_function(Z_OBJCE_P(exception), default_exception_ce TSRMLS_CC)) {
prev_str = str;
_default_exception_get_entry(exception, "message", sizeof("message")-1, &message TSRMLS_CC);
_default_exception_get_entry(exception, "file", sizeof("file")-1, &file TSRMLS_CC);
@@ -658,6 +685,7 @@ ZEND_METHOD(exception, __toString)
convert_to_string(&file);
convert_to_long(&line);
trace = NULL;
fci.size = sizeof(fci);
fci.function_table = &Z_OBJCE_P(exception)->function_table;
fci.function_name = &fname;
@@ -670,7 +698,7 @@ ZEND_METHOD(exception, __toString)
zend_call_function(&fci, NULL TSRMLS_CC);
if (Z_TYPE_P(trace) != IS_STRING) {
if (trace && Z_TYPE_P(trace) != IS_STRING) {
zval_ptr_dtor(&trace);
trace = NULL;
}
@@ -727,6 +755,7 @@ ZEND_END_ARG_INFO()
const static zend_function_entry default_exception_functions[] = {
ZEND_ME(exception, __clone, NULL, ZEND_ACC_PRIVATE|ZEND_ACC_FINAL)
ZEND_ME(exception, __construct, arginfo_exception___construct, ZEND_ACC_PUBLIC)
ZEND_ME(exception, __wakeup, NULL, ZEND_ACC_PUBLIC)
ZEND_ME(exception, getMessage, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
ZEND_ME(exception, getCode, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
ZEND_ME(exception, getFile, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
+2 -3
View File
@@ -1534,11 +1534,10 @@ ZEND_API int zend_hash_compare(HashTable *ht1, HashTable *ht2, compare_func_t co
}
if (ordered) {
if (p1->nKeyLength==0 && p2->nKeyLength==0) { /* numeric indices */
result = p1->h - p2->h;
if (result!=0) {
if (p1->h != p2->h) {
HASH_UNPROTECT_RECURSION(ht1);
HASH_UNPROTECT_RECURSION(ht2);
return result;
return p1->h > p2->h ? 1 : -1;
}
} else { /* string indices */
result = p1->nKeyLength - p2->nKeyLength;
+1 -1
View File
@@ -1926,7 +1926,7 @@ end_raw_value_chars:
}
/* Eat leading and trailing double quotes */
if (yytext[0] == '"' && yytext[yyleng - 1] == '"') {
if (yyleng > 1 && yytext[0] == '"' && yytext[yyleng - 1] == '"') {
SCNG(yy_text)++;
yyleng = yyleng - 2;
} else if (sc) {
+1 -1
View File
@@ -472,7 +472,7 @@ end_raw_value_chars:
}
/* Eat leading and trailing double quotes */
if (yytext[0] == '"' && yytext[yyleng - 1] == '"') {
if (yyleng > 1 && yytext[0] == '"' && yytext[yyleng - 1] == '"') {
SCNG(yy_text)++;
yyleng = yyleng - 2;
} else if (sc) {
+7 -2
View File
@@ -1319,14 +1319,19 @@ ZEND_API int concat_function(zval *result, zval *op1, zval *op2 TSRMLS_DC) /* {{
zend_error(E_ERROR, "String size overflow");
}
Z_STRVAL_P(result) = erealloc(Z_STRVAL_P(result), res_len+1);
Z_STRVAL_P(result) = safe_erealloc(Z_STRVAL_P(result), res_len, 1, 1);
memcpy(Z_STRVAL_P(result)+Z_STRLEN_P(result), Z_STRVAL_P(op2), Z_STRLEN_P(op2));
Z_STRVAL_P(result)[res_len]=0;
Z_STRLEN_P(result) = res_len;
} else {
int length = Z_STRLEN_P(op1) + Z_STRLEN_P(op2);
char *buf = (char *) emalloc(length + 1);
char *buf;
if (Z_STRLEN_P(op1) < 0 || Z_STRLEN_P(op2) < 0 || (int) (Z_STRLEN_P(op1) + Z_STRLEN_P(op2)) < 0) {
zend_error(E_ERROR, "String size overflow");
}
buf = (char *) safe_emalloc(length, 1, 1);
memcpy(buf, Z_STRVAL_P(op1), Z_STRLEN_P(op1));
memcpy(buf + Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2));
+6 -5
View File
@@ -1762,7 +1762,9 @@ ZEND_VM_HANDLER(38, ZEND_ASSIGN, VAR|CV, CONST|TMP|VAR|CV)
}
}
FREE_OP1_VAR_PTR();
if (OP1_TYPE == IS_VAR && OP1_FREE) {
zval_ptr_dtor(&value);
}
/* zend_assign_to_variable() always takes care of op2, never free it! */
FREE_OP2_IF_VAR();
@@ -5191,7 +5193,6 @@ ZEND_VM_HANDLER(153, ZEND_DECLARE_LAMBDA_FUNCTION, CONST, UNUSED)
{
USE_OPLINE
zend_function *op_array;
int closure_is_static, closure_is_being_defined_inside_static_context;
SAVE_OPLINE();
@@ -5200,9 +5201,9 @@ ZEND_VM_HANDLER(153, ZEND_DECLARE_LAMBDA_FUNCTION, CONST, UNUSED)
zend_error_noreturn(E_ERROR, "Base lambda function for closure not found");
}
closure_is_static = op_array->common.fn_flags & ZEND_ACC_STATIC;
closure_is_being_defined_inside_static_context = EX(prev_execute_data) && EX(prev_execute_data)->function_state.function->common.fn_flags & ZEND_ACC_STATIC;
if (closure_is_static || closure_is_being_defined_inside_static_context) {
if (UNEXPECTED((op_array->common.fn_flags & ZEND_ACC_STATIC) ||
(EX(prev_execute_data) &&
EX(prev_execute_data)->function_state.function->common.fn_flags & ZEND_ACC_STATIC))) {
zend_create_closure(&EX_T(opline->result.var).tmp_var, (zend_function *) op_array, EG(called_scope), NULL TSRMLS_CC);
} else {
zend_create_closure(&EX_T(opline->result.var).tmp_var, (zend_function *) op_array, EG(scope), EG(This) TSRMLS_CC);
+31 -8
View File
@@ -6494,7 +6494,6 @@ static int ZEND_FASTCALL ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_CONST_UNUSED_HANDLER
{
USE_OPLINE
zend_function *op_array;
int closure_is_static, closure_is_being_defined_inside_static_context;
SAVE_OPLINE();
@@ -6503,9 +6502,9 @@ static int ZEND_FASTCALL ZEND_DECLARE_LAMBDA_FUNCTION_SPEC_CONST_UNUSED_HANDLER
zend_error_noreturn(E_ERROR, "Base lambda function for closure not found");
}
closure_is_static = op_array->common.fn_flags & ZEND_ACC_STATIC;
closure_is_being_defined_inside_static_context = EX(prev_execute_data) && EX(prev_execute_data)->function_state.function->common.fn_flags & ZEND_ACC_STATIC;
if (closure_is_static || closure_is_being_defined_inside_static_context) {
if (UNEXPECTED((op_array->common.fn_flags & ZEND_ACC_STATIC) ||
(EX(prev_execute_data) &&
EX(prev_execute_data)->function_state.function->common.fn_flags & ZEND_ACC_STATIC))) {
zend_create_closure(&EX_T(opline->result.var).tmp_var, (zend_function *) op_array, EG(called_scope), NULL TSRMLS_CC);
} else {
zend_create_closure(&EX_T(opline->result.var).tmp_var, (zend_function *) op_array, EG(scope), EG(This) TSRMLS_CC);
@@ -15308,7 +15307,9 @@ static int ZEND_FASTCALL ZEND_ASSIGN_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER
}
}
if (free_op1.var) {zval_ptr_dtor(&free_op1.var);};
if (IS_VAR == IS_VAR && (free_op1.var != NULL)) {
zval_ptr_dtor(&value);
}
/* zend_assign_to_variable() always takes care of op2, never free it! */
@@ -17663,7 +17664,9 @@ static int ZEND_FASTCALL ZEND_ASSIGN_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_A
}
}
if (free_op1.var) {zval_ptr_dtor(&free_op1.var);};
if (IS_VAR == IS_VAR && (free_op1.var != NULL)) {
zval_ptr_dtor(&value);
}
/* zend_assign_to_variable() always takes care of op2, never free it! */
@@ -19924,7 +19927,9 @@ static int ZEND_FASTCALL ZEND_ASSIGN_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_A
}
}
if (free_op1.var) {zval_ptr_dtor(&free_op1.var);};
if (IS_VAR == IS_VAR && (free_op1.var != NULL)) {
zval_ptr_dtor(&value);
}
/* zend_assign_to_variable() always takes care of op2, never free it! */
if (free_op2.var) {zval_ptr_dtor(&free_op2.var);};
@@ -23396,7 +23401,9 @@ static int ZEND_FASTCALL ZEND_ASSIGN_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_AR
}
}
if (free_op1.var) {zval_ptr_dtor(&free_op1.var);};
if (IS_VAR == IS_VAR && (free_op1.var != NULL)) {
zval_ptr_dtor(&value);
}
/* zend_assign_to_variable() always takes care of op2, never free it! */
@@ -32829,6 +32836,10 @@ static int ZEND_FASTCALL ZEND_ASSIGN_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_
}
}
if (IS_CV == IS_VAR && 0) {
zval_ptr_dtor(&value);
}
/* zend_assign_to_variable() always takes care of op2, never free it! */
CHECK_EXCEPTION();
@@ -34949,6 +34960,10 @@ static int ZEND_FASTCALL ZEND_ASSIGN_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_AR
}
}
if (IS_CV == IS_VAR && 0) {
zval_ptr_dtor(&value);
}
/* zend_assign_to_variable() always takes care of op2, never free it! */
CHECK_EXCEPTION();
@@ -37072,6 +37087,10 @@ static int ZEND_FASTCALL ZEND_ASSIGN_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_AR
}
}
if (IS_CV == IS_VAR && 0) {
zval_ptr_dtor(&value);
}
/* zend_assign_to_variable() always takes care of op2, never free it! */
if (free_op2.var) {zval_ptr_dtor(&free_op2.var);};
@@ -40257,6 +40276,10 @@ static int ZEND_FASTCALL ZEND_ASSIGN_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARG
}
}
if (IS_CV == IS_VAR && 0) {
zval_ptr_dtor(&value);
}
/* zend_assign_to_variable() always takes care of op2, never free it! */
CHECK_EXCEPTION();
+2 -2
View File
@@ -119,8 +119,8 @@ int zend_sprintf(char *buffer, const char *format, ...);
PHP_MAJOR_VERSION=5
PHP_MINOR_VERSION=5
PHP_RELEASE_VERSION=26
PHP_EXTRA_VERSION="-dev"
PHP_RELEASE_VERSION=28
PHP_EXTRA_VERSION=""
PHP_VERSION="$PHP_MAJOR_VERSION.$PHP_MINOR_VERSION.$PHP_RELEASE_VERSION$PHP_EXTRA_VERSION"
PHP_VERSION_ID=`expr [$]PHP_MAJOR_VERSION \* 10000 + [$]PHP_MINOR_VERSION \* 100 + [$]PHP_RELEASE_VERSION`
+785 -748
View File
File diff suppressed because it is too large. Load diff
+72 -62
View File
@@ -593,7 +593,7 @@ static zend_object_handlers date_object_handlers_period;
#define DATE_SET_CONTEXT \
zval *object; \
object = getThis(); \
#define DATE_FETCH_OBJECT \
php_date_obj *obj; \
DATE_SET_CONTEXT; \
@@ -762,7 +762,7 @@ PHP_RSHUTDOWN_FUNCTION(date)
* RFC2822, Section 3.3: http://www.ietf.org/rfc/rfc2822.txt
* FWS = ([*WSP CRLF] 1*WSP) / ; Folding white space
* CFWS = *([FWS] comment) (([FWS] comment) / FWS)
*
*
* date-time = [ day-of-week "," ] date FWS time [CFWS]
* day-of-week = ([FWS] day-name)
* day-name = "Mon" / "Tue" / "Wed" / "Thu" / "Fri" / "Sat" / "Sun"
@@ -784,19 +784,19 @@ PHP_RSHUTDOWN_FUNCTION(date)
* date-fullyear = 4DIGIT
* date-month = 2DIGIT ; 01-12
* date-mday = 2DIGIT ; 01-28, 01-29, 01-30, 01-31 based on month/year
*
*
* time-hour = 2DIGIT ; 00-23
* time-minute = 2DIGIT ; 00-59
* time-second = 2DIGIT ; 00-58, 00-59, 00-60 based on leap second rules
*
*
* time-secfrac = "." 1*DIGIT
* time-numoffset = ("+" / "-") time-hour ":" time-minute
* time-offset = "Z" / time-numoffset
*
*
* partial-time = time-hour ":" time-minute ":" time-second [time-secfrac]
* full-date = date-fullyear "-" date-month "-" date-mday
* full-time = partial-time time-offset
*
*
* date-time = full-date "T" full-time
*/
#define DATE_FORMAT_RFC3339 "Y-m-d\\TH:i:sP"
@@ -877,6 +877,10 @@ PHP_MSHUTDOWN_FUNCTION(date)
timelib_error_container_dtor(DATEG(last_errors));
}
#ifndef ZTS
DATEG(default_timezone) = NULL;
#endif
return SUCCESS;
}
/* }}} */
@@ -885,7 +889,7 @@ PHP_MSHUTDOWN_FUNCTION(date)
PHP_MINFO_FUNCTION(date)
{
const timelib_tzdb *tzdb = DATE_TIMEZONEDB;
php_info_print_table_start();
php_info_print_table_row(2, "date/time support", "enabled");
php_info_print_table_row(2, "\"Olson\" Timezone Database Version", tzdb->version);
@@ -1037,8 +1041,8 @@ char *php_date_full_day_name(timelib_sll y, timelib_sll m, timelib_sll d)
timelib_sll day_of_week = timelib_day_of_week(y, m, d);
if (day_of_week < 0) {
return "Unknown";
}
return day_full_names[day_of_week];
}
return day_full_names[day_of_week];
}
char *php_date_short_day_name(timelib_sll y, timelib_sll m, timelib_sll d)
@@ -1046,8 +1050,8 @@ char *php_date_short_day_name(timelib_sll y, timelib_sll m, timelib_sll d)
timelib_sll day_of_week = timelib_day_of_week(y, m, d);
if (day_of_week < 0) {
return "Unknown";
}
return day_short_names[day_of_week];
}
return day_short_names[day_of_week];
}
/* }}} */
@@ -1079,7 +1083,7 @@ static char *date_format(char *format, int format_len, timelib_time *t, int loca
offset->leap_secs = 0;
offset->is_dst = 0;
offset->abbr = malloc(9); /* GMT�xxxx\0 */
snprintf(offset->abbr, 9, "GMT%c%02d%02d",
snprintf(offset->abbr, 9, "GMT%c%02d%02d",
localtime ? ((offset->offset < 0) ? '-' : '+') : '+',
localtime ? abs(offset->offset / 3600) : 0,
localtime ? abs((offset->offset % 3600) / 60) : 0 );
@@ -1125,7 +1129,7 @@ static char *date_format(char *format, int format_len, timelib_time *t, int loca
case 'a': length = slprintf(buffer, 32, "%s", t->h >= 12 ? "pm" : "am"); break;
case 'A': length = slprintf(buffer, 32, "%s", t->h >= 12 ? "PM" : "AM"); break;
case 'B': {
int retval = (((((long)t->sse)-(((long)t->sse) - ((((long)t->sse) % 86400) + 3600))) * 10) / 864);
int retval = (((((long)t->sse)-(((long)t->sse) - ((((long)t->sse) % 86400) + 3600))) * 10) / 864);
while (retval < 0) {
retval += 1000;
}
@@ -1225,7 +1229,7 @@ static void php_date(INTERNAL_FUNCTION_PARAMETERS, int localtime)
}
string = php_format_date(format, format_len, ts, localtime TSRMLS_CC);
RETVAL_STRING(string, 0);
}
/* }}} */
@@ -1249,7 +1253,7 @@ PHPAPI char *php_format_date(char *format, int format_len, time_t ts, int localt
}
string = date_format(format, format_len, t, localtime);
timelib_time_dtor(t);
return string;
}
@@ -1290,7 +1294,7 @@ PHPAPI int php_idate(char format, time_t ts, int localtime TSRMLS_DC)
offset->leap_secs = 0;
offset->is_dst = t->dst;
offset->abbr = malloc(9); /* GMT�xxxx\0 */
snprintf(offset->abbr, 9, "GMT%c%02d%02d",
snprintf(offset->abbr, 9, "GMT%c%02d%02d",
!localtime ? ((offset->offset < 0) ? '-' : '+') : '+',
!localtime ? abs(offset->offset / 3600) : 0,
!localtime ? abs((offset->offset % 3600) / 60) : 0 );
@@ -1322,7 +1326,7 @@ PHPAPI int php_idate(char format, time_t ts, int localtime TSRMLS_DC)
/* Swatch Beat a.k.a. Internet Time */
case 'B':
retval = (((((long)t->sse)-(((long)t->sse) - ((((long)t->sse) % 86400) + 3600))) * 10) / 864);
retval = (((((long)t->sse)-(((long)t->sse) - ((((long)t->sse) % 86400) + 3600))) * 10) / 864);
while (retval < 0) {
retval += 1000;
}
@@ -1374,7 +1378,7 @@ PHP_FUNCTION(idate)
char *format;
int format_len;
long ts = 0;
int ret;
int ret;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &format, &format_len, &ts) == FAILURE) {
RETURN_FALSE;
@@ -1402,7 +1406,7 @@ PHP_FUNCTION(idate)
PHPAPI void php_date_set_tzdb(timelib_tzdb *tzdb)
{
const timelib_tzdb *builtin = timelib_builtin_db();
if (php_version_compare(tzdb->version, builtin->version) > 0) {
php_date_global_timezone_db = tzdb;
php_date_global_timezone_db_enabled = 1;
@@ -1473,7 +1477,7 @@ PHP_FUNCTION(strtotime)
}
if (!time_len) {
timelib_time_dtor(now);
timelib_time_dtor(now);
RETURN_FALSE;
}
@@ -1922,7 +1926,7 @@ static void date_period_it_current_data(zend_object_iterator *iter, zval ***data
if (it_time->tz_info) {
newdateobj->time->tz_info = it_time->tz_info;
}
*data = &iterator->current;
}
/* }}} */
@@ -2116,13 +2120,13 @@ static inline zend_object_value date_object_new_date_ex(zend_class_entry *class_
if (ptr) {
*ptr = intern;
}
zend_object_std_init(&intern->std, class_type TSRMLS_CC);
object_properties_init(&intern->std, class_type);
retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) date_object_free_storage_date, NULL TSRMLS_CC);
retval.handlers = &date_object_handlers_date;
return retval;
}
@@ -2136,12 +2140,12 @@ static zend_object_value date_object_clone_date(zval *this_ptr TSRMLS_DC)
php_date_obj *new_obj = NULL;
php_date_obj *old_obj = (php_date_obj *) zend_object_store_get_object(this_ptr TSRMLS_CC);
zend_object_value new_ov = date_object_new_date_ex(old_obj->std.ce, &new_obj TSRMLS_CC);
zend_objects_clone_members(&new_obj->std, new_ov, &old_obj->std, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC);
if (!old_obj->time) {
return new_ov;
}
/* this should probably moved to a new `timelib_time *timelime_time_clone(timelib_time *)` */
new_obj->time = timelib_time_ctor();
*new_obj->time = *old_obj->time;
@@ -2151,7 +2155,7 @@ static zend_object_value date_object_clone_date(zval *this_ptr TSRMLS_DC)
if (old_obj->time->tz_info) {
new_obj->time->tz_info = old_obj->time->tz_info;
}
return new_ov;
}
@@ -2268,10 +2272,10 @@ static inline zend_object_value date_object_new_timezone_ex(zend_class_entry *cl
zend_object_std_init(&intern->std, class_type TSRMLS_CC);
object_properties_init(&intern->std, class_type);
retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) date_object_free_storage_timezone, NULL TSRMLS_CC);
retval.handlers = &date_object_handlers_timezone;
return retval;
}
@@ -2285,12 +2289,12 @@ static zend_object_value date_object_clone_timezone(zval *this_ptr TSRMLS_DC)
php_timezone_obj *new_obj = NULL;
php_timezone_obj *old_obj = (php_timezone_obj *) zend_object_store_get_object(this_ptr TSRMLS_CC);
zend_object_value new_ov = date_object_new_timezone_ex(old_obj->std.ce, &new_obj TSRMLS_CC);
zend_objects_clone_members(&new_obj->std, new_ov, &old_obj->std, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC);
if (!old_obj->initialized) {
return new_ov;
}
new_obj->type = old_obj->type;
new_obj->initialized = 1;
switch (new_obj->type) {
@@ -2306,7 +2310,7 @@ static zend_object_value date_object_clone_timezone(zval *this_ptr TSRMLS_DC)
new_obj->tzi.z.abbr = strdup(old_obj->tzi.z.abbr);
break;
}
return new_ov;
}
@@ -2367,10 +2371,10 @@ static inline zend_object_value date_object_new_interval_ex(zend_class_entry *cl
zend_object_std_init(&intern->std, class_type TSRMLS_CC);
object_properties_init(&intern->std, class_type);
retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) date_object_free_storage_interval, NULL TSRMLS_CC);
retval.handlers = &date_object_handlers_interval;
return retval;
}
@@ -2384,7 +2388,7 @@ static zend_object_value date_object_clone_interval(zval *this_ptr TSRMLS_DC)
php_interval_obj *new_obj = NULL;
php_interval_obj *old_obj = (php_interval_obj *) zend_object_store_get_object(this_ptr TSRMLS_CC);
zend_object_value new_ov = date_object_new_interval_ex(old_obj->std.ce, &new_obj TSRMLS_CC);
zend_objects_clone_members(&new_obj->std, new_ov, &old_obj->std, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC);
/** FIX ME ADD CLONE STUFF **/
@@ -2456,10 +2460,10 @@ static inline zend_object_value date_object_new_period_ex(zend_class_entry *clas
zend_object_std_init(&intern->std, class_type TSRMLS_CC);
object_properties_init(&intern->std, class_type);
retval.handle = zend_objects_store_put(intern, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t) date_object_free_storage_period, NULL TSRMLS_CC);
retval.handlers = &date_object_handlers_period;
return retval;
}
@@ -2473,7 +2477,7 @@ static zend_object_value date_object_clone_period(zval *this_ptr TSRMLS_DC)
php_period_obj *new_obj = NULL;
php_period_obj *old_obj = (php_period_obj *) zend_object_store_get_object(this_ptr TSRMLS_CC);
zend_object_value new_ov = date_object_new_period_ex(old_obj->std.ce, &new_obj TSRMLS_CC);
zend_objects_clone_members(&new_obj->std, new_ov, &old_obj->std, Z_OBJ_HANDLE_P(this_ptr) TSRMLS_CC);
/** FIX ME ADD CLONE STUFF **/
@@ -2559,7 +2563,7 @@ PHPAPI int php_date_initialize(php_date_obj *dateobj, /*const*/ char *time_str,
int type = TIMELIB_ZONETYPE_ID, new_dst = 0;
char *new_abbr = NULL;
timelib_sll new_offset;
if (dateobj->time) {
timelib_time_dtor(dateobj->time);
}
@@ -2938,7 +2942,7 @@ void php_date_do_return_parsed_time(INTERNAL_FUNCTION_PARAMETERS, timelib_time *
PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(hour, h);
PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(minute, i);
PHP_DATE_PARSE_DATE_SET_TIME_ELEMENT(second, s);
if (parsed_time->f == -99999) {
add_assoc_bool(return_value, "fraction", 0);
} else {
@@ -3005,7 +3009,7 @@ PHP_FUNCTION(date_parse)
int date_len;
struct timelib_error_container *error;
timelib_time *parsed_time;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &date, &date_len) == FAILURE) {
RETURN_FALSE;
}
@@ -3024,7 +3028,7 @@ PHP_FUNCTION(date_parse_from_format)
int date_len, format_len;
struct timelib_error_container *error;
timelib_time *parsed_time;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss", &format, &format_len, &date, &date_len) == FAILURE) {
RETURN_FALSE;
}
@@ -3508,7 +3512,7 @@ static void php_date_isodate_set(zval *object, long y, long w, long d, zval *ret
memset(&dateobj->time->relative, 0, sizeof(dateobj->time->relative));
dateobj->time->relative.d = timelib_daynr_from_weeknr(y, w, d);
dateobj->time->have_relative = 1;
timelib_update_ts(dateobj->time, NULL);
}
@@ -3697,7 +3701,7 @@ PHP_METHOD(DateTimeZone, __construct)
int tz_len;
php_timezone_obj *tzobj;
zend_error_handling error_handling;
zend_replace_error_handling(EH_THROW, NULL, &error_handling TSRMLS_CC);
if (SUCCESS == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &tz, &tz_len)) {
tzobj = zend_object_store_get_object(getThis() TSRMLS_CC);
@@ -3975,7 +3979,7 @@ static int date_interval_initialize(timelib_rel_time **rt, /*const*/ char *forma
struct timelib_error_container *errors;
timelib_strtointerval(format, format_length, &b, &e, &p, &r, &errors);
if (errors->error_count > 0) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown or bad format (%s)", format);
retval = FAILURE;
@@ -4134,7 +4138,7 @@ PHP_METHOD(DateInterval, __construct)
php_interval_obj *diobj;
timelib_rel_time *reltime;
zend_error_handling error_handling;
zend_replace_error_handling(EH_THROW, NULL, &error_handling TSRMLS_CC);
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &interval_string, &interval_string_length) == SUCCESS) {
if (date_interval_initialize(&reltime, interval_string, interval_string_length TSRMLS_CC) == SUCCESS) {
@@ -4157,8 +4161,7 @@ static int php_date_interval_initialize_from_hash(zval **return_value, php_inter
#define PHP_DATE_INTERVAL_READ_PROPERTY(element, member, itype, def) \
do { \
zval **z_arg = NULL; \
if (zend_hash_find(myht, element, strlen(element) + 1, (void**) &z_arg) == SUCCESS) { \
convert_to_long(*z_arg); \
if (zend_hash_find(myht, element, strlen(element) + 1, (void**) &z_arg) == SUCCESS && Z_TYPE_PP(z_arg) == IS_LONG) { \
(*intobj)->diff->member = (itype)Z_LVAL_PP(z_arg); \
} else { \
(*intobj)->diff->member = (itype)def; \
@@ -4169,8 +4172,15 @@ static int php_date_interval_initialize_from_hash(zval **return_value, php_inter
do { \
zval **z_arg = NULL; \
if (zend_hash_find(myht, element, strlen(element) + 1, (void**) &z_arg) == SUCCESS) { \
convert_to_string(*z_arg); \
DATE_A64I((*intobj)->diff->member, Z_STRVAL_PP(z_arg)); \
if (Z_TYPE_PP(z_arg) == IS_STRING) { \
DATE_A64I((*intobj)->diff->member, Z_STRVAL_PP(z_arg)); \
} else if (Z_TYPE_PP(z_arg) == IS_LONG || Z_TYPE_PP(z_arg) == IS_BOOL) { \
(*intobj)->diff->member = (timelib_sll)Z_LVAL_PP(z_arg); \
} else if (Z_TYPE_PP(z_arg) == IS_DOUBLE) { \
(*intobj)->diff->member = (timelib_sll)Z_DVAL_PP(z_arg); \
} else { \
(*intobj)->diff->member = -1LL; \
} \
} else { \
(*intobj)->diff->member = -1LL; \
} \
@@ -4348,7 +4358,7 @@ static int date_period_initialize(timelib_time **st, timelib_time **et, timelib_
struct timelib_error_container *errors;
timelib_strtointerval(format, format_length, &b, &e, &p, &r, &errors);
if (errors->error_count > 0) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown or bad format (%s)", format);
retval = FAILURE;
@@ -4377,7 +4387,7 @@ PHP_METHOD(DatePeriod, __construct)
int isostr_len = 0;
timelib_time *clone;
zend_error_handling error_handling;
zend_replace_error_handling(EH_THROW, NULL, &error_handling TSRMLS_CC);
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "OOl|l", &start, date_ce_interface, &interval, date_ce_interval, &recurrences, &options) == FAILURE) {
if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "OOO|l", &start, date_ce_interface, &interval, date_ce_interval, &end, date_ce_interface, &options) == FAILURE) {
@@ -4492,7 +4502,7 @@ PHP_FUNCTION(timezone_identifiers_list)
tzdb = DATE_TIMEZONEDB;
item_count = tzdb->index_size;
table = tzdb->index;
array_init(return_value);
for (i = 0; i < item_count; ++i) {
@@ -4526,7 +4536,7 @@ PHP_FUNCTION(timezone_abbreviations_list)
{
const timelib_tz_lookup_table *table, *entry;
zval *element, **abbr_array_pp, *abbr_array;
table = timelib_timezone_abbreviations_list();
array_init(return_value);
entry = table;
@@ -4602,11 +4612,11 @@ static void php_do_date_sunrise_sunset(INTERNAL_FUNCTION_PARAMETERS, int calc_su
timelib_time *t;
timelib_tzinfo *tzi;
char *retstr;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|ldddd", &time, &retformat, &latitude, &longitude, &zenith, &gmt_offset) == FAILURE) {
RETURN_FALSE;
}
switch (ZEND_NUM_ARGS()) {
case 1:
retformat = SUNFUNCS_RET_STRING;
@@ -4650,7 +4660,7 @@ static void php_do_date_sunrise_sunset(INTERNAL_FUNCTION_PARAMETERS, int calc_su
timelib_unixtime2local(t, time);
rs = timelib_astro_rise_set_altitude(t, longitude, latitude, altitude, 1, &h_rise, &h_set, &rise, &set, &transit);
timelib_time_dtor(t);
if (rs != 0) {
RETURN_FALSE;
}
@@ -4704,7 +4714,7 @@ PHP_FUNCTION(date_sun_info)
timelib_sll rise, set, transit;
int dummy;
double ddummy;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ldd", &time, &latitude, &longitude) == FAILURE) {
RETURN_FALSE;
}
@@ -4718,7 +4728,7 @@ PHP_FUNCTION(date_sun_info)
/* Setup */
t2 = timelib_time_ctor();
array_init(return_value);
/* Get sun up/down and transit */
rs = timelib_astro_rise_set_altitude(t, longitude, latitude, -35.0/60, 1, &ddummy, &ddummy, &rise, &set, &transit);
switch (rs) {
@@ -4862,7 +4872,7 @@ static HashTable *date_object_get_properties_period(zval *object TSRMLS_DC)
ZVAL_NULL(zv);
}
zend_hash_update(props, "interval", sizeof("interval"), &zv, sizeof(zv), NULL);
/* converted to larger type (int->long); must check when unserializing */
MAKE_STD_ZVAL(zv);
ZVAL_LONG(zv, (long) period_obj->recurrences);
@@ -4945,7 +4955,7 @@ static int php_date_period_initialize_from_hash(php_period_obj *period_obj, Hash
}
period_obj->initialized = 1;
return 1;
}
@@ -4962,7 +4972,7 @@ PHP_METHOD(DatePeriod, __set_state)
}
myht = Z_ARRVAL_P(array);
object_init_ex(return_value, date_ce_period);
period_obj = zend_object_store_get_object(return_value TSRMLS_CC);
if (!php_date_period_initialize_from_hash(period_obj, myht TSRMLS_CC)) {
+1 -1
View File
@@ -46,7 +46,7 @@ array(12) {
bool(false)
object(DateTime)#1 (3) {
["date"]=>
string(20) "-0001-11-30 00:00:00.000000"
string(27) "-0001-11-30 00:00:00.000000"
["timezone_type"]=>
int(3)
["timezone"]=>
+6 -6
View File
@@ -14,17 +14,17 @@ var_dump($di);
--EXPECTF--
object(DateInterval)#%d (15) {
["y"]=>
int(2)
int(-1)
["m"]=>
int(0)
int(-1)
["d"]=>
int(0)
int(-1)
["h"]=>
int(6)
int(-1)
["i"]=>
int(8)
int(-1)
["s"]=>
int(0)
int(-1)
["weekday"]=>
int(10)
["weekday_behavior"]=>
+6 -6
View File
@@ -14,17 +14,17 @@ var_dump($di);
--EXPECTF--
object(DateInterval)#%d (15) {
["y"]=>
int(2)
int(-1)
["m"]=>
int(0)
int(-1)
["d"]=>
int(0)
int(-1)
["h"]=>
int(6)
int(-1)
["i"]=>
int(8)
int(-1)
["s"]=>
int(0)
int(-1)
["weekday"]=>
int(10)
["weekday_behavior"]=>
+2 -2
View File
@@ -61,7 +61,7 @@ array\(11\) {
\["mday"\]=>
int\((9|14|23)\)
\["wday"\]=>
int\(0\)
int\((0|6)\)
\["mon"\]=>
int\((10|12)\)
\["year"\]=>
@@ -69,7 +69,7 @@ array\(11\) {
\["yday"\]=>
int\((282|347|295)\)
\["weekday"\]=>
string\(6\) "Sunday"
string\((6|8)\) "(Sunday|Saturday)"
\["month"\]=>
string\((7|8)\) "(October|December)"
\[0\]=>
+2 -2
View File
@@ -87,7 +87,7 @@ array\(9\) {
\[5\]=>
int\((104|1|-3843)\)
\[6\]=>
int\(6\)
int\((5|6)\)
\[7\]=>
int\((281|346|294)\)
\[8\]=>
@@ -107,7 +107,7 @@ array\(9\) {
\["tm_year"\]=>
int\((104|1|-3843)\)
\["tm_wday"\]=>
int\(6\)
int\((5|6)\)
\["tm_yday"\]=>
int\((281|346|294)\)
\["tm_isdst"\]=>
+17 -5
View File
@@ -1761,7 +1761,7 @@ PHP_FUNCTION(dom_document_save)
char *file;
long options = 0;
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os|l", &id, dom_document_class_entry, &file, &file_len, &options) == FAILURE) {
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Op|l", &id, dom_document_class_entry, &file, &file_len, &options) == FAILURE) {
return;
}
@@ -1991,7 +1991,7 @@ static void _dom_document_schema_validate(INTERNAL_FUNCTION_PARAMETERS, int type
int is_valid;
char resolved_path[MAXPATHLEN + 1];
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Op|l", &id, dom_document_class_entry, &source, &source_len, &flags) == FAILURE) {
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os|l", &id, dom_document_class_entry, &source, &source_len, &flags) == FAILURE) {
return;
}
@@ -2004,6 +2004,10 @@ static void _dom_document_schema_validate(INTERNAL_FUNCTION_PARAMETERS, int type
switch (type) {
case DOM_LOAD_FILE:
if (CHECK_NULL_PATH(source, source_len)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid Schema file source");
RETURN_FALSE;
}
valid_file = _dom_get_valid_file_path(source, resolved_path, MAXPATHLEN TSRMLS_CC);
if (!valid_file) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid Schema file source");
@@ -2087,7 +2091,7 @@ static void _dom_document_relaxNG_validate(INTERNAL_FUNCTION_PARAMETERS, int typ
int is_valid;
char resolved_path[MAXPATHLEN + 1];
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Op", &id, dom_document_class_entry, &source, &source_len) == FAILURE) {
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &id, dom_document_class_entry, &source, &source_len) == FAILURE) {
return;
}
@@ -2100,6 +2104,10 @@ static void _dom_document_relaxNG_validate(INTERNAL_FUNCTION_PARAMETERS, int typ
switch (type) {
case DOM_LOAD_FILE:
if (CHECK_NULL_PATH(source, source_len)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid RelaxNG file source");
RETURN_FALSE;
}
valid_file = _dom_get_valid_file_path(source, resolved_path, MAXPATHLEN TSRMLS_CC);
if (!valid_file) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid RelaxNG file source");
@@ -2180,7 +2188,7 @@ static void dom_load_html(INTERNAL_FUNCTION_PARAMETERS, int mode) /* {{{ */
id = getThis();
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "p|l", &source, &source_len, &options) == FAILURE) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &source, &source_len, &options) == FAILURE) {
return;
}
@@ -2190,6 +2198,10 @@ static void dom_load_html(INTERNAL_FUNCTION_PARAMETERS, int mode) /* {{{ */
}
if (mode == DOM_LOAD_FILE) {
if (CHECK_NULL_PATH(source, source_len)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid file source");
RETURN_FALSE;
}
ctxt = htmlCreateFileParserCtxt(source, NULL);
} else {
source_len = xmlStrlen(source);
@@ -2278,7 +2290,7 @@ PHP_FUNCTION(dom_document_save_html_file)
char *file;
const char *encoding;
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &id, dom_document_class_entry, &file, &file_len) == FAILURE) {
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Op", &id, dom_document_class_entry, &file, &file_len) == FAILURE) {
return;
}
@@ -15,9 +15,9 @@ $result = $doc->loadHTMLFile("");
assert('$result === false');
$doc = new DOMDocument();
$result = $doc->loadHTMLFile("text.html\0something");
assert('$result === null');
assert('$result === false');
?>
--EXPECTF--
%r(PHP ){0,1}%rWarning: DOMDocument::loadHTMLFile(): Empty string supplied as input %s
%r(PHP ){0,1}%rWarning: DOMDocument::loadHTMLFile() expects parameter 1 to be a valid path, string given %s
%r(PHP ){0,1}%rWarning: DOMDocument::loadHTMLFile(): Invalid file source %s
+41 -43
View File
@@ -188,9 +188,9 @@ ftp_close(ftpbuf_t *ftp)
SSL_shutdown(ftp->ssl_handle);
SSL_free(ftp->ssl_handle);
}
#endif
#endif
closesocket(ftp->fd);
}
}
ftp_gc(ftp);
efree(ftp);
return NULL;
@@ -262,7 +262,7 @@ ftp_login(ftpbuf_t *ftp, const char *user, const char *pass TSRMLS_DC)
if (!ftp_getresp(ftp)) {
return 0;
}
if (ftp->resp != 234) {
if (!ftp_putcmd(ftp, "AUTH", "SSL")) {
return 0;
@@ -270,7 +270,7 @@ ftp_login(ftpbuf_t *ftp, const char *user, const char *pass TSRMLS_DC)
if (!ftp_getresp(ftp)) {
return 0;
}
if (ftp->resp != 334) {
return 0;
} else {
@@ -278,7 +278,7 @@ ftp_login(ftpbuf_t *ftp, const char *user, const char *pass TSRMLS_DC)
ftp->use_ssl_for_data = 1;
}
}
ctx = SSL_CTX_new(SSLv23_client_method());
if (ctx == NULL) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "failed to create the SSL context");
@@ -325,8 +325,8 @@ ftp_login(ftpbuf_t *ftp, const char *user, const char *pass TSRMLS_DC)
if (!ftp_getresp(ftp)) {
return 0;
}
ftp->use_ssl_for_data = (ftp->resp >= 200 && ftp->resp <=299);
ftp->use_ssl_for_data = (ftp->resp >= 200 && ftp->resp <=299);
}
}
#endif
@@ -360,7 +360,7 @@ ftp_reinit(ftpbuf_t *ftp)
{
if (ftp == NULL) {
return 0;
}
}
ftp_gc(ftp);
@@ -395,7 +395,7 @@ ftp_syst(ftpbuf_t *ftp)
if (!ftp_putcmd(ftp, "SYST", NULL)) {
return NULL;
}
if (!ftp_getresp(ftp) || ftp->resp != 215) {
if (!ftp_getresp(ftp) || ftp->resp != 215) {
return NULL;
}
syst = ftp->inbuf;
@@ -431,14 +431,14 @@ ftp_pwd(ftpbuf_t *ftp)
if (!ftp_putcmd(ftp, "PWD", NULL)) {
return NULL;
}
if (!ftp_getresp(ftp) || ftp->resp != 257) {
if (!ftp_getresp(ftp) || ftp->resp != 257) {
return NULL;
}
/* copy out the pwd from response */
if ((pwd = strchr(ftp->inbuf, '"')) == NULL) {
if ((pwd = strchr(ftp->inbuf, '"')) == NULL) {
return NULL;
}
if ((end = strrchr(++pwd, '"')) == NULL) {
if ((end = strrchr(++pwd, '"')) == NULL) {
return NULL;
}
ftp->pwd = estrndup(pwd, end - pwd);
@@ -608,7 +608,7 @@ ftp_chmod(ftpbuf_t *ftp, const int mode, const char *filename, const int filenam
if (!ftp_getresp(ftp) || ftp->resp != 200) {
return 0;
}
return 1;
}
/* }}} */
@@ -625,7 +625,7 @@ ftp_alloc(ftpbuf_t *ftp, const long size, char **response)
}
snprintf(buffer, sizeof(buffer) - 1, "%ld", size);
if (!ftp_putcmd(ftp, "ALLO", buffer)) {
return 0;
}
@@ -642,7 +642,7 @@ ftp_alloc(ftpbuf_t *ftp, const long size, char **response)
return 0;
}
return 1;
return 1;
}
/* }}} */
@@ -674,7 +674,7 @@ ftp_type(ftpbuf_t *ftp, ftptype_t type)
if (ftp == NULL) {
return 0;
}
if (type == ftp->type) {
if (type == ftp->type) {
return 1;
}
if (type == FTPTYPE_ASCII) {
@@ -765,7 +765,7 @@ ftp_pasv(ftpbuf_t *ftp, int pasv)
if (!ftp_putcmd(ftp, "PASV", NULL)) {
return 0;
}
if (!ftp_getresp(ftp) || ftp->resp != 227) {
if (!ftp_getresp(ftp) || ftp->resp != 227) {
return 0;
}
/* parse out the IP and port */
@@ -807,7 +807,7 @@ ftp_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, ftptype_t type,
if ((data = ftp_getdata(ftp TSRMLS_CC)) == NULL) {
goto bail;
}
ftp->data = data;
if (resumepos > 0) {
@@ -900,7 +900,7 @@ ftp_put(ftpbuf_t *ftp, const char *path, php_stream *instream, ftptype_t type, l
if ((data = ftp_getdata(ftp TSRMLS_CC)) == NULL) {
goto bail;
}
ftp->data = data;
ftp->data = data;
if (startpos > 0) {
snprintf(arg, sizeof(arg), "%ld", startpos);
@@ -1101,7 +1101,7 @@ ftp_putcmd(ftpbuf_t *ftp, const char *cmd, const char *args)
if (strpbrk(cmd, "\r\n")) {
return 0;
}
}
/* build the output buffer */
if (args && args[0]) {
/* "cmd args\r\n\0" */
@@ -1247,7 +1247,7 @@ my_send(ftpbuf_t *ftp, php_socket_t s, void *buf, size_t len)
#if HAVE_OPENSSL_EXT
if (ftp->use_ssl && ftp->fd == s && ftp->ssl_active) {
sent = SSL_write(ftp->ssl_handle, buf, size);
} else if (ftp->use_ssl && ftp->fd != s && ftp->use_ssl_for_data && ftp->data->ssl_active) {
} else if (ftp->use_ssl && ftp->fd != s && ftp->use_ssl_for_data && ftp->data->ssl_active) {
sent = SSL_write(ftp->data->ssl_handle, buf, size);
} else {
#endif
@@ -1287,14 +1287,14 @@ my_recv(ftpbuf_t *ftp, php_socket_t s, void *buf, size_t len)
#if HAVE_OPENSSL_EXT
if (ftp->use_ssl && ftp->fd == s && ftp->ssl_active) {
nr_bytes = SSL_read(ftp->ssl_handle, buf, len);
} else if (ftp->use_ssl && ftp->fd != s && ftp->use_ssl_for_data && ftp->data->ssl_active) {
} else if (ftp->use_ssl && ftp->fd != s && ftp->use_ssl_for_data && ftp->data->ssl_active) {
nr_bytes = SSL_read(ftp->data->ssl_handle, buf, len);
} else {
#endif
nr_bytes = recv(s, buf, len, 0);
#if HAVE_OPENSSL_EXT
}
#endif
#endif
return (nr_bytes);
}
/* }}} */
@@ -1511,7 +1511,7 @@ data_accept(databuf_t *data, ftpbuf_t *ftp TSRMLS_DC)
data_accepted:
#if HAVE_OPENSSL_EXT
/* now enable ssl if we need to */
if (ftp->use_ssl && ftp->use_ssl_for_data) {
ctx = SSL_CTX_new(SSLv23_client_method());
@@ -1531,23 +1531,23 @@ data_accepted:
SSL_CTX_free(ctx);
return 0;
}
SSL_set_fd(data->ssl_handle, data->fd);
if (ftp->old_ssl) {
SSL_copy_session_id(data->ssl_handle, ftp->ssl_handle);
}
if (SSL_connect(data->ssl_handle) <= 0) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "data_accept: SSL/TLS handshake failed");
SSL_shutdown(data->ssl_handle);
SSL_free(data->ssl_handle);
return 0;
}
data->ssl_active = 1;
}
}
#endif
@@ -1562,14 +1562,14 @@ data_close(ftpbuf_t *ftp, databuf_t *data)
{
#if HAVE_OPENSSL_EXT
SSL_CTX *ctx;
#endif
#endif
if (data == NULL) {
return NULL;
}
if (data->listener != -1) {
#if HAVE_OPENSSL_EXT
if (data->ssl_active) {
ctx = SSL_get_SSL_CTX(data->ssl_handle);
SSL_CTX_free(ctx);
@@ -1577,9 +1577,9 @@ data_close(ftpbuf_t *ftp, databuf_t *data)
SSL_free(data->ssl_handle);
data->ssl_active = 0;
}
#endif
#endif
closesocket(data->listener);
}
}
if (data->fd != -1) {
#if HAVE_OPENSSL_EXT
if (data->ssl_active) {
@@ -1590,9 +1590,9 @@ data_close(ftpbuf_t *ftp, databuf_t *data)
SSL_free(data->ssl_handle);
data->ssl_active = 0;
}
#endif
#endif
closesocket(data->fd);
}
}
if (ftp) {
ftp->data = NULL;
}
@@ -1610,8 +1610,8 @@ ftp_genlist(ftpbuf_t *ftp, const char *cmd, const char *path TSRMLS_DC)
databuf_t *data = NULL;
char *ptr;
int ch, lastch;
int size, rcvd;
int lines;
size_t size, rcvd;
size_t lines;
char **ret = NULL;
char **entry;
char *text;
@@ -1629,7 +1629,7 @@ ftp_genlist(ftpbuf_t *ftp, const char *cmd, const char *path TSRMLS_DC)
if ((data = ftp_getdata(ftp TSRMLS_CC)) == NULL) {
goto bail;
}
ftp->data = data;
ftp->data = data;
if (!ftp_putcmd(ftp, cmd, path)) {
goto bail;
@@ -1653,7 +1653,7 @@ ftp_genlist(ftpbuf_t *ftp, const char *cmd, const char *path TSRMLS_DC)
lines = 0;
lastch = 0;
while ((rcvd = my_recv(ftp, data->fd, data->buf, FTP_BUFSIZE))) {
if (rcvd == -1) {
if (rcvd == -1 || rcvd > ((size_t)(-1))-size) {
goto bail;
}
@@ -1663,8 +1663,6 @@ ftp_genlist(ftpbuf_t *ftp, const char *cmd, const char *path TSRMLS_DC)
for (ptr = data->buf; rcvd; rcvd--, ptr++) {
if (*ptr == '\n' && lastch == '\r') {
lines++;
} else {
size++;
}
lastch = *ptr;
}
@@ -1858,7 +1856,7 @@ ftp_nb_put(ftpbuf_t *ftp, const char *path, php_stream *instream, ftptype_t type
if (!ftp_getresp(ftp) || (ftp->resp != 150 && ftp->resp != 125)) {
goto bail;
}
if ((data = data_accept(data, ftp TSRMLS_CC)) == NULL) {
if ((data = data_accept(data, ftp TSRMLS_CC)) == NULL) {
goto bail;
}
ftp->data = data;
@@ -1914,7 +1912,7 @@ ftp_nb_continue_write(ftpbuf_t *ftp TSRMLS_DC)
goto bail;
}
ftp->data = data_close(ftp, ftp->data);
if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250)) {
goto bail;
}
+9 -8
View File
@@ -1735,7 +1735,7 @@ PHP_FUNCTION(imagefilledarc)
long cx, cy, w, h, ST, E, col, style;
gdImagePtr im;
int e, st;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rllllllll", &IM, &cx, &cy, &w, &h, &ST, &E, &col, &style) == FAILURE) {
return;
}
@@ -1976,7 +1976,7 @@ PHP_FUNCTION(imagegrabwindow)
if ( handle == 0 ) {
goto clean;
}
pPrintWindow = (tPrintWindow) GetProcAddress(handle, "PrintWindow");
pPrintWindow = (tPrintWindow) GetProcAddress(handle, "PrintWindow");
if ( pPrintWindow ) {
pPrintWindow(window, memDC, (UINT) client_area);
@@ -3045,10 +3045,11 @@ PHP_FUNCTION(imagegammacorrect)
for (x = 0; x < gdImageSX(im); x++) {
c = gdImageGetPixel(im, x, y);
gdImageSetPixel(im, x, y,
gdTrueColor(
gdTrueColorAlpha(
(int) ((pow((pow((gdTrueColorGetRed(c) / 255.0), input)), 1.0 / output) * 255) + .5),
(int) ((pow((pow((gdTrueColorGetGreen(c) / 255.0), input)), 1.0 / output) * 255) + .5),
(int) ((pow((pow((gdTrueColorGetBlue(c) / 255.0), input)), 1.0 / output) * 255) + .5)
(int) ((pow((pow((gdTrueColorGetBlue(c) / 255.0), input)), 1.0 / output) * 255) + .5),
gdTrueColorGetAlpha(c)
)
);
}
@@ -3845,7 +3846,7 @@ static void php_imagettftext_common(INTERNAL_FUNCTION_PARAMETERS, int mode, int
if (zend_hash_get_current_data_ex(HASH_OF(EXT), (void **) &item, &pos) == FAILURE) {
continue;
}
if (strcmp("linespacing", key) == 0) {
convert_to_double_ex(item);
strex.flags |= gdFTEX_LINESPACE;
@@ -3924,7 +3925,7 @@ PHP_FUNCTION(imagepsloadfont)
struct stat st;
#endif
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &file, &file_len) == FAILURE) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "p", &file, &file_len) == FAILURE) {
return;
}
@@ -4264,11 +4265,11 @@ PHP_FUNCTION(imagepsbbox)
if (argc != 3 && argc != 6) {
ZEND_WRONG_PARAM_COUNT();
}
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "srl|lld", &str, &str_len, &fnt, &sz, &sp, &wd, &angle) == FAILURE) {
return;
}
if (argc == 6) {
space = sp;
add_width = wd;
+7 -7
View File
@@ -706,14 +706,14 @@ static WebPResult VPXEncode(const uint8* Y,
codec_ctl(&enc, VP8E_SET_STATIC_THRESHOLD, 0);
codec_ctl(&enc, VP8E_SET_TOKEN_PARTITIONS, 2);
vpx_img_wrap(&img, IMG_FMT_I420,
vpx_img_wrap(&img, VPX_IMG_FMT_I420,
y_width, y_height, 16, (uint8*)(Y));
img.planes[PLANE_Y] = (uint8*)(Y);
img.planes[PLANE_U] = (uint8*)(U);
img.planes[PLANE_V] = (uint8*)(V);
img.stride[PLANE_Y] = y_stride;
img.stride[PLANE_U] = uv_stride;
img.stride[PLANE_V] = uv_stride;
img.planes[VPX_PLANE_Y] = (uint8*)(Y);
img.planes[VPX_PLANE_U] = (uint8*)(U);
img.planes[VPX_PLANE_V] = (uint8*)(V);
img.stride[VPX_PLANE_Y] = y_stride;
img.stride[VPX_PLANE_U] = uv_stride;
img.stride[VPX_PLANE_V] = uv_stride;
res = vpx_codec_encode(&enc, &img, 0, 1, 0, VPX_DL_BEST_QUALITY);
+23
View File
@@ -0,0 +1,23 @@
--TEST--
Bug #61221 - imagegammacorrect function loses alpha channel
--SKIPIF--
<?php
if (!extension_loaded('gd')) die('skip gd extension not available');
?>
--FILE--
<?php
$imagew = 50;
$imageh = 50;
$img = imagecreatetruecolor($imagew, $imageh);
$blacktransparent = imagecolorallocatealpha($img, 0, 0, 0, 127);
$redsolid = imagecolorallocate($img, 255, 0, 0);
imagefill($img, 0, 0, $blacktransparent);
imageline($img, $imagew / 2, 0, $imagew / 2, $imageh - 1, $redsolid);
imageline($img, 0, $imageh / 2, $imagew - 1, $imageh / 2, $redsolid);
imagegammacorrect($img, 1, 1);
$color = imagecolorat($img, 0, 0);
var_dump($color === $blacktransparent);
imagedestroy($img);
?>
--EXPECT--
bool(true)
+35 -4
View File
@@ -35,7 +35,7 @@ if test "$PHP_ICONV" != "no"; then
PHP_ICONV_H_PATH="$PHP_ICONV_PREFIX/include/giconv.h"
else
PHP_ICONV_H_PATH="$PHP_ICONV_PREFIX/include/iconv.h"
fi
fi
AC_MSG_CHECKING([if iconv is glibc's])
AC_TRY_LINK([#include <gnu/libc-version.h>],[gnu_get_libc_version();],
@@ -53,8 +53,8 @@ if test "$PHP_ICONV" != "no"; then
AC_TRY_RUN([
#include <$PHP_ICONV_H_PATH>
int main() {
printf("%d", _libiconv_version);
return 0;
printf("%d", _libiconv_version);
return 0;
}
],[
AC_MSG_RESULT(yes)
@@ -138,7 +138,7 @@ int main() {
if (cd == (iconv_t)(-1)) {
if (errno == EINVAL) {
return 0;
} else {
} else {
return 1;
}
}
@@ -159,6 +159,37 @@ int main() {
AC_DEFINE([ICONV_SUPPORTS_ERRNO],0,[Whether iconv supports error no or not])
])
AC_MSG_CHECKING([if iconv supports //IGNORE])
AC_TRY_RUN([
#include <$PHP_ICONV_H_PATH>
#include <stdlib.h>
int main() {
iconv_t cd = iconv_open( "UTF-8//IGNORE", "UTF-8" );
char *in_p = "\xC3\xC3\xC3\xB8";
size_t in_left = 4, out_left = 4096;
char *out = malloc(out_left);
char *out_p = out;
size_t result = iconv(cd, (char **) &in_p, &in_left, (char **) &out_p, &out_left);
if(result == (size_t)-1) {
return 1;
}
return 0;
}
],[
AC_MSG_RESULT(yes)
PHP_DEFINE([ICONV_BROKEN_IGNORE],0,[ext/iconv])
AC_DEFINE([ICONV_BROKEN_IGNORE],0,[Whether iconv supports IGNORE])
],[
AC_MSG_RESULT(no)
PHP_DEFINE([ICONV_BROKEN_IGNORE],1,[ext/iconv])
AC_DEFINE([ICONV_BROKEN_IGNORE],1,[Whether iconv supports IGNORE])
],[
AC_MSG_RESULT(no, cross-compiling)
PHP_DEFINE([ICONV_BROKEN_IGNORE],0,[ext/iconv])
AC_DEFINE([ICONV_BROKEN_IGNORE],0,[Whether iconv supports IGNORE])
])
AC_MSG_CHECKING([if your cpp allows macro usage in include lines])
AC_TRY_COMPILE([
#define FOO <$PHP_ICONV_H_PATH>
+30
View File
@@ -464,6 +464,24 @@ static php_iconv_err_t _php_iconv_appendc(smart_str *d, const char c, iconv_t cd
}
/* }}} */
/* {{{ */
#if ICONV_BROKEN_IGNORE
static int _php_check_ignore(const char *charset)
{
size_t clen = strlen(charset);
if (clen >= 9 && strcmp("//IGNORE", charset+clen-8) == 0) {
return 1;
}
if (clen >= 19 && strcmp("//IGNORE//TRANSLIT", charset+clen-18) == 0) {
return 1;
}
return 0;
}
#else
#define _php_check_ignore(x) (0)
#endif
/* }}} */
/* {{{ php_iconv_string()
*/
PHP_ICONV_API php_iconv_err_t php_iconv_string(const char *in_p, size_t in_len,
@@ -545,6 +563,7 @@ PHP_ICONV_API php_iconv_err_t php_iconv_string(const char *in_p, size_t in_len,
char *out_p, *out_buf, *tmp_buf;
size_t bsz, result = 0;
php_iconv_err_t retval = PHP_ICONV_ERR_SUCCESS;
int ignore_ilseq = _php_check_ignore(out_charset);
*out = NULL;
*out_len = 0;
@@ -569,6 +588,17 @@ PHP_ICONV_API php_iconv_err_t php_iconv_string(const char *in_p, size_t in_len,
result = iconv(cd, (char **) &in_p, &in_left, (char **) &out_p, &out_left);
out_size = bsz - out_left;
if (result == (size_t)(-1)) {
if (ignore_ilseq && errno == EILSEQ) {
if (in_left <= 1) {
result = 0;
} else {
errno = 0;
in_p++;
in_left--;
continue;
}
}
if (errno == E2BIG && in_left > 0) {
/* converted string is longer than out buffer */
bsz += in_len;
+27
View File
@@ -0,0 +1,27 @@
--TEST--
Bug #48147 (iconv with //IGNORE cuts the string)
--SKIPIF--
<?php extension_loaded('iconv') or die('skip iconv extension is not available'); ?>
--FILE--
<?php
$text = "aa\xC3\xC3\xC3\xB8aa";
var_dump(iconv("UTF-8", "UTF-8", $text));
var_dump(urlencode(iconv("UTF-8", "UTF-8//IGNORE", $text)));
// only invalid
var_dump(urlencode(iconv("UTF-8", "UTF-8//IGNORE", "\xC3")));
// start invalid
var_dump(urlencode(iconv("UTF-8", "UTF-8//IGNORE", "\xC3\xC3\xC3\xB8aa")));
// finish invalid
var_dump(urlencode(iconv("UTF-8", "UTF-8//IGNORE", "aa\xC3\xC3\xC3")));
?>
--EXPECTF--
Notice: iconv(): Detected an illegal character in input string in %s on line %d
bool(false)
string(10) "aa%C3%B8aa"
Notice: iconv(): Detected an incomplete multibyte character in input string in %s on line %d
string(0) ""
string(8) "%C3%B8aa"
Notice: iconv(): Detected an incomplete multibyte character in input string in %s on line %d
string(0) ""
+29 -15
View File
@@ -415,7 +415,13 @@ static void php_mcrypt_module_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{
}
}
/* }}} */
typedef enum {
RANDOM = 0,
URANDOM,
RAND
} iv_source;
static PHP_MINIT_FUNCTION(mcrypt) /* {{{ */
{
le_mcrypt = zend_register_list_destructors_ex(php_mcrypt_module_dtor, NULL, "mcrypt", module_number);
@@ -473,6 +479,9 @@ static PHP_MINIT_FUNCTION(mcrypt) /* {{{ */
php_stream_filter_register_factory("mcrypt.*", &php_mcrypt_filter_factory TSRMLS_CC);
php_stream_filter_register_factory("mdecrypt.*", &php_mcrypt_filter_factory TSRMLS_CC);
MCG(fd[RANDOM]) = -1;
MCG(fd[URANDOM]) = -1;
return SUCCESS;
}
/* }}} */
@@ -482,6 +491,14 @@ static PHP_MSHUTDOWN_FUNCTION(mcrypt) /* {{{ */
php_stream_filter_unregister_factory("mcrypt.*" TSRMLS_CC);
php_stream_filter_unregister_factory("mdecrypt.*" TSRMLS_CC);
if (MCG(fd[RANDOM]) > 0) {
close(MCG(fd[RANDOM]));
}
if (MCG(fd[URANDOM]) > 0) {
close(MCG(fd[URANDOM]));
}
UNREGISTER_INI_ENTRIES();
return SUCCESS;
}
@@ -536,12 +553,6 @@ PHP_MINFO_FUNCTION(mcrypt) /* {{{ */
}
/* }}} */
typedef enum {
RANDOM = 0,
URANDOM,
RAND
} iv_source;
/* {{{ proto resource mcrypt_module_open(string cipher, string cipher_directory, string mode, string mode_directory)
Opens the module of the algorithm and the mode to be used */
PHP_FUNCTION(mcrypt_module_open)
@@ -1403,24 +1414,27 @@ PHP_FUNCTION(mcrypt_create_iv)
}
n = size;
#else
int fd;
int *fd = &MCG(fd[source]);
size_t read_bytes = 0;
fd = open(source == RANDOM ? "/dev/random" : "/dev/urandom", O_RDONLY);
if (fd < 0) {
efree(iv);
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot open source device");
RETURN_FALSE;
if (*fd < 0) {
*fd = open(source == RANDOM ? "/dev/random" : "/dev/urandom", O_RDONLY);
if (*fd < 0) {
efree(iv);
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot open source device");
RETURN_FALSE;
}
}
while (read_bytes < size) {
n = read(fd, iv + read_bytes, size - read_bytes);
n = read(*fd, iv + read_bytes, size - read_bytes);
if (n < 0) {
break;
}
read_bytes += n;
}
n = read_bytes;
close(fd);
if (n < size) {
efree(iv);
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Could not gather sufficient random data");
+1
View File
@@ -77,6 +77,7 @@ ZEND_BEGIN_MODULE_GLOBALS(mcrypt)
int le_h;
char *modes_dir;
char *algorithms_dir;
int fd[2]; // RANDOM = 0, URANDOM = 1
ZEND_END_MODULE_GLOBALS(mcrypt)
#ifdef ZTS
+37 -23
View File
@@ -400,7 +400,7 @@ MYSQLND_METHOD(mysqlnd_conn_data, set_server_option)(MYSQLND_CONN_DATA * const c
int2store(buffer, (unsigned int) option);
ret = conn->m->simple_command(conn, COM_SET_OPTION, buffer, sizeof(buffer), PROT_EOF_PACKET, FALSE, TRUE TSRMLS_CC);
conn->m->local_tx_end(conn, this_func, ret TSRMLS_CC);
}
DBG_RETURN(ret);
@@ -464,27 +464,41 @@ mysqlnd_switch_to_ssl_if_needed(
}
#ifdef MYSQLND_SSL_SUPPORTED
if ((greet_packet->server_capabilities & CLIENT_SSL) && (mysql_flags & CLIENT_SSL)) {
zend_bool verify = mysql_flags & CLIENT_SSL_VERIFY_SERVER_CERT? TRUE:FALSE;
DBG_INF("Switching to SSL");
if (!PACKET_WRITE(auth_packet, conn)) {
CONN_SET_STATE(conn, CONN_QUIT_SENT);
conn->m->send_close(conn TSRMLS_CC);
SET_CLIENT_ERROR(*conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
goto end;
}
if (mysql_flags & CLIENT_SSL) {
zend_bool server_has_ssl = (greet_packet->server_capabilities & CLIENT_SSL)? TRUE:FALSE;
if (server_has_ssl == FALSE) {
goto close_conn;
} else {
zend_bool verify = mysql_flags & CLIENT_SSL_VERIFY_SERVER_CERT? TRUE:FALSE;
DBG_INF("Switching to SSL");
if (!PACKET_WRITE(auth_packet, conn)) {
goto close_conn;
}
conn->net->data->m.set_client_option(conn->net, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, (const char *) &verify TSRMLS_CC);
conn->net->data->m.set_client_option(conn->net, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, (const char *) &verify TSRMLS_CC);
if (FAIL == conn->net->data->m.enable_ssl(conn->net TSRMLS_CC)) {
goto end;
if (FAIL == conn->net->data->m.enable_ssl(conn->net TSRMLS_CC)) {
goto end;
}
}
}
#else
auth_packet->client_flags &= ~CLIENT_SSL;
if (!PACKET_WRITE(auth_packet, conn)) {
goto close_conn;
}
#endif
ret = PASS;
end:
PACKET_FREE(auth_packet);
DBG_RETURN(ret);
close_conn:
CONN_SET_STATE(conn, CONN_QUIT_SENT);
conn->m->send_close(conn TSRMLS_CC);
SET_CLIENT_ERROR(*conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
PACKET_FREE(auth_packet);
DBG_RETURN(ret);
}
/* }}} */
@@ -1563,7 +1577,7 @@ MYSQLND_METHOD(mysqlnd_conn_data, sqlstate)(const MYSQLND_CONN_DATA * const conn
/* {{{ mysqlnd_old_escape_string */
PHPAPI ulong
PHPAPI ulong
mysqlnd_old_escape_string(char * newstr, const char * escapestr, size_t escapestr_len TSRMLS_DC)
{
DBG_ENTER("mysqlnd_old_escape_string");
@@ -1725,7 +1739,7 @@ MYSQLND_METHOD(mysqlnd_conn_data, statistic)(MYSQLND_CONN_DATA * conn, char **me
if (PASS == (ret = PACKET_READ(stats_header, conn))) {
/* will be freed by Zend, thus don't use the mnd_ allocator */
*message = estrndup(stats_header->message, stats_header->message_len);
*message = estrndup(stats_header->message, stats_header->message_len);
*message_len = stats_header->message_len;
DBG_INF(*message);
}
@@ -1851,7 +1865,7 @@ MYSQLND_METHOD(mysqlnd_conn_data, shutdown)(MYSQLND_CONN_DATA * const conn, uint
conn->m->local_tx_end(conn, this_func, ret TSRMLS_CC);
}
DBG_RETURN(ret);
DBG_RETURN(ret);
}
/* }}} */
@@ -2350,7 +2364,7 @@ MYSQLND_METHOD(mysqlnd_conn_data, set_client_option)(MYSQLND_CONN_DATA * const c
ret = FAIL;
break;
}
new_charset_name = mnd_pestrdup(value, conn->persistent);
if (!new_charset_name) {
goto oom;
@@ -2429,11 +2443,11 @@ MYSQLND_METHOD(mysqlnd_conn_data, set_client_option)(MYSQLND_CONN_DATA * const c
default:
ret = FAIL;
}
conn->m->local_tx_end(conn, this_func, ret TSRMLS_CC);
conn->m->local_tx_end(conn, this_func, ret TSRMLS_CC);
DBG_RETURN(ret);
oom:
SET_OOM_ERROR(*conn->error_info);
conn->m->local_tx_end(conn, this_func, FAIL TSRMLS_CC);
conn->m->local_tx_end(conn, this_func, FAIL TSRMLS_CC);
end:
DBG_RETURN(FAIL);
}
@@ -2510,7 +2524,7 @@ MYSQLND_METHOD(mysqlnd_conn_data, set_client_option_2d)(MYSQLND_CONN_DATA * cons
DBG_RETURN(ret);
oom:
SET_OOM_ERROR(*conn->error_info);
conn->m->local_tx_end(conn, this_func, FAIL TSRMLS_CC);
conn->m->local_tx_end(conn, this_func, FAIL TSRMLS_CC);
end:
DBG_RETURN(FAIL);
}
@@ -2551,7 +2565,7 @@ MYSQLND_METHOD(mysqlnd_conn_data, use_result)(MYSQLND_CONN_DATA * const conn TSR
conn->current_result = NULL;
} while (0);
conn->m->local_tx_end(conn, this_func, result == NULL? FAIL:PASS TSRMLS_CC);
conn->m->local_tx_end(conn, this_func, result == NULL? FAIL:PASS TSRMLS_CC);
}
DBG_RETURN(result);
@@ -2591,7 +2605,7 @@ MYSQLND_METHOD(mysqlnd_conn_data, store_result)(MYSQLND_CONN_DATA * const conn T
conn->current_result = NULL;
} while (0);
conn->m->local_tx_end(conn, this_func, result == NULL? FAIL:PASS TSRMLS_CC);
conn->m->local_tx_end(conn, this_func, result == NULL? FAIL:PASS TSRMLS_CC);
}
DBG_RETURN(result);
}
@@ -2620,7 +2634,7 @@ MYSQLND_METHOD(mysqlnd_conn_data, set_autocommit)(MYSQLND_CONN_DATA * conn, unsi
if (PASS == conn->m->local_tx_start(conn, this_func TSRMLS_CC)) {
ret = conn->m->query(conn, (mode) ? "SET AUTOCOMMIT=1":"SET AUTOCOMMIT=0", sizeof("SET AUTOCOMMIT=1") - 1 TSRMLS_CC);
conn->m->local_tx_end(conn, this_func, ret TSRMLS_CC);
conn->m->local_tx_end(conn, this_func, ret TSRMLS_CC);
}
DBG_RETURN(ret);
+9 -7
View File
@@ -1759,13 +1759,15 @@ next_target_ex:
}
} else if (block->op2_to == block->ext_to) {
/* both goto the same one - it's JMP */
/* JMPZNZ(?,L,L) -> JMP(L) */
last_op->opcode = ZEND_JMP;
SET_UNUSED(last_op->op1);
SET_UNUSED(last_op->op2);
block->op1_to = block->op2_to;
block->op2_to = NULL;
block->ext_to = NULL;
if (!(last_op->op1_type & (IS_VAR|IS_TMP_VAR))) {
/* JMPZNZ(?,L,L) -> JMP(L) */
last_op->opcode = ZEND_JMP;
SET_UNUSED(last_op->op1);
SET_UNUSED(last_op->op2);
block->op1_to = block->op2_to;
block->op2_to = NULL;
block->ext_to = NULL;
}
} else if (block->op2_to == next) {
/* jumping to next on Z - can follow to it and jump only on NZ */
/* JMPZNZ(X,L1,L2) L1: -> JMPNZ(X,L2) */
+1 -1
View File
@@ -27,7 +27,7 @@
#endif
#define ACCELERATOR_PRODUCT_NAME "Zend OPcache"
#define PHP_ZENDOPCACHE_VERSION "7.0.4-dev"
#define PHP_ZENDOPCACHE_VERSION "7.0.6-dev"
#define ACCELERATOR_VERSION PHP_ZENDOPCACHE_VERSION
/* 2 - added Profiler support, on 20010712 */
/* 3 - added support for Optimizer's encoded-only-files mode */
+18
View File
@@ -0,0 +1,18 @@
--TEST--
Bug #69549 (Memory leak with opcache.optimization_level=0xFFFFFFFF)
--INI--
opcache.enable=1
opcache.enable_cli=1
opcache.optimization_level=-1
--SKIPIF--
<?php require_once('skipif.inc'); ?>
--FILE--
<?php
$a = array(true);
if($a[0] && false) {
echo 'test';
}
echo "ok\n";
?>
--EXPECT--
ok
+2 -4
View File
@@ -5136,7 +5136,6 @@ PHP_FUNCTION(openssl_random_pseudo_bytes)
long buffer_length;
unsigned char *buffer = NULL;
zval *zstrong_result_returned = NULL;
int strong_result = 0;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|z", &buffer_length, &zstrong_result_returned) == FAILURE) {
return;
@@ -5154,7 +5153,6 @@ PHP_FUNCTION(openssl_random_pseudo_bytes)
buffer = emalloc(buffer_length + 1);
#ifdef PHP_WIN32
strong_result = 1;
/* random/urandom equivalent on Windows */
if (php_win32_get_random_bytes(buffer, (size_t) buffer_length) == FAILURE){
efree(buffer);
@@ -5164,7 +5162,7 @@ PHP_FUNCTION(openssl_random_pseudo_bytes)
RETURN_FALSE;
}
#else
if ((strong_result = RAND_pseudo_bytes(buffer, buffer_length)) < 0) {
if (RAND_bytes(buffer, buffer_length) <= 0) {
efree(buffer);
if (zstrong_result_returned) {
ZVAL_BOOL(zstrong_result_returned, 0);
@@ -5177,7 +5175,7 @@ PHP_FUNCTION(openssl_random_pseudo_bytes)
RETVAL_STRINGL((char *)buffer, buffer_length, 0);
if (zstrong_result_returned) {
ZVAL_BOOL(zstrong_result_returned, strong_result);
ZVAL_BOOL(zstrong_result_returned, 1);
}
}
/* }}} */
+36 -36
View File
@@ -198,7 +198,7 @@ ZEND_GET_MODULE(pcntl)
static void pcntl_signal_handler(int);
static void pcntl_signal_dispatch();
void php_register_signal_constants(INIT_FUNC_ARGS)
{
@@ -234,7 +234,7 @@ void php_register_signal_constants(INIT_FUNC_ARGS)
REGISTER_LONG_CONSTANT("SIGTERM", (long) SIGTERM, CONST_CS | CONST_PERSISTENT);
#ifdef SIGSTKFLT
REGISTER_LONG_CONSTANT("SIGSTKFLT",(long) SIGSTKFLT, CONST_CS | CONST_PERSISTENT);
#endif
#endif
#ifdef SIGCLD
REGISTER_LONG_CONSTANT("SIGCLD", (long) SIGCLD, CONST_CS | CONST_PERSISTENT);
#endif
@@ -484,7 +484,7 @@ static void php_pcntl_register_errno_constants(INIT_FUNC_ARGS)
}
static PHP_GINIT_FUNCTION(pcntl)
{
{
memset(pcntl_globals, 0, sizeof(*pcntl_globals));
}
@@ -547,7 +547,7 @@ PHP_FUNCTION(pcntl_fork)
PCNTL_G(last_error) = errno;
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d", errno);
}
RETURN_LONG((long) id);
}
/* }}} */
@@ -560,7 +560,7 @@ PHP_FUNCTION(pcntl_alarm)
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &seconds) == FAILURE)
return;
RETURN_LONG ((long) alarm(seconds));
}
/* }}} */
@@ -576,7 +576,7 @@ PHP_FUNCTION(pcntl_waitpid)
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lz|l", &pid, &z_status, &options) == FAILURE)
return;
convert_to_long_ex(&z_status);
status = Z_LVAL_P(z_status);
@@ -604,7 +604,7 @@ PHP_FUNCTION(pcntl_wait)
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", &z_status, &options) == FAILURE)
return;
convert_to_long_ex(&z_status);
status = Z_LVAL_P(z_status);
@@ -628,7 +628,7 @@ PHP_FUNCTION(pcntl_wait)
}
/* }}} */
/* {{{ proto bool pcntl_wifexited(int status)
/* {{{ proto bool pcntl_wifexited(int status)
Returns true if the child status code represents a successful exit */
PHP_FUNCTION(pcntl_wifexited)
{
@@ -646,7 +646,7 @@ PHP_FUNCTION(pcntl_wifexited)
}
/* }}} */
/* {{{ proto bool pcntl_wifstopped(int status)
/* {{{ proto bool pcntl_wifstopped(int status)
Returns true if the child status code represents a stopped process (WUNTRACED must have been used with waitpid) */
PHP_FUNCTION(pcntl_wifstopped)
{
@@ -664,7 +664,7 @@ PHP_FUNCTION(pcntl_wifstopped)
}
/* }}} */
/* {{{ proto bool pcntl_wifsignaled(int status)
/* {{{ proto bool pcntl_wifsignaled(int status)
Returns true if the child status code represents a process that was terminated due to a signal */
PHP_FUNCTION(pcntl_wifsignaled)
{
@@ -682,7 +682,7 @@ PHP_FUNCTION(pcntl_wifsignaled)
}
/* }}} */
/* {{{ proto int pcntl_wexitstatus(int status)
/* {{{ proto int pcntl_wexitstatus(int status)
Returns the status code of a child's exit */
PHP_FUNCTION(pcntl_wexitstatus)
{
@@ -700,7 +700,7 @@ PHP_FUNCTION(pcntl_wexitstatus)
}
/* }}} */
/* {{{ proto int pcntl_wtermsig(int status)
/* {{{ proto int pcntl_wtermsig(int status)
Returns the number of the signal that terminated the process who's status code is passed */
PHP_FUNCTION(pcntl_wtermsig)
{
@@ -718,7 +718,7 @@ PHP_FUNCTION(pcntl_wtermsig)
}
/* }}} */
/* {{{ proto int pcntl_wstopsig(int status)
/* {{{ proto int pcntl_wstopsig(int status)
Returns the number of the signal that caused the process to stop who's status code is passed */
PHP_FUNCTION(pcntl_wstopsig)
{
@@ -754,19 +754,19 @@ PHP_FUNCTION(pcntl_exec)
char *path;
int path_len;
ulong key_num;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|aa", &path, &path_len, &args, &envs) == FAILURE) {
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "p|aa", &path, &path_len, &args, &envs) == FAILURE) {
return;
}
if (ZEND_NUM_ARGS() > 1) {
/* Build argument list */
args_hash = HASH_OF(args);
argc = zend_hash_num_elements(args_hash);
argv = safe_emalloc((argc + 2), sizeof(char *), 0);
*argv = path;
for ( zend_hash_internal_pointer_reset(args_hash), current_arg = argv+1;
for ( zend_hash_internal_pointer_reset(args_hash), current_arg = argv+1;
(argi < argc && (zend_hash_get_current_data(args_hash, (void **) &element) == SUCCESS));
(argi++, current_arg++, zend_hash_move_forward(args_hash)) ) {
@@ -784,9 +784,9 @@ PHP_FUNCTION(pcntl_exec)
/* Build environment pair list */
envs_hash = HASH_OF(envs);
envc = zend_hash_num_elements(envs_hash);
envp = safe_emalloc((envc + 1), sizeof(char *), 0);
for ( zend_hash_internal_pointer_reset(envs_hash), pair = envp;
for ( zend_hash_internal_pointer_reset(envs_hash), pair = envp;
(envi < envc && (zend_hash_get_current_data(envs_hash, (void **) &element) == SUCCESS));
(envi++, pair++, zend_hash_move_forward(envs_hash)) ) {
switch (return_val = zend_hash_get_current_key_ex(envs_hash, &key, &key_length, &key_num, 0, NULL)) {
@@ -802,13 +802,13 @@ PHP_FUNCTION(pcntl_exec)
convert_to_string_ex(element);
/* Length of element + equal sign + length of key + null */
/* Length of element + equal sign + length of key + null */
pair_length = Z_STRLEN_PP(element) + key_length + 2;
*pair = emalloc(pair_length);
strlcpy(*pair, key, key_length);
strlcpy(*pair, key, key_length);
strlcat(*pair, "=", pair_length);
strlcat(*pair, Z_STRVAL_PP(element), pair_length);
/* Cleanup */
if (return_val == HASH_KEY_IS_LONG) efree(key);
}
@@ -818,7 +818,7 @@ PHP_FUNCTION(pcntl_exec)
PCNTL_G(last_error) = errno;
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error has occurred: (errno %d) %s", errno, strerror(errno));
}
/* Cleanup */
for (pair = envp; *pair != NULL; pair++) efree(*pair);
efree(envp);
@@ -831,7 +831,7 @@ PHP_FUNCTION(pcntl_exec)
}
efree(argv);
RETURN_FALSE;
}
/* }}} */
@@ -881,7 +881,7 @@ PHP_FUNCTION(pcntl_signal)
zend_hash_index_del(&PCNTL_G(php_signal_table), signo);
RETURN_TRUE;
}
if (!zend_is_callable(handle, 0, &func_name TSRMLS_CC)) {
PCNTL_G(last_error) = EINVAL;
php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s is not a callable function name error", func_name);
@@ -889,11 +889,11 @@ PHP_FUNCTION(pcntl_signal)
RETURN_FALSE;
}
efree(func_name);
/* Add the function name to our signal table */
zend_hash_index_update(&PCNTL_G(php_signal_table), signo, (void **) &handle, sizeof(zval *), (void **) &dest_handle);
if (dest_handle) zval_add_ref(dest_handle);
if (php_signal4(signo, pcntl_signal_handler, (int) restart_syscalls, 1) == SIG_ERR) {
PCNTL_G(last_error) = errno;
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error assigning signal");
@@ -1030,7 +1030,7 @@ static void pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAMETERS, int timedwait) /* {{
}
/*
* sigtimedwait and sigwaitinfo can return 0 on success on some
* sigtimedwait and sigwaitinfo can return 0 on success on some
* platforms, e.g. NetBSD
*/
if (!signo && siginfo.si_signo) {
@@ -1078,7 +1078,7 @@ static void pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAMETERS, int timedwait) /* {{
EMPTY_SWITCH_DEFAULT_CASE();
}
}
RETURN_LONG(signo);
}
/* }}} */
@@ -1108,12 +1108,12 @@ PHP_FUNCTION(pcntl_getpriority)
long who = PRIO_PROCESS;
long pid = getpid();
int pri;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ll", &pid, &who) == FAILURE) {
RETURN_FALSE;
}
/* needs to be cleared, since any returned value is valid */
/* needs to be cleared, since any returned value is valid */
errno = 0;
pri = getpriority(who, pid);
@@ -1173,7 +1173,7 @@ PHP_FUNCTION(pcntl_setpriority)
}
RETURN_FALSE;
}
RETURN_TRUE;
}
/* }}} */
@@ -1206,7 +1206,7 @@ static void pcntl_signal_handler(int signo)
{
struct php_pcntl_pending_signal *psig;
TSRMLS_FETCH();
psig = PCNTL_G(spares);
if (!psig) {
/* oops, too many signals for us to track, so we'll forget about this one */
@@ -1255,7 +1255,7 @@ void pcntl_signal_dispatch()
queue = PCNTL_G(head);
PCNTL_G(head) = NULL; /* simple stores are atomic */
/* Allocate */
while (queue) {
@@ -1282,7 +1282,7 @@ void pcntl_signal_dispatch()
/* Re-enable queue */
PCNTL_G(processing_signal_queue) = 0;
/* return signal mask to previous state */
sigprocmask(SIG_SETMASK, &old_mask, NULL);
}
+1 -1
View File
@@ -3,7 +3,7 @@
EXTENSION("pcre", "php_pcre.c", false /* never shared */,
"-Iext/pcre/pcrelib");
ADD_SOURCES("ext/pcre/pcrelib", "pcre_chartables.c pcre_ucd.c pcre_compile.c pcre_config.c pcre_exec.c pcre_fullinfo.c pcre_get.c pcre_globals.c pcre_maketables.c pcre_newline.c pcre_ord2utf8.c pcre_refcount.c pcre_study.c pcre_tables.c pcre_valid_utf8.c pcre_version.c pcre_xclass.c", "pcre");
ADD_SOURCES("ext/pcre/pcrelib", "pcre_chartables.c pcre_ucd.c pcre_compile.c pcre_config.c pcre_exec.c pcre_fullinfo.c pcre_get.c pcre_globals.c pcre_maketables.c pcre_newline.c pcre_ord2utf8.c pcre_refcount.c pcre_study.c pcre_tables.c pcre_valid_utf8.c pcre_version.c pcre_xclass.c pcre_jit_compile.c", "pcre");
ADD_DEF_FILE("ext\\pcre\\php_pcre.def");
AC_DEFINE('HAVE_BUNDLED_PCRE', 1, 'Using bundled PCRE library');
+2 -1
View File
@@ -58,7 +58,8 @@ PHP_ARG_WITH(pcre-regex,,
pcrelib/pcre_maketables.c pcrelib/pcre_newline.c \
pcrelib/pcre_ord2utf8.c pcrelib/pcre_refcount.c pcrelib/pcre_study.c \
pcrelib/pcre_tables.c pcrelib/pcre_valid_utf8.c \
pcrelib/pcre_version.c pcrelib/pcre_xclass.c"
pcrelib/pcre_version.c pcrelib/pcre_xclass.c \
pcrelib/pcre_jit_compile.c"
PHP_PCRE_CFLAGS="-DHAVE_CONFIG_H -I@ext_srcdir@/pcrelib"
PHP_NEW_EXTENSION(pcre, $pcrelib_sources php_pcre.c, no,,$PHP_PCRE_CFLAGS)
PHP_ADD_BUILD_DIR($ext_builddir/pcrelib)
+3 -3
View File
@@ -8,7 +8,7 @@ Email domain: cam.ac.uk
University of Cambridge Computing Service,
Cambridge, England.
Copyright (c) 1997-2014 University of Cambridge
Copyright (c) 1997-2015 University of Cambridge
All rights reserved
@@ -19,7 +19,7 @@ Written by: Zoltan Herczeg
Email local part: hzmester
Emain domain: freemail.hu
Copyright(c) 2010-2014 Zoltan Herczeg
Copyright(c) 2010-2015 Zoltan Herczeg
All rights reserved.
@@ -30,7 +30,7 @@ Written by: Zoltan Herczeg
Email local part: hzmester
Emain domain: freemail.hu
Copyright(c) 2009-2014 Zoltan Herczeg
Copyright(c) 2009-2015 Zoltan Herczeg
All rights reserved.
+167
View File
@@ -1,6 +1,173 @@
ChangeLog for PCRE
------------------
Version 8.37 28-April-2015
--------------------------
1. When an (*ACCEPT) is triggered inside capturing parentheses, it arranges
for those parentheses to be closed with whatever has been captured so far.
However, it was failing to mark any other groups between the hightest
capture so far and the currrent group as "unset". Thus, the ovector for
those groups contained whatever was previously there. An example is the
pattern /(x)|((*ACCEPT))/ when matched against "abcd".
2. If an assertion condition was quantified with a minimum of zero (an odd
thing to do, but it happened), SIGSEGV or other misbehaviour could occur.
3. If a pattern in pcretest input had the P (POSIX) modifier followed by an
unrecognized modifier, a crash could occur.
4. An attempt to do global matching in pcretest with a zero-length ovector
caused a crash.
5. Fixed a memory leak during matching that could occur for a subpattern
subroutine call (recursive or otherwise) if the number of captured groups
that had to be saved was greater than ten.
6. Catch a bad opcode during auto-possessification after compiling a bad UTF
string with NO_UTF_CHECK. This is a tidyup, not a bug fix, as passing bad
UTF with NO_UTF_CHECK is documented as having an undefined outcome.
7. A UTF pattern containing a "not" match of a non-ASCII character and a
subroutine reference could loop at compile time. Example: /[^\xff]((?1))/.
8. When a pattern is compiled, it remembers the highest back reference so that
when matching, if the ovector is too small, extra memory can be obtained to
use instead. A conditional subpattern whose condition is a check on a
capture having happened, such as, for example in the pattern
/^(?:(a)|b)(?(1)A|B)/, is another kind of back reference, but it was not
setting the highest backreference number. This mattered only if pcre_exec()
was called with an ovector that was too small to hold the capture, and there
was no other kind of back reference (a situation which is probably quite
rare). The effect of the bug was that the condition was always treated as
FALSE when the capture could not be consulted, leading to a incorrect
behaviour by pcre_exec(). This bug has been fixed.
9. A reference to a duplicated named group (either a back reference or a test
for being set in a conditional) that occurred in a part of the pattern where
PCRE_DUPNAMES was not set caused the amount of memory needed for the pattern
to be incorrectly calculated, leading to overwriting.
10. A mutually recursive set of back references such as (\2)(\1) caused a
segfault at study time (while trying to find the minimum matching length).
The infinite loop is now broken (with the minimum length unset, that is,
zero).
11. If an assertion that was used as a condition was quantified with a minimum
of zero, matching went wrong. In particular, if the whole group had
unlimited repetition and could match an empty string, a segfault was
likely. The pattern (?(?=0)?)+ is an example that caused this. Perl allows
assertions to be quantified, but not if they are being used as conditions,
so the above pattern is faulted by Perl. PCRE has now been changed so that
it also rejects such patterns.
12. A possessive capturing group such as (a)*+ with a minimum repeat of zero
failed to allow the zero-repeat case if pcre2_exec() was called with an
ovector too small to capture the group.
13. Fixed two bugs in pcretest that were discovered by fuzzing and reported by
Red Hat Product Security:
(a) A crash if /K and /F were both set with the option to save the compiled
pattern.
(b) Another crash if the option to print captured substrings in a callout
was combined with setting a null ovector, for example \O\C+ as a subject
string.
14. A pattern such as "((?2){0,1999}())?", which has a group containing a
forward reference repeated a large (but limited) number of times within a
repeated outer group that has a zero minimum quantifier, caused incorrect
code to be compiled, leading to the error "internal error:
previously-checked referenced subpattern not found" when an incorrect
memory address was read. This bug was reported as "heap overflow",
discovered by Kai Lu of Fortinet's FortiGuard Labs and given the CVE number
CVE-2015-2325.
23. A pattern such as "((?+1)(\1))/" containing a forward reference subroutine
call within a group that also contained a recursive back reference caused
incorrect code to be compiled. This bug was reported as "heap overflow",
discovered by Kai Lu of Fortinet's FortiGuard Labs, and given the CVE
number CVE-2015-2326.
24. Computing the size of the JIT read-only data in advance has been a source
of various issues, and new ones are still appear unfortunately. To fix
existing and future issues, size computation is eliminated from the code,
and replaced by on-demand memory allocation.
25. A pattern such as /(?i)[A-`]/, where characters in the other case are
adjacent to the end of the range, and the range contained characters with
more than one other case, caused incorrect behaviour when compiled in UTF
mode. In that example, the range a-j was left out of the class.
26. Fix JIT compilation of conditional blocks, which assertion
is converted to (*FAIL). E.g: /(?(?!))/.
27. The pattern /(?(?!)^)/ caused references to random memory. This bug was
discovered by the LLVM fuzzer.
28. The assertion (?!) is optimized to (*FAIL). This was not handled correctly
when this assertion was used as a condition, for example (?(?!)a|b). In
pcre2_match() it worked by luck; in pcre2_dfa_match() it gave an incorrect
error about an unsupported item.
29. For some types of pattern, for example /Z*(|d*){216}/, the auto-
possessification code could take exponential time to complete. A recursion
depth limit of 1000 has been imposed to limit the resources used by this
optimization.
30. A pattern such as /(*UTF)[\S\V\H]/, which contains a negated special class
such as \S in non-UCP mode, explicit wide characters (> 255) can be ignored
because \S ensures they are all in the class. The code for doing this was
interacting badly with the code for computing the amount of space needed to
compile the pattern, leading to a buffer overflow. This bug was discovered
by the LLVM fuzzer.
31. A pattern such as /((?2)+)((?1))/ which has mutual recursion nested inside
other kinds of group caused stack overflow at compile time. This bug was
discovered by the LLVM fuzzer.
32. A pattern such as /(?1)(?#?'){8}(a)/ which had a parenthesized comment
between a subroutine call and its quantifier was incorrectly compiled,
leading to buffer overflow or other errors. This bug was discovered by the
LLVM fuzzer.
33. The illegal pattern /(?(?<E>.*!.*)?)/ was not being diagnosed as missing an
assertion after (?(. The code was failing to check the character after
(?(?< for the ! or = that would indicate a lookbehind assertion. This bug
was discovered by the LLVM fuzzer.
34. A pattern such as /X((?2)()*+){2}+/ which has a possessive quantifier with
a fixed maximum following a group that contains a subroutine reference was
incorrectly compiled and could trigger buffer overflow. This bug was
discovered by the LLVM fuzzer.
35. A mutual recursion within a lookbehind assertion such as (?<=((?2))((?1)))
caused a stack overflow instead of the diagnosis of a non-fixed length
lookbehind assertion. This bug was discovered by the LLVM fuzzer.
36. The use of \K in a positive lookbehind assertion in a non-anchored pattern
(e.g. /(?<=\Ka)/) could make pcregrep loop.
37. There was a similar problem to 36 in pcretest for global matches.
38. If a greedy quantified \X was preceded by \C in UTF mode (e.g. \C\X*),
and a subsequent item in the pattern caused a non-match, backtracking over
the repeated \X did not stop, but carried on past the start of the subject,
causing reference to random memory and/or a segfault. There were also some
other cases where backtracking after \C could crash. This set of bugs was
discovered by the LLVM fuzzer.
39. The function for finding the minimum length of a matching string could take
a very long time if mutual recursion was present many times in a pattern,
for example, /((?2){73}(?2))((?1))/. A better mutual recursion detection
method has been implemented. This infelicity was discovered by the LLVM
fuzzer.
40. Static linking against the PCRE library using the pkg-config module was
failing on missing pthread symbols.
Version 8.36 26-September-2014
------------------------------
+5 -4
View File
@@ -6,7 +6,8 @@ and semantics are as close as possible to those of the Perl 5 language.
Release 8 of PCRE is distributed under the terms of the "BSD" licence, as
specified below. The documentation for PCRE, supplied in the "doc"
directory, is distributed under the same terms as the software itself.
directory, is distributed under the same terms as the software itself. The data
in the testdata directory is not copyrighted and is in the public domain.
The basic library functions are written in C and are freestanding. Also
included in the distribution is a set of C++ wrapper functions, and a
@@ -24,7 +25,7 @@ Email domain: cam.ac.uk
University of Cambridge Computing Service,
Cambridge, England.
Copyright (c) 1997-2014 University of Cambridge
Copyright (c) 1997-2015 University of Cambridge
All rights reserved.
@@ -35,7 +36,7 @@ Written by: Zoltan Herczeg
Email local part: hzmester
Emain domain: freemail.hu
Copyright(c) 2010-2014 Zoltan Herczeg
Copyright(c) 2010-2015 Zoltan Herczeg
All rights reserved.
@@ -46,7 +47,7 @@ Written by: Zoltan Herczeg
Email local part: hzmester
Emain domain: freemail.hu
Copyright(c) 2009-2014 Zoltan Herczeg
Copyright(c) 2009-2015 Zoltan Herczeg
All rights reserved.
+8
View File
@@ -1,6 +1,14 @@
News about PCRE releases
------------------------
Release 8.37 28-April-2015
--------------------------
This is bug-fix release. Note that this library (now called PCRE1) is now being
maintained for bug fixes only. New projects are advised to use the new PCRE2
libraries.
Release 8.36 26-September-2014
------------------------------
+11 -2
View File
@@ -1,7 +1,16 @@
README file for PCRE (Perl-compatible regular expression library)
-----------------------------------------------------------------
The latest release of PCRE is always available in three alternative formats
NOTE: This set of files relates to PCRE releases that use the original API,
with library names libpcre, libpcre16, and libpcre32. January 2015 saw the
first release of a new API, known as PCRE2, with release numbers starting at
10.00 and library names libpcre2-8, libpcre2-16, and libpcre2-32. The old
libraries (now called PCRE1) are still being maintained for bug fixes, but
there will be no new development. New projects are advised to use the new PCRE2
libraries.
The latest release of PCRE1 is always available in three alternative formats
from:
ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-xxx.tar.gz
@@ -990,4 +999,4 @@ pcre_xxx, one with the name pcre16_xx, and a third with the name pcre32_xxx.
Philip Hazel
Email local part: ph10
Email domain: cam.ac.uk
Last updated: 24 October 2014
Last updated: 10 February 2015
+4 -4
View File
@@ -314,7 +314,7 @@ them both to 0; an emulation function will be used. */
#define PACKAGE_NAME "PCRE"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "PCRE 8.36"
#define PACKAGE_STRING "PCRE 8.37"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "pcre"
@@ -323,7 +323,7 @@ them both to 0; an emulation function will be used. */
#define PACKAGE_URL ""
/* Define to the version of this package. */
#define PACKAGE_VERSION "8.36"
#define PACKAGE_VERSION "8.37"
/* to make a symbol visible */
/* #undef PCRECPP_EXP_DECL */
@@ -397,7 +397,7 @@ them both to 0; an emulation function will be used. */
#undef SUPPORT_GCOV
/* Define to any value to enable support for Just-In-Time compiling. */
#undef SUPPORT_JIT
#define SUPPORT_JIT
/* Define to any value to allow pcregrep to be linked with libbz2, so that it
is able to handle .bz2 files. */
@@ -439,7 +439,7 @@ them both to 0; an emulation function will be used. */
/* Version number of package */
#ifndef VERSION
#define VERSION "8.36"
#define VERSION "8.37"
#endif
/* Define to empty if `const' does not conform to ANSI C. */
+2 -2
View File
@@ -42,9 +42,9 @@ POSSIBILITY OF SUCH DAMAGE.
/* The current PCRE version information. */
#define PCRE_MAJOR 8
#define PCRE_MINOR 36
#define PCRE_MINOR 37
#define PCRE_PRERELEASE
#define PCRE_DATE 2014-09-26
#define PCRE_DATE 2015-04-28
/* When an application links to a PCRE DLL in Windows, the symbols that are
imported have to be identified as such. When building PCRE, the appropriate
+165 -84
View File
@@ -1704,6 +1704,7 @@ Arguments:
utf TRUE in UTF-8 / UTF-16 / UTF-32 mode
atend TRUE if called when the pattern is complete
cd the "compile data" structure
recurses chain of recurse_check to catch mutual recursion
Returns: the fixed length,
or -1 if there is no fixed length,
@@ -1713,10 +1714,11 @@ Returns: the fixed length,
*/
static int
find_fixedlength(pcre_uchar *code, BOOL utf, BOOL atend, compile_data *cd)
find_fixedlength(pcre_uchar *code, BOOL utf, BOOL atend, compile_data *cd,
recurse_check *recurses)
{
int length = -1;
recurse_check this_recurse;
register int branchlength = 0;
register pcre_uchar *cc = code + 1 + LINK_SIZE;
@@ -1741,7 +1743,8 @@ for (;;)
case OP_ONCE:
case OP_ONCE_NC:
case OP_COND:
d = find_fixedlength(cc + ((op == OP_CBRA)? IMM2_SIZE : 0), utf, atend, cd);
d = find_fixedlength(cc + ((op == OP_CBRA)? IMM2_SIZE : 0), utf, atend, cd,
recurses);
if (d < 0) return d;
branchlength += d;
do cc += GET(cc, 1); while (*cc == OP_ALT);
@@ -1775,7 +1778,15 @@ for (;;)
cs = ce = (pcre_uchar *)cd->start_code + GET(cc, 1); /* Start subpattern */
do ce += GET(ce, 1); while (*ce == OP_ALT); /* End subpattern */
if (cc > cs && cc < ce) return -1; /* Recursion */
d = find_fixedlength(cs + IMM2_SIZE, utf, atend, cd);
else /* Check for mutual recursion */
{
recurse_check *r = recurses;
for (r = recurses; r != NULL; r = r->prev) if (r->group == cs) break;
if (r != NULL) return -1; /* Mutual recursion */
}
this_recurse.prev = recurses;
this_recurse.group = cs;
d = find_fixedlength(cs + IMM2_SIZE, utf, atend, cd, &this_recurse);
if (d < 0) return d;
branchlength += d;
cc += 1 + LINK_SIZE;
@@ -2129,32 +2140,60 @@ for (;;)
{
case OP_CHAR:
case OP_CHARI:
case OP_NOT:
case OP_NOTI:
case OP_EXACT:
case OP_EXACTI:
case OP_NOTEXACT:
case OP_NOTEXACTI:
case OP_UPTO:
case OP_UPTOI:
case OP_NOTUPTO:
case OP_NOTUPTOI:
case OP_MINUPTO:
case OP_MINUPTOI:
case OP_NOTMINUPTO:
case OP_NOTMINUPTOI:
case OP_POSUPTO:
case OP_POSUPTOI:
case OP_NOTPOSUPTO:
case OP_NOTPOSUPTOI:
case OP_STAR:
case OP_STARI:
case OP_NOTSTAR:
case OP_NOTSTARI:
case OP_MINSTAR:
case OP_MINSTARI:
case OP_NOTMINSTAR:
case OP_NOTMINSTARI:
case OP_POSSTAR:
case OP_POSSTARI:
case OP_NOTPOSSTAR:
case OP_NOTPOSSTARI:
case OP_PLUS:
case OP_PLUSI:
case OP_NOTPLUS:
case OP_NOTPLUSI:
case OP_MINPLUS:
case OP_MINPLUSI:
case OP_NOTMINPLUS:
case OP_NOTMINPLUSI:
case OP_POSPLUS:
case OP_POSPLUSI:
case OP_NOTPOSPLUS:
case OP_NOTPOSPLUSI:
case OP_QUERY:
case OP_QUERYI:
case OP_NOTQUERY:
case OP_NOTQUERYI:
case OP_MINQUERY:
case OP_MINQUERYI:
case OP_NOTMINQUERY:
case OP_NOTMINQUERYI:
case OP_POSQUERY:
case OP_POSQUERYI:
case OP_NOTPOSQUERY:
case OP_NOTPOSQUERYI:
if (HAS_EXTRALEN(code[-1])) code += GET_EXTRALEN(code[-1]);
break;
}
@@ -2334,11 +2373,6 @@ Arguments:
Returns: TRUE if what is matched could be empty
*/
typedef struct recurse_check {
struct recurse_check *prev;
const pcre_uchar *group;
} recurse_check;
static BOOL
could_be_empty_branch(const pcre_uchar *code, const pcre_uchar *endcode,
BOOL utf, compile_data *cd, recurse_check *recurses)
@@ -2469,8 +2503,8 @@ for (code = first_significant_code(code + PRIV(OP_lengths)[*code], TRUE);
empty_branch = FALSE;
do
{
if (!empty_branch && could_be_empty_branch(code, endcode, utf, cd, NULL))
empty_branch = TRUE;
if (!empty_branch && could_be_empty_branch(code, endcode, utf, cd,
recurses)) empty_branch = TRUE;
code += GET(code, 1);
}
while (*code == OP_ALT);
@@ -3065,7 +3099,7 @@ Returns: TRUE if the auto-possessification is possible
static BOOL
compare_opcodes(const pcre_uchar *code, BOOL utf, const compile_data *cd,
const pcre_uint32 *base_list, const pcre_uchar *base_end)
const pcre_uint32 *base_list, const pcre_uchar *base_end, int *rec_limit)
{
pcre_uchar c;
pcre_uint32 list[8];
@@ -3082,6 +3116,9 @@ pcre_uint32 chr;
BOOL accepted, invert_bits;
BOOL entered_a_group = FALSE;
if (*rec_limit == 0) return FALSE;
--(*rec_limit);
/* Note: the base_list[1] contains whether the current opcode has greedy
(represented by a non-zero value) quantifier. This is a different from
other character type lists, which stores here that the character iterator
@@ -3152,7 +3189,8 @@ for(;;)
while (*next_code == OP_ALT)
{
if (!compare_opcodes(code, utf, cd, base_list, base_end)) return FALSE;
if (!compare_opcodes(code, utf, cd, base_list, base_end, rec_limit))
return FALSE;
code = next_code + 1 + LINK_SIZE;
next_code += GET(next_code, 1);
}
@@ -3172,7 +3210,7 @@ for(;;)
/* The bracket content will be checked by the
OP_BRA/OP_CBRA case above. */
next_code += 1 + LINK_SIZE;
if (!compare_opcodes(next_code, utf, cd, base_list, base_end))
if (!compare_opcodes(next_code, utf, cd, base_list, base_end, rec_limit))
return FALSE;
code += PRIV(OP_lengths)[c];
@@ -3605,11 +3643,20 @@ register pcre_uchar c;
const pcre_uchar *end;
pcre_uchar *repeat_opcode;
pcre_uint32 list[8];
int rec_limit;
for (;;)
{
c = *code;
/* When a pattern with bad UTF-8 encoding is compiled with NO_UTF_CHECK,
it may compile without complaining, but may get into a loop here if the code
pointer points to a bad value. This is, of course a documentated possibility,
when NO_UTF_CHECK is set, so it isn't a bug, but we can detect this case and
just give up on this optimization. */
if (c >= OP_TABLE_LENGTH) return;
if (c >= OP_STAR && c <= OP_TYPEPOSUPTO)
{
c -= get_repeat_base(c) - OP_STAR;
@@ -3617,7 +3664,8 @@ for (;;)
get_chr_property_list(code, utf, cd->fcc, list) : NULL;
list[1] = c == OP_STAR || c == OP_PLUS || c == OP_QUERY || c == OP_UPTO;
if (end != NULL && compare_opcodes(end, utf, cd, list, end))
rec_limit = 1000;
if (end != NULL && compare_opcodes(end, utf, cd, list, end, &rec_limit))
{
switch(c)
{
@@ -3673,7 +3721,8 @@ for (;;)
list[1] = (c & 1) == 0;
if (compare_opcodes(end, utf, cd, list, end))
rec_limit = 1000;
if (compare_opcodes(end, utf, cd, list, end, &rec_limit))
{
switch (c)
{
@@ -3947,14 +3996,14 @@ Arguments:
adjust the amount by which the group is to be moved
utf TRUE in UTF-8 / UTF-16 / UTF-32 mode
cd contains pointers to tables etc.
save_hwm the hwm forward reference pointer at the start of the group
save_hwm_offset the hwm forward reference offset at the start of the group
Returns: nothing
*/
static void
adjust_recurse(pcre_uchar *group, int adjust, BOOL utf, compile_data *cd,
pcre_uchar *save_hwm)
size_t save_hwm_offset)
{
pcre_uchar *ptr = group;
@@ -3966,7 +4015,8 @@ while ((ptr = (pcre_uchar *)find_recurse(ptr, utf)) != NULL)
/* See if this recursion is on the forward reference list. If so, adjust the
reference. */
for (hc = save_hwm; hc < cd->hwm; hc += LINK_SIZE)
for (hc = (pcre_uchar *)cd->start_workspace + save_hwm_offset; hc < cd->hwm;
hc += LINK_SIZE)
{
offset = (int)GET(hc, 0);
if (cd->start_code + offset == ptr + 1)
@@ -4171,7 +4221,11 @@ if ((options & PCRE_CASELESS) != 0)
range. Otherwise, use a recursive call to add the additional range. */
else if (oc < start && od >= start - 1) start = oc; /* Extend downwards */
else if (od > end && oc <= end + 1) end = od; /* Extend upwards */
else if (od > end && oc <= end + 1)
{
end = od; /* Extend upwards */
if (end > classbits_end) classbits_end = (end <= 0xff ? end : 0xff);
}
else n8 += add_to_class(classbits, uchardptr, options, cd, oc, od);
}
}
@@ -4411,7 +4465,7 @@ const pcre_uchar *tempptr;
const pcre_uchar *nestptr = NULL;
pcre_uchar *previous = NULL;
pcre_uchar *previous_callout = NULL;
pcre_uchar *save_hwm = NULL;
size_t save_hwm_offset = 0;
pcre_uint8 classbits[32];
/* We can fish out the UTF-8 setting once and for all into a BOOL, but we
@@ -5470,6 +5524,12 @@ for (;; ptr++)
PUT(previous, 1, (int)(code - previous));
break; /* End of class handling */
}
/* Even though any XCLASS list is now discarded, we must allow for
its memory. */
if (lengthptr != NULL)
*lengthptr += (int)(class_uchardata - class_uchardata_base);
#endif
/* If there are no characters > 255, or they are all to be included or
@@ -5870,6 +5930,7 @@ for (;; ptr++)
{
register int i;
int len = (int)(code - previous);
size_t base_hwm_offset = save_hwm_offset;
pcre_uchar *bralink = NULL;
pcre_uchar *brazeroptr = NULL;
@@ -5924,7 +5985,7 @@ for (;; ptr++)
if (repeat_max <= 1) /* Covers 0, 1, and unlimited */
{
*code = OP_END;
adjust_recurse(previous, 1, utf, cd, save_hwm);
adjust_recurse(previous, 1, utf, cd, save_hwm_offset);
memmove(previous + 1, previous, IN_UCHARS(len));
code++;
if (repeat_max == 0)
@@ -5948,7 +6009,7 @@ for (;; ptr++)
{
int offset;
*code = OP_END;
adjust_recurse(previous, 2 + LINK_SIZE, utf, cd, save_hwm);
adjust_recurse(previous, 2 + LINK_SIZE, utf, cd, save_hwm_offset);
memmove(previous + 2 + LINK_SIZE, previous, IN_UCHARS(len));
code += 2 + LINK_SIZE;
*previous++ = OP_BRAZERO + repeat_type;
@@ -6011,26 +6072,25 @@ for (;; ptr++)
for (i = 1; i < repeat_min; i++)
{
pcre_uchar *hc;
pcre_uchar *this_hwm = cd->hwm;
size_t this_hwm_offset = cd->hwm - cd->start_workspace;
memcpy(code, previous, IN_UCHARS(len));
while (cd->hwm > cd->start_workspace + cd->workspace_size -
WORK_SIZE_SAFETY_MARGIN - (this_hwm - save_hwm))
WORK_SIZE_SAFETY_MARGIN -
(this_hwm_offset - base_hwm_offset))
{
size_t save_offset = save_hwm - cd->start_workspace;
size_t this_offset = this_hwm - cd->start_workspace;
*errorcodeptr = expand_workspace(cd);
if (*errorcodeptr != 0) goto FAILED;
save_hwm = (pcre_uchar *)cd->start_workspace + save_offset;
this_hwm = (pcre_uchar *)cd->start_workspace + this_offset;
}
for (hc = save_hwm; hc < this_hwm; hc += LINK_SIZE)
for (hc = (pcre_uchar *)cd->start_workspace + base_hwm_offset;
hc < (pcre_uchar *)cd->start_workspace + this_hwm_offset;
hc += LINK_SIZE)
{
PUT(cd->hwm, 0, GET(hc, 0) + len);
cd->hwm += LINK_SIZE;
}
save_hwm = this_hwm;
base_hwm_offset = this_hwm_offset;
code += len;
}
}
@@ -6075,7 +6135,7 @@ for (;; ptr++)
else for (i = repeat_max - 1; i >= 0; i--)
{
pcre_uchar *hc;
pcre_uchar *this_hwm = cd->hwm;
size_t this_hwm_offset = cd->hwm - cd->start_workspace;
*code++ = OP_BRAZERO + repeat_type;
@@ -6097,22 +6157,21 @@ for (;; ptr++)
copying them. */
while (cd->hwm > cd->start_workspace + cd->workspace_size -
WORK_SIZE_SAFETY_MARGIN - (this_hwm - save_hwm))
WORK_SIZE_SAFETY_MARGIN -
(this_hwm_offset - base_hwm_offset))
{
size_t save_offset = save_hwm - cd->start_workspace;
size_t this_offset = this_hwm - cd->start_workspace;
*errorcodeptr = expand_workspace(cd);
if (*errorcodeptr != 0) goto FAILED;
save_hwm = (pcre_uchar *)cd->start_workspace + save_offset;
this_hwm = (pcre_uchar *)cd->start_workspace + this_offset;
}
for (hc = save_hwm; hc < this_hwm; hc += LINK_SIZE)
for (hc = (pcre_uchar *)cd->start_workspace + base_hwm_offset;
hc < (pcre_uchar *)cd->start_workspace + this_hwm_offset;
hc += LINK_SIZE)
{
PUT(cd->hwm, 0, GET(hc, 0) + len + ((i != 0)? 2+LINK_SIZE : 1));
cd->hwm += LINK_SIZE;
}
save_hwm = this_hwm;
base_hwm_offset = this_hwm_offset;
code += len;
}
@@ -6208,7 +6267,7 @@ for (;; ptr++)
{
int nlen = (int)(code - bracode);
*code = OP_END;
adjust_recurse(bracode, 1 + LINK_SIZE, utf, cd, save_hwm);
adjust_recurse(bracode, 1 + LINK_SIZE, utf, cd, save_hwm_offset);
memmove(bracode + 1 + LINK_SIZE, bracode, IN_UCHARS(nlen));
code += 1 + LINK_SIZE;
nlen += 1 + LINK_SIZE;
@@ -6342,7 +6401,7 @@ for (;; ptr++)
else
{
*code = OP_END;
adjust_recurse(tempcode, 1 + LINK_SIZE, utf, cd, save_hwm);
adjust_recurse(tempcode, 1 + LINK_SIZE, utf, cd, save_hwm_offset);
memmove(tempcode + 1 + LINK_SIZE, tempcode, IN_UCHARS(len));
code += 1 + LINK_SIZE;
len += 1 + LINK_SIZE;
@@ -6391,7 +6450,7 @@ for (;; ptr++)
default:
*code = OP_END;
adjust_recurse(tempcode, 1 + LINK_SIZE, utf, cd, save_hwm);
adjust_recurse(tempcode, 1 + LINK_SIZE, utf, cd, save_hwm_offset);
memmove(tempcode + 1 + LINK_SIZE, tempcode, IN_UCHARS(len));
code += 1 + LINK_SIZE;
len += 1 + LINK_SIZE;
@@ -6420,15 +6479,25 @@ for (;; ptr++)
parenthesis forms. */
case CHAR_LEFT_PARENTHESIS:
newoptions = options;
skipbytes = 0;
bravalue = OP_CBRA;
save_hwm = cd->hwm;
reset_bracount = FALSE;
/* First deal with various "verbs" that can be introduced by '*'. */
ptr++;
/* First deal with comments. Putting this code right at the start ensures
that comments have no bad side effects. */
if (ptr[0] == CHAR_QUESTION_MARK && ptr[1] == CHAR_NUMBER_SIGN)
{
ptr += 2;
while (*ptr != CHAR_NULL && *ptr != CHAR_RIGHT_PARENTHESIS) ptr++;
if (*ptr == CHAR_NULL)
{
*errorcodeptr = ERR18;
goto FAILED;
}
continue;
}
/* Now deal with various "verbs" that can be introduced by '*'. */
if (ptr[0] == CHAR_ASTERISK && (ptr[1] == ':'
|| (MAX_255(ptr[1]) && ((cd->ctypes[ptr[1]] & ctype_letter) != 0))))
{
@@ -6549,10 +6618,18 @@ for (;; ptr++)
goto FAILED;
}
/* Initialize for "real" parentheses */
newoptions = options;
skipbytes = 0;
bravalue = OP_CBRA;
save_hwm_offset = cd->hwm - cd->start_workspace;
reset_bracount = FALSE;
/* Deal with the extended parentheses; all are introduced by '?', and the
appearance of any of them means that this is not a capturing group. */
else if (*ptr == CHAR_QUESTION_MARK)
if (*ptr == CHAR_QUESTION_MARK)
{
int i, set, unset, namelen;
int *optset;
@@ -6561,17 +6638,6 @@ for (;; ptr++)
switch (*(++ptr))
{
case CHAR_NUMBER_SIGN: /* Comment; skip to ket */
ptr++;
while (*ptr != CHAR_NULL && *ptr != CHAR_RIGHT_PARENTHESIS) ptr++;
if (*ptr == CHAR_NULL)
{
*errorcodeptr = ERR18;
goto FAILED;
}
continue;
/* ------------------------------------------------------------ */
case CHAR_VERTICAL_LINE: /* Reset capture count for each branch */
reset_bracount = TRUE;
@@ -6620,8 +6686,13 @@ for (;; ptr++)
if (tempptr[1] == CHAR_QUESTION_MARK &&
(tempptr[2] == CHAR_EQUALS_SIGN ||
tempptr[2] == CHAR_EXCLAMATION_MARK ||
tempptr[2] == CHAR_LESS_THAN_SIGN))
(tempptr[2] == CHAR_LESS_THAN_SIGN &&
(tempptr[3] == CHAR_EQUALS_SIGN ||
tempptr[3] == CHAR_EXCLAMATION_MARK))))
{
cd->iscondassert = TRUE;
break;
}
/* Other conditions use OP_CREF/OP_DNCREF/OP_RREF/OP_DNRREF, and all
need to skip at least 1+IMM2_SIZE bytes at the start of the group. */
@@ -6698,8 +6769,7 @@ for (;; ptr++)
ptr++;
}
namelen = (int)(ptr - name);
if (lengthptr != NULL && (options & PCRE_DUPNAMES) != 0)
*lengthptr += IMM2_SIZE;
if (lengthptr != NULL) *lengthptr += IMM2_SIZE;
}
/* Check the terminator */
@@ -6735,6 +6805,7 @@ for (;; ptr++)
goto FAILED;
}
PUT2(code, 2+LINK_SIZE, recno);
if (recno > cd->top_backref) cd->top_backref = recno;
break;
}
@@ -6757,6 +6828,7 @@ for (;; ptr++)
int offset = i++;
int count = 1;
recno = GET2(slot, 0); /* Number from first found */
if (recno > cd->top_backref) cd->top_backref = recno;
for (; i < cd->names_found; i++)
{
slot += cd->name_entry_size;
@@ -7114,11 +7186,11 @@ for (;; ptr++)
if (!is_recurse) cd->namedrefcount++;
/* If duplicate names are permitted, we have to allow for a named
reference to a duplicated name (this cannot be determined until the
second pass). This needs an extra 16-bit data item. */
/* We have to allow for a named reference to a duplicated name (this
cannot be determined until the second pass). This needs an extra
16-bit data item. */
if ((options & PCRE_DUPNAMES) != 0) *lengthptr += IMM2_SIZE;
*lengthptr += IMM2_SIZE;
}
/* In the real compile, search the name table. We check the name
@@ -7475,12 +7547,22 @@ for (;; ptr++)
goto FAILED;
}
/* Assertions used not to be repeatable, but this was changed for Perl
compatibility, so all kinds can now be repeated. We copy code into a
/* All assertions used not to be repeatable, but this was changed for Perl
compatibility. All kinds can now be repeated except for assertions that are
conditions (Perl also forbids these to be repeated). We copy code into a
non-register variable (tempcode) in order to be able to pass its address
because some compilers complain otherwise. */
because some compilers complain otherwise. At the start of a conditional
group whose condition is an assertion, cd->iscondassert is set. We unset it
here so as to allow assertions later in the group to be quantified. */
if (bravalue >= OP_ASSERT && bravalue <= OP_ASSERTBACK_NOT &&
cd->iscondassert)
{
previous = NULL;
cd->iscondassert = FALSE;
}
else previous = code;
previous = code; /* For handling repetition */
*code = bravalue;
tempcode = code;
tempreqvary = cd->req_varyopt; /* Save value before bracket */
@@ -7727,7 +7809,7 @@ for (;; ptr++)
const pcre_uchar *p;
pcre_uint32 cf;
save_hwm = cd->hwm; /* Normally this is set when '(' is read */
save_hwm_offset = cd->hwm - cd->start_workspace; /* Normally this is set when '(' is read */
terminator = (*(++ptr) == CHAR_LESS_THAN_SIGN)?
CHAR_GREATER_THAN_SIGN : CHAR_APOSTROPHE;
@@ -8054,6 +8136,7 @@ int length;
unsigned int orig_bracount;
unsigned int max_bracount;
branch_chain bc;
size_t save_hwm_offset;
/* If set, call the external function that checks for stack availability. */
@@ -8071,6 +8154,8 @@ bc.current_branch = code;
firstchar = reqchar = 0;
firstcharflags = reqcharflags = REQ_UNSET;
save_hwm_offset = cd->hwm - cd->start_workspace;
/* Accumulate the length for use in the pre-compile phase. Start with the
length of the BRA and KET and any extra bytes that are required at the
beginning. We accumulate in a local variable to save frequent testing of
@@ -8212,7 +8297,7 @@ for (;;)
int fixed_length;
*code = OP_END;
fixed_length = find_fixedlength(last_branch, (options & PCRE_UTF8) != 0,
FALSE, cd);
FALSE, cd, NULL);
DPRINTF(("fixed length = %d\n", fixed_length));
if (fixed_length == -3)
{
@@ -8273,7 +8358,7 @@ for (;;)
{
*code = OP_END;
adjust_recurse(start_bracket, 1 + LINK_SIZE,
(options & PCRE_UTF8) != 0, cd, cd->hwm);
(options & PCRE_UTF8) != 0, cd, save_hwm_offset);
memmove(start_bracket + 1 + LINK_SIZE, start_bracket,
IN_UCHARS(code - start_bracket));
*start_bracket = OP_ONCE;
@@ -8497,6 +8582,7 @@ do {
case OP_RREF:
case OP_DNRREF:
case OP_DEF:
case OP_FAIL:
return FALSE;
default: /* Assertion */
@@ -9081,6 +9167,7 @@ cd->dupnames = FALSE;
cd->namedrefcount = 0;
cd->start_code = cworkspace;
cd->hwm = cworkspace;
cd->iscondassert = FALSE;
cd->start_workspace = cworkspace;
cd->workspace_size = COMPILE_WORK_SIZE;
cd->named_groups = named_groups;
@@ -9118,13 +9205,6 @@ if (length > MAX_PATTERN_SIZE)
goto PCRE_EARLY_ERROR_RETURN;
}
/* If there are groups with duplicate names and there are also references by
name, we must allow for the possibility of named references to duplicated
groups. These require an extra data item each. */
if (cd->dupnames && cd->namedrefcount > 0)
length += cd->namedrefcount * IMM2_SIZE * sizeof(pcre_uchar);
/* Compute the size of the data block for storing the compiled pattern. Integer
overflow should no longer be possible because nowadays we limit the maximum
value of cd->names_found and cd->name_entry_size. */
@@ -9183,6 +9263,7 @@ cd->name_table = (pcre_uchar *)re + re->name_table_offset;
codestart = cd->name_table + re->name_entry_size * re->name_count;
cd->start_code = codestart;
cd->hwm = (pcre_uchar *)(cd->start_workspace);
cd->iscondassert = FALSE;
cd->req_varyopt = 0;
cd->had_accept = FALSE;
cd->had_pruneorskip = FALSE;
@@ -9319,7 +9400,7 @@ if (cd->check_lookbehind)
int end_op = *be;
*be = OP_END;
fixed_length = find_fixedlength(cc, (re->options & PCRE_UTF8) != 0, TRUE,
cd);
cd, NULL);
*be = end_op;
DPRINTF(("fixed length = %d\n", fixed_length));
if (fixed_length < 0)
+95 -83
View File
@@ -1136,93 +1136,81 @@ for (;;)
printf("\n");
#endif
if (offset < md->offset_max)
if (offset >= md->offset_max) goto POSSESSIVE_NON_CAPTURE;
matched_once = FALSE;
code_offset = (int)(ecode - md->start_code);
save_offset1 = md->offset_vector[offset];
save_offset2 = md->offset_vector[offset+1];
save_offset3 = md->offset_vector[md->offset_end - number];
save_capture_last = md->capture_last;
DPRINTF(("saving %d %d %d\n", save_offset1, save_offset2, save_offset3));
/* Each time round the loop, save the current subject position for use
when the group matches. For MATCH_MATCH, the group has matched, so we
restart it with a new subject starting position, remembering that we had
at least one match. For MATCH_NOMATCH, carry on with the alternatives, as
usual. If we haven't matched any alternatives in any iteration, check to
see if a previous iteration matched. If so, the group has matched;
continue from afterwards. Otherwise it has failed; restore the previous
capture values before returning NOMATCH. */
for (;;)
{
matched_once = FALSE;
code_offset = (int)(ecode - md->start_code);
save_offset1 = md->offset_vector[offset];
save_offset2 = md->offset_vector[offset+1];
save_offset3 = md->offset_vector[md->offset_end - number];
save_capture_last = md->capture_last;
DPRINTF(("saving %d %d %d\n", save_offset1, save_offset2, save_offset3));
/* Each time round the loop, save the current subject position for use
when the group matches. For MATCH_MATCH, the group has matched, so we
restart it with a new subject starting position, remembering that we had
at least one match. For MATCH_NOMATCH, carry on with the alternatives, as
usual. If we haven't matched any alternatives in any iteration, check to
see if a previous iteration matched. If so, the group has matched;
continue from afterwards. Otherwise it has failed; restore the previous
capture values before returning NOMATCH. */
for (;;)
md->offset_vector[md->offset_end - number] =
(int)(eptr - md->start_subject);
if (op >= OP_SBRA) md->match_function_type = MATCH_CBEGROUP;
RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode], offset_top, md,
eptrb, RM63);
if (rrc == MATCH_KETRPOS)
{
md->offset_vector[md->offset_end - number] =
(int)(eptr - md->start_subject);
if (op >= OP_SBRA) md->match_function_type = MATCH_CBEGROUP;
RMATCH(eptr, ecode + PRIV(OP_lengths)[*ecode], offset_top, md,
eptrb, RM63);
if (rrc == MATCH_KETRPOS)
offset_top = md->end_offset_top;
ecode = md->start_code + code_offset;
save_capture_last = md->capture_last;
matched_once = TRUE;
mstart = md->start_match_ptr; /* In case \K changed it */
if (eptr == md->end_match_ptr) /* Matched an empty string */
{
offset_top = md->end_offset_top;
ecode = md->start_code + code_offset;
save_capture_last = md->capture_last;
matched_once = TRUE;
mstart = md->start_match_ptr; /* In case \K changed it */
if (eptr == md->end_match_ptr) /* Matched an empty string */
{
do ecode += GET(ecode, 1); while (*ecode == OP_ALT);
break;
}
eptr = md->end_match_ptr;
continue;
do ecode += GET(ecode, 1); while (*ecode == OP_ALT);
break;
}
/* See comment in the code for capturing groups above about handling
THEN. */
if (rrc == MATCH_THEN)
{
next = ecode + GET(ecode,1);
if (md->start_match_ptr < next &&
(*ecode == OP_ALT || *next == OP_ALT))
rrc = MATCH_NOMATCH;
}
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
md->capture_last = save_capture_last;
ecode += GET(ecode, 1);
if (*ecode != OP_ALT) break;
eptr = md->end_match_ptr;
continue;
}
if (!matched_once)
/* See comment in the code for capturing groups above about handling
THEN. */
if (rrc == MATCH_THEN)
{
md->offset_vector[offset] = save_offset1;
md->offset_vector[offset+1] = save_offset2;
md->offset_vector[md->offset_end - number] = save_offset3;
next = ecode + GET(ecode,1);
if (md->start_match_ptr < next &&
(*ecode == OP_ALT || *next == OP_ALT))
rrc = MATCH_NOMATCH;
}
if (allow_zero || matched_once)
{
ecode += 1 + LINK_SIZE;
break;
}
RRETURN(MATCH_NOMATCH);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
md->capture_last = save_capture_last;
ecode += GET(ecode, 1);
if (*ecode != OP_ALT) break;
}
/* FALL THROUGH ... Insufficient room for saving captured contents. Treat
as a non-capturing bracket. */
if (!matched_once)
{
md->offset_vector[offset] = save_offset1;
md->offset_vector[offset+1] = save_offset2;
md->offset_vector[md->offset_end - number] = save_offset3;
}
/* VVVVVVVVVVVVVVVVVVVVVVVVV */
/* VVVVVVVVVVVVVVVVVVVVVVVVV */
if (allow_zero || matched_once)
{
ecode += 1 + LINK_SIZE;
break;
}
DPRINTF(("insufficient capture room: treat as non-capturing\n"));
/* VVVVVVVVVVVVVVVVVVVVVVVVV */
/* VVVVVVVVVVVVVVVVVVVVVVVVV */
RRETURN(MATCH_NOMATCH);
/* Non-capturing possessive bracket with unlimited repeat. We come here
from BRAZERO with allow_zero = TRUE. The code is similar to the above,
@@ -1388,6 +1376,7 @@ for (;;)
break;
case OP_DEF: /* DEFINE - always false */
case OP_FAIL: /* From optimized (?!) condition */
break;
/* The condition is an assertion. Call match() to evaluate it - setting
@@ -1404,8 +1393,11 @@ for (;;)
condition = TRUE;
/* Advance ecode past the assertion to the start of the first branch,
but adjust it so that the general choosing code below works. */
but adjust it so that the general choosing code below works. If the
assertion has a quantifier that allows zero repeats we must skip over
the BRAZERO. This is a lunatic thing to do, but somebody did! */
if (*ecode == OP_BRAZERO) ecode++;
ecode += GET(ecode, 1);
while (*ecode == OP_ALT) ecode += GET(ecode, 1);
ecode += 1 + LINK_SIZE - PRIV(OP_lengths)[condcode];
@@ -1474,7 +1466,18 @@ for (;;)
md->offset_vector[offset] =
md->offset_vector[md->offset_end - number];
md->offset_vector[offset+1] = (int)(eptr - md->start_subject);
if (offset_top <= offset) offset_top = offset + 2;
/* If this group is at or above the current highwater mark, ensure that
any groups between the current high water mark and this group are marked
unset and then update the high water mark. */
if (offset >= offset_top)
{
register int *iptr = md->offset_vector + offset_top;
register int *iend = md->offset_vector + offset;
while (iptr < iend) *iptr++ = -1;
offset_top = offset + 2;
}
}
ecode += 1 + IMM2_SIZE;
break;
@@ -1826,7 +1829,11 @@ for (;;)
are defined in a range that can be tested for. */
if (rrc >= MATCH_BACKTRACK_MIN && rrc <= MATCH_BACKTRACK_MAX)
{
if (new_recursive.offset_save != stacksave)
(PUBL(free))(new_recursive.offset_save);
RRETURN(MATCH_NOMATCH);
}
/* Any return code other than NOMATCH is an error. */
@@ -3476,7 +3483,7 @@ for (;;)
if (possessive) continue; /* No backtracking */
for(;;)
{
if (eptr == pp) goto TAIL_RECURSE;
if (eptr <= pp) goto TAIL_RECURSE;
RMATCH(eptr, ecode, offset_top, md, eptrb, RM23);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
#ifdef SUPPORT_UCP
@@ -3897,7 +3904,7 @@ for (;;)
if (possessive) continue; /* No backtracking */
for(;;)
{
if (eptr == pp) goto TAIL_RECURSE;
if (eptr <= pp) goto TAIL_RECURSE;
RMATCH(eptr, ecode, offset_top, md, eptrb, RM30);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
eptr--;
@@ -4032,7 +4039,7 @@ for (;;)
if (possessive) continue; /* No backtracking */
for(;;)
{
if (eptr == pp) goto TAIL_RECURSE;
if (eptr <= pp) goto TAIL_RECURSE;
RMATCH(eptr, ecode, offset_top, md, eptrb, RM34);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
eptr--;
@@ -5603,7 +5610,7 @@ for (;;)
if (possessive) continue; /* No backtracking */
for(;;)
{
if (eptr == pp) goto TAIL_RECURSE;
if (eptr <= pp) goto TAIL_RECURSE;
RMATCH(eptr, ecode, offset_top, md, eptrb, RM44);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
eptr--;
@@ -5645,12 +5652,17 @@ for (;;)
if (possessive) continue; /* No backtracking */
/* We use <= pp rather than == pp to detect the start of the run while
backtracking because the use of \C in UTF mode can cause BACKCHAR to
move back past pp. This is just palliative; the use of \C in UTF mode
is fraught with danger. */
for(;;)
{
int lgb, rgb;
PCRE_PUCHAR fptr;
if (eptr == pp) goto TAIL_RECURSE; /* At start of char run */
if (eptr <= pp) goto TAIL_RECURSE; /* At start of char run */
RMATCH(eptr, ecode, offset_top, md, eptrb, RM45);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
@@ -5668,7 +5680,7 @@ for (;;)
for (;;)
{
if (eptr == pp) goto TAIL_RECURSE; /* At start of char run */
if (eptr <= pp) goto TAIL_RECURSE; /* At start of char run */
fptr = eptr - 1;
if (!utf) c = *fptr; else
{
@@ -5918,7 +5930,7 @@ for (;;)
if (possessive) continue; /* No backtracking */
for(;;)
{
if (eptr == pp) goto TAIL_RECURSE;
if (eptr <= pp) goto TAIL_RECURSE;
RMATCH(eptr, ecode, offset_top, md, eptrb, RM46);
if (rrc != MATCH_NOMATCH) RRETURN(rrc);
eptr--;
+8
View File
@@ -2450,6 +2450,7 @@ typedef struct compile_data {
BOOL had_pruneorskip; /* (*PRUNE) or (*SKIP) encountered */
BOOL check_lookbehind; /* Lookbehinds need later checking */
BOOL dupnames; /* Duplicate names exist */
BOOL iscondassert; /* Next assert is a condition */
int nltype; /* Newline type */
int nllen; /* Newline string length */
pcre_uchar nl[4]; /* Newline string when fixed length */
@@ -2463,6 +2464,13 @@ typedef struct branch_chain {
pcre_uchar *current_branch;
} branch_chain;
/* Structure for mutual recursion detection. */
typedef struct recurse_check {
struct recurse_check *prev;
const pcre_uchar *group;
} recurse_check;
/* Structure for items in a linked list that represents an explicit recursive
call within the pattern; used by pcre_exec(). */
File diff suppressed because it is too large. Load diff
+48 -12
View File
@@ -70,7 +70,7 @@ Arguments:
code pointer to start of group (the bracket)
startcode pointer to start of the whole pattern's code
options the compiling options
int RECURSE depth
recurses chain of recurse_check to catch mutual recursion
Returns: the minimum length
-1 if \C in UTF-8 mode or (*ACCEPT) was encountered
@@ -80,12 +80,13 @@ Returns: the minimum length
static int
find_minlength(const REAL_PCRE *re, const pcre_uchar *code,
const pcre_uchar *startcode, int options, int recurse_depth)
const pcre_uchar *startcode, int options, recurse_check *recurses)
{
int length = -1;
/* PCRE_UTF16 has the same value as PCRE_UTF8. */
BOOL utf = (options & PCRE_UTF8) != 0;
BOOL had_recurse = FALSE;
recurse_check this_recurse;
register int branchlength = 0;
register pcre_uchar *cc = (pcre_uchar *)code + 1 + LINK_SIZE;
@@ -130,7 +131,7 @@ for (;;)
case OP_SBRAPOS:
case OP_ONCE:
case OP_ONCE_NC:
d = find_minlength(re, cc, startcode, options, recurse_depth);
d = find_minlength(re, cc, startcode, options, recurses);
if (d < 0) return d;
branchlength += d;
do cc += GET(cc, 1); while (*cc == OP_ALT);
@@ -393,7 +394,7 @@ for (;;)
ce = cs = (pcre_uchar *)PRIV(find_bracket)(startcode, utf, GET2(slot, 0));
if (cs == NULL) return -2;
do ce += GET(ce, 1); while (*ce == OP_ALT);
if (cc > cs && cc < ce)
if (cc > cs && cc < ce) /* Simple recursion */
{
d = 0;
had_recurse = TRUE;
@@ -401,8 +402,22 @@ for (;;)
}
else
{
int dd = find_minlength(re, cs, startcode, options, recurse_depth);
if (dd < d) d = dd;
recurse_check *r = recurses;
for (r = recurses; r != NULL; r = r->prev) if (r->group == cs) break;
if (r != NULL) /* Mutual recursion */
{
d = 0;
had_recurse = TRUE;
break;
}
else
{
int dd;
this_recurse.prev = recurses;
this_recurse.group = cs;
dd = find_minlength(re, cs, startcode, options, &this_recurse);
if (dd < d) d = dd;
}
}
slot += re->name_entry_size;
}
@@ -418,14 +433,26 @@ for (;;)
ce = cs = (pcre_uchar *)PRIV(find_bracket)(startcode, utf, GET2(cc, 1));
if (cs == NULL) return -2;
do ce += GET(ce, 1); while (*ce == OP_ALT);
if (cc > cs && cc < ce)
if (cc > cs && cc < ce) /* Simple recursion */
{
d = 0;
had_recurse = TRUE;
}
else
{
d = find_minlength(re, cs, startcode, options, recurse_depth);
recurse_check *r = recurses;
for (r = recurses; r != NULL; r = r->prev) if (r->group == cs) break;
if (r != NULL) /* Mutual recursion */
{
d = 0;
had_recurse = TRUE;
}
else
{
this_recurse.prev = recurses;
this_recurse.group = cs;
d = find_minlength(re, cs, startcode, options, &this_recurse);
}
}
}
else d = 0;
@@ -474,12 +501,21 @@ for (;;)
case OP_RECURSE:
cs = ce = (pcre_uchar *)startcode + GET(cc, 1);
do ce += GET(ce, 1); while (*ce == OP_ALT);
if ((cc > cs && cc < ce) || recurse_depth > 10)
if (cc > cs && cc < ce) /* Simple recursion */
had_recurse = TRUE;
else
{
branchlength += find_minlength(re, cs, startcode, options,
recurse_depth + 1);
recurse_check *r = recurses;
for (r = recurses; r != NULL; r = r->prev) if (r->group == cs) break;
if (r != NULL) /* Mutual recursion */
had_recurse = TRUE;
else
{
this_recurse.prev = recurses;
this_recurse.group = cs;
branchlength += find_minlength(re, cs, startcode, options,
&this_recurse);
}
}
cc += 1 + LINK_SIZE;
break;
@@ -1503,7 +1539,7 @@ if ((re->options & PCRE_ANCHORED) == 0 &&
/* Find the minimum length of subject string. */
switch(min = find_minlength(re, code, code, re->options, 0))
switch(min = find_minlength(re, code, code, re->options, NULL))
{
case -2: *errorptr = "internal error: missing capturing bracket"; return NULL;
case -3: *errorptr = "internal error: opcode not recognized"; return NULL;
+126
View File
@@ -0,0 +1,126 @@
/*
* Stack-less Just-In-Time compiler
*
* Copyright 2009-2012 Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _SLJIT_CONFIG_H_
#define _SLJIT_CONFIG_H_
/* --------------------------------------------------------------------- */
/* Custom defines */
/* --------------------------------------------------------------------- */
/* Put your custom defines here. This empty section will never change
which helps maintaining patches (with diff / patch utilities). */
/* --------------------------------------------------------------------- */
/* Architecture */
/* --------------------------------------------------------------------- */
/* Architecture selection. */
/* #define SLJIT_CONFIG_X86_32 1 */
/* #define SLJIT_CONFIG_X86_64 1 */
/* #define SLJIT_CONFIG_ARM_V5 1 */
/* #define SLJIT_CONFIG_ARM_V7 1 */
/* #define SLJIT_CONFIG_ARM_THUMB2 1 */
/* #define SLJIT_CONFIG_ARM_64 1 */
/* #define SLJIT_CONFIG_PPC_32 1 */
/* #define SLJIT_CONFIG_PPC_64 1 */
/* #define SLJIT_CONFIG_MIPS_32 1 */
/* #define SLJIT_CONFIG_MIPS_64 1 */
/* #define SLJIT_CONFIG_SPARC_32 1 */
/* #define SLJIT_CONFIG_TILEGX 1 */
/* #define SLJIT_CONFIG_AUTO 1 */
/* #define SLJIT_CONFIG_UNSUPPORTED 1 */
/* --------------------------------------------------------------------- */
/* Utilities */
/* --------------------------------------------------------------------- */
/* Useful for thread-safe compiling of global functions. */
#ifndef SLJIT_UTIL_GLOBAL_LOCK
/* Enabled by default */
#define SLJIT_UTIL_GLOBAL_LOCK 1
#endif
/* Implements a stack like data structure (by using mmap / VirtualAlloc). */
#ifndef SLJIT_UTIL_STACK
/* Enabled by default */
#define SLJIT_UTIL_STACK 1
#endif
/* Single threaded application. Does not require any locks. */
#ifndef SLJIT_SINGLE_THREADED
/* Disabled by default. */
#define SLJIT_SINGLE_THREADED 0
#endif
/* --------------------------------------------------------------------- */
/* Configuration */
/* --------------------------------------------------------------------- */
/* If SLJIT_STD_MACROS_DEFINED is not defined, the application should
define SLJIT_MALLOC, SLJIT_FREE, SLJIT_MEMMOVE, and NULL. */
#ifndef SLJIT_STD_MACROS_DEFINED
/* Disabled by default. */
#define SLJIT_STD_MACROS_DEFINED 0
#endif
/* Executable code allocation:
If SLJIT_EXECUTABLE_ALLOCATOR is not defined, the application should
define both SLJIT_MALLOC_EXEC and SLJIT_FREE_EXEC. */
#ifndef SLJIT_EXECUTABLE_ALLOCATOR
/* Enabled by default. */
#define SLJIT_EXECUTABLE_ALLOCATOR 1
#endif
/* Return with error when an invalid argument is passed. */
#ifndef SLJIT_ARGUMENT_CHECKS
/* Disabled by default */
#define SLJIT_ARGUMENT_CHECKS 0
#endif
/* Debug checks (assertions, etc.). */
#ifndef SLJIT_DEBUG
/* Enabled by default */
#define SLJIT_DEBUG 1
#endif
/* Verbose operations. */
#ifndef SLJIT_VERBOSE
/* Enabled by default */
#define SLJIT_VERBOSE 1
#endif
/*
SLJIT_IS_FPU_AVAILABLE
The availability of the FPU can be controlled by SLJIT_IS_FPU_AVAILABLE.
zero value - FPU is NOT present.
nonzero value - FPU is present.
*/
/* For further configurations, see the beginning of sljitConfigInternal.h */
#endif
@@ -0,0 +1,702 @@
/*
* Stack-less Just-In-Time compiler
*
* Copyright 2009-2012 Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef _SLJIT_CONFIG_INTERNAL_H_
#define _SLJIT_CONFIG_INTERNAL_H_
/*
SLJIT defines the following architecture dependent types and macros:
Types:
sljit_sb, sljit_ub : signed and unsigned 8 bit byte
sljit_sh, sljit_uh : signed and unsigned 16 bit half-word (short) type
sljit_si, sljit_ui : signed and unsigned 32 bit integer type
sljit_sw, sljit_uw : signed and unsigned machine word, enough to store a pointer
sljit_p : unsgined pointer value (usually the same as sljit_uw, but
some 64 bit ABIs may use 32 bit pointers)
sljit_s : single precision floating point value
sljit_d : double precision floating point value
Macros for feature detection (boolean):
SLJIT_32BIT_ARCHITECTURE : 32 bit architecture
SLJIT_64BIT_ARCHITECTURE : 64 bit architecture
SLJIT_LITTLE_ENDIAN : little endian architecture
SLJIT_BIG_ENDIAN : big endian architecture
SLJIT_UNALIGNED : allows unaligned memory accesses for non-fpu operations (only!)
SLJIT_INDIRECT_CALL : see SLJIT_FUNC_OFFSET() for more information
Constants:
SLJIT_NUMBER_OF_REGISTERS : number of available registers
SLJIT_NUMBER_OF_SCRATCH_REGISTERS : number of available scratch registers
SLJIT_NUMBER_OF_SAVED_REGISTERS : number of available saved registers
SLJIT_NUMBER_OF_FLOAT_REGISTERS : number of available floating point registers
SLJIT_NUMBER_OF_SCRATCH_FLOAT_REGISTERS : number of available floating point scratch registers
SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS : number of available floating point saved registers
SLJIT_WORD_SHIFT : the shift required to apply when accessing a sljit_sw/sljit_uw array by index
SLJIT_DOUBLE_SHIFT : the shift required to apply when accessing
a double precision floating point array by index
SLJIT_SINGLE_SHIFT : the shift required to apply when accessing
a single precision floating point array by index
SLJIT_LOCALS_OFFSET : local space starting offset (SLJIT_SP + SLJIT_LOCALS_OFFSET)
SLJIT_RETURN_ADDRESS_OFFSET : a return instruction always adds this offset to the return address
Other macros:
SLJIT_CALL : C calling convention define for both calling JIT form C and C callbacks for JIT
SLJIT_W(number) : defining 64 bit constants on 64 bit architectures (compiler independent helper)
*/
/*****************/
/* Sanity check. */
/*****************/
#if !((defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) \
|| (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) \
|| (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) \
|| (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) \
|| (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2) \
|| (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) \
|| (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) \
|| (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) \
|| (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) \
|| (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) \
|| (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32) \
|| (defined SLJIT_CONFIG_TILEGX && SLJIT_CONFIG_TILEGX) \
|| (defined SLJIT_CONFIG_AUTO && SLJIT_CONFIG_AUTO) \
|| (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED))
#error "An architecture must be selected"
#endif
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) \
+ (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) \
+ (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) \
+ (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) \
+ (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2) \
+ (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) \
+ (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) \
+ (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) \
+ (defined SLJIT_CONFIG_TILEGX && SLJIT_CONFIG_TILEGX) \
+ (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) \
+ (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) \
+ (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32) \
+ (defined SLJIT_CONFIG_AUTO && SLJIT_CONFIG_AUTO) \
+ (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED) >= 2
#error "Multiple architectures are selected"
#endif
/********************************************************/
/* Automatic CPU detection (requires compiler support). */
/********************************************************/
#if (defined SLJIT_CONFIG_AUTO && SLJIT_CONFIG_AUTO)
#ifndef _WIN32
#if defined(__i386__) || defined(__i386)
#define SLJIT_CONFIG_X86_32 1
#elif defined(__x86_64__)
#define SLJIT_CONFIG_X86_64 1
#elif defined(__arm__) || defined(__ARM__)
#ifdef __thumb2__
#define SLJIT_CONFIG_ARM_THUMB2 1
#elif defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__)
#define SLJIT_CONFIG_ARM_V7 1
#else
#define SLJIT_CONFIG_ARM_V5 1
#endif
#elif defined (__aarch64__)
#define SLJIT_CONFIG_ARM_64 1
#elif defined(__ppc64__) || defined(__powerpc64__) || defined(_ARCH_PPC64) || (defined(_POWER) && defined(__64BIT__))
#define SLJIT_CONFIG_PPC_64 1
#elif defined(__ppc__) || defined(__powerpc__) || defined(_ARCH_PPC) || defined(_ARCH_PWR) || defined(_ARCH_PWR2) || defined(_POWER)
#define SLJIT_CONFIG_PPC_32 1
#elif defined(__mips__) && !defined(_LP64)
#define SLJIT_CONFIG_MIPS_32 1
#elif defined(__mips64)
#define SLJIT_CONFIG_MIPS_64 1
#elif defined(__sparc__) || defined(__sparc)
#define SLJIT_CONFIG_SPARC_32 1
#elif defined(__tilegx__)
#define SLJIT_CONFIG_TILEGX 1
#else
/* Unsupported architecture */
#define SLJIT_CONFIG_UNSUPPORTED 1
#endif
#else /* !_WIN32 */
#if defined(_M_X64) || defined(__x86_64__)
#define SLJIT_CONFIG_X86_64 1
#elif defined(_ARM_)
#define SLJIT_CONFIG_ARM_V5 1
#else
#define SLJIT_CONFIG_X86_32 1
#endif
#endif /* !WIN32 */
#endif /* SLJIT_CONFIG_AUTO */
#if (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED)
#undef SLJIT_EXECUTABLE_ALLOCATOR
#endif
/******************************/
/* CPU family type detection. */
/******************************/
#if (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) || (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) \
|| (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2)
#define SLJIT_CONFIG_ARM_32 1
#endif
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) || (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
#define SLJIT_CONFIG_X86 1
#elif (defined SLJIT_CONFIG_ARM_32 && SLJIT_CONFIG_ARM_32) || (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64)
#define SLJIT_CONFIG_ARM 1
#elif (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) || (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
#define SLJIT_CONFIG_PPC 1
#elif (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) || (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
#define SLJIT_CONFIG_MIPS 1
#elif (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32) || (defined SLJIT_CONFIG_SPARC_64 && SLJIT_CONFIG_SPARC_64)
#define SLJIT_CONFIG_SPARC 1
#endif
/**********************************/
/* External function definitions. */
/**********************************/
#if !(defined SLJIT_STD_MACROS_DEFINED && SLJIT_STD_MACROS_DEFINED)
/* These libraries are needed for the macros below. */
#include <stdlib.h>
#include <string.h>
#endif /* SLJIT_STD_MACROS_DEFINED */
/* General macros:
Note: SLJIT is designed to be independent from them as possible.
In release mode (SLJIT_DEBUG is not defined) only the following
external functions are needed:
*/
#ifndef SLJIT_MALLOC
#define SLJIT_MALLOC(size, allocator_data) malloc(size)
#endif
#ifndef SLJIT_FREE
#define SLJIT_FREE(ptr, allocator_data) free(ptr)
#endif
#ifndef SLJIT_MEMMOVE
#define SLJIT_MEMMOVE(dest, src, len) memmove(dest, src, len)
#endif
#ifndef SLJIT_ZEROMEM
#define SLJIT_ZEROMEM(dest, len) memset(dest, 0, len)
#endif
/***************************/
/* Compiler helper macros. */
/***************************/
#if !defined(SLJIT_LIKELY) && !defined(SLJIT_UNLIKELY)
#if defined(__GNUC__) && (__GNUC__ >= 3)
#define SLJIT_LIKELY(x) __builtin_expect((x), 1)
#define SLJIT_UNLIKELY(x) __builtin_expect((x), 0)
#else
#define SLJIT_LIKELY(x) (x)
#define SLJIT_UNLIKELY(x) (x)
#endif
#endif /* !defined(SLJIT_LIKELY) && !defined(SLJIT_UNLIKELY) */
#ifndef SLJIT_INLINE
/* Inline functions. Some old compilers do not support them. */
#if defined(__SUNPRO_C) && __SUNPRO_C <= 0x510
#define SLJIT_INLINE
#else
#define SLJIT_INLINE __inline
#endif
#endif /* !SLJIT_INLINE */
#ifndef SLJIT_NOINLINE
/* Not inline functions. */
#if defined(__GNUC__)
#define SLJIT_NOINLINE __attribute__ ((noinline))
#else
#define SLJIT_NOINLINE
#endif
#endif /* !SLJIT_INLINE */
#ifndef SLJIT_CONST
/* Const variables. */
#define SLJIT_CONST const
#endif
#ifndef SLJIT_UNUSED_ARG
/* Unused arguments. */
#define SLJIT_UNUSED_ARG(arg) (void)arg
#endif
/*********************************/
/* Type of public API functions. */
/*********************************/
#if (defined SLJIT_CONFIG_STATIC && SLJIT_CONFIG_STATIC)
/* Static ABI functions. For all-in-one programs. */
#if defined(__GNUC__)
/* Disable unused warnings in gcc. */
#define SLJIT_API_FUNC_ATTRIBUTE static __attribute__((unused))
#else
#define SLJIT_API_FUNC_ATTRIBUTE static
#endif
#else
#define SLJIT_API_FUNC_ATTRIBUTE
#endif /* (defined SLJIT_CONFIG_STATIC && SLJIT_CONFIG_STATIC) */
/****************************/
/* Instruction cache flush. */
/****************************/
#ifndef SLJIT_CACHE_FLUSH
#if (defined SLJIT_CONFIG_X86 && SLJIT_CONFIG_X86)
/* Not required to implement on archs with unified caches. */
#define SLJIT_CACHE_FLUSH(from, to)
#elif defined __APPLE__
/* Supported by all macs since Mac OS 10.5.
However, it does not work on non-jailbroken iOS devices,
although the compilation is successful. */
#define SLJIT_CACHE_FLUSH(from, to) \
sys_icache_invalidate((char*)(from), (char*)(to) - (char*)(from))
#elif defined __ANDROID__
/* Android lacks __clear_cache; instead, cacheflush should be used. */
#define SLJIT_CACHE_FLUSH(from, to) \
cacheflush((long)(from), (long)(to), 0)
#elif (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC)
/* The __clear_cache() implementation of GCC is a dummy function on PowerPC. */
#define SLJIT_CACHE_FLUSH(from, to) \
ppc_cache_flush((from), (to))
#elif (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
/* The __clear_cache() implementation of GCC is a dummy function on Sparc. */
#define SLJIT_CACHE_FLUSH(from, to) \
sparc_cache_flush((from), (to))
#else
/* Calls __ARM_NR_cacheflush on ARM-Linux. */
#define SLJIT_CACHE_FLUSH(from, to) \
__clear_cache((char*)(from), (char*)(to))
#endif
#endif /* !SLJIT_CACHE_FLUSH */
/******************************************************/
/* Byte/half/int/word/single/double type definitions. */
/******************************************************/
/* 8 bit byte type. */
typedef unsigned char sljit_ub;
typedef signed char sljit_sb;
/* 16 bit half-word type. */
typedef unsigned short int sljit_uh;
typedef signed short int sljit_sh;
/* 32 bit integer type. */
typedef unsigned int sljit_ui;
typedef signed int sljit_si;
/* Machine word type. Enough for storing a pointer.
32 bit for 32 bit machines.
64 bit for 64 bit machines. */
#if (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED)
/* Just to have something. */
#define SLJIT_WORD_SHIFT 0
typedef unsigned long int sljit_uw;
typedef long int sljit_sw;
#elif !(defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) \
&& !(defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) \
&& !(defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) \
&& !(defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64) \
&& !(defined SLJIT_CONFIG_TILEGX && SLJIT_CONFIG_TILEGX)
#define SLJIT_32BIT_ARCHITECTURE 1
#define SLJIT_WORD_SHIFT 2
typedef unsigned int sljit_uw;
typedef int sljit_sw;
#else
#define SLJIT_64BIT_ARCHITECTURE 1
#define SLJIT_WORD_SHIFT 3
#ifdef _WIN32
typedef unsigned __int64 sljit_uw;
typedef __int64 sljit_sw;
#else
typedef unsigned long int sljit_uw;
typedef long int sljit_sw;
#endif
#endif
typedef sljit_uw sljit_p;
/* Floating point types. */
typedef float sljit_s;
typedef double sljit_d;
/* Shift for pointer sized data. */
#define SLJIT_POINTER_SHIFT SLJIT_WORD_SHIFT
/* Shift for double precision sized data. */
#define SLJIT_DOUBLE_SHIFT 3
#define SLJIT_SINGLE_SHIFT 2
#ifndef SLJIT_W
/* Defining long constants. */
#if (defined SLJIT_64BIT_ARCHITECTURE && SLJIT_64BIT_ARCHITECTURE)
#define SLJIT_W(w) (w##ll)
#else
#define SLJIT_W(w) (w)
#endif
#endif /* !SLJIT_W */
/*************************/
/* Endianness detection. */
/*************************/
#if !defined(SLJIT_BIG_ENDIAN) && !defined(SLJIT_LITTLE_ENDIAN)
/* These macros are mostly useful for the applications. */
#if (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) \
|| (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
#ifdef __LITTLE_ENDIAN__
#define SLJIT_LITTLE_ENDIAN 1
#else
#define SLJIT_BIG_ENDIAN 1
#endif
#elif (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32) \
|| (defined SLJIT_CONFIG_MIPS_64 && SLJIT_CONFIG_MIPS_64)
#ifdef __MIPSEL__
#define SLJIT_LITTLE_ENDIAN 1
#else
#define SLJIT_BIG_ENDIAN 1
#endif
#elif (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
#define SLJIT_BIG_ENDIAN 1
#else
#define SLJIT_LITTLE_ENDIAN 1
#endif
#endif /* !defined(SLJIT_BIG_ENDIAN) && !defined(SLJIT_LITTLE_ENDIAN) */
/* Sanity check. */
#if (defined SLJIT_BIG_ENDIAN && SLJIT_BIG_ENDIAN) && (defined SLJIT_LITTLE_ENDIAN && SLJIT_LITTLE_ENDIAN)
#error "Exactly one endianness must be selected"
#endif
#if !(defined SLJIT_BIG_ENDIAN && SLJIT_BIG_ENDIAN) && !(defined SLJIT_LITTLE_ENDIAN && SLJIT_LITTLE_ENDIAN)
#error "Exactly one endianness must be selected"
#endif
#ifndef SLJIT_UNALIGNED
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32) \
|| (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) \
|| (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7) \
|| (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2) \
|| (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64) \
|| (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) \
|| (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64)
#define SLJIT_UNALIGNED 1
#endif
#endif /* !SLJIT_UNALIGNED */
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
/* Auto detect SSE2 support using CPUID.
On 64 bit x86 cpus, sse2 must be present. */
#define SLJIT_DETECT_SSE2 1
#endif
/*****************************************************************************************/
/* Calling convention of functions generated by SLJIT or called from the generated code. */
/*****************************************************************************************/
#ifndef SLJIT_CALL
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
#if defined(__GNUC__) && !defined(__APPLE__)
#define SLJIT_CALL __attribute__ ((fastcall))
#define SLJIT_X86_32_FASTCALL 1
#elif defined(_MSC_VER)
#define SLJIT_CALL __fastcall
#define SLJIT_X86_32_FASTCALL 1
#elif defined(__BORLANDC__)
#define SLJIT_CALL __msfastcall
#define SLJIT_X86_32_FASTCALL 1
#else /* Unknown compiler. */
/* The cdecl attribute is the default. */
#define SLJIT_CALL
#endif
#else /* Non x86-32 architectures. */
#define SLJIT_CALL
#endif /* SLJIT_CONFIG_X86_32 */
#endif /* !SLJIT_CALL */
#ifndef SLJIT_INDIRECT_CALL
#if ((defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) && (defined SLJIT_BIG_ENDIAN && SLJIT_BIG_ENDIAN)) \
|| ((defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32) && defined _AIX)
/* It seems certain ppc compilers use an indirect addressing for functions
which makes things complicated. */
#define SLJIT_INDIRECT_CALL 1
#endif
#endif /* SLJIT_INDIRECT_CALL */
/* The offset which needs to be substracted from the return address to
determine the next executed instruction after return. */
#ifndef SLJIT_RETURN_ADDRESS_OFFSET
#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
#define SLJIT_RETURN_ADDRESS_OFFSET 8
#else
#define SLJIT_RETURN_ADDRESS_OFFSET 0
#endif
#endif /* SLJIT_RETURN_ADDRESS_OFFSET */
/***************************************************/
/* Functions of the built-in executable allocator. */
/***************************************************/
#if (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR)
SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size);
SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr);
SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void);
#define SLJIT_MALLOC_EXEC(size) sljit_malloc_exec(size)
#define SLJIT_FREE_EXEC(ptr) sljit_free_exec(ptr)
#endif
/**********************************************/
/* Registers and locals offset determination. */
/**********************************************/
#if (defined SLJIT_CONFIG_X86_32 && SLJIT_CONFIG_X86_32)
#define SLJIT_NUMBER_OF_REGISTERS 10
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 7
#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
#define SLJIT_LOCALS_OFFSET_BASE ((2 + 4) * sizeof(sljit_sw))
#else
/* Maximum 3 arguments are passed on the stack, +1 for double alignment. */
#define SLJIT_LOCALS_OFFSET_BASE ((3 + 1 + 4) * sizeof(sljit_sw))
#endif /* SLJIT_X86_32_FASTCALL */
#elif (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64)
#ifndef _WIN64
#define SLJIT_NUMBER_OF_REGISTERS 12
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 6
#define SLJIT_LOCALS_OFFSET_BASE (sizeof(sljit_sw))
#else
#define SLJIT_NUMBER_OF_REGISTERS 12
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 8
#define SLJIT_LOCALS_OFFSET_BASE ((4 + 2) * sizeof(sljit_sw))
#endif /* _WIN64 */
#elif (defined SLJIT_CONFIG_ARM_V5 && SLJIT_CONFIG_ARM_V5) || (defined SLJIT_CONFIG_ARM_V7 && SLJIT_CONFIG_ARM_V7)
#define SLJIT_NUMBER_OF_REGISTERS 11
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 8
#define SLJIT_LOCALS_OFFSET_BASE 0
#elif (defined SLJIT_CONFIG_ARM_THUMB2 && SLJIT_CONFIG_ARM_THUMB2)
#define SLJIT_NUMBER_OF_REGISTERS 11
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 7
#define SLJIT_LOCALS_OFFSET_BASE 0
#elif (defined SLJIT_CONFIG_ARM_64 && SLJIT_CONFIG_ARM_64)
#define SLJIT_NUMBER_OF_REGISTERS 25
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 10
#define SLJIT_LOCALS_OFFSET_BASE (2 * sizeof(sljit_sw))
#elif (defined SLJIT_CONFIG_PPC && SLJIT_CONFIG_PPC)
#define SLJIT_NUMBER_OF_REGISTERS 22
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 17
#if (defined SLJIT_CONFIG_PPC_64 && SLJIT_CONFIG_PPC_64) || (defined _AIX)
#define SLJIT_LOCALS_OFFSET_BASE ((6 + 8) * sizeof(sljit_sw))
#elif (defined SLJIT_CONFIG_PPC_32 && SLJIT_CONFIG_PPC_32)
/* Add +1 for double alignment. */
#define SLJIT_LOCALS_OFFSET_BASE ((3 + 1) * sizeof(sljit_sw))
#else
#define SLJIT_LOCALS_OFFSET_BASE (3 * sizeof(sljit_sw))
#endif /* SLJIT_CONFIG_PPC_64 || _AIX */
#elif (defined SLJIT_CONFIG_MIPS && SLJIT_CONFIG_MIPS)
#define SLJIT_NUMBER_OF_REGISTERS 17
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 8
#if (defined SLJIT_CONFIG_MIPS_32 && SLJIT_CONFIG_MIPS_32)
#define SLJIT_LOCALS_OFFSET_BASE (4 * sizeof(sljit_sw))
#else
#define SLJIT_LOCALS_OFFSET_BASE 0
#endif
#elif (defined SLJIT_CONFIG_SPARC && SLJIT_CONFIG_SPARC)
#define SLJIT_NUMBER_OF_REGISTERS 18
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 14
#if (defined SLJIT_CONFIG_SPARC_32 && SLJIT_CONFIG_SPARC_32)
/* Add +1 for double alignment. */
#define SLJIT_LOCALS_OFFSET_BASE ((23 + 1) * sizeof(sljit_sw))
#endif
#elif (defined SLJIT_CONFIG_UNSUPPORTED && SLJIT_CONFIG_UNSUPPORTED)
#define SLJIT_NUMBER_OF_REGISTERS 0
#define SLJIT_NUMBER_OF_SAVED_REGISTERS 0
#define SLJIT_LOCALS_OFFSET_BASE 0
#endif
#define SLJIT_LOCALS_OFFSET (SLJIT_LOCALS_OFFSET_BASE)
#define SLJIT_NUMBER_OF_SCRATCH_REGISTERS \
(SLJIT_NUMBER_OF_REGISTERS - SLJIT_NUMBER_OF_SAVED_REGISTERS)
#define SLJIT_NUMBER_OF_FLOAT_REGISTERS 6
#if (defined SLJIT_CONFIG_X86_64 && SLJIT_CONFIG_X86_64) && (defined _WIN64)
#define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 1
#else
#define SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS 0
#endif
#define SLJIT_NUMBER_OF_SCRATCH_FLOAT_REGISTERS \
(SLJIT_NUMBER_OF_FLOAT_REGISTERS - SLJIT_NUMBER_OF_SAVED_FLOAT_REGISTERS)
/*************************************/
/* Debug and verbose related macros. */
/*************************************/
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE)
#include <stdio.h>
#endif
#if (defined SLJIT_DEBUG && SLJIT_DEBUG)
#if !defined(SLJIT_ASSERT) || !defined(SLJIT_ASSERT_STOP)
/* SLJIT_HALT_PROCESS must halt the process. */
#ifndef SLJIT_HALT_PROCESS
#include <stdlib.h>
#define SLJIT_HALT_PROCESS() \
abort();
#endif /* !SLJIT_HALT_PROCESS */
#include <stdio.h>
#endif /* !SLJIT_ASSERT || !SLJIT_ASSERT_STOP */
/* Feel free to redefine these two macros. */
#ifndef SLJIT_ASSERT
#define SLJIT_ASSERT(x) \
do { \
if (SLJIT_UNLIKELY(!(x))) { \
printf("Assertion failed at " __FILE__ ":%d\n", __LINE__); \
SLJIT_HALT_PROCESS(); \
} \
} while (0)
#endif /* !SLJIT_ASSERT */
#ifndef SLJIT_ASSERT_STOP
#define SLJIT_ASSERT_STOP() \
do { \
printf("Should never been reached " __FILE__ ":%d\n", __LINE__); \
SLJIT_HALT_PROCESS(); \
} while (0)
#endif /* !SLJIT_ASSERT_STOP */
#else /* (defined SLJIT_DEBUG && SLJIT_DEBUG) */
/* Forcing empty, but valid statements. */
#undef SLJIT_ASSERT
#undef SLJIT_ASSERT_STOP
#define SLJIT_ASSERT(x) \
do { } while (0)
#define SLJIT_ASSERT_STOP() \
do { } while (0)
#endif /* (defined SLJIT_DEBUG && SLJIT_DEBUG) */
#ifndef SLJIT_COMPILE_ASSERT
/* Should be improved eventually. */
#define SLJIT_COMPILE_ASSERT(x, description) \
SLJIT_ASSERT(x)
#endif /* !SLJIT_COMPILE_ASSERT */
#endif
+312
View File
@@ -0,0 +1,312 @@
/*
* Stack-less Just-In-Time compiler
*
* Copyright 2009-2012 Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/*
This file contains a simple executable memory allocator
It is assumed, that executable code blocks are usually medium (or sometimes
large) memory blocks, and the allocator is not too frequently called (less
optimized than other allocators). Thus, using it as a generic allocator is
not suggested.
How does it work:
Memory is allocated in continuous memory areas called chunks by alloc_chunk()
Chunk format:
[ block ][ block ] ... [ block ][ block terminator ]
All blocks and the block terminator is started with block_header. The block
header contains the size of the previous and the next block. These sizes
can also contain special values.
Block size:
0 - The block is a free_block, with a different size member.
1 - The block is a block terminator.
n - The block is used at the moment, and the value contains its size.
Previous block size:
0 - This is the first block of the memory chunk.
n - The size of the previous block.
Using these size values we can go forward or backward on the block chain.
The unused blocks are stored in a chain list pointed by free_blocks. This
list is useful if we need to find a suitable memory area when the allocator
is called.
When a block is freed, the new free block is connected to its adjacent free
blocks if possible.
[ free block ][ used block ][ free block ]
and "used block" is freed, the three blocks are connected together:
[ one big free block ]
*/
/* --------------------------------------------------------------------- */
/* System (OS) functions */
/* --------------------------------------------------------------------- */
/* 64 KByte. */
#define CHUNK_SIZE 0x10000
/*
alloc_chunk / free_chunk :
* allocate executable system memory chunks
* the size is always divisible by CHUNK_SIZE
allocator_grab_lock / allocator_release_lock :
* make the allocator thread safe
* can be empty if the OS (or the application) does not support threading
* only the allocator requires this lock, sljit is fully thread safe
as it only uses local variables
*/
#ifdef _WIN32
static SLJIT_INLINE void* alloc_chunk(sljit_uw size)
{
return VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
}
static SLJIT_INLINE void free_chunk(void* chunk, sljit_uw size)
{
SLJIT_UNUSED_ARG(size);
VirtualFree(chunk, 0, MEM_RELEASE);
}
#else
static SLJIT_INLINE void* alloc_chunk(sljit_uw size)
{
void* retval;
#ifdef MAP_ANON
retval = mmap(NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANON, -1, 0);
#else
if (dev_zero < 0) {
if (open_dev_zero())
return NULL;
}
retval = mmap(NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE, dev_zero, 0);
#endif
return (retval != MAP_FAILED) ? retval : NULL;
}
static SLJIT_INLINE void free_chunk(void* chunk, sljit_uw size)
{
munmap(chunk, size);
}
#endif
/* --------------------------------------------------------------------- */
/* Common functions */
/* --------------------------------------------------------------------- */
#define CHUNK_MASK (~(CHUNK_SIZE - 1))
struct block_header {
sljit_uw size;
sljit_uw prev_size;
};
struct free_block {
struct block_header header;
struct free_block *next;
struct free_block *prev;
sljit_uw size;
};
#define AS_BLOCK_HEADER(base, offset) \
((struct block_header*)(((sljit_ub*)base) + offset))
#define AS_FREE_BLOCK(base, offset) \
((struct free_block*)(((sljit_ub*)base) + offset))
#define MEM_START(base) ((void*)(((sljit_ub*)base) + sizeof(struct block_header)))
#define ALIGN_SIZE(size) (((size) + sizeof(struct block_header) + 7) & ~7)
static struct free_block* free_blocks;
static sljit_uw allocated_size;
static sljit_uw total_size;
static SLJIT_INLINE void sljit_insert_free_block(struct free_block *free_block, sljit_uw size)
{
free_block->header.size = 0;
free_block->size = size;
free_block->next = free_blocks;
free_block->prev = 0;
if (free_blocks)
free_blocks->prev = free_block;
free_blocks = free_block;
}
static SLJIT_INLINE void sljit_remove_free_block(struct free_block *free_block)
{
if (free_block->next)
free_block->next->prev = free_block->prev;
if (free_block->prev)
free_block->prev->next = free_block->next;
else {
SLJIT_ASSERT(free_blocks == free_block);
free_blocks = free_block->next;
}
}
SLJIT_API_FUNC_ATTRIBUTE void* sljit_malloc_exec(sljit_uw size)
{
struct block_header *header;
struct block_header *next_header;
struct free_block *free_block;
sljit_uw chunk_size;
allocator_grab_lock();
if (size < sizeof(struct free_block))
size = sizeof(struct free_block);
size = ALIGN_SIZE(size);
free_block = free_blocks;
while (free_block) {
if (free_block->size >= size) {
chunk_size = free_block->size;
if (chunk_size > size + 64) {
/* We just cut a block from the end of the free block. */
chunk_size -= size;
free_block->size = chunk_size;
header = AS_BLOCK_HEADER(free_block, chunk_size);
header->prev_size = chunk_size;
AS_BLOCK_HEADER(header, size)->prev_size = size;
}
else {
sljit_remove_free_block(free_block);
header = (struct block_header*)free_block;
size = chunk_size;
}
allocated_size += size;
header->size = size;
allocator_release_lock();
return MEM_START(header);
}
free_block = free_block->next;
}
chunk_size = (size + sizeof(struct block_header) + CHUNK_SIZE - 1) & CHUNK_MASK;
header = (struct block_header*)alloc_chunk(chunk_size);
if (!header) {
allocator_release_lock();
return NULL;
}
chunk_size -= sizeof(struct block_header);
total_size += chunk_size;
header->prev_size = 0;
if (chunk_size > size + 64) {
/* Cut the allocated space into a free and a used block. */
allocated_size += size;
header->size = size;
chunk_size -= size;
free_block = AS_FREE_BLOCK(header, size);
free_block->header.prev_size = size;
sljit_insert_free_block(free_block, chunk_size);
next_header = AS_BLOCK_HEADER(free_block, chunk_size);
}
else {
/* All space belongs to this allocation. */
allocated_size += chunk_size;
header->size = chunk_size;
next_header = AS_BLOCK_HEADER(header, chunk_size);
}
next_header->size = 1;
next_header->prev_size = chunk_size;
allocator_release_lock();
return MEM_START(header);
}
SLJIT_API_FUNC_ATTRIBUTE void sljit_free_exec(void* ptr)
{
struct block_header *header;
struct free_block* free_block;
allocator_grab_lock();
header = AS_BLOCK_HEADER(ptr, -(sljit_sw)sizeof(struct block_header));
allocated_size -= header->size;
/* Connecting free blocks together if possible. */
/* If header->prev_size == 0, free_block will equal to header.
In this case, free_block->header.size will be > 0. */
free_block = AS_FREE_BLOCK(header, -(sljit_sw)header->prev_size);
if (SLJIT_UNLIKELY(!free_block->header.size)) {
free_block->size += header->size;
header = AS_BLOCK_HEADER(free_block, free_block->size);
header->prev_size = free_block->size;
}
else {
free_block = (struct free_block*)header;
sljit_insert_free_block(free_block, header->size);
}
header = AS_BLOCK_HEADER(free_block, free_block->size);
if (SLJIT_UNLIKELY(!header->size)) {
free_block->size += ((struct free_block*)header)->size;
sljit_remove_free_block((struct free_block*)header);
header = AS_BLOCK_HEADER(free_block, free_block->size);
header->prev_size = free_block->size;
}
/* The whole chunk is free. */
if (SLJIT_UNLIKELY(!free_block->header.prev_size && header->size == 1)) {
/* If this block is freed, we still have (allocated_size / 2) free space. */
if (total_size - free_block->size > (allocated_size * 3 / 2)) {
total_size -= free_block->size;
sljit_remove_free_block(free_block);
free_chunk(free_block, free_block->size + sizeof(struct block_header));
}
}
allocator_release_lock();
}
SLJIT_API_FUNC_ATTRIBUTE void sljit_free_unused_memory_exec(void)
{
struct free_block* free_block;
struct free_block* next_free_block;
allocator_grab_lock();
free_block = free_blocks;
while (free_block) {
next_free_block = free_block->next;
if (!free_block->header.prev_size &&
AS_BLOCK_HEADER(free_block, free_block->size)->size == 1) {
total_size -= free_block->size;
sljit_remove_free_block(free_block);
free_chunk(free_block, free_block->size + sizeof(struct block_header));
}
free_block = next_free_block;
}
SLJIT_ASSERT((total_size && free_blocks) || (!total_size && !free_blocks));
allocator_release_lock();
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+366
View File
@@ -0,0 +1,366 @@
/*
* Stack-less Just-In-Time compiler
*
* Copyright 2009-2012 Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* mips 32-bit arch dependent functions. */
static sljit_si load_immediate(struct sljit_compiler *compiler, sljit_si dst_ar, sljit_sw imm)
{
if (!(imm & ~0xffff))
return push_inst(compiler, ORI | SA(0) | TA(dst_ar) | IMM(imm), dst_ar);
if (imm < 0 && imm >= SIMM_MIN)
return push_inst(compiler, ADDIU | SA(0) | TA(dst_ar) | IMM(imm), dst_ar);
FAIL_IF(push_inst(compiler, LUI | TA(dst_ar) | IMM(imm >> 16), dst_ar));
return (imm & 0xffff) ? push_inst(compiler, ORI | SA(dst_ar) | TA(dst_ar) | IMM(imm), dst_ar) : SLJIT_SUCCESS;
}
#define EMIT_LOGICAL(op_imm, op_norm) \
if (flags & SRC2_IMM) { \
if (op & SLJIT_SET_E) \
FAIL_IF(push_inst(compiler, op_imm | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG)); \
if (CHECK_FLAGS(SLJIT_SET_E)) \
FAIL_IF(push_inst(compiler, op_imm | S(src1) | T(dst) | IMM(src2), DR(dst))); \
} \
else { \
if (op & SLJIT_SET_E) \
FAIL_IF(push_inst(compiler, op_norm | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG)); \
if (CHECK_FLAGS(SLJIT_SET_E)) \
FAIL_IF(push_inst(compiler, op_norm | S(src1) | T(src2) | D(dst), DR(dst))); \
}
#define EMIT_SHIFT(op_imm, op_v) \
if (flags & SRC2_IMM) { \
if (op & SLJIT_SET_E) \
FAIL_IF(push_inst(compiler, op_imm | T(src1) | DA(EQUAL_FLAG) | SH_IMM(src2), EQUAL_FLAG)); \
if (CHECK_FLAGS(SLJIT_SET_E)) \
FAIL_IF(push_inst(compiler, op_imm | T(src1) | D(dst) | SH_IMM(src2), DR(dst))); \
} \
else { \
if (op & SLJIT_SET_E) \
FAIL_IF(push_inst(compiler, op_v | S(src2) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG)); \
if (CHECK_FLAGS(SLJIT_SET_E)) \
FAIL_IF(push_inst(compiler, op_v | S(src2) | T(src1) | D(dst), DR(dst))); \
}
static SLJIT_INLINE sljit_si emit_single_op(struct sljit_compiler *compiler, sljit_si op, sljit_si flags,
sljit_si dst, sljit_si src1, sljit_sw src2)
{
switch (GET_OPCODE(op)) {
case SLJIT_MOV:
case SLJIT_MOV_UI:
case SLJIT_MOV_SI:
case SLJIT_MOV_P:
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
if (dst != src2)
return push_inst(compiler, ADDU | S(src2) | TA(0) | D(dst), DR(dst));
return SLJIT_SUCCESS;
case SLJIT_MOV_UB:
case SLJIT_MOV_SB:
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
if (op == SLJIT_MOV_SB) {
#if (defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1)
return push_inst(compiler, SEB | T(src2) | D(dst), DR(dst));
#else
FAIL_IF(push_inst(compiler, SLL | T(src2) | D(dst) | SH_IMM(24), DR(dst)));
return push_inst(compiler, SRA | T(dst) | D(dst) | SH_IMM(24), DR(dst));
#endif
}
return push_inst(compiler, ANDI | S(src2) | T(dst) | IMM(0xff), DR(dst));
}
else if (dst != src2)
SLJIT_ASSERT_STOP();
return SLJIT_SUCCESS;
case SLJIT_MOV_UH:
case SLJIT_MOV_SH:
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
if (op == SLJIT_MOV_SH) {
#if (defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1)
return push_inst(compiler, SEH | T(src2) | D(dst), DR(dst));
#else
FAIL_IF(push_inst(compiler, SLL | T(src2) | D(dst) | SH_IMM(16), DR(dst)));
return push_inst(compiler, SRA | T(dst) | D(dst) | SH_IMM(16), DR(dst));
#endif
}
return push_inst(compiler, ANDI | S(src2) | T(dst) | IMM(0xffff), DR(dst));
}
else if (dst != src2)
SLJIT_ASSERT_STOP();
return SLJIT_SUCCESS;
case SLJIT_NOT:
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
if (op & SLJIT_SET_E)
FAIL_IF(push_inst(compiler, NOR | S(src2) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
if (CHECK_FLAGS(SLJIT_SET_E))
FAIL_IF(push_inst(compiler, NOR | S(src2) | T(src2) | D(dst), DR(dst)));
return SLJIT_SUCCESS;
case SLJIT_CLZ:
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
#if (defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1)
if (op & SLJIT_SET_E)
FAIL_IF(push_inst(compiler, CLZ | S(src2) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
if (CHECK_FLAGS(SLJIT_SET_E))
FAIL_IF(push_inst(compiler, CLZ | S(src2) | T(dst) | D(dst), DR(dst)));
#else
if (SLJIT_UNLIKELY(flags & UNUSED_DEST)) {
FAIL_IF(push_inst(compiler, SRL | T(src2) | DA(EQUAL_FLAG) | SH_IMM(31), EQUAL_FLAG));
return push_inst(compiler, XORI | SA(EQUAL_FLAG) | TA(EQUAL_FLAG) | IMM(1), EQUAL_FLAG);
}
/* Nearly all instructions are unmovable in the following sequence. */
FAIL_IF(push_inst(compiler, ADDU | S(src2) | TA(0) | D(TMP_REG1), DR(TMP_REG1)));
/* Check zero. */
FAIL_IF(push_inst(compiler, BEQ | S(TMP_REG1) | TA(0) | IMM(5), UNMOVABLE_INS));
FAIL_IF(push_inst(compiler, ORI | SA(0) | T(dst) | IMM(32), UNMOVABLE_INS));
FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(dst) | IMM(-1), DR(dst)));
/* Loop for searching the highest bit. */
FAIL_IF(push_inst(compiler, ADDIU | S(dst) | T(dst) | IMM(1), DR(dst)));
FAIL_IF(push_inst(compiler, BGEZ | S(TMP_REG1) | IMM(-2), UNMOVABLE_INS));
FAIL_IF(push_inst(compiler, SLL | T(TMP_REG1) | D(TMP_REG1) | SH_IMM(1), UNMOVABLE_INS));
if (op & SLJIT_SET_E)
return push_inst(compiler, ADDU | S(dst) | TA(0) | DA(EQUAL_FLAG), EQUAL_FLAG);
#endif
return SLJIT_SUCCESS;
case SLJIT_ADD:
if (flags & SRC2_IMM) {
if (op & SLJIT_SET_O) {
if (src2 >= 0)
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src1) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
else
FAIL_IF(push_inst(compiler, NOR | S(src1) | T(src1) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
}
if (op & SLJIT_SET_E)
FAIL_IF(push_inst(compiler, ADDIU | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
if (op & (SLJIT_SET_C | SLJIT_SET_O)) {
if (src2 >= 0)
FAIL_IF(push_inst(compiler, ORI | S(src1) | TA(ULESS_FLAG) | IMM(src2), ULESS_FLAG));
else {
FAIL_IF(push_inst(compiler, ADDIU | SA(0) | TA(ULESS_FLAG) | IMM(src2), ULESS_FLAG));
FAIL_IF(push_inst(compiler, OR | S(src1) | TA(ULESS_FLAG) | DA(ULESS_FLAG), ULESS_FLAG));
}
}
/* dst may be the same as src1 or src2. */
if (CHECK_FLAGS(SLJIT_SET_E))
FAIL_IF(push_inst(compiler, ADDIU | S(src1) | T(dst) | IMM(src2), DR(dst)));
}
else {
if (op & SLJIT_SET_O)
FAIL_IF(push_inst(compiler, XOR | S(src1) | T(src2) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
if (op & SLJIT_SET_E)
FAIL_IF(push_inst(compiler, ADDU | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
if (op & (SLJIT_SET_C | SLJIT_SET_O))
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src2) | DA(ULESS_FLAG), ULESS_FLAG));
/* dst may be the same as src1 or src2. */
if (CHECK_FLAGS(SLJIT_SET_E))
FAIL_IF(push_inst(compiler, ADDU | S(src1) | T(src2) | D(dst), DR(dst)));
}
/* a + b >= a | b (otherwise, the carry should be set to 1). */
if (op & (SLJIT_SET_C | SLJIT_SET_O))
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(ULESS_FLAG) | DA(ULESS_FLAG), ULESS_FLAG));
if (!(op & SLJIT_SET_O))
return SLJIT_SUCCESS;
FAIL_IF(push_inst(compiler, SLL | TA(ULESS_FLAG) | D(TMP_REG1) | SH_IMM(31), DR(TMP_REG1)));
FAIL_IF(push_inst(compiler, XOR | S(TMP_REG1) | TA(OVERFLOW_FLAG) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
FAIL_IF(push_inst(compiler, XOR | S(dst) | TA(OVERFLOW_FLAG) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
return push_inst(compiler, SLL | TA(OVERFLOW_FLAG) | DA(OVERFLOW_FLAG) | SH_IMM(31), OVERFLOW_FLAG);
case SLJIT_ADDC:
if (flags & SRC2_IMM) {
if (op & SLJIT_SET_C) {
if (src2 >= 0)
FAIL_IF(push_inst(compiler, ORI | S(src1) | TA(OVERFLOW_FLAG) | IMM(src2), OVERFLOW_FLAG));
else {
FAIL_IF(push_inst(compiler, ADDIU | SA(0) | TA(OVERFLOW_FLAG) | IMM(src2), OVERFLOW_FLAG));
FAIL_IF(push_inst(compiler, OR | S(src1) | TA(OVERFLOW_FLAG) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
}
}
FAIL_IF(push_inst(compiler, ADDIU | S(src1) | T(dst) | IMM(src2), DR(dst)));
} else {
if (op & SLJIT_SET_C)
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src2) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
/* dst may be the same as src1 or src2. */
FAIL_IF(push_inst(compiler, ADDU | S(src1) | T(src2) | D(dst), DR(dst)));
}
if (op & SLJIT_SET_C)
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(OVERFLOW_FLAG) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
FAIL_IF(push_inst(compiler, ADDU | S(dst) | TA(ULESS_FLAG) | D(dst), DR(dst)));
if (!(op & SLJIT_SET_C))
return SLJIT_SUCCESS;
/* Set ULESS_FLAG (dst == 0) && (ULESS_FLAG == 1). */
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(ULESS_FLAG) | DA(ULESS_FLAG), ULESS_FLAG));
/* Set carry flag. */
return push_inst(compiler, OR | SA(ULESS_FLAG) | TA(OVERFLOW_FLAG) | DA(ULESS_FLAG), ULESS_FLAG);
case SLJIT_SUB:
if ((flags & SRC2_IMM) && ((op & (SLJIT_SET_U | SLJIT_SET_S)) || src2 == SIMM_MIN)) {
FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(TMP_REG2) | IMM(src2), DR(TMP_REG2)));
src2 = TMP_REG2;
flags &= ~SRC2_IMM;
}
if (flags & SRC2_IMM) {
if (op & SLJIT_SET_O) {
if (src2 >= 0)
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src1) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
else
FAIL_IF(push_inst(compiler, NOR | S(src1) | T(src1) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
}
if (op & SLJIT_SET_E)
FAIL_IF(push_inst(compiler, ADDIU | S(src1) | TA(EQUAL_FLAG) | IMM(-src2), EQUAL_FLAG));
if (op & (SLJIT_SET_C | SLJIT_SET_O))
FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(ULESS_FLAG) | IMM(src2), ULESS_FLAG));
/* dst may be the same as src1 or src2. */
if (CHECK_FLAGS(SLJIT_SET_E))
FAIL_IF(push_inst(compiler, ADDIU | S(src1) | T(dst) | IMM(-src2), DR(dst)));
}
else {
if (op & SLJIT_SET_O)
FAIL_IF(push_inst(compiler, XOR | S(src1) | T(src2) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
if (op & SLJIT_SET_E)
FAIL_IF(push_inst(compiler, SUBU | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
if (op & (SLJIT_SET_U | SLJIT_SET_C | SLJIT_SET_O))
FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(ULESS_FLAG), ULESS_FLAG));
if (op & SLJIT_SET_U)
FAIL_IF(push_inst(compiler, SLTU | S(src2) | T(src1) | DA(UGREATER_FLAG), UGREATER_FLAG));
if (op & SLJIT_SET_S) {
FAIL_IF(push_inst(compiler, SLT | S(src1) | T(src2) | DA(LESS_FLAG), LESS_FLAG));
FAIL_IF(push_inst(compiler, SLT | S(src2) | T(src1) | DA(GREATER_FLAG), GREATER_FLAG));
}
/* dst may be the same as src1 or src2. */
if (CHECK_FLAGS(SLJIT_SET_E | SLJIT_SET_U | SLJIT_SET_S | SLJIT_SET_C))
FAIL_IF(push_inst(compiler, SUBU | S(src1) | T(src2) | D(dst), DR(dst)));
}
if (!(op & SLJIT_SET_O))
return SLJIT_SUCCESS;
FAIL_IF(push_inst(compiler, SLL | TA(ULESS_FLAG) | D(TMP_REG1) | SH_IMM(31), DR(TMP_REG1)));
FAIL_IF(push_inst(compiler, XOR | S(TMP_REG1) | TA(OVERFLOW_FLAG) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
FAIL_IF(push_inst(compiler, XOR | S(dst) | TA(OVERFLOW_FLAG) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
return push_inst(compiler, SRL | TA(OVERFLOW_FLAG) | DA(OVERFLOW_FLAG) | SH_IMM(31), OVERFLOW_FLAG);
case SLJIT_SUBC:
if ((flags & SRC2_IMM) && src2 == SIMM_MIN) {
FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(TMP_REG2) | IMM(src2), DR(TMP_REG2)));
src2 = TMP_REG2;
flags &= ~SRC2_IMM;
}
if (flags & SRC2_IMM) {
if (op & SLJIT_SET_C)
FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(OVERFLOW_FLAG) | IMM(src2), OVERFLOW_FLAG));
/* dst may be the same as src1 or src2. */
FAIL_IF(push_inst(compiler, ADDIU | S(src1) | T(dst) | IMM(-src2), DR(dst)));
}
else {
if (op & SLJIT_SET_C)
FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
/* dst may be the same as src1 or src2. */
FAIL_IF(push_inst(compiler, SUBU | S(src1) | T(src2) | D(dst), DR(dst)));
}
if (op & SLJIT_SET_C)
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(ULESS_FLAG) | DA(LESS_FLAG), LESS_FLAG));
FAIL_IF(push_inst(compiler, SUBU | S(dst) | TA(ULESS_FLAG) | D(dst), DR(dst)));
return (op & SLJIT_SET_C) ? push_inst(compiler, OR | SA(OVERFLOW_FLAG) | TA(LESS_FLAG) | DA(ULESS_FLAG), ULESS_FLAG) : SLJIT_SUCCESS;
case SLJIT_MUL:
SLJIT_ASSERT(!(flags & SRC2_IMM));
if (!(op & SLJIT_SET_O)) {
#if (defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1)
return push_inst(compiler, MUL | S(src1) | T(src2) | D(dst), DR(dst));
#else
FAIL_IF(push_inst(compiler, MULT | S(src1) | T(src2), MOVABLE_INS));
return push_inst(compiler, MFLO | D(dst), DR(dst));
#endif
}
FAIL_IF(push_inst(compiler, MULT | S(src1) | T(src2), MOVABLE_INS));
FAIL_IF(push_inst(compiler, MFHI | DA(ULESS_FLAG), ULESS_FLAG));
FAIL_IF(push_inst(compiler, MFLO | D(dst), DR(dst)));
FAIL_IF(push_inst(compiler, SRA | T(dst) | DA(UGREATER_FLAG) | SH_IMM(31), UGREATER_FLAG));
return push_inst(compiler, SUBU | SA(ULESS_FLAG) | TA(UGREATER_FLAG) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG);
case SLJIT_AND:
EMIT_LOGICAL(ANDI, AND);
return SLJIT_SUCCESS;
case SLJIT_OR:
EMIT_LOGICAL(ORI, OR);
return SLJIT_SUCCESS;
case SLJIT_XOR:
EMIT_LOGICAL(XORI, XOR);
return SLJIT_SUCCESS;
case SLJIT_SHL:
EMIT_SHIFT(SLL, SLLV);
return SLJIT_SUCCESS;
case SLJIT_LSHR:
EMIT_SHIFT(SRL, SRLV);
return SLJIT_SUCCESS;
case SLJIT_ASHR:
EMIT_SHIFT(SRA, SRAV);
return SLJIT_SUCCESS;
}
SLJIT_ASSERT_STOP();
return SLJIT_SUCCESS;
}
static SLJIT_INLINE sljit_si emit_const(struct sljit_compiler *compiler, sljit_si dst, sljit_sw init_value)
{
FAIL_IF(push_inst(compiler, LUI | T(dst) | IMM(init_value >> 16), DR(dst)));
return push_inst(compiler, ORI | S(dst) | T(dst) | IMM(init_value), DR(dst));
}
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_addr)
{
sljit_ins *inst = (sljit_ins*)addr;
inst[0] = (inst[0] & 0xffff0000) | ((new_addr >> 16) & 0xffff);
inst[1] = (inst[1] & 0xffff0000) | (new_addr & 0xffff);
SLJIT_CACHE_FLUSH(inst, inst + 2);
}
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant)
{
sljit_ins *inst = (sljit_ins*)addr;
inst[0] = (inst[0] & 0xffff0000) | ((new_constant >> 16) & 0xffff);
inst[1] = (inst[1] & 0xffff0000) | (new_constant & 0xffff);
SLJIT_CACHE_FLUSH(inst, inst + 2);
}
+469
View File
@@ -0,0 +1,469 @@
/*
* Stack-less Just-In-Time compiler
*
* Copyright 2009-2012 Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* mips 64-bit arch dependent functions. */
static sljit_si load_immediate(struct sljit_compiler *compiler, sljit_si dst_ar, sljit_sw imm)
{
sljit_si shift = 32;
sljit_si shift2;
sljit_si inv = 0;
sljit_ins ins;
sljit_uw uimm;
if (!(imm & ~0xffff))
return push_inst(compiler, ORI | SA(0) | TA(dst_ar) | IMM(imm), dst_ar);
if (imm < 0 && imm >= SIMM_MIN)
return push_inst(compiler, ADDIU | SA(0) | TA(dst_ar) | IMM(imm), dst_ar);
if (imm <= 0x7fffffffl && imm >= -0x80000000l) {
FAIL_IF(push_inst(compiler, LUI | TA(dst_ar) | IMM(imm >> 16), dst_ar));
return (imm & 0xffff) ? push_inst(compiler, ORI | SA(dst_ar) | TA(dst_ar) | IMM(imm), dst_ar) : SLJIT_SUCCESS;
}
/* Zero extended number. */
uimm = imm;
if (imm < 0) {
uimm = ~imm;
inv = 1;
}
while (!(uimm & 0xff00000000000000l)) {
shift -= 8;
uimm <<= 8;
}
if (!(uimm & 0xf000000000000000l)) {
shift -= 4;
uimm <<= 4;
}
if (!(uimm & 0xc000000000000000l)) {
shift -= 2;
uimm <<= 2;
}
if ((sljit_sw)uimm < 0) {
uimm >>= 1;
shift += 1;
}
SLJIT_ASSERT(((uimm & 0xc000000000000000l) == 0x4000000000000000l) && (shift > 0) && (shift <= 32));
if (inv)
uimm = ~uimm;
FAIL_IF(push_inst(compiler, LUI | TA(dst_ar) | IMM(uimm >> 48), dst_ar));
if (uimm & 0x0000ffff00000000l)
FAIL_IF(push_inst(compiler, ORI | SA(dst_ar) | TA(dst_ar) | IMM(uimm >> 32), dst_ar));
imm &= (1l << shift) - 1;
if (!(imm & ~0xffff)) {
ins = (shift == 32) ? DSLL32 : DSLL;
if (shift < 32)
ins |= SH_IMM(shift);
FAIL_IF(push_inst(compiler, ins | TA(dst_ar) | DA(dst_ar), dst_ar));
return !(imm & 0xffff) ? SLJIT_SUCCESS : push_inst(compiler, ORI | SA(dst_ar) | TA(dst_ar) | IMM(imm), dst_ar);
}
/* Double shifts needs to be performed. */
uimm <<= 32;
shift2 = shift - 16;
while (!(uimm & 0xf000000000000000l)) {
shift2 -= 4;
uimm <<= 4;
}
if (!(uimm & 0xc000000000000000l)) {
shift2 -= 2;
uimm <<= 2;
}
if (!(uimm & 0x8000000000000000l)) {
shift2--;
uimm <<= 1;
}
SLJIT_ASSERT((uimm & 0x8000000000000000l) && (shift2 > 0) && (shift2 <= 16));
FAIL_IF(push_inst(compiler, DSLL | TA(dst_ar) | DA(dst_ar) | SH_IMM(shift - shift2), dst_ar));
FAIL_IF(push_inst(compiler, ORI | SA(dst_ar) | TA(dst_ar) | IMM(uimm >> 48), dst_ar));
FAIL_IF(push_inst(compiler, DSLL | TA(dst_ar) | DA(dst_ar) | SH_IMM(shift2), dst_ar));
imm &= (1l << shift2) - 1;
return !(imm & 0xffff) ? SLJIT_SUCCESS : push_inst(compiler, ORI | SA(dst_ar) | TA(dst_ar) | IMM(imm), dst_ar);
}
#define SELECT_OP(a, b) \
(!(op & SLJIT_INT_OP) ? a : b)
#define EMIT_LOGICAL(op_imm, op_norm) \
if (flags & SRC2_IMM) { \
if (op & SLJIT_SET_E) \
FAIL_IF(push_inst(compiler, op_imm | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG)); \
if (CHECK_FLAGS(SLJIT_SET_E)) \
FAIL_IF(push_inst(compiler, op_imm | S(src1) | T(dst) | IMM(src2), DR(dst))); \
} \
else { \
if (op & SLJIT_SET_E) \
FAIL_IF(push_inst(compiler, op_norm | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG)); \
if (CHECK_FLAGS(SLJIT_SET_E)) \
FAIL_IF(push_inst(compiler, op_norm | S(src1) | T(src2) | D(dst), DR(dst))); \
}
#define EMIT_SHIFT(op_dimm, op_dimm32, op_imm, op_dv, op_v) \
if (flags & SRC2_IMM) { \
if (src2 >= 32) { \
SLJIT_ASSERT(!(op & SLJIT_INT_OP)); \
ins = op_dimm32; \
src2 -= 32; \
} \
else \
ins = (op & SLJIT_INT_OP) ? op_imm : op_dimm; \
if (op & SLJIT_SET_E) \
FAIL_IF(push_inst(compiler, ins | T(src1) | DA(EQUAL_FLAG) | SH_IMM(src2), EQUAL_FLAG)); \
if (CHECK_FLAGS(SLJIT_SET_E)) \
FAIL_IF(push_inst(compiler, ins | T(src1) | D(dst) | SH_IMM(src2), DR(dst))); \
} \
else { \
ins = (op & SLJIT_INT_OP) ? op_v : op_dv; \
if (op & SLJIT_SET_E) \
FAIL_IF(push_inst(compiler, ins | S(src2) | T(src1) | DA(EQUAL_FLAG), EQUAL_FLAG)); \
if (CHECK_FLAGS(SLJIT_SET_E)) \
FAIL_IF(push_inst(compiler, ins | S(src2) | T(src1) | D(dst), DR(dst))); \
}
static SLJIT_INLINE sljit_si emit_single_op(struct sljit_compiler *compiler, sljit_si op, sljit_si flags,
sljit_si dst, sljit_si src1, sljit_sw src2)
{
sljit_ins ins;
switch (GET_OPCODE(op)) {
case SLJIT_MOV:
case SLJIT_MOV_P:
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
if (dst != src2)
return push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(src2) | TA(0) | D(dst), DR(dst));
return SLJIT_SUCCESS;
case SLJIT_MOV_UB:
case SLJIT_MOV_SB:
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
if (op == SLJIT_MOV_SB) {
FAIL_IF(push_inst(compiler, DSLL32 | T(src2) | D(dst) | SH_IMM(24), DR(dst)));
return push_inst(compiler, DSRA32 | T(dst) | D(dst) | SH_IMM(24), DR(dst));
}
return push_inst(compiler, ANDI | S(src2) | T(dst) | IMM(0xff), DR(dst));
}
else if (dst != src2)
SLJIT_ASSERT_STOP();
return SLJIT_SUCCESS;
case SLJIT_MOV_UH:
case SLJIT_MOV_SH:
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
if (op == SLJIT_MOV_SH) {
FAIL_IF(push_inst(compiler, DSLL32 | T(src2) | D(dst) | SH_IMM(16), DR(dst)));
return push_inst(compiler, DSRA32 | T(dst) | D(dst) | SH_IMM(16), DR(dst));
}
return push_inst(compiler, ANDI | S(src2) | T(dst) | IMM(0xffff), DR(dst));
}
else if (dst != src2)
SLJIT_ASSERT_STOP();
return SLJIT_SUCCESS;
case SLJIT_MOV_UI:
SLJIT_ASSERT(!(op & SLJIT_INT_OP));
FAIL_IF(push_inst(compiler, DSLL32 | T(src2) | D(dst) | SH_IMM(0), DR(dst)));
return push_inst(compiler, DSRL32 | T(dst) | D(dst) | SH_IMM(0), DR(dst));
case SLJIT_MOV_SI:
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
return push_inst(compiler, SLL | T(src2) | D(dst) | SH_IMM(0), DR(dst));
case SLJIT_NOT:
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
if (op & SLJIT_SET_E)
FAIL_IF(push_inst(compiler, NOR | S(src2) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
if (CHECK_FLAGS(SLJIT_SET_E))
FAIL_IF(push_inst(compiler, NOR | S(src2) | T(src2) | D(dst), DR(dst)));
return SLJIT_SUCCESS;
case SLJIT_CLZ:
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
#if (defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1)
if (op & SLJIT_SET_E)
FAIL_IF(push_inst(compiler, SELECT_OP(DCLZ, CLZ) | S(src2) | TA(EQUAL_FLAG) | DA(EQUAL_FLAG), EQUAL_FLAG));
if (CHECK_FLAGS(SLJIT_SET_E))
FAIL_IF(push_inst(compiler, SELECT_OP(DCLZ, CLZ) | S(src2) | T(dst) | D(dst), DR(dst)));
#else
if (SLJIT_UNLIKELY(flags & UNUSED_DEST)) {
FAIL_IF(push_inst(compiler, SELECT_OP(DSRL32, SRL) | T(src2) | DA(EQUAL_FLAG) | SH_IMM(31), EQUAL_FLAG));
return push_inst(compiler, XORI | SA(EQUAL_FLAG) | TA(EQUAL_FLAG) | IMM(1), EQUAL_FLAG);
}
/* Nearly all instructions are unmovable in the following sequence. */
FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(src2) | TA(0) | D(TMP_REG1), DR(TMP_REG1)));
/* Check zero. */
FAIL_IF(push_inst(compiler, BEQ | S(TMP_REG1) | TA(0) | IMM(5), UNMOVABLE_INS));
FAIL_IF(push_inst(compiler, ORI | SA(0) | T(dst) | IMM((op & SLJIT_INT_OP) ? 32 : 64), UNMOVABLE_INS));
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | SA(0) | T(dst) | IMM(-1), DR(dst)));
/* Loop for searching the highest bit. */
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(dst) | T(dst) | IMM(1), DR(dst)));
FAIL_IF(push_inst(compiler, BGEZ | S(TMP_REG1) | IMM(-2), UNMOVABLE_INS));
FAIL_IF(push_inst(compiler, SELECT_OP(DSLL, SLL) | T(TMP_REG1) | D(TMP_REG1) | SH_IMM(1), UNMOVABLE_INS));
if (op & SLJIT_SET_E)
return push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(dst) | TA(0) | DA(EQUAL_FLAG), EQUAL_FLAG);
#endif
return SLJIT_SUCCESS;
case SLJIT_ADD:
if (flags & SRC2_IMM) {
if (op & SLJIT_SET_O) {
if (src2 >= 0)
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src1) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
else
FAIL_IF(push_inst(compiler, NOR | S(src1) | T(src1) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
}
if (op & SLJIT_SET_E)
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | TA(EQUAL_FLAG) | IMM(src2), EQUAL_FLAG));
if (op & (SLJIT_SET_C | SLJIT_SET_O)) {
if (src2 >= 0)
FAIL_IF(push_inst(compiler, ORI | S(src1) | TA(ULESS_FLAG) | IMM(src2), ULESS_FLAG));
else {
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | SA(0) | TA(ULESS_FLAG) | IMM(src2), ULESS_FLAG));
FAIL_IF(push_inst(compiler, OR | S(src1) | TA(ULESS_FLAG) | DA(ULESS_FLAG), ULESS_FLAG));
}
}
/* dst may be the same as src1 or src2. */
if (CHECK_FLAGS(SLJIT_SET_E))
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | T(dst) | IMM(src2), DR(dst)));
}
else {
if (op & SLJIT_SET_O)
FAIL_IF(push_inst(compiler, XOR | S(src1) | T(src2) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
if (op & SLJIT_SET_E)
FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
if (op & (SLJIT_SET_C | SLJIT_SET_O))
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src2) | DA(ULESS_FLAG), ULESS_FLAG));
/* dst may be the same as src1 or src2. */
if (CHECK_FLAGS(SLJIT_SET_E))
FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(src1) | T(src2) | D(dst), DR(dst)));
}
/* a + b >= a | b (otherwise, the carry should be set to 1). */
if (op & (SLJIT_SET_C | SLJIT_SET_O))
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(ULESS_FLAG) | DA(ULESS_FLAG), ULESS_FLAG));
if (!(op & SLJIT_SET_O))
return SLJIT_SUCCESS;
FAIL_IF(push_inst(compiler, SELECT_OP(DSLL32, SLL) | TA(ULESS_FLAG) | D(TMP_REG1) | SH_IMM(31), DR(TMP_REG1)));
FAIL_IF(push_inst(compiler, XOR | S(TMP_REG1) | TA(OVERFLOW_FLAG) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
FAIL_IF(push_inst(compiler, XOR | S(dst) | TA(OVERFLOW_FLAG) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
return push_inst(compiler, SELECT_OP(DSRL32, SLL) | TA(OVERFLOW_FLAG) | DA(OVERFLOW_FLAG) | SH_IMM(31), OVERFLOW_FLAG);
case SLJIT_ADDC:
if (flags & SRC2_IMM) {
if (op & SLJIT_SET_C) {
if (src2 >= 0)
FAIL_IF(push_inst(compiler, ORI | S(src1) | TA(OVERFLOW_FLAG) | IMM(src2), OVERFLOW_FLAG));
else {
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | SA(0) | TA(OVERFLOW_FLAG) | IMM(src2), OVERFLOW_FLAG));
FAIL_IF(push_inst(compiler, OR | S(src1) | TA(OVERFLOW_FLAG) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
}
}
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | T(dst) | IMM(src2), DR(dst)));
} else {
if (op & SLJIT_SET_C)
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src2) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
/* dst may be the same as src1 or src2. */
FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(src1) | T(src2) | D(dst), DR(dst)));
}
if (op & SLJIT_SET_C)
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(OVERFLOW_FLAG) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
FAIL_IF(push_inst(compiler, SELECT_OP(DADDU, ADDU) | S(dst) | TA(ULESS_FLAG) | D(dst), DR(dst)));
if (!(op & SLJIT_SET_C))
return SLJIT_SUCCESS;
/* Set ULESS_FLAG (dst == 0) && (ULESS_FLAG == 1). */
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(ULESS_FLAG) | DA(ULESS_FLAG), ULESS_FLAG));
/* Set carry flag. */
return push_inst(compiler, OR | SA(ULESS_FLAG) | TA(OVERFLOW_FLAG) | DA(ULESS_FLAG), ULESS_FLAG);
case SLJIT_SUB:
if ((flags & SRC2_IMM) && ((op & (SLJIT_SET_U | SLJIT_SET_S)) || src2 == SIMM_MIN)) {
FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(TMP_REG2) | IMM(src2), DR(TMP_REG2)));
src2 = TMP_REG2;
flags &= ~SRC2_IMM;
}
if (flags & SRC2_IMM) {
if (op & SLJIT_SET_O) {
if (src2 >= 0)
FAIL_IF(push_inst(compiler, OR | S(src1) | T(src1) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
else
FAIL_IF(push_inst(compiler, NOR | S(src1) | T(src1) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
}
if (op & SLJIT_SET_E)
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | TA(EQUAL_FLAG) | IMM(-src2), EQUAL_FLAG));
if (op & (SLJIT_SET_C | SLJIT_SET_O))
FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(ULESS_FLAG) | IMM(src2), ULESS_FLAG));
/* dst may be the same as src1 or src2. */
if (CHECK_FLAGS(SLJIT_SET_E))
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | T(dst) | IMM(-src2), DR(dst)));
}
else {
if (op & SLJIT_SET_O)
FAIL_IF(push_inst(compiler, XOR | S(src1) | T(src2) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
if (op & SLJIT_SET_E)
FAIL_IF(push_inst(compiler, SELECT_OP(DSUBU, SUBU) | S(src1) | T(src2) | DA(EQUAL_FLAG), EQUAL_FLAG));
if (op & (SLJIT_SET_U | SLJIT_SET_C | SLJIT_SET_O))
FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(ULESS_FLAG), ULESS_FLAG));
if (op & SLJIT_SET_U)
FAIL_IF(push_inst(compiler, SLTU | S(src2) | T(src1) | DA(UGREATER_FLAG), UGREATER_FLAG));
if (op & SLJIT_SET_S) {
FAIL_IF(push_inst(compiler, SLT | S(src1) | T(src2) | DA(LESS_FLAG), LESS_FLAG));
FAIL_IF(push_inst(compiler, SLT | S(src2) | T(src1) | DA(GREATER_FLAG), GREATER_FLAG));
}
/* dst may be the same as src1 or src2. */
if (CHECK_FLAGS(SLJIT_SET_E | SLJIT_SET_U | SLJIT_SET_S | SLJIT_SET_C))
FAIL_IF(push_inst(compiler, SELECT_OP(DSUBU, SUBU) | S(src1) | T(src2) | D(dst), DR(dst)));
}
if (!(op & SLJIT_SET_O))
return SLJIT_SUCCESS;
FAIL_IF(push_inst(compiler, SELECT_OP(DSLL32, SLL) | TA(ULESS_FLAG) | D(TMP_REG1) | SH_IMM(31), DR(TMP_REG1)));
FAIL_IF(push_inst(compiler, XOR | S(TMP_REG1) | TA(OVERFLOW_FLAG) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
FAIL_IF(push_inst(compiler, XOR | S(dst) | TA(OVERFLOW_FLAG) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
return push_inst(compiler, SELECT_OP(DSRL32, SRL) | TA(OVERFLOW_FLAG) | DA(OVERFLOW_FLAG) | SH_IMM(31), OVERFLOW_FLAG);
case SLJIT_SUBC:
if ((flags & SRC2_IMM) && src2 == SIMM_MIN) {
FAIL_IF(push_inst(compiler, ADDIU | SA(0) | T(TMP_REG2) | IMM(src2), DR(TMP_REG2)));
src2 = TMP_REG2;
flags &= ~SRC2_IMM;
}
if (flags & SRC2_IMM) {
if (op & SLJIT_SET_C)
FAIL_IF(push_inst(compiler, SLTIU | S(src1) | TA(OVERFLOW_FLAG) | IMM(src2), OVERFLOW_FLAG));
/* dst may be the same as src1 or src2. */
FAIL_IF(push_inst(compiler, SELECT_OP(DADDIU, ADDIU) | S(src1) | T(dst) | IMM(-src2), DR(dst)));
}
else {
if (op & SLJIT_SET_C)
FAIL_IF(push_inst(compiler, SLTU | S(src1) | T(src2) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG));
/* dst may be the same as src1 or src2. */
FAIL_IF(push_inst(compiler, SELECT_OP(DSUBU, SUBU) | S(src1) | T(src2) | D(dst), DR(dst)));
}
if (op & SLJIT_SET_C)
FAIL_IF(push_inst(compiler, SLTU | S(dst) | TA(ULESS_FLAG) | DA(LESS_FLAG), LESS_FLAG));
FAIL_IF(push_inst(compiler, SELECT_OP(DSUBU, SUBU) | S(dst) | TA(ULESS_FLAG) | D(dst), DR(dst)));
return (op & SLJIT_SET_C) ? push_inst(compiler, OR | SA(OVERFLOW_FLAG) | TA(LESS_FLAG) | DA(ULESS_FLAG), ULESS_FLAG) : SLJIT_SUCCESS;
case SLJIT_MUL:
SLJIT_ASSERT(!(flags & SRC2_IMM));
if (!(op & SLJIT_SET_O)) {
#if (defined SLJIT_MIPS_R1 && SLJIT_MIPS_R1)
if (op & SLJIT_INT_OP)
return push_inst(compiler, MUL | S(src1) | T(src2) | D(dst), DR(dst));
FAIL_IF(push_inst(compiler, DMULT | S(src1) | T(src2), MOVABLE_INS));
return push_inst(compiler, MFLO | D(dst), DR(dst));
#else
FAIL_IF(push_inst(compiler, SELECT_OP(DMULT, MULT) | S(src1) | T(src2), MOVABLE_INS));
return push_inst(compiler, MFLO | D(dst), DR(dst));
#endif
}
FAIL_IF(push_inst(compiler, SELECT_OP(DMULT, MULT) | S(src1) | T(src2), MOVABLE_INS));
FAIL_IF(push_inst(compiler, MFHI | DA(ULESS_FLAG), ULESS_FLAG));
FAIL_IF(push_inst(compiler, MFLO | D(dst), DR(dst)));
FAIL_IF(push_inst(compiler, SELECT_OP(DSRA32, SRA) | T(dst) | DA(UGREATER_FLAG) | SH_IMM(31), UGREATER_FLAG));
return push_inst(compiler, SELECT_OP(DSUBU, SUBU) | SA(ULESS_FLAG) | TA(UGREATER_FLAG) | DA(OVERFLOW_FLAG), OVERFLOW_FLAG);
case SLJIT_AND:
EMIT_LOGICAL(ANDI, AND);
return SLJIT_SUCCESS;
case SLJIT_OR:
EMIT_LOGICAL(ORI, OR);
return SLJIT_SUCCESS;
case SLJIT_XOR:
EMIT_LOGICAL(XORI, XOR);
return SLJIT_SUCCESS;
case SLJIT_SHL:
EMIT_SHIFT(DSLL, DSLL32, SLL, DSLLV, SLLV);
return SLJIT_SUCCESS;
case SLJIT_LSHR:
EMIT_SHIFT(DSRL, DSRL32, SRL, DSRLV, SRLV);
return SLJIT_SUCCESS;
case SLJIT_ASHR:
EMIT_SHIFT(DSRA, DSRA32, SRA, DSRAV, SRAV);
return SLJIT_SUCCESS;
}
SLJIT_ASSERT_STOP();
return SLJIT_SUCCESS;
}
static SLJIT_INLINE sljit_si emit_const(struct sljit_compiler *compiler, sljit_si dst, sljit_sw init_value)
{
FAIL_IF(push_inst(compiler, LUI | T(dst) | IMM(init_value >> 48), DR(dst)));
FAIL_IF(push_inst(compiler, ORI | S(dst) | T(dst) | IMM(init_value >> 32), DR(dst)));
FAIL_IF(push_inst(compiler, DSLL | T(dst) | D(dst) | SH_IMM(16), DR(dst)));
FAIL_IF(push_inst(compiler, ORI | S(dst) | T(dst) | IMM(init_value >> 16), DR(dst)));
FAIL_IF(push_inst(compiler, DSLL | T(dst) | D(dst) | SH_IMM(16), DR(dst)));
return push_inst(compiler, ORI | S(dst) | T(dst) | IMM(init_value), DR(dst));
}
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_addr)
{
sljit_ins *inst = (sljit_ins*)addr;
inst[0] = (inst[0] & 0xffff0000) | ((new_addr >> 48) & 0xffff);
inst[1] = (inst[1] & 0xffff0000) | ((new_addr >> 32) & 0xffff);
inst[3] = (inst[3] & 0xffff0000) | ((new_addr >> 16) & 0xffff);
inst[5] = (inst[5] & 0xffff0000) | (new_addr & 0xffff);
SLJIT_CACHE_FLUSH(inst, inst + 6);
}
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant)
{
sljit_ins *inst = (sljit_ins*)addr;
inst[0] = (inst[0] & 0xffff0000) | ((new_constant >> 48) & 0xffff);
inst[1] = (inst[1] & 0xffff0000) | ((new_constant >> 32) & 0xffff);
inst[3] = (inst[3] & 0xffff0000) | ((new_constant >> 16) & 0xffff);
inst[5] = (inst[5] & 0xffff0000) | (new_constant & 0xffff);
SLJIT_CACHE_FLUSH(inst, inst + 6);
}
File diff suppressed because it is too large. Load diff
+269
View File
@@ -0,0 +1,269 @@
/*
* Stack-less Just-In-Time compiler
*
* Copyright 2009-2012 Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* ppc 32-bit arch dependent functions. */
static sljit_si load_immediate(struct sljit_compiler *compiler, sljit_si reg, sljit_sw imm)
{
if (imm <= SIMM_MAX && imm >= SIMM_MIN)
return push_inst(compiler, ADDI | D(reg) | A(0) | IMM(imm));
if (!(imm & ~0xffff))
return push_inst(compiler, ORI | S(TMP_ZERO) | A(reg) | IMM(imm));
FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | IMM(imm >> 16)));
return (imm & 0xffff) ? push_inst(compiler, ORI | S(reg) | A(reg) | IMM(imm)) : SLJIT_SUCCESS;
}
#define INS_CLEAR_LEFT(dst, src, from) \
(RLWINM | S(src) | A(dst) | ((from) << 6) | (31 << 1))
static SLJIT_INLINE sljit_si emit_single_op(struct sljit_compiler *compiler, sljit_si op, sljit_si flags,
sljit_si dst, sljit_si src1, sljit_si src2)
{
switch (op) {
case SLJIT_MOV:
case SLJIT_MOV_UI:
case SLJIT_MOV_SI:
case SLJIT_MOV_P:
SLJIT_ASSERT(src1 == TMP_REG1);
if (dst != src2)
return push_inst(compiler, OR | S(src2) | A(dst) | B(src2));
return SLJIT_SUCCESS;
case SLJIT_MOV_UB:
case SLJIT_MOV_SB:
SLJIT_ASSERT(src1 == TMP_REG1);
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
if (op == SLJIT_MOV_SB)
return push_inst(compiler, EXTSB | S(src2) | A(dst));
return push_inst(compiler, INS_CLEAR_LEFT(dst, src2, 24));
}
else if ((flags & REG_DEST) && op == SLJIT_MOV_SB)
return push_inst(compiler, EXTSB | S(src2) | A(dst));
else {
SLJIT_ASSERT(dst == src2);
}
return SLJIT_SUCCESS;
case SLJIT_MOV_UH:
case SLJIT_MOV_SH:
SLJIT_ASSERT(src1 == TMP_REG1);
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
if (op == SLJIT_MOV_SH)
return push_inst(compiler, EXTSH | S(src2) | A(dst));
return push_inst(compiler, INS_CLEAR_LEFT(dst, src2, 16));
}
else {
SLJIT_ASSERT(dst == src2);
}
return SLJIT_SUCCESS;
case SLJIT_NOT:
SLJIT_ASSERT(src1 == TMP_REG1);
return push_inst(compiler, NOR | RC(flags) | S(src2) | A(dst) | B(src2));
case SLJIT_NEG:
SLJIT_ASSERT(src1 == TMP_REG1);
return push_inst(compiler, NEG | OERC(flags) | D(dst) | A(src2));
case SLJIT_CLZ:
SLJIT_ASSERT(src1 == TMP_REG1);
return push_inst(compiler, CNTLZW | RC(flags) | S(src2) | A(dst));
case SLJIT_ADD:
if (flags & ALT_FORM1) {
/* Flags does not set: BIN_IMM_EXTS unnecessary. */
SLJIT_ASSERT(src2 == TMP_REG2);
return push_inst(compiler, ADDI | D(dst) | A(src1) | compiler->imm);
}
if (flags & ALT_FORM2) {
/* Flags does not set: BIN_IMM_EXTS unnecessary. */
SLJIT_ASSERT(src2 == TMP_REG2);
return push_inst(compiler, ADDIS | D(dst) | A(src1) | compiler->imm);
}
if (flags & ALT_FORM3) {
SLJIT_ASSERT(src2 == TMP_REG2);
return push_inst(compiler, ADDIC | D(dst) | A(src1) | compiler->imm);
}
if (flags & ALT_FORM4) {
/* Flags does not set: BIN_IMM_EXTS unnecessary. */
FAIL_IF(push_inst(compiler, ADDI | D(dst) | A(src1) | (compiler->imm & 0xffff)));
return push_inst(compiler, ADDIS | D(dst) | A(dst) | (((compiler->imm >> 16) & 0xffff) + ((compiler->imm >> 15) & 0x1)));
}
if (!(flags & ALT_SET_FLAGS))
return push_inst(compiler, ADD | D(dst) | A(src1) | B(src2));
return push_inst(compiler, ADDC | OERC(ALT_SET_FLAGS) | D(dst) | A(src1) | B(src2));
case SLJIT_ADDC:
if (flags & ALT_FORM1) {
FAIL_IF(push_inst(compiler, MFXER | D(0)));
FAIL_IF(push_inst(compiler, ADDE | D(dst) | A(src1) | B(src2)));
return push_inst(compiler, MTXER | S(0));
}
return push_inst(compiler, ADDE | D(dst) | A(src1) | B(src2));
case SLJIT_SUB:
if (flags & ALT_FORM1) {
/* Flags does not set: BIN_IMM_EXTS unnecessary. */
SLJIT_ASSERT(src2 == TMP_REG2);
return push_inst(compiler, SUBFIC | D(dst) | A(src1) | compiler->imm);
}
if (flags & (ALT_FORM2 | ALT_FORM3)) {
SLJIT_ASSERT(src2 == TMP_REG2);
if (flags & ALT_FORM2)
FAIL_IF(push_inst(compiler, CMPI | CRD(0) | A(src1) | compiler->imm));
if (flags & ALT_FORM3)
return push_inst(compiler, CMPLI | CRD(4) | A(src1) | compiler->imm);
return SLJIT_SUCCESS;
}
if (flags & (ALT_FORM4 | ALT_FORM5)) {
if (flags & ALT_FORM4)
FAIL_IF(push_inst(compiler, CMPL | CRD(4) | A(src1) | B(src2)));
if (flags & ALT_FORM5)
FAIL_IF(push_inst(compiler, CMP | CRD(0) | A(src1) | B(src2)));
return SLJIT_SUCCESS;
}
if (!(flags & ALT_SET_FLAGS))
return push_inst(compiler, SUBF | D(dst) | A(src2) | B(src1));
if (flags & ALT_FORM6)
FAIL_IF(push_inst(compiler, CMPL | CRD(4) | A(src1) | B(src2)));
return push_inst(compiler, SUBFC | OERC(ALT_SET_FLAGS) | D(dst) | A(src2) | B(src1));
case SLJIT_SUBC:
if (flags & ALT_FORM1) {
FAIL_IF(push_inst(compiler, MFXER | D(0)));
FAIL_IF(push_inst(compiler, SUBFE | D(dst) | A(src2) | B(src1)));
return push_inst(compiler, MTXER | S(0));
}
return push_inst(compiler, SUBFE | D(dst) | A(src2) | B(src1));
case SLJIT_MUL:
if (flags & ALT_FORM1) {
SLJIT_ASSERT(src2 == TMP_REG2);
return push_inst(compiler, MULLI | D(dst) | A(src1) | compiler->imm);
}
return push_inst(compiler, MULLW | OERC(flags) | D(dst) | A(src2) | B(src1));
case SLJIT_AND:
if (flags & ALT_FORM1) {
SLJIT_ASSERT(src2 == TMP_REG2);
return push_inst(compiler, ANDI | S(src1) | A(dst) | compiler->imm);
}
if (flags & ALT_FORM2) {
SLJIT_ASSERT(src2 == TMP_REG2);
return push_inst(compiler, ANDIS | S(src1) | A(dst) | compiler->imm);
}
return push_inst(compiler, AND | RC(flags) | S(src1) | A(dst) | B(src2));
case SLJIT_OR:
if (flags & ALT_FORM1) {
SLJIT_ASSERT(src2 == TMP_REG2);
return push_inst(compiler, ORI | S(src1) | A(dst) | compiler->imm);
}
if (flags & ALT_FORM2) {
SLJIT_ASSERT(src2 == TMP_REG2);
return push_inst(compiler, ORIS | S(src1) | A(dst) | compiler->imm);
}
if (flags & ALT_FORM3) {
SLJIT_ASSERT(src2 == TMP_REG2);
FAIL_IF(push_inst(compiler, ORI | S(src1) | A(dst) | IMM(compiler->imm)));
return push_inst(compiler, ORIS | S(dst) | A(dst) | IMM(compiler->imm >> 16));
}
return push_inst(compiler, OR | RC(flags) | S(src1) | A(dst) | B(src2));
case SLJIT_XOR:
if (flags & ALT_FORM1) {
SLJIT_ASSERT(src2 == TMP_REG2);
return push_inst(compiler, XORI | S(src1) | A(dst) | compiler->imm);
}
if (flags & ALT_FORM2) {
SLJIT_ASSERT(src2 == TMP_REG2);
return push_inst(compiler, XORIS | S(src1) | A(dst) | compiler->imm);
}
if (flags & ALT_FORM3) {
SLJIT_ASSERT(src2 == TMP_REG2);
FAIL_IF(push_inst(compiler, XORI | S(src1) | A(dst) | IMM(compiler->imm)));
return push_inst(compiler, XORIS | S(dst) | A(dst) | IMM(compiler->imm >> 16));
}
return push_inst(compiler, XOR | RC(flags) | S(src1) | A(dst) | B(src2));
case SLJIT_SHL:
if (flags & ALT_FORM1) {
SLJIT_ASSERT(src2 == TMP_REG2);
compiler->imm &= 0x1f;
return push_inst(compiler, RLWINM | RC(flags) | S(src1) | A(dst) | (compiler->imm << 11) | ((31 - compiler->imm) << 1));
}
return push_inst(compiler, SLW | RC(flags) | S(src1) | A(dst) | B(src2));
case SLJIT_LSHR:
if (flags & ALT_FORM1) {
SLJIT_ASSERT(src2 == TMP_REG2);
compiler->imm &= 0x1f;
return push_inst(compiler, RLWINM | RC(flags) | S(src1) | A(dst) | (((32 - compiler->imm) & 0x1f) << 11) | (compiler->imm << 6) | (31 << 1));
}
return push_inst(compiler, SRW | RC(flags) | S(src1) | A(dst) | B(src2));
case SLJIT_ASHR:
if (flags & ALT_FORM3)
FAIL_IF(push_inst(compiler, MFXER | D(0)));
if (flags & ALT_FORM1) {
SLJIT_ASSERT(src2 == TMP_REG2);
compiler->imm &= 0x1f;
FAIL_IF(push_inst(compiler, SRAWI | RC(flags) | S(src1) | A(dst) | (compiler->imm << 11)));
}
else
FAIL_IF(push_inst(compiler, SRAW | RC(flags) | S(src1) | A(dst) | B(src2)));
return (flags & ALT_FORM3) ? push_inst(compiler, MTXER | S(0)) : SLJIT_SUCCESS;
}
SLJIT_ASSERT_STOP();
return SLJIT_SUCCESS;
}
static SLJIT_INLINE sljit_si emit_const(struct sljit_compiler *compiler, sljit_si reg, sljit_sw init_value)
{
FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | IMM(init_value >> 16)));
return push_inst(compiler, ORI | S(reg) | A(reg) | IMM(init_value));
}
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_addr)
{
sljit_ins *inst = (sljit_ins*)addr;
inst[0] = (inst[0] & 0xffff0000) | ((new_addr >> 16) & 0xffff);
inst[1] = (inst[1] & 0xffff0000) | (new_addr & 0xffff);
SLJIT_CACHE_FLUSH(inst, inst + 2);
}
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant)
{
sljit_ins *inst = (sljit_ins*)addr;
inst[0] = (inst[0] & 0xffff0000) | ((new_constant >> 16) & 0xffff);
inst[1] = (inst[1] & 0xffff0000) | (new_constant & 0xffff);
SLJIT_CACHE_FLUSH(inst, inst + 2);
}
+421
View File
@@ -0,0 +1,421 @@
/*
* Stack-less Just-In-Time compiler
*
* Copyright 2009-2012 Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* ppc 64-bit arch dependent functions. */
#if defined(__GNUC__) || (defined(__IBM_GCC_ASM) && __IBM_GCC_ASM)
#define ASM_SLJIT_CLZ(src, dst) \
__asm__ volatile ( "cntlzd %0, %1" : "=r"(dst) : "r"(src) )
#elif defined(__xlc__)
#error "Please enable GCC syntax for inline assembly statements"
#else
#error "Must implement count leading zeroes"
#endif
#define RLDI(dst, src, sh, mb, type) \
(HI(30) | S(src) | A(dst) | ((type) << 2) | (((sh) & 0x1f) << 11) | (((sh) & 0x20) >> 4) | (((mb) & 0x1f) << 6) | ((mb) & 0x20))
#define PUSH_RLDICR(reg, shift) \
push_inst(compiler, RLDI(reg, reg, 63 - shift, shift, 1))
static sljit_si load_immediate(struct sljit_compiler *compiler, sljit_si reg, sljit_sw imm)
{
sljit_uw tmp;
sljit_uw shift;
sljit_uw tmp2;
sljit_uw shift2;
if (imm <= SIMM_MAX && imm >= SIMM_MIN)
return push_inst(compiler, ADDI | D(reg) | A(0) | IMM(imm));
if (!(imm & ~0xffff))
return push_inst(compiler, ORI | S(TMP_ZERO) | A(reg) | IMM(imm));
if (imm <= 0x7fffffffl && imm >= -0x80000000l) {
FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | IMM(imm >> 16)));
return (imm & 0xffff) ? push_inst(compiler, ORI | S(reg) | A(reg) | IMM(imm)) : SLJIT_SUCCESS;
}
/* Count leading zeroes. */
tmp = (imm >= 0) ? imm : ~imm;
ASM_SLJIT_CLZ(tmp, shift);
SLJIT_ASSERT(shift > 0);
shift--;
tmp = (imm << shift);
if ((tmp & ~0xffff000000000000ul) == 0) {
FAIL_IF(push_inst(compiler, ADDI | D(reg) | A(0) | IMM(tmp >> 48)));
shift += 15;
return PUSH_RLDICR(reg, shift);
}
if ((tmp & ~0xffffffff00000000ul) == 0) {
FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | IMM(tmp >> 48)));
FAIL_IF(push_inst(compiler, ORI | S(reg) | A(reg) | IMM(tmp >> 32)));
shift += 31;
return PUSH_RLDICR(reg, shift);
}
/* Cut out the 16 bit from immediate. */
shift += 15;
tmp2 = imm & ((1ul << (63 - shift)) - 1);
if (tmp2 <= 0xffff) {
FAIL_IF(push_inst(compiler, ADDI | D(reg) | A(0) | IMM(tmp >> 48)));
FAIL_IF(PUSH_RLDICR(reg, shift));
return push_inst(compiler, ORI | S(reg) | A(reg) | tmp2);
}
if (tmp2 <= 0xffffffff) {
FAIL_IF(push_inst(compiler, ADDI | D(reg) | A(0) | IMM(tmp >> 48)));
FAIL_IF(PUSH_RLDICR(reg, shift));
FAIL_IF(push_inst(compiler, ORIS | S(reg) | A(reg) | (tmp2 >> 16)));
return (imm & 0xffff) ? push_inst(compiler, ORI | S(reg) | A(reg) | IMM(tmp2)) : SLJIT_SUCCESS;
}
ASM_SLJIT_CLZ(tmp2, shift2);
tmp2 <<= shift2;
if ((tmp2 & ~0xffff000000000000ul) == 0) {
FAIL_IF(push_inst(compiler, ADDI | D(reg) | A(0) | IMM(tmp >> 48)));
shift2 += 15;
shift += (63 - shift2);
FAIL_IF(PUSH_RLDICR(reg, shift));
FAIL_IF(push_inst(compiler, ORI | S(reg) | A(reg) | (tmp2 >> 48)));
return PUSH_RLDICR(reg, shift2);
}
/* The general version. */
FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | IMM(imm >> 48)));
FAIL_IF(push_inst(compiler, ORI | S(reg) | A(reg) | IMM(imm >> 32)));
FAIL_IF(PUSH_RLDICR(reg, 31));
FAIL_IF(push_inst(compiler, ORIS | S(reg) | A(reg) | IMM(imm >> 16)));
return push_inst(compiler, ORI | S(reg) | A(reg) | IMM(imm));
}
/* Simplified mnemonics: clrldi. */
#define INS_CLEAR_LEFT(dst, src, from) \
(RLDICL | S(src) | A(dst) | ((from) << 6) | (1 << 5))
/* Sign extension for integer operations. */
#define UN_EXTS() \
if ((flags & (ALT_SIGN_EXT | REG2_SOURCE)) == (ALT_SIGN_EXT | REG2_SOURCE)) { \
FAIL_IF(push_inst(compiler, EXTSW | S(src2) | A(TMP_REG2))); \
src2 = TMP_REG2; \
}
#define BIN_EXTS() \
if (flags & ALT_SIGN_EXT) { \
if (flags & REG1_SOURCE) { \
FAIL_IF(push_inst(compiler, EXTSW | S(src1) | A(TMP_REG1))); \
src1 = TMP_REG1; \
} \
if (flags & REG2_SOURCE) { \
FAIL_IF(push_inst(compiler, EXTSW | S(src2) | A(TMP_REG2))); \
src2 = TMP_REG2; \
} \
}
#define BIN_IMM_EXTS() \
if ((flags & (ALT_SIGN_EXT | REG1_SOURCE)) == (ALT_SIGN_EXT | REG1_SOURCE)) { \
FAIL_IF(push_inst(compiler, EXTSW | S(src1) | A(TMP_REG1))); \
src1 = TMP_REG1; \
}
static SLJIT_INLINE sljit_si emit_single_op(struct sljit_compiler *compiler, sljit_si op, sljit_si flags,
sljit_si dst, sljit_si src1, sljit_si src2)
{
switch (op) {
case SLJIT_MOV:
case SLJIT_MOV_P:
SLJIT_ASSERT(src1 == TMP_REG1);
if (dst != src2)
return push_inst(compiler, OR | S(src2) | A(dst) | B(src2));
return SLJIT_SUCCESS;
case SLJIT_MOV_UI:
case SLJIT_MOV_SI:
SLJIT_ASSERT(src1 == TMP_REG1);
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
if (op == SLJIT_MOV_SI)
return push_inst(compiler, EXTSW | S(src2) | A(dst));
return push_inst(compiler, INS_CLEAR_LEFT(dst, src2, 0));
}
else {
SLJIT_ASSERT(dst == src2);
}
return SLJIT_SUCCESS;
case SLJIT_MOV_UB:
case SLJIT_MOV_SB:
SLJIT_ASSERT(src1 == TMP_REG1);
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
if (op == SLJIT_MOV_SB)
return push_inst(compiler, EXTSB | S(src2) | A(dst));
return push_inst(compiler, INS_CLEAR_LEFT(dst, src2, 24));
}
else if ((flags & REG_DEST) && op == SLJIT_MOV_SB)
return push_inst(compiler, EXTSB | S(src2) | A(dst));
else {
SLJIT_ASSERT(dst == src2);
}
return SLJIT_SUCCESS;
case SLJIT_MOV_UH:
case SLJIT_MOV_SH:
SLJIT_ASSERT(src1 == TMP_REG1);
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
if (op == SLJIT_MOV_SH)
return push_inst(compiler, EXTSH | S(src2) | A(dst));
return push_inst(compiler, INS_CLEAR_LEFT(dst, src2, 16));
}
else {
SLJIT_ASSERT(dst == src2);
}
return SLJIT_SUCCESS;
case SLJIT_NOT:
SLJIT_ASSERT(src1 == TMP_REG1);
UN_EXTS();
return push_inst(compiler, NOR | RC(flags) | S(src2) | A(dst) | B(src2));
case SLJIT_NEG:
SLJIT_ASSERT(src1 == TMP_REG1);
UN_EXTS();
return push_inst(compiler, NEG | OERC(flags) | D(dst) | A(src2));
case SLJIT_CLZ:
SLJIT_ASSERT(src1 == TMP_REG1);
if (flags & ALT_FORM1)
return push_inst(compiler, CNTLZW | RC(flags) | S(src2) | A(dst));
return push_inst(compiler, CNTLZD | RC(flags) | S(src2) | A(dst));
case SLJIT_ADD:
if (flags & ALT_FORM1) {
/* Flags does not set: BIN_IMM_EXTS unnecessary. */
SLJIT_ASSERT(src2 == TMP_REG2);
return push_inst(compiler, ADDI | D(dst) | A(src1) | compiler->imm);
}
if (flags & ALT_FORM2) {
/* Flags does not set: BIN_IMM_EXTS unnecessary. */
SLJIT_ASSERT(src2 == TMP_REG2);
return push_inst(compiler, ADDIS | D(dst) | A(src1) | compiler->imm);
}
if (flags & ALT_FORM3) {
SLJIT_ASSERT(src2 == TMP_REG2);
BIN_IMM_EXTS();
return push_inst(compiler, ADDIC | D(dst) | A(src1) | compiler->imm);
}
if (flags & ALT_FORM4) {
/* Flags does not set: BIN_IMM_EXTS unnecessary. */
FAIL_IF(push_inst(compiler, ADDI | D(dst) | A(src1) | (compiler->imm & 0xffff)));
return push_inst(compiler, ADDIS | D(dst) | A(dst) | (((compiler->imm >> 16) & 0xffff) + ((compiler->imm >> 15) & 0x1)));
}
if (!(flags & ALT_SET_FLAGS))
return push_inst(compiler, ADD | D(dst) | A(src1) | B(src2));
BIN_EXTS();
return push_inst(compiler, ADDC | OERC(ALT_SET_FLAGS) | D(dst) | A(src1) | B(src2));
case SLJIT_ADDC:
if (flags & ALT_FORM1) {
FAIL_IF(push_inst(compiler, MFXER | D(0)));
FAIL_IF(push_inst(compiler, ADDE | D(dst) | A(src1) | B(src2)));
return push_inst(compiler, MTXER | S(0));
}
BIN_EXTS();
return push_inst(compiler, ADDE | D(dst) | A(src1) | B(src2));
case SLJIT_SUB:
if (flags & ALT_FORM1) {
/* Flags does not set: BIN_IMM_EXTS unnecessary. */
SLJIT_ASSERT(src2 == TMP_REG2);
return push_inst(compiler, SUBFIC | D(dst) | A(src1) | compiler->imm);
}
if (flags & (ALT_FORM2 | ALT_FORM3)) {
SLJIT_ASSERT(src2 == TMP_REG2);
if (flags & ALT_FORM2)
FAIL_IF(push_inst(compiler, CMPI | CRD(0 | ((flags & ALT_SIGN_EXT) ? 0 : 1)) | A(src1) | compiler->imm));
if (flags & ALT_FORM3)
return push_inst(compiler, CMPLI | CRD(4 | ((flags & ALT_SIGN_EXT) ? 0 : 1)) | A(src1) | compiler->imm);
return SLJIT_SUCCESS;
}
if (flags & (ALT_FORM4 | ALT_FORM5)) {
if (flags & ALT_FORM4)
FAIL_IF(push_inst(compiler, CMPL | CRD(4 | ((flags & ALT_SIGN_EXT) ? 0 : 1)) | A(src1) | B(src2)));
if (flags & ALT_FORM5)
return push_inst(compiler, CMP | CRD(0 | ((flags & ALT_SIGN_EXT) ? 0 : 1)) | A(src1) | B(src2));
return SLJIT_SUCCESS;
}
if (!(flags & ALT_SET_FLAGS))
return push_inst(compiler, SUBF | D(dst) | A(src2) | B(src1));
BIN_EXTS();
if (flags & ALT_FORM6)
FAIL_IF(push_inst(compiler, CMPL | CRD(4 | ((flags & ALT_SIGN_EXT) ? 0 : 1)) | A(src1) | B(src2)));
return push_inst(compiler, SUBFC | OERC(ALT_SET_FLAGS) | D(dst) | A(src2) | B(src1));
case SLJIT_SUBC:
if (flags & ALT_FORM1) {
FAIL_IF(push_inst(compiler, MFXER | D(0)));
FAIL_IF(push_inst(compiler, SUBFE | D(dst) | A(src2) | B(src1)));
return push_inst(compiler, MTXER | S(0));
}
BIN_EXTS();
return push_inst(compiler, SUBFE | D(dst) | A(src2) | B(src1));
case SLJIT_MUL:
if (flags & ALT_FORM1) {
SLJIT_ASSERT(src2 == TMP_REG2);
return push_inst(compiler, MULLI | D(dst) | A(src1) | compiler->imm);
}
BIN_EXTS();
if (flags & ALT_FORM2)
return push_inst(compiler, MULLW | OERC(flags) | D(dst) | A(src2) | B(src1));
return push_inst(compiler, MULLD | OERC(flags) | D(dst) | A(src2) | B(src1));
case SLJIT_AND:
if (flags & ALT_FORM1) {
SLJIT_ASSERT(src2 == TMP_REG2);
return push_inst(compiler, ANDI | S(src1) | A(dst) | compiler->imm);
}
if (flags & ALT_FORM2) {
SLJIT_ASSERT(src2 == TMP_REG2);
return push_inst(compiler, ANDIS | S(src1) | A(dst) | compiler->imm);
}
return push_inst(compiler, AND | RC(flags) | S(src1) | A(dst) | B(src2));
case SLJIT_OR:
if (flags & ALT_FORM1) {
SLJIT_ASSERT(src2 == TMP_REG2);
return push_inst(compiler, ORI | S(src1) | A(dst) | compiler->imm);
}
if (flags & ALT_FORM2) {
SLJIT_ASSERT(src2 == TMP_REG2);
return push_inst(compiler, ORIS | S(src1) | A(dst) | compiler->imm);
}
if (flags & ALT_FORM3) {
SLJIT_ASSERT(src2 == TMP_REG2);
FAIL_IF(push_inst(compiler, ORI | S(src1) | A(dst) | IMM(compiler->imm)));
return push_inst(compiler, ORIS | S(dst) | A(dst) | IMM(compiler->imm >> 16));
}
return push_inst(compiler, OR | RC(flags) | S(src1) | A(dst) | B(src2));
case SLJIT_XOR:
if (flags & ALT_FORM1) {
SLJIT_ASSERT(src2 == TMP_REG2);
return push_inst(compiler, XORI | S(src1) | A(dst) | compiler->imm);
}
if (flags & ALT_FORM2) {
SLJIT_ASSERT(src2 == TMP_REG2);
return push_inst(compiler, XORIS | S(src1) | A(dst) | compiler->imm);
}
if (flags & ALT_FORM3) {
SLJIT_ASSERT(src2 == TMP_REG2);
FAIL_IF(push_inst(compiler, XORI | S(src1) | A(dst) | IMM(compiler->imm)));
return push_inst(compiler, XORIS | S(dst) | A(dst) | IMM(compiler->imm >> 16));
}
return push_inst(compiler, XOR | RC(flags) | S(src1) | A(dst) | B(src2));
case SLJIT_SHL:
if (flags & ALT_FORM1) {
SLJIT_ASSERT(src2 == TMP_REG2);
if (flags & ALT_FORM2) {
compiler->imm &= 0x1f;
return push_inst(compiler, RLWINM | RC(flags) | S(src1) | A(dst) | (compiler->imm << 11) | ((31 - compiler->imm) << 1));
}
else {
compiler->imm &= 0x3f;
return push_inst(compiler, RLDI(dst, src1, compiler->imm, 63 - compiler->imm, 1) | RC(flags));
}
}
return push_inst(compiler, ((flags & ALT_FORM2) ? SLW : SLD) | RC(flags) | S(src1) | A(dst) | B(src2));
case SLJIT_LSHR:
if (flags & ALT_FORM1) {
SLJIT_ASSERT(src2 == TMP_REG2);
if (flags & ALT_FORM2) {
compiler->imm &= 0x1f;
return push_inst(compiler, RLWINM | RC(flags) | S(src1) | A(dst) | (((32 - compiler->imm) & 0x1f) << 11) | (compiler->imm << 6) | (31 << 1));
}
else {
compiler->imm &= 0x3f;
return push_inst(compiler, RLDI(dst, src1, 64 - compiler->imm, compiler->imm, 0) | RC(flags));
}
}
return push_inst(compiler, ((flags & ALT_FORM2) ? SRW : SRD) | RC(flags) | S(src1) | A(dst) | B(src2));
case SLJIT_ASHR:
if (flags & ALT_FORM3)
FAIL_IF(push_inst(compiler, MFXER | D(0)));
if (flags & ALT_FORM1) {
SLJIT_ASSERT(src2 == TMP_REG2);
if (flags & ALT_FORM2) {
compiler->imm &= 0x1f;
FAIL_IF(push_inst(compiler, SRAWI | RC(flags) | S(src1) | A(dst) | (compiler->imm << 11)));
}
else {
compiler->imm &= 0x3f;
FAIL_IF(push_inst(compiler, SRADI | RC(flags) | S(src1) | A(dst) | ((compiler->imm & 0x1f) << 11) | ((compiler->imm & 0x20) >> 4)));
}
}
else
FAIL_IF(push_inst(compiler, ((flags & ALT_FORM2) ? SRAW : SRAD) | RC(flags) | S(src1) | A(dst) | B(src2)));
return (flags & ALT_FORM3) ? push_inst(compiler, MTXER | S(0)) : SLJIT_SUCCESS;
}
SLJIT_ASSERT_STOP();
return SLJIT_SUCCESS;
}
static SLJIT_INLINE sljit_si emit_const(struct sljit_compiler *compiler, sljit_si reg, sljit_sw init_value)
{
FAIL_IF(push_inst(compiler, ADDIS | D(reg) | A(0) | IMM(init_value >> 48)));
FAIL_IF(push_inst(compiler, ORI | S(reg) | A(reg) | IMM(init_value >> 32)));
FAIL_IF(PUSH_RLDICR(reg, 31));
FAIL_IF(push_inst(compiler, ORIS | S(reg) | A(reg) | IMM(init_value >> 16)));
return push_inst(compiler, ORI | S(reg) | A(reg) | IMM(init_value));
}
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_addr)
{
sljit_ins *inst = (sljit_ins*)addr;
inst[0] = (inst[0] & 0xffff0000) | ((new_addr >> 48) & 0xffff);
inst[1] = (inst[1] & 0xffff0000) | ((new_addr >> 32) & 0xffff);
inst[3] = (inst[3] & 0xffff0000) | ((new_addr >> 16) & 0xffff);
inst[4] = (inst[4] & 0xffff0000) | (new_addr & 0xffff);
SLJIT_CACHE_FLUSH(inst, inst + 5);
}
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant)
{
sljit_ins *inst = (sljit_ins*)addr;
inst[0] = (inst[0] & 0xffff0000) | ((new_constant >> 48) & 0xffff);
inst[1] = (inst[1] & 0xffff0000) | ((new_constant >> 32) & 0xffff);
inst[3] = (inst[3] & 0xffff0000) | ((new_constant >> 16) & 0xffff);
inst[4] = (inst[4] & 0xffff0000) | (new_constant & 0xffff);
SLJIT_CACHE_FLUSH(inst, inst + 5);
}
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,164 @@
/*
* Stack-less Just-In-Time compiler
*
* Copyright 2009-2012 Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
static sljit_si load_immediate(struct sljit_compiler *compiler, sljit_si dst, sljit_sw imm)
{
if (imm <= SIMM_MAX && imm >= SIMM_MIN)
return push_inst(compiler, OR | D(dst) | S1(0) | IMM(imm), DR(dst));
FAIL_IF(push_inst(compiler, SETHI | D(dst) | ((imm >> 10) & 0x3fffff), DR(dst)));
return (imm & 0x3ff) ? push_inst(compiler, OR | D(dst) | S1(dst) | IMM_ARG | (imm & 0x3ff), DR(dst)) : SLJIT_SUCCESS;
}
#define ARG2(flags, src2) ((flags & SRC2_IMM) ? IMM(src2) : S2(src2))
static SLJIT_INLINE sljit_si emit_single_op(struct sljit_compiler *compiler, sljit_si op, sljit_si flags,
sljit_si dst, sljit_si src1, sljit_sw src2)
{
SLJIT_COMPILE_ASSERT(ICC_IS_SET == SET_FLAGS, icc_is_set_and_set_flags_must_be_the_same);
switch (op) {
case SLJIT_MOV:
case SLJIT_MOV_UI:
case SLJIT_MOV_SI:
case SLJIT_MOV_P:
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
if (dst != src2)
return push_inst(compiler, OR | D(dst) | S1(0) | S2(src2), DR(dst));
return SLJIT_SUCCESS;
case SLJIT_MOV_UB:
case SLJIT_MOV_SB:
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
if (op == SLJIT_MOV_UB)
return push_inst(compiler, AND | D(dst) | S1(src2) | IMM(0xff), DR(dst));
FAIL_IF(push_inst(compiler, SLL | D(dst) | S1(src2) | IMM(24), DR(dst)));
return push_inst(compiler, SRA | D(dst) | S1(dst) | IMM(24), DR(dst));
}
else if (dst != src2)
SLJIT_ASSERT_STOP();
return SLJIT_SUCCESS;
case SLJIT_MOV_UH:
case SLJIT_MOV_SH:
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
if ((flags & (REG_DEST | REG2_SOURCE)) == (REG_DEST | REG2_SOURCE)) {
FAIL_IF(push_inst(compiler, SLL | D(dst) | S1(src2) | IMM(16), DR(dst)));
return push_inst(compiler, (op == SLJIT_MOV_SH ? SRA : SRL) | D(dst) | S1(dst) | IMM(16), DR(dst));
}
else if (dst != src2)
SLJIT_ASSERT_STOP();
return SLJIT_SUCCESS;
case SLJIT_NOT:
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
return push_inst(compiler, XNOR | (flags & SET_FLAGS) | D(dst) | S1(0) | S2(src2), DR(dst) | (flags & SET_FLAGS));
case SLJIT_CLZ:
SLJIT_ASSERT(src1 == TMP_REG1 && !(flags & SRC2_IMM));
/* sparc 32 does not support SLJIT_KEEP_FLAGS. Not sure I can fix this. */
FAIL_IF(push_inst(compiler, SUB | SET_FLAGS | D(0) | S1(src2) | S2(0), SET_FLAGS));
FAIL_IF(push_inst(compiler, OR | D(TMP_REG1) | S1(0) | S2(src2), DR(TMP_REG1)));
FAIL_IF(push_inst(compiler, BICC | DA(0x1) | (7 & DISP_MASK), UNMOVABLE_INS));
FAIL_IF(push_inst(compiler, OR | (flags & SET_FLAGS) | D(dst) | S1(0) | IMM(32), UNMOVABLE_INS | (flags & SET_FLAGS)));
FAIL_IF(push_inst(compiler, OR | D(dst) | S1(0) | IMM(-1), DR(dst)));
/* Loop. */
FAIL_IF(push_inst(compiler, SUB | SET_FLAGS | D(0) | S1(TMP_REG1) | S2(0), SET_FLAGS));
FAIL_IF(push_inst(compiler, SLL | D(TMP_REG1) | S1(TMP_REG1) | IMM(1), DR(TMP_REG1)));
FAIL_IF(push_inst(compiler, BICC | DA(0xe) | (-2 & DISP_MASK), UNMOVABLE_INS));
return push_inst(compiler, ADD | (flags & SET_FLAGS) | D(dst) | S1(dst) | IMM(1), UNMOVABLE_INS | (flags & SET_FLAGS));
case SLJIT_ADD:
return push_inst(compiler, ADD | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS));
case SLJIT_ADDC:
return push_inst(compiler, ADDC | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS));
case SLJIT_SUB:
return push_inst(compiler, SUB | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS));
case SLJIT_SUBC:
return push_inst(compiler, SUBC | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS));
case SLJIT_MUL:
FAIL_IF(push_inst(compiler, SMUL | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst)));
if (!(flags & SET_FLAGS))
return SLJIT_SUCCESS;
FAIL_IF(push_inst(compiler, SRA | D(TMP_REG1) | S1(dst) | IMM(31), DR(TMP_REG1)));
FAIL_IF(push_inst(compiler, RDY | D(TMP_LINK), DR(TMP_LINK)));
return push_inst(compiler, SUB | SET_FLAGS | D(0) | S1(TMP_REG1) | S2(TMP_LINK), MOVABLE_INS | SET_FLAGS);
case SLJIT_AND:
return push_inst(compiler, AND | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS));
case SLJIT_OR:
return push_inst(compiler, OR | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS));
case SLJIT_XOR:
return push_inst(compiler, XOR | (flags & SET_FLAGS) | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst) | (flags & SET_FLAGS));
case SLJIT_SHL:
FAIL_IF(push_inst(compiler, SLL | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst)));
return !(flags & SET_FLAGS) ? SLJIT_SUCCESS : push_inst(compiler, SUB | SET_FLAGS | D(0) | S1(dst) | S2(0), SET_FLAGS);
case SLJIT_LSHR:
FAIL_IF(push_inst(compiler, SRL | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst)));
return !(flags & SET_FLAGS) ? SLJIT_SUCCESS : push_inst(compiler, SUB | SET_FLAGS | D(0) | S1(dst) | S2(0), SET_FLAGS);
case SLJIT_ASHR:
FAIL_IF(push_inst(compiler, SRA | D(dst) | S1(src1) | ARG2(flags, src2), DR(dst)));
return !(flags & SET_FLAGS) ? SLJIT_SUCCESS : push_inst(compiler, SUB | SET_FLAGS | D(0) | S1(dst) | S2(0), SET_FLAGS);
}
SLJIT_ASSERT_STOP();
return SLJIT_SUCCESS;
}
static SLJIT_INLINE sljit_si emit_const(struct sljit_compiler *compiler, sljit_si dst, sljit_sw init_value)
{
FAIL_IF(push_inst(compiler, SETHI | D(dst) | ((init_value >> 10) & 0x3fffff), DR(dst)));
return push_inst(compiler, OR | D(dst) | S1(dst) | IMM_ARG | (init_value & 0x3ff), DR(dst));
}
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_jump_addr(sljit_uw addr, sljit_uw new_addr)
{
sljit_ins *inst = (sljit_ins*)addr;
inst[0] = (inst[0] & 0xffc00000) | ((new_addr >> 10) & 0x3fffff);
inst[1] = (inst[1] & 0xfffffc00) | (new_addr & 0x3ff);
SLJIT_CACHE_FLUSH(inst, inst + 2);
}
SLJIT_API_FUNC_ATTRIBUTE void sljit_set_const(sljit_uw addr, sljit_sw new_constant)
{
sljit_ins *inst = (sljit_ins*)addr;
inst[0] = (inst[0] & 0xffc00000) | ((new_constant >> 10) & 0x3fffff);
inst[1] = (inst[1] & 0xfffffc00) | (new_constant & 0x3ff);
SLJIT_CACHE_FLUSH(inst, inst + 2);
}
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+550
View File
@@ -0,0 +1,550 @@
/*
* Stack-less Just-In-Time compiler
*
* Copyright 2009-2012 Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* x86 32-bit arch dependent functions. */
static sljit_si emit_do_imm(struct sljit_compiler *compiler, sljit_ub opcode, sljit_sw imm)
{
sljit_ub *inst;
inst = (sljit_ub*)ensure_buf(compiler, 1 + 1 + sizeof(sljit_sw));
FAIL_IF(!inst);
INC_SIZE(1 + sizeof(sljit_sw));
*inst++ = opcode;
*(sljit_sw*)inst = imm;
return SLJIT_SUCCESS;
}
static sljit_ub* generate_far_jump_code(struct sljit_jump *jump, sljit_ub *code_ptr, sljit_si type)
{
if (type == SLJIT_JUMP) {
*code_ptr++ = JMP_i32;
jump->addr++;
}
else if (type >= SLJIT_FAST_CALL) {
*code_ptr++ = CALL_i32;
jump->addr++;
}
else {
*code_ptr++ = GROUP_0F;
*code_ptr++ = get_jump_code(type);
jump->addr += 2;
}
if (jump->flags & JUMP_LABEL)
jump->flags |= PATCH_MW;
else
*(sljit_sw*)code_ptr = jump->u.target - (jump->addr + 4);
code_ptr += 4;
return code_ptr;
}
SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_enter(struct sljit_compiler *compiler,
sljit_si options, sljit_si args, sljit_si scratches, sljit_si saveds,
sljit_si fscratches, sljit_si fsaveds, sljit_si local_size)
{
sljit_si size;
sljit_ub *inst;
CHECK_ERROR();
CHECK(check_sljit_emit_enter(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size));
set_emit_enter(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size);
compiler->args = args;
compiler->flags_saved = 0;
size = 1 + (scratches > 7 ? (scratches - 7) : 0) + (saveds <= 3 ? saveds : 3);
#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
size += (args > 0 ? (args * 2) : 0) + (args > 2 ? 2 : 0);
#else
size += (args > 0 ? (2 + args * 3) : 0);
#endif
inst = (sljit_ub*)ensure_buf(compiler, 1 + size);
FAIL_IF(!inst);
INC_SIZE(size);
PUSH_REG(reg_map[TMP_REG1]);
#if !(defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
if (args > 0) {
*inst++ = MOV_r_rm;
*inst++ = MOD_REG | (reg_map[TMP_REG1] << 3) | 0x4 /* esp */;
}
#endif
if (saveds > 2 || scratches > 7)
PUSH_REG(reg_map[SLJIT_S2]);
if (saveds > 1 || scratches > 8)
PUSH_REG(reg_map[SLJIT_S1]);
if (saveds > 0 || scratches > 9)
PUSH_REG(reg_map[SLJIT_S0]);
#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
if (args > 0) {
*inst++ = MOV_r_rm;
*inst++ = MOD_REG | (reg_map[SLJIT_S0] << 3) | reg_map[SLJIT_R2];
}
if (args > 1) {
*inst++ = MOV_r_rm;
*inst++ = MOD_REG | (reg_map[SLJIT_S1] << 3) | reg_map[SLJIT_R1];
}
if (args > 2) {
*inst++ = MOV_r_rm;
*inst++ = MOD_DISP8 | (reg_map[SLJIT_S2] << 3) | 0x4 /* esp */;
*inst++ = 0x24;
*inst++ = sizeof(sljit_sw) * (3 + 2); /* saveds >= 3 as well. */
}
#else
if (args > 0) {
*inst++ = MOV_r_rm;
*inst++ = MOD_DISP8 | (reg_map[SLJIT_S0] << 3) | reg_map[TMP_REG1];
*inst++ = sizeof(sljit_sw) * 2;
}
if (args > 1) {
*inst++ = MOV_r_rm;
*inst++ = MOD_DISP8 | (reg_map[SLJIT_S1] << 3) | reg_map[TMP_REG1];
*inst++ = sizeof(sljit_sw) * 3;
}
if (args > 2) {
*inst++ = MOV_r_rm;
*inst++ = MOD_DISP8 | (reg_map[SLJIT_S2] << 3) | reg_map[TMP_REG1];
*inst++ = sizeof(sljit_sw) * 4;
}
#endif
SLJIT_COMPILE_ASSERT(SLJIT_LOCALS_OFFSET >= (2 + 4) * sizeof(sljit_uw), require_at_least_two_words);
#if defined(__APPLE__)
/* Ignore pushed registers and SLJIT_LOCALS_OFFSET when computing the aligned local size. */
saveds = (2 + (scratches > 7 ? (scratches - 7) : 0) + (saveds <= 3 ? saveds : 3)) * sizeof(sljit_uw);
local_size = ((SLJIT_LOCALS_OFFSET + saveds + local_size + 15) & ~15) - saveds;
#else
if (options & SLJIT_DOUBLE_ALIGNMENT) {
local_size = SLJIT_LOCALS_OFFSET + ((local_size + 7) & ~7);
inst = (sljit_ub*)ensure_buf(compiler, 1 + 17);
FAIL_IF(!inst);
INC_SIZE(17);
inst[0] = MOV_r_rm;
inst[1] = MOD_REG | (reg_map[TMP_REG1] << 3) | reg_map[SLJIT_SP];
inst[2] = GROUP_F7;
inst[3] = MOD_REG | (0 << 3) | reg_map[SLJIT_SP];
*(sljit_sw*)(inst + 4) = 0x4;
inst[8] = JNE_i8;
inst[9] = 6;
inst[10] = GROUP_BINARY_81;
inst[11] = MOD_REG | (5 << 3) | reg_map[SLJIT_SP];
*(sljit_sw*)(inst + 12) = 0x4;
inst[16] = PUSH_r + reg_map[TMP_REG1];
}
else
local_size = SLJIT_LOCALS_OFFSET + ((local_size + 3) & ~3);
#endif
compiler->local_size = local_size;
#ifdef _WIN32
if (local_size > 1024) {
#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
FAIL_IF(emit_do_imm(compiler, MOV_r_i32 + reg_map[SLJIT_R0], local_size));
#else
local_size -= SLJIT_LOCALS_OFFSET;
FAIL_IF(emit_do_imm(compiler, MOV_r_i32 + reg_map[SLJIT_R0], local_size));
FAIL_IF(emit_non_cum_binary(compiler, SUB_r_rm, SUB_rm_r, SUB, SUB_EAX_i32,
SLJIT_SP, 0, SLJIT_SP, 0, SLJIT_IMM, SLJIT_LOCALS_OFFSET));
#endif
FAIL_IF(sljit_emit_ijump(compiler, SLJIT_CALL1, SLJIT_IMM, SLJIT_FUNC_OFFSET(sljit_grow_stack)));
}
#endif
SLJIT_ASSERT(local_size > 0);
return emit_non_cum_binary(compiler, SUB_r_rm, SUB_rm_r, SUB, SUB_EAX_i32,
SLJIT_SP, 0, SLJIT_SP, 0, SLJIT_IMM, local_size);
}
SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_set_context(struct sljit_compiler *compiler,
sljit_si options, sljit_si args, sljit_si scratches, sljit_si saveds,
sljit_si fscratches, sljit_si fsaveds, sljit_si local_size)
{
CHECK_ERROR();
CHECK(check_sljit_set_context(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size));
set_set_context(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size);
compiler->args = args;
#if defined(__APPLE__)
saveds = (2 + (scratches > 7 ? (scratches - 7) : 0) + (saveds <= 3 ? saveds : 3)) * sizeof(sljit_uw);
compiler->local_size = ((SLJIT_LOCALS_OFFSET + saveds + local_size + 15) & ~15) - saveds;
#else
if (options & SLJIT_DOUBLE_ALIGNMENT)
compiler->local_size = SLJIT_LOCALS_OFFSET + ((local_size + 7) & ~7);
else
compiler->local_size = SLJIT_LOCALS_OFFSET + ((local_size + 3) & ~3);
#endif
return SLJIT_SUCCESS;
}
SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_return(struct sljit_compiler *compiler, sljit_si op, sljit_si src, sljit_sw srcw)
{
sljit_si size;
sljit_ub *inst;
CHECK_ERROR();
CHECK(check_sljit_emit_return(compiler, op, src, srcw));
SLJIT_ASSERT(compiler->args >= 0);
compiler->flags_saved = 0;
FAIL_IF(emit_mov_before_return(compiler, op, src, srcw));
SLJIT_ASSERT(compiler->local_size > 0);
FAIL_IF(emit_cum_binary(compiler, ADD_r_rm, ADD_rm_r, ADD, ADD_EAX_i32,
SLJIT_SP, 0, SLJIT_SP, 0, SLJIT_IMM, compiler->local_size));
#if !defined(__APPLE__)
if (compiler->options & SLJIT_DOUBLE_ALIGNMENT) {
inst = (sljit_ub*)ensure_buf(compiler, 1 + 3);
FAIL_IF(!inst);
INC_SIZE(3);
inst[0] = MOV_r_rm;
inst[1] = (reg_map[SLJIT_SP] << 3) | 0x4 /* SIB */;
inst[2] = (4 << 3) | reg_map[SLJIT_SP];
}
#endif
size = 2 + (compiler->scratches > 7 ? (compiler->scratches - 7) : 0) +
(compiler->saveds <= 3 ? compiler->saveds : 3);
#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
if (compiler->args > 2)
size += 2;
#else
if (compiler->args > 0)
size += 2;
#endif
inst = (sljit_ub*)ensure_buf(compiler, 1 + size);
FAIL_IF(!inst);
INC_SIZE(size);
if (compiler->saveds > 0 || compiler->scratches > 9)
POP_REG(reg_map[SLJIT_S0]);
if (compiler->saveds > 1 || compiler->scratches > 8)
POP_REG(reg_map[SLJIT_S1]);
if (compiler->saveds > 2 || compiler->scratches > 7)
POP_REG(reg_map[SLJIT_S2]);
POP_REG(reg_map[TMP_REG1]);
#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
if (compiler->args > 2)
RET_I16(sizeof(sljit_sw));
else
RET();
#else
RET();
#endif
return SLJIT_SUCCESS;
}
/* --------------------------------------------------------------------- */
/* Operators */
/* --------------------------------------------------------------------- */
/* Size contains the flags as well. */
static sljit_ub* emit_x86_instruction(struct sljit_compiler *compiler, sljit_si size,
/* The register or immediate operand. */
sljit_si a, sljit_sw imma,
/* The general operand (not immediate). */
sljit_si b, sljit_sw immb)
{
sljit_ub *inst;
sljit_ub *buf_ptr;
sljit_si flags = size & ~0xf;
sljit_si inst_size;
/* Both cannot be switched on. */
SLJIT_ASSERT((flags & (EX86_BIN_INS | EX86_SHIFT_INS)) != (EX86_BIN_INS | EX86_SHIFT_INS));
/* Size flags not allowed for typed instructions. */
SLJIT_ASSERT(!(flags & (EX86_BIN_INS | EX86_SHIFT_INS)) || (flags & (EX86_BYTE_ARG | EX86_HALF_ARG)) == 0);
/* Both size flags cannot be switched on. */
SLJIT_ASSERT((flags & (EX86_BYTE_ARG | EX86_HALF_ARG)) != (EX86_BYTE_ARG | EX86_HALF_ARG));
/* SSE2 and immediate is not possible. */
SLJIT_ASSERT(!(a & SLJIT_IMM) || !(flags & EX86_SSE2));
SLJIT_ASSERT((flags & (EX86_PREF_F2 | EX86_PREF_F3)) != (EX86_PREF_F2 | EX86_PREF_F3)
&& (flags & (EX86_PREF_F2 | EX86_PREF_66)) != (EX86_PREF_F2 | EX86_PREF_66)
&& (flags & (EX86_PREF_F3 | EX86_PREF_66)) != (EX86_PREF_F3 | EX86_PREF_66));
size &= 0xf;
inst_size = size;
if (flags & (EX86_PREF_F2 | EX86_PREF_F3))
inst_size++;
if (flags & EX86_PREF_66)
inst_size++;
/* Calculate size of b. */
inst_size += 1; /* mod r/m byte. */
if (b & SLJIT_MEM) {
if ((b & REG_MASK) == SLJIT_UNUSED)
inst_size += sizeof(sljit_sw);
else if (immb != 0 && !(b & OFFS_REG_MASK)) {
/* Immediate operand. */
if (immb <= 127 && immb >= -128)
inst_size += sizeof(sljit_sb);
else
inst_size += sizeof(sljit_sw);
}
if ((b & REG_MASK) == SLJIT_SP && !(b & OFFS_REG_MASK))
b |= TO_OFFS_REG(SLJIT_SP);
if ((b & OFFS_REG_MASK) != SLJIT_UNUSED)
inst_size += 1; /* SIB byte. */
}
/* Calculate size of a. */
if (a & SLJIT_IMM) {
if (flags & EX86_BIN_INS) {
if (imma <= 127 && imma >= -128) {
inst_size += 1;
flags |= EX86_BYTE_ARG;
} else
inst_size += 4;
}
else if (flags & EX86_SHIFT_INS) {
imma &= 0x1f;
if (imma != 1) {
inst_size ++;
flags |= EX86_BYTE_ARG;
}
} else if (flags & EX86_BYTE_ARG)
inst_size++;
else if (flags & EX86_HALF_ARG)
inst_size += sizeof(short);
else
inst_size += sizeof(sljit_sw);
}
else
SLJIT_ASSERT(!(flags & EX86_SHIFT_INS) || a == SLJIT_PREF_SHIFT_REG);
inst = (sljit_ub*)ensure_buf(compiler, 1 + inst_size);
PTR_FAIL_IF(!inst);
/* Encoding the byte. */
INC_SIZE(inst_size);
if (flags & EX86_PREF_F2)
*inst++ = 0xf2;
if (flags & EX86_PREF_F3)
*inst++ = 0xf3;
if (flags & EX86_PREF_66)
*inst++ = 0x66;
buf_ptr = inst + size;
/* Encode mod/rm byte. */
if (!(flags & EX86_SHIFT_INS)) {
if ((flags & EX86_BIN_INS) && (a & SLJIT_IMM))
*inst = (flags & EX86_BYTE_ARG) ? GROUP_BINARY_83 : GROUP_BINARY_81;
if ((a & SLJIT_IMM) || (a == 0))
*buf_ptr = 0;
else if (!(flags & EX86_SSE2_OP1))
*buf_ptr = reg_map[a] << 3;
else
*buf_ptr = a << 3;
}
else {
if (a & SLJIT_IMM) {
if (imma == 1)
*inst = GROUP_SHIFT_1;
else
*inst = GROUP_SHIFT_N;
} else
*inst = GROUP_SHIFT_CL;
*buf_ptr = 0;
}
if (!(b & SLJIT_MEM))
*buf_ptr++ |= MOD_REG + ((!(flags & EX86_SSE2_OP2)) ? reg_map[b] : b);
else if ((b & REG_MASK) != SLJIT_UNUSED) {
if ((b & OFFS_REG_MASK) == SLJIT_UNUSED || (b & OFFS_REG_MASK) == TO_OFFS_REG(SLJIT_SP)) {
if (immb != 0) {
if (immb <= 127 && immb >= -128)
*buf_ptr |= 0x40;
else
*buf_ptr |= 0x80;
}
if ((b & OFFS_REG_MASK) == SLJIT_UNUSED)
*buf_ptr++ |= reg_map[b & REG_MASK];
else {
*buf_ptr++ |= 0x04;
*buf_ptr++ = reg_map[b & REG_MASK] | (reg_map[OFFS_REG(b)] << 3);
}
if (immb != 0) {
if (immb <= 127 && immb >= -128)
*buf_ptr++ = immb; /* 8 bit displacement. */
else {
*(sljit_sw*)buf_ptr = immb; /* 32 bit displacement. */
buf_ptr += sizeof(sljit_sw);
}
}
}
else {
*buf_ptr++ |= 0x04;
*buf_ptr++ = reg_map[b & REG_MASK] | (reg_map[OFFS_REG(b)] << 3) | (immb << 6);
}
}
else {
*buf_ptr++ |= 0x05;
*(sljit_sw*)buf_ptr = immb; /* 32 bit displacement. */
buf_ptr += sizeof(sljit_sw);
}
if (a & SLJIT_IMM) {
if (flags & EX86_BYTE_ARG)
*buf_ptr = imma;
else if (flags & EX86_HALF_ARG)
*(short*)buf_ptr = imma;
else if (!(flags & EX86_SHIFT_INS))
*(sljit_sw*)buf_ptr = imma;
}
return !(flags & EX86_SHIFT_INS) ? inst : (inst + 1);
}
/* --------------------------------------------------------------------- */
/* Call / return instructions */
/* --------------------------------------------------------------------- */
static SLJIT_INLINE sljit_si call_with_args(struct sljit_compiler *compiler, sljit_si type)
{
sljit_ub *inst;
#if (defined SLJIT_X86_32_FASTCALL && SLJIT_X86_32_FASTCALL)
inst = (sljit_ub*)ensure_buf(compiler, type >= SLJIT_CALL3 ? 1 + 2 + 1 : 1 + 2);
FAIL_IF(!inst);
INC_SIZE(type >= SLJIT_CALL3 ? 2 + 1 : 2);
if (type >= SLJIT_CALL3)
PUSH_REG(reg_map[SLJIT_R2]);
*inst++ = MOV_r_rm;
*inst++ = MOD_REG | (reg_map[SLJIT_R2] << 3) | reg_map[SLJIT_R0];
#else
inst = (sljit_ub*)ensure_buf(compiler, 1 + 4 * (type - SLJIT_CALL0));
FAIL_IF(!inst);
INC_SIZE(4 * (type - SLJIT_CALL0));
*inst++ = MOV_rm_r;
*inst++ = MOD_DISP8 | (reg_map[SLJIT_R0] << 3) | 0x4 /* SIB */;
*inst++ = (0x4 /* none*/ << 3) | reg_map[SLJIT_SP];
*inst++ = 0;
if (type >= SLJIT_CALL2) {
*inst++ = MOV_rm_r;
*inst++ = MOD_DISP8 | (reg_map[SLJIT_R1] << 3) | 0x4 /* SIB */;
*inst++ = (0x4 /* none*/ << 3) | reg_map[SLJIT_SP];
*inst++ = sizeof(sljit_sw);
}
if (type >= SLJIT_CALL3) {
*inst++ = MOV_rm_r;
*inst++ = MOD_DISP8 | (reg_map[SLJIT_R2] << 3) | 0x4 /* SIB */;
*inst++ = (0x4 /* none*/ << 3) | reg_map[SLJIT_SP];
*inst++ = 2 * sizeof(sljit_sw);
}
#endif
return SLJIT_SUCCESS;
}
SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw)
{
sljit_ub *inst;
CHECK_ERROR();
CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw));
ADJUST_LOCAL_OFFSET(dst, dstw);
CHECK_EXTRA_REGS(dst, dstw, (void)0);
/* For UNUSED dst. Uncommon, but possible. */
if (dst == SLJIT_UNUSED)
dst = TMP_REG1;
if (FAST_IS_REG(dst)) {
/* Unused dest is possible here. */
inst = (sljit_ub*)ensure_buf(compiler, 1 + 1);
FAIL_IF(!inst);
INC_SIZE(1);
POP_REG(reg_map[dst]);
return SLJIT_SUCCESS;
}
/* Memory. */
inst = emit_x86_instruction(compiler, 1, 0, 0, dst, dstw);
FAIL_IF(!inst);
*inst++ = POP_rm;
return SLJIT_SUCCESS;
}
SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_return(struct sljit_compiler *compiler, sljit_si src, sljit_sw srcw)
{
sljit_ub *inst;
CHECK_ERROR();
CHECK(check_sljit_emit_fast_return(compiler, src, srcw));
ADJUST_LOCAL_OFFSET(src, srcw);
CHECK_EXTRA_REGS(src, srcw, (void)0);
if (FAST_IS_REG(src)) {
inst = (sljit_ub*)ensure_buf(compiler, 1 + 1 + 1);
FAIL_IF(!inst);
INC_SIZE(1 + 1);
PUSH_REG(reg_map[src]);
}
else if (src & SLJIT_MEM) {
inst = emit_x86_instruction(compiler, 1, 0, 0, src, srcw);
FAIL_IF(!inst);
*inst++ = GROUP_FF;
*inst |= PUSH_rm;
inst = (sljit_ub*)ensure_buf(compiler, 1 + 1);
FAIL_IF(!inst);
INC_SIZE(1);
}
else {
/* SLJIT_IMM. */
inst = (sljit_ub*)ensure_buf(compiler, 1 + 5 + 1);
FAIL_IF(!inst);
INC_SIZE(5 + 1);
*inst++ = PUSH_i32;
*(sljit_sw*)inst = srcw;
inst += sizeof(sljit_sw);
}
RET();
return SLJIT_SUCCESS;
}
+747
View File
@@ -0,0 +1,747 @@
/*
* Stack-less Just-In-Time compiler
*
* Copyright 2009-2012 Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* x86 64-bit arch dependent functions. */
static sljit_si emit_load_imm64(struct sljit_compiler *compiler, sljit_si reg, sljit_sw imm)
{
sljit_ub *inst;
inst = (sljit_ub*)ensure_buf(compiler, 1 + 2 + sizeof(sljit_sw));
FAIL_IF(!inst);
INC_SIZE(2 + sizeof(sljit_sw));
*inst++ = REX_W | ((reg_map[reg] <= 7) ? 0 : REX_B);
*inst++ = MOV_r_i32 + (reg_map[reg] & 0x7);
*(sljit_sw*)inst = imm;
return SLJIT_SUCCESS;
}
static sljit_ub* generate_far_jump_code(struct sljit_jump *jump, sljit_ub *code_ptr, sljit_si type)
{
if (type < SLJIT_JUMP) {
/* Invert type. */
*code_ptr++ = get_jump_code(type ^ 0x1) - 0x10;
*code_ptr++ = 10 + 3;
}
SLJIT_COMPILE_ASSERT(reg_map[TMP_REG3] == 9, tmp3_is_9_first);
*code_ptr++ = REX_W | REX_B;
*code_ptr++ = MOV_r_i32 + 1;
jump->addr = (sljit_uw)code_ptr;
if (jump->flags & JUMP_LABEL)
jump->flags |= PATCH_MD;
else
*(sljit_sw*)code_ptr = jump->u.target;
code_ptr += sizeof(sljit_sw);
*code_ptr++ = REX_B;
*code_ptr++ = GROUP_FF;
*code_ptr++ = (type >= SLJIT_FAST_CALL) ? (MOD_REG | CALL_rm | 1) : (MOD_REG | JMP_rm | 1);
return code_ptr;
}
static sljit_ub* generate_fixed_jump(sljit_ub *code_ptr, sljit_sw addr, sljit_si type)
{
sljit_sw delta = addr - ((sljit_sw)code_ptr + 1 + sizeof(sljit_si));
if (delta <= HALFWORD_MAX && delta >= HALFWORD_MIN) {
*code_ptr++ = (type == 2) ? CALL_i32 : JMP_i32;
*(sljit_sw*)code_ptr = delta;
}
else {
SLJIT_COMPILE_ASSERT(reg_map[TMP_REG3] == 9, tmp3_is_9_second);
*code_ptr++ = REX_W | REX_B;
*code_ptr++ = MOV_r_i32 + 1;
*(sljit_sw*)code_ptr = addr;
code_ptr += sizeof(sljit_sw);
*code_ptr++ = REX_B;
*code_ptr++ = GROUP_FF;
*code_ptr++ = (type == 2) ? (MOD_REG | CALL_rm | 1) : (MOD_REG | JMP_rm | 1);
}
return code_ptr;
}
SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_enter(struct sljit_compiler *compiler,
sljit_si options, sljit_si args, sljit_si scratches, sljit_si saveds,
sljit_si fscratches, sljit_si fsaveds, sljit_si local_size)
{
sljit_si i, tmp, size, saved_register_size;
sljit_ub *inst;
CHECK_ERROR();
CHECK(check_sljit_emit_enter(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size));
set_emit_enter(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size);
compiler->flags_saved = 0;
/* Including the return address saved by the call instruction. */
saved_register_size = GET_SAVED_REGISTERS_SIZE(scratches, saveds, 1);
tmp = saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - saveds) : SLJIT_FIRST_SAVED_REG;
for (i = SLJIT_S0; i >= tmp; i--) {
size = reg_map[i] >= 8 ? 2 : 1;
inst = (sljit_ub*)ensure_buf(compiler, 1 + size);
FAIL_IF(!inst);
INC_SIZE(size);
if (reg_map[i] >= 8)
*inst++ = REX_B;
PUSH_REG(reg_lmap[i]);
}
for (i = scratches; i >= SLJIT_FIRST_SAVED_REG; i--) {
size = reg_map[i] >= 8 ? 2 : 1;
inst = (sljit_ub*)ensure_buf(compiler, 1 + size);
FAIL_IF(!inst);
INC_SIZE(size);
if (reg_map[i] >= 8)
*inst++ = REX_B;
PUSH_REG(reg_lmap[i]);
}
if (args > 0) {
size = args * 3;
inst = (sljit_ub*)ensure_buf(compiler, 1 + size);
FAIL_IF(!inst);
INC_SIZE(size);
#ifndef _WIN64
if (args > 0) {
*inst++ = REX_W;
*inst++ = MOV_r_rm;
*inst++ = MOD_REG | (reg_map[SLJIT_S0] << 3) | 0x7 /* rdi */;
}
if (args > 1) {
*inst++ = REX_W | REX_R;
*inst++ = MOV_r_rm;
*inst++ = MOD_REG | (reg_lmap[SLJIT_S1] << 3) | 0x6 /* rsi */;
}
if (args > 2) {
*inst++ = REX_W | REX_R;
*inst++ = MOV_r_rm;
*inst++ = MOD_REG | (reg_lmap[SLJIT_S2] << 3) | 0x2 /* rdx */;
}
#else
if (args > 0) {
*inst++ = REX_W;
*inst++ = MOV_r_rm;
*inst++ = MOD_REG | (reg_map[SLJIT_S0] << 3) | 0x1 /* rcx */;
}
if (args > 1) {
*inst++ = REX_W;
*inst++ = MOV_r_rm;
*inst++ = MOD_REG | (reg_map[SLJIT_S1] << 3) | 0x2 /* rdx */;
}
if (args > 2) {
*inst++ = REX_W | REX_B;
*inst++ = MOV_r_rm;
*inst++ = MOD_REG | (reg_map[SLJIT_S2] << 3) | 0x0 /* r8 */;
}
#endif
}
local_size = ((local_size + SLJIT_LOCALS_OFFSET + saved_register_size + 15) & ~15) - saved_register_size;
compiler->local_size = local_size;
#ifdef _WIN64
if (local_size > 1024) {
/* Allocate stack for the callback, which grows the stack. */
inst = (sljit_ub*)ensure_buf(compiler, 1 + 4 + (3 + sizeof(sljit_si)));
FAIL_IF(!inst);
INC_SIZE(4 + (3 + sizeof(sljit_si)));
*inst++ = REX_W;
*inst++ = GROUP_BINARY_83;
*inst++ = MOD_REG | SUB | 4;
/* Allocated size for registers must be divisible by 8. */
SLJIT_ASSERT(!(saved_register_size & 0x7));
/* Aligned to 16 byte. */
if (saved_register_size & 0x8) {
*inst++ = 5 * sizeof(sljit_sw);
local_size -= 5 * sizeof(sljit_sw);
} else {
*inst++ = 4 * sizeof(sljit_sw);
local_size -= 4 * sizeof(sljit_sw);
}
/* Second instruction */
SLJIT_COMPILE_ASSERT(reg_map[SLJIT_R0] < 8, temporary_reg1_is_loreg);
*inst++ = REX_W;
*inst++ = MOV_rm_i32;
*inst++ = MOD_REG | reg_lmap[SLJIT_R0];
*(sljit_si*)inst = local_size;
#if (defined SLJIT_VERBOSE && SLJIT_VERBOSE) \
|| (defined SLJIT_ARGUMENT_CHECKS && SLJIT_ARGUMENT_CHECKS)
compiler->skip_checks = 1;
#endif
FAIL_IF(sljit_emit_ijump(compiler, SLJIT_CALL1, SLJIT_IMM, SLJIT_FUNC_OFFSET(sljit_grow_stack)));
}
#endif
SLJIT_ASSERT(local_size > 0);
if (local_size <= 127) {
inst = (sljit_ub*)ensure_buf(compiler, 1 + 4);
FAIL_IF(!inst);
INC_SIZE(4);
*inst++ = REX_W;
*inst++ = GROUP_BINARY_83;
*inst++ = MOD_REG | SUB | 4;
*inst++ = local_size;
}
else {
inst = (sljit_ub*)ensure_buf(compiler, 1 + 7);
FAIL_IF(!inst);
INC_SIZE(7);
*inst++ = REX_W;
*inst++ = GROUP_BINARY_81;
*inst++ = MOD_REG | SUB | 4;
*(sljit_si*)inst = local_size;
inst += sizeof(sljit_si);
}
#ifdef _WIN64
/* Save xmm6 register: movaps [rsp + 0x20], xmm6 */
if (fscratches >= 6 || fsaveds >= 1) {
inst = (sljit_ub*)ensure_buf(compiler, 1 + 5);
FAIL_IF(!inst);
INC_SIZE(5);
*inst++ = GROUP_0F;
*(sljit_si*)inst = 0x20247429;
}
#endif
return SLJIT_SUCCESS;
}
SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_set_context(struct sljit_compiler *compiler,
sljit_si options, sljit_si args, sljit_si scratches, sljit_si saveds,
sljit_si fscratches, sljit_si fsaveds, sljit_si local_size)
{
sljit_si saved_register_size;
CHECK_ERROR();
CHECK(check_sljit_set_context(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size));
set_set_context(compiler, options, args, scratches, saveds, fscratches, fsaveds, local_size);
/* Including the return address saved by the call instruction. */
saved_register_size = GET_SAVED_REGISTERS_SIZE(scratches, saveds, 1);
compiler->local_size = ((local_size + SLJIT_LOCALS_OFFSET + saved_register_size + 15) & ~15) - saved_register_size;
return SLJIT_SUCCESS;
}
SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_return(struct sljit_compiler *compiler, sljit_si op, sljit_si src, sljit_sw srcw)
{
sljit_si i, tmp, size;
sljit_ub *inst;
CHECK_ERROR();
CHECK(check_sljit_emit_return(compiler, op, src, srcw));
compiler->flags_saved = 0;
FAIL_IF(emit_mov_before_return(compiler, op, src, srcw));
#ifdef _WIN64
/* Restore xmm6 register: movaps xmm6, [rsp + 0x20] */
if (compiler->fscratches >= 6 || compiler->fsaveds >= 1) {
inst = (sljit_ub*)ensure_buf(compiler, 1 + 5);
FAIL_IF(!inst);
INC_SIZE(5);
*inst++ = GROUP_0F;
*(sljit_si*)inst = 0x20247428;
}
#endif
SLJIT_ASSERT(compiler->local_size > 0);
if (compiler->local_size <= 127) {
inst = (sljit_ub*)ensure_buf(compiler, 1 + 4);
FAIL_IF(!inst);
INC_SIZE(4);
*inst++ = REX_W;
*inst++ = GROUP_BINARY_83;
*inst++ = MOD_REG | ADD | 4;
*inst = compiler->local_size;
}
else {
inst = (sljit_ub*)ensure_buf(compiler, 1 + 7);
FAIL_IF(!inst);
INC_SIZE(7);
*inst++ = REX_W;
*inst++ = GROUP_BINARY_81;
*inst++ = MOD_REG | ADD | 4;
*(sljit_si*)inst = compiler->local_size;
}
tmp = compiler->scratches;
for (i = SLJIT_FIRST_SAVED_REG; i <= tmp; i++) {
size = reg_map[i] >= 8 ? 2 : 1;
inst = (sljit_ub*)ensure_buf(compiler, 1 + size);
FAIL_IF(!inst);
INC_SIZE(size);
if (reg_map[i] >= 8)
*inst++ = REX_B;
POP_REG(reg_lmap[i]);
}
tmp = compiler->saveds < SLJIT_NUMBER_OF_SAVED_REGISTERS ? (SLJIT_S0 + 1 - compiler->saveds) : SLJIT_FIRST_SAVED_REG;
for (i = tmp; i <= SLJIT_S0; i++) {
size = reg_map[i] >= 8 ? 2 : 1;
inst = (sljit_ub*)ensure_buf(compiler, 1 + size);
FAIL_IF(!inst);
INC_SIZE(size);
if (reg_map[i] >= 8)
*inst++ = REX_B;
POP_REG(reg_lmap[i]);
}
inst = (sljit_ub*)ensure_buf(compiler, 1 + 1);
FAIL_IF(!inst);
INC_SIZE(1);
RET();
return SLJIT_SUCCESS;
}
/* --------------------------------------------------------------------- */
/* Operators */
/* --------------------------------------------------------------------- */
static sljit_si emit_do_imm32(struct sljit_compiler *compiler, sljit_ub rex, sljit_ub opcode, sljit_sw imm)
{
sljit_ub *inst;
sljit_si length = 1 + (rex ? 1 : 0) + sizeof(sljit_si);
inst = (sljit_ub*)ensure_buf(compiler, 1 + length);
FAIL_IF(!inst);
INC_SIZE(length);
if (rex)
*inst++ = rex;
*inst++ = opcode;
*(sljit_si*)inst = imm;
return SLJIT_SUCCESS;
}
static sljit_ub* emit_x86_instruction(struct sljit_compiler *compiler, sljit_si size,
/* The register or immediate operand. */
sljit_si a, sljit_sw imma,
/* The general operand (not immediate). */
sljit_si b, sljit_sw immb)
{
sljit_ub *inst;
sljit_ub *buf_ptr;
sljit_ub rex = 0;
sljit_si flags = size & ~0xf;
sljit_si inst_size;
/* The immediate operand must be 32 bit. */
SLJIT_ASSERT(!(a & SLJIT_IMM) || compiler->mode32 || IS_HALFWORD(imma));
/* Both cannot be switched on. */
SLJIT_ASSERT((flags & (EX86_BIN_INS | EX86_SHIFT_INS)) != (EX86_BIN_INS | EX86_SHIFT_INS));
/* Size flags not allowed for typed instructions. */
SLJIT_ASSERT(!(flags & (EX86_BIN_INS | EX86_SHIFT_INS)) || (flags & (EX86_BYTE_ARG | EX86_HALF_ARG)) == 0);
/* Both size flags cannot be switched on. */
SLJIT_ASSERT((flags & (EX86_BYTE_ARG | EX86_HALF_ARG)) != (EX86_BYTE_ARG | EX86_HALF_ARG));
/* SSE2 and immediate is not possible. */
SLJIT_ASSERT(!(a & SLJIT_IMM) || !(flags & EX86_SSE2));
SLJIT_ASSERT((flags & (EX86_PREF_F2 | EX86_PREF_F3)) != (EX86_PREF_F2 | EX86_PREF_F3)
&& (flags & (EX86_PREF_F2 | EX86_PREF_66)) != (EX86_PREF_F2 | EX86_PREF_66)
&& (flags & (EX86_PREF_F3 | EX86_PREF_66)) != (EX86_PREF_F3 | EX86_PREF_66));
size &= 0xf;
inst_size = size;
if (!compiler->mode32 && !(flags & EX86_NO_REXW))
rex |= REX_W;
else if (flags & EX86_REX)
rex |= REX;
if (flags & (EX86_PREF_F2 | EX86_PREF_F3))
inst_size++;
if (flags & EX86_PREF_66)
inst_size++;
/* Calculate size of b. */
inst_size += 1; /* mod r/m byte. */
if (b & SLJIT_MEM) {
if (!(b & OFFS_REG_MASK)) {
if (NOT_HALFWORD(immb)) {
if (emit_load_imm64(compiler, TMP_REG3, immb))
return NULL;
immb = 0;
if (b & REG_MASK)
b |= TO_OFFS_REG(TMP_REG3);
else
b |= TMP_REG3;
}
else if (reg_lmap[b & REG_MASK] == 4)
b |= TO_OFFS_REG(SLJIT_SP);
}
if ((b & REG_MASK) == SLJIT_UNUSED)
inst_size += 1 + sizeof(sljit_si); /* SIB byte required to avoid RIP based addressing. */
else {
if (reg_map[b & REG_MASK] >= 8)
rex |= REX_B;
if (immb != 0 && (!(b & OFFS_REG_MASK) || (b & OFFS_REG_MASK) == TO_OFFS_REG(SLJIT_SP))) {
/* Immediate operand. */
if (immb <= 127 && immb >= -128)
inst_size += sizeof(sljit_sb);
else
inst_size += sizeof(sljit_si);
}
else if (reg_lmap[b & REG_MASK] == 5)
inst_size += sizeof(sljit_sb);
if ((b & OFFS_REG_MASK) != SLJIT_UNUSED) {
inst_size += 1; /* SIB byte. */
if (reg_map[OFFS_REG(b)] >= 8)
rex |= REX_X;
}
}
}
else if (!(flags & EX86_SSE2_OP2) && reg_map[b] >= 8)
rex |= REX_B;
if (a & SLJIT_IMM) {
if (flags & EX86_BIN_INS) {
if (imma <= 127 && imma >= -128) {
inst_size += 1;
flags |= EX86_BYTE_ARG;
} else
inst_size += 4;
}
else if (flags & EX86_SHIFT_INS) {
imma &= compiler->mode32 ? 0x1f : 0x3f;
if (imma != 1) {
inst_size ++;
flags |= EX86_BYTE_ARG;
}
} else if (flags & EX86_BYTE_ARG)
inst_size++;
else if (flags & EX86_HALF_ARG)
inst_size += sizeof(short);
else
inst_size += sizeof(sljit_si);
}
else {
SLJIT_ASSERT(!(flags & EX86_SHIFT_INS) || a == SLJIT_PREF_SHIFT_REG);
/* reg_map[SLJIT_PREF_SHIFT_REG] is less than 8. */
if (!(flags & EX86_SSE2_OP1) && reg_map[a] >= 8)
rex |= REX_R;
}
if (rex)
inst_size++;
inst = (sljit_ub*)ensure_buf(compiler, 1 + inst_size);
PTR_FAIL_IF(!inst);
/* Encoding the byte. */
INC_SIZE(inst_size);
if (flags & EX86_PREF_F2)
*inst++ = 0xf2;
if (flags & EX86_PREF_F3)
*inst++ = 0xf3;
if (flags & EX86_PREF_66)
*inst++ = 0x66;
if (rex)
*inst++ = rex;
buf_ptr = inst + size;
/* Encode mod/rm byte. */
if (!(flags & EX86_SHIFT_INS)) {
if ((flags & EX86_BIN_INS) && (a & SLJIT_IMM))
*inst = (flags & EX86_BYTE_ARG) ? GROUP_BINARY_83 : GROUP_BINARY_81;
if ((a & SLJIT_IMM) || (a == 0))
*buf_ptr = 0;
else if (!(flags & EX86_SSE2_OP1))
*buf_ptr = reg_lmap[a] << 3;
else
*buf_ptr = a << 3;
}
else {
if (a & SLJIT_IMM) {
if (imma == 1)
*inst = GROUP_SHIFT_1;
else
*inst = GROUP_SHIFT_N;
} else
*inst = GROUP_SHIFT_CL;
*buf_ptr = 0;
}
if (!(b & SLJIT_MEM))
*buf_ptr++ |= MOD_REG + ((!(flags & EX86_SSE2_OP2)) ? reg_lmap[b] : b);
else if ((b & REG_MASK) != SLJIT_UNUSED) {
if ((b & OFFS_REG_MASK) == SLJIT_UNUSED || (b & OFFS_REG_MASK) == TO_OFFS_REG(SLJIT_SP)) {
if (immb != 0 || reg_lmap[b & REG_MASK] == 5) {
if (immb <= 127 && immb >= -128)
*buf_ptr |= 0x40;
else
*buf_ptr |= 0x80;
}
if ((b & OFFS_REG_MASK) == SLJIT_UNUSED)
*buf_ptr++ |= reg_lmap[b & REG_MASK];
else {
*buf_ptr++ |= 0x04;
*buf_ptr++ = reg_lmap[b & REG_MASK] | (reg_lmap[OFFS_REG(b)] << 3);
}
if (immb != 0 || reg_lmap[b & REG_MASK] == 5) {
if (immb <= 127 && immb >= -128)
*buf_ptr++ = immb; /* 8 bit displacement. */
else {
*(sljit_si*)buf_ptr = immb; /* 32 bit displacement. */
buf_ptr += sizeof(sljit_si);
}
}
}
else {
if (reg_lmap[b & REG_MASK] == 5)
*buf_ptr |= 0x40;
*buf_ptr++ |= 0x04;
*buf_ptr++ = reg_lmap[b & REG_MASK] | (reg_lmap[OFFS_REG(b)] << 3) | (immb << 6);
if (reg_lmap[b & REG_MASK] == 5)
*buf_ptr++ = 0;
}
}
else {
*buf_ptr++ |= 0x04;
*buf_ptr++ = 0x25;
*(sljit_si*)buf_ptr = immb; /* 32 bit displacement. */
buf_ptr += sizeof(sljit_si);
}
if (a & SLJIT_IMM) {
if (flags & EX86_BYTE_ARG)
*buf_ptr = imma;
else if (flags & EX86_HALF_ARG)
*(short*)buf_ptr = imma;
else if (!(flags & EX86_SHIFT_INS))
*(sljit_si*)buf_ptr = imma;
}
return !(flags & EX86_SHIFT_INS) ? inst : (inst + 1);
}
/* --------------------------------------------------------------------- */
/* Call / return instructions */
/* --------------------------------------------------------------------- */
static SLJIT_INLINE sljit_si call_with_args(struct sljit_compiler *compiler, sljit_si type)
{
sljit_ub *inst;
#ifndef _WIN64
SLJIT_COMPILE_ASSERT(reg_map[SLJIT_R1] == 6 && reg_map[SLJIT_R0] < 8 && reg_map[SLJIT_R2] < 8, args_registers);
inst = (sljit_ub*)ensure_buf(compiler, 1 + ((type < SLJIT_CALL3) ? 3 : 6));
FAIL_IF(!inst);
INC_SIZE((type < SLJIT_CALL3) ? 3 : 6);
if (type >= SLJIT_CALL3) {
*inst++ = REX_W;
*inst++ = MOV_r_rm;
*inst++ = MOD_REG | (0x2 /* rdx */ << 3) | reg_lmap[SLJIT_R2];
}
*inst++ = REX_W;
*inst++ = MOV_r_rm;
*inst++ = MOD_REG | (0x7 /* rdi */ << 3) | reg_lmap[SLJIT_R0];
#else
SLJIT_COMPILE_ASSERT(reg_map[SLJIT_R1] == 2 && reg_map[SLJIT_R0] < 8 && reg_map[SLJIT_R2] < 8, args_registers);
inst = (sljit_ub*)ensure_buf(compiler, 1 + ((type < SLJIT_CALL3) ? 3 : 6));
FAIL_IF(!inst);
INC_SIZE((type < SLJIT_CALL3) ? 3 : 6);
if (type >= SLJIT_CALL3) {
*inst++ = REX_W | REX_R;
*inst++ = MOV_r_rm;
*inst++ = MOD_REG | (0x0 /* r8 */ << 3) | reg_lmap[SLJIT_R2];
}
*inst++ = REX_W;
*inst++ = MOV_r_rm;
*inst++ = MOD_REG | (0x1 /* rcx */ << 3) | reg_lmap[SLJIT_R0];
#endif
return SLJIT_SUCCESS;
}
SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_enter(struct sljit_compiler *compiler, sljit_si dst, sljit_sw dstw)
{
sljit_ub *inst;
CHECK_ERROR();
CHECK(check_sljit_emit_fast_enter(compiler, dst, dstw));
ADJUST_LOCAL_OFFSET(dst, dstw);
/* For UNUSED dst. Uncommon, but possible. */
if (dst == SLJIT_UNUSED)
dst = TMP_REG1;
if (FAST_IS_REG(dst)) {
if (reg_map[dst] < 8) {
inst = (sljit_ub*)ensure_buf(compiler, 1 + 1);
FAIL_IF(!inst);
INC_SIZE(1);
POP_REG(reg_lmap[dst]);
return SLJIT_SUCCESS;
}
inst = (sljit_ub*)ensure_buf(compiler, 1 + 2);
FAIL_IF(!inst);
INC_SIZE(2);
*inst++ = REX_B;
POP_REG(reg_lmap[dst]);
return SLJIT_SUCCESS;
}
/* REX_W is not necessary (src is not immediate). */
compiler->mode32 = 1;
inst = emit_x86_instruction(compiler, 1, 0, 0, dst, dstw);
FAIL_IF(!inst);
*inst++ = POP_rm;
return SLJIT_SUCCESS;
}
SLJIT_API_FUNC_ATTRIBUTE sljit_si sljit_emit_fast_return(struct sljit_compiler *compiler, sljit_si src, sljit_sw srcw)
{
sljit_ub *inst;
CHECK_ERROR();
CHECK(check_sljit_emit_fast_return(compiler, src, srcw));
ADJUST_LOCAL_OFFSET(src, srcw);
if ((src & SLJIT_IMM) && NOT_HALFWORD(srcw)) {
FAIL_IF(emit_load_imm64(compiler, TMP_REG1, srcw));
src = TMP_REG1;
}
if (FAST_IS_REG(src)) {
if (reg_map[src] < 8) {
inst = (sljit_ub*)ensure_buf(compiler, 1 + 1 + 1);
FAIL_IF(!inst);
INC_SIZE(1 + 1);
PUSH_REG(reg_lmap[src]);
}
else {
inst = (sljit_ub*)ensure_buf(compiler, 1 + 2 + 1);
FAIL_IF(!inst);
INC_SIZE(2 + 1);
*inst++ = REX_B;
PUSH_REG(reg_lmap[src]);
}
}
else if (src & SLJIT_MEM) {
/* REX_W is not necessary (src is not immediate). */
compiler->mode32 = 1;
inst = emit_x86_instruction(compiler, 1, 0, 0, src, srcw);
FAIL_IF(!inst);
*inst++ = GROUP_FF;
*inst |= PUSH_rm;
inst = (sljit_ub*)ensure_buf(compiler, 1 + 1);
FAIL_IF(!inst);
INC_SIZE(1);
}
else {
SLJIT_ASSERT(IS_HALFWORD(srcw));
/* SLJIT_IMM. */
inst = (sljit_ub*)ensure_buf(compiler, 1 + 5 + 1);
FAIL_IF(!inst);
INC_SIZE(5 + 1);
*inst++ = PUSH_i32;
*(sljit_si*)inst = srcw;
inst += sizeof(sljit_si);
}
RET();
return SLJIT_SUCCESS;
}
/* --------------------------------------------------------------------- */
/* Extend input */
/* --------------------------------------------------------------------- */
static sljit_si emit_mov_int(struct sljit_compiler *compiler, sljit_si sign,
sljit_si dst, sljit_sw dstw,
sljit_si src, sljit_sw srcw)
{
sljit_ub* inst;
sljit_si dst_r;
compiler->mode32 = 0;
if (dst == SLJIT_UNUSED && !(src & SLJIT_MEM))
return SLJIT_SUCCESS; /* Empty instruction. */
if (src & SLJIT_IMM) {
if (FAST_IS_REG(dst)) {
if (sign || ((sljit_uw)srcw <= 0x7fffffff)) {
inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, (sljit_sw)(sljit_si)srcw, dst, dstw);
FAIL_IF(!inst);
*inst = MOV_rm_i32;
return SLJIT_SUCCESS;
}
return emit_load_imm64(compiler, dst, srcw);
}
compiler->mode32 = 1;
inst = emit_x86_instruction(compiler, 1, SLJIT_IMM, (sljit_sw)(sljit_si)srcw, dst, dstw);
FAIL_IF(!inst);
*inst = MOV_rm_i32;
compiler->mode32 = 0;
return SLJIT_SUCCESS;
}
dst_r = FAST_IS_REG(dst) ? dst : TMP_REG1;
if ((dst & SLJIT_MEM) && FAST_IS_REG(src))
dst_r = src;
else {
if (sign) {
inst = emit_x86_instruction(compiler, 1, dst_r, 0, src, srcw);
FAIL_IF(!inst);
*inst++ = MOVSXD_r_rm;
} else {
compiler->mode32 = 1;
FAIL_IF(emit_mov(compiler, dst_r, 0, src, srcw));
compiler->mode32 = 0;
}
}
if (dst & SLJIT_MEM) {
compiler->mode32 = 1;
inst = emit_x86_instruction(compiler, 1, dst_r, 0, dst, dstw);
FAIL_IF(!inst);
*inst = MOV_rm_r;
compiler->mode32 = 0;
}
return SLJIT_SUCCESS;
}
File diff suppressed because it is too large. Load diff
+334
View File
@@ -0,0 +1,334 @@
/*
* Stack-less Just-In-Time compiler
*
* Copyright 2009-2012 Zoltan Herczeg (hzmester@freemail.hu). All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list
* of conditions and the following disclaimer in the documentation and/or other materials
* provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) AND CONTRIBUTORS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE COPYRIGHT HOLDER(S) OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* ------------------------------------------------------------------------ */
/* Locks */
/* ------------------------------------------------------------------------ */
#if (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR) || (defined SLJIT_UTIL_GLOBAL_LOCK && SLJIT_UTIL_GLOBAL_LOCK)
#if (defined SLJIT_SINGLE_THREADED && SLJIT_SINGLE_THREADED)
#if (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR)
static SLJIT_INLINE void allocator_grab_lock(void)
{
/* Always successful. */
}
static SLJIT_INLINE void allocator_release_lock(void)
{
/* Always successful. */
}
#endif /* SLJIT_EXECUTABLE_ALLOCATOR */
#if (defined SLJIT_UTIL_GLOBAL_LOCK && SLJIT_UTIL_GLOBAL_LOCK)
SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_grab_lock(void)
{
/* Always successful. */
}
SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_release_lock(void)
{
/* Always successful. */
}
#endif /* SLJIT_UTIL_GLOBAL_LOCK */
#elif defined(_WIN32) /* SLJIT_SINGLE_THREADED */
#include "windows.h"
#if (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR)
static HANDLE allocator_mutex = 0;
static SLJIT_INLINE void allocator_grab_lock(void)
{
/* No idea what to do if an error occures. Static mutexes should never fail... */
if (!allocator_mutex)
allocator_mutex = CreateMutex(NULL, TRUE, NULL);
else
WaitForSingleObject(allocator_mutex, INFINITE);
}
static SLJIT_INLINE void allocator_release_lock(void)
{
ReleaseMutex(allocator_mutex);
}
#endif /* SLJIT_EXECUTABLE_ALLOCATOR */
#if (defined SLJIT_UTIL_GLOBAL_LOCK && SLJIT_UTIL_GLOBAL_LOCK)
static HANDLE global_mutex = 0;
SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_grab_lock(void)
{
/* No idea what to do if an error occures. Static mutexes should never fail... */
if (!global_mutex)
global_mutex = CreateMutex(NULL, TRUE, NULL);
else
WaitForSingleObject(global_mutex, INFINITE);
}
SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_release_lock(void)
{
ReleaseMutex(global_mutex);
}
#endif /* SLJIT_UTIL_GLOBAL_LOCK */
#else /* _WIN32 */
#if (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR)
#include <pthread.h>
static pthread_mutex_t allocator_mutex = PTHREAD_MUTEX_INITIALIZER;
static SLJIT_INLINE void allocator_grab_lock(void)
{
pthread_mutex_lock(&allocator_mutex);
}
static SLJIT_INLINE void allocator_release_lock(void)
{
pthread_mutex_unlock(&allocator_mutex);
}
#endif /* SLJIT_EXECUTABLE_ALLOCATOR */
#if (defined SLJIT_UTIL_GLOBAL_LOCK && SLJIT_UTIL_GLOBAL_LOCK)
#include <pthread.h>
static pthread_mutex_t global_mutex = PTHREAD_MUTEX_INITIALIZER;
SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_grab_lock(void)
{
pthread_mutex_lock(&global_mutex);
}
SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_release_lock(void)
{
pthread_mutex_unlock(&global_mutex);
}
#endif /* SLJIT_UTIL_GLOBAL_LOCK */
#endif /* _WIN32 */
/* ------------------------------------------------------------------------ */
/* Stack */
/* ------------------------------------------------------------------------ */
#if (defined SLJIT_UTIL_STACK && SLJIT_UTIL_STACK) || (defined SLJIT_EXECUTABLE_ALLOCATOR && SLJIT_EXECUTABLE_ALLOCATOR)
#ifdef _WIN32
#include "windows.h"
#else
/* Provides mmap function. */
#include <sys/mman.h>
/* For detecting the page size. */
#include <unistd.h>
#ifndef MAP_ANON
#include <fcntl.h>
/* Some old systems does not have MAP_ANON. */
static sljit_si dev_zero = -1;
#if (defined SLJIT_SINGLE_THREADED && SLJIT_SINGLE_THREADED)
static SLJIT_INLINE sljit_si open_dev_zero(void)
{
dev_zero = open("/dev/zero", O_RDWR);
return dev_zero < 0;
}
#else /* SLJIT_SINGLE_THREADED */
#include <pthread.h>
static pthread_mutex_t dev_zero_mutex = PTHREAD_MUTEX_INITIALIZER;
static SLJIT_INLINE sljit_si open_dev_zero(void)
{
pthread_mutex_lock(&dev_zero_mutex);
dev_zero = open("/dev/zero", O_RDWR);
pthread_mutex_unlock(&dev_zero_mutex);
return dev_zero < 0;
}
#endif /* SLJIT_SINGLE_THREADED */
#endif
#endif
#endif /* SLJIT_UTIL_STACK || SLJIT_EXECUTABLE_ALLOCATOR */
#if (defined SLJIT_UTIL_STACK && SLJIT_UTIL_STACK)
/* Planning to make it even more clever in the future. */
static sljit_sw sljit_page_align = 0;
SLJIT_API_FUNC_ATTRIBUTE struct sljit_stack* SLJIT_CALL sljit_allocate_stack(sljit_uw limit, sljit_uw max_limit, void *allocator_data)
{
struct sljit_stack *stack;
union {
void *ptr;
sljit_uw uw;
} base;
#ifdef _WIN32
SYSTEM_INFO si;
#endif
SLJIT_UNUSED_ARG(allocator_data);
if (limit > max_limit || limit < 1)
return NULL;
#ifdef _WIN32
if (!sljit_page_align) {
GetSystemInfo(&si);
sljit_page_align = si.dwPageSize - 1;
}
#else
if (!sljit_page_align) {
sljit_page_align = sysconf(_SC_PAGESIZE);
/* Should never happen. */
if (sljit_page_align < 0)
sljit_page_align = 4096;
sljit_page_align--;
}
#endif
/* Align limit and max_limit. */
max_limit = (max_limit + sljit_page_align) & ~sljit_page_align;
stack = (struct sljit_stack*)SLJIT_MALLOC(sizeof(struct sljit_stack), allocator_data);
if (!stack)
return NULL;
#ifdef _WIN32
base.ptr = VirtualAlloc(NULL, max_limit, MEM_RESERVE, PAGE_READWRITE);
if (!base.ptr) {
SLJIT_FREE(stack, allocator_data);
return NULL;
}
stack->base = base.uw;
stack->limit = stack->base;
stack->max_limit = stack->base + max_limit;
if (sljit_stack_resize(stack, stack->base + limit)) {
sljit_free_stack(stack, allocator_data);
return NULL;
}
#else
#ifdef MAP_ANON
base.ptr = mmap(NULL, max_limit, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
#else
if (dev_zero < 0) {
if (open_dev_zero()) {
SLJIT_FREE(stack, allocator_data);
return NULL;
}
}
base.ptr = mmap(NULL, max_limit, PROT_READ | PROT_WRITE, MAP_PRIVATE, dev_zero, 0);
#endif
if (base.ptr == MAP_FAILED) {
SLJIT_FREE(stack, allocator_data);
return NULL;
}
stack->base = base.uw;
stack->limit = stack->base + limit;
stack->max_limit = stack->base + max_limit;
#endif
stack->top = stack->base;
return stack;
}
#undef PAGE_ALIGN
SLJIT_API_FUNC_ATTRIBUTE void SLJIT_CALL sljit_free_stack(struct sljit_stack* stack, void *allocator_data)
{
SLJIT_UNUSED_ARG(allocator_data);
#ifdef _WIN32
VirtualFree((void*)stack->base, 0, MEM_RELEASE);
#else
munmap((void*)stack->base, stack->max_limit - stack->base);
#endif
SLJIT_FREE(stack, allocator_data);
}
SLJIT_API_FUNC_ATTRIBUTE sljit_sw SLJIT_CALL sljit_stack_resize(struct sljit_stack* stack, sljit_uw new_limit)
{
sljit_uw aligned_old_limit;
sljit_uw aligned_new_limit;
if ((new_limit > stack->max_limit) || (new_limit < stack->base))
return -1;
#ifdef _WIN32
aligned_new_limit = (new_limit + sljit_page_align) & ~sljit_page_align;
aligned_old_limit = (stack->limit + sljit_page_align) & ~sljit_page_align;
if (aligned_new_limit != aligned_old_limit) {
if (aligned_new_limit > aligned_old_limit) {
if (!VirtualAlloc((void*)aligned_old_limit, aligned_new_limit - aligned_old_limit, MEM_COMMIT, PAGE_READWRITE))
return -1;
}
else {
if (!VirtualFree((void*)aligned_new_limit, aligned_old_limit - aligned_new_limit, MEM_DECOMMIT))
return -1;
}
}
stack->limit = new_limit;
return 0;
#else
if (new_limit >= stack->limit) {
stack->limit = new_limit;
return 0;
}
aligned_new_limit = (new_limit + sljit_page_align) & ~sljit_page_align;
aligned_old_limit = (stack->limit + sljit_page_align) & ~sljit_page_align;
/* If madvise is available, we release the unnecessary space. */
#if defined(MADV_DONTNEED)
if (aligned_new_limit < aligned_old_limit)
madvise((void*)aligned_new_limit, aligned_old_limit - aligned_new_limit, MADV_DONTNEED);
#elif defined(POSIX_MADV_DONTNEED)
if (aligned_new_limit < aligned_old_limit)
posix_madvise((void*)aligned_new_limit, aligned_old_limit - aligned_new_limit, POSIX_MADV_DONTNEED);
#endif
stack->limit = new_limit;
return 0;
#endif
}
#endif /* SLJIT_UTIL_STACK */
#endif
+45 -10
View File
@@ -169,13 +169,14 @@ static PHP_MSHUTDOWN_FUNCTION(pcre)
/* {{{ static pcre_clean_cache */
static int pcre_clean_cache(void *data, void *arg TSRMLS_DC)
{
pcre_cache_entry *pce = (pcre_cache_entry *) data;
int *num_clean = (int *)arg;
if (*num_clean > 0) {
if (*num_clean > 0 && !pce->refcount) {
(*num_clean)--;
return 1;
return ZEND_HASH_APPLY_REMOVE;
} else {
return 0;
return ZEND_HASH_APPLY_KEEP;
}
}
/* }}} */
@@ -224,6 +225,25 @@ static char **make_subpats_table(int num_subpats, pcre_cache_entry *pce TSRMLS_D
}
/* }}} */
/* {{{ static calculate_unit_length */
/* Calculates the byte length of the next character. Assumes valid UTF-8 for PCRE_UTF8. */
static zend_always_inline int calculate_unit_length(pcre_cache_entry *pce, char *start)
{
int unit_len;
if (pce->compile_options & PCRE_UTF8) {
char *end = start;
/* skip continuation bytes */
while ((*++end & 0xC0) == 0x80);
unit_len = end - start;
} else {
unit_len = 1;
}
return unit_len;
}
/* }}} */
/* {{{ pcre_get_compiled_regex_cache
*/
PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(char *regex, int regex_len TSRMLS_DC)
@@ -446,6 +466,7 @@ PHPAPI pcre_cache_entry* pcre_get_compiled_regex_cache(char *regex, int regex_le
new_entry.locale = pestrdup(locale, 1);
new_entry.tables = tables;
#endif
new_entry.refcount = 0;
/*
* Interned strings are not duplicated when stored in HashTable,
@@ -550,8 +571,10 @@ static void php_do_pcre_match(INTERNAL_FUNCTION_PARAMETERS, int global) /* {{{ *
RETURN_FALSE;
}
pce->refcount++;
php_pcre_match_impl(pce, subject, subject_len, return_value, subpats,
global, ZEND_NUM_ARGS() >= 4, flags, start_offset TSRMLS_CC);
pce->refcount--;
}
/* }}} */
@@ -754,8 +777,10 @@ PHPAPI void php_pcre_match_impl(pcre_cache_entry *pce, char *subject, int subjec
the start offset, and continue. Fudge the offset values
to achieve this, unless we're already at the end of the string. */
if (g_notempty != 0 && start_offset < subject_len) {
int unit_len = calculate_unit_length(pce, subject + start_offset);
offsets[0] = start_offset;
offsets[1] = start_offset + 1;
offsets[1] = start_offset + unit_len;
} else
break;
} else {
@@ -988,14 +1013,18 @@ PHPAPI char *php_pcre_replace(char *regex, int regex_len,
int *result_len, int limit, int *replace_count TSRMLS_DC)
{
pcre_cache_entry *pce; /* Compiled regular expression */
char *result; /* Function result */
/* Compile regex or get it from cache. */
if ((pce = pcre_get_compiled_regex_cache(regex, regex_len TSRMLS_CC)) == NULL) {
return NULL;
}
return php_pcre_replace_impl(pce, subject, subject_len, replace_val,
pce->refcount++;
result = php_pcre_replace_impl(pce, subject, subject_len, replace_val,
is_callable_replace, result_len, limit, replace_count TSRMLS_CC);
pce->refcount--;
return result;
}
/* }}} */
@@ -1198,10 +1227,12 @@ PHPAPI char *php_pcre_replace_impl(pcre_cache_entry *pce, char *subject, int sub
the start offset, and continue. Fudge the offset values
to achieve this, unless we're already at the end of the string. */
if (g_notempty != 0 && start_offset < subject_len) {
int unit_len = calculate_unit_length(pce, piece);
offsets[0] = start_offset;
offsets[1] = start_offset + 1;
memcpy(&result[*result_len], piece, 1);
(*result_len)++;
offsets[1] = start_offset + unit_len;
memcpy(&result[*result_len], piece, unit_len);
*result_len += unit_len;
} else {
new_len = *result_len + subject_len - start_offset;
if (new_len + 1 > alloc_len) {
@@ -1476,7 +1507,9 @@ static PHP_FUNCTION(preg_split)
RETURN_FALSE;
}
pce->refcount++;
php_pcre_split_impl(pce, subject, subject_len, return_value, limit_val, flags TSRMLS_CC);
pce->refcount--;
}
/* }}} */
@@ -1756,8 +1789,10 @@ static PHP_FUNCTION(preg_grep)
if ((pce = pcre_get_compiled_regex_cache(regex, regex_len TSRMLS_CC)) == NULL) {
RETURN_FALSE;
}
pce->refcount++;
php_pcre_grep_impl(pce, input, return_value, flags TSRMLS_CC);
pce->refcount--;
}
/* }}} */
+13
View File
@@ -0,0 +1,13 @@
--TEST--
Bug #53823 - preg_replace: * qualifier on unicode replace garbles the string
--FILE--
<?php
var_dump(preg_replace('/[^\pL\pM]*/iu', '', 'áéíóú'));
// invalid UTF-8
var_dump(preg_replace('/[^\pL\pM]*/iu', '', "\xFCáéíóú"));
var_dump(preg_replace('/[^\pL\pM]*/iu', '', "áéíóú\xFC"));
?>
--EXPECT--
string(10) "áéíóú"
NULL
NULL
+47
View File
@@ -0,0 +1,47 @@
--TEST--
Bug #66121 - UTF-8 lookbehinds match bytes instead of characters
--FILE--
<?php
// Sinhala characters
var_dump(preg_replace('/(?<!ක)/u', '*', 'ක'));
var_dump(preg_replace('/(?<!ක)/u', '*', 'ම'));
// English characters
var_dump(preg_replace('/(?<!k)/u', '*', 'k'));
var_dump(preg_replace('/(?<!k)/u', '*', 'm'));
// Sinhala characters
preg_match_all('/(?<!ක)/u', 'ම', $matches, PREG_OFFSET_CAPTURE);
var_dump($matches);
// invalid UTF-8
var_dump(preg_replace('/(?<!ක)/u', '*', "\xFCක"));
var_dump(preg_replace('/(?<!ක)/u', '*', "ක\xFC"));
var_dump(preg_match_all('/(?<!ක)/u', "\xFCම", $matches, PREG_OFFSET_CAPTURE));
var_dump(preg_match_all('/(?<!ක)/u', "\xFCම", $matches, PREG_OFFSET_CAPTURE));
?>
--EXPECT--
string(4) "*ක"
string(5) "*ම*"
string(2) "*k"
string(3) "*m*"
array(1) {
[0]=>
array(2) {
[0]=>
array(2) {
[0]=>
string(0) ""
[1]=>
int(0)
}
[1]=>
array(2) {
[0]=>
string(0) ""
[1]=>
int(3)
}
}
}
NULL
NULL
bool(false)
bool(false)
+36
View File
@@ -0,0 +1,36 @@
--TEST--
Bug #69864 (Segfault in preg_replace_callback)
--FILE--
<?php
const PREG_CACHE_SIZE = 4096; // this has to be >= the resp. constant in php_pcre.c
var_dump(preg_replace_callback('/a/', function($m) {
for ($i = 0; $i < PREG_CACHE_SIZE; $i++) {
preg_match('/foo' . $i . 'bar/', '???foo' . $i . 'bar???');
}
return 'b';
}, 'aa'));
var_dump(preg_replace_callback('/a/', function($m) {
for ($i = 0; $i < PREG_CACHE_SIZE; $i++) {
preg_replace('/foo' . $i . 'bar/', 'baz', '???foo' . $i . 'bar???');
}
return 'b';
}, 'aa'));
var_dump(preg_replace_callback('/a/', function($m) {
for ($i = 0; $i < PREG_CACHE_SIZE; $i++) {
preg_split('/foo' . $i . 'bar/', '???foo' . $i . 'bar???');
}
return 'b';
}, 'aa'));
var_dump(preg_replace_callback('/a/', function($m) {
for ($i = 0; $i < PREG_CACHE_SIZE; $i++) {
preg_grep('/foo' . $i . 'bar/', ['???foo' . $i . 'bar???']);
}
return 'b';
}, 'aa'));
?>
--EXPECT--
string(2) "bb"
string(2) "bb"
string(2) "bb"
string(2) "bb"
+28 -31
View File
@@ -27,6 +27,7 @@
#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "ext/standard/php_string.h"
#include "pdo/php_pdo.h"
#include "pdo/php_pdo_driver.h"
#include "ext/standard/file.h"
@@ -60,6 +61,17 @@ static char * _pdo_pgsql_trim_message(const char *message, int persistent)
return tmp;
}
static char * _pdo_pgsql_escape_credentials(char *str TSRMLS_DC)
{
int len;
if (str) {
return php_addcslashes(str, strlen(str), &len, 0, "\\'", sizeof("\\'") TSRMLS_CC);
}
return NULL;
}
int _pdo_pgsql_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, int errcode, const char *sqlstate, const char *file, int line TSRMLS_DC) /* {{{ */
{
pdo_pgsql_db_handle *H = (pdo_pgsql_db_handle *)dbh->driver_data;
@@ -1055,7 +1067,7 @@ static int pdo_pgsql_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_
pdo_pgsql_db_handle *H;
int ret = 0;
char *conn_str, *p, *e;
char *tmp_pass;
char *tmp_user, *tmp_pass;
long connect_timeout = 30;
H = pecalloc(1, sizeof(pdo_pgsql_db_handle), dbh->is_persistent);
@@ -1063,7 +1075,7 @@ static int pdo_pgsql_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_
H->einfo.errcode = 0;
H->einfo.errmsg = NULL;
/* PostgreSQL wants params in the connect string to be separated by spaces,
* if the PDO standard semicolons are used, we convert them to spaces
*/
@@ -1077,42 +1089,27 @@ static int pdo_pgsql_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_
connect_timeout = pdo_attr_lval(driver_options, PDO_ATTR_TIMEOUT, 30 TSRMLS_CC);
}
if (dbh->password) {
if (dbh->password[0] != '\'' && dbh->password[strlen(dbh->password) - 1] != '\'') {
char *pwd = dbh->password;
int pos = 1;
tmp_pass = safe_emalloc(2, strlen(dbh->password), 3);
tmp_pass[0] = '\'';
while (*pwd != '\0') {
if (*pwd == '\\' || *pwd == '\'') {
tmp_pass[pos++] = '\\';
}
tmp_pass[pos++] = *pwd++;
}
tmp_pass[pos++] = '\'';
tmp_pass[pos] = '\0';
} else {
tmp_pass = dbh->password;
}
}
/* escape username and password, if provided */
tmp_user = _pdo_pgsql_escape_credentials(dbh->username TSRMLS_CC);
tmp_pass = _pdo_pgsql_escape_credentials(dbh->password TSRMLS_CC);
/* support both full connection string & connection string + login and/or password */
if (dbh->username && dbh->password) {
spprintf(&conn_str, 0, "%s user=%s password=%s connect_timeout=%ld", dbh->data_source, dbh->username, tmp_pass, connect_timeout);
} else if (dbh->username) {
spprintf(&conn_str, 0, "%s user=%s connect_timeout=%ld", dbh->data_source, dbh->username, connect_timeout);
} else if (dbh->password) {
spprintf(&conn_str, 0, "%s password=%s connect_timeout=%ld", dbh->data_source, tmp_pass, connect_timeout);
if (tmp_user && tmp_pass) {
spprintf(&conn_str, 0, "%s user='%s' password='%s' connect_timeout=%ld", dbh->data_source, tmp_user, tmp_pass, connect_timeout);
} else if (tmp_user) {
spprintf(&conn_str, 0, "%s user='%s' connect_timeout=%ld", dbh->data_source, tmp_user, connect_timeout);
} else if (tmp_pass) {
spprintf(&conn_str, 0, "%s password='%s' connect_timeout=%ld", dbh->data_source, tmp_pass, connect_timeout);
} else {
spprintf(&conn_str, 0, "%s connect_timeout=%ld", (char *) dbh->data_source, connect_timeout);
}
H->server = PQconnectdb(conn_str);
if (dbh->password && tmp_pass != dbh->password) {
if (tmp_user) {
efree(tmp_user);
}
if (tmp_pass) {
efree(tmp_pass);
}
+9 -3
View File
@@ -220,7 +220,7 @@ stmt_retry:
return 0;
}
if (!stmt->executed && !stmt->column_count) {
if (!stmt->executed && (!stmt->column_count || S->cols == NULL)) {
stmt->column_count = (int) PQnfields(S->result);
S->cols = ecalloc(stmt->column_count, sizeof(pdo_pgsql_column));
}
@@ -294,8 +294,8 @@ static int pgsql_stmt_param_hook(pdo_stmt_t *stmt, struct pdo_bound_param_data *
sizeof(Oid));
}
if (param->paramno >= 0) {
if (param->paramno >= zend_hash_num_elements(stmt->bound_param_map)) {
pdo_pgsql_error_stmt(stmt, PGRES_FATAL_ERROR, "HY105");
if (param->paramno >= zend_hash_num_elements(stmt->bound_params)) {
pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "parameter was not defined" TSRMLS_CC);
return 0;
}
@@ -614,6 +614,12 @@ done:
static int pdo_pgsql_stmt_cursor_closer(pdo_stmt_t *stmt TSRMLS_DC)
{
pdo_pgsql_stmt *S = (pdo_pgsql_stmt*)stmt->driver_data;
if (S->cols != NULL){
efree(S->cols);
S->cols = NULL;
}
return 1;
}
+44
View File
@@ -0,0 +1,44 @@
--TEST--
PDO PgSQL Bug #69344 (PDO PgSQL Incorrect binding numeric array with gaps)
--SKIPIF--
<?php
if (!extension_loaded('pdo') || !extension_loaded('pdo_pgsql')) die('skip not loaded');
require dirname(__FILE__) . '/config.inc';
require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc';
PDOTest::skip();
?>
--FILE--
<?php
require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc';
$pdo = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt');
$pdo->setAttribute (\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute (\PDO::ATTR_DEFAULT_FETCH_MODE, \PDO::FETCH_ASSOC);
$test = function () use ($pdo) {
$arr = [
0 => "a",
2 => "b",
];
$stmt = $pdo->prepare("SELECT (?)::text AS a, (?)::text AS b");
try {
$stmt->execute($arr);
var_dump($stmt->fetch());
} catch (\Exception $e) {
echo $e->getMessage()."\n";
}
};
$test();
$pdo->setAttribute(\PDO::ATTR_EMULATE_PREPARES, true);
$test();
?>
--EXPECT--
SQLSTATE[HY093]: Invalid parameter number: parameter was not defined
SQLSTATE[HY093]: Invalid parameter number: parameter was not defined
+63
View File
@@ -0,0 +1,63 @@
--TEST--
PDO PgSQL Bug #69362 (PDO-pgsql fails to connect if password contains a leading single quote)
--SKIPIF--
<?php
if (!extension_loaded('pdo') || !extension_loaded('pdo_pgsql')) die('skip not loaded');
require dirname(__FILE__) . '/config.inc';
require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc';
PDOTest::skip();
$dsn = getenv('PDOTEST_DSN');
if (empty($dsn)) die('skip no dsn found in env');
$db = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$user = 'pdo_test_'.rand(5, 400);
$pass = 'testpass';
// Assume that if we can't create or drop a user, this test needs to be skipped
try {
$db->exec("DROP USER IF EXISTS $user");
$db->exec("CREATE USER $user WITH PASSWORD '$pass'");
} catch (PDOException $e) {
die("skip You need CREATEUSER permissions to run the test");
}
// Peer authentication might prevent the test from properly running
try {
$testConn = new PDO($dsn, $user, $pass);
} catch (PDOException $e) {
echo "skip ".$e->getMessage();
}
$db->exec("DROP USER $user");
?>
--FILE--
<?php
require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc';
$pdo = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt');
$pdo->setAttribute(PDO::ATTR_EMULATE_PREPARES, true);
$rand = rand(5, 400);
$user = "pdo_test_$rand";
$template = "CREATE USER $user WITH PASSWORD '%s'";
$dropUser = "DROP USER $user";
$testQuery = 'SELECT 1 as verification';
// Create temp user with leading single quote
$sql = sprintf($template, "''mypassword");
$pdo->query($sql);
$testConn = new PDO($conf['ENV']['PDOTEST_DSN'], $user, "'mypassword");
$result = $testConn->query($testQuery)->fetch();
$check = $result[0];
var_dump($check);
// Remove the user
$pdo->query($dropUser);
?>
--EXPECT--
int(1)
+55
View File
@@ -0,0 +1,55 @@
--TEST--
PDO PgSQL Bug #69752 (memory leak with closeCursor)
--SKIPIF--
<?php
if (!extension_loaded('pdo') || !extension_loaded('pdo_pgsql')) die('skip not loaded');
require dirname(__FILE__) . '/config.inc';
require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc';
PDOTest::skip();
?>
--FILE--
<?php
require dirname(__FILE__) . '/../../../ext/pdo/tests/pdo_test.inc';
$pdo = PDOTest::test_factory(dirname(__FILE__) . '/common.phpt');
$pdo->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
$pdo->beginTransaction();
$pdo->exec("
create table foo (
id bigserial not null primary key,
field1 text not null,
field2 text not null,
field3 text not null,
field4 int4 not null
)
");
$stmt = $pdo->prepare("insert into foo (field1, field2, field3, field4) values (:field1, :field2, :field3, :field4)");
$max = 1000;
$first_time_usage = null;
for($i = 0; $i < $max; $i++) {
$data = array(
'field1' => "field1: $i",
'field2' => "field2: $i",
'field3' => "field3: $i",
'field4' => $i
);
$stmt->execute($data);
$stmt->closeCursor();
$usage = intval(floor(memory_get_usage() / 1024));
if ($first_time_usage === null) $first_time_usage = $usage;
/* Use delta instead of direct comparison here */
if (abs($first_time_usage - $usage) > 3){
printf("Memory Leak Detected: %d != %d\n", $usage, $first_time_usage);
break;
}
}
$pdo->rollBack();
echo "done\n"
?>
--EXPECTF--
done
+7 -2
View File
@@ -5120,7 +5120,11 @@ PHP_PGSQL_API int php_pgsql_meta_data(PGconn *pg_link, const char *table_name, z
src = estrdup(table_name);
tmp_name = php_strtok_r(src, ".", &tmp_name2);
if (!tmp_name) {
efree(src);
php_error_docref(NULL TSRMLS_CC, E_WARNING, "The table name must be specified");
return FAILURE;
}
if (!tmp_name2 || !*tmp_name2) {
/* Default schema */
tmp_name2 = tmp_name;
@@ -6130,7 +6134,8 @@ static int do_exec(smart_str *querystr, int expect, PGconn *pg_link, ulong opt T
static inline void build_tablename(smart_str *querystr, PGconn *pg_link, const char *table)
{
char *table_copy, *escaped, *token, *tmp;
char *table_copy, *escaped, *tmp;
const char *token;
size_t len;
/* schame.table should be "schame"."table" */
+27
View File
@@ -0,0 +1,27 @@
--TEST--
PostgreSQL pg_insert() - test for CVE-2015-1532
--SKIPIF--
<?php include("skipif.inc"); ?>
--FILE--
<?php
include('config.inc');
$conn = pg_connect($conn_str);
foreach (array('', '.', '..') as $table) {
var_dump(pg_insert($conn, $table, array('id' => 1, 'id2' => 1)));
}
?>
Done
--EXPECTF--
Warning: pg_insert(): The table name must be specified in %s on line %d
bool(false)
Warning: pg_insert(): The table name must be specified in %s on line %d
bool(false)
Warning: pg_insert(): The table name must be specified in %s on line %d
bool(false)
Done
+1 -1
View File
@@ -39,7 +39,7 @@ install-pharcmd: pharcmd
-@$(mkinstalldirs) $(INSTALL_ROOT)$(bindir)
$(INSTALL) $(builddir)/phar.phar $(INSTALL_ROOT)$(bindir)
-@rm -f $(INSTALL_ROOT)$(bindir)/phar
$(LN_S) -f $(INSTALL_ROOT)$(bindir)/phar.phar $(INSTALL_ROOT)$(bindir)/phar
$(LN_S) -f phar.phar $(INSTALL_ROOT)$(bindir)/phar
@$(mkinstalldirs) $(INSTALL_ROOT)$(mandir)/man1
@$(INSTALL_DATA) $(builddir)/phar.1 $(INSTALL_ROOT)$(mandir)/man1/phar.1
@$(INSTALL_DATA) $(builddir)/phar.phar.1 $(INSTALL_ROOT)$(mandir)/man1/phar.phar.1
+8 -2
View File
@@ -2141,7 +2141,7 @@ char *tsrm_strtok_r(char *s, const char *delim, char **last) /* {{{ */
*/
char *phar_fix_filepath(char *path, int *new_len, int use_cwd TSRMLS_DC) /* {{{ */
{
char newpath[MAXPATHLEN];
char *newpath;
int newpath_len;
char *ptr;
char *tok;
@@ -2149,8 +2149,10 @@ char *phar_fix_filepath(char *path, int *new_len, int use_cwd TSRMLS_DC) /* {{{
if (PHAR_G(cwd_len) && use_cwd && path_length > 2 && path[0] == '.' && path[1] == '/') {
newpath_len = PHAR_G(cwd_len);
newpath = emalloc(strlen(path) + newpath_len + 1);
memcpy(newpath, PHAR_G(cwd), newpath_len);
} else {
newpath = emalloc(strlen(path) + 2);
newpath[0] = '/';
newpath_len = 1;
}
@@ -2173,6 +2175,7 @@ char *phar_fix_filepath(char *path, int *new_len, int use_cwd TSRMLS_DC) /* {{{
if (*tok == '.') {
efree(path);
*new_len = 1;
efree(newpath);
return estrndup("/", 1);
}
break;
@@ -2180,9 +2183,11 @@ char *phar_fix_filepath(char *path, int *new_len, int use_cwd TSRMLS_DC) /* {{{
if (tok[0] == '.' && tok[1] == '.') {
efree(path);
*new_len = 1;
efree(newpath);
return estrndup("/", 1);
}
}
efree(newpath);
return path;
}
@@ -2231,7 +2236,8 @@ last_time:
efree(path);
*new_len = newpath_len;
return estrndup(newpath, newpath_len);
newpath[newpath_len] = '\0';
return erealloc(newpath, newpath_len + 1);
}
/* }}} */
+8 -5
View File
@@ -561,13 +561,16 @@ static inline void phar_set_inode(phar_entry_info *entry TSRMLS_DC) /* {{{ */
{
char tmp[MAXPATHLEN];
int tmp_len;
size_t len;
size_t len1, len2;
tmp_len = MIN(MAXPATHLEN, entry->filename_len + entry->phar->fname_len);
len = MIN(entry->phar->fname_len, tmp_len);
memcpy(tmp, entry->phar->fname, len);
len = MIN(tmp_len - len, entry->filename_len);
memcpy(tmp + entry->phar->fname_len, entry->filename, len);
len1 = MIN(entry->phar->fname_len, tmp_len);
memcpy(tmp, entry->phar->fname, len1);
len2 = MIN(tmp_len - len1, entry->filename_len);
memcpy(tmp + len1, entry->filename, len2);
entry->inode = (unsigned short)zend_get_hash_value(tmp, tmp_len);
}
/* }}} */
+94 -45
View File
@@ -1252,7 +1252,7 @@ PHP_METHOD(Phar, __construct)
INIT_PZVAL(&arg2);
ZVAL_LONG(&arg2, flags);
zend_call_method_with_2_params(&zobj, Z_OBJCE_P(zobj),
zend_call_method_with_2_params(&zobj, Z_OBJCE_P(zobj),
&spl_ce_RecursiveDirectoryIterator->constructor, "__construct", NULL, &arg1, &arg2);
if (!phar_data->is_persistent) {
@@ -1276,7 +1276,7 @@ PHP_METHOD(Phar, getSupportedSignatures)
if (zend_parse_parameters_none() == FAILURE) {
return;
}
array_init(return_value);
add_next_index_stringl(return_value, "MD5", 3, 1);
@@ -1303,7 +1303,7 @@ PHP_METHOD(Phar, getSupportedCompression)
if (zend_parse_parameters_none() == FAILURE) {
return;
}
array_init(return_value);
phar_request_initialize(TSRMLS_C);
@@ -1548,7 +1548,7 @@ phar_spl_fileinfo:
}
return ZEND_HASH_APPLY_STOP;
}
base = temp;
base_len = strlen(base);
@@ -1737,7 +1737,7 @@ after_open_fp:
/* {{{ proto array Phar::buildFromDirectory(string base_dir[, string regex])
* Construct a phar archive from an existing directory, recursively.
* Optional second parameter is a regular expression for filtering directory contents.
*
*
* Return value is an array mapping phar index to actual files added.
*/
PHP_METHOD(Phar, buildFromDirectory)
@@ -1773,7 +1773,7 @@ PHP_METHOD(Phar, buildFromDirectory)
INIT_PZVAL(&arg2);
ZVAL_LONG(&arg2, SPL_FILE_DIR_SKIPDOTS|SPL_FILE_DIR_UNIXPATHS);
zend_call_method_with_2_params(&iter, spl_ce_RecursiveDirectoryIterator,
zend_call_method_with_2_params(&iter, spl_ce_RecursiveDirectoryIterator,
&spl_ce_RecursiveDirectoryIterator->constructor, "__construct", NULL, &arg, &arg2);
if (EG(exception)) {
@@ -1790,7 +1790,7 @@ PHP_METHOD(Phar, buildFromDirectory)
RETURN_FALSE;
}
zend_call_method_with_1_params(&iteriter, spl_ce_RecursiveIteratorIterator,
zend_call_method_with_1_params(&iteriter, spl_ce_RecursiveIteratorIterator,
&spl_ce_RecursiveIteratorIterator->constructor, "__construct", NULL, iter);
if (EG(exception)) {
@@ -1815,7 +1815,7 @@ PHP_METHOD(Phar, buildFromDirectory)
INIT_PZVAL(&arg2);
ZVAL_STRINGL(&arg2, regex, regex_len, 0);
zend_call_method_with_2_params(&regexiter, spl_ce_RegexIterator,
zend_call_method_with_2_params(&regexiter, spl_ce_RegexIterator,
&spl_ce_RegexIterator->constructor, "__construct", NULL, iteriter, &arg2);
}
@@ -1936,7 +1936,7 @@ PHP_METHOD(Phar, buildFromIterator)
PHP_METHOD(Phar, count)
{
PHAR_ARCHIVE_OBJECT();
if (zend_parse_parameters_none() == FAILURE) {
return;
}
@@ -2017,9 +2017,10 @@ static int phar_copy_file_contents(phar_entry_info *entry, php_stream *fp TSRMLS
}
/* }}} */
static zval *phar_rename_archive(phar_archive_data *phar, char *ext, zend_bool compress TSRMLS_DC) /* {{{ */
static zval *phar_rename_archive(phar_archive_data **sphar, char *ext, zend_bool compress TSRMLS_DC) /* {{{ */
{
const char *oldname = NULL;
phar_archive_data *phar = *sphar;
char *oldpath = NULL;
char *basename = NULL, *basepath = NULL;
char *newname = NULL, *newpath = NULL;
@@ -2101,7 +2102,7 @@ static zval *phar_rename_archive(phar_archive_data *phar, char *ext, zend_bool c
spprintf(&newname, 0, "%s.%s", strtok(basename, "."), ext);
efree(basename);
basepath = estrndup(oldpath, (strlen(oldpath) - oldname_len));
phar->fname_len = spprintf(&newpath, 0, "%s%s", basepath, newname);
@@ -2126,7 +2127,9 @@ static zval *phar_rename_archive(phar_archive_data *phar, char *ext, zend_bool c
(*pphar)->fp = phar->fp;
phar->fp = NULL;
phar_destroy_phar_data(phar TSRMLS_CC);
*sphar = NULL;
phar = *pphar;
*sphar = NULL;
phar->refcount++;
newpath = oldpath;
goto its_ok;
@@ -2333,15 +2336,19 @@ no_copy:
phar_add_virtual_dirs(phar, newentry.filename, newentry.filename_len TSRMLS_CC);
}
if ((ret = phar_rename_archive(phar, ext, 0 TSRMLS_CC))) {
if ((ret = phar_rename_archive(&phar, ext, 0 TSRMLS_CC))) {
return ret;
} else {
zend_hash_destroy(&(phar->manifest));
zend_hash_destroy(&(phar->mounted_dirs));
zend_hash_destroy(&(phar->virtual_dirs));
php_stream_close(phar->fp);
efree(phar->fname);
efree(phar);
if(phar != NULL) {
zend_hash_destroy(&(phar->manifest));
zend_hash_destroy(&(phar->mounted_dirs));
zend_hash_destroy(&(phar->virtual_dirs));
if (phar->fp) {
php_stream_close(phar->fp);
}
efree(phar->fname);
efree(phar);
}
return NULL;
}
}
@@ -2559,7 +2566,7 @@ PHP_METHOD(Phar, convertToData)
PHP_METHOD(Phar, isCompressed)
{
PHAR_ARCHIVE_OBJECT();
if (zend_parse_parameters_none() == FAILURE) {
return;
}
@@ -2583,7 +2590,7 @@ PHP_METHOD(Phar, isWritable)
{
php_stream_statbuf ssb;
PHAR_ARCHIVE_OBJECT();
if (zend_parse_parameters_none() == FAILURE) {
return;
}
@@ -2661,7 +2668,7 @@ PHP_METHOD(Phar, delete)
PHP_METHOD(Phar, getAlias)
{
PHAR_ARCHIVE_OBJECT();
if (zend_parse_parameters_none() == FAILURE) {
return;
}
@@ -2678,7 +2685,7 @@ PHP_METHOD(Phar, getAlias)
PHP_METHOD(Phar, getPath)
{
PHAR_ARCHIVE_OBJECT();
if (zend_parse_parameters_none() == FAILURE) {
return;
}
@@ -2794,7 +2801,7 @@ valid_alias:
PHP_METHOD(Phar, getVersion)
{
PHAR_ARCHIVE_OBJECT();
if (zend_parse_parameters_none() == FAILURE) {
return;
}
@@ -2809,7 +2816,7 @@ PHP_METHOD(Phar, getVersion)
PHP_METHOD(Phar, startBuffering)
{
PHAR_ARCHIVE_OBJECT();
if (zend_parse_parameters_none() == FAILURE) {
return;
}
@@ -2824,7 +2831,7 @@ PHP_METHOD(Phar, startBuffering)
PHP_METHOD(Phar, isBuffering)
{
PHAR_ARCHIVE_OBJECT();
if (zend_parse_parameters_none() == FAILURE) {
return;
}
@@ -2841,7 +2848,7 @@ PHP_METHOD(Phar, stopBuffering)
char *error;
PHAR_ARCHIVE_OBJECT();
if (zend_parse_parameters_none() == FAILURE) {
return;
}
@@ -3076,7 +3083,7 @@ PHP_METHOD(Phar, setSignatureAlgorithm)
PHP_METHOD(Phar, getSignature)
{
PHAR_ARCHIVE_OBJECT();
if (zend_parse_parameters_none() == FAILURE) {
return;
}
@@ -3120,7 +3127,7 @@ PHP_METHOD(Phar, getSignature)
PHP_METHOD(Phar, getModified)
{
PHAR_ARCHIVE_OBJECT();
if (zend_parse_parameters_none() == FAILURE) {
return;
}
@@ -3382,7 +3389,7 @@ PHP_METHOD(Phar, decompressFiles)
{
char *error;
PHAR_ARCHIVE_OBJECT();
if (zend_parse_parameters_none() == FAILURE) {
return;
}
@@ -3899,7 +3906,7 @@ PHP_METHOD(Phar, getStub)
phar_entry_info *stub;
PHAR_ARCHIVE_OBJECT();
if (zend_parse_parameters_none() == FAILURE) {
return;
}
@@ -4002,7 +4009,7 @@ PHP_METHOD(Phar, hasMetadata)
PHP_METHOD(Phar, getMetadata)
{
PHAR_ARCHIVE_OBJECT();
if (zend_parse_parameters_none() == FAILURE) {
return;
}
@@ -4110,6 +4117,9 @@ static int phar_extract_file(zend_bool overwrite, phar_entry_info *entry, char *
char *fullpath;
const char *slash;
mode_t mode;
cwd_state new_state;
char *filename;
size_t filename_len;
if (entry->is_mounted) {
/* silently ignore mounted entries */
@@ -4119,8 +4129,39 @@ static int phar_extract_file(zend_bool overwrite, phar_entry_info *entry, char *
if (entry->filename_len >= sizeof(".phar")-1 && !memcmp(entry->filename, ".phar", sizeof(".phar")-1)) {
return SUCCESS;
}
/* strip .. from path and restrict it to be under dest directory */
new_state.cwd = (char*)malloc(2);
new_state.cwd[0] = DEFAULT_SLASH;
new_state.cwd[1] = '\0';
new_state.cwd_length = 1;
if (virtual_file_ex(&new_state, entry->filename, NULL, CWD_EXPAND TSRMLS_CC) != 0 ||
new_state.cwd_length <= 1) {
if (EINVAL == errno && entry->filename_len > 50) {
char *tmp = estrndup(entry->filename, 50);
spprintf(error, 4096, "Cannot extract \"%s...\" to \"%s...\", extracted filename is too long for filesystem", tmp, dest);
efree(tmp);
} else {
spprintf(error, 4096, "Cannot extract \"%s\", internal error", entry->filename);
}
free(new_state.cwd);
return FAILURE;
}
filename = new_state.cwd + 1;
filename_len = new_state.cwd_length - 1;
#ifdef PHP_WIN32
/* unixify the path back, otherwise non zip formats might be broken */
{
int cnt = filename_len;
len = spprintf(&fullpath, 0, "%s/%s", dest, entry->filename);
do {
if ('\\' == filename[cnt]) {
filename[cnt] = '/';
}
} while (cnt-- >= 0);
}
#endif
len = spprintf(&fullpath, 0, "%s/%s", dest, filename);
if (len >= MAXPATHLEN) {
char *tmp;
@@ -4134,18 +4175,21 @@ static int phar_extract_file(zend_bool overwrite, phar_entry_info *entry, char *
spprintf(error, 4096, "Cannot extract \"%s\" to \"%s...\", extracted filename is too long for filesystem", entry->filename, fullpath);
}
efree(fullpath);
free(new_state.cwd);
return FAILURE;
}
if (!len) {
spprintf(error, 4096, "Cannot extract \"%s\", internal error", entry->filename);
efree(fullpath);
free(new_state.cwd);
return FAILURE;
}
if (PHAR_OPENBASEDIR_CHECKPATH(fullpath)) {
spprintf(error, 4096, "Cannot extract \"%s\" to \"%s\", openbasedir/safe mode restrictions in effect", entry->filename, fullpath);
efree(fullpath);
free(new_state.cwd);
return FAILURE;
}
@@ -4153,14 +4197,15 @@ static int phar_extract_file(zend_bool overwrite, phar_entry_info *entry, char *
if (!overwrite && SUCCESS == php_stream_stat_path(fullpath, &ssb)) {
spprintf(error, 4096, "Cannot extract \"%s\" to \"%s\", path already exists", entry->filename, fullpath);
efree(fullpath);
free(new_state.cwd);
return FAILURE;
}
/* perform dirname */
slash = zend_memrchr(entry->filename, '/', entry->filename_len);
slash = zend_memrchr(filename, '/', filename_len);
if (slash) {
fullpath[dest_len + (slash - entry->filename) + 1] = '\0';
fullpath[dest_len + (slash - filename) + 1] = '\0';
} else {
fullpath[dest_len] = '\0';
}
@@ -4170,23 +4215,27 @@ static int phar_extract_file(zend_bool overwrite, phar_entry_info *entry, char *
if (!php_stream_mkdir(fullpath, entry->flags & PHAR_ENT_PERM_MASK, PHP_STREAM_MKDIR_RECURSIVE, NULL)) {
spprintf(error, 4096, "Cannot extract \"%s\", could not create directory \"%s\"", entry->filename, fullpath);
efree(fullpath);
free(new_state.cwd);
return FAILURE;
}
} else {
if (!php_stream_mkdir(fullpath, 0777, PHP_STREAM_MKDIR_RECURSIVE, NULL)) {
spprintf(error, 4096, "Cannot extract \"%s\", could not create directory \"%s\"", entry->filename, fullpath);
efree(fullpath);
free(new_state.cwd);
return FAILURE;
}
}
}
if (slash) {
fullpath[dest_len + (slash - entry->filename) + 1] = '/';
fullpath[dest_len + (slash - filename) + 1] = '/';
} else {
fullpath[dest_len] = '/';
}
filename = NULL;
free(new_state.cwd);
/* it is a standalone directory, job done */
if (entry->is_dir) {
efree(fullpath);
@@ -4450,7 +4499,7 @@ PHP_METHOD(PharFileInfo, __construct)
INIT_PZVAL(&arg1);
ZVAL_STRINGL(&arg1, fname, fname_len, 0);
zend_call_method_with_1_params(&zobj, Z_OBJCE_P(zobj),
zend_call_method_with_1_params(&zobj, Z_OBJCE_P(zobj),
&spl_ce_SplFileInfo->constructor, "__construct", NULL, &arg1);
}
/* }}} */
@@ -4488,7 +4537,7 @@ PHP_METHOD(PharFileInfo, __destruct)
PHP_METHOD(PharFileInfo, getCompressedSize)
{
PHAR_ENTRY_OBJECT();
if (zend_parse_parameters_none() == FAILURE) {
return;
}
@@ -4530,7 +4579,7 @@ PHP_METHOD(PharFileInfo, isCompressed)
PHP_METHOD(PharFileInfo, getCRC32)
{
PHAR_ENTRY_OBJECT();
if (zend_parse_parameters_none() == FAILURE) {
return;
}
@@ -4556,7 +4605,7 @@ PHP_METHOD(PharFileInfo, getCRC32)
PHP_METHOD(PharFileInfo, isCRCChecked)
{
PHAR_ENTRY_OBJECT();
if (zend_parse_parameters_none() == FAILURE) {
return;
}
@@ -4571,7 +4620,7 @@ PHP_METHOD(PharFileInfo, isCRCChecked)
PHP_METHOD(PharFileInfo, getPharFlags)
{
PHAR_ENTRY_OBJECT();
if (zend_parse_parameters_none() == FAILURE) {
return;
}
@@ -4649,7 +4698,7 @@ PHP_METHOD(PharFileInfo, chmod)
PHP_METHOD(PharFileInfo, hasMetadata)
{
PHAR_ENTRY_OBJECT();
if (zend_parse_parameters_none() == FAILURE) {
return;
}
@@ -4664,7 +4713,7 @@ PHP_METHOD(PharFileInfo, hasMetadata)
PHP_METHOD(PharFileInfo, getMetadata)
{
PHAR_ENTRY_OBJECT();
if (zend_parse_parameters_none() == FAILURE) {
return;
}
@@ -4745,7 +4794,7 @@ PHP_METHOD(PharFileInfo, delMetadata)
char *error;
PHAR_ENTRY_OBJECT();
if (zend_parse_parameters_none() == FAILURE) {
return;
}
@@ -4803,7 +4852,7 @@ PHP_METHOD(PharFileInfo, getContent)
phar_entry_info *link;
PHAR_ENTRY_OBJECT();
if (zend_parse_parameters_none() == FAILURE) {
return;
}
@@ -4977,7 +5026,7 @@ PHP_METHOD(PharFileInfo, decompress)
{
char *error;
PHAR_ENTRY_OBJECT();
if (zend_parse_parameters_none() == FAILURE) {
return;
}
+1 -1
View File
@@ -434,7 +434,7 @@ bail:
entry.filename_len = i;
entry.filename = pestrndup(hdr->name, i, myphar->is_persistent);
if (entry.filename[entry.filename_len - 1] == '/') {
if (i > 0 && entry.filename[entry.filename_len - 1] == '/') {
/* some tar programs store directories with trailing slash */
entry.filename[entry.filename_len - 1] = '\0';
entry.filename_len--;
+1 -1
View File
@@ -14,7 +14,7 @@ $r = new Phar($fname, 0);
==DONE==
--EXPECTF--
exception 'UnexpectedValueException' with message 'phar error: corrupted central directory entry, no magic signature in zip-based phar "%s%ebug69441.phar"' in %s%ebug69441.php:%d
exception 'UnexpectedValueException' with message 'phar error: corrupted central directory entry, no magic signature in zip-based phar "%sbug69441.phar"' in %sbug69441.php:%d
Stack trace:
#0 %s%ebug69441.php(%d): Phar->__construct('%s', 0)
#1 {main}
+21
View File
@@ -0,0 +1,21 @@
--TEST--
Phar: bug #69453: Memory Corruption in phar_parse_tarfile when entry filename starts with null
--SKIPIF--
<?php if (!extension_loaded("phar")) die("skip"); ?>
--FILE--
<?php
$fname = dirname(__FILE__) . '/bug69453.tar.phar';
try {
$r = new Phar($fname, 0);
} catch(UnexpectedValueException $e) {
echo $e;
}
?>
==DONE==
--EXPECTF--
exception 'UnexpectedValueException' with message 'phar error: "%s/bug69453.tar.phar" is a corrupted tar file (checksum mismatch of file "")' in %s:%d
Stack trace:
#0 %s/bug69453.php(%d): Phar->__construct('%s', 0)
#1 {main}
==DONE==
Binary file not shown.
+16
View File
@@ -0,0 +1,16 @@
--TEST--
Phar: bug #69958: Segfault in Phar::convertToData on invalid file
--XFAIL--
Still has memory leaks, see https://bugs.php.net/bug.php?id=70005
--SKIPIF--
<?php if (!extension_loaded("phar")) die("skip"); ?>
--FILE--
<?php
$tarphar = new PharData(__DIR__.'/bug69958.tar');
$phar = $tarphar->convertToData(Phar::TAR);
--EXPECTF--
Fatal error: Uncaught exception 'BadMethodCallException' with message 'phar "%s/bug69958.tar" exists and must be unlinked prior to conversion' in %s/bug69958.php:%d
Stack trace:
#0 %s/bug69958.php(%d): PharData->convertToData(%d)
#1 {main}
thrown in %s/bug69958.php on line %d
Binary file not shown.
+22
View File
@@ -0,0 +1,22 @@
--TEST--
Bug #70019 Files extracted from archive may be placed outside of destination directory
--FILE--
<?php
$dir = __DIR__."/bug70019";
$phar = new PharData(__DIR__."/bug70019.zip");
if(!is_dir($dir)) {
mkdir($dir);
}
$phar->extractTo($dir);
var_dump(file_exists("$dir/ThisIsATestFile.txt"));
?>
===DONE===
--CLEAN--
<?php
$dir = __DIR__."/bug70019";
unlink("$dir/ThisIsATestFile.txt");
rmdir($dir);
?>
--EXPECTF--
bool(true)
===DONE===
Loaded 100 of 170 files, more files were not shown because too many files have changed in this diff. Show more