ZendAccelerator.c 94 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Zend OPcache |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1998-2018 The PHP Group |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_01.txt |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. | Authors: Andi Gutmans <andi@php.net> |
  16. | Zeev Suraski <zeev@php.net> |
  17. | Stanislav Malyshev <stas@zend.com> |
  18. | Dmitry Stogov <dmitry@php.net> |
  19. +----------------------------------------------------------------------+
  20. */
  21. #include "main/php.h"
  22. #include "main/php_globals.h"
  23. #include "zend.h"
  24. #include "zend_extensions.h"
  25. #include "zend_compile.h"
  26. #include "ZendAccelerator.h"
  27. #include "zend_persist.h"
  28. #include "zend_shared_alloc.h"
  29. #include "zend_accelerator_module.h"
  30. #include "zend_accelerator_blacklist.h"
  31. #include "zend_list.h"
  32. #include "zend_execute.h"
  33. #include "main/SAPI.h"
  34. #include "main/php_streams.h"
  35. #include "main/php_open_temporary_file.h"
  36. #include "zend_API.h"
  37. #include "zend_ini.h"
  38. #include "zend_virtual_cwd.h"
  39. #include "zend_accelerator_util_funcs.h"
  40. #include "zend_accelerator_hash.h"
  41. #include "ext/pcre/php_pcre.h"
  42. #include "ext/standard/md5.h"
  43. #ifdef HAVE_OPCACHE_FILE_CACHE
  44. # include "zend_file_cache.h"
  45. #endif
  46. #ifndef ZEND_WIN32
  47. #include <netdb.h>
  48. #endif
  49. #ifdef ZEND_WIN32
  50. typedef int uid_t;
  51. typedef int gid_t;
  52. #include <io.h>
  53. #endif
  54. #ifndef ZEND_WIN32
  55. # include <sys/time.h>
  56. #else
  57. # include <process.h>
  58. #endif
  59. #ifdef HAVE_UNISTD_H
  60. # include <unistd.h>
  61. #endif
  62. #include <fcntl.h>
  63. #include <signal.h>
  64. #include <time.h>
  65. #ifndef ZEND_WIN32
  66. # include <sys/types.h>
  67. # include <sys/ipc.h>
  68. #endif
  69. #include <sys/stat.h>
  70. #include <errno.h>
  71. #ifdef __AVX__
  72. #include <immintrin.h>
  73. #endif
  74. #define SHM_PROTECT() \
  75. do { \
  76. if (ZCG(accel_directives).protect_memory) { \
  77. zend_accel_shared_protect(1); \
  78. } \
  79. } while (0)
  80. #define SHM_UNPROTECT() \
  81. do { \
  82. if (ZCG(accel_directives).protect_memory) { \
  83. zend_accel_shared_protect(0); \
  84. } \
  85. } while (0)
  86. ZEND_EXTENSION();
  87. #ifndef ZTS
  88. zend_accel_globals accel_globals;
  89. #else
  90. int accel_globals_id;
  91. #if defined(COMPILE_DL_OPCACHE)
  92. ZEND_TSRMLS_CACHE_DEFINE()
  93. #endif
  94. #endif
  95. /* Points to the structure shared across all PHP processes */
  96. zend_accel_shared_globals *accel_shared_globals = NULL;
  97. /* true globals, no need for thread safety */
  98. zend_bool accel_startup_ok = 0;
  99. static char *zps_failure_reason = NULL;
  100. char *zps_api_failure_reason = NULL;
  101. #ifdef HAVE_OPCACHE_FILE_CACHE
  102. zend_bool file_cache_only = 0; /* process uses file cache only */
  103. #endif
  104. #if ENABLE_FILE_CACHE_FALLBACK
  105. zend_bool fallback_process = 0; /* process uses file cache fallback */
  106. #endif
  107. static zend_op_array *(*accelerator_orig_compile_file)(zend_file_handle *file_handle, int type);
  108. static int (*accelerator_orig_zend_stream_open_function)(const char *filename, zend_file_handle *handle );
  109. static zend_string *(*accelerator_orig_zend_resolve_path)(const char *filename, size_t filename_len);
  110. static zif_handler orig_chdir = NULL;
  111. static ZEND_INI_MH((*orig_include_path_on_modify)) = NULL;
  112. static int (*orig_post_startup_cb)(void);
  113. static void accel_gen_system_id(void);
  114. static int accel_post_startup(void);
  115. #ifdef ZEND_WIN32
  116. # define INCREMENT(v) InterlockedIncrement64(&ZCSG(v))
  117. # define DECREMENT(v) InterlockedDecrement64(&ZCSG(v))
  118. # define LOCKVAL(v) (ZCSG(v))
  119. #endif
  120. #ifdef ZEND_WIN32
  121. static time_t zend_accel_get_time(void)
  122. {
  123. FILETIME now;
  124. GetSystemTimeAsFileTime(&now);
  125. return (time_t) ((((((__int64)now.dwHighDateTime) << 32)|now.dwLowDateTime) - 116444736000000000L)/10000000);
  126. }
  127. #else
  128. # define zend_accel_get_time() time(NULL)
  129. #endif
  130. static inline int is_stream_path(const char *filename)
  131. {
  132. const char *p;
  133. for (p = filename;
  134. (*p >= 'a' && *p <= 'z') ||
  135. (*p >= 'A' && *p <= 'Z') ||
  136. (*p >= '0' && *p <= '9') ||
  137. *p == '+' || *p == '-' || *p == '.';
  138. p++);
  139. return ((p != filename) && (p[0] == ':') && (p[1] == '/') && (p[2] == '/'));
  140. }
  141. static inline int is_cacheable_stream_path(const char *filename)
  142. {
  143. return memcmp(filename, "file://", sizeof("file://") - 1) == 0 ||
  144. memcmp(filename, "phar://", sizeof("phar://") - 1) == 0;
  145. }
  146. /* O+ overrides PHP chdir() function and remembers the current working directory
  147. * in ZCG(cwd) and ZCG(cwd_len). Later accel_getcwd() can use stored value and
  148. * avoid getcwd() call.
  149. */
  150. static ZEND_FUNCTION(accel_chdir)
  151. {
  152. char cwd[MAXPATHLEN];
  153. orig_chdir(INTERNAL_FUNCTION_PARAM_PASSTHRU);
  154. if (VCWD_GETCWD(cwd, MAXPATHLEN)) {
  155. if (ZCG(cwd)) {
  156. zend_string_release_ex(ZCG(cwd), 0);
  157. }
  158. ZCG(cwd) = zend_string_init(cwd, strlen(cwd), 0);
  159. } else {
  160. if (ZCG(cwd)) {
  161. zend_string_release_ex(ZCG(cwd), 0);
  162. ZCG(cwd) = NULL;
  163. }
  164. }
  165. ZCG(cwd_key_len) = 0;
  166. ZCG(cwd_check) = 1;
  167. }
  168. static inline zend_string* accel_getcwd(void)
  169. {
  170. if (ZCG(cwd)) {
  171. return ZCG(cwd);
  172. } else {
  173. char cwd[MAXPATHLEN + 1];
  174. if (!VCWD_GETCWD(cwd, MAXPATHLEN)) {
  175. return NULL;
  176. }
  177. ZCG(cwd) = zend_string_init(cwd, strlen(cwd), 0);
  178. ZCG(cwd_key_len) = 0;
  179. ZCG(cwd_check) = 1;
  180. return ZCG(cwd);
  181. }
  182. }
  183. void zend_accel_schedule_restart_if_necessary(zend_accel_restart_reason reason)
  184. {
  185. if ((((double) ZSMMG(wasted_shared_memory)) / ZCG(accel_directives).memory_consumption) >= ZCG(accel_directives).max_wasted_percentage) {
  186. zend_accel_schedule_restart(reason);
  187. }
  188. }
  189. /* O+ tracks changes of "include_path" directive. It stores all the requested
  190. * values in ZCG(include_paths) shared hash table, current value in
  191. * ZCG(include_path)/ZCG(include_path_len) and one letter "path key" in
  192. * ZCG(include_path_key).
  193. */
  194. static ZEND_INI_MH(accel_include_path_on_modify)
  195. {
  196. int ret = orig_include_path_on_modify(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
  197. if (ret == SUCCESS) {
  198. ZCG(include_path) = new_value;
  199. ZCG(include_path_key_len) = 0;
  200. ZCG(include_path_check) = 1;
  201. }
  202. return ret;
  203. }
  204. static inline void accel_restart_enter(void)
  205. {
  206. #ifdef ZEND_WIN32
  207. INCREMENT(restart_in);
  208. #else
  209. struct flock restart_in_progress;
  210. restart_in_progress.l_type = F_WRLCK;
  211. restart_in_progress.l_whence = SEEK_SET;
  212. restart_in_progress.l_start = 2;
  213. restart_in_progress.l_len = 1;
  214. if (fcntl(lock_file, F_SETLK, &restart_in_progress) == -1) {
  215. zend_accel_error(ACCEL_LOG_DEBUG, "RestartC(+1): %s (%d)", strerror(errno), errno);
  216. }
  217. #endif
  218. ZCSG(restart_in_progress) = 1;
  219. }
  220. static inline void accel_restart_leave(void)
  221. {
  222. #ifdef ZEND_WIN32
  223. ZCSG(restart_in_progress) = 0;
  224. DECREMENT(restart_in);
  225. #else
  226. struct flock restart_finished;
  227. restart_finished.l_type = F_UNLCK;
  228. restart_finished.l_whence = SEEK_SET;
  229. restart_finished.l_start = 2;
  230. restart_finished.l_len = 1;
  231. ZCSG(restart_in_progress) = 0;
  232. if (fcntl(lock_file, F_SETLK, &restart_finished) == -1) {
  233. zend_accel_error(ACCEL_LOG_DEBUG, "RestartC(-1): %s (%d)", strerror(errno), errno);
  234. }
  235. #endif
  236. }
  237. static inline int accel_restart_is_active(void)
  238. {
  239. if (ZCSG(restart_in_progress)) {
  240. #ifndef ZEND_WIN32
  241. struct flock restart_check;
  242. restart_check.l_type = F_WRLCK;
  243. restart_check.l_whence = SEEK_SET;
  244. restart_check.l_start = 2;
  245. restart_check.l_len = 1;
  246. if (fcntl(lock_file, F_GETLK, &restart_check) == -1) {
  247. zend_accel_error(ACCEL_LOG_DEBUG, "RestartC: %s (%d)", strerror(errno), errno);
  248. return FAILURE;
  249. }
  250. if (restart_check.l_type == F_UNLCK) {
  251. ZCSG(restart_in_progress) = 0;
  252. return 0;
  253. } else {
  254. return 1;
  255. }
  256. #else
  257. return LOCKVAL(restart_in) != 0;
  258. #endif
  259. }
  260. return 0;
  261. }
  262. /* Creates a read lock for SHM access */
  263. static inline int accel_activate_add(void)
  264. {
  265. #ifdef ZEND_WIN32
  266. INCREMENT(mem_usage);
  267. #else
  268. struct flock mem_usage_lock;
  269. mem_usage_lock.l_type = F_RDLCK;
  270. mem_usage_lock.l_whence = SEEK_SET;
  271. mem_usage_lock.l_start = 1;
  272. mem_usage_lock.l_len = 1;
  273. if (fcntl(lock_file, F_SETLK, &mem_usage_lock) == -1) {
  274. zend_accel_error(ACCEL_LOG_DEBUG, "UpdateC(+1): %s (%d)", strerror(errno), errno);
  275. return FAILURE;
  276. }
  277. #endif
  278. return SUCCESS;
  279. }
  280. /* Releases a lock for SHM access */
  281. static inline void accel_deactivate_sub(void)
  282. {
  283. #ifdef ZEND_WIN32
  284. if (ZCG(counted)) {
  285. DECREMENT(mem_usage);
  286. ZCG(counted) = 0;
  287. }
  288. #else
  289. struct flock mem_usage_unlock;
  290. mem_usage_unlock.l_type = F_UNLCK;
  291. mem_usage_unlock.l_whence = SEEK_SET;
  292. mem_usage_unlock.l_start = 1;
  293. mem_usage_unlock.l_len = 1;
  294. if (fcntl(lock_file, F_SETLK, &mem_usage_unlock) == -1) {
  295. zend_accel_error(ACCEL_LOG_DEBUG, "UpdateC(-1): %s (%d)", strerror(errno), errno);
  296. }
  297. #endif
  298. }
  299. static inline void accel_unlock_all(void)
  300. {
  301. #ifdef ZEND_WIN32
  302. accel_deactivate_sub();
  303. #else
  304. struct flock mem_usage_unlock_all;
  305. mem_usage_unlock_all.l_type = F_UNLCK;
  306. mem_usage_unlock_all.l_whence = SEEK_SET;
  307. mem_usage_unlock_all.l_start = 0;
  308. mem_usage_unlock_all.l_len = 0;
  309. if (fcntl(lock_file, F_SETLK, &mem_usage_unlock_all) == -1) {
  310. zend_accel_error(ACCEL_LOG_DEBUG, "UnlockAll: %s (%d)", strerror(errno), errno);
  311. }
  312. #endif
  313. }
  314. /* Interned strings support */
  315. /* O+ disables creation of interned strings by regular PHP compiler, instead,
  316. * it creates interned strings in shared memory when saves a script.
  317. * Such interned strings are shared across all PHP processes
  318. */
  319. #define STRTAB_INVALID_POS 0
  320. #define STRTAB_HASH_TO_SLOT(tab, h) \
  321. ((uint32_t*)((char*)(tab) + sizeof(*(tab)) + ((h) & (tab)->nTableMask)))
  322. #define STRTAB_STR_TO_POS(tab, s) \
  323. ((uint32_t)((char*)s - (char*)(tab)))
  324. #define STRTAB_POS_TO_STR(tab, pos) \
  325. ((zend_string*)((char*)(tab) + (pos)))
  326. #define STRTAB_COLLISION(s) \
  327. (*((uint32_t*)((char*)s - sizeof(uint32_t))))
  328. #define STRTAB_STR_SIZE(s) \
  329. ZEND_MM_ALIGNED_SIZE_EX(_ZSTR_HEADER_SIZE + ZSTR_LEN(s) + 5, 8)
  330. #define STRTAB_NEXT(s) \
  331. ((zend_string*)((char*)(s) + STRTAB_STR_SIZE(s)))
  332. static void accel_interned_strings_restore_state(void)
  333. {
  334. zend_string *s, *top;
  335. uint32_t *hash_slot, n;
  336. /* clear removed content */
  337. memset(ZCSG(interned_strings).saved_top,
  338. 0, (char*)ZCSG(interned_strings).top - (char*)ZCSG(interned_strings).saved_top);
  339. /* Reset "top" */
  340. ZCSG(interned_strings).top = ZCSG(interned_strings).saved_top;
  341. /* rehash */
  342. memset((char*)&ZCSG(interned_strings) + sizeof(zend_string_table),
  343. STRTAB_INVALID_POS,
  344. (char*)ZCSG(interned_strings).start -
  345. ((char*)&ZCSG(interned_strings) + sizeof(zend_string_table)));
  346. s = ZCSG(interned_strings).start;
  347. top = ZCSG(interned_strings).top;
  348. n = 0;
  349. if (EXPECTED(s < top)) {
  350. do {
  351. hash_slot = STRTAB_HASH_TO_SLOT(&ZCSG(interned_strings), ZSTR_H(s));
  352. STRTAB_COLLISION(s) = *hash_slot;
  353. *hash_slot = STRTAB_STR_TO_POS(&ZCSG(interned_strings), s);
  354. s = STRTAB_NEXT(s);
  355. n++;
  356. } while (s < top);
  357. }
  358. ZCSG(interned_strings).nNumOfElements = n;
  359. }
  360. static void accel_interned_strings_save_state(void)
  361. {
  362. ZCSG(interned_strings).saved_top = ZCSG(interned_strings).top;
  363. }
  364. static zend_always_inline zend_string *accel_find_interned_string(zend_string *str)
  365. {
  366. /* for now interned strings are supported only for non-ZTS build */
  367. zend_ulong h;
  368. uint32_t pos;
  369. zend_string *s;
  370. if (IS_ACCEL_INTERNED(str)) {
  371. /* this is already an interned string */
  372. return str;
  373. }
  374. if (!ZCG(counted)) {
  375. if (!ZCG(accelerator_enabled) || accel_activate_add() == FAILURE) {
  376. return NULL;
  377. }
  378. ZCG(counted) = 1;
  379. }
  380. h = zend_string_hash_val(str);
  381. /* check for existing interned string */
  382. pos = *STRTAB_HASH_TO_SLOT(&ZCSG(interned_strings), h);
  383. if (EXPECTED(pos != STRTAB_INVALID_POS)) {
  384. do {
  385. s = STRTAB_POS_TO_STR(&ZCSG(interned_strings), pos);
  386. if (EXPECTED(ZSTR_H(s) == h) && zend_string_equal_content(s, str)) {
  387. return s;
  388. }
  389. pos = STRTAB_COLLISION(s);
  390. } while (pos != STRTAB_INVALID_POS);
  391. }
  392. return NULL;
  393. }
  394. zend_string* ZEND_FASTCALL accel_new_interned_string(zend_string *str)
  395. {
  396. zend_ulong h;
  397. uint32_t pos, *hash_slot;
  398. zend_string *s;
  399. #ifdef HAVE_OPCACHE_FILE_CACHE
  400. if (UNEXPECTED(file_cache_only)) {
  401. return str;
  402. }
  403. #endif
  404. if (IS_ACCEL_INTERNED(str)) {
  405. /* this is already an interned string */
  406. return str;
  407. }
  408. h = zend_string_hash_val(str);
  409. /* check for existing interned string */
  410. hash_slot = STRTAB_HASH_TO_SLOT(&ZCSG(interned_strings), h);
  411. pos = *hash_slot;
  412. if (EXPECTED(pos != STRTAB_INVALID_POS)) {
  413. do {
  414. s = STRTAB_POS_TO_STR(&ZCSG(interned_strings), pos);
  415. if (EXPECTED(ZSTR_H(s) == h) && zend_string_equal_content(s, str)) {
  416. zend_string_release(str);
  417. return s;
  418. }
  419. pos = STRTAB_COLLISION(s);
  420. } while (pos != STRTAB_INVALID_POS);
  421. }
  422. if (UNEXPECTED((char*)ZCSG(interned_strings).end - (char*)ZCSG(interned_strings).top < STRTAB_STR_SIZE(str))) {
  423. /* no memory, return the same non-interned string */
  424. zend_accel_error(ACCEL_LOG_WARNING, "Interned string buffer overflow");
  425. return str;
  426. }
  427. /* create new interning string in shared interned strings buffer */
  428. ZCSG(interned_strings).nNumOfElements++;
  429. s = ZCSG(interned_strings).top;
  430. hash_slot = STRTAB_HASH_TO_SLOT(&ZCSG(interned_strings), h);
  431. STRTAB_COLLISION(s) = *hash_slot;
  432. *hash_slot = STRTAB_STR_TO_POS(&ZCSG(interned_strings), s);
  433. GC_SET_REFCOUNT(s, 1);
  434. GC_TYPE_INFO(s) = IS_STRING | ((IS_STR_INTERNED | IS_STR_PERMANENT) << GC_FLAGS_SHIFT);
  435. ZSTR_H(s) = h;
  436. ZSTR_LEN(s) = ZSTR_LEN(str);
  437. memcpy(ZSTR_VAL(s), ZSTR_VAL(str), ZSTR_LEN(s) + 1);
  438. ZCSG(interned_strings).top = STRTAB_NEXT(s);
  439. zend_string_release(str);
  440. return s;
  441. }
  442. static zend_string* ZEND_FASTCALL accel_new_interned_string_for_php(zend_string *str)
  443. {
  444. zend_string_hash_val(str);
  445. if (ZCG(counted)) {
  446. zend_string *ret = accel_find_interned_string(str);
  447. if (ret) {
  448. zend_string_release(str);
  449. return ret;
  450. }
  451. }
  452. return str;
  453. }
  454. static zend_always_inline zend_string *accel_find_interned_string_ex(zend_ulong h, const char *str, size_t size)
  455. {
  456. uint32_t pos;
  457. zend_string *s;
  458. /* check for existing interned string */
  459. pos = *STRTAB_HASH_TO_SLOT(&ZCSG(interned_strings), h);
  460. if (EXPECTED(pos != STRTAB_INVALID_POS)) {
  461. do {
  462. s = STRTAB_POS_TO_STR(&ZCSG(interned_strings), pos);
  463. if (EXPECTED(ZSTR_H(s) == h) && EXPECTED(ZSTR_LEN(s) == size)) {
  464. if (!memcmp(ZSTR_VAL(s), str, size)) {
  465. return s;
  466. }
  467. }
  468. pos = STRTAB_COLLISION(s);
  469. } while (pos != STRTAB_INVALID_POS);
  470. }
  471. return NULL;
  472. }
  473. static zend_string* ZEND_FASTCALL accel_init_interned_string_for_php(const char *str, size_t size, int permanent)
  474. {
  475. if (ZCG(counted)) {
  476. zend_ulong h = zend_inline_hash_func(str, size);
  477. zend_string *ret = accel_find_interned_string_ex(h, str, size);
  478. if (!ret) {
  479. ret = zend_string_init(str, size, permanent);
  480. ZSTR_H(ret) = h;
  481. }
  482. return ret;
  483. }
  484. return zend_string_init(str, size, permanent);
  485. }
  486. /* Copy PHP interned strings from PHP process memory into the shared memory */
  487. static void accel_copy_permanent_strings(zend_new_interned_string_func_t new_interned_string)
  488. {
  489. uint32_t j;
  490. Bucket *p, *q;
  491. HashTable *ht;
  492. /* empty string */
  493. zend_empty_string = new_interned_string(zend_empty_string);
  494. for (j = 0; j < 256; j++) {
  495. zend_one_char_string[j] = new_interned_string(ZSTR_CHAR(j));
  496. }
  497. for (j = 0; j < ZEND_STR_LAST_KNOWN; j++) {
  498. zend_known_strings[j] = new_interned_string(zend_known_strings[j]);
  499. }
  500. /* function table hash keys */
  501. ZEND_HASH_FOREACH_BUCKET(CG(function_table), p) {
  502. if (p->key) {
  503. p->key = new_interned_string(p->key);
  504. }
  505. if (Z_FUNC(p->val)->common.function_name) {
  506. Z_FUNC(p->val)->common.function_name = new_interned_string(Z_FUNC(p->val)->common.function_name);
  507. }
  508. if (Z_FUNC(p->val)->common.arg_info &&
  509. (Z_FUNC(p->val)->common.fn_flags & (ZEND_ACC_HAS_RETURN_TYPE|ZEND_ACC_HAS_TYPE_HINTS))) {
  510. uint32_t i;
  511. uint32_t num_args = Z_FUNC(p->val)->common.num_args + 1;
  512. zend_arg_info *arg_info = Z_FUNC(p->val)->common.arg_info - 1;
  513. if (Z_FUNC(p->val)->common.fn_flags & ZEND_ACC_VARIADIC) {
  514. num_args++;
  515. }
  516. for (i = 0 ; i < num_args; i++) {
  517. if (ZEND_TYPE_IS_CLASS(arg_info[i].type)) {
  518. zend_bool allow_null = ZEND_TYPE_ALLOW_NULL(arg_info[i].type);
  519. arg_info[i].type = ZEND_TYPE_ENCODE_CLASS(new_interned_string(ZEND_TYPE_NAME(arg_info[i].type)), allow_null);
  520. }
  521. }
  522. }
  523. } ZEND_HASH_FOREACH_END();
  524. /* class table hash keys, class names, properties, methods, constants, etc */
  525. ZEND_HASH_FOREACH_BUCKET(CG(class_table), p) {
  526. zend_class_entry *ce;
  527. ce = (zend_class_entry*)Z_PTR(p->val);
  528. if (p->key) {
  529. p->key = new_interned_string(p->key);
  530. }
  531. if (ce->name) {
  532. ce->name = new_interned_string(ce->name);
  533. }
  534. ZEND_HASH_FOREACH_BUCKET(&ce->properties_info, q) {
  535. zend_property_info *info;
  536. info = (zend_property_info*)Z_PTR(q->val);
  537. if (q->key) {
  538. q->key = new_interned_string(q->key);
  539. }
  540. if (info->name) {
  541. info->name = new_interned_string(info->name);
  542. }
  543. } ZEND_HASH_FOREACH_END();
  544. ZEND_HASH_FOREACH_BUCKET(&ce->function_table, q) {
  545. if (q->key) {
  546. q->key = new_interned_string(q->key);
  547. }
  548. if (Z_FUNC(q->val)->common.function_name) {
  549. Z_FUNC(q->val)->common.function_name = new_interned_string(Z_FUNC(q->val)->common.function_name);
  550. }
  551. } ZEND_HASH_FOREACH_END();
  552. ZEND_HASH_FOREACH_BUCKET(&ce->constants_table, q) {
  553. if (q->key) {
  554. q->key = new_interned_string(q->key);
  555. }
  556. } ZEND_HASH_FOREACH_END();
  557. } ZEND_HASH_FOREACH_END();
  558. /* constant hash keys */
  559. ZEND_HASH_FOREACH_BUCKET(EG(zend_constants), p) {
  560. zend_constant *c;
  561. if (p->key) {
  562. p->key = new_interned_string(p->key);
  563. }
  564. c = (zend_constant*)Z_PTR(p->val);
  565. if (c->name) {
  566. c->name = new_interned_string(c->name);
  567. }
  568. if (Z_TYPE(c->value) == IS_STRING) {
  569. ZVAL_STR(&c->value, new_interned_string(Z_STR(c->value)));
  570. }
  571. } ZEND_HASH_FOREACH_END();
  572. /* auto globals hash keys and names */
  573. ZEND_HASH_FOREACH_BUCKET(CG(auto_globals), p) {
  574. zend_auto_global *auto_global;
  575. auto_global = (zend_auto_global*)Z_PTR(p->val);
  576. zend_string_addref(auto_global->name);
  577. auto_global->name = new_interned_string(auto_global->name);
  578. if (p->key) {
  579. p->key = new_interned_string(p->key);
  580. }
  581. } ZEND_HASH_FOREACH_END();
  582. ZEND_HASH_FOREACH_BUCKET(&module_registry, p) {
  583. if (p->key) {
  584. p->key = new_interned_string(p->key);
  585. }
  586. } ZEND_HASH_FOREACH_END();
  587. ZEND_HASH_FOREACH_BUCKET(EG(ini_directives), p) {
  588. zend_ini_entry *entry = (zend_ini_entry*)Z_PTR(p->val);
  589. if (p->key) {
  590. p->key = new_interned_string(p->key);
  591. }
  592. if (entry->name) {
  593. entry->name = new_interned_string(entry->name);
  594. }
  595. if (entry->value) {
  596. entry->value = new_interned_string(entry->value);
  597. }
  598. if (entry->orig_value) {
  599. entry->orig_value = new_interned_string(entry->orig_value);
  600. }
  601. } ZEND_HASH_FOREACH_END();
  602. ht = php_get_stream_filters_hash_global();
  603. ZEND_HASH_FOREACH_BUCKET(ht, p) {
  604. if (p->key) {
  605. p->key = new_interned_string(p->key);
  606. }
  607. } ZEND_HASH_FOREACH_END();
  608. ht = php_stream_get_url_stream_wrappers_hash_global();
  609. ZEND_HASH_FOREACH_BUCKET(ht, p) {
  610. if (p->key) {
  611. p->key = new_interned_string(p->key);
  612. }
  613. } ZEND_HASH_FOREACH_END();
  614. ht = php_stream_xport_get_hash();
  615. ZEND_HASH_FOREACH_BUCKET(ht, p) {
  616. if (p->key) {
  617. p->key = new_interned_string(p->key);
  618. }
  619. } ZEND_HASH_FOREACH_END();
  620. }
  621. static zend_string* ZEND_FASTCALL accel_replace_string_by_shm_permanent(zend_string *str)
  622. {
  623. zend_string *ret = accel_find_interned_string(str);
  624. if (ret) {
  625. zend_string_release(str);
  626. return ret;
  627. }
  628. return str;
  629. }
  630. static zend_string* ZEND_FASTCALL accel_replace_string_by_process_permanent(zend_string *str)
  631. {
  632. zend_string *ret = zend_interned_string_find_permanent(str);
  633. if (ret) {
  634. zend_string_release(str);
  635. return ret;
  636. }
  637. ZEND_ASSERT(!IS_ACCEL_INTERNED(str));
  638. return str;
  639. }
  640. static void accel_use_shm_interned_strings(void)
  641. {
  642. HANDLE_BLOCK_INTERRUPTIONS();
  643. SHM_UNPROTECT();
  644. zend_shared_alloc_lock();
  645. if (ZCSG(interned_strings).saved_top == NULL) {
  646. accel_copy_permanent_strings(accel_new_interned_string);
  647. } else {
  648. ZCG(counted) = 1;
  649. accel_copy_permanent_strings(accel_replace_string_by_shm_permanent);
  650. ZCG(counted) = 0;
  651. }
  652. accel_interned_strings_save_state();
  653. zend_shared_alloc_unlock();
  654. SHM_PROTECT();
  655. HANDLE_UNBLOCK_INTERRUPTIONS();
  656. }
  657. static void accel_use_permanent_interned_strings(void)
  658. {
  659. accel_copy_permanent_strings(accel_replace_string_by_process_permanent);
  660. }
  661. #ifndef ZEND_WIN32
  662. static inline void kill_all_lockers(struct flock *mem_usage_check)
  663. {
  664. int success, tries;
  665. /* so that other process won't try to force while we are busy cleaning up */
  666. ZCSG(force_restart_time) = 0;
  667. while (mem_usage_check->l_pid > 0) {
  668. /* Clear previous errno, reset success and tries */
  669. errno = 0;
  670. success = 0;
  671. tries = 10;
  672. while (tries--) {
  673. zend_accel_error(ACCEL_LOG_WARNING, "Attempting to kill locker %d", mem_usage_check->l_pid);
  674. if (kill(mem_usage_check->l_pid, SIGKILL)) {
  675. if (errno == ESRCH) {
  676. /* Process died before the signal was sent */
  677. success = 1;
  678. zend_accel_error(ACCEL_LOG_WARNING, "Process %d died before SIGKILL was sent", mem_usage_check->l_pid);
  679. }
  680. break;
  681. }
  682. /* give it a chance to die */
  683. usleep(20000);
  684. if (kill(mem_usage_check->l_pid, 0)) {
  685. if (errno == ESRCH) {
  686. /* successfully killed locker, process no longer exists */
  687. success = 1;
  688. zend_accel_error(ACCEL_LOG_WARNING, "Killed locker %d", mem_usage_check->l_pid);
  689. }
  690. break;
  691. }
  692. usleep(10000);
  693. }
  694. if (!success) {
  695. /* errno is not ESRCH or we ran out of tries to kill the locker */
  696. ZCSG(force_restart_time) = time(NULL); /* restore forced restart request */
  697. /* cannot kill the locker, bail out with error */
  698. zend_accel_error(ACCEL_LOG_ERROR, "Cannot kill process %d: %s!", mem_usage_check->l_pid, strerror(errno));
  699. }
  700. mem_usage_check->l_type = F_WRLCK;
  701. mem_usage_check->l_whence = SEEK_SET;
  702. mem_usage_check->l_start = 1;
  703. mem_usage_check->l_len = 1;
  704. mem_usage_check->l_pid = -1;
  705. if (fcntl(lock_file, F_GETLK, mem_usage_check) == -1) {
  706. zend_accel_error(ACCEL_LOG_DEBUG, "KLockers: %s (%d)", strerror(errno), errno);
  707. break;
  708. }
  709. if (mem_usage_check->l_type == F_UNLCK || mem_usage_check->l_pid <= 0) {
  710. break;
  711. }
  712. }
  713. }
  714. #endif
  715. static inline int accel_is_inactive(void)
  716. {
  717. #ifdef ZEND_WIN32
  718. if (LOCKVAL(mem_usage) == 0) {
  719. return SUCCESS;
  720. }
  721. #else
  722. struct flock mem_usage_check;
  723. mem_usage_check.l_type = F_WRLCK;
  724. mem_usage_check.l_whence = SEEK_SET;
  725. mem_usage_check.l_start = 1;
  726. mem_usage_check.l_len = 1;
  727. mem_usage_check.l_pid = -1;
  728. if (fcntl(lock_file, F_GETLK, &mem_usage_check) == -1) {
  729. zend_accel_error(ACCEL_LOG_DEBUG, "UpdateC: %s (%d)", strerror(errno), errno);
  730. return FAILURE;
  731. }
  732. if (mem_usage_check.l_type == F_UNLCK) {
  733. return SUCCESS;
  734. }
  735. if (ZCG(accel_directives).force_restart_timeout
  736. && ZCSG(force_restart_time)
  737. && time(NULL) >= ZCSG(force_restart_time)) {
  738. zend_accel_error(ACCEL_LOG_WARNING, "Forced restart at %ld (after " ZEND_LONG_FMT " seconds), locked by %d", (long)time(NULL), ZCG(accel_directives).force_restart_timeout, mem_usage_check.l_pid);
  739. kill_all_lockers(&mem_usage_check);
  740. return FAILURE; /* next request should be able to restart it */
  741. }
  742. #endif
  743. return FAILURE;
  744. }
  745. static int zend_get_stream_timestamp(const char *filename, zend_stat_t *statbuf)
  746. {
  747. php_stream_wrapper *wrapper;
  748. php_stream_statbuf stream_statbuf;
  749. int ret, er;
  750. if (!filename) {
  751. return FAILURE;
  752. }
  753. wrapper = php_stream_locate_url_wrapper(filename, NULL, STREAM_LOCATE_WRAPPERS_ONLY);
  754. if (!wrapper) {
  755. return FAILURE;
  756. }
  757. if (!wrapper->wops || !wrapper->wops->url_stat) {
  758. statbuf->st_mtime = 1;
  759. return SUCCESS; /* anything other than 0 is considered to be a valid timestamp */
  760. }
  761. er = EG(error_reporting);
  762. EG(error_reporting) = 0;
  763. zend_try {
  764. ret = wrapper->wops->url_stat(wrapper, (char*)filename, PHP_STREAM_URL_STAT_QUIET, &stream_statbuf, NULL);
  765. } zend_catch {
  766. ret = -1;
  767. } zend_end_try();
  768. EG(error_reporting) = er;
  769. if (ret != 0) {
  770. return FAILURE;
  771. }
  772. *statbuf = stream_statbuf.sb;
  773. return SUCCESS;
  774. }
  775. #if ZEND_WIN32
  776. static accel_time_t zend_get_file_handle_timestamp_win(zend_file_handle *file_handle, size_t *size)
  777. {
  778. static unsigned __int64 utc_base = 0;
  779. static FILETIME utc_base_ft;
  780. WIN32_FILE_ATTRIBUTE_DATA fdata;
  781. if (!file_handle->opened_path) {
  782. return 0;
  783. }
  784. if (!utc_base) {
  785. SYSTEMTIME st;
  786. st.wYear = 1970;
  787. st.wMonth = 1;
  788. st.wDay = 1;
  789. st.wHour = 0;
  790. st.wMinute = 0;
  791. st.wSecond = 0;
  792. st.wMilliseconds = 0;
  793. SystemTimeToFileTime (&st, &utc_base_ft);
  794. utc_base = (((unsigned __int64)utc_base_ft.dwHighDateTime) << 32) + utc_base_ft.dwLowDateTime;
  795. }
  796. if (file_handle->opened_path && GetFileAttributesEx(file_handle->opened_path->val, GetFileExInfoStandard, &fdata) != 0) {
  797. unsigned __int64 ftime;
  798. if (CompareFileTime (&fdata.ftLastWriteTime, &utc_base_ft) < 0) {
  799. return 0;
  800. }
  801. ftime = (((unsigned __int64)fdata.ftLastWriteTime.dwHighDateTime) << 32) + fdata.ftLastWriteTime.dwLowDateTime - utc_base;
  802. ftime /= 10000000L;
  803. if (size) {
  804. *size = (size_t)((((unsigned __int64)fdata.nFileSizeHigh) << 32) + (unsigned __int64)fdata.nFileSizeLow);
  805. }
  806. return (accel_time_t)ftime;
  807. }
  808. return 0;
  809. }
  810. #endif
  811. accel_time_t zend_get_file_handle_timestamp(zend_file_handle *file_handle, size_t *size)
  812. {
  813. zend_stat_t statbuf;
  814. #ifdef ZEND_WIN32
  815. accel_time_t res;
  816. #endif
  817. if (sapi_module.get_stat &&
  818. !EG(current_execute_data) &&
  819. file_handle->filename == SG(request_info).path_translated) {
  820. zend_stat_t *tmpbuf = sapi_module.get_stat();
  821. if (tmpbuf) {
  822. if (size) {
  823. *size = tmpbuf->st_size;
  824. }
  825. return tmpbuf->st_mtime;
  826. }
  827. }
  828. #ifdef ZEND_WIN32
  829. res = zend_get_file_handle_timestamp_win(file_handle, size);
  830. if (res) {
  831. return res;
  832. }
  833. #endif
  834. switch (file_handle->type) {
  835. case ZEND_HANDLE_FD:
  836. if (zend_fstat(file_handle->handle.fd, &statbuf) == -1) {
  837. return 0;
  838. }
  839. break;
  840. case ZEND_HANDLE_FP:
  841. if (zend_fstat(fileno(file_handle->handle.fp), &statbuf) == -1) {
  842. if (zend_get_stream_timestamp(file_handle->filename, &statbuf) != SUCCESS) {
  843. return 0;
  844. }
  845. }
  846. break;
  847. case ZEND_HANDLE_FILENAME:
  848. case ZEND_HANDLE_MAPPED:
  849. if (file_handle->opened_path) {
  850. char *file_path = ZSTR_VAL(file_handle->opened_path);
  851. if (is_stream_path(file_path)) {
  852. if (zend_get_stream_timestamp(file_path, &statbuf) == SUCCESS) {
  853. break;
  854. }
  855. }
  856. if (VCWD_STAT(file_path, &statbuf) != -1) {
  857. break;
  858. }
  859. }
  860. if (zend_get_stream_timestamp(file_handle->filename, &statbuf) != SUCCESS) {
  861. return 0;
  862. }
  863. break;
  864. case ZEND_HANDLE_STREAM:
  865. {
  866. php_stream *stream = (php_stream *)file_handle->handle.stream.handle;
  867. php_stream_statbuf sb;
  868. int ret, er;
  869. if (!stream ||
  870. !stream->ops ||
  871. !stream->ops->stat) {
  872. return 0;
  873. }
  874. er = EG(error_reporting);
  875. EG(error_reporting) = 0;
  876. zend_try {
  877. ret = stream->ops->stat(stream, &sb);
  878. } zend_catch {
  879. ret = -1;
  880. } zend_end_try();
  881. EG(error_reporting) = er;
  882. if (ret != 0) {
  883. return 0;
  884. }
  885. statbuf = sb.sb;
  886. }
  887. break;
  888. default:
  889. return 0;
  890. }
  891. if (size) {
  892. *size = statbuf.st_size;
  893. }
  894. return statbuf.st_mtime;
  895. }
  896. static inline int do_validate_timestamps(zend_persistent_script *persistent_script, zend_file_handle *file_handle)
  897. {
  898. zend_file_handle ps_handle;
  899. zend_string *full_path_ptr = NULL;
  900. /** check that the persistent script is indeed the same file we cached
  901. * (if part of the path is a symlink than it possible that the user will change it)
  902. * See bug #15140
  903. */
  904. if (file_handle->opened_path) {
  905. if (persistent_script->script.filename != file_handle->opened_path &&
  906. !zend_string_equal_content(persistent_script->script.filename, file_handle->opened_path)) {
  907. return FAILURE;
  908. }
  909. } else {
  910. full_path_ptr = accelerator_orig_zend_resolve_path(file_handle->filename, strlen(file_handle->filename));
  911. if (full_path_ptr &&
  912. persistent_script->script.filename != full_path_ptr &&
  913. !zend_string_equal_content(persistent_script->script.filename, full_path_ptr)) {
  914. zend_string_release_ex(full_path_ptr, 0);
  915. return FAILURE;
  916. }
  917. file_handle->opened_path = full_path_ptr;
  918. }
  919. if (persistent_script->timestamp == 0) {
  920. if (full_path_ptr) {
  921. zend_string_release_ex(full_path_ptr, 0);
  922. file_handle->opened_path = NULL;
  923. }
  924. return FAILURE;
  925. }
  926. if (zend_get_file_handle_timestamp(file_handle, NULL) == persistent_script->timestamp) {
  927. if (full_path_ptr) {
  928. zend_string_release_ex(full_path_ptr, 0);
  929. file_handle->opened_path = NULL;
  930. }
  931. return SUCCESS;
  932. }
  933. if (full_path_ptr) {
  934. zend_string_release_ex(full_path_ptr, 0);
  935. file_handle->opened_path = NULL;
  936. }
  937. ps_handle.type = ZEND_HANDLE_FILENAME;
  938. ps_handle.filename = ZSTR_VAL(persistent_script->script.filename);
  939. ps_handle.opened_path = persistent_script->script.filename;
  940. if (zend_get_file_handle_timestamp(&ps_handle, NULL) == persistent_script->timestamp) {
  941. return SUCCESS;
  942. }
  943. return FAILURE;
  944. }
  945. int validate_timestamp_and_record(zend_persistent_script *persistent_script, zend_file_handle *file_handle)
  946. {
  947. if (ZCG(accel_directives).revalidate_freq &&
  948. persistent_script->dynamic_members.revalidate >= ZCG(request_time)) {
  949. return SUCCESS;
  950. } else if (do_validate_timestamps(persistent_script, file_handle) == FAILURE) {
  951. return FAILURE;
  952. } else {
  953. persistent_script->dynamic_members.revalidate = ZCG(request_time) + ZCG(accel_directives).revalidate_freq;
  954. return SUCCESS;
  955. }
  956. }
  957. int validate_timestamp_and_record_ex(zend_persistent_script *persistent_script, zend_file_handle *file_handle)
  958. {
  959. int ret;
  960. SHM_UNPROTECT();
  961. ret = validate_timestamp_and_record(persistent_script, file_handle);
  962. SHM_PROTECT();
  963. return ret;
  964. }
  965. /* Instead of resolving full real path name each time we need to identify file,
  966. * we create a key that consist from requested file name, current working
  967. * directory, current include_path, etc */
  968. char *accel_make_persistent_key(const char *path, size_t path_length, int *key_len)
  969. {
  970. int key_length;
  971. /* CWD and include_path don't matter for absolute file names and streams */
  972. if (IS_ABSOLUTE_PATH(path, path_length)) {
  973. /* pass */
  974. ZCG(key_len) = 0;
  975. } else if (UNEXPECTED(is_stream_path(path))) {
  976. if (!is_cacheable_stream_path(path)) {
  977. return NULL;
  978. }
  979. /* pass */
  980. ZCG(key_len) = 0;
  981. } else if (UNEXPECTED(!ZCG(accel_directives).use_cwd)) {
  982. /* pass */
  983. ZCG(key_len) = 0;
  984. } else {
  985. const char *include_path = NULL, *cwd = NULL;
  986. int include_path_len = 0, cwd_len = 0;
  987. zend_string *parent_script = NULL;
  988. size_t parent_script_len = 0;
  989. if (EXPECTED(ZCG(cwd_key_len))) {
  990. cwd = ZCG(cwd_key);
  991. cwd_len = ZCG(cwd_key_len);
  992. } else {
  993. zend_string *cwd_str = accel_getcwd();
  994. if (UNEXPECTED(!cwd_str)) {
  995. /* we don't handle this well for now. */
  996. zend_accel_error(ACCEL_LOG_INFO, "getcwd() failed for '%s' (%d), please try to set opcache.use_cwd to 0 in ini file", path, errno);
  997. return NULL;
  998. }
  999. cwd = ZSTR_VAL(cwd_str);
  1000. cwd_len = ZSTR_LEN(cwd_str);
  1001. if (ZCG(cwd_check)) {
  1002. ZCG(cwd_check) = 0;
  1003. if (ZCG(accelerator_enabled)) {
  1004. zend_string *str = accel_find_interned_string(cwd_str);
  1005. if (!str) {
  1006. HANDLE_BLOCK_INTERRUPTIONS();
  1007. SHM_UNPROTECT();
  1008. zend_shared_alloc_lock();
  1009. str = accel_new_interned_string(zend_string_copy(cwd_str));
  1010. if (str == cwd_str) {
  1011. zend_string_release_ex(str, 0);
  1012. str = NULL;
  1013. }
  1014. zend_shared_alloc_unlock();
  1015. SHM_PROTECT();
  1016. HANDLE_UNBLOCK_INTERRUPTIONS();
  1017. }
  1018. if (str) {
  1019. char buf[32];
  1020. char *res = zend_print_long_to_buf(buf + sizeof(buf) - 1, STRTAB_STR_TO_POS(&ZCSG(interned_strings), str));
  1021. cwd_len = ZCG(cwd_key_len) = buf + sizeof(buf) - 1 - res;
  1022. cwd = ZCG(cwd_key);
  1023. memcpy(ZCG(cwd_key), res, cwd_len + 1);
  1024. } else {
  1025. return NULL;
  1026. }
  1027. } else {
  1028. return NULL;
  1029. }
  1030. }
  1031. }
  1032. if (EXPECTED(ZCG(include_path_key_len))) {
  1033. include_path = ZCG(include_path_key);
  1034. include_path_len = ZCG(include_path_key_len);
  1035. } else if (!ZCG(include_path) || ZSTR_LEN(ZCG(include_path)) == 0) {
  1036. include_path = "";
  1037. include_path_len = 0;
  1038. } else {
  1039. include_path = ZSTR_VAL(ZCG(include_path));
  1040. include_path_len = ZSTR_LEN(ZCG(include_path));
  1041. if (ZCG(include_path_check)) {
  1042. ZCG(include_path_check) = 0;
  1043. if (ZCG(accelerator_enabled)) {
  1044. zend_string *str = accel_find_interned_string(ZCG(include_path));
  1045. if (!str) {
  1046. HANDLE_BLOCK_INTERRUPTIONS();
  1047. SHM_UNPROTECT();
  1048. zend_shared_alloc_lock();
  1049. str = accel_new_interned_string(zend_string_copy(ZCG(include_path)));
  1050. if (str == ZCG(include_path)) {
  1051. str = NULL;
  1052. }
  1053. zend_shared_alloc_unlock();
  1054. SHM_PROTECT();
  1055. HANDLE_UNBLOCK_INTERRUPTIONS();
  1056. }
  1057. if (str) {
  1058. char buf[32];
  1059. char *res = zend_print_long_to_buf(buf + sizeof(buf) - 1, STRTAB_STR_TO_POS(&ZCSG(interned_strings), str));
  1060. include_path_len = ZCG(include_path_key_len) = buf + sizeof(buf) - 1 - res;
  1061. include_path = ZCG(include_path_key);
  1062. memcpy(ZCG(include_path_key), res, include_path_len + 1);
  1063. } else {
  1064. return NULL;
  1065. }
  1066. } else {
  1067. return NULL;
  1068. }
  1069. }
  1070. }
  1071. /* Calculate key length */
  1072. if (UNEXPECTED((size_t)(cwd_len + path_length + include_path_len + 2) >= sizeof(ZCG(key)))) {
  1073. return NULL;
  1074. }
  1075. /* Generate key
  1076. * Note - the include_path must be the last element in the key,
  1077. * since in itself, it may include colons (which we use to separate
  1078. * different components of the key)
  1079. */
  1080. memcpy(ZCG(key), path, path_length);
  1081. ZCG(key)[path_length] = ':';
  1082. key_length = path_length + 1;
  1083. memcpy(ZCG(key) + key_length, cwd, cwd_len);
  1084. key_length += cwd_len;
  1085. if (include_path_len) {
  1086. ZCG(key)[key_length] = ':';
  1087. key_length += 1;
  1088. memcpy(ZCG(key) + key_length, include_path, include_path_len);
  1089. key_length += include_path_len;
  1090. }
  1091. /* Here we add to the key the parent script directory,
  1092. * since fopen_wrappers from version 4.0.7 use current script's path
  1093. * in include path too.
  1094. */
  1095. if (EXPECTED(EG(current_execute_data)) &&
  1096. EXPECTED((parent_script = zend_get_executed_filename_ex()) != NULL)) {
  1097. parent_script_len = ZSTR_LEN(parent_script);
  1098. while ((--parent_script_len > 0) && !IS_SLASH(ZSTR_VAL(parent_script)[parent_script_len]));
  1099. if (UNEXPECTED((size_t)(key_length + parent_script_len + 1) >= sizeof(ZCG(key)))) {
  1100. return NULL;
  1101. }
  1102. ZCG(key)[key_length] = ':';
  1103. key_length += 1;
  1104. memcpy(ZCG(key) + key_length, ZSTR_VAL(parent_script), parent_script_len);
  1105. key_length += parent_script_len;
  1106. }
  1107. ZCG(key)[key_length] = '\0';
  1108. *key_len = ZCG(key_len) = key_length;
  1109. return ZCG(key);
  1110. }
  1111. /* not use_cwd */
  1112. *key_len = path_length;
  1113. return (char*)path;
  1114. }
  1115. int zend_accel_invalidate(const char *filename, size_t filename_len, zend_bool force)
  1116. {
  1117. zend_string *realpath;
  1118. zend_persistent_script *persistent_script;
  1119. if (!ZCG(accelerator_enabled) || accelerator_shm_read_lock() != SUCCESS) {
  1120. return FAILURE;
  1121. }
  1122. realpath = accelerator_orig_zend_resolve_path(filename, filename_len);
  1123. if (!realpath) {
  1124. return FAILURE;
  1125. }
  1126. #ifdef HAVE_OPCACHE_FILE_CACHE
  1127. if (ZCG(accel_directives).file_cache) {
  1128. zend_file_cache_invalidate(realpath);
  1129. }
  1130. #endif
  1131. persistent_script = zend_accel_hash_find(&ZCSG(hash), realpath);
  1132. if (persistent_script && !persistent_script->corrupted) {
  1133. zend_file_handle file_handle;
  1134. file_handle.type = ZEND_HANDLE_FILENAME;
  1135. file_handle.filename = ZSTR_VAL(realpath);
  1136. file_handle.opened_path = realpath;
  1137. if (force ||
  1138. !ZCG(accel_directives).validate_timestamps ||
  1139. do_validate_timestamps(persistent_script, &file_handle) == FAILURE) {
  1140. HANDLE_BLOCK_INTERRUPTIONS();
  1141. SHM_UNPROTECT();
  1142. zend_shared_alloc_lock();
  1143. if (!persistent_script->corrupted) {
  1144. persistent_script->corrupted = 1;
  1145. persistent_script->timestamp = 0;
  1146. ZSMMG(wasted_shared_memory) += persistent_script->dynamic_members.memory_consumption;
  1147. if (ZSMMG(memory_exhausted)) {
  1148. zend_accel_restart_reason reason =
  1149. zend_accel_hash_is_full(&ZCSG(hash)) ? ACCEL_RESTART_HASH : ACCEL_RESTART_OOM;
  1150. zend_accel_schedule_restart_if_necessary(reason);
  1151. }
  1152. }
  1153. zend_shared_alloc_unlock();
  1154. SHM_PROTECT();
  1155. HANDLE_UNBLOCK_INTERRUPTIONS();
  1156. }
  1157. }
  1158. accelerator_shm_read_unlock();
  1159. zend_string_release_ex(realpath, 0);
  1160. return SUCCESS;
  1161. }
  1162. /* Adds another key for existing cached script */
  1163. static void zend_accel_add_key(const char *key, unsigned int key_length, zend_accel_hash_entry *bucket)
  1164. {
  1165. if (!zend_accel_hash_str_find(&ZCSG(hash), key, key_length)) {
  1166. if (zend_accel_hash_is_full(&ZCSG(hash))) {
  1167. zend_accel_error(ACCEL_LOG_DEBUG, "No more entries in hash table!");
  1168. ZSMMG(memory_exhausted) = 1;
  1169. zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_HASH);
  1170. } else {
  1171. char *new_key = zend_shared_alloc(key_length + 1);
  1172. if (new_key) {
  1173. memcpy(new_key, key, key_length + 1);
  1174. if (zend_accel_hash_update(&ZCSG(hash), new_key, key_length, 1, bucket)) {
  1175. zend_accel_error(ACCEL_LOG_INFO, "Added key '%s'", new_key);
  1176. }
  1177. } else {
  1178. zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_OOM);
  1179. }
  1180. }
  1181. }
  1182. }
  1183. static zend_always_inline zend_bool is_phar_file(zend_string *filename)
  1184. {
  1185. return filename && ZSTR_LEN(filename) >= sizeof(".phar") &&
  1186. !memcmp(ZSTR_VAL(filename) + ZSTR_LEN(filename) - (sizeof(".phar")-1), ".phar", sizeof(".phar")-1) &&
  1187. !strstr(ZSTR_VAL(filename), "://");
  1188. }
  1189. #ifdef HAVE_OPCACHE_FILE_CACHE
  1190. static zend_persistent_script *store_script_in_file_cache(zend_persistent_script *new_persistent_script)
  1191. {
  1192. uint32_t memory_used;
  1193. zend_shared_alloc_init_xlat_table();
  1194. /* Calculate the required memory size */
  1195. memory_used = zend_accel_script_persist_calc(new_persistent_script, NULL, 0, 0);
  1196. /* Allocate memory block */
  1197. #if defined(__AVX__) || defined(__SSE2__)
  1198. /* Align to 64-byte boundary */
  1199. ZCG(mem) = zend_arena_alloc(&CG(arena), memory_used + 64);
  1200. ZCG(mem) = (void*)(((zend_uintptr_t)ZCG(mem) + 63L) & ~63L);
  1201. #elif ZEND_MM_ALIGNMENT < 8
  1202. /* Align to 8-byte boundary */
  1203. ZCG(mem) = zend_arena_alloc(&CG(arena), memory_used + 8);
  1204. ZCG(mem) = (void*)(((zend_uintptr_t)ZCG(mem) + 7L) & ~7L);
  1205. #else
  1206. ZCG(mem) = zend_arena_alloc(&CG(arena), memory_used);
  1207. #endif
  1208. /* Copy into memory block */
  1209. new_persistent_script = zend_accel_script_persist(new_persistent_script, NULL, 0, 0);
  1210. zend_shared_alloc_destroy_xlat_table();
  1211. new_persistent_script->is_phar = is_phar_file(new_persistent_script->script.filename);
  1212. /* Consistency check */
  1213. if ((char*)new_persistent_script->mem + new_persistent_script->size != (char*)ZCG(mem)) {
  1214. zend_accel_error(
  1215. ((char*)new_persistent_script->mem + new_persistent_script->size < (char*)ZCG(mem)) ? ACCEL_LOG_ERROR : ACCEL_LOG_WARNING,
  1216. "Internal error: wrong size calculation: %s start=" ZEND_ADDR_FMT ", end=" ZEND_ADDR_FMT ", real=" ZEND_ADDR_FMT "\n",
  1217. ZSTR_VAL(new_persistent_script->script.filename),
  1218. (size_t)new_persistent_script->mem,
  1219. (size_t)((char *)new_persistent_script->mem + new_persistent_script->size),
  1220. (size_t)ZCG(mem));
  1221. }
  1222. new_persistent_script->dynamic_members.checksum = zend_accel_script_checksum(new_persistent_script);
  1223. zend_file_cache_script_store(new_persistent_script, 0);
  1224. return new_persistent_script;
  1225. }
  1226. static zend_persistent_script *cache_script_in_file_cache(zend_persistent_script *new_persistent_script, int *from_shared_memory)
  1227. {
  1228. uint32_t orig_compiler_options;
  1229. /* Check if script may be stored in shared memory */
  1230. if (!zend_accel_script_persistable(new_persistent_script)) {
  1231. return new_persistent_script;
  1232. }
  1233. orig_compiler_options = CG(compiler_options);
  1234. CG(compiler_options) |= ZEND_COMPILE_WITH_FILE_CACHE;
  1235. if (!zend_optimize_script(&new_persistent_script->script, ZCG(accel_directives).optimization_level, ZCG(accel_directives).opt_debug_level)) {
  1236. CG(compiler_options) = orig_compiler_options;
  1237. return new_persistent_script;
  1238. }
  1239. CG(compiler_options) = orig_compiler_options;
  1240. *from_shared_memory = 1;
  1241. return store_script_in_file_cache(new_persistent_script);
  1242. }
  1243. #endif
  1244. static zend_persistent_script *cache_script_in_shared_memory(zend_persistent_script *new_persistent_script, const char *key, unsigned int key_length, int *from_shared_memory)
  1245. {
  1246. zend_accel_hash_entry *bucket;
  1247. uint32_t memory_used;
  1248. uint32_t orig_compiler_options;
  1249. /* Check if script may be stored in shared memory */
  1250. if (!zend_accel_script_persistable(new_persistent_script)) {
  1251. return new_persistent_script;
  1252. }
  1253. orig_compiler_options = CG(compiler_options);
  1254. #ifdef HAVE_OPCACHE_FILE_CACHE
  1255. if (ZCG(accel_directives).file_cache) {
  1256. CG(compiler_options) |= ZEND_COMPILE_WITH_FILE_CACHE;
  1257. }
  1258. #endif
  1259. if (!zend_optimize_script(&new_persistent_script->script, ZCG(accel_directives).optimization_level, ZCG(accel_directives).opt_debug_level)) {
  1260. CG(compiler_options) = orig_compiler_options;
  1261. return new_persistent_script;
  1262. }
  1263. CG(compiler_options) = orig_compiler_options;
  1264. /* exclusive lock */
  1265. zend_shared_alloc_lock();
  1266. /* Check if we still need to put the file into the cache (may be it was
  1267. * already stored by another process. This final check is done under
  1268. * exclusive lock) */
  1269. bucket = zend_accel_hash_find_entry(&ZCSG(hash), new_persistent_script->script.filename);
  1270. if (bucket) {
  1271. zend_persistent_script *existing_persistent_script = (zend_persistent_script *)bucket->data;
  1272. if (!existing_persistent_script->corrupted) {
  1273. if (key &&
  1274. (!ZCG(accel_directives).validate_timestamps ||
  1275. (new_persistent_script->timestamp == existing_persistent_script->timestamp))) {
  1276. zend_accel_add_key(key, key_length, bucket);
  1277. }
  1278. zend_shared_alloc_unlock();
  1279. return new_persistent_script;
  1280. }
  1281. }
  1282. if (zend_accel_hash_is_full(&ZCSG(hash))) {
  1283. zend_accel_error(ACCEL_LOG_DEBUG, "No more entries in hash table!");
  1284. ZSMMG(memory_exhausted) = 1;
  1285. zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_HASH);
  1286. zend_shared_alloc_unlock();
  1287. #ifdef HAVE_OPCACHE_FILE_CACHE
  1288. if (ZCG(accel_directives).file_cache) {
  1289. new_persistent_script = store_script_in_file_cache(new_persistent_script);
  1290. *from_shared_memory = 1;
  1291. }
  1292. #endif
  1293. return new_persistent_script;
  1294. }
  1295. zend_shared_alloc_init_xlat_table();
  1296. /* Calculate the required memory size */
  1297. memory_used = zend_accel_script_persist_calc(new_persistent_script, key, key_length, 1);
  1298. /* Allocate shared memory */
  1299. #if defined(__AVX__) || defined(__SSE2__)
  1300. /* Align to 64-byte boundary */
  1301. ZCG(mem) = zend_shared_alloc(memory_used + 64);
  1302. if (ZCG(mem)) {
  1303. ZCG(mem) = (void*)(((zend_uintptr_t)ZCG(mem) + 63L) & ~63L);
  1304. #if defined(__x86_64__)
  1305. memset(ZCG(mem), 0, memory_used);
  1306. #elif defined(__AVX__)
  1307. {
  1308. char *p = (char*)ZCG(mem);
  1309. char *end = p + memory_used;
  1310. __m256i ymm0 = _mm256_setzero_si256();
  1311. while (p < end) {
  1312. _mm256_store_si256((__m256i*)p, ymm0);
  1313. _mm256_store_si256((__m256i*)(p+32), ymm0);
  1314. p += 64;
  1315. }
  1316. }
  1317. #else
  1318. {
  1319. char *p = (char*)ZCG(mem);
  1320. char *end = p + memory_used;
  1321. __m128i xmm0 = _mm_setzero_si128();
  1322. while (p < end) {
  1323. _mm_store_si128((__m128i*)p, xmm0);
  1324. _mm_store_si128((__m128i*)(p+16), xmm0);
  1325. _mm_store_si128((__m128i*)(p+32), xmm0);
  1326. _mm_store_si128((__m128i*)(p+48), xmm0);
  1327. p += 64;
  1328. }
  1329. }
  1330. #endif
  1331. }
  1332. #else
  1333. ZCG(mem) = zend_shared_alloc(memory_used);
  1334. if (ZCG(mem)) {
  1335. memset(ZCG(mem), 0, memory_used);
  1336. }
  1337. #endif
  1338. if (!ZCG(mem)) {
  1339. zend_shared_alloc_destroy_xlat_table();
  1340. zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_OOM);
  1341. zend_shared_alloc_unlock();
  1342. #ifdef HAVE_OPCACHE_FILE_CACHE
  1343. if (ZCG(accel_directives).file_cache) {
  1344. new_persistent_script = store_script_in_file_cache(new_persistent_script);
  1345. *from_shared_memory = 1;
  1346. }
  1347. #endif
  1348. return new_persistent_script;
  1349. }
  1350. /* Copy into shared memory */
  1351. new_persistent_script = zend_accel_script_persist(new_persistent_script, &key, key_length, 1);
  1352. zend_shared_alloc_destroy_xlat_table();
  1353. new_persistent_script->is_phar = is_phar_file(new_persistent_script->script.filename);
  1354. /* Consistency check */
  1355. if ((char*)new_persistent_script->mem + new_persistent_script->size != (char*)ZCG(mem)) {
  1356. zend_accel_error(
  1357. ((char*)new_persistent_script->mem + new_persistent_script->size < (char*)ZCG(mem)) ? ACCEL_LOG_ERROR : ACCEL_LOG_WARNING,
  1358. "Internal error: wrong size calculation: %s start=" ZEND_ADDR_FMT ", end=" ZEND_ADDR_FMT ", real=" ZEND_ADDR_FMT "\n",
  1359. ZSTR_VAL(new_persistent_script->script.filename),
  1360. (size_t)new_persistent_script->mem,
  1361. (size_t)((char *)new_persistent_script->mem + new_persistent_script->size),
  1362. (size_t)ZCG(mem));
  1363. }
  1364. new_persistent_script->dynamic_members.checksum = zend_accel_script_checksum(new_persistent_script);
  1365. /* store script structure in the hash table */
  1366. bucket = zend_accel_hash_update(&ZCSG(hash), ZSTR_VAL(new_persistent_script->script.filename), ZSTR_LEN(new_persistent_script->script.filename), 0, new_persistent_script);
  1367. if (bucket) {
  1368. zend_accel_error(ACCEL_LOG_INFO, "Cached script '%s'", ZSTR_VAL(new_persistent_script->script.filename));
  1369. if (key &&
  1370. /* key may contain non-persistent PHAR aliases (see issues #115 and #149) */
  1371. memcmp(key, "phar://", sizeof("phar://") - 1) != 0 &&
  1372. (ZSTR_LEN(new_persistent_script->script.filename) != key_length ||
  1373. memcmp(ZSTR_VAL(new_persistent_script->script.filename), key, key_length) != 0)) {
  1374. /* link key to the same persistent script in hash table */
  1375. if (zend_accel_hash_update(&ZCSG(hash), key, key_length, 1, bucket)) {
  1376. zend_accel_error(ACCEL_LOG_INFO, "Added key '%s'", key);
  1377. } else {
  1378. zend_accel_error(ACCEL_LOG_DEBUG, "No more entries in hash table!");
  1379. ZSMMG(memory_exhausted) = 1;
  1380. zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_HASH);
  1381. }
  1382. }
  1383. }
  1384. new_persistent_script->dynamic_members.memory_consumption = ZEND_ALIGNED_SIZE(new_persistent_script->size);
  1385. zend_shared_alloc_unlock();
  1386. #ifdef HAVE_OPCACHE_FILE_CACHE
  1387. if (ZCG(accel_directives).file_cache) {
  1388. SHM_PROTECT();
  1389. zend_file_cache_script_store(new_persistent_script, 1);
  1390. SHM_UNPROTECT();
  1391. }
  1392. #endif
  1393. *from_shared_memory = 1;
  1394. return new_persistent_script;
  1395. }
  1396. static const struct jit_auto_global_info
  1397. {
  1398. const char *name;
  1399. size_t len;
  1400. } jit_auto_globals_info[] = {
  1401. { "_SERVER", sizeof("_SERVER")-1},
  1402. { "_ENV", sizeof("_ENV")-1},
  1403. { "_REQUEST", sizeof("_REQUEST")-1},
  1404. { "GLOBALS", sizeof("GLOBALS")-1},
  1405. };
  1406. static zend_string *jit_auto_globals_str[4];
  1407. static int zend_accel_get_auto_globals(void)
  1408. {
  1409. int i, ag_size = (sizeof(jit_auto_globals_info) / sizeof(jit_auto_globals_info[0]));
  1410. int n = 1;
  1411. int mask = 0;
  1412. for (i = 0; i < ag_size ; i++) {
  1413. if (zend_hash_exists(&EG(symbol_table), jit_auto_globals_str[i])) {
  1414. mask |= n;
  1415. }
  1416. n += n;
  1417. }
  1418. return mask;
  1419. }
  1420. static int zend_accel_get_auto_globals_no_jit(void)
  1421. {
  1422. if (zend_hash_exists(&EG(symbol_table), jit_auto_globals_str[3])) {
  1423. return 8;
  1424. }
  1425. return 0;
  1426. }
  1427. static void zend_accel_set_auto_globals(int mask)
  1428. {
  1429. int i, ag_size = (sizeof(jit_auto_globals_info) / sizeof(jit_auto_globals_info[0]));
  1430. int n = 1;
  1431. for (i = 0; i < ag_size ; i++) {
  1432. if ((mask & n) && !(ZCG(auto_globals_mask) & n)) {
  1433. ZCG(auto_globals_mask) |= n;
  1434. zend_is_auto_global(jit_auto_globals_str[i]);
  1435. }
  1436. n += n;
  1437. }
  1438. }
  1439. static void zend_accel_init_auto_globals(void)
  1440. {
  1441. int i, ag_size = (sizeof(jit_auto_globals_info) / sizeof(jit_auto_globals_info[0]));
  1442. for (i = 0; i < ag_size ; i++) {
  1443. jit_auto_globals_str[i] = zend_string_init(jit_auto_globals_info[i].name, jit_auto_globals_info[i].len, 1);
  1444. zend_string_hash_val(jit_auto_globals_str[i]);
  1445. jit_auto_globals_str[i] = accel_new_interned_string(jit_auto_globals_str[i]);
  1446. }
  1447. }
  1448. static zend_persistent_script *opcache_compile_file(zend_file_handle *file_handle, int type, const char *key, zend_op_array **op_array_p)
  1449. {
  1450. zend_persistent_script *new_persistent_script;
  1451. zend_op_array *orig_active_op_array;
  1452. HashTable *orig_function_table, *orig_class_table;
  1453. zval orig_user_error_handler;
  1454. zend_op_array *op_array;
  1455. int do_bailout = 0;
  1456. accel_time_t timestamp = 0;
  1457. uint32_t orig_compiler_options = 0;
  1458. /* Try to open file */
  1459. if (file_handle->type == ZEND_HANDLE_FILENAME) {
  1460. if (accelerator_orig_zend_stream_open_function(file_handle->filename, file_handle) != SUCCESS) {
  1461. *op_array_p = NULL;
  1462. if (type == ZEND_REQUIRE) {
  1463. zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, file_handle->filename);
  1464. zend_bailout();
  1465. } else {
  1466. zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, file_handle->filename);
  1467. }
  1468. return NULL;
  1469. }
  1470. }
  1471. /* check blacklist right after ensuring that file was opened */
  1472. if (file_handle->opened_path && zend_accel_blacklist_is_blacklisted(&accel_blacklist, ZSTR_VAL(file_handle->opened_path), ZSTR_LEN(file_handle->opened_path))) {
  1473. SHM_UNPROTECT();
  1474. ZCSG(blacklist_misses)++;
  1475. SHM_PROTECT();
  1476. *op_array_p = accelerator_orig_compile_file(file_handle, type);
  1477. return NULL;
  1478. }
  1479. if (ZCG(accel_directives).validate_timestamps ||
  1480. ZCG(accel_directives).file_update_protection ||
  1481. ZCG(accel_directives).max_file_size > 0) {
  1482. size_t size = 0;
  1483. /* Obtain the file timestamps, *before* actually compiling them,
  1484. * otherwise we have a race-condition.
  1485. */
  1486. timestamp = zend_get_file_handle_timestamp(file_handle, ZCG(accel_directives).max_file_size > 0 ? &size : NULL);
  1487. /* If we can't obtain a timestamp (that means file is possibly socket)
  1488. * we won't cache it
  1489. */
  1490. if (timestamp == 0) {
  1491. *op_array_p = accelerator_orig_compile_file(file_handle, type);
  1492. return NULL;
  1493. }
  1494. /* check if file is too new (may be it's not written completely yet) */
  1495. if (ZCG(accel_directives).file_update_protection &&
  1496. ((accel_time_t)(ZCG(request_time) - ZCG(accel_directives).file_update_protection) < timestamp)) {
  1497. *op_array_p = accelerator_orig_compile_file(file_handle, type);
  1498. return NULL;
  1499. }
  1500. if (ZCG(accel_directives).max_file_size > 0 && size > (size_t)ZCG(accel_directives).max_file_size) {
  1501. SHM_UNPROTECT();
  1502. ZCSG(blacklist_misses)++;
  1503. SHM_PROTECT();
  1504. *op_array_p = accelerator_orig_compile_file(file_handle, type);
  1505. return NULL;
  1506. }
  1507. }
  1508. new_persistent_script = create_persistent_script();
  1509. /* Save the original values for the op_array, function table and class table */
  1510. orig_active_op_array = CG(active_op_array);
  1511. orig_function_table = CG(function_table);
  1512. orig_class_table = CG(class_table);
  1513. ZVAL_COPY_VALUE(&orig_user_error_handler, &EG(user_error_handler));
  1514. /* Override them with ours */
  1515. CG(function_table) = &ZCG(function_table);
  1516. EG(class_table) = CG(class_table) = &new_persistent_script->script.class_table;
  1517. ZVAL_UNDEF(&EG(user_error_handler));
  1518. zend_try {
  1519. orig_compiler_options = CG(compiler_options);
  1520. CG(compiler_options) |= ZEND_COMPILE_HANDLE_OP_ARRAY;
  1521. CG(compiler_options) |= ZEND_COMPILE_IGNORE_INTERNAL_CLASSES;
  1522. CG(compiler_options) |= ZEND_COMPILE_DELAYED_BINDING;
  1523. CG(compiler_options) |= ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION;
  1524. #ifdef HAVE_OPCACHE_FILE_CACHE
  1525. if (ZCG(accel_directives).file_cache) {
  1526. CG(compiler_options) |= ZEND_COMPILE_WITH_FILE_CACHE;
  1527. }
  1528. #endif
  1529. op_array = *op_array_p = accelerator_orig_compile_file(file_handle, type);
  1530. CG(compiler_options) = orig_compiler_options;
  1531. } zend_catch {
  1532. op_array = NULL;
  1533. do_bailout = 1;
  1534. CG(compiler_options) = orig_compiler_options;
  1535. } zend_end_try();
  1536. /* Restore originals */
  1537. CG(active_op_array) = orig_active_op_array;
  1538. CG(function_table) = orig_function_table;
  1539. EG(class_table) = CG(class_table) = orig_class_table;
  1540. EG(user_error_handler) = orig_user_error_handler;
  1541. if (!op_array) {
  1542. /* compilation failed */
  1543. free_persistent_script(new_persistent_script, 1);
  1544. zend_accel_free_user_functions(&ZCG(function_table));
  1545. if (do_bailout) {
  1546. zend_bailout();
  1547. }
  1548. return NULL;
  1549. }
  1550. /* Build the persistent_script structure.
  1551. Here we aren't sure we would store it, but we will need it
  1552. further anyway.
  1553. */
  1554. zend_accel_move_user_functions(&ZCG(function_table), &new_persistent_script->script.function_table);
  1555. new_persistent_script->script.first_early_binding_opline =
  1556. (op_array->fn_flags & ZEND_ACC_EARLY_BINDING) ?
  1557. zend_build_delayed_early_binding_list(op_array) :
  1558. (uint32_t)-1;
  1559. new_persistent_script->script.main_op_array = *op_array;
  1560. efree(op_array); /* we have valid persistent_script, so it's safe to free op_array */
  1561. /* Fill in the ping_auto_globals_mask for the new script. If jit for auto globals is enabled we
  1562. will have to ping the used auto global variables before execution */
  1563. if (PG(auto_globals_jit)) {
  1564. new_persistent_script->ping_auto_globals_mask = zend_accel_get_auto_globals();
  1565. } else {
  1566. new_persistent_script->ping_auto_globals_mask = zend_accel_get_auto_globals_no_jit();
  1567. }
  1568. if (ZCG(accel_directives).validate_timestamps) {
  1569. /* Obtain the file timestamps, *before* actually compiling them,
  1570. * otherwise we have a race-condition.
  1571. */
  1572. new_persistent_script->timestamp = timestamp;
  1573. new_persistent_script->dynamic_members.revalidate = ZCG(request_time) + ZCG(accel_directives).revalidate_freq;
  1574. }
  1575. if (file_handle->opened_path) {
  1576. new_persistent_script->script.filename = zend_string_copy(file_handle->opened_path);
  1577. } else {
  1578. new_persistent_script->script.filename = zend_string_init(file_handle->filename, strlen(file_handle->filename), 0);
  1579. }
  1580. zend_string_hash_val(new_persistent_script->script.filename);
  1581. /* Now persistent_script structure is ready in process memory */
  1582. return new_persistent_script;
  1583. }
  1584. #ifdef HAVE_OPCACHE_FILE_CACHE
  1585. zend_op_array *file_cache_compile_file(zend_file_handle *file_handle, int type)
  1586. {
  1587. zend_persistent_script *persistent_script;
  1588. zend_op_array *op_array = NULL;
  1589. int from_memory; /* if the script we've got is stored in SHM */
  1590. if (is_stream_path(file_handle->filename) &&
  1591. !is_cacheable_stream_path(file_handle->filename)) {
  1592. return accelerator_orig_compile_file(file_handle, type);
  1593. }
  1594. if (!file_handle->opened_path) {
  1595. if (file_handle->type == ZEND_HANDLE_FILENAME &&
  1596. accelerator_orig_zend_stream_open_function(file_handle->filename, file_handle) == FAILURE) {
  1597. if (type == ZEND_REQUIRE) {
  1598. zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, file_handle->filename);
  1599. zend_bailout();
  1600. } else {
  1601. zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, file_handle->filename);
  1602. }
  1603. return NULL;
  1604. }
  1605. }
  1606. HANDLE_BLOCK_INTERRUPTIONS();
  1607. SHM_UNPROTECT();
  1608. persistent_script = zend_file_cache_script_load(file_handle);
  1609. SHM_PROTECT();
  1610. HANDLE_UNBLOCK_INTERRUPTIONS();
  1611. if (persistent_script) {
  1612. /* see bug #15471 (old BTS) */
  1613. if (persistent_script->script.filename) {
  1614. if (!EG(current_execute_data) || !EG(current_execute_data)->opline ||
  1615. !EG(current_execute_data)->func ||
  1616. !ZEND_USER_CODE(EG(current_execute_data)->func->common.type) ||
  1617. EG(current_execute_data)->opline->opcode != ZEND_INCLUDE_OR_EVAL ||
  1618. (EG(current_execute_data)->opline->extended_value != ZEND_INCLUDE_ONCE &&
  1619. EG(current_execute_data)->opline->extended_value != ZEND_REQUIRE_ONCE)) {
  1620. if (zend_hash_add_empty_element(&EG(included_files), persistent_script->script.filename) != NULL) {
  1621. /* ext/phar has to load phar's metadata into memory */
  1622. if (persistent_script->is_phar) {
  1623. php_stream_statbuf ssb;
  1624. char *fname = emalloc(sizeof("phar://") + ZSTR_LEN(persistent_script->script.filename));
  1625. memcpy(fname, "phar://", sizeof("phar://") - 1);
  1626. memcpy(fname + sizeof("phar://") - 1, ZSTR_VAL(persistent_script->script.filename), ZSTR_LEN(persistent_script->script.filename) + 1);
  1627. php_stream_stat_path(fname, &ssb);
  1628. efree(fname);
  1629. }
  1630. }
  1631. }
  1632. }
  1633. zend_file_handle_dtor(file_handle);
  1634. if (persistent_script->ping_auto_globals_mask) {
  1635. zend_accel_set_auto_globals(persistent_script->ping_auto_globals_mask);
  1636. }
  1637. return zend_accel_load_script(persistent_script, 1);
  1638. }
  1639. persistent_script = opcache_compile_file(file_handle, type, NULL, &op_array);
  1640. if (persistent_script) {
  1641. from_memory = 0;
  1642. persistent_script = cache_script_in_file_cache(persistent_script, &from_memory);
  1643. return zend_accel_load_script(persistent_script, from_memory);
  1644. }
  1645. return op_array;
  1646. }
  1647. #endif
  1648. int check_persistent_script_access(zend_persistent_script *persistent_script)
  1649. {
  1650. char *phar_path, *ptr;
  1651. int ret;
  1652. if ((ZSTR_LEN(persistent_script->script.filename)<sizeof("phar://.phar")) ||
  1653. memcmp(ZSTR_VAL(persistent_script->script.filename), "phar://", sizeof("phar://")-1)) {
  1654. return access(ZSTR_VAL(persistent_script->script.filename), R_OK) != 0;
  1655. } else {
  1656. /* we got a cached file from .phar, so we have to strip prefix and path inside .phar to check access() */
  1657. phar_path = estrdup(ZSTR_VAL(persistent_script->script.filename)+sizeof("phar://")-1);
  1658. if ((ptr = strstr(phar_path, ".phar/")) != NULL)
  1659. {
  1660. *(ptr+sizeof(".phar/")-2) = 0; /* strip path inside .phar file */
  1661. }
  1662. ret = access(phar_path, R_OK) != 0;
  1663. efree(phar_path);
  1664. return ret;
  1665. }
  1666. }
  1667. /* zend_compile() replacement */
  1668. zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type)
  1669. {
  1670. zend_persistent_script *persistent_script = NULL;
  1671. char *key = NULL;
  1672. int key_length;
  1673. int from_shared_memory; /* if the script we've got is stored in SHM */
  1674. if (!file_handle->filename || !ZCG(accelerator_enabled)) {
  1675. /* The Accelerator is disabled, act as if without the Accelerator */
  1676. ZCG(cache_opline) = NULL;
  1677. ZCG(cache_persistent_script) = NULL;
  1678. #ifdef HAVE_OPCACHE_FILE_CACHE
  1679. if (file_handle->filename
  1680. && ZCG(accel_directives).file_cache
  1681. && ZCG(enabled) && accel_startup_ok) {
  1682. return file_cache_compile_file(file_handle, type);
  1683. }
  1684. #endif
  1685. return accelerator_orig_compile_file(file_handle, type);
  1686. #ifdef HAVE_OPCACHE_FILE_CACHE
  1687. } else if (file_cache_only) {
  1688. ZCG(cache_opline) = NULL;
  1689. ZCG(cache_persistent_script) = NULL;
  1690. return file_cache_compile_file(file_handle, type);
  1691. #endif
  1692. } else if (!ZCG(accelerator_enabled) ||
  1693. (ZCSG(restart_in_progress) && accel_restart_is_active())) {
  1694. #ifdef HAVE_OPCACHE_FILE_CACHE
  1695. if (ZCG(accel_directives).file_cache) {
  1696. return file_cache_compile_file(file_handle, type);
  1697. }
  1698. #endif
  1699. ZCG(cache_opline) = NULL;
  1700. ZCG(cache_persistent_script) = NULL;
  1701. return accelerator_orig_compile_file(file_handle, type);
  1702. }
  1703. /* In case this callback is called from include_once, require_once or it's
  1704. * a main FastCGI request, the key must be already calculated, and cached
  1705. * persistent script already found */
  1706. if (ZCG(cache_persistent_script) &&
  1707. ((!EG(current_execute_data) &&
  1708. file_handle->filename == SG(request_info).path_translated &&
  1709. ZCG(cache_opline) == NULL) ||
  1710. (EG(current_execute_data) &&
  1711. EG(current_execute_data)->func &&
  1712. ZEND_USER_CODE(EG(current_execute_data)->func->common.type) &&
  1713. ZCG(cache_opline) == EG(current_execute_data)->opline))) {
  1714. persistent_script = ZCG(cache_persistent_script);
  1715. if (ZCG(key_len)) {
  1716. key = ZCG(key);
  1717. key_length = ZCG(key_len);
  1718. }
  1719. } else {
  1720. if (!ZCG(accel_directives).revalidate_path) {
  1721. /* try to find cached script by key */
  1722. key = accel_make_persistent_key(file_handle->filename, strlen(file_handle->filename), &key_length);
  1723. if (!key) {
  1724. ZCG(cache_opline) = NULL;
  1725. ZCG(cache_persistent_script) = NULL;
  1726. return accelerator_orig_compile_file(file_handle, type);
  1727. }
  1728. persistent_script = zend_accel_hash_str_find(&ZCSG(hash), key, key_length);
  1729. } else if (UNEXPECTED(is_stream_path(file_handle->filename) && !is_cacheable_stream_path(file_handle->filename))) {
  1730. ZCG(cache_opline) = NULL;
  1731. ZCG(cache_persistent_script) = NULL;
  1732. return accelerator_orig_compile_file(file_handle, type);
  1733. }
  1734. if (!persistent_script) {
  1735. /* try to find cached script by full real path */
  1736. zend_accel_hash_entry *bucket;
  1737. /* open file to resolve the path */
  1738. if (file_handle->type == ZEND_HANDLE_FILENAME &&
  1739. accelerator_orig_zend_stream_open_function(file_handle->filename, file_handle) == FAILURE) {
  1740. if (type == ZEND_REQUIRE) {
  1741. zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, file_handle->filename);
  1742. zend_bailout();
  1743. } else {
  1744. zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, file_handle->filename);
  1745. }
  1746. return NULL;
  1747. }
  1748. if (file_handle->opened_path) {
  1749. bucket = zend_accel_hash_find_entry(&ZCSG(hash), file_handle->opened_path);
  1750. if (bucket) {
  1751. persistent_script = (zend_persistent_script *)bucket->data;
  1752. if (key && !persistent_script->corrupted) {
  1753. HANDLE_BLOCK_INTERRUPTIONS();
  1754. SHM_UNPROTECT();
  1755. zend_shared_alloc_lock();
  1756. zend_accel_add_key(key, key_length, bucket);
  1757. zend_shared_alloc_unlock();
  1758. SHM_PROTECT();
  1759. HANDLE_UNBLOCK_INTERRUPTIONS();
  1760. }
  1761. }
  1762. }
  1763. }
  1764. }
  1765. /* clear cache */
  1766. ZCG(cache_opline) = NULL;
  1767. ZCG(cache_persistent_script) = NULL;
  1768. if (persistent_script && persistent_script->corrupted) {
  1769. persistent_script = NULL;
  1770. }
  1771. /* Make sure we only increase the currently running processes semaphore
  1772. * once each execution (this function can be called more than once on
  1773. * each execution)
  1774. */
  1775. if (!ZCG(counted)) {
  1776. if (accel_activate_add() == FAILURE) {
  1777. #ifdef HAVE_OPCACHE_FILE_CACHE
  1778. if (ZCG(accel_directives).file_cache) {
  1779. return file_cache_compile_file(file_handle, type);
  1780. }
  1781. #endif
  1782. return accelerator_orig_compile_file(file_handle, type);
  1783. }
  1784. ZCG(counted) = 1;
  1785. }
  1786. /* Revalidate acessibility of cached file */
  1787. if (EXPECTED(persistent_script != NULL) &&
  1788. UNEXPECTED(ZCG(accel_directives).validate_permission) &&
  1789. file_handle->type == ZEND_HANDLE_FILENAME &&
  1790. UNEXPECTED(check_persistent_script_access(persistent_script))) {
  1791. if (type == ZEND_REQUIRE) {
  1792. zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, file_handle->filename);
  1793. zend_bailout();
  1794. } else {
  1795. zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, file_handle->filename);
  1796. }
  1797. return NULL;
  1798. }
  1799. HANDLE_BLOCK_INTERRUPTIONS();
  1800. SHM_UNPROTECT();
  1801. /* If script is found then validate_timestamps if option is enabled */
  1802. if (persistent_script && ZCG(accel_directives).validate_timestamps) {
  1803. if (validate_timestamp_and_record(persistent_script, file_handle) == FAILURE) {
  1804. zend_shared_alloc_lock();
  1805. if (!persistent_script->corrupted) {
  1806. persistent_script->corrupted = 1;
  1807. persistent_script->timestamp = 0;
  1808. ZSMMG(wasted_shared_memory) += persistent_script->dynamic_members.memory_consumption;
  1809. if (ZSMMG(memory_exhausted)) {
  1810. zend_accel_restart_reason reason =
  1811. zend_accel_hash_is_full(&ZCSG(hash)) ? ACCEL_RESTART_HASH : ACCEL_RESTART_OOM;
  1812. zend_accel_schedule_restart_if_necessary(reason);
  1813. }
  1814. }
  1815. zend_shared_alloc_unlock();
  1816. persistent_script = NULL;
  1817. }
  1818. }
  1819. /* if turned on - check the compiled script ADLER32 checksum */
  1820. if (persistent_script && ZCG(accel_directives).consistency_checks
  1821. && persistent_script->dynamic_members.hits % ZCG(accel_directives).consistency_checks == 0) {
  1822. unsigned int checksum = zend_accel_script_checksum(persistent_script);
  1823. if (checksum != persistent_script->dynamic_members.checksum ) {
  1824. /* The checksum is wrong */
  1825. zend_accel_error(ACCEL_LOG_INFO, "Checksum failed for '%s': expected=0x%08x, found=0x%08x",
  1826. ZSTR_VAL(persistent_script->script.filename), persistent_script->dynamic_members.checksum, checksum);
  1827. zend_shared_alloc_lock();
  1828. if (!persistent_script->corrupted) {
  1829. persistent_script->corrupted = 1;
  1830. persistent_script->timestamp = 0;
  1831. ZSMMG(wasted_shared_memory) += persistent_script->dynamic_members.memory_consumption;
  1832. if (ZSMMG(memory_exhausted)) {
  1833. zend_accel_restart_reason reason =
  1834. zend_accel_hash_is_full(&ZCSG(hash)) ? ACCEL_RESTART_HASH : ACCEL_RESTART_OOM;
  1835. zend_accel_schedule_restart_if_necessary(reason);
  1836. }
  1837. }
  1838. zend_shared_alloc_unlock();
  1839. persistent_script = NULL;
  1840. }
  1841. }
  1842. #ifdef HAVE_OPCACHE_FILE_CACHE
  1843. /* Check the second level cache */
  1844. if (!persistent_script && ZCG(accel_directives).file_cache) {
  1845. persistent_script = zend_file_cache_script_load(file_handle);
  1846. }
  1847. #endif
  1848. /* If script was not found or invalidated by validate_timestamps */
  1849. if (!persistent_script) {
  1850. uint32_t old_const_num = zend_hash_next_free_element(EG(zend_constants));
  1851. zend_op_array *op_array;
  1852. /* Cache miss.. */
  1853. ZCSG(misses)++;
  1854. /* No memory left. Behave like without the Accelerator */
  1855. if (ZSMMG(memory_exhausted) || ZCSG(restart_pending)) {
  1856. SHM_PROTECT();
  1857. HANDLE_UNBLOCK_INTERRUPTIONS();
  1858. #ifdef HAVE_OPCACHE_FILE_CACHE
  1859. if (ZCG(accel_directives).file_cache) {
  1860. return file_cache_compile_file(file_handle, type);
  1861. }
  1862. #endif
  1863. return accelerator_orig_compile_file(file_handle, type);
  1864. }
  1865. SHM_PROTECT();
  1866. HANDLE_UNBLOCK_INTERRUPTIONS();
  1867. persistent_script = opcache_compile_file(file_handle, type, key, &op_array);
  1868. HANDLE_BLOCK_INTERRUPTIONS();
  1869. SHM_UNPROTECT();
  1870. /* Try and cache the script and assume that it is returned from_shared_memory.
  1871. * If it isn't compile_and_cache_file() changes the flag to 0
  1872. */
  1873. from_shared_memory = 0;
  1874. if (persistent_script) {
  1875. persistent_script = cache_script_in_shared_memory(persistent_script, key, key ? key_length : 0, &from_shared_memory);
  1876. }
  1877. /* Caching is disabled, returning op_array;
  1878. * or something went wrong during compilation, returning NULL
  1879. */
  1880. if (!persistent_script) {
  1881. SHM_PROTECT();
  1882. HANDLE_UNBLOCK_INTERRUPTIONS();
  1883. return op_array;
  1884. }
  1885. if (from_shared_memory) {
  1886. /* Delete immutable arrays moved into SHM */
  1887. uint32_t new_const_num = zend_hash_next_free_element(EG(zend_constants));
  1888. while (new_const_num > old_const_num) {
  1889. new_const_num--;
  1890. zend_hash_index_del(EG(zend_constants), new_const_num);
  1891. }
  1892. }
  1893. } else {
  1894. #if !ZEND_WIN32
  1895. ZCSG(hits)++; /* TBFixed: may lose one hit */
  1896. persistent_script->dynamic_members.hits++; /* see above */
  1897. #else
  1898. #ifdef _M_X64
  1899. InterlockedIncrement64(&ZCSG(hits));
  1900. #else
  1901. InterlockedIncrement(&ZCSG(hits));
  1902. #endif
  1903. InterlockedIncrement64(&persistent_script->dynamic_members.hits);
  1904. #endif
  1905. /* see bug #15471 (old BTS) */
  1906. if (persistent_script->script.filename) {
  1907. if (!EG(current_execute_data) || !EG(current_execute_data)->opline ||
  1908. !EG(current_execute_data)->func ||
  1909. !ZEND_USER_CODE(EG(current_execute_data)->func->common.type) ||
  1910. EG(current_execute_data)->opline->opcode != ZEND_INCLUDE_OR_EVAL ||
  1911. (EG(current_execute_data)->opline->extended_value != ZEND_INCLUDE_ONCE &&
  1912. EG(current_execute_data)->opline->extended_value != ZEND_REQUIRE_ONCE)) {
  1913. if (zend_hash_add_empty_element(&EG(included_files), persistent_script->script.filename) != NULL) {
  1914. /* ext/phar has to load phar's metadata into memory */
  1915. if (persistent_script->is_phar) {
  1916. php_stream_statbuf ssb;
  1917. char *fname = emalloc(sizeof("phar://") + ZSTR_LEN(persistent_script->script.filename));
  1918. memcpy(fname, "phar://", sizeof("phar://") - 1);
  1919. memcpy(fname + sizeof("phar://") - 1, ZSTR_VAL(persistent_script->script.filename), ZSTR_LEN(persistent_script->script.filename) + 1);
  1920. php_stream_stat_path(fname, &ssb);
  1921. efree(fname);
  1922. }
  1923. }
  1924. }
  1925. }
  1926. zend_file_handle_dtor(file_handle);
  1927. from_shared_memory = 1;
  1928. }
  1929. persistent_script->dynamic_members.last_used = ZCG(request_time);
  1930. SHM_PROTECT();
  1931. HANDLE_UNBLOCK_INTERRUPTIONS();
  1932. /* Fetch jit auto globals used in the script before execution */
  1933. if (persistent_script->ping_auto_globals_mask) {
  1934. zend_accel_set_auto_globals(persistent_script->ping_auto_globals_mask);
  1935. }
  1936. return zend_accel_load_script(persistent_script, from_shared_memory);
  1937. }
  1938. /* zend_stream_open_function() replacement for PHP 5.3 and above */
  1939. static int persistent_stream_open_function(const char *filename, zend_file_handle *handle)
  1940. {
  1941. if (ZCG(cache_persistent_script)) {
  1942. /* check if callback is called from include_once or it's a main request */
  1943. if ((!EG(current_execute_data) &&
  1944. filename == SG(request_info).path_translated &&
  1945. ZCG(cache_opline) == NULL) ||
  1946. (EG(current_execute_data) &&
  1947. EG(current_execute_data)->func &&
  1948. ZEND_USER_CODE(EG(current_execute_data)->func->common.type) &&
  1949. ZCG(cache_opline) == EG(current_execute_data)->opline)) {
  1950. /* we are in include_once or FastCGI request */
  1951. handle->filename = (char*)filename;
  1952. handle->free_filename = 0;
  1953. handle->opened_path = zend_string_copy(ZCG(cache_persistent_script)->script.filename);
  1954. handle->type = ZEND_HANDLE_FILENAME;
  1955. return SUCCESS;
  1956. }
  1957. ZCG(cache_opline) = NULL;
  1958. ZCG(cache_persistent_script) = NULL;
  1959. }
  1960. return accelerator_orig_zend_stream_open_function(filename, handle);
  1961. }
  1962. /* zend_resolve_path() replacement for PHP 5.3 and above */
  1963. static zend_string* persistent_zend_resolve_path(const char *filename, size_t filename_len)
  1964. {
  1965. if (
  1966. #ifdef HAVE_OPCACHE_FILE_CACHE
  1967. !file_cache_only &&
  1968. #endif
  1969. ZCG(accelerator_enabled)) {
  1970. /* check if callback is called from include_once or it's a main request */
  1971. if ((!EG(current_execute_data) &&
  1972. filename == SG(request_info).path_translated) ||
  1973. (EG(current_execute_data) &&
  1974. EG(current_execute_data)->func &&
  1975. ZEND_USER_CODE(EG(current_execute_data)->func->common.type) &&
  1976. EG(current_execute_data)->opline->opcode == ZEND_INCLUDE_OR_EVAL &&
  1977. (EG(current_execute_data)->opline->extended_value == ZEND_INCLUDE_ONCE ||
  1978. EG(current_execute_data)->opline->extended_value == ZEND_REQUIRE_ONCE))) {
  1979. /* we are in include_once or FastCGI request */
  1980. zend_string *resolved_path;
  1981. int key_length;
  1982. char *key = NULL;
  1983. if (!ZCG(accel_directives).revalidate_path) {
  1984. /* lookup by "not-real" path */
  1985. key = accel_make_persistent_key(filename, filename_len, &key_length);
  1986. if (key) {
  1987. zend_accel_hash_entry *bucket = zend_accel_hash_str_find_entry(&ZCSG(hash), key, key_length);
  1988. if (bucket != NULL) {
  1989. zend_persistent_script *persistent_script = (zend_persistent_script *)bucket->data;
  1990. if (!persistent_script->corrupted) {
  1991. ZCG(cache_opline) = EG(current_execute_data) ? EG(current_execute_data)->opline : NULL;
  1992. ZCG(cache_persistent_script) = persistent_script;
  1993. return zend_string_copy(persistent_script->script.filename);
  1994. }
  1995. }
  1996. } else {
  1997. ZCG(cache_opline) = NULL;
  1998. ZCG(cache_persistent_script) = NULL;
  1999. return accelerator_orig_zend_resolve_path(filename, filename_len);
  2000. }
  2001. }
  2002. /* find the full real path */
  2003. resolved_path = accelerator_orig_zend_resolve_path(filename, filename_len);
  2004. if (resolved_path) {
  2005. /* lookup by real path */
  2006. zend_accel_hash_entry *bucket = zend_accel_hash_find_entry(&ZCSG(hash), resolved_path);
  2007. if (bucket) {
  2008. zend_persistent_script *persistent_script = (zend_persistent_script *)bucket->data;
  2009. if (!persistent_script->corrupted) {
  2010. if (key) {
  2011. /* add another "key" for the same bucket */
  2012. HANDLE_BLOCK_INTERRUPTIONS();
  2013. SHM_UNPROTECT();
  2014. zend_shared_alloc_lock();
  2015. zend_accel_add_key(key, key_length, bucket);
  2016. zend_shared_alloc_unlock();
  2017. SHM_PROTECT();
  2018. HANDLE_UNBLOCK_INTERRUPTIONS();
  2019. } else {
  2020. ZCG(key_len) = 0;
  2021. }
  2022. ZCG(cache_opline) = EG(current_execute_data) ? EG(current_execute_data)->opline : NULL;
  2023. ZCG(cache_persistent_script) = persistent_script;
  2024. return resolved_path;
  2025. }
  2026. }
  2027. }
  2028. ZCG(cache_opline) = NULL;
  2029. ZCG(cache_persistent_script) = NULL;
  2030. return resolved_path;
  2031. }
  2032. }
  2033. ZCG(cache_opline) = NULL;
  2034. ZCG(cache_persistent_script) = NULL;
  2035. return accelerator_orig_zend_resolve_path(filename, filename_len);
  2036. }
  2037. static void zend_reset_cache_vars(void)
  2038. {
  2039. ZSMMG(memory_exhausted) = 0;
  2040. ZCSG(hits) = 0;
  2041. ZCSG(misses) = 0;
  2042. ZCSG(blacklist_misses) = 0;
  2043. ZSMMG(wasted_shared_memory) = 0;
  2044. ZCSG(restart_pending) = 0;
  2045. ZCSG(force_restart_time) = 0;
  2046. }
  2047. static void accel_reset_pcre_cache(void)
  2048. {
  2049. Bucket *p;
  2050. ZEND_HASH_FOREACH_BUCKET(&PCRE_G(pcre_cache), p) {
  2051. /* Remove PCRE cache entries with inconsistent keys */
  2052. if (zend_accel_in_shm(p->key)) {
  2053. p->key = NULL;
  2054. zend_hash_del_bucket(&PCRE_G(pcre_cache), p);
  2055. }
  2056. } ZEND_HASH_FOREACH_END();
  2057. }
  2058. static void accel_activate(void)
  2059. {
  2060. if (!ZCG(enabled) || !accel_startup_ok) {
  2061. ZCG(accelerator_enabled) = 0;
  2062. return;
  2063. }
  2064. if (!ZCG(function_table).nTableSize) {
  2065. zend_hash_init(&ZCG(function_table), zend_hash_num_elements(CG(function_table)), NULL, ZEND_FUNCTION_DTOR, 1);
  2066. zend_accel_copy_internal_functions();
  2067. }
  2068. /* PHP-5.4 and above return "double", but we use 1 sec precision */
  2069. ZCG(auto_globals_mask) = 0;
  2070. ZCG(request_time) = (time_t)sapi_get_request_time();
  2071. ZCG(cache_opline) = NULL;
  2072. ZCG(cache_persistent_script) = NULL;
  2073. ZCG(include_path_key_len) = 0;
  2074. ZCG(include_path_check) = 1;
  2075. /* check if ZCG(function_table) wasn't somehow polluted on the way */
  2076. if (ZCG(internal_functions_count) != (zend_long)zend_hash_num_elements(&ZCG(function_table))) {
  2077. zend_accel_error(ACCEL_LOG_WARNING, "Internal functions count changed - was %d, now %d", ZCG(internal_functions_count), zend_hash_num_elements(&ZCG(function_table)));
  2078. }
  2079. ZCG(cwd) = NULL;
  2080. ZCG(cwd_key_len) = 0;
  2081. ZCG(cwd_check) = 1;
  2082. #ifdef HAVE_OPCACHE_FILE_CACHE
  2083. if (file_cache_only) {
  2084. ZCG(accelerator_enabled) = 0;
  2085. return;
  2086. }
  2087. #endif
  2088. #ifndef ZEND_WIN32
  2089. if (ZCG(accel_directives).validate_root) {
  2090. struct stat buf;
  2091. if (stat("/", &buf) != 0) {
  2092. ZCG(root_hash) = 0;
  2093. } else {
  2094. ZCG(root_hash) = buf.st_ino;
  2095. if (sizeof(buf.st_ino) > sizeof(ZCG(root_hash))) {
  2096. if (ZCG(root_hash) != buf.st_ino) {
  2097. zend_string *key = zend_string_init("opcache.enable", sizeof("opcache.enable")-1, 0);
  2098. zend_alter_ini_entry_chars(key, "0", 1, ZEND_INI_SYSTEM, ZEND_INI_STAGE_RUNTIME);
  2099. zend_string_release_ex(key, 0);
  2100. zend_accel_error(ACCEL_LOG_WARNING, "Can't cache files in chroot() directory with too big inode");
  2101. return;
  2102. }
  2103. }
  2104. }
  2105. } else {
  2106. ZCG(root_hash) = 0;
  2107. }
  2108. #endif
  2109. HANDLE_BLOCK_INTERRUPTIONS();
  2110. SHM_UNPROTECT();
  2111. if (ZCG(counted)) {
  2112. #ifdef ZTS
  2113. zend_accel_error(ACCEL_LOG_WARNING, "Stuck count for thread id %lu", (unsigned long) tsrm_thread_id());
  2114. #else
  2115. zend_accel_error(ACCEL_LOG_WARNING, "Stuck count for pid %d", getpid());
  2116. #endif
  2117. accel_unlock_all();
  2118. ZCG(counted) = 0;
  2119. }
  2120. if (ZCSG(restart_pending)) {
  2121. zend_shared_alloc_lock();
  2122. if (ZCSG(restart_pending) != 0) { /* check again, to ensure that the cache wasn't already cleaned by another process */
  2123. if (accel_is_inactive() == SUCCESS) {
  2124. zend_accel_error(ACCEL_LOG_DEBUG, "Restarting!");
  2125. ZCSG(restart_pending) = 0;
  2126. switch ZCSG(restart_reason) {
  2127. case ACCEL_RESTART_OOM:
  2128. ZCSG(oom_restarts)++;
  2129. break;
  2130. case ACCEL_RESTART_HASH:
  2131. ZCSG(hash_restarts)++;
  2132. break;
  2133. case ACCEL_RESTART_USER:
  2134. ZCSG(manual_restarts)++;
  2135. break;
  2136. }
  2137. accel_restart_enter();
  2138. zend_reset_cache_vars();
  2139. zend_accel_hash_clean(&ZCSG(hash));
  2140. if (ZCG(accel_directives).interned_strings_buffer) {
  2141. accel_interned_strings_restore_state();
  2142. }
  2143. zend_shared_alloc_restore_state();
  2144. ZCSG(accelerator_enabled) = ZCSG(cache_status_before_restart);
  2145. if (ZCSG(last_restart_time) < ZCG(request_time)) {
  2146. ZCSG(last_restart_time) = ZCG(request_time);
  2147. } else {
  2148. ZCSG(last_restart_time)++;
  2149. }
  2150. accel_restart_leave();
  2151. }
  2152. }
  2153. zend_shared_alloc_unlock();
  2154. }
  2155. ZCG(accelerator_enabled) = ZCSG(accelerator_enabled);
  2156. SHM_PROTECT();
  2157. HANDLE_UNBLOCK_INTERRUPTIONS();
  2158. if (ZCG(accelerator_enabled) && ZCSG(last_restart_time) != ZCG(last_restart_time)) {
  2159. /* SHM was reinitialized. */
  2160. ZCG(last_restart_time) = ZCSG(last_restart_time);
  2161. /* Reset in-process realpath cache */
  2162. realpath_cache_clean();
  2163. accel_reset_pcre_cache();
  2164. ZCG(pcre_reseted) = 0;
  2165. } else if (!ZCG(accelerator_enabled) && !ZCG(pcre_reseted)) {
  2166. accel_reset_pcre_cache();
  2167. ZCG(pcre_reseted) = 1;
  2168. }
  2169. }
  2170. int accel_post_deactivate(void)
  2171. {
  2172. if (!ZCG(enabled) || !accel_startup_ok) {
  2173. return SUCCESS;
  2174. }
  2175. zend_shared_alloc_safe_unlock(); /* be sure we didn't leave cache locked */
  2176. accel_unlock_all();
  2177. ZCG(counted) = 0;
  2178. return SUCCESS;
  2179. }
  2180. static void accel_deactivate(void)
  2181. {
  2182. /* ensure that we restore function_table and class_table
  2183. * In general, they're restored by persistent_compile_file(), but in case
  2184. * the script is aborted abnormally, they may become messed up.
  2185. */
  2186. if (ZCG(cwd)) {
  2187. zend_string_release_ex(ZCG(cwd), 0);
  2188. ZCG(cwd) = NULL;
  2189. }
  2190. }
  2191. static int accelerator_remove_cb(zend_extension *element1, zend_extension *element2)
  2192. {
  2193. (void)element2; /* keep the compiler happy */
  2194. if (!strcmp(element1->name, ACCELERATOR_PRODUCT_NAME )) {
  2195. element1->startup = NULL;
  2196. #if 0
  2197. /* We have to call shutdown callback it to free TS resources */
  2198. element1->shutdown = NULL;
  2199. #endif
  2200. element1->activate = NULL;
  2201. element1->deactivate = NULL;
  2202. element1->op_array_handler = NULL;
  2203. #ifdef __DEBUG_MESSAGES__
  2204. fprintf(stderr, ACCELERATOR_PRODUCT_NAME " is disabled: %s\n", (zps_failure_reason ? zps_failure_reason : "unknown error"));
  2205. fflush(stderr);
  2206. #endif
  2207. }
  2208. return 0;
  2209. }
  2210. static void zps_startup_failure(char *reason, char *api_reason, int (*cb)(zend_extension *, zend_extension *))
  2211. {
  2212. accel_startup_ok = 0;
  2213. zps_failure_reason = reason;
  2214. zps_api_failure_reason = api_reason?api_reason:reason;
  2215. zend_llist_del_element(&zend_extensions, NULL, (int (*)(void *, void *))cb);
  2216. }
  2217. static inline int accel_find_sapi(void)
  2218. {
  2219. static const char *supported_sapis[] = {
  2220. "apache",
  2221. "fastcgi",
  2222. "cli-server",
  2223. "cgi-fcgi",
  2224. "fpm-fcgi",
  2225. "fpmi-fcgi",
  2226. "apache2handler",
  2227. "litespeed",
  2228. "uwsgi",
  2229. NULL
  2230. };
  2231. const char **sapi_name;
  2232. if (sapi_module.name) {
  2233. for (sapi_name = supported_sapis; *sapi_name; sapi_name++) {
  2234. if (strcmp(sapi_module.name, *sapi_name) == 0) {
  2235. return SUCCESS;
  2236. }
  2237. }
  2238. if (ZCG(accel_directives).enable_cli && (
  2239. strcmp(sapi_module.name, "cli") == 0
  2240. || strcmp(sapi_module.name, "phpdbg") == 0)) {
  2241. return SUCCESS;
  2242. }
  2243. }
  2244. return FAILURE;
  2245. }
  2246. static int zend_accel_init_shm(void)
  2247. {
  2248. int i;
  2249. zend_shared_alloc_lock();
  2250. if (ZCG(accel_directives).interned_strings_buffer) {
  2251. accel_shared_globals = zend_shared_alloc((ZCG(accel_directives).interned_strings_buffer * 1024 * 1024));
  2252. } else {
  2253. accel_shared_globals = zend_shared_alloc(sizeof(zend_accel_shared_globals));
  2254. }
  2255. if (!accel_shared_globals) {
  2256. zend_accel_error(ACCEL_LOG_FATAL, "Insufficient shared memory!");
  2257. zend_shared_alloc_unlock();
  2258. return FAILURE;
  2259. }
  2260. memset(accel_shared_globals, 0, sizeof(zend_accel_shared_globals));
  2261. ZSMMG(app_shared_globals) = accel_shared_globals;
  2262. zend_accel_hash_init(&ZCSG(hash), ZCG(accel_directives).max_accelerated_files);
  2263. if (ZCG(accel_directives).interned_strings_buffer) {
  2264. uint32_t hash_size;
  2265. /* must be a power of two */
  2266. hash_size = ZCG(accel_directives).interned_strings_buffer * (32 * 1024);
  2267. hash_size |= (hash_size >> 1);
  2268. hash_size |= (hash_size >> 2);
  2269. hash_size |= (hash_size >> 4);
  2270. hash_size |= (hash_size >> 8);
  2271. hash_size |= (hash_size >> 16);
  2272. ZCSG(interned_strings).nTableMask = hash_size << 2;
  2273. ZCSG(interned_strings).nNumOfElements = 0;
  2274. ZCSG(interned_strings).start =
  2275. (zend_string*)((char*)&ZCSG(interned_strings) +
  2276. sizeof(zend_string_table) +
  2277. ((hash_size + 1) * sizeof(uint32_t))) +
  2278. 8;
  2279. ZCSG(interned_strings).top =
  2280. ZCSG(interned_strings).start;
  2281. ZCSG(interned_strings).end =
  2282. (zend_string*)((char*)accel_shared_globals +
  2283. ZCG(accel_directives).interned_strings_buffer * 1024 * 1024);
  2284. ZCSG(interned_strings).saved_top = NULL;
  2285. memset((char*)&ZCSG(interned_strings) + sizeof(zend_string_table),
  2286. STRTAB_INVALID_POS,
  2287. (char*)ZCSG(interned_strings).start -
  2288. ((char*)&ZCSG(interned_strings) + sizeof(zend_string_table)));
  2289. zend_interned_strings_set_permanent_storage_copy_handlers(accel_use_shm_interned_strings, accel_use_permanent_interned_strings);
  2290. }
  2291. zend_interned_strings_set_request_storage_handlers(accel_new_interned_string_for_php, accel_init_interned_string_for_php);
  2292. zend_reset_cache_vars();
  2293. ZCSG(oom_restarts) = 0;
  2294. ZCSG(hash_restarts) = 0;
  2295. ZCSG(manual_restarts) = 0;
  2296. ZCSG(accelerator_enabled) = 1;
  2297. ZCSG(start_time) = zend_accel_get_time();
  2298. ZCSG(last_restart_time) = 0;
  2299. ZCSG(restart_in_progress) = 0;
  2300. for (i = 0; i < -HT_MIN_MASK; i++) {
  2301. ZCSG(uninitialized_bucket)[i] = HT_INVALID_IDX;
  2302. }
  2303. zend_shared_alloc_unlock();
  2304. return SUCCESS;
  2305. }
  2306. static void accel_globals_ctor(zend_accel_globals *accel_globals)
  2307. {
  2308. #if defined(COMPILE_DL_OPCACHE) && defined(ZTS)
  2309. ZEND_TSRMLS_CACHE_UPDATE();
  2310. #endif
  2311. memset(accel_globals, 0, sizeof(zend_accel_globals));
  2312. /* TODO refactor to init this just once. */
  2313. accel_gen_system_id();
  2314. }
  2315. static void accel_globals_dtor(zend_accel_globals *accel_globals)
  2316. {
  2317. if (accel_globals->function_table.nTableSize) {
  2318. accel_globals->function_table.pDestructor = NULL;
  2319. zend_hash_destroy(&accel_globals->function_table);
  2320. }
  2321. }
  2322. #define ZEND_BIN_ID "BIN_" ZEND_TOSTR(SIZEOF_CHAR) ZEND_TOSTR(SIZEOF_INT) ZEND_TOSTR(SIZEOF_LONG) ZEND_TOSTR(SIZEOF_SIZE_T) ZEND_TOSTR(SIZEOF_ZEND_LONG) ZEND_TOSTR(ZEND_MM_ALIGNMENT)
  2323. static void accel_gen_system_id(void)
  2324. {
  2325. PHP_MD5_CTX context;
  2326. unsigned char digest[16], c;
  2327. char *md5str = ZCG(system_id);
  2328. int i;
  2329. zend_module_entry *module;
  2330. zend_extension *extension;
  2331. zend_llist_position pos;
  2332. PHP_MD5Init(&context);
  2333. PHP_MD5Update(&context, PHP_VERSION, sizeof(PHP_VERSION)-1);
  2334. PHP_MD5Update(&context, ZEND_EXTENSION_BUILD_ID, sizeof(ZEND_EXTENSION_BUILD_ID)-1);
  2335. PHP_MD5Update(&context, ZEND_BIN_ID, sizeof(ZEND_BIN_ID)-1);
  2336. if (strstr(PHP_VERSION, "-dev") != 0) {
  2337. /* Development versions may be changed from build to build */
  2338. PHP_MD5Update(&context, __DATE__, sizeof(__DATE__)-1);
  2339. PHP_MD5Update(&context, __TIME__, sizeof(__TIME__)-1);
  2340. }
  2341. /* Modules may have changed after restart which can cause dangling pointers from
  2342. * custom opcode handlers in the second-level cache files
  2343. */
  2344. ZEND_HASH_FOREACH_PTR(&module_registry, module) {
  2345. PHP_MD5Update(&context, module->name, strlen(module->name));
  2346. if (module->version != NULL) {
  2347. PHP_MD5Update(&context, module->version, strlen(module->version));
  2348. }
  2349. } ZEND_HASH_FOREACH_END();
  2350. extension = (zend_extension *) zend_llist_get_first_ex(&zend_extensions, &pos);
  2351. while (extension) {
  2352. PHP_MD5Update(&context, extension->name, strlen(extension->name));
  2353. if (extension->version != NULL) {
  2354. PHP_MD5Update(&context, extension->version, strlen(extension->version));
  2355. }
  2356. extension = (zend_extension *) zend_llist_get_next_ex(&zend_extensions, &pos);
  2357. }
  2358. PHP_MD5Final(digest, &context);
  2359. for (i = 0; i < 16; i++) {
  2360. c = digest[i] >> 4;
  2361. c = (c <= 9) ? c + '0' : c - 10 + 'a';
  2362. md5str[i * 2] = c;
  2363. c = digest[i] & 0x0f;
  2364. c = (c <= 9) ? c + '0' : c - 10 + 'a';
  2365. md5str[(i * 2) + 1] = c;
  2366. }
  2367. }
  2368. #ifdef HAVE_HUGE_CODE_PAGES
  2369. # ifndef _WIN32
  2370. # include <sys/mman.h>
  2371. # ifndef MAP_ANON
  2372. # ifdef MAP_ANONYMOUS
  2373. # define MAP_ANON MAP_ANONYMOUS
  2374. # endif
  2375. # endif
  2376. # ifndef MAP_FAILED
  2377. # define MAP_FAILED ((void*)-1)
  2378. # endif
  2379. # endif
  2380. # if defined(MAP_HUGETLB) || defined(MADV_HUGEPAGE)
  2381. static int accel_remap_huge_pages(void *start, size_t size, const char *name, size_t offset)
  2382. {
  2383. void *ret = MAP_FAILED;
  2384. void *mem;
  2385. mem = mmap(NULL, size,
  2386. PROT_READ | PROT_WRITE,
  2387. MAP_PRIVATE | MAP_ANONYMOUS,
  2388. -1, 0);
  2389. if (mem == MAP_FAILED) {
  2390. zend_error(E_WARNING,
  2391. ACCELERATOR_PRODUCT_NAME " huge_code_pages: mmap failed: %s (%d)",
  2392. strerror(errno), errno);
  2393. return -1;
  2394. }
  2395. memcpy(mem, start, size);
  2396. # ifdef MAP_HUGETLB
  2397. ret = mmap(start, size,
  2398. PROT_READ | PROT_WRITE | PROT_EXEC,
  2399. MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED | MAP_HUGETLB,
  2400. -1, 0);
  2401. # endif
  2402. if (ret == MAP_FAILED) {
  2403. ret = mmap(start, size,
  2404. PROT_READ | PROT_WRITE | PROT_EXEC,
  2405. MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
  2406. -1, 0);
  2407. /* this should never happen? */
  2408. ZEND_ASSERT(ret != MAP_FAILED);
  2409. # ifdef MADV_HUGEPAGE
  2410. if (-1 == madvise(start, size, MADV_HUGEPAGE)) {
  2411. memcpy(start, mem, size);
  2412. mprotect(start, size, PROT_READ | PROT_EXEC);
  2413. munmap(mem, size);
  2414. zend_error(E_WARNING,
  2415. ACCELERATOR_PRODUCT_NAME " huge_code_pages: madvise(HUGEPAGE) failed: %s (%d)",
  2416. strerror(errno), errno);
  2417. return -1;
  2418. }
  2419. # else
  2420. memcpy(start, mem, size);
  2421. mprotect(start, size, PROT_READ | PROT_EXEC);
  2422. munmap(mem, size);
  2423. zend_error(E_WARNING,
  2424. ACCELERATOR_PRODUCT_NAME " huge_code_pages: mmap(HUGETLB) failed: %s (%d)",
  2425. strerror(errno), errno);
  2426. return -1;
  2427. # endif
  2428. }
  2429. if (ret == start) {
  2430. memcpy(start, mem, size);
  2431. mprotect(start, size, PROT_READ | PROT_EXEC);
  2432. }
  2433. munmap(mem, size);
  2434. return (ret == start) ? 0 : -1;
  2435. }
  2436. static void accel_move_code_to_huge_pages(void)
  2437. {
  2438. FILE *f;
  2439. long unsigned int huge_page_size = 2 * 1024 * 1024;
  2440. f = fopen("/proc/self/maps", "r");
  2441. if (f) {
  2442. long unsigned int start, end, offset, inode;
  2443. char perm[5], dev[6], name[MAXPATHLEN];
  2444. int ret;
  2445. ret = fscanf(f, "%lx-%lx %4s %lx %5s %ld %s\n", &start, &end, perm, &offset, dev, &inode, name);
  2446. if (ret == 7 && perm[0] == 'r' && perm[1] == '-' && perm[2] == 'x' && name[0] == '/') {
  2447. long unsigned int seg_start = ZEND_MM_ALIGNED_SIZE_EX(start, huge_page_size);
  2448. long unsigned int seg_end = (end & ~(huge_page_size-1L));
  2449. if (seg_end > seg_start) {
  2450. zend_accel_error(ACCEL_LOG_DEBUG, "remap to huge page %lx-%lx %s \n", seg_start, seg_end, name);
  2451. accel_remap_huge_pages((void*)seg_start, seg_end - seg_start, name, offset + seg_start - start);
  2452. }
  2453. }
  2454. fclose(f);
  2455. }
  2456. }
  2457. # else
  2458. static void accel_move_code_to_huge_pages(void)
  2459. {
  2460. zend_error(E_WARNING, ACCELERATOR_PRODUCT_NAME ": opcache.huge_code_pages has no affect as huge page is not supported");
  2461. return;
  2462. }
  2463. # endif /* defined(MAP_HUGETLB) || defined(MADV_HUGEPAGE) */
  2464. #endif /* HAVE_HUGE_CODE_PAGES */
  2465. static int accel_startup(zend_extension *extension)
  2466. {
  2467. #ifdef ZTS
  2468. accel_globals_id = ts_allocate_id(&accel_globals_id, sizeof(zend_accel_globals), (ts_allocate_ctor) accel_globals_ctor, (ts_allocate_dtor) accel_globals_dtor);
  2469. #else
  2470. accel_globals_ctor(&accel_globals);
  2471. #endif
  2472. #ifdef ZEND_WIN32
  2473. # if !defined(__has_feature) || !__has_feature(address_sanitizer)
  2474. _setmaxstdio(2048); /* The default configuration is limited to 512 stdio files */
  2475. # endif
  2476. #endif
  2477. if (start_accel_module() == FAILURE) {
  2478. accel_startup_ok = 0;
  2479. zend_error(E_WARNING, ACCELERATOR_PRODUCT_NAME ": module registration failed!");
  2480. return FAILURE;
  2481. }
  2482. accel_gen_system_id();
  2483. #ifdef HAVE_HUGE_CODE_PAGES
  2484. if (ZCG(accel_directives).huge_code_pages &&
  2485. (strcmp(sapi_module.name, "cli") == 0 ||
  2486. strcmp(sapi_module.name, "cli-server") == 0 ||
  2487. strcmp(sapi_module.name, "cgi-fcgi") == 0 ||
  2488. strcmp(sapi_module.name, "fpm-fcgi") == 0)) {
  2489. accel_move_code_to_huge_pages();
  2490. }
  2491. #endif
  2492. /* no supported SAPI found - disable acceleration and stop initialization */
  2493. if (accel_find_sapi() == FAILURE) {
  2494. accel_startup_ok = 0;
  2495. if (!ZCG(accel_directives).enable_cli &&
  2496. strcmp(sapi_module.name, "cli") == 0) {
  2497. zps_startup_failure("Opcode Caching is disabled for CLI", NULL, accelerator_remove_cb);
  2498. } else {
  2499. zps_startup_failure("Opcode Caching is only supported in Apache, FPM, FastCGI and LiteSpeed SAPIs", NULL, accelerator_remove_cb);
  2500. }
  2501. return SUCCESS;
  2502. }
  2503. if (ZCG(enabled) == 0) {
  2504. return SUCCESS ;
  2505. }
  2506. orig_post_startup_cb = zend_post_startup_cb;
  2507. zend_post_startup_cb = accel_post_startup;
  2508. return SUCCESS;
  2509. }
  2510. static int accel_post_startup(void)
  2511. {
  2512. zend_function *func;
  2513. zend_ini_entry *ini_entry;
  2514. if (orig_post_startup_cb) {
  2515. int (*cb)(void) = orig_post_startup_cb;
  2516. orig_post_startup_cb = NULL;
  2517. if (cb() != SUCCESS) {
  2518. return FAILURE;
  2519. }
  2520. }
  2521. /********************************************/
  2522. /* End of non-SHM dependent initializations */
  2523. /********************************************/
  2524. #ifdef HAVE_OPCACHE_FILE_CACHE
  2525. file_cache_only = ZCG(accel_directives).file_cache_only;
  2526. if (!file_cache_only) {
  2527. #else
  2528. if (1) {
  2529. #endif
  2530. switch (zend_shared_alloc_startup(ZCG(accel_directives).memory_consumption)) {
  2531. case ALLOC_SUCCESS:
  2532. if (zend_accel_init_shm() == FAILURE) {
  2533. accel_startup_ok = 0;
  2534. return FAILURE;
  2535. }
  2536. break;
  2537. case ALLOC_FAILURE:
  2538. accel_startup_ok = 0;
  2539. zend_accel_error(ACCEL_LOG_FATAL, "Failure to initialize shared memory structures - probably not enough shared memory.");
  2540. return SUCCESS;
  2541. case SUCCESSFULLY_REATTACHED:
  2542. zend_shared_alloc_lock();
  2543. accel_shared_globals = (zend_accel_shared_globals *) ZSMMG(app_shared_globals);
  2544. if (ZCG(accel_directives).interned_strings_buffer) {
  2545. zend_interned_strings_set_permanent_storage_copy_handlers(accel_use_shm_interned_strings, accel_use_permanent_interned_strings);
  2546. }
  2547. zend_interned_strings_set_request_storage_handlers(accel_new_interned_string_for_php, accel_init_interned_string_for_php);
  2548. zend_shared_alloc_unlock();
  2549. break;
  2550. case FAILED_REATTACHED:
  2551. accel_startup_ok = 0;
  2552. zend_accel_error(ACCEL_LOG_FATAL, "Failure to initialize shared memory structures - can not reattach to exiting shared memory.");
  2553. return SUCCESS;
  2554. break;
  2555. #if ENABLE_FILE_CACHE_FALLBACK
  2556. case ALLOC_FALLBACK:
  2557. zend_shared_alloc_lock();
  2558. file_cache_only = 1;
  2559. fallback_process = 1;
  2560. zend_accel_init_auto_globals();
  2561. zend_shared_alloc_unlock();
  2562. goto file_cache_fallback;
  2563. break;
  2564. #endif
  2565. }
  2566. /* from this point further, shared memory is supposed to be OK */
  2567. /* remember the last restart time in the process memory */
  2568. ZCG(last_restart_time) = ZCSG(last_restart_time);
  2569. /* Init auto-global strings */
  2570. zend_accel_init_auto_globals();
  2571. zend_shared_alloc_lock();
  2572. zend_shared_alloc_save_state();
  2573. zend_shared_alloc_unlock();
  2574. SHM_PROTECT();
  2575. #ifdef HAVE_OPCACHE_FILE_CACHE
  2576. } else if (!ZCG(accel_directives).file_cache) {
  2577. accel_startup_ok = 0;
  2578. zend_accel_error(ACCEL_LOG_FATAL, "opcache.file_cache_only is set without a proper setting of opcache.file_cache");
  2579. return SUCCESS;
  2580. } else {
  2581. accel_shared_globals = calloc(1, sizeof(zend_accel_shared_globals));
  2582. /* Init auto-global strings */
  2583. zend_accel_init_auto_globals();
  2584. #endif
  2585. }
  2586. #if ENABLE_FILE_CACHE_FALLBACK
  2587. file_cache_fallback:
  2588. #endif
  2589. /* Override compiler */
  2590. accelerator_orig_compile_file = zend_compile_file;
  2591. zend_compile_file = persistent_compile_file;
  2592. /* Override stream opener function (to eliminate open() call caused by
  2593. * include/require statements ) */
  2594. accelerator_orig_zend_stream_open_function = zend_stream_open_function;
  2595. zend_stream_open_function = persistent_stream_open_function;
  2596. /* Override path resolver function (to eliminate stat() calls caused by
  2597. * include_once/require_once statements */
  2598. accelerator_orig_zend_resolve_path = zend_resolve_path;
  2599. zend_resolve_path = persistent_zend_resolve_path;
  2600. /* Override chdir() function */
  2601. if ((func = zend_hash_str_find_ptr(CG(function_table), "chdir", sizeof("chdir")-1)) != NULL &&
  2602. func->type == ZEND_INTERNAL_FUNCTION) {
  2603. orig_chdir = func->internal_function.handler;
  2604. func->internal_function.handler = ZEND_FN(accel_chdir);
  2605. }
  2606. ZCG(cwd) = NULL;
  2607. ZCG(include_path) = NULL;
  2608. /* Override "include_path" modifier callback */
  2609. if ((ini_entry = zend_hash_str_find_ptr(EG(ini_directives), "include_path", sizeof("include_path")-1)) != NULL) {
  2610. ZCG(include_path) = ini_entry->value;
  2611. orig_include_path_on_modify = ini_entry->on_modify;
  2612. ini_entry->on_modify = accel_include_path_on_modify;
  2613. }
  2614. accel_startup_ok = 1;
  2615. /* Override file_exists(), is_file() and is_readable() */
  2616. zend_accel_override_file_functions();
  2617. /* Load black list */
  2618. accel_blacklist.entries = NULL;
  2619. if (ZCG(enabled) && accel_startup_ok &&
  2620. ZCG(accel_directives).user_blacklist_filename &&
  2621. *ZCG(accel_directives.user_blacklist_filename)) {
  2622. zend_accel_blacklist_init(&accel_blacklist);
  2623. zend_accel_blacklist_load(&accel_blacklist, ZCG(accel_directives.user_blacklist_filename));
  2624. }
  2625. zend_optimizer_startup();
  2626. return SUCCESS;
  2627. }
  2628. static void accel_free_ts_resources()
  2629. {
  2630. #ifndef ZTS
  2631. accel_globals_dtor(&accel_globals);
  2632. #else
  2633. ts_free_id(accel_globals_id);
  2634. #endif
  2635. }
  2636. void accel_shutdown(void)
  2637. {
  2638. zend_ini_entry *ini_entry;
  2639. zend_bool _file_cache_only = 0;
  2640. zend_optimizer_shutdown();
  2641. zend_accel_blacklist_shutdown(&accel_blacklist);
  2642. if (!ZCG(enabled) || !accel_startup_ok) {
  2643. accel_free_ts_resources();
  2644. return;
  2645. }
  2646. #ifdef HAVE_OPCACHE_FILE_CACHE
  2647. _file_cache_only = file_cache_only;
  2648. #endif
  2649. accel_reset_pcre_cache();
  2650. accel_free_ts_resources();
  2651. if (!_file_cache_only) {
  2652. zend_shared_alloc_shutdown();
  2653. }
  2654. zend_compile_file = accelerator_orig_compile_file;
  2655. if ((ini_entry = zend_hash_str_find_ptr(EG(ini_directives), "include_path", sizeof("include_path")-1)) != NULL) {
  2656. ini_entry->on_modify = orig_include_path_on_modify;
  2657. }
  2658. }
  2659. void zend_accel_schedule_restart(zend_accel_restart_reason reason)
  2660. {
  2661. const char *zend_accel_restart_reason_text[ACCEL_RESTART_USER + 1] = {
  2662. "out of memory",
  2663. "hash overflow",
  2664. "user",
  2665. };
  2666. if (ZCSG(restart_pending)) {
  2667. /* don't schedule twice */
  2668. return;
  2669. }
  2670. zend_accel_error(ACCEL_LOG_DEBUG, "Restart Scheduled! Reason: %s",
  2671. zend_accel_restart_reason_text[reason]);
  2672. HANDLE_BLOCK_INTERRUPTIONS();
  2673. SHM_UNPROTECT();
  2674. ZCSG(restart_pending) = 1;
  2675. ZCSG(restart_reason) = reason;
  2676. ZCSG(cache_status_before_restart) = ZCSG(accelerator_enabled);
  2677. ZCSG(accelerator_enabled) = 0;
  2678. if (ZCG(accel_directives).force_restart_timeout) {
  2679. ZCSG(force_restart_time) = zend_accel_get_time() + ZCG(accel_directives).force_restart_timeout;
  2680. } else {
  2681. ZCSG(force_restart_time) = 0;
  2682. }
  2683. SHM_PROTECT();
  2684. HANDLE_UNBLOCK_INTERRUPTIONS();
  2685. }
  2686. /* this is needed because on WIN32 lock is not decreased unless ZCG(counted) is set */
  2687. #ifdef ZEND_WIN32
  2688. #define accel_deactivate_now() ZCG(counted) = 1; accel_deactivate_sub()
  2689. #else
  2690. #define accel_deactivate_now() accel_deactivate_sub()
  2691. #endif
  2692. /* ensures it is OK to read SHM
  2693. if it's not OK (restart in progress) returns FAILURE
  2694. if OK returns SUCCESS
  2695. MUST call accelerator_shm_read_unlock after done lock operations
  2696. */
  2697. int accelerator_shm_read_lock(void)
  2698. {
  2699. if (ZCG(counted)) {
  2700. /* counted means we are holding read lock for SHM, so that nothing bad can happen */
  2701. return SUCCESS;
  2702. } else {
  2703. /* here accelerator is active but we do not hold SHM lock. This means restart was scheduled
  2704. or is in progress now */
  2705. if (accel_activate_add() == FAILURE) { /* acquire usage lock */
  2706. return FAILURE;
  2707. }
  2708. /* Now if we weren't inside restart, restart would not begin until we remove usage lock */
  2709. if (ZCSG(restart_in_progress)) {
  2710. /* we already were inside restart this means it's not safe to touch shm */
  2711. accel_deactivate_now(); /* drop usage lock */
  2712. return FAILURE;
  2713. }
  2714. ZCG(counted) = 1;
  2715. }
  2716. return SUCCESS;
  2717. }
  2718. /* must be called ONLY after SUCCESSFUL accelerator_shm_read_lock */
  2719. void accelerator_shm_read_unlock(void)
  2720. {
  2721. if (!ZCG(counted)) {
  2722. /* counted is 0 - meaning we had to readlock manually, release readlock now */
  2723. accel_deactivate_now();
  2724. }
  2725. }
  2726. ZEND_EXT_API zend_extension zend_extension_entry = {
  2727. ACCELERATOR_PRODUCT_NAME, /* name */
  2728. PHP_VERSION, /* version */
  2729. "Zend Technologies", /* author */
  2730. "http://www.zend.com/", /* URL */
  2731. "Copyright (c) 1999-2018", /* copyright */
  2732. accel_startup, /* startup */
  2733. NULL, /* shutdown */
  2734. accel_activate, /* per-script activation */
  2735. accel_deactivate, /* per-script deactivation */
  2736. NULL, /* message handler */
  2737. NULL, /* op_array handler */
  2738. NULL, /* extended statement handler */
  2739. NULL, /* extended fcall begin handler */
  2740. NULL, /* extended fcall end handler */
  2741. NULL, /* op_array ctor */
  2742. NULL, /* op_array dtor */
  2743. STANDARD_ZEND_EXTENSION_PROPERTIES
  2744. };