]> granicus.if.org Git - php/commitdiff
Fixed bug #38579 (include_once() may include the same file twice)
authorDmitry Stogov <dmitry@php.net>
Wed, 20 Sep 2006 07:35:59 +0000 (07:35 +0000)
committerDmitry Stogov <dmitry@php.net>
Wed, 20 Sep 2006 07:35:59 +0000 (07:35 +0000)
NEWS
TSRM/tsrm_virtual_cwd.c
tests/lang/bug38579.inc [new file with mode: 0755]
tests/lang/bug38579.phpt [new file with mode: 0755]

diff --git a/NEWS b/NEWS
index bcd636213307edaa5eeb14552f4a829baec93b5c..052be56a5bb8a94751fcbd82d94388f0ae4bc494 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -8,6 +8,7 @@ PHP                                                                        NEWS
   (Tony)
 - Fixed bug #38623 (leaks in a tricky code with switch() and exceptions).
   (Dmitry)
+- Fixed bug #38579 (include_once() may include the same file twice). (Dmitry)
 - Fixed bug #38574 (missing curl constants and improper constant detection).
   (Ilia)
 - Fixed bug #37870 (pgo_pgsql tries to de-allocate unused statements).
index 0b333ede04daa39decc3da17a48b1bb99757fcd0..7afc8dafbdf159f39dfec6bec1668a36eeff820d 100644 (file)
@@ -366,23 +366,11 @@ static inline realpath_cache_bucket* realpath_cache_find(const char *path, int p
 CWD_API int virtual_file_ex(cwd_state *state, const char *path, verify_path_func verify_path, int use_realpath)
 {
        int path_length = strlen(path);
-       char *ptr, *path_copy;
-       char *tok = NULL;
-       int ptr_length;
        cwd_state old_state;
-       int ret = 0;
-       int copy_amount = -1;
-       char *free_path;
-       unsigned char is_absolute = 0;
-#ifndef TSRM_WIN32
-       char resolved_path[MAXPATHLEN];
-#else
-       char *new_path;
-#endif
        char orig_path[MAXPATHLEN];
-       int orig_path_len = 0;
        realpath_cache_bucket *bucket;
        time_t t = 0;
+       int ret;
        TSRMLS_FETCH();
 
        if (path_length == 0) 
@@ -390,21 +378,29 @@ CWD_API int virtual_file_ex(cwd_state *state, const char *path, verify_path_func
        if (path_length >= MAXPATHLEN)
                return (1);
 
-       if (use_realpath && CWDG(realpath_cache_size_limit)) {
-               if (IS_ABSOLUTE_PATH(path, path_length) || (state->cwd_length < 1)) {
-                       memcpy(orig_path, path, path_length+1);
-                       orig_path_len = path_length;
-               } else {
-                       orig_path_len = path_length + state->cwd_length + 1;
-                       if (orig_path_len >= MAXPATHLEN) {
-                               return 1;
-                       }
-                       memcpy(orig_path, state->cwd, state->cwd_length);
-                       orig_path[state->cwd_length] = DEFAULT_SLASH;
-                       memcpy(orig_path + state->cwd_length + 1, path, path_length + 1);
+#if VIRTUAL_CWD_DEBUG
+               fprintf(stderr,"cwd = %s path = %s\n", state->cwd, path);
+#endif
+
+       /* cwd_length can be 0 when getcwd() fails.
+        * This can happen under solaris when a dir does not have read permissions
+        * but *does* have execute permissions */
+       if (!IS_ABSOLUTE_PATH(path, path_length) && (state->cwd_length > 1)) {
+               int orig_path_len = path_length + state->cwd_length + 1;
+
+               if (orig_path_len >= MAXPATHLEN) {
+                       return 1;
                }
+               memcpy(orig_path, state->cwd, state->cwd_length);
+               orig_path[state->cwd_length] = DEFAULT_SLASH;
+               memcpy(orig_path + state->cwd_length + 1, path, path_length + 1);
+               path = orig_path;
+               path_length = orig_path_len; 
+       }
+
+       if (use_realpath && CWDG(realpath_cache_size_limit)) {
                t = CWDG(realpath_cache_ttl)?time(NULL):0;
-               if ((bucket = realpath_cache_find(orig_path, orig_path_len, t TSRMLS_CC)) != NULL) {            
+               if ((bucket = realpath_cache_find(path, path_length, t TSRMLS_CC)) != NULL) {           
                        int len = bucket->realpath_len;
 
                        CWD_STATE_COPY(&old_state, state);
@@ -421,107 +417,55 @@ CWD_API int virtual_file_ex(cwd_state *state, const char *path, verify_path_func
                        }
                }
        }
+
+       if (use_realpath) {
 #if !defined(TSRM_WIN32) && !defined(NETWARE)
-       /* cwd_length can be 0 when getcwd() fails.
-        * This can happen under solaris when a dir does not have read permissions
-        * but *does* have execute permissions */
-       if (IS_ABSOLUTE_PATH(path, path_length) || (state->cwd_length < 1)) {
-               if (use_realpath) {
-                       if (realpath(path, resolved_path)) {  /* Note: Not threadsafe on older *BSD's */
-                               path = resolved_path;
-                               path_length = strlen(path);
-                       } else {
-                               /* disable for now
-                               return 1; */
-                       }
-               }
-       } else { /* Concat current directory with relative path and then run realpath() on it */
-               char *tmp;
-               char *ptr;
+               char resolved_path[MAXPATHLEN];
 
-               ptr = tmp = (char *) malloc(state->cwd_length+path_length+sizeof("/"));
-               if (!tmp) {
-                       return 1;
-               }
-               memcpy(ptr, state->cwd, state->cwd_length);
-               ptr += state->cwd_length;
-               *ptr++ = DEFAULT_SLASH;
-               memcpy(ptr, path, path_length);
-               ptr += path_length;
-               *ptr = '\0';
-               if (strlen(tmp) >= MAXPATHLEN) {
-                       free(tmp);
-                       return 1;
-               }
-               if (use_realpath) {
-                       if (realpath(tmp, resolved_path)) {
-                               path = resolved_path;
-                               path_length = strlen(path);
-                       } else {
-                               /* disable for now 
-                               free(tmp);
-                               return 1; */
-                       }
-               }
-               free(tmp);
-       }
-#endif
-#if defined(TSRM_WIN32)
-       {
-               int new_path_length;
-  
-               new_path_length = GetLongPathName(path, NULL, 0);
-               if (new_path_length == 0) {
-                       goto php_failed_getlongpath;
+               if (!realpath(path, resolved_path)) {  /* Note: Not threadsafe on older *BSD's */
+                       goto no_realpath;
                }
+               CWD_STATE_COPY(&old_state, state);
 
-               /* GetLongPathName already counts the \0 */
-               new_path = (char *) malloc(new_path_length);
-               if (!new_path) {
-                       return 1;
-               }
-               
-               if (GetLongPathName(path, new_path, new_path_length) != 0) {
-                       path = new_path;
-                       path_length = new_path_length;
-               } else {
-                       free(new_path);
-php_failed_getlongpath:
-                       new_path = NULL;
-               }
-       }
+               state->cwd_length = strlen(resolved_path);
+               state->cwd = (char *) realloc(state->cwd, state->cwd_length+1);
+               memcpy(state->cwd, resolved_path, state->cwd_length+1);
+#else
+               goto no_realpath;
 #endif
-       free_path = path_copy = tsrm_strndup(path, path_length);
-
-       CWD_STATE_COPY(&old_state, state);
-#if VIRTUAL_CWD_DEBUG
-       fprintf(stderr,"cwd = %s path = %s\n", state->cwd, path);
+       } else {
+               char *ptr, *path_copy, *free_path;
+               char *tok = NULL;
+               int ptr_length;
+
+no_realpath:
+
+               free_path = path_copy = tsrm_strndup(path, path_length);
+               CWD_STATE_COPY(&old_state, state);
+
+#ifdef TSRM_WIN32              
+               if (path_length >= 2 && path[1] == ':') {                       
+                       state->cwd = (char *) realloc(state->cwd, 2 + 1);
+                       state->cwd[0] = toupper(path[0]);
+                       state->cwd[1] = ':';
+                       state->cwd[2] = '\0';
+                       state->cwd_length = 2;
+                       path_copy += 2;
+               } else if (IS_UNC_PATH(path, path_length)) {
+                       state->cwd = (char *) realloc(state->cwd, 1 + 1);
+                       state->cwd[0] = DEFAULT_SLASH;
+                       state->cwd[1] = '\0';
+                       state->cwd_length = 1;
+                       path_copy += 2;
+               } else {
 #endif
-       if (IS_ABSOLUTE_PATH(path_copy, path_length)) {
-        copy_amount = COPY_WHEN_ABSOLUTE(path_copy);
-               is_absolute = 1;
+                       state->cwd = (char *) realloc(state->cwd, 1);
+                       state->cwd[0] = '\0';
+                       state->cwd_length = 0;
 #ifdef TSRM_WIN32
-       } else if (IS_SLASH(path_copy[0])) {
-               copy_amount = 2;
-#endif
-       }
-
-       if (copy_amount != -1) {
-               state->cwd = (char *) realloc(state->cwd, copy_amount + 1);
-               if (copy_amount) {
-                       if (is_absolute) {
-                               memcpy(state->cwd, path_copy, copy_amount);
-                               path_copy += copy_amount;
-                       } else {
-                               memcpy(state->cwd, old_state.cwd, copy_amount);
-                       }
                }
-               state->cwd[copy_amount] = '\0';
-               state->cwd_length = copy_amount;
-       }
-
-
-       if (state->cwd_length > 0 || IS_ABSOLUTE_PATH(path, path_length)) {
+#endif
+               
                ptr = tsrm_strtok_r(path_copy, TOKENIZER_STRING, &tok);
                while (ptr) {
                        ptr_length = strlen(ptr);
@@ -551,7 +495,8 @@ php_failed_getlongpath:
                                state->cwd = (char *) realloc(state->cwd, state->cwd_length+ptr_length+1+1);
 #ifdef TSRM_WIN32
                                /* Windows 9x will consider C:\\Foo as a network path. Avoid it. */
-                               if ((state->cwd[state->cwd_length-1]!='\\' && state->cwd[state->cwd_length-1]!='/') || 
+                               if (state->cwd_length < 2 ||
+                                   (state->cwd[state->cwd_length-1]!='\\' && state->cwd[state->cwd_length-1]!='/') ||
                                                IsDBCSLeadByte(state->cwd[state->cwd_length-2])) {
                                        state->cwd[state->cwd_length++] = DEFAULT_SLASH;
                                }
@@ -575,32 +520,42 @@ php_failed_getlongpath:
                                state->cwd[state->cwd_length++] = DEFAULT_SLASH;
 #endif
                                memcpy(&state->cwd[state->cwd_length], ptr, ptr_length+1);
+
+#ifdef TSRM_WIN32
+                               if (use_realpath) {
+                                       WIN32_FIND_DATA data;
+                                       HANDLE hFind;
+
+                                       if ((hFind = FindFirstFile(state->cwd, &data)) != INVALID_HANDLE_VALUE) {
+                                               int length = strlen(data.cFileName);
+
+                                               if (length != ptr_length) {
+                                                       state->cwd = (char *) realloc(state->cwd, state->cwd_length+length+1);
+                                               }
+                                               memcpy(&state->cwd[state->cwd_length], data.cFileName, length+1);
+                                               ptr_length = length;
+                                               FindClose(hFind);
+                                       }
+                               }
+#endif
+
                                state->cwd_length += ptr_length;
                        }
                        ptr = tsrm_strtok_r(NULL, TOKENIZER_STRING, &tok);
                }
 
+               free(free_path);
+
                if (state->cwd_length == COPY_WHEN_ABSOLUTE(state->cwd)) {
                        state->cwd = (char *) realloc(state->cwd, state->cwd_length+1+1);
                        state->cwd[state->cwd_length] = DEFAULT_SLASH;
                        state->cwd[state->cwd_length+1] = '\0';
                        state->cwd_length++;
                }
-       } else {
-               state->cwd = (char *) realloc(state->cwd, path_length+1);
-               memcpy(state->cwd, path, path_length+1);
-               state->cwd_length = path_length;
        }
 
-#ifdef TSRM_WIN32
-       if (new_path) {
-               free(new_path);
-       }
-#endif
-       free(free_path);
-
        if (use_realpath && CWDG(realpath_cache_size_limit)) {
-               realpath_cache_add(orig_path, orig_path_len, state->cwd, state->cwd_length, t TSRMLS_CC);
+               realpath_cache_add(path, path_length, state->cwd, state->cwd_length, t TSRMLS_CC);
        }
 
        if (verify_path && verify_path(state)) {
diff --git a/tests/lang/bug38579.inc b/tests/lang/bug38579.inc
new file mode 100755 (executable)
index 0000000..8ecc558
--- /dev/null
@@ -0,0 +1,3 @@
+<?php
+echo "ok\n";
+?>
diff --git a/tests/lang/bug38579.phpt b/tests/lang/bug38579.phpt
new file mode 100755 (executable)
index 0000000..445296c
--- /dev/null
@@ -0,0 +1,16 @@
+--TEST--
+Bug #38579 (include_once() may include the same file twice)
+--SKIPIF--
+<?php
+if (substr(PHP_OS, 0, 3) != 'WIN') {
+    die('skip only for Windows');
+}
+?>
+--FILE--
+<?php
+$file = dirname(__FILE__)."/bug38579.inc";
+include_once(strtolower($file));
+include_once(strtoupper($file));
+?>
+--EXPECT--
+ok