cataphract Fri, 05 Nov 2010 01:29:08 +0000
Revision: http://svn.php.net/viewvc?view=revision&revision=305095
Log:
- Fixed bug #53241 (stream casting that relies on fdopen/fopencookie fails
with streams opened with, inter alia, the 'xb' mode).
Bug: http://bugs.php.net/53241 (Assigned) fopen(..., 'xb') and CURLOPT_FILE
make cURL fail with: fopencookie failed
Changed paths:
U php/php-src/branches/PHP_5_3/NEWS
A php/php-src/branches/PHP_5_3/ext/standard/tests/file/bug53241.phpt
U php/php-src/branches/PHP_5_3/main/php_streams.h
U php/php-src/branches/PHP_5_3/main/streams/cast.c
U php/php-src/branches/PHP_5_3/main/streams/plain_wrapper.c
A php/php-src/trunk/ext/standard/tests/file/bug53241.phpt
U php/php-src/trunk/main/php_streams.h
U php/php-src/trunk/main/streams/cast.c
U php/php-src/trunk/main/streams/plain_wrapper.c
Modified: php/php-src/branches/PHP_5_3/NEWS
===================================================================
--- php/php-src/branches/PHP_5_3/NEWS 2010-11-04 23:28:35 UTC (rev 305094)
+++ php/php-src/branches/PHP_5_3/NEWS 2010-11-05 01:29:08 UTC (rev 305095)
@@ -53,6 +53,8 @@
obtained with ReflectionClass::getProperties(). (Gustavo)
- Fixed covariance of return-by-ref constraints. (Etienne)
+- Fixed bug #53241 (stream casting that relies on fdopen/fopencookie fails
+ with streams opened with, inter alia, the 'xb' mode). (Gustavo)
- Fixed bug #53198 (changing INI setting "from" with ini_set did not have any
effect). (Gustavo)
- Fixed bug #53180 (post_max_size=0 not disabling the limit when the content
Added: php/php-src/branches/PHP_5_3/ext/standard/tests/file/bug53241.phpt
===================================================================
--- php/php-src/branches/PHP_5_3/ext/standard/tests/file/bug53241.phpt (rev 0)
+++ php/php-src/branches/PHP_5_3/ext/standard/tests/file/bug53241.phpt 2010-11-05 01:29:08 UTC (rev 305095)
@@ -0,0 +1,18 @@
+--TEST--
+Bug #53241 (stream casting that relies on fdopen/fopencookie fails with 'xb' mode)
+--SKIPIF--
+<?php
+/* unfortunately no standard function does a cast to FILE*, so we need
+ * curl to test this */
+if (!extension_loaded("curl")) exit("skip curl extension not loaded");
+--FILE--
+<?php
+$fn = __DIR__ . "/test.tmp";
+...@unlink($fn);
+$fh = fopen($fn, 'xb');
+$ch = curl_init('http://www.yahoo.com/');
+var_dump(curl_setopt($ch, CURLOPT_FILE, $fh));
+echo "Done.\n";
+--EXPECT--
+bool(true)
+Done.
Modified: php/php-src/branches/PHP_5_3/main/php_streams.h
===================================================================
--- php/php-src/branches/PHP_5_3/main/php_streams.h 2010-11-04 23:28:35 UTC (rev 305094)
+++ php/php-src/branches/PHP_5_3/main/php_streams.h 2010-11-05 01:29:08 UTC (rev 305095)
@@ -462,6 +462,12 @@
#define PHP_STREAM_CAST_MASK (PHP_STREAM_CAST_TRY_HARD | PHP_STREAM_CAST_RELEASE | PHP_STREAM_CAST_INTERNAL)
BEGIN_EXTERN_C()
PHPAPI int _php_stream_cast(php_stream *stream, int castas, void **ret, int show_err TSRMLS_DC);
+/* This functions transforms the first char to 'w' if it's not 'r', 'a' or 'w'
+ * and strips any subsequent chars except '+' and 'b'.
+ * Use this to sanitize stream->mode if you call e.g. fdopen, fopencookie or
+ * any other function that expects standard modes and you allow non-standard
+ * ones. result should be a char[5]. */
+PHPAPI void php_stream_rep_nonstand_mode(php_stream *stream, char *result);
END_EXTERN_C()
/* use this to check if a stream can be cast into another form */
#define php_stream_can_cast(stream, as) _php_stream_cast((stream), (as), NULL, 0 TSRMLS_CC)
Modified: php/php-src/branches/PHP_5_3/main/streams/cast.c
===================================================================
--- php/php-src/branches/PHP_5_3/main/streams/cast.c 2010-11-04 23:28:35 UTC (rev 305094)
+++ php/php-src/branches/PHP_5_3/main/streams/cast.c 2010-11-05 01:29:08 UTC (rev 305095)
@@ -144,6 +144,50 @@
#endif
/* }}} */
+/* {{{ php_stream_rep_nonstand_mode
+ * Result should have at least size 5, e.g. to write wbx+\0 */
+PHPAPI void php_stream_rep_nonstand_mode(php_stream *stream, char *result)
+{
+ /* replace modes not supported by fdopen and fopencookie, but supported
+ * by PHP's fread(), so that their calls won't fail */
+ const char *cur_mode = stream->mode;
+ int has_plus = 0,
+ has_bin = 0,
+ i,
+ res_curs = 0;
+
+ if (cur_mode[0] == 'r' || cur_mode[0] == 'w' || cur_mode[0] == 'a') {
+ result[res_curs++] = cur_mode[0];
+ } else {
+ /* assume cur_mode[0] is 'c' or 'x'; substitute by 'w', which should not
+ * truncate anything in fdopen/fopencookie */
+ result[res_curs++] = 'w';
+
+ /* x is allowed (at least by glibc & compat), but not as the 1st mode
+ * as in PHP and in any case is (at best) ignored by fdopen and fopencookie */
+ }
+
+ /* assume current mode has at most length 4 (e.g. wbn+) */
+ for (i = 1; i < 4 && cur_mode[i] != '\0'; i++) {
+ if (cur_mode[i] == 'b') {
+ has_bin = 1;
+ } else if (cur_mode[i] == '+') {
+ has_plus = 1;
+ }
+ /* ignore 'n', 't' or other stuff */
+ }
+
+ if (has_bin) {
+ result[res_curs++] = 'b';
+ }
+ if (has_plus) {
+ result[res_curs++] = '+';
+ }
+
+ result[res_curs] = '\0';
+}
+/* }}} */
+
/* {{{ php_stream_cast */
PHPAPI int _php_stream_cast(php_stream *stream, int castas, void **ret, int show_err TSRMLS_DC)
{
@@ -187,7 +231,11 @@
goto exit_success;
}
- *(FILE**)ret = fopencookie(stream, stream->mode, PHP_STREAM_COOKIE_FUNCTIONS);
+ {
+ char fixed_mode[5];
+ php_stream_rep_nonstand_mode(stream, fixed_mode);
+ *(FILE**)ret = fopencookie(stream, fixed_mode, PHP_STREAM_COOKIE_FUNCTIONS);
+ }
if (*ret != NULL) {
off_t pos;
Modified: php/php-src/branches/PHP_5_3/main/streams/plain_wrapper.c
===================================================================
--- php/php-src/branches/PHP_5_3/main/streams/plain_wrapper.c 2010-11-04 23:28:35 UTC (rev 305094)
+++ php/php-src/branches/PHP_5_3/main/streams/plain_wrapper.c 2010-11-05 01:29:08 UTC (rev 305095)
@@ -490,7 +490,9 @@
if (data->file == NULL) {
/* we were opened as a plain file descriptor, so we
* need fdopen now */
- data->file = fdopen(data->fd, stream->mode);
+ char fixed_mode[5];
+ php_stream_rep_nonstand_mode(stream, fixed_mode);
+ data->file = fdopen(data->fd, fixed_mode);
if (data->file == NULL) {
return FAILURE;
}
Added: php/php-src/trunk/ext/standard/tests/file/bug53241.phpt
===================================================================
--- php/php-src/trunk/ext/standard/tests/file/bug53241.phpt (rev 0)
+++ php/php-src/trunk/ext/standard/tests/file/bug53241.phpt 2010-11-05 01:29:08 UTC (rev 305095)
@@ -0,0 +1,18 @@
+--TEST--
+Bug #53241 (stream casting that relies on fdopen/fopencookie fails with 'xb' mode)
+--SKIPIF--
+<?php
+/* unfortunately no standard function does a cast to FILE*, so we need
+ * curl to test this */
+if (!extension_loaded("curl")) exit("skip curl extension not loaded");
+--FILE--
+<?php
+$fn = __DIR__ . "/test.tmp";
+...@unlink($fn);
+$fh = fopen($fn, 'xb');
+$ch = curl_init('http://www.yahoo.com/');
+var_dump(curl_setopt($ch, CURLOPT_FILE, $fh));
+echo "Done.\n";
+--EXPECT--
+bool(true)
+Done.
Modified: php/php-src/trunk/main/php_streams.h
===================================================================
--- php/php-src/trunk/main/php_streams.h 2010-11-04 23:28:35 UTC (rev 305094)
+++ php/php-src/trunk/main/php_streams.h 2010-11-05 01:29:08 UTC (rev 305095)
@@ -462,6 +462,12 @@
#define PHP_STREAM_CAST_MASK (PHP_STREAM_CAST_TRY_HARD | PHP_STREAM_CAST_RELEASE | PHP_STREAM_CAST_INTERNAL)
BEGIN_EXTERN_C()
PHPAPI int _php_stream_cast(php_stream *stream, int castas, void **ret, int show_err TSRMLS_DC);
+/* This functions transforms the first char to 'w' if it's not 'r', 'a' or 'w'
+ * and strips any subsequent chars except '+' and 'b'.
+ * Use this to sanitize stream->mode if you call e.g. fdopen, fopencookie or
+ * any other function that expects standard modes and you allow non-standard
+ * ones. result should be a char[5]. */
+PHPAPI void php_stream_rep_nonstand_mode(php_stream *stream, char *result);
END_EXTERN_C()
/* use this to check if a stream can be cast into another form */
#define php_stream_can_cast(stream, as) _php_stream_cast((stream), (as), NULL, 0 TSRMLS_CC)
Modified: php/php-src/trunk/main/streams/cast.c
===================================================================
--- php/php-src/trunk/main/streams/cast.c 2010-11-04 23:28:35 UTC (rev 305094)
+++ php/php-src/trunk/main/streams/cast.c 2010-11-05 01:29:08 UTC (rev 305095)
@@ -144,6 +144,50 @@
#endif
/* }}} */
+/* {{{ php_stream_rep_nonstand_mode
+ * Result should have at least size 5, e.g. to write wbx+\0 */
+PHPAPI void php_stream_rep_nonstand_mode(php_stream *stream, char *result)
+{
+ /* replace modes not supported by fdopen and fopencookie, but supported
+ * by PHP's fread(), so that their calls won't fail */
+ const char *cur_mode = stream->mode;
+ int has_plus = 0,
+ has_bin = 0,
+ i,
+ res_curs = 0;
+
+ if (cur_mode[0] == 'r' || cur_mode[0] == 'w' || cur_mode[0] == 'a') {
+ result[res_curs++] = cur_mode[0];
+ } else {
+ /* assume cur_mode[0] is 'c' or 'x'; substitute by 'w', which should not
+ * truncate anything in fdopen/fopencookie */
+ result[res_curs++] = 'w';
+
+ /* x is allowed (at least by glibc & compat), but not as the 1st mode
+ * as in PHP and in any case is (at best) ignored by fdopen and fopencookie */
+ }
+
+ /* assume current mode has at most length 4 (e.g. wbn+) */
+ for (i = 1; i < 4 && cur_mode[i] != '\0'; i++) {
+ if (cur_mode[i] == 'b') {
+ has_bin = 1;
+ } else if (cur_mode[i] == '+') {
+ has_plus = 1;
+ }
+ /* ignore 'n', 't' or other stuff */
+ }
+
+ if (has_bin) {
+ result[res_curs++] = 'b';
+ }
+ if (has_plus) {
+ result[res_curs++] = '+';
+ }
+
+ result[res_curs] = '\0';
+}
+/* }}} */
+
/* {{{ php_stream_cast */
PHPAPI int _php_stream_cast(php_stream *stream, int castas, void **ret, int show_err TSRMLS_DC)
{
@@ -187,7 +231,11 @@
goto exit_success;
}
- *(FILE**)ret = fopencookie(stream, stream->mode, PHP_STREAM_COOKIE_FUNCTIONS);
+ {
+ char fixed_mode[5];
+ php_stream_rep_nonstand_mode(stream, fixed_mode);
+ *(FILE**)ret = fopencookie(stream, fixed_mode, PHP_STREAM_COOKIE_FUNCTIONS);
+ }
if (*ret != NULL) {
off_t pos;
Modified: php/php-src/trunk/main/streams/plain_wrapper.c
===================================================================
--- php/php-src/trunk/main/streams/plain_wrapper.c 2010-11-04 23:28:35 UTC (rev 305094)
+++ php/php-src/trunk/main/streams/plain_wrapper.c 2010-11-05 01:29:08 UTC (rev 305095)
@@ -490,7 +490,9 @@
if (data->file == NULL) {
/* we were opened as a plain file descriptor, so we
* need fdopen now */
- data->file = fdopen(data->fd, stream->mode);
+ char fixed_mode[5];
+ php_stream_rep_nonstand_mode(stream, fixed_mode);
+ data->file = fdopen(data->fd, fixed_mode);
if (data->file == NULL) {
return FAILURE;
}
--
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php