12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835 |
- /*
- +----------------------------------------------------------------------+
- | Zend OPcache |
- +----------------------------------------------------------------------+
- | Copyright (c) The PHP Group |
- +----------------------------------------------------------------------+
- | This source file is subject to version 3.01 of the PHP license, |
- | that is bundled with this package in the file LICENSE, and is |
- | available through the world-wide-web at the following url: |
- | https://www.php.net/license/3_01.txt |
- | If you did not receive a copy of the PHP license and are unable to |
- | obtain it through the world-wide-web, please send a note to |
- | license@php.net so we can mail you a copy immediately. |
- +----------------------------------------------------------------------+
- | Authors: Andi Gutmans <andi@php.net> |
- | Zeev Suraski <zeev@php.net> |
- | Stanislav Malyshev <stas@zend.com> |
- | Dmitry Stogov <dmitry@php.net> |
- +----------------------------------------------------------------------+
- */
- #include "main/php.h"
- #include "main/php_globals.h"
- #include "zend.h"
- #include "zend_extensions.h"
- #include "zend_compile.h"
- #include "ZendAccelerator.h"
- #include "zend_persist.h"
- #include "zend_shared_alloc.h"
- #include "zend_accelerator_module.h"
- #include "zend_accelerator_blacklist.h"
- #include "zend_list.h"
- #include "zend_execute.h"
- #include "zend_vm.h"
- #include "zend_inheritance.h"
- #include "zend_exceptions.h"
- #include "main/php_main.h"
- #include "main/SAPI.h"
- #include "main/php_streams.h"
- #include "main/php_open_temporary_file.h"
- #include "zend_API.h"
- #include "zend_ini.h"
- #include "zend_virtual_cwd.h"
- #include "zend_accelerator_util_funcs.h"
- #include "zend_accelerator_hash.h"
- #include "zend_file_cache.h"
- #include "ext/pcre/php_pcre.h"
- #include "ext/standard/md5.h"
- #include "ext/hash/php_hash.h"
- #ifdef HAVE_JIT
- # include "jit/zend_jit.h"
- #endif
- #ifndef ZEND_WIN32
- #include <netdb.h>
- #endif
- #ifdef ZEND_WIN32
- typedef int uid_t;
- typedef int gid_t;
- #include <io.h>
- #include <lmcons.h>
- #endif
- #ifndef ZEND_WIN32
- # include <sys/time.h>
- #else
- # include <process.h>
- #endif
- #ifdef HAVE_UNISTD_H
- # include <unistd.h>
- #endif
- #include <fcntl.h>
- #include <signal.h>
- #include <time.h>
- #ifndef ZEND_WIN32
- # include <sys/types.h>
- # include <sys/wait.h>
- # include <sys/ipc.h>
- # include <pwd.h>
- # include <grp.h>
- #endif
- #include <sys/stat.h>
- #include <errno.h>
- #ifdef __AVX__
- #include <immintrin.h>
- #endif
- ZEND_EXTENSION();
- #ifndef ZTS
- zend_accel_globals accel_globals;
- #else
- int accel_globals_id;
- #if defined(COMPILE_DL_OPCACHE)
- ZEND_TSRMLS_CACHE_DEFINE()
- #endif
- #endif
- /* Points to the structure shared across all PHP processes */
- zend_accel_shared_globals *accel_shared_globals = NULL;
- /* true globals, no need for thread safety */
- #ifdef ZEND_WIN32
- char accel_uname_id[32];
- #endif
- bool accel_startup_ok = 0;
- static char *zps_failure_reason = NULL;
- char *zps_api_failure_reason = NULL;
- bool file_cache_only = 0; /* process uses file cache only */
- #if ENABLE_FILE_CACHE_FALLBACK
- bool fallback_process = 0; /* process uses file cache fallback */
- #endif
- static zend_op_array *(*accelerator_orig_compile_file)(zend_file_handle *file_handle, int type);
- static zend_class_entry* (*accelerator_orig_inheritance_cache_get)(zend_class_entry *ce, zend_class_entry *parent, zend_class_entry **traits_and_interfaces);
- static zend_class_entry* (*accelerator_orig_inheritance_cache_add)(zend_class_entry *ce, zend_class_entry *proto, zend_class_entry *parent, zend_class_entry **traits_and_interfaces, HashTable *dependencies);
- static zend_result (*accelerator_orig_zend_stream_open_function)(zend_file_handle *handle );
- static zend_string *(*accelerator_orig_zend_resolve_path)(zend_string *filename);
- static zif_handler orig_chdir = NULL;
- static ZEND_INI_MH((*orig_include_path_on_modify)) = NULL;
- static zend_result (*orig_post_startup_cb)(void);
- static zend_result accel_post_startup(void);
- static int accel_finish_startup(void);
- static void preload_shutdown(void);
- static void preload_activate(void);
- static void preload_restart(void);
- #ifdef ZEND_WIN32
- # define INCREMENT(v) InterlockedIncrement64(&ZCSG(v))
- # define DECREMENT(v) InterlockedDecrement64(&ZCSG(v))
- # define LOCKVAL(v) (ZCSG(v))
- #endif
- #ifdef ZEND_WIN32
- static time_t zend_accel_get_time(void)
- {
- FILETIME now;
- GetSystemTimeAsFileTime(&now);
- return (time_t) ((((((__int64)now.dwHighDateTime) << 32)|now.dwLowDateTime) - 116444736000000000L)/10000000);
- }
- #else
- # define zend_accel_get_time() time(NULL)
- #endif
- static inline int is_stream_path(const char *filename)
- {
- const char *p;
- for (p = filename;
- (*p >= 'a' && *p <= 'z') ||
- (*p >= 'A' && *p <= 'Z') ||
- (*p >= '0' && *p <= '9') ||
- *p == '+' || *p == '-' || *p == '.';
- p++);
- return ((p != filename) && (p[0] == ':') && (p[1] == '/') && (p[2] == '/'));
- }
- static inline int is_cacheable_stream_path(const char *filename)
- {
- return memcmp(filename, "file://", sizeof("file://") - 1) == 0 ||
- memcmp(filename, "phar://", sizeof("phar://") - 1) == 0;
- }
- /* O+ overrides PHP chdir() function and remembers the current working directory
- * in ZCG(cwd) and ZCG(cwd_len). Later accel_getcwd() can use stored value and
- * avoid getcwd() call.
- */
- static ZEND_FUNCTION(accel_chdir)
- {
- char cwd[MAXPATHLEN];
- orig_chdir(INTERNAL_FUNCTION_PARAM_PASSTHRU);
- if (VCWD_GETCWD(cwd, MAXPATHLEN)) {
- if (ZCG(cwd)) {
- zend_string_release_ex(ZCG(cwd), 0);
- }
- ZCG(cwd) = zend_string_init(cwd, strlen(cwd), 0);
- } else {
- if (ZCG(cwd)) {
- zend_string_release_ex(ZCG(cwd), 0);
- ZCG(cwd) = NULL;
- }
- }
- ZCG(cwd_key_len) = 0;
- ZCG(cwd_check) = 1;
- }
- static inline zend_string* accel_getcwd(void)
- {
- if (ZCG(cwd)) {
- return ZCG(cwd);
- } else {
- char cwd[MAXPATHLEN + 1];
- if (!VCWD_GETCWD(cwd, MAXPATHLEN)) {
- return NULL;
- }
- ZCG(cwd) = zend_string_init(cwd, strlen(cwd), 0);
- ZCG(cwd_key_len) = 0;
- ZCG(cwd_check) = 1;
- return ZCG(cwd);
- }
- }
- void zend_accel_schedule_restart_if_necessary(zend_accel_restart_reason reason)
- {
- if ((((double) ZSMMG(wasted_shared_memory)) / ZCG(accel_directives).memory_consumption) >= ZCG(accel_directives).max_wasted_percentage) {
- zend_accel_schedule_restart(reason);
- }
- }
- /* O+ tracks changes of "include_path" directive. It stores all the requested
- * values in ZCG(include_paths) shared hash table, current value in
- * ZCG(include_path)/ZCG(include_path_len) and one letter "path key" in
- * ZCG(include_path_key).
- */
- static ZEND_INI_MH(accel_include_path_on_modify)
- {
- int ret = orig_include_path_on_modify(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
- if (ret == SUCCESS) {
- ZCG(include_path) = new_value;
- ZCG(include_path_key_len) = 0;
- ZCG(include_path_check) = 1;
- }
- return ret;
- }
- static inline void accel_restart_enter(void)
- {
- #ifdef ZEND_WIN32
- INCREMENT(restart_in);
- #else
- struct flock restart_in_progress;
- restart_in_progress.l_type = F_WRLCK;
- restart_in_progress.l_whence = SEEK_SET;
- restart_in_progress.l_start = 2;
- restart_in_progress.l_len = 1;
- if (fcntl(lock_file, F_SETLK, &restart_in_progress) == -1) {
- zend_accel_error(ACCEL_LOG_DEBUG, "RestartC(+1): %s (%d)", strerror(errno), errno);
- }
- #endif
- ZCSG(restart_in_progress) = 1;
- }
- static inline void accel_restart_leave(void)
- {
- #ifdef ZEND_WIN32
- ZCSG(restart_in_progress) = 0;
- DECREMENT(restart_in);
- #else
- struct flock restart_finished;
- restart_finished.l_type = F_UNLCK;
- restart_finished.l_whence = SEEK_SET;
- restart_finished.l_start = 2;
- restart_finished.l_len = 1;
- ZCSG(restart_in_progress) = 0;
- if (fcntl(lock_file, F_SETLK, &restart_finished) == -1) {
- zend_accel_error(ACCEL_LOG_DEBUG, "RestartC(-1): %s (%d)", strerror(errno), errno);
- }
- #endif
- }
- static inline int accel_restart_is_active(void)
- {
- if (ZCSG(restart_in_progress)) {
- #ifndef ZEND_WIN32
- struct flock restart_check;
- restart_check.l_type = F_WRLCK;
- restart_check.l_whence = SEEK_SET;
- restart_check.l_start = 2;
- restart_check.l_len = 1;
- if (fcntl(lock_file, F_GETLK, &restart_check) == -1) {
- zend_accel_error(ACCEL_LOG_DEBUG, "RestartC: %s (%d)", strerror(errno), errno);
- return FAILURE;
- }
- if (restart_check.l_type == F_UNLCK) {
- ZCSG(restart_in_progress) = 0;
- return 0;
- } else {
- return 1;
- }
- #else
- return LOCKVAL(restart_in) != 0;
- #endif
- }
- return 0;
- }
- /* Creates a read lock for SHM access */
- static inline zend_result accel_activate_add(void)
- {
- #ifdef ZEND_WIN32
- SHM_UNPROTECT();
- INCREMENT(mem_usage);
- SHM_PROTECT();
- #else
- struct flock mem_usage_lock;
- mem_usage_lock.l_type = F_RDLCK;
- mem_usage_lock.l_whence = SEEK_SET;
- mem_usage_lock.l_start = 1;
- mem_usage_lock.l_len = 1;
- if (fcntl(lock_file, F_SETLK, &mem_usage_lock) == -1) {
- zend_accel_error(ACCEL_LOG_DEBUG, "UpdateC(+1): %s (%d)", strerror(errno), errno);
- return FAILURE;
- }
- #endif
- return SUCCESS;
- }
- /* Releases a lock for SHM access */
- static inline void accel_deactivate_sub(void)
- {
- #ifdef ZEND_WIN32
- if (ZCG(counted)) {
- SHM_UNPROTECT();
- DECREMENT(mem_usage);
- ZCG(counted) = 0;
- SHM_PROTECT();
- }
- #else
- struct flock mem_usage_unlock;
- mem_usage_unlock.l_type = F_UNLCK;
- mem_usage_unlock.l_whence = SEEK_SET;
- mem_usage_unlock.l_start = 1;
- mem_usage_unlock.l_len = 1;
- if (fcntl(lock_file, F_SETLK, &mem_usage_unlock) == -1) {
- zend_accel_error(ACCEL_LOG_DEBUG, "UpdateC(-1): %s (%d)", strerror(errno), errno);
- }
- #endif
- }
- static inline void accel_unlock_all(void)
- {
- #ifdef ZEND_WIN32
- accel_deactivate_sub();
- #else
- struct flock mem_usage_unlock_all;
- mem_usage_unlock_all.l_type = F_UNLCK;
- mem_usage_unlock_all.l_whence = SEEK_SET;
- mem_usage_unlock_all.l_start = 0;
- mem_usage_unlock_all.l_len = 0;
- if (fcntl(lock_file, F_SETLK, &mem_usage_unlock_all) == -1) {
- zend_accel_error(ACCEL_LOG_DEBUG, "UnlockAll: %s (%d)", strerror(errno), errno);
- }
- #endif
- }
- /* Interned strings support */
- /* O+ disables creation of interned strings by regular PHP compiler, instead,
- * it creates interned strings in shared memory when saves a script.
- * Such interned strings are shared across all PHP processes
- */
- #define STRTAB_INVALID_POS 0
- #define STRTAB_HASH_TO_SLOT(tab, h) \
- ((uint32_t*)((char*)(tab) + sizeof(*(tab)) + ((h) & (tab)->nTableMask)))
- #define STRTAB_STR_TO_POS(tab, s) \
- ((uint32_t)((char*)s - (char*)(tab)))
- #define STRTAB_POS_TO_STR(tab, pos) \
- ((zend_string*)((char*)(tab) + (pos)))
- #define STRTAB_COLLISION(s) \
- (*((uint32_t*)((char*)s - sizeof(uint32_t))))
- #define STRTAB_STR_SIZE(s) \
- ZEND_MM_ALIGNED_SIZE_EX(_ZSTR_HEADER_SIZE + ZSTR_LEN(s) + 5, 8)
- #define STRTAB_NEXT(s) \
- ((zend_string*)((char*)(s) + STRTAB_STR_SIZE(s)))
- static void accel_interned_strings_restore_state(void)
- {
- zend_string *s, *top;
- uint32_t *hash_slot, n;
- /* clear removed content */
- memset(ZCSG(interned_strings).saved_top,
- 0, (char*)ZCSG(interned_strings).top - (char*)ZCSG(interned_strings).saved_top);
- /* Reset "top" */
- ZCSG(interned_strings).top = ZCSG(interned_strings).saved_top;
- /* rehash */
- memset((char*)&ZCSG(interned_strings) + sizeof(zend_string_table),
- STRTAB_INVALID_POS,
- (char*)ZCSG(interned_strings).start -
- ((char*)&ZCSG(interned_strings) + sizeof(zend_string_table)));
- s = ZCSG(interned_strings).start;
- top = ZCSG(interned_strings).top;
- n = 0;
- if (EXPECTED(s < top)) {
- do {
- if (ZSTR_HAS_CE_CACHE(s)) {
- /* Discard non-global CE_CACHE slots on reset. */
- uintptr_t idx = (GC_REFCOUNT(s) - 1) / sizeof(void *);
- if (idx >= ZCSG(map_ptr_last)) {
- GC_SET_REFCOUNT(s, 2);
- GC_DEL_FLAGS(s, IS_STR_CLASS_NAME_MAP_PTR);
- }
- }
- hash_slot = STRTAB_HASH_TO_SLOT(&ZCSG(interned_strings), ZSTR_H(s));
- STRTAB_COLLISION(s) = *hash_slot;
- *hash_slot = STRTAB_STR_TO_POS(&ZCSG(interned_strings), s);
- s = STRTAB_NEXT(s);
- n++;
- } while (s < top);
- }
- ZCSG(interned_strings).nNumOfElements = n;
- }
- static void accel_interned_strings_save_state(void)
- {
- ZCSG(interned_strings).saved_top = ZCSG(interned_strings).top;
- }
- static zend_always_inline zend_string *accel_find_interned_string(zend_string *str)
- {
- zend_ulong h;
- uint32_t pos;
- zend_string *s;
- if (IS_ACCEL_INTERNED(str)) {
- /* this is already an interned string */
- return str;
- }
- if (!ZCG(counted)) {
- if (!ZCG(accelerator_enabled) || accel_activate_add() == FAILURE) {
- return NULL;
- }
- ZCG(counted) = 1;
- }
- h = zend_string_hash_val(str);
- /* check for existing interned string */
- pos = *STRTAB_HASH_TO_SLOT(&ZCSG(interned_strings), h);
- if (EXPECTED(pos != STRTAB_INVALID_POS)) {
- do {
- s = STRTAB_POS_TO_STR(&ZCSG(interned_strings), pos);
- if (EXPECTED(ZSTR_H(s) == h) && zend_string_equal_content(s, str)) {
- return s;
- }
- pos = STRTAB_COLLISION(s);
- } while (pos != STRTAB_INVALID_POS);
- }
- return NULL;
- }
- zend_string* ZEND_FASTCALL accel_new_interned_string(zend_string *str)
- {
- zend_ulong h;
- uint32_t pos, *hash_slot;
- zend_string *s;
- if (UNEXPECTED(file_cache_only)) {
- return str;
- }
- if (IS_ACCEL_INTERNED(str)) {
- /* this is already an interned string */
- return str;
- }
- h = zend_string_hash_val(str);
- /* check for existing interned string */
- hash_slot = STRTAB_HASH_TO_SLOT(&ZCSG(interned_strings), h);
- pos = *hash_slot;
- if (EXPECTED(pos != STRTAB_INVALID_POS)) {
- do {
- s = STRTAB_POS_TO_STR(&ZCSG(interned_strings), pos);
- if (EXPECTED(ZSTR_H(s) == h) && zend_string_equal_content(s, str)) {
- goto finish;
- }
- pos = STRTAB_COLLISION(s);
- } while (pos != STRTAB_INVALID_POS);
- }
- if (UNEXPECTED((char*)ZCSG(interned_strings).end - (char*)ZCSG(interned_strings).top < STRTAB_STR_SIZE(str))) {
- /* no memory, return the same non-interned string */
- zend_accel_error(ACCEL_LOG_WARNING, "Interned string buffer overflow");
- return str;
- }
- /* create new interning string in shared interned strings buffer */
- ZCSG(interned_strings).nNumOfElements++;
- s = ZCSG(interned_strings).top;
- hash_slot = STRTAB_HASH_TO_SLOT(&ZCSG(interned_strings), h);
- STRTAB_COLLISION(s) = *hash_slot;
- *hash_slot = STRTAB_STR_TO_POS(&ZCSG(interned_strings), s);
- GC_SET_REFCOUNT(s, 2);
- GC_TYPE_INFO(s) = GC_STRING | ((IS_STR_INTERNED | IS_STR_PERMANENT) << GC_FLAGS_SHIFT);
- ZSTR_H(s) = h;
- ZSTR_LEN(s) = ZSTR_LEN(str);
- memcpy(ZSTR_VAL(s), ZSTR_VAL(str), ZSTR_LEN(s) + 1);
- ZCSG(interned_strings).top = STRTAB_NEXT(s);
- finish:
- /* Transfer CE_CACHE map ptr slot to new interned string.
- * Should only happen for permanent interned strings with permanent map_ptr slot. */
- if (ZSTR_HAS_CE_CACHE(str) && !ZSTR_HAS_CE_CACHE(s)) {
- ZEND_ASSERT(GC_FLAGS(str) & IS_STR_PERMANENT);
- GC_SET_REFCOUNT(s, GC_REFCOUNT(str));
- GC_ADD_FLAGS(s, IS_STR_CLASS_NAME_MAP_PTR);
- }
- zend_string_release(str);
- return s;
- }
- static zend_string* ZEND_FASTCALL accel_new_interned_string_for_php(zend_string *str)
- {
- zend_string_hash_val(str);
- if (ZCG(counted)) {
- zend_string *ret = accel_find_interned_string(str);
- if (ret) {
- zend_string_release(str);
- return ret;
- }
- }
- return str;
- }
- static zend_always_inline zend_string *accel_find_interned_string_ex(zend_ulong h, const char *str, size_t size)
- {
- uint32_t pos;
- zend_string *s;
- /* check for existing interned string */
- pos = *STRTAB_HASH_TO_SLOT(&ZCSG(interned_strings), h);
- if (EXPECTED(pos != STRTAB_INVALID_POS)) {
- do {
- s = STRTAB_POS_TO_STR(&ZCSG(interned_strings), pos);
- if (EXPECTED(ZSTR_H(s) == h) && EXPECTED(ZSTR_LEN(s) == size)) {
- if (!memcmp(ZSTR_VAL(s), str, size)) {
- return s;
- }
- }
- pos = STRTAB_COLLISION(s);
- } while (pos != STRTAB_INVALID_POS);
- }
- return NULL;
- }
- static zend_string* ZEND_FASTCALL accel_init_interned_string_for_php(const char *str, size_t size, bool permanent)
- {
- if (ZCG(counted)) {
- zend_ulong h = zend_inline_hash_func(str, size);
- zend_string *ret = accel_find_interned_string_ex(h, str, size);
- if (!ret) {
- ret = zend_string_init(str, size, permanent);
- ZSTR_H(ret) = h;
- }
- return ret;
- }
- return zend_string_init(str, size, permanent);
- }
- /* Copy PHP interned strings from PHP process memory into the shared memory */
- static void accel_copy_permanent_strings(zend_new_interned_string_func_t new_interned_string)
- {
- uint32_t j;
- Bucket *p, *q;
- HashTable *ht;
- /* empty string */
- zend_empty_string = new_interned_string(zend_empty_string);
- for (j = 0; j < 256; j++) {
- zend_one_char_string[j] = new_interned_string(ZSTR_CHAR(j));
- }
- for (j = 0; j < ZEND_STR_LAST_KNOWN; j++) {
- zend_known_strings[j] = new_interned_string(zend_known_strings[j]);
- }
- /* function table hash keys */
- ZEND_HASH_FOREACH_BUCKET(CG(function_table), p) {
- if (p->key) {
- p->key = new_interned_string(p->key);
- }
- if (Z_FUNC(p->val)->common.function_name) {
- Z_FUNC(p->val)->common.function_name = new_interned_string(Z_FUNC(p->val)->common.function_name);
- }
- if (Z_FUNC(p->val)->common.arg_info &&
- (Z_FUNC(p->val)->common.fn_flags & (ZEND_ACC_HAS_RETURN_TYPE|ZEND_ACC_HAS_TYPE_HINTS))) {
- uint32_t i;
- uint32_t num_args = Z_FUNC(p->val)->common.num_args + 1;
- zend_arg_info *arg_info = Z_FUNC(p->val)->common.arg_info - 1;
- if (Z_FUNC(p->val)->common.fn_flags & ZEND_ACC_VARIADIC) {
- num_args++;
- }
- for (i = 0 ; i < num_args; i++) {
- zend_type *single_type;
- ZEND_TYPE_FOREACH(arg_info[i].type, single_type) {
- if (ZEND_TYPE_HAS_NAME(*single_type)) {
- ZEND_TYPE_SET_PTR(*single_type,
- new_interned_string(ZEND_TYPE_NAME(*single_type)));
- }
- } ZEND_TYPE_FOREACH_END();
- }
- }
- } ZEND_HASH_FOREACH_END();
- /* class table hash keys, class names, properties, methods, constants, etc */
- ZEND_HASH_FOREACH_BUCKET(CG(class_table), p) {
- zend_class_entry *ce;
- ce = (zend_class_entry*)Z_PTR(p->val);
- if (p->key) {
- p->key = new_interned_string(p->key);
- }
- if (ce->name) {
- ce->name = new_interned_string(ce->name);
- ZEND_ASSERT(ZSTR_HAS_CE_CACHE(ce->name));
- }
- ZEND_HASH_FOREACH_BUCKET(&ce->properties_info, q) {
- zend_property_info *info;
- info = (zend_property_info*)Z_PTR(q->val);
- if (q->key) {
- q->key = new_interned_string(q->key);
- }
- if (info->name) {
- info->name = new_interned_string(info->name);
- }
- } ZEND_HASH_FOREACH_END();
- ZEND_HASH_FOREACH_BUCKET(&ce->function_table, q) {
- if (q->key) {
- q->key = new_interned_string(q->key);
- }
- if (Z_FUNC(q->val)->common.function_name) {
- Z_FUNC(q->val)->common.function_name = new_interned_string(Z_FUNC(q->val)->common.function_name);
- }
- } ZEND_HASH_FOREACH_END();
- ZEND_HASH_FOREACH_BUCKET(&ce->constants_table, q) {
- zend_class_constant* c;
- if (q->key) {
- q->key = new_interned_string(q->key);
- }
- c = (zend_class_constant*)Z_PTR(q->val);
- if (Z_TYPE(c->value) == IS_STRING) {
- ZVAL_STR(&c->value, new_interned_string(Z_STR(c->value)));
- }
- } ZEND_HASH_FOREACH_END();
- } ZEND_HASH_FOREACH_END();
- /* constant hash keys */
- ZEND_HASH_FOREACH_BUCKET(EG(zend_constants), p) {
- zend_constant *c;
- if (p->key) {
- p->key = new_interned_string(p->key);
- }
- c = (zend_constant*)Z_PTR(p->val);
- if (c->name) {
- c->name = new_interned_string(c->name);
- }
- if (Z_TYPE(c->value) == IS_STRING) {
- ZVAL_STR(&c->value, new_interned_string(Z_STR(c->value)));
- }
- } ZEND_HASH_FOREACH_END();
- /* auto globals hash keys and names */
- ZEND_HASH_FOREACH_BUCKET(CG(auto_globals), p) {
- zend_auto_global *auto_global;
- auto_global = (zend_auto_global*)Z_PTR(p->val);
- zend_string_addref(auto_global->name);
- auto_global->name = new_interned_string(auto_global->name);
- if (p->key) {
- p->key = new_interned_string(p->key);
- }
- } ZEND_HASH_FOREACH_END();
- ZEND_HASH_FOREACH_BUCKET(&module_registry, p) {
- if (p->key) {
- p->key = new_interned_string(p->key);
- }
- } ZEND_HASH_FOREACH_END();
- ZEND_HASH_FOREACH_BUCKET(EG(ini_directives), p) {
- zend_ini_entry *entry = (zend_ini_entry*)Z_PTR(p->val);
- if (p->key) {
- p->key = new_interned_string(p->key);
- }
- if (entry->name) {
- entry->name = new_interned_string(entry->name);
- }
- if (entry->value) {
- entry->value = new_interned_string(entry->value);
- }
- if (entry->orig_value) {
- entry->orig_value = new_interned_string(entry->orig_value);
- }
- } ZEND_HASH_FOREACH_END();
- ht = php_get_stream_filters_hash_global();
- ZEND_HASH_FOREACH_BUCKET(ht, p) {
- if (p->key) {
- p->key = new_interned_string(p->key);
- }
- } ZEND_HASH_FOREACH_END();
- ht = php_stream_get_url_stream_wrappers_hash_global();
- ZEND_HASH_FOREACH_BUCKET(ht, p) {
- if (p->key) {
- p->key = new_interned_string(p->key);
- }
- } ZEND_HASH_FOREACH_END();
- ht = php_stream_xport_get_hash();
- ZEND_HASH_FOREACH_BUCKET(ht, p) {
- if (p->key) {
- p->key = new_interned_string(p->key);
- }
- } ZEND_HASH_FOREACH_END();
- }
- static zend_string* ZEND_FASTCALL accel_replace_string_by_shm_permanent(zend_string *str)
- {
- zend_string *ret = accel_find_interned_string(str);
- if (ret) {
- zend_string_release(str);
- return ret;
- }
- return str;
- }
- static void accel_use_shm_interned_strings(void)
- {
- HANDLE_BLOCK_INTERRUPTIONS();
- SHM_UNPROTECT();
- zend_shared_alloc_lock();
- if (ZCSG(interned_strings).saved_top == NULL) {
- accel_copy_permanent_strings(accel_new_interned_string);
- } else {
- ZCG(counted) = 1;
- accel_copy_permanent_strings(accel_replace_string_by_shm_permanent);
- ZCG(counted) = 0;
- }
- accel_interned_strings_save_state();
- zend_shared_alloc_unlock();
- SHM_PROTECT();
- HANDLE_UNBLOCK_INTERRUPTIONS();
- }
- #ifndef ZEND_WIN32
- static inline void kill_all_lockers(struct flock *mem_usage_check)
- {
- int success, tries;
- /* so that other process won't try to force while we are busy cleaning up */
- ZCSG(force_restart_time) = 0;
- while (mem_usage_check->l_pid > 0) {
- /* Try SIGTERM first, switch to SIGKILL if not successful. */
- int signal = SIGTERM;
- errno = 0;
- success = 0;
- tries = 10;
- while (tries--) {
- zend_accel_error(ACCEL_LOG_WARNING, "Attempting to kill locker %d", mem_usage_check->l_pid);
- if (kill(mem_usage_check->l_pid, signal)) {
- if (errno == ESRCH) {
- /* Process died before the signal was sent */
- success = 1;
- zend_accel_error(ACCEL_LOG_WARNING, "Process %d died before SIGKILL was sent", mem_usage_check->l_pid);
- } else if (errno != 0) {
- zend_accel_error(ACCEL_LOG_WARNING, "Failed to send SIGKILL to locker %d: %s", mem_usage_check->l_pid, strerror(errno));
- }
- break;
- }
- /* give it a chance to die */
- usleep(20000);
- if (kill(mem_usage_check->l_pid, 0)) {
- if (errno == ESRCH) {
- /* successfully killed locker, process no longer exists */
- success = 1;
- zend_accel_error(ACCEL_LOG_WARNING, "Killed locker %d", mem_usage_check->l_pid);
- } else if (errno != 0) {
- zend_accel_error(ACCEL_LOG_WARNING, "Failed to check locker %d: %s", mem_usage_check->l_pid, strerror(errno));
- }
- break;
- }
- usleep(10000);
- /* If SIGTERM was not sufficient, use SIGKILL. */
- signal = SIGKILL;
- }
- if (!success) {
- /* errno is not ESRCH or we ran out of tries to kill the locker */
- ZCSG(force_restart_time) = time(NULL); /* restore forced restart request */
- /* cannot kill the locker, bail out with error */
- zend_accel_error_noreturn(ACCEL_LOG_ERROR, "Cannot kill process %d!", mem_usage_check->l_pid);
- }
- mem_usage_check->l_type = F_WRLCK;
- mem_usage_check->l_whence = SEEK_SET;
- mem_usage_check->l_start = 1;
- mem_usage_check->l_len = 1;
- mem_usage_check->l_pid = -1;
- if (fcntl(lock_file, F_GETLK, mem_usage_check) == -1) {
- zend_accel_error(ACCEL_LOG_DEBUG, "KLockers: %s (%d)", strerror(errno), errno);
- break;
- }
- if (mem_usage_check->l_type == F_UNLCK || mem_usage_check->l_pid <= 0) {
- break;
- }
- }
- }
- #endif
- static inline int accel_is_inactive(void)
- {
- #ifdef ZEND_WIN32
- if (LOCKVAL(mem_usage) == 0) {
- return SUCCESS;
- }
- #else
- struct flock mem_usage_check;
- mem_usage_check.l_type = F_WRLCK;
- mem_usage_check.l_whence = SEEK_SET;
- mem_usage_check.l_start = 1;
- mem_usage_check.l_len = 1;
- mem_usage_check.l_pid = -1;
- if (fcntl(lock_file, F_GETLK, &mem_usage_check) == -1) {
- zend_accel_error(ACCEL_LOG_DEBUG, "UpdateC: %s (%d)", strerror(errno), errno);
- return FAILURE;
- }
- if (mem_usage_check.l_type == F_UNLCK) {
- return SUCCESS;
- }
- if (ZCG(accel_directives).force_restart_timeout
- && ZCSG(force_restart_time)
- && time(NULL) >= ZCSG(force_restart_time)) {
- 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);
- kill_all_lockers(&mem_usage_check);
- return FAILURE; /* next request should be able to restart it */
- }
- #endif
- return FAILURE;
- }
- static int zend_get_stream_timestamp(const char *filename, zend_stat_t *statbuf)
- {
- php_stream_wrapper *wrapper;
- php_stream_statbuf stream_statbuf;
- int ret, er;
- if (!filename) {
- return FAILURE;
- }
- wrapper = php_stream_locate_url_wrapper(filename, NULL, STREAM_LOCATE_WRAPPERS_ONLY);
- if (!wrapper) {
- return FAILURE;
- }
- if (!wrapper->wops || !wrapper->wops->url_stat) {
- statbuf->st_mtime = 1;
- return SUCCESS; /* anything other than 0 is considered to be a valid timestamp */
- }
- er = EG(error_reporting);
- EG(error_reporting) = 0;
- zend_try {
- ret = wrapper->wops->url_stat(wrapper, (char*)filename, PHP_STREAM_URL_STAT_QUIET, &stream_statbuf, NULL);
- } zend_catch {
- ret = -1;
- } zend_end_try();
- EG(error_reporting) = er;
- if (ret != 0) {
- return FAILURE;
- }
- *statbuf = stream_statbuf.sb;
- return SUCCESS;
- }
- #if ZEND_WIN32
- static accel_time_t zend_get_file_handle_timestamp_win(zend_file_handle *file_handle, size_t *size)
- {
- static unsigned __int64 utc_base = 0;
- static FILETIME utc_base_ft;
- WIN32_FILE_ATTRIBUTE_DATA fdata;
- if (!file_handle->opened_path) {
- return 0;
- }
- if (!utc_base) {
- SYSTEMTIME st;
- st.wYear = 1970;
- st.wMonth = 1;
- st.wDay = 1;
- st.wHour = 0;
- st.wMinute = 0;
- st.wSecond = 0;
- st.wMilliseconds = 0;
- SystemTimeToFileTime (&st, &utc_base_ft);
- utc_base = (((unsigned __int64)utc_base_ft.dwHighDateTime) << 32) + utc_base_ft.dwLowDateTime;
- }
- if (file_handle->opened_path && GetFileAttributesEx(file_handle->opened_path->val, GetFileExInfoStandard, &fdata) != 0) {
- unsigned __int64 ftime;
- if (CompareFileTime (&fdata.ftLastWriteTime, &utc_base_ft) < 0) {
- return 0;
- }
- ftime = (((unsigned __int64)fdata.ftLastWriteTime.dwHighDateTime) << 32) + fdata.ftLastWriteTime.dwLowDateTime - utc_base;
- ftime /= 10000000L;
- if (size) {
- *size = (size_t)((((unsigned __int64)fdata.nFileSizeHigh) << 32) + (unsigned __int64)fdata.nFileSizeLow);
- }
- return (accel_time_t)ftime;
- }
- return 0;
- }
- #endif
- accel_time_t zend_get_file_handle_timestamp(zend_file_handle *file_handle, size_t *size)
- {
- zend_stat_t statbuf;
- #ifdef ZEND_WIN32
- accel_time_t res;
- #endif
- if (sapi_module.get_stat &&
- !EG(current_execute_data) &&
- file_handle->primary_script) {
- zend_stat_t *tmpbuf = sapi_module.get_stat();
- if (tmpbuf) {
- if (size) {
- *size = tmpbuf->st_size;
- }
- return tmpbuf->st_mtime;
- }
- }
- #ifdef ZEND_WIN32
- res = zend_get_file_handle_timestamp_win(file_handle, size);
- if (res) {
- return res;
- }
- #endif
- switch (file_handle->type) {
- case ZEND_HANDLE_FP:
- if (zend_fstat(fileno(file_handle->handle.fp), &statbuf) == -1) {
- if (zend_get_stream_timestamp(ZSTR_VAL(file_handle->filename), &statbuf) != SUCCESS) {
- return 0;
- }
- }
- break;
- case ZEND_HANDLE_FILENAME:
- if (file_handle->opened_path) {
- char *file_path = ZSTR_VAL(file_handle->opened_path);
- if (is_stream_path(file_path)) {
- if (zend_get_stream_timestamp(file_path, &statbuf) == SUCCESS) {
- break;
- }
- }
- if (VCWD_STAT(file_path, &statbuf) != -1) {
- break;
- }
- }
- if (zend_get_stream_timestamp(ZSTR_VAL(file_handle->filename), &statbuf) != SUCCESS) {
- return 0;
- }
- break;
- case ZEND_HANDLE_STREAM:
- {
- php_stream *stream = (php_stream *)file_handle->handle.stream.handle;
- php_stream_statbuf sb;
- int ret, er;
- if (!stream ||
- !stream->ops ||
- !stream->ops->stat) {
- return 0;
- }
- er = EG(error_reporting);
- EG(error_reporting) = 0;
- zend_try {
- ret = stream->ops->stat(stream, &sb);
- } zend_catch {
- ret = -1;
- } zend_end_try();
- EG(error_reporting) = er;
- if (ret != 0) {
- return 0;
- }
- statbuf = sb.sb;
- }
- break;
- default:
- return 0;
- }
- if (size) {
- *size = statbuf.st_size;
- }
- return statbuf.st_mtime;
- }
- static inline int do_validate_timestamps(zend_persistent_script *persistent_script, zend_file_handle *file_handle)
- {
- zend_file_handle ps_handle;
- zend_string *full_path_ptr = NULL;
- int ret;
- /** check that the persistent script is indeed the same file we cached
- * (if part of the path is a symlink than it possible that the user will change it)
- * See bug #15140
- */
- if (file_handle->opened_path) {
- if (persistent_script->script.filename != file_handle->opened_path &&
- !zend_string_equal_content(persistent_script->script.filename, file_handle->opened_path)) {
- return FAILURE;
- }
- } else {
- full_path_ptr = accelerator_orig_zend_resolve_path(file_handle->filename);
- if (full_path_ptr &&
- persistent_script->script.filename != full_path_ptr &&
- !zend_string_equal_content(persistent_script->script.filename, full_path_ptr)) {
- zend_string_release_ex(full_path_ptr, 0);
- return FAILURE;
- }
- file_handle->opened_path = full_path_ptr;
- }
- if (persistent_script->timestamp == 0) {
- if (full_path_ptr) {
- zend_string_release_ex(full_path_ptr, 0);
- file_handle->opened_path = NULL;
- }
- return FAILURE;
- }
- if (zend_get_file_handle_timestamp(file_handle, NULL) == persistent_script->timestamp) {
- if (full_path_ptr) {
- zend_string_release_ex(full_path_ptr, 0);
- file_handle->opened_path = NULL;
- }
- return SUCCESS;
- }
- if (full_path_ptr) {
- zend_string_release_ex(full_path_ptr, 0);
- file_handle->opened_path = NULL;
- }
- zend_stream_init_filename_ex(&ps_handle, persistent_script->script.filename);
- ps_handle.opened_path = persistent_script->script.filename;
- ret = zend_get_file_handle_timestamp(&ps_handle, NULL) == persistent_script->timestamp
- ? SUCCESS : FAILURE;
- zend_destroy_file_handle(&ps_handle);
- return ret;
- }
- int validate_timestamp_and_record(zend_persistent_script *persistent_script, zend_file_handle *file_handle)
- {
- if (persistent_script->timestamp == 0) {
- return SUCCESS; /* Don't check timestamps of preloaded scripts */
- } else if (ZCG(accel_directives).revalidate_freq &&
- persistent_script->dynamic_members.revalidate >= ZCG(request_time)) {
- return SUCCESS;
- } else if (do_validate_timestamps(persistent_script, file_handle) == FAILURE) {
- return FAILURE;
- } else {
- persistent_script->dynamic_members.revalidate = ZCG(request_time) + ZCG(accel_directives).revalidate_freq;
- return SUCCESS;
- }
- }
- int validate_timestamp_and_record_ex(zend_persistent_script *persistent_script, zend_file_handle *file_handle)
- {
- int ret;
- SHM_UNPROTECT();
- ret = validate_timestamp_and_record(persistent_script, file_handle);
- SHM_PROTECT();
- return ret;
- }
- /* Instead of resolving full real path name each time we need to identify file,
- * we create a key that consist from requested file name, current working
- * directory, current include_path, etc */
- zend_string *accel_make_persistent_key(zend_string *str)
- {
- const char *path = ZSTR_VAL(str);
- size_t path_length = ZSTR_LEN(str);
- char *key;
- int key_length;
- ZSTR_LEN(&ZCG(key)) = 0;
- /* CWD and include_path don't matter for absolute file names and streams */
- if (IS_ABSOLUTE_PATH(path, path_length)) {
- /* pass */
- } else if (UNEXPECTED(is_stream_path(path))) {
- if (!is_cacheable_stream_path(path)) {
- return NULL;
- }
- /* pass */
- } else if (UNEXPECTED(!ZCG(accel_directives).use_cwd)) {
- /* pass */
- } else {
- const char *include_path = NULL, *cwd = NULL;
- int include_path_len = 0, cwd_len = 0;
- zend_string *parent_script = NULL;
- size_t parent_script_len = 0;
- if (EXPECTED(ZCG(cwd_key_len))) {
- cwd = ZCG(cwd_key);
- cwd_len = ZCG(cwd_key_len);
- } else {
- zend_string *cwd_str = accel_getcwd();
- if (UNEXPECTED(!cwd_str)) {
- /* we don't handle this well for now. */
- 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);
- return NULL;
- }
- cwd = ZSTR_VAL(cwd_str);
- cwd_len = ZSTR_LEN(cwd_str);
- if (ZCG(cwd_check)) {
- ZCG(cwd_check) = 0;
- if (ZCG(accelerator_enabled)) {
- zend_string *str = accel_find_interned_string(cwd_str);
- if (!str) {
- HANDLE_BLOCK_INTERRUPTIONS();
- SHM_UNPROTECT();
- zend_shared_alloc_lock();
- str = accel_new_interned_string(zend_string_copy(cwd_str));
- if (str == cwd_str) {
- zend_string_release_ex(str, 0);
- str = NULL;
- }
- zend_shared_alloc_unlock();
- SHM_PROTECT();
- HANDLE_UNBLOCK_INTERRUPTIONS();
- }
- if (str) {
- char buf[32];
- char *res = zend_print_long_to_buf(buf + sizeof(buf) - 1, STRTAB_STR_TO_POS(&ZCSG(interned_strings), str));
- cwd_len = ZCG(cwd_key_len) = buf + sizeof(buf) - 1 - res;
- cwd = ZCG(cwd_key);
- memcpy(ZCG(cwd_key), res, cwd_len + 1);
- } else {
- return NULL;
- }
- } else {
- return NULL;
- }
- }
- }
- if (EXPECTED(ZCG(include_path_key_len))) {
- include_path = ZCG(include_path_key);
- include_path_len = ZCG(include_path_key_len);
- } else if (!ZCG(include_path) || ZSTR_LEN(ZCG(include_path)) == 0) {
- include_path = "";
- include_path_len = 0;
- } else {
- include_path = ZSTR_VAL(ZCG(include_path));
- include_path_len = ZSTR_LEN(ZCG(include_path));
- if (ZCG(include_path_check)) {
- ZCG(include_path_check) = 0;
- if (ZCG(accelerator_enabled)) {
- zend_string *str = accel_find_interned_string(ZCG(include_path));
- if (!str) {
- HANDLE_BLOCK_INTERRUPTIONS();
- SHM_UNPROTECT();
- zend_shared_alloc_lock();
- str = accel_new_interned_string(zend_string_copy(ZCG(include_path)));
- if (str == ZCG(include_path)) {
- zend_string_release(str);
- str = NULL;
- }
- zend_shared_alloc_unlock();
- SHM_PROTECT();
- HANDLE_UNBLOCK_INTERRUPTIONS();
- }
- if (str) {
- char buf[32];
- char *res = zend_print_long_to_buf(buf + sizeof(buf) - 1, STRTAB_STR_TO_POS(&ZCSG(interned_strings), str));
- include_path_len = ZCG(include_path_key_len) = buf + sizeof(buf) - 1 - res;
- include_path = ZCG(include_path_key);
- memcpy(ZCG(include_path_key), res, include_path_len + 1);
- } else {
- return NULL;
- }
- } else {
- return NULL;
- }
- }
- }
- /* Calculate key length */
- if (UNEXPECTED((size_t)(cwd_len + path_length + include_path_len + 2) >= sizeof(ZCG(_key)))) {
- return NULL;
- }
- /* Generate key
- * Note - the include_path must be the last element in the key,
- * since in itself, it may include colons (which we use to separate
- * different components of the key)
- */
- key = ZSTR_VAL(&ZCG(key));
- memcpy(key, path, path_length);
- key[path_length] = ':';
- key_length = path_length + 1;
- memcpy(key + key_length, cwd, cwd_len);
- key_length += cwd_len;
- if (include_path_len) {
- key[key_length] = ':';
- key_length += 1;
- memcpy(key + key_length, include_path, include_path_len);
- key_length += include_path_len;
- }
- /* Here we add to the key the parent script directory,
- * since fopen_wrappers from version 4.0.7 use current script's path
- * in include path too.
- */
- if (EXPECTED(EG(current_execute_data)) &&
- EXPECTED((parent_script = zend_get_executed_filename_ex()) != NULL)) {
- parent_script_len = ZSTR_LEN(parent_script);
- while ((--parent_script_len > 0) && !IS_SLASH(ZSTR_VAL(parent_script)[parent_script_len]));
- if (UNEXPECTED((size_t)(key_length + parent_script_len + 1) >= sizeof(ZCG(_key)))) {
- return NULL;
- }
- key[key_length] = ':';
- key_length += 1;
- memcpy(key + key_length, ZSTR_VAL(parent_script), parent_script_len);
- key_length += parent_script_len;
- }
- key[key_length] = '\0';
- GC_SET_REFCOUNT(&ZCG(key), 1);
- GC_TYPE_INFO(&ZCG(key)) = GC_STRING;
- ZSTR_H(&ZCG(key)) = 0;
- ZSTR_LEN(&ZCG(key)) = key_length;
- return &ZCG(key);
- }
- /* not use_cwd */
- return str;
- }
- int zend_accel_invalidate(zend_string *filename, bool force)
- {
- zend_string *realpath;
- zend_persistent_script *persistent_script;
- if (!ZCG(accelerator_enabled) || accelerator_shm_read_lock() != SUCCESS) {
- return FAILURE;
- }
- realpath = accelerator_orig_zend_resolve_path(filename);
- if (!realpath) {
- return FAILURE;
- }
- if (ZCG(accel_directives).file_cache) {
- zend_file_cache_invalidate(realpath);
- }
- persistent_script = zend_accel_hash_find(&ZCSG(hash), realpath);
- if (persistent_script && !persistent_script->corrupted) {
- zend_file_handle file_handle;
- zend_stream_init_filename_ex(&file_handle, realpath);
- file_handle.opened_path = realpath;
- if (force ||
- !ZCG(accel_directives).validate_timestamps ||
- do_validate_timestamps(persistent_script, &file_handle) == FAILURE) {
- HANDLE_BLOCK_INTERRUPTIONS();
- SHM_UNPROTECT();
- zend_shared_alloc_lock();
- if (!persistent_script->corrupted) {
- persistent_script->corrupted = 1;
- persistent_script->timestamp = 0;
- ZSMMG(wasted_shared_memory) += persistent_script->dynamic_members.memory_consumption;
- if (ZSMMG(memory_exhausted)) {
- zend_accel_restart_reason reason =
- zend_accel_hash_is_full(&ZCSG(hash)) ? ACCEL_RESTART_HASH : ACCEL_RESTART_OOM;
- zend_accel_schedule_restart_if_necessary(reason);
- }
- }
- zend_shared_alloc_unlock();
- SHM_PROTECT();
- HANDLE_UNBLOCK_INTERRUPTIONS();
- }
- file_handle.opened_path = NULL;
- zend_destroy_file_handle(&file_handle);
- }
- accelerator_shm_read_unlock();
- zend_string_release_ex(realpath, 0);
- return SUCCESS;
- }
- static zend_string* accel_new_interned_key(zend_string *key)
- {
- zend_string *new_key;
- if (zend_accel_in_shm(key)) {
- return key;
- }
- GC_ADDREF(key);
- new_key = accel_new_interned_string(key);
- if (UNEXPECTED(new_key == key)) {
- GC_DELREF(key);
- new_key = zend_shared_alloc(ZEND_MM_ALIGNED_SIZE_EX(_ZSTR_STRUCT_SIZE(ZSTR_LEN(key)), 8));
- if (EXPECTED(new_key)) {
- GC_SET_REFCOUNT(new_key, 2);
- GC_TYPE_INFO(new_key) = GC_STRING | (IS_STR_INTERNED << GC_FLAGS_SHIFT);
- ZSTR_H(new_key) = ZSTR_H(key);
- ZSTR_LEN(new_key) = ZSTR_LEN(key);
- memcpy(ZSTR_VAL(new_key), ZSTR_VAL(key), ZSTR_LEN(new_key) + 1);
- }
- }
- return new_key;
- }
- /* Adds another key for existing cached script */
- static void zend_accel_add_key(zend_string *key, zend_accel_hash_entry *bucket)
- {
- if (!zend_accel_hash_find(&ZCSG(hash), key)) {
- if (zend_accel_hash_is_full(&ZCSG(hash))) {
- zend_accel_error(ACCEL_LOG_DEBUG, "No more entries in hash table!");
- ZSMMG(memory_exhausted) = 1;
- zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_HASH);
- } else {
- zend_string *new_key = accel_new_interned_key(key);
- if (new_key) {
- if (zend_accel_hash_update(&ZCSG(hash), new_key, 1, bucket)) {
- zend_accel_error(ACCEL_LOG_INFO, "Added key '%s'", ZSTR_VAL(new_key));
- }
- } else {
- zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_OOM);
- }
- }
- }
- }
- static zend_always_inline bool is_phar_file(zend_string *filename)
- {
- return filename && ZSTR_LEN(filename) >= sizeof(".phar") &&
- !memcmp(ZSTR_VAL(filename) + ZSTR_LEN(filename) - (sizeof(".phar")-1), ".phar", sizeof(".phar")-1) &&
- !strstr(ZSTR_VAL(filename), "://");
- }
- static zend_persistent_script *store_script_in_file_cache(zend_persistent_script *new_persistent_script)
- {
- uint32_t memory_used;
- zend_shared_alloc_init_xlat_table();
- /* Calculate the required memory size */
- memory_used = zend_accel_script_persist_calc(new_persistent_script, 0);
- /* Allocate memory block */
- #if defined(__AVX__) || defined(__SSE2__)
- /* Align to 64-byte boundary */
- ZCG(mem) = zend_arena_alloc(&CG(arena), memory_used + 64);
- ZCG(mem) = (void*)(((zend_uintptr_t)ZCG(mem) + 63L) & ~63L);
- #elif ZEND_MM_ALIGNMENT < 8
- /* Align to 8-byte boundary */
- ZCG(mem) = zend_arena_alloc(&CG(arena), memory_used + 8);
- ZCG(mem) = (void*)(((zend_uintptr_t)ZCG(mem) + 7L) & ~7L);
- #else
- ZCG(mem) = zend_arena_alloc(&CG(arena), memory_used);
- #endif
- zend_shared_alloc_clear_xlat_table();
- /* Copy into memory block */
- new_persistent_script = zend_accel_script_persist(new_persistent_script, 0);
- zend_shared_alloc_destroy_xlat_table();
- new_persistent_script->is_phar = is_phar_file(new_persistent_script->script.filename);
- /* Consistency check */
- if ((char*)new_persistent_script->mem + new_persistent_script->size != (char*)ZCG(mem)) {
- zend_accel_error(
- ((char*)new_persistent_script->mem + new_persistent_script->size < (char*)ZCG(mem)) ? ACCEL_LOG_ERROR : ACCEL_LOG_WARNING,
- "Internal error: wrong size calculation: %s start=" ZEND_ADDR_FMT ", end=" ZEND_ADDR_FMT ", real=" ZEND_ADDR_FMT "\n",
- ZSTR_VAL(new_persistent_script->script.filename),
- (size_t)new_persistent_script->mem,
- (size_t)((char *)new_persistent_script->mem + new_persistent_script->size),
- (size_t)ZCG(mem));
- }
- new_persistent_script->dynamic_members.checksum = zend_accel_script_checksum(new_persistent_script);
- zend_file_cache_script_store(new_persistent_script, 0);
- return new_persistent_script;
- }
- static zend_persistent_script *cache_script_in_file_cache(zend_persistent_script *new_persistent_script, int *from_shared_memory)
- {
- uint32_t orig_compiler_options;
- orig_compiler_options = CG(compiler_options);
- CG(compiler_options) |= ZEND_COMPILE_WITH_FILE_CACHE;
- if (!zend_optimize_script(&new_persistent_script->script, ZCG(accel_directives).optimization_level, ZCG(accel_directives).opt_debug_level)) {
- CG(compiler_options) = orig_compiler_options;
- return new_persistent_script;
- }
- CG(compiler_options) = orig_compiler_options;
- *from_shared_memory = 1;
- return store_script_in_file_cache(new_persistent_script);
- }
- static zend_persistent_script *cache_script_in_shared_memory(zend_persistent_script *new_persistent_script, zend_string *key, int *from_shared_memory)
- {
- zend_accel_hash_entry *bucket;
- uint32_t memory_used;
- uint32_t orig_compiler_options;
- orig_compiler_options = CG(compiler_options);
- if (ZCG(accel_directives).file_cache) {
- CG(compiler_options) |= ZEND_COMPILE_WITH_FILE_CACHE;
- }
- if (!zend_optimize_script(&new_persistent_script->script, ZCG(accel_directives).optimization_level, ZCG(accel_directives).opt_debug_level)) {
- CG(compiler_options) = orig_compiler_options;
- return new_persistent_script;
- }
- CG(compiler_options) = orig_compiler_options;
- /* exclusive lock */
- zend_shared_alloc_lock();
- /* Check if we still need to put the file into the cache (may be it was
- * already stored by another process. This final check is done under
- * exclusive lock) */
- bucket = zend_accel_hash_find_entry(&ZCSG(hash), new_persistent_script->script.filename);
- if (bucket) {
- zend_persistent_script *existing_persistent_script = (zend_persistent_script *)bucket->data;
- if (!existing_persistent_script->corrupted) {
- if (key &&
- (!ZCG(accel_directives).validate_timestamps ||
- (new_persistent_script->timestamp == existing_persistent_script->timestamp))) {
- zend_accel_add_key(key, bucket);
- }
- zend_shared_alloc_unlock();
- #if 1
- /* prefer the script already stored in SHM */
- free_persistent_script(new_persistent_script, 1);
- *from_shared_memory = 1;
- return existing_persistent_script;
- #else
- return new_persistent_script;
- #endif
- }
- }
- if (zend_accel_hash_is_full(&ZCSG(hash))) {
- zend_accel_error(ACCEL_LOG_DEBUG, "No more entries in hash table!");
- ZSMMG(memory_exhausted) = 1;
- zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_HASH);
- zend_shared_alloc_unlock();
- if (ZCG(accel_directives).file_cache) {
- new_persistent_script = store_script_in_file_cache(new_persistent_script);
- *from_shared_memory = 1;
- }
- return new_persistent_script;
- }
- zend_shared_alloc_init_xlat_table();
- /* Calculate the required memory size */
- memory_used = zend_accel_script_persist_calc(new_persistent_script, 1);
- /* Allocate shared memory */
- #if defined(__AVX__) || defined(__SSE2__)
- /* Align to 64-byte boundary */
- ZCG(mem) = zend_shared_alloc(memory_used + 64);
- if (ZCG(mem)) {
- ZCG(mem) = (void*)(((zend_uintptr_t)ZCG(mem) + 63L) & ~63L);
- #if defined(__x86_64__)
- memset(ZCG(mem), 0, memory_used);
- #elif defined(__AVX__)
- {
- char *p = (char*)ZCG(mem);
- char *end = p + memory_used;
- __m256i ymm0 = _mm256_setzero_si256();
- while (p < end) {
- _mm256_store_si256((__m256i*)p, ymm0);
- _mm256_store_si256((__m256i*)(p+32), ymm0);
- p += 64;
- }
- }
- #else
- {
- char *p = (char*)ZCG(mem);
- char *end = p + memory_used;
- __m128i xmm0 = _mm_setzero_si128();
- while (p < end) {
- _mm_store_si128((__m128i*)p, xmm0);
- _mm_store_si128((__m128i*)(p+16), xmm0);
- _mm_store_si128((__m128i*)(p+32), xmm0);
- _mm_store_si128((__m128i*)(p+48), xmm0);
- p += 64;
- }
- }
- #endif
- }
- #else
- ZCG(mem) = zend_shared_alloc(memory_used);
- if (ZCG(mem)) {
- memset(ZCG(mem), 0, memory_used);
- }
- #endif
- if (!ZCG(mem)) {
- zend_shared_alloc_destroy_xlat_table();
- zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_OOM);
- zend_shared_alloc_unlock();
- if (ZCG(accel_directives).file_cache) {
- new_persistent_script = store_script_in_file_cache(new_persistent_script);
- *from_shared_memory = 1;
- }
- return new_persistent_script;
- }
- zend_shared_alloc_clear_xlat_table();
- /* Copy into shared memory */
- new_persistent_script = zend_accel_script_persist(new_persistent_script, 1);
- zend_shared_alloc_destroy_xlat_table();
- new_persistent_script->is_phar = is_phar_file(new_persistent_script->script.filename);
- /* Consistency check */
- if ((char*)new_persistent_script->mem + new_persistent_script->size != (char*)ZCG(mem)) {
- zend_accel_error(
- ((char*)new_persistent_script->mem + new_persistent_script->size < (char*)ZCG(mem)) ? ACCEL_LOG_ERROR : ACCEL_LOG_WARNING,
- "Internal error: wrong size calculation: %s start=" ZEND_ADDR_FMT ", end=" ZEND_ADDR_FMT ", real=" ZEND_ADDR_FMT "\n",
- ZSTR_VAL(new_persistent_script->script.filename),
- (size_t)new_persistent_script->mem,
- (size_t)((char *)new_persistent_script->mem + new_persistent_script->size),
- (size_t)ZCG(mem));
- }
- new_persistent_script->dynamic_members.checksum = zend_accel_script_checksum(new_persistent_script);
- /* store script structure in the hash table */
- bucket = zend_accel_hash_update(&ZCSG(hash), new_persistent_script->script.filename, 0, new_persistent_script);
- if (bucket) {
- zend_accel_error(ACCEL_LOG_INFO, "Cached script '%s'", ZSTR_VAL(new_persistent_script->script.filename));
- if (key &&
- /* key may contain non-persistent PHAR aliases (see issues #115 and #149) */
- memcmp(ZSTR_VAL(key), "phar://", sizeof("phar://") - 1) != 0 &&
- !zend_string_equals(new_persistent_script->script.filename, key)) {
- /* link key to the same persistent script in hash table */
- zend_string *new_key = accel_new_interned_key(key);
- if (new_key) {
- if (zend_accel_hash_update(&ZCSG(hash), new_key, 1, bucket)) {
- zend_accel_error(ACCEL_LOG_INFO, "Added key '%s'", ZSTR_VAL(key));
- } else {
- zend_accel_error(ACCEL_LOG_DEBUG, "No more entries in hash table!");
- ZSMMG(memory_exhausted) = 1;
- zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_HASH);
- }
- } else {
- zend_accel_schedule_restart_if_necessary(ACCEL_RESTART_OOM);
- }
- }
- }
- new_persistent_script->dynamic_members.memory_consumption = ZEND_ALIGNED_SIZE(new_persistent_script->size);
- zend_shared_alloc_unlock();
- if (ZCG(accel_directives).file_cache) {
- SHM_PROTECT();
- zend_file_cache_script_store(new_persistent_script, 1);
- SHM_UNPROTECT();
- }
- *from_shared_memory = 1;
- return new_persistent_script;
- }
- #define ZEND_AUTOGLOBAL_MASK_SERVER (1 << 0)
- #define ZEND_AUTOGLOBAL_MASK_ENV (1 << 1)
- #define ZEND_AUTOGLOBAL_MASK_REQUEST (1 << 2)
- static int zend_accel_get_auto_globals(void)
- {
- int mask = 0;
- if (zend_hash_exists(&EG(symbol_table), ZSTR_KNOWN(ZEND_STR_AUTOGLOBAL_SERVER))) {
- mask |= ZEND_AUTOGLOBAL_MASK_SERVER;
- }
- if (zend_hash_exists(&EG(symbol_table), ZSTR_KNOWN(ZEND_STR_AUTOGLOBAL_ENV))) {
- mask |= ZEND_AUTOGLOBAL_MASK_ENV;
- }
- if (zend_hash_exists(&EG(symbol_table), ZSTR_KNOWN(ZEND_STR_AUTOGLOBAL_REQUEST))) {
- mask |= ZEND_AUTOGLOBAL_MASK_REQUEST;
- }
- return mask;
- }
- static void zend_accel_set_auto_globals(int mask)
- {
- if (mask & ZEND_AUTOGLOBAL_MASK_SERVER) {
- zend_is_auto_global(ZSTR_KNOWN(ZEND_STR_AUTOGLOBAL_SERVER));
- }
- if (mask & ZEND_AUTOGLOBAL_MASK_ENV) {
- zend_is_auto_global(ZSTR_KNOWN(ZEND_STR_AUTOGLOBAL_ENV));
- }
- if (mask & ZEND_AUTOGLOBAL_MASK_REQUEST) {
- zend_is_auto_global(ZSTR_KNOWN(ZEND_STR_AUTOGLOBAL_REQUEST));
- }
- ZCG(auto_globals_mask) |= mask;
- }
- static void replay_warnings(uint32_t num_warnings, zend_error_info **warnings) {
- for (uint32_t i = 0; i < num_warnings; i++) {
- zend_error_info *warning = warnings[i];
- zend_error_zstr_at(warning->type, warning->filename, warning->lineno, warning->message);
- }
- }
- static zend_persistent_script *opcache_compile_file(zend_file_handle *file_handle, int type, zend_op_array **op_array_p)
- {
- zend_persistent_script *new_persistent_script;
- uint32_t orig_functions_count, orig_class_count;
- zend_op_array *orig_active_op_array;
- zval orig_user_error_handler;
- zend_op_array *op_array;
- int do_bailout = 0;
- accel_time_t timestamp = 0;
- uint32_t orig_compiler_options = 0;
- /* Try to open file */
- if (file_handle->type == ZEND_HANDLE_FILENAME) {
- if (accelerator_orig_zend_stream_open_function(file_handle) != SUCCESS) {
- *op_array_p = NULL;
- if (!EG(exception)) {
- if (type == ZEND_REQUIRE) {
- zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, ZSTR_VAL(file_handle->filename));
- } else {
- zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, ZSTR_VAL(file_handle->filename));
- }
- }
- return NULL;
- }
- }
- /* check blacklist right after ensuring that file was opened */
- if (file_handle->opened_path && zend_accel_blacklist_is_blacklisted(&accel_blacklist, ZSTR_VAL(file_handle->opened_path), ZSTR_LEN(file_handle->opened_path))) {
- SHM_UNPROTECT();
- ZCSG(blacklist_misses)++;
- SHM_PROTECT();
- *op_array_p = accelerator_orig_compile_file(file_handle, type);
- return NULL;
- }
- if (ZCG(accel_directives).validate_timestamps ||
- ZCG(accel_directives).file_update_protection ||
- ZCG(accel_directives).max_file_size > 0) {
- size_t size = 0;
- /* Obtain the file timestamps, *before* actually compiling them,
- * otherwise we have a race-condition.
- */
- timestamp = zend_get_file_handle_timestamp(file_handle, ZCG(accel_directives).max_file_size > 0 ? &size : NULL);
- /* If we can't obtain a timestamp (that means file is possibly socket)
- * we won't cache it
- */
- if (timestamp == 0) {
- *op_array_p = accelerator_orig_compile_file(file_handle, type);
- return NULL;
- }
- /* check if file is too new (may be it's not written completely yet) */
- if (ZCG(accel_directives).file_update_protection &&
- ((accel_time_t)(ZCG(request_time) - ZCG(accel_directives).file_update_protection) < timestamp)) {
- *op_array_p = accelerator_orig_compile_file(file_handle, type);
- return NULL;
- }
- if (ZCG(accel_directives).max_file_size > 0 && size > (size_t)ZCG(accel_directives).max_file_size) {
- SHM_UNPROTECT();
- ZCSG(blacklist_misses)++;
- SHM_PROTECT();
- *op_array_p = accelerator_orig_compile_file(file_handle, type);
- return NULL;
- }
- }
- /* Save the original values for the op_array, function table and class table */
- orig_active_op_array = CG(active_op_array);
- orig_functions_count = EG(function_table)->nNumUsed;
- orig_class_count = EG(class_table)->nNumUsed;
- ZVAL_COPY_VALUE(&orig_user_error_handler, &EG(user_error_handler));
- /* Override them with ours */
- ZVAL_UNDEF(&EG(user_error_handler));
- if (ZCG(accel_directives).record_warnings) {
- zend_begin_record_errors();
- }
- zend_try {
- orig_compiler_options = CG(compiler_options);
- CG(compiler_options) |= ZEND_COMPILE_HANDLE_OP_ARRAY;
- CG(compiler_options) |= ZEND_COMPILE_IGNORE_INTERNAL_CLASSES;
- CG(compiler_options) |= ZEND_COMPILE_DELAYED_BINDING;
- CG(compiler_options) |= ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION;
- CG(compiler_options) |= ZEND_COMPILE_IGNORE_OTHER_FILES;
- if (ZCG(accel_directives).file_cache) {
- CG(compiler_options) |= ZEND_COMPILE_WITH_FILE_CACHE;
- }
- op_array = *op_array_p = accelerator_orig_compile_file(file_handle, type);
- CG(compiler_options) = orig_compiler_options;
- } zend_catch {
- op_array = NULL;
- do_bailout = 1;
- CG(compiler_options) = orig_compiler_options;
- } zend_end_try();
- /* Restore originals */
- CG(active_op_array) = orig_active_op_array;
- EG(user_error_handler) = orig_user_error_handler;
- EG(record_errors) = 0;
- if (!op_array) {
- /* compilation failed */
- zend_free_recorded_errors();
- if (do_bailout) {
- zend_bailout();
- }
- return NULL;
- }
- /* Build the persistent_script structure.
- Here we aren't sure we would store it, but we will need it
- further anyway.
- */
- new_persistent_script = create_persistent_script();
- new_persistent_script->script.main_op_array = *op_array;
- zend_accel_move_user_functions(CG(function_table), CG(function_table)->nNumUsed - orig_functions_count, &new_persistent_script->script);
- zend_accel_move_user_classes(CG(class_table), CG(class_table)->nNumUsed - orig_class_count, &new_persistent_script->script);
- new_persistent_script->script.first_early_binding_opline =
- (op_array->fn_flags & ZEND_ACC_EARLY_BINDING) ?
- zend_build_delayed_early_binding_list(op_array) :
- (uint32_t)-1;
- new_persistent_script->num_warnings = EG(num_errors);
- new_persistent_script->warnings = EG(errors);
- EG(num_errors) = 0;
- EG(errors) = NULL;
- efree(op_array); /* we have valid persistent_script, so it's safe to free op_array */
- /* Fill in the ping_auto_globals_mask for the new script. If jit for auto globals is enabled we
- will have to ping the used auto global variables before execution */
- if (PG(auto_globals_jit)) {
- new_persistent_script->ping_auto_globals_mask = zend_accel_get_auto_globals();
- }
- if (ZCG(accel_directives).validate_timestamps) {
- /* Obtain the file timestamps, *before* actually compiling them,
- * otherwise we have a race-condition.
- */
- new_persistent_script->timestamp = timestamp;
- new_persistent_script->dynamic_members.revalidate = ZCG(request_time) + ZCG(accel_directives).revalidate_freq;
- }
- if (file_handle->opened_path) {
- new_persistent_script->script.filename = zend_string_copy(file_handle->opened_path);
- } else {
- new_persistent_script->script.filename = zend_string_copy(file_handle->filename);
- }
- zend_string_hash_val(new_persistent_script->script.filename);
- /* Now persistent_script structure is ready in process memory */
- return new_persistent_script;
- }
- zend_op_array *file_cache_compile_file(zend_file_handle *file_handle, int type)
- {
- zend_persistent_script *persistent_script;
- zend_op_array *op_array = NULL;
- int from_memory; /* if the script we've got is stored in SHM */
- if (is_stream_path(ZSTR_VAL(file_handle->filename)) &&
- !is_cacheable_stream_path(ZSTR_VAL(file_handle->filename))) {
- return accelerator_orig_compile_file(file_handle, type);
- }
- if (!file_handle->opened_path) {
- if (file_handle->type == ZEND_HANDLE_FILENAME &&
- accelerator_orig_zend_stream_open_function(file_handle) == FAILURE) {
- if (!EG(exception)) {
- if (type == ZEND_REQUIRE) {
- zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, ZSTR_VAL(file_handle->filename));
- } else {
- zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, ZSTR_VAL(file_handle->filename));
- }
- }
- return NULL;
- }
- }
- HANDLE_BLOCK_INTERRUPTIONS();
- SHM_UNPROTECT();
- persistent_script = zend_file_cache_script_load(file_handle);
- SHM_PROTECT();
- HANDLE_UNBLOCK_INTERRUPTIONS();
- if (persistent_script) {
- /* see bug #15471 (old BTS) */
- if (persistent_script->script.filename) {
- if (!EG(current_execute_data) || !EG(current_execute_data)->opline ||
- !EG(current_execute_data)->func ||
- !ZEND_USER_CODE(EG(current_execute_data)->func->common.type) ||
- EG(current_execute_data)->opline->opcode != ZEND_INCLUDE_OR_EVAL ||
- (EG(current_execute_data)->opline->extended_value != ZEND_INCLUDE_ONCE &&
- EG(current_execute_data)->opline->extended_value != ZEND_REQUIRE_ONCE)) {
- if (zend_hash_add_empty_element(&EG(included_files), persistent_script->script.filename) != NULL) {
- /* ext/phar has to load phar's metadata into memory */
- if (persistent_script->is_phar) {
- php_stream_statbuf ssb;
- char *fname = emalloc(sizeof("phar://") + ZSTR_LEN(persistent_script->script.filename));
- memcpy(fname, "phar://", sizeof("phar://") - 1);
- memcpy(fname + sizeof("phar://") - 1, ZSTR_VAL(persistent_script->script.filename), ZSTR_LEN(persistent_script->script.filename) + 1);
- php_stream_stat_path(fname, &ssb);
- efree(fname);
- }
- }
- }
- }
- replay_warnings(persistent_script->num_warnings, persistent_script->warnings);
- if (persistent_script->ping_auto_globals_mask & ~ZCG(auto_globals_mask)) {
- zend_accel_set_auto_globals(persistent_script->ping_auto_globals_mask & ~ZCG(auto_globals_mask));
- }
- return zend_accel_load_script(persistent_script, 1);
- }
- persistent_script = opcache_compile_file(file_handle, type, &op_array);
- if (persistent_script) {
- from_memory = 0;
- persistent_script = cache_script_in_file_cache(persistent_script, &from_memory);
- return zend_accel_load_script(persistent_script, from_memory);
- }
- return op_array;
- }
- int check_persistent_script_access(zend_persistent_script *persistent_script)
- {
- char *phar_path, *ptr;
- int ret;
- if ((ZSTR_LEN(persistent_script->script.filename)<sizeof("phar://.phar")) ||
- memcmp(ZSTR_VAL(persistent_script->script.filename), "phar://", sizeof("phar://")-1)) {
- return access(ZSTR_VAL(persistent_script->script.filename), R_OK) != 0;
- } else {
- /* we got a cached file from .phar, so we have to strip prefix and path inside .phar to check access() */
- phar_path = estrdup(ZSTR_VAL(persistent_script->script.filename)+sizeof("phar://")-1);
- if ((ptr = strstr(phar_path, ".phar/")) != NULL)
- {
- *(ptr+sizeof(".phar/")-2) = 0; /* strip path inside .phar file */
- }
- ret = access(phar_path, R_OK) != 0;
- efree(phar_path);
- return ret;
- }
- }
- /* zend_compile() replacement */
- zend_op_array *persistent_compile_file(zend_file_handle *file_handle, int type)
- {
- zend_persistent_script *persistent_script = NULL;
- zend_string *key = NULL;
- int from_shared_memory; /* if the script we've got is stored in SHM */
- if (!file_handle->filename || !ZCG(accelerator_enabled)) {
- /* The Accelerator is disabled, act as if without the Accelerator */
- ZCG(cache_opline) = NULL;
- ZCG(cache_persistent_script) = NULL;
- if (file_handle->filename
- && ZCG(accel_directives).file_cache
- && ZCG(enabled) && accel_startup_ok) {
- return file_cache_compile_file(file_handle, type);
- }
- return accelerator_orig_compile_file(file_handle, type);
- } else if (file_cache_only) {
- ZCG(cache_opline) = NULL;
- ZCG(cache_persistent_script) = NULL;
- return file_cache_compile_file(file_handle, type);
- } else if (!ZCG(accelerator_enabled) ||
- (ZCSG(restart_in_progress) && accel_restart_is_active())) {
- if (ZCG(accel_directives).file_cache) {
- return file_cache_compile_file(file_handle, type);
- }
- ZCG(cache_opline) = NULL;
- ZCG(cache_persistent_script) = NULL;
- return accelerator_orig_compile_file(file_handle, type);
- }
- /* In case this callback is called from include_once, require_once or it's
- * a main FastCGI request, the key must be already calculated, and cached
- * persistent script already found */
- if (ZCG(cache_persistent_script) &&
- ((!EG(current_execute_data) &&
- file_handle->primary_script &&
- ZCG(cache_opline) == NULL) ||
- (EG(current_execute_data) &&
- EG(current_execute_data)->func &&
- ZEND_USER_CODE(EG(current_execute_data)->func->common.type) &&
- ZCG(cache_opline) == EG(current_execute_data)->opline))) {
- persistent_script = ZCG(cache_persistent_script);
- if (ZSTR_LEN(&ZCG(key))) {
- key = &ZCG(key);
- }
- } else {
- if (!ZCG(accel_directives).revalidate_path) {
- /* try to find cached script by key */
- key = accel_make_persistent_key(file_handle->filename);
- if (!key) {
- ZCG(cache_opline) = NULL;
- ZCG(cache_persistent_script) = NULL;
- return accelerator_orig_compile_file(file_handle, type);
- }
- persistent_script = zend_accel_hash_find(&ZCSG(hash), key);
- } else if (UNEXPECTED(is_stream_path(ZSTR_VAL(file_handle->filename)) && !is_cacheable_stream_path(ZSTR_VAL(file_handle->filename)))) {
- ZCG(cache_opline) = NULL;
- ZCG(cache_persistent_script) = NULL;
- return accelerator_orig_compile_file(file_handle, type);
- }
- if (!persistent_script) {
- /* try to find cached script by full real path */
- zend_accel_hash_entry *bucket;
- /* open file to resolve the path */
- if (file_handle->type == ZEND_HANDLE_FILENAME
- && accelerator_orig_zend_stream_open_function(file_handle) == FAILURE) {
- if (!EG(exception)) {
- if (type == ZEND_REQUIRE) {
- zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, ZSTR_VAL(file_handle->filename));
- } else {
- zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, ZSTR_VAL(file_handle->filename));
- }
- }
- return NULL;
- }
- if (file_handle->opened_path) {
- bucket = zend_accel_hash_find_entry(&ZCSG(hash), file_handle->opened_path);
- if (bucket) {
- persistent_script = (zend_persistent_script *)bucket->data;
- if (key && !persistent_script->corrupted) {
- HANDLE_BLOCK_INTERRUPTIONS();
- SHM_UNPROTECT();
- zend_shared_alloc_lock();
- zend_accel_add_key(key, bucket);
- zend_shared_alloc_unlock();
- SHM_PROTECT();
- HANDLE_UNBLOCK_INTERRUPTIONS();
- }
- }
- }
- }
- }
- /* clear cache */
- ZCG(cache_opline) = NULL;
- ZCG(cache_persistent_script) = NULL;
- if (persistent_script && persistent_script->corrupted) {
- persistent_script = NULL;
- }
- /* Make sure we only increase the currently running processes semaphore
- * once each execution (this function can be called more than once on
- * each execution)
- */
- if (!ZCG(counted)) {
- if (accel_activate_add() == FAILURE) {
- if (ZCG(accel_directives).file_cache) {
- return file_cache_compile_file(file_handle, type);
- }
- return accelerator_orig_compile_file(file_handle, type);
- }
- ZCG(counted) = 1;
- }
- /* Revalidate accessibility of cached file */
- if (EXPECTED(persistent_script != NULL) &&
- UNEXPECTED(ZCG(accel_directives).validate_permission) &&
- file_handle->type == ZEND_HANDLE_FILENAME &&
- UNEXPECTED(check_persistent_script_access(persistent_script))) {
- if (!EG(exception)) {
- if (type == ZEND_REQUIRE) {
- zend_message_dispatcher(ZMSG_FAILED_REQUIRE_FOPEN, ZSTR_VAL(file_handle->filename));
- } else {
- zend_message_dispatcher(ZMSG_FAILED_INCLUDE_FOPEN, ZSTR_VAL(file_handle->filename));
- }
- }
- return NULL;
- }
- HANDLE_BLOCK_INTERRUPTIONS();
- SHM_UNPROTECT();
- /* If script is found then validate_timestamps if option is enabled */
- if (persistent_script && ZCG(accel_directives).validate_timestamps) {
- if (validate_timestamp_and_record(persistent_script, file_handle) == FAILURE) {
- zend_shared_alloc_lock();
- if (!persistent_script->corrupted) {
- persistent_script->corrupted = 1;
- persistent_script->timestamp = 0;
- ZSMMG(wasted_shared_memory) += persistent_script->dynamic_members.memory_consumption;
- if (ZSMMG(memory_exhausted)) {
- zend_accel_restart_reason reason =
- zend_accel_hash_is_full(&ZCSG(hash)) ? ACCEL_RESTART_HASH : ACCEL_RESTART_OOM;
- zend_accel_schedule_restart_if_necessary(reason);
- }
- }
- zend_shared_alloc_unlock();
- persistent_script = NULL;
- }
- }
- /* if turned on - check the compiled script ADLER32 checksum */
- if (persistent_script && ZCG(accel_directives).consistency_checks
- && persistent_script->dynamic_members.hits % ZCG(accel_directives).consistency_checks == 0) {
- unsigned int checksum = zend_accel_script_checksum(persistent_script);
- if (checksum != persistent_script->dynamic_members.checksum ) {
- /* The checksum is wrong */
- zend_accel_error(ACCEL_LOG_INFO, "Checksum failed for '%s': expected=0x%08x, found=0x%08x",
- ZSTR_VAL(persistent_script->script.filename), persistent_script->dynamic_members.checksum, checksum);
- zend_shared_alloc_lock();
- if (!persistent_script->corrupted) {
- persistent_script->corrupted = 1;
- persistent_script->timestamp = 0;
- ZSMMG(wasted_shared_memory) += persistent_script->dynamic_members.memory_consumption;
- if (ZSMMG(memory_exhausted)) {
- zend_accel_restart_reason reason =
- zend_accel_hash_is_full(&ZCSG(hash)) ? ACCEL_RESTART_HASH : ACCEL_RESTART_OOM;
- zend_accel_schedule_restart_if_necessary(reason);
- }
- }
- zend_shared_alloc_unlock();
- persistent_script = NULL;
- }
- }
- /* Check the second level cache */
- if (!persistent_script && ZCG(accel_directives).file_cache) {
- persistent_script = zend_file_cache_script_load(file_handle);
- }
- /* If script was not found or invalidated by validate_timestamps */
- if (!persistent_script) {
- uint32_t old_const_num = zend_hash_next_free_element(EG(zend_constants));
- zend_op_array *op_array;
- /* Cache miss.. */
- ZCSG(misses)++;
- /* No memory left. Behave like without the Accelerator */
- if (ZSMMG(memory_exhausted) || ZCSG(restart_pending)) {
- SHM_PROTECT();
- HANDLE_UNBLOCK_INTERRUPTIONS();
- if (ZCG(accel_directives).file_cache) {
- return file_cache_compile_file(file_handle, type);
- }
- return accelerator_orig_compile_file(file_handle, type);
- }
- SHM_PROTECT();
- HANDLE_UNBLOCK_INTERRUPTIONS();
- persistent_script = opcache_compile_file(file_handle, type, &op_array);
- HANDLE_BLOCK_INTERRUPTIONS();
- SHM_UNPROTECT();
- /* Try and cache the script and assume that it is returned from_shared_memory.
- * If it isn't compile_and_cache_file() changes the flag to 0
- */
- from_shared_memory = 0;
- if (persistent_script) {
- persistent_script = cache_script_in_shared_memory(persistent_script, key, &from_shared_memory);
- }
- /* Caching is disabled, returning op_array;
- * or something went wrong during compilation, returning NULL
- */
- if (!persistent_script) {
- SHM_PROTECT();
- HANDLE_UNBLOCK_INTERRUPTIONS();
- return op_array;
- }
- if (from_shared_memory) {
- /* Delete immutable arrays moved into SHM */
- uint32_t new_const_num = zend_hash_next_free_element(EG(zend_constants));
- while (new_const_num > old_const_num) {
- new_const_num--;
- zend_hash_index_del(EG(zend_constants), new_const_num);
- }
- }
- persistent_script->dynamic_members.last_used = ZCG(request_time);
- SHM_PROTECT();
- HANDLE_UNBLOCK_INTERRUPTIONS();
- } else {
- #if !ZEND_WIN32
- ZCSG(hits)++; /* TBFixed: may lose one hit */
- persistent_script->dynamic_members.hits++; /* see above */
- #else
- #ifdef _M_X64
- InterlockedIncrement64(&ZCSG(hits));
- #else
- InterlockedIncrement(&ZCSG(hits));
- #endif
- InterlockedIncrement64(&persistent_script->dynamic_members.hits);
- #endif
- /* see bug #15471 (old BTS) */
- if (persistent_script->script.filename) {
- if (!EG(current_execute_data) ||
- !EG(current_execute_data)->func ||
- !ZEND_USER_CODE(EG(current_execute_data)->func->common.type) ||
- !EG(current_execute_data)->opline ||
- EG(current_execute_data)->opline->opcode != ZEND_INCLUDE_OR_EVAL ||
- (EG(current_execute_data)->opline->extended_value != ZEND_INCLUDE_ONCE &&
- EG(current_execute_data)->opline->extended_value != ZEND_REQUIRE_ONCE)) {
- if (zend_hash_add_empty_element(&EG(included_files), persistent_script->script.filename) != NULL) {
- /* ext/phar has to load phar's metadata into memory */
- if (persistent_script->is_phar) {
- php_stream_statbuf ssb;
- char *fname = emalloc(sizeof("phar://") + ZSTR_LEN(persistent_script->script.filename));
- memcpy(fname, "phar://", sizeof("phar://") - 1);
- memcpy(fname + sizeof("phar://") - 1, ZSTR_VAL(persistent_script->script.filename), ZSTR_LEN(persistent_script->script.filename) + 1);
- php_stream_stat_path(fname, &ssb);
- efree(fname);
- }
- }
- }
- }
- persistent_script->dynamic_members.last_used = ZCG(request_time);
- SHM_PROTECT();
- HANDLE_UNBLOCK_INTERRUPTIONS();
- replay_warnings(persistent_script->num_warnings, persistent_script->warnings);
- from_shared_memory = 1;
- }
- /* Fetch jit auto globals used in the script before execution */
- if (persistent_script->ping_auto_globals_mask & ~ZCG(auto_globals_mask)) {
- zend_accel_set_auto_globals(persistent_script->ping_auto_globals_mask & ~ZCG(auto_globals_mask));
- }
- return zend_accel_load_script(persistent_script, from_shared_memory);
- }
- static zend_always_inline zend_inheritance_cache_entry* zend_accel_inheritance_cache_find(zend_inheritance_cache_entry *entry, zend_class_entry *ce, zend_class_entry *parent, zend_class_entry **traits_and_interfaces, bool *needs_autoload_ptr)
- {
- uint32_t i;
- ZEND_ASSERT(ce->ce_flags & ZEND_ACC_IMMUTABLE);
- ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_LINKED));
- while (entry) {
- bool found = 1;
- bool needs_autoload = 0;
- if (entry->parent != parent) {
- found = 0;
- } else {
- for (i = 0; i < ce->num_traits + ce->num_interfaces; i++) {
- if (entry->traits_and_interfaces[i] != traits_and_interfaces[i]) {
- found = 0;
- break;
- }
- }
- if (found && entry->dependencies) {
- for (i = 0; i < entry->dependencies_count; i++) {
- zend_class_entry *ce = zend_lookup_class_ex(entry->dependencies[i].name, NULL, ZEND_FETCH_CLASS_NO_AUTOLOAD);
- if (ce != entry->dependencies[i].ce) {
- if (!ce) {
- needs_autoload = 1;
- } else {
- found = 0;
- break;
- }
- }
- }
- }
- }
- if (found) {
- *needs_autoload_ptr = needs_autoload;
- return entry;
- }
- entry = entry->next;
- }
- return NULL;
- }
- static zend_class_entry* zend_accel_inheritance_cache_get(zend_class_entry *ce, zend_class_entry *parent, zend_class_entry **traits_and_interfaces)
- {
- uint32_t i;
- bool needs_autoload;
- zend_inheritance_cache_entry *entry = ce->inheritance_cache;
- while (entry) {
- entry = zend_accel_inheritance_cache_find(entry, ce, parent, traits_and_interfaces, &needs_autoload);
- if (entry) {
- if (!needs_autoload) {
- replay_warnings(entry->num_warnings, entry->warnings);
- if (ZCSG(map_ptr_last) > CG(map_ptr_last)) {
- zend_map_ptr_extend(ZCSG(map_ptr_last));
- }
- ce = entry->ce;
- if (ZSTR_HAS_CE_CACHE(ce->name)) {
- ZSTR_SET_CE_CACHE_EX(ce->name, ce, 0);
- }
- return ce;
- }
- for (i = 0; i < entry->dependencies_count; i++) {
- zend_class_entry *ce = zend_lookup_class_ex(entry->dependencies[i].name, NULL, 0);
- if (ce == NULL) {
- return NULL;
- }
- }
- }
- }
- return NULL;
- }
- static zend_class_entry* zend_accel_inheritance_cache_add(zend_class_entry *ce, zend_class_entry *proto, zend_class_entry *parent, zend_class_entry **traits_and_interfaces, HashTable *dependencies)
- {
- zend_persistent_script dummy;
- size_t size;
- uint32_t i;
- bool needs_autoload;
- zend_class_entry *new_ce;
- zend_inheritance_cache_entry *entry;
- ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_IMMUTABLE));
- ZEND_ASSERT(ce->ce_flags & ZEND_ACC_LINKED);
- if (!ZCG(accelerator_enabled) ||
- (ZCSG(restart_in_progress) && accel_restart_is_active())) {
- return NULL;
- }
- if (traits_and_interfaces && dependencies) {
- for (i = 0; i < proto->num_traits + proto->num_interfaces; i++) {
- if (traits_and_interfaces[i]) {
- zend_hash_del(dependencies, traits_and_interfaces[i]->name);
- }
- }
- }
- SHM_UNPROTECT();
- zend_shared_alloc_lock();
- entry = ce->inheritance_cache;
- while (entry) {
- entry = zend_accel_inheritance_cache_find(entry, ce, parent, traits_and_interfaces, &needs_autoload);
- if (entry) {
- if (!needs_autoload) {
- zend_shared_alloc_unlock();
- SHM_PROTECT();
- zend_map_ptr_extend(ZCSG(map_ptr_last));
- return entry->ce;
- }
- ZEND_ASSERT(0); // entry = entry->next; // This shouldn't be posible ???
- }
- }
- zend_shared_alloc_init_xlat_table();
- memset(&dummy, 0, sizeof(dummy));
- dummy.size = ZEND_ALIGNED_SIZE(
- sizeof(zend_inheritance_cache_entry) -
- sizeof(void*) +
- (sizeof(void*) * (proto->num_traits + proto->num_interfaces)));
- if (dependencies) {
- dummy.size += ZEND_ALIGNED_SIZE(zend_hash_num_elements(dependencies) * sizeof(zend_class_dependency));
- }
- ZCG(current_persistent_script) = &dummy;
- zend_persist_class_entry_calc(ce);
- zend_persist_warnings_calc(EG(num_errors), EG(errors));
- size = dummy.size;
- zend_shared_alloc_clear_xlat_table();
- #if ZEND_MM_ALIGNMENT < 8
- /* Align to 8-byte boundary */
- ZCG(mem) = zend_shared_alloc(size + 8);
- #else
- ZCG(mem) = zend_shared_alloc(size);
- #endif
- if (!ZCG(mem)) {
- zend_shared_alloc_destroy_xlat_table();
- zend_shared_alloc_unlock();
- SHM_PROTECT();
- return NULL;
- }
- zend_map_ptr_extend(ZCSG(map_ptr_last));
- #if ZEND_MM_ALIGNMENT < 8
- /* Align to 8-byte boundary */
- ZCG(mem) = (void*)(((zend_uintptr_t)ZCG(mem) + 7L) & ~7L);
- #endif
- memset(ZCG(mem), 0, size);
- entry = (zend_inheritance_cache_entry*)ZCG(mem);
- ZCG(mem) = (char*)ZCG(mem) +
- ZEND_ALIGNED_SIZE(
- (sizeof(zend_inheritance_cache_entry) -
- sizeof(void*) +
- (sizeof(void*) * (proto->num_traits + proto->num_interfaces))));
- entry->parent = parent;
- for (i = 0; i < proto->num_traits + proto->num_interfaces; i++) {
- entry->traits_and_interfaces[i] = traits_and_interfaces[i];
- }
- if (dependencies && zend_hash_num_elements(dependencies)) {
- zend_string *dep_name;
- zend_class_entry *dep_ce;
- i = 0;
- entry->dependencies_count = zend_hash_num_elements(dependencies);
- entry->dependencies = (zend_class_dependency*)ZCG(mem);
- ZEND_HASH_FOREACH_STR_KEY_PTR(dependencies, dep_name, dep_ce) {
- #if ZEND_DEBUG
- ZEND_ASSERT(zend_accel_in_shm(dep_name));
- #endif
- entry->dependencies[i].name = dep_name;
- entry->dependencies[i].ce = dep_ce;
- i++;
- } ZEND_HASH_FOREACH_END();
- ZCG(mem) = (char*)ZCG(mem) + zend_hash_num_elements(dependencies) * sizeof(zend_class_dependency);
- }
- entry->ce = new_ce = zend_persist_class_entry(ce);
- zend_update_parent_ce(new_ce);
- entry->num_warnings = EG(num_errors);
- entry->warnings = zend_persist_warnings(EG(num_errors), EG(errors));
- entry->next = proto->inheritance_cache;
- proto->inheritance_cache = entry;
- EG(num_errors) = 0;
- EG(errors) = NULL;
- ZCSG(map_ptr_last) = CG(map_ptr_last);
- zend_shared_alloc_destroy_xlat_table();
- zend_shared_alloc_unlock();
- SHM_PROTECT();
- /* Consistency check */
- if ((char*)entry + size != (char*)ZCG(mem)) {
- zend_accel_error(
- ((char*)entry + size < (char*)ZCG(mem)) ? ACCEL_LOG_ERROR : ACCEL_LOG_WARNING,
- "Internal error: wrong class size calculation: %s start=" ZEND_ADDR_FMT ", end=" ZEND_ADDR_FMT ", real=" ZEND_ADDR_FMT "\n",
- ZSTR_VAL(ce->name),
- (size_t)entry,
- (size_t)((char *)entry + size),
- (size_t)ZCG(mem));
- }
- zend_map_ptr_extend(ZCSG(map_ptr_last));
- return new_ce;
- }
- #ifdef ZEND_WIN32
- static int accel_gen_uname_id(void)
- {
- PHP_MD5_CTX ctx;
- unsigned char digest[16];
- wchar_t uname[UNLEN + 1];
- DWORD unsize = UNLEN;
- if (!GetUserNameW(uname, &unsize)) {
- return FAILURE;
- }
- PHP_MD5Init(&ctx);
- PHP_MD5Update(&ctx, (void *) uname, (unsize - 1) * sizeof(wchar_t));
- PHP_MD5Update(&ctx, ZCG(accel_directives).cache_id, strlen(ZCG(accel_directives).cache_id));
- PHP_MD5Final(digest, &ctx);
- php_hash_bin2hex(accel_uname_id, digest, sizeof digest);
- return SUCCESS;
- }
- #endif
- /* zend_stream_open_function() replacement for PHP 5.3 and above */
- static zend_result persistent_stream_open_function(zend_file_handle *handle)
- {
- if (ZCG(cache_persistent_script)) {
- /* check if callback is called from include_once or it's a main request */
- if ((!EG(current_execute_data) &&
- handle->primary_script &&
- ZCG(cache_opline) == NULL) ||
- (EG(current_execute_data) &&
- EG(current_execute_data)->func &&
- ZEND_USER_CODE(EG(current_execute_data)->func->common.type) &&
- ZCG(cache_opline) == EG(current_execute_data)->opline)) {
- /* we are in include_once or FastCGI request */
- handle->opened_path = zend_string_copy(ZCG(cache_persistent_script)->script.filename);
- return SUCCESS;
- }
- ZCG(cache_opline) = NULL;
- ZCG(cache_persistent_script) = NULL;
- }
- return accelerator_orig_zend_stream_open_function(handle);
- }
- /* zend_resolve_path() replacement for PHP 5.3 and above */
- static zend_string* persistent_zend_resolve_path(zend_string *filename)
- {
- if (!file_cache_only &&
- ZCG(accelerator_enabled)) {
- /* check if callback is called from include_once or it's a main request */
- if ((!EG(current_execute_data)) ||
- (EG(current_execute_data) &&
- EG(current_execute_data)->func &&
- ZEND_USER_CODE(EG(current_execute_data)->func->common.type) &&
- EG(current_execute_data)->opline->opcode == ZEND_INCLUDE_OR_EVAL &&
- (EG(current_execute_data)->opline->extended_value == ZEND_INCLUDE_ONCE ||
- EG(current_execute_data)->opline->extended_value == ZEND_REQUIRE_ONCE))) {
- /* we are in include_once or FastCGI request */
- zend_string *resolved_path;
- zend_string *key = NULL;
- if (!ZCG(accel_directives).revalidate_path) {
- /* lookup by "not-real" path */
- key = accel_make_persistent_key(filename);
- if (key) {
- zend_accel_hash_entry *bucket = zend_accel_hash_find_entry(&ZCSG(hash), key);
- if (bucket != NULL) {
- zend_persistent_script *persistent_script = (zend_persistent_script *)bucket->data;
- if (!persistent_script->corrupted) {
- ZCG(cache_opline) = EG(current_execute_data) ? EG(current_execute_data)->opline : NULL;
- ZCG(cache_persistent_script) = persistent_script;
- return zend_string_copy(persistent_script->script.filename);
- }
- }
- } else {
- ZCG(cache_opline) = NULL;
- ZCG(cache_persistent_script) = NULL;
- return accelerator_orig_zend_resolve_path(filename);
- }
- }
- /* find the full real path */
- resolved_path = accelerator_orig_zend_resolve_path(filename);
- if (resolved_path) {
- /* lookup by real path */
- zend_accel_hash_entry *bucket = zend_accel_hash_find_entry(&ZCSG(hash), resolved_path);
- if (bucket) {
- zend_persistent_script *persistent_script = (zend_persistent_script *)bucket->data;
- if (!persistent_script->corrupted) {
- if (key) {
- /* add another "key" for the same bucket */
- HANDLE_BLOCK_INTERRUPTIONS();
- SHM_UNPROTECT();
- zend_shared_alloc_lock();
- zend_accel_add_key(key, bucket);
- zend_shared_alloc_unlock();
- SHM_PROTECT();
- HANDLE_UNBLOCK_INTERRUPTIONS();
- } else {
- ZSTR_LEN(&ZCG(key)) = 0;
- }
- ZCG(cache_opline) = EG(current_execute_data) ? EG(current_execute_data)->opline : NULL;
- ZCG(cache_persistent_script) = persistent_script;
- return resolved_path;
- }
- }
- }
- ZCG(cache_opline) = NULL;
- ZCG(cache_persistent_script) = NULL;
- return resolved_path;
- }
- }
- ZCG(cache_opline) = NULL;
- ZCG(cache_persistent_script) = NULL;
- return accelerator_orig_zend_resolve_path(filename);
- }
- static void zend_reset_cache_vars(void)
- {
- ZSMMG(memory_exhausted) = 0;
- ZCSG(hits) = 0;
- ZCSG(misses) = 0;
- ZCSG(blacklist_misses) = 0;
- ZSMMG(wasted_shared_memory) = 0;
- ZCSG(restart_pending) = 0;
- ZCSG(force_restart_time) = 0;
- ZCSG(map_ptr_last) = CG(map_ptr_last);
- }
- static void accel_reset_pcre_cache(void)
- {
- Bucket *p;
- if (PCRE_G(per_request_cache)) {
- return;
- }
- ZEND_HASH_FOREACH_BUCKET(&PCRE_G(pcre_cache), p) {
- /* Remove PCRE cache entries with inconsistent keys */
- if (zend_accel_in_shm(p->key)) {
- p->key = NULL;
- zend_hash_del_bucket(&PCRE_G(pcre_cache), p);
- }
- } ZEND_HASH_FOREACH_END();
- }
- zend_result accel_activate(INIT_FUNC_ARGS)
- {
- if (!ZCG(enabled) || !accel_startup_ok) {
- ZCG(accelerator_enabled) = 0;
- return SUCCESS;
- }
- /* PHP-5.4 and above return "double", but we use 1 sec precision */
- ZCG(auto_globals_mask) = 0;
- ZCG(request_time) = (time_t)sapi_get_request_time();
- ZCG(cache_opline) = NULL;
- ZCG(cache_persistent_script) = NULL;
- ZCG(include_path_key_len) = 0;
- ZCG(include_path_check) = 1;
- ZCG(cwd) = NULL;
- ZCG(cwd_key_len) = 0;
- ZCG(cwd_check) = 1;
- if (file_cache_only) {
- ZCG(accelerator_enabled) = 0;
- return SUCCESS;
- }
- #ifndef ZEND_WIN32
- if (ZCG(accel_directives).validate_root) {
- struct stat buf;
- if (stat("/", &buf) != 0) {
- ZCG(root_hash) = 0;
- } else {
- ZCG(root_hash) = buf.st_ino;
- if (sizeof(buf.st_ino) > sizeof(ZCG(root_hash))) {
- if (ZCG(root_hash) != buf.st_ino) {
- zend_string *key = zend_string_init("opcache.enable", sizeof("opcache.enable")-1, 0);
- zend_alter_ini_entry_chars(key, "0", 1, ZEND_INI_SYSTEM, ZEND_INI_STAGE_RUNTIME);
- zend_string_release_ex(key, 0);
- zend_accel_error(ACCEL_LOG_WARNING, "Can't cache files in chroot() directory with too big inode");
- return SUCCESS;
- }
- }
- }
- } else {
- ZCG(root_hash) = 0;
- }
- #endif
- HANDLE_BLOCK_INTERRUPTIONS();
- SHM_UNPROTECT();
- if (ZCG(counted)) {
- #ifdef ZTS
- zend_accel_error(ACCEL_LOG_WARNING, "Stuck count for thread id %lu", (unsigned long) tsrm_thread_id());
- #else
- zend_accel_error(ACCEL_LOG_WARNING, "Stuck count for pid %d", getpid());
- #endif
- accel_unlock_all();
- ZCG(counted) = 0;
- }
- if (ZCSG(restart_pending)) {
- zend_shared_alloc_lock();
- if (ZCSG(restart_pending) != 0) { /* check again, to ensure that the cache wasn't already cleaned by another process */
- if (accel_is_inactive() == SUCCESS) {
- zend_accel_error(ACCEL_LOG_DEBUG, "Restarting!");
- ZCSG(restart_pending) = 0;
- switch ZCSG(restart_reason) {
- case ACCEL_RESTART_OOM:
- ZCSG(oom_restarts)++;
- break;
- case ACCEL_RESTART_HASH:
- ZCSG(hash_restarts)++;
- break;
- case ACCEL_RESTART_USER:
- ZCSG(manual_restarts)++;
- break;
- }
- accel_restart_enter();
- zend_map_ptr_reset();
- zend_reset_cache_vars();
- zend_accel_hash_clean(&ZCSG(hash));
- if (ZCG(accel_directives).interned_strings_buffer) {
- accel_interned_strings_restore_state();
- }
- zend_shared_alloc_restore_state();
- if (ZCSG(preload_script)) {
- preload_restart();
- }
- #ifdef HAVE_JIT
- zend_jit_restart();
- #endif
- ZCSG(accelerator_enabled) = ZCSG(cache_status_before_restart);
- if (ZCSG(last_restart_time) < ZCG(request_time)) {
- ZCSG(last_restart_time) = ZCG(request_time);
- } else {
- ZCSG(last_restart_time)++;
- }
- accel_restart_leave();
- }
- }
- zend_shared_alloc_unlock();
- }
- ZCG(accelerator_enabled) = ZCSG(accelerator_enabled);
- SHM_PROTECT();
- HANDLE_UNBLOCK_INTERRUPTIONS();
- if (ZCG(accelerator_enabled) && ZCSG(last_restart_time) != ZCG(last_restart_time)) {
- /* SHM was reinitialized. */
- ZCG(last_restart_time) = ZCSG(last_restart_time);
- /* Reset in-process realpath cache */
- realpath_cache_clean();
- accel_reset_pcre_cache();
- ZCG(pcre_reseted) = 0;
- } else if (!ZCG(accelerator_enabled) && !ZCG(pcre_reseted)) {
- accel_reset_pcre_cache();
- ZCG(pcre_reseted) = 1;
- }
- #ifdef HAVE_JIT
- zend_jit_activate();
- #endif
- if (ZCSG(preload_script)) {
- preload_activate();
- }
- return SUCCESS;
- }
- #ifdef HAVE_JIT
- void accel_deactivate(void)
- {
- zend_jit_deactivate();
- }
- #endif
- zend_result accel_post_deactivate(void)
- {
- if (ZCG(cwd)) {
- zend_string_release_ex(ZCG(cwd), 0);
- ZCG(cwd) = NULL;
- }
- if (!ZCG(enabled) || !accel_startup_ok) {
- return SUCCESS;
- }
- zend_shared_alloc_safe_unlock(); /* be sure we didn't leave cache locked */
- accel_unlock_all();
- ZCG(counted) = 0;
- return SUCCESS;
- }
- static int accelerator_remove_cb(zend_extension *element1, zend_extension *element2)
- {
- (void)element2; /* keep the compiler happy */
- if (!strcmp(element1->name, ACCELERATOR_PRODUCT_NAME )) {
- element1->startup = NULL;
- #if 0
- /* We have to call shutdown callback it to free TS resources */
- element1->shutdown = NULL;
- #endif
- element1->activate = NULL;
- element1->deactivate = NULL;
- element1->op_array_handler = NULL;
- #ifdef __DEBUG_MESSAGES__
- fprintf(stderr, ACCELERATOR_PRODUCT_NAME " is disabled: %s\n", (zps_failure_reason ? zps_failure_reason : "unknown error"));
- fflush(stderr);
- #endif
- }
- return 0;
- }
- static void zps_startup_failure(char *reason, char *api_reason, int (*cb)(zend_extension *, zend_extension *))
- {
- accel_startup_ok = 0;
- zps_failure_reason = reason;
- zps_api_failure_reason = api_reason?api_reason:reason;
- zend_llist_del_element(&zend_extensions, NULL, (int (*)(void *, void *))cb);
- }
- static inline int accel_find_sapi(void)
- {
- static const char *supported_sapis[] = {
- "apache",
- "fastcgi",
- "cli-server",
- "cgi-fcgi",
- "fpm-fcgi",
- "fpmi-fcgi",
- "apache2handler",
- "litespeed",
- "uwsgi",
- NULL
- };
- const char **sapi_name;
- if (sapi_module.name) {
- for (sapi_name = supported_sapis; *sapi_name; sapi_name++) {
- if (strcmp(sapi_module.name, *sapi_name) == 0) {
- return SUCCESS;
- }
- }
- if (ZCG(accel_directives).enable_cli && (
- strcmp(sapi_module.name, "cli") == 0
- || strcmp(sapi_module.name, "phpdbg") == 0)) {
- return SUCCESS;
- }
- }
- return FAILURE;
- }
- static int zend_accel_init_shm(void)
- {
- int i;
- zend_shared_alloc_lock();
- if (ZCG(accel_directives).interned_strings_buffer) {
- accel_shared_globals = zend_shared_alloc((ZCG(accel_directives).interned_strings_buffer * 1024 * 1024));
- } else {
- /* Make sure there is always at least one interned string hash slot,
- * so the table can be queried unconditionally. */
- accel_shared_globals = zend_shared_alloc(sizeof(zend_accel_shared_globals) + sizeof(uint32_t));
- }
- if (!accel_shared_globals) {
- zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Insufficient shared memory!");
- zend_shared_alloc_unlock();
- return FAILURE;
- }
- memset(accel_shared_globals, 0, sizeof(zend_accel_shared_globals));
- ZSMMG(app_shared_globals) = accel_shared_globals;
- zend_accel_hash_init(&ZCSG(hash), ZCG(accel_directives).max_accelerated_files);
- if (ZCG(accel_directives).interned_strings_buffer) {
- uint32_t hash_size;
- /* must be a power of two */
- hash_size = ZCG(accel_directives).interned_strings_buffer * (32 * 1024);
- hash_size |= (hash_size >> 1);
- hash_size |= (hash_size >> 2);
- hash_size |= (hash_size >> 4);
- hash_size |= (hash_size >> 8);
- hash_size |= (hash_size >> 16);
- ZCSG(interned_strings).nTableMask = hash_size << 2;
- ZCSG(interned_strings).nNumOfElements = 0;
- ZCSG(interned_strings).start =
- (zend_string*)((char*)&ZCSG(interned_strings) +
- sizeof(zend_string_table) +
- ((hash_size + 1) * sizeof(uint32_t))) +
- 8;
- ZCSG(interned_strings).top =
- ZCSG(interned_strings).start;
- ZCSG(interned_strings).end =
- (zend_string*)((char*)accel_shared_globals +
- ZCG(accel_directives).interned_strings_buffer * 1024 * 1024);
- ZCSG(interned_strings).saved_top = NULL;
- memset((char*)&ZCSG(interned_strings) + sizeof(zend_string_table),
- STRTAB_INVALID_POS,
- (char*)ZCSG(interned_strings).start -
- ((char*)&ZCSG(interned_strings) + sizeof(zend_string_table)));
- } else {
- *STRTAB_HASH_TO_SLOT(&ZCSG(interned_strings), 0) = STRTAB_INVALID_POS;
- }
- /* We can reuse init_interned_string_for_php for the "init_existing_interned" case,
- * because the function does not create new interned strings at runtime. */
- zend_interned_strings_set_request_storage_handlers(
- accel_new_interned_string_for_php,
- accel_init_interned_string_for_php,
- accel_init_interned_string_for_php);
- zend_reset_cache_vars();
- ZCSG(oom_restarts) = 0;
- ZCSG(hash_restarts) = 0;
- ZCSG(manual_restarts) = 0;
- ZCSG(accelerator_enabled) = 1;
- ZCSG(start_time) = zend_accel_get_time();
- ZCSG(last_restart_time) = 0;
- ZCSG(restart_in_progress) = 0;
- for (i = 0; i < -HT_MIN_MASK; i++) {
- ZCSG(uninitialized_bucket)[i] = HT_INVALID_IDX;
- }
- zend_shared_alloc_unlock();
- return SUCCESS;
- }
- static void accel_globals_ctor(zend_accel_globals *accel_globals)
- {
- #if defined(COMPILE_DL_OPCACHE) && defined(ZTS)
- ZEND_TSRMLS_CACHE_UPDATE();
- #endif
- memset(accel_globals, 0, sizeof(zend_accel_globals));
- }
- #ifdef HAVE_HUGE_CODE_PAGES
- # ifndef _WIN32
- # include <sys/mman.h>
- # ifndef MAP_ANON
- # ifdef MAP_ANONYMOUS
- # define MAP_ANON MAP_ANONYMOUS
- # endif
- # endif
- # ifndef MAP_FAILED
- # define MAP_FAILED ((void*)-1)
- # endif
- # ifdef MAP_ALIGNED_SUPER
- # include <sys/types.h>
- # include <sys/sysctl.h>
- # include <sys/user.h>
- # define MAP_HUGETLB MAP_ALIGNED_SUPER
- # endif
- # endif
- # if defined(MAP_HUGETLB) || defined(MADV_HUGEPAGE)
- static int accel_remap_huge_pages(void *start, size_t size, size_t real_size, const char *name, size_t offset)
- {
- void *ret = MAP_FAILED;
- void *mem;
- mem = mmap(NULL, size,
- PROT_READ | PROT_WRITE,
- MAP_PRIVATE | MAP_ANONYMOUS,
- -1, 0);
- if (mem == MAP_FAILED) {
- zend_error(E_WARNING,
- ACCELERATOR_PRODUCT_NAME " huge_code_pages: mmap failed: %s (%d)",
- strerror(errno), errno);
- return -1;
- }
- memcpy(mem, start, real_size);
- # ifdef MAP_HUGETLB
- ret = mmap(start, size,
- PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED | MAP_HUGETLB,
- -1, 0);
- # endif
- if (ret == MAP_FAILED) {
- ret = mmap(start, size,
- PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
- -1, 0);
- /* this should never happen? */
- ZEND_ASSERT(ret != MAP_FAILED);
- # ifdef MADV_HUGEPAGE
- if (-1 == madvise(start, size, MADV_HUGEPAGE)) {
- memcpy(start, mem, real_size);
- mprotect(start, size, PROT_READ | PROT_EXEC);
- munmap(mem, size);
- zend_error(E_WARNING,
- ACCELERATOR_PRODUCT_NAME " huge_code_pages: madvise(HUGEPAGE) failed: %s (%d)",
- strerror(errno), errno);
- return -1;
- }
- # else
- memcpy(start, mem, real_size);
- mprotect(start, size, PROT_READ | PROT_EXEC);
- munmap(mem, size);
- zend_error(E_WARNING,
- ACCELERATOR_PRODUCT_NAME " huge_code_pages: mmap(HUGETLB) failed: %s (%d)",
- strerror(errno), errno);
- return -1;
- # endif
- }
- if (ret == start) {
- memcpy(start, mem, real_size);
- mprotect(start, size, PROT_READ | PROT_EXEC);
- }
- munmap(mem, size);
- return (ret == start) ? 0 : -1;
- }
- static void accel_move_code_to_huge_pages(void)
- {
- #if defined(__linux__)
- FILE *f;
- long unsigned int huge_page_size = 2 * 1024 * 1024;
- f = fopen("/proc/self/maps", "r");
- if (f) {
- long unsigned int start, end, offset, inode;
- char perm[5], dev[10], name[MAXPATHLEN];
- int ret;
- while (1) {
- ret = fscanf(f, "%lx-%lx %4s %lx %9s %ld %s\n", &start, &end, perm, &offset, dev, &inode, name);
- if (ret == 7) {
- if (perm[0] == 'r' && perm[1] == '-' && perm[2] == 'x' && name[0] == '/') {
- long unsigned int seg_start = ZEND_MM_ALIGNED_SIZE_EX(start, huge_page_size);
- long unsigned int seg_end = (end & ~(huge_page_size-1L));
- long unsigned int real_end;
- ret = fscanf(f, "%lx-", &start);
- if (ret == 1 && start == seg_end + huge_page_size) {
- real_end = end;
- seg_end = start;
- } else {
- real_end = seg_end;
- }
- if (seg_end > seg_start) {
- zend_accel_error(ACCEL_LOG_DEBUG, "remap to huge page %lx-%lx %s \n", seg_start, seg_end, name);
- accel_remap_huge_pages((void*)seg_start, seg_end - seg_start, real_end - seg_start, name, offset + seg_start - start);
- }
- break;
- }
- } else {
- break;
- }
- }
- fclose(f);
- }
- #elif defined(__FreeBSD__)
- size_t s = 0;
- int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_VMMAP, getpid()};
- long unsigned int huge_page_size = 2 * 1024 * 1024;
- if (sysctl(mib, 4, NULL, &s, NULL, 0) == 0) {
- s = s * 4 / 3;
- void *addr = mmap(NULL, s, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON, -1, 0);
- if (addr != MAP_FAILED) {
- if (sysctl(mib, 4, addr, &s, NULL, 0) == 0) {
- uintptr_t start = (uintptr_t)addr;
- uintptr_t end = start + s;
- while (start < end) {
- struct kinfo_vmentry *entry = (struct kinfo_vmentry *)start;
- size_t sz = entry->kve_structsize;
- if (sz == 0) {
- break;
- }
- int permflags = entry->kve_protection;
- if ((permflags & KVME_PROT_READ) && !(permflags & KVME_PROT_WRITE) &&
- (permflags & KVME_PROT_EXEC) && entry->kve_path[0] != '\0') {
- long unsigned int seg_start = ZEND_MM_ALIGNED_SIZE_EX(start, huge_page_size);
- long unsigned int seg_end = (end & ~(huge_page_size-1L));
- if (seg_end > seg_start) {
- zend_accel_error(ACCEL_LOG_DEBUG, "remap to huge page %lx-%lx %s \n", seg_start, seg_end, entry->kve_path);
- accel_remap_huge_pages((void*)seg_start, seg_end - seg_start, seg_end - seg_start, entry->kve_path, entry->kve_offset + seg_start - start);
- // First relevant segment found is our binary
- break;
- }
- }
- start += sz;
- }
- }
- munmap(addr, s);
- }
- }
- #endif
- }
- # else
- static void accel_move_code_to_huge_pages(void)
- {
- zend_error(E_WARNING, ACCELERATOR_PRODUCT_NAME ": opcache.huge_code_pages has no affect as huge page is not supported");
- return;
- }
- # endif /* defined(MAP_HUGETLB) || defined(MADV_HUGEPAGE) */
- #endif /* HAVE_HUGE_CODE_PAGES */
- static int accel_startup(zend_extension *extension)
- {
- #ifdef ZTS
- accel_globals_id = ts_allocate_id(&accel_globals_id, sizeof(zend_accel_globals), (ts_allocate_ctor) accel_globals_ctor, NULL);
- #else
- accel_globals_ctor(&accel_globals);
- #endif
- #ifdef HAVE_JIT
- zend_jit_init();
- #endif
- #ifdef ZEND_WIN32
- # if !defined(__has_feature) || !__has_feature(address_sanitizer)
- _setmaxstdio(2048); /* The default configuration is limited to 512 stdio files */
- # endif
- #endif
- if (start_accel_module() == FAILURE) {
- accel_startup_ok = 0;
- zend_error(E_WARNING, ACCELERATOR_PRODUCT_NAME ": module registration failed!");
- return FAILURE;
- }
- #ifdef ZEND_WIN32
- if (UNEXPECTED(accel_gen_uname_id() == FAILURE)) {
- zps_startup_failure("Unable to get user name", NULL, accelerator_remove_cb);
- return SUCCESS;
- }
- #endif
- #ifdef HAVE_HUGE_CODE_PAGES
- if (ZCG(accel_directives).huge_code_pages &&
- (strcmp(sapi_module.name, "cli") == 0 ||
- strcmp(sapi_module.name, "cli-server") == 0 ||
- strcmp(sapi_module.name, "cgi-fcgi") == 0 ||
- strcmp(sapi_module.name, "fpm-fcgi") == 0)) {
- accel_move_code_to_huge_pages();
- }
- #endif
- /* no supported SAPI found - disable acceleration and stop initialization */
- if (accel_find_sapi() == FAILURE) {
- accel_startup_ok = 0;
- if (!ZCG(accel_directives).enable_cli &&
- strcmp(sapi_module.name, "cli") == 0) {
- zps_startup_failure("Opcode Caching is disabled for CLI", NULL, accelerator_remove_cb);
- } else {
- zps_startup_failure("Opcode Caching is only supported in Apache, FPM, FastCGI and LiteSpeed SAPIs", NULL, accelerator_remove_cb);
- }
- return SUCCESS;
- }
- if (ZCG(enabled) == 0) {
- return SUCCESS ;
- }
- orig_post_startup_cb = zend_post_startup_cb;
- zend_post_startup_cb = accel_post_startup;
- /* Prevent unloading */
- extension->handle = 0;
- return SUCCESS;
- }
- static zend_result accel_post_startup(void)
- {
- zend_function *func;
- zend_ini_entry *ini_entry;
- if (orig_post_startup_cb) {
- zend_result (*cb)(void) = orig_post_startup_cb;
- orig_post_startup_cb = NULL;
- if (cb() != SUCCESS) {
- return FAILURE;
- }
- }
- /********************************************/
- /* End of non-SHM dependent initializations */
- /********************************************/
- file_cache_only = ZCG(accel_directives).file_cache_only;
- if (!file_cache_only) {
- size_t shm_size = ZCG(accel_directives).memory_consumption;
- #ifdef HAVE_JIT
- size_t jit_size = 0;
- bool reattached = 0;
- if (JIT_G(enabled) && JIT_G(buffer_size)
- && zend_jit_check_support() == SUCCESS) {
- size_t page_size;
- page_size = zend_get_page_size();
- if (!page_size && (page_size & (page_size - 1))) {
- zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Failure to initialize shared memory structures - can't get page size.");
- abort();
- }
- jit_size = JIT_G(buffer_size);
- jit_size = ZEND_MM_ALIGNED_SIZE_EX(jit_size, page_size);
- shm_size += jit_size;
- }
- switch (zend_shared_alloc_startup(shm_size, jit_size)) {
- #else
- switch (zend_shared_alloc_startup(shm_size, 0)) {
- #endif
- case ALLOC_SUCCESS:
- if (zend_accel_init_shm() == FAILURE) {
- accel_startup_ok = 0;
- return FAILURE;
- }
- break;
- case ALLOC_FAILURE:
- accel_startup_ok = 0;
- zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Failure to initialize shared memory structures - probably not enough shared memory.");
- return SUCCESS;
- case SUCCESSFULLY_REATTACHED:
- #ifdef HAVE_JIT
- reattached = 1;
- #endif
- zend_shared_alloc_lock();
- accel_shared_globals = (zend_accel_shared_globals *) ZSMMG(app_shared_globals);
- zend_interned_strings_set_request_storage_handlers(
- accel_new_interned_string_for_php,
- accel_init_interned_string_for_php,
- accel_init_interned_string_for_php);
- zend_shared_alloc_unlock();
- break;
- case FAILED_REATTACHED:
- accel_startup_ok = 0;
- zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Failure to initialize shared memory structures - can not reattach to exiting shared memory.");
- return SUCCESS;
- break;
- #if ENABLE_FILE_CACHE_FALLBACK
- case ALLOC_FALLBACK:
- zend_shared_alloc_lock();
- file_cache_only = 1;
- fallback_process = 1;
- zend_shared_alloc_unlock();
- goto file_cache_fallback;
- break;
- #endif
- }
- /* from this point further, shared memory is supposed to be OK */
- /* remember the last restart time in the process memory */
- ZCG(last_restart_time) = ZCSG(last_restart_time);
- zend_shared_alloc_lock();
- #ifdef HAVE_JIT
- if (JIT_G(enabled)) {
- if (JIT_G(buffer_size) == 0
- || !ZSMMG(reserved)
- || zend_jit_startup(ZSMMG(reserved), jit_size, reattached) != SUCCESS) {
- JIT_G(enabled) = 0;
- JIT_G(on) = 0;
- }
- }
- #endif
- zend_shared_alloc_save_state();
- zend_shared_alloc_unlock();
- SHM_PROTECT();
- } else if (!ZCG(accel_directives).file_cache) {
- accel_startup_ok = 0;
- zend_accel_error_noreturn(ACCEL_LOG_FATAL, "opcache.file_cache_only is set without a proper setting of opcache.file_cache");
- return SUCCESS;
- } else {
- #ifdef HAVE_JIT
- JIT_G(enabled) = 0;
- JIT_G(on) = 0;
- #endif
- accel_shared_globals = calloc(1, sizeof(zend_accel_shared_globals));
- }
- #if ENABLE_FILE_CACHE_FALLBACK
- file_cache_fallback:
- #endif
- /* Override compiler */
- accelerator_orig_compile_file = zend_compile_file;
- zend_compile_file = persistent_compile_file;
- /* Override stream opener function (to eliminate open() call caused by
- * include/require statements ) */
- accelerator_orig_zend_stream_open_function = zend_stream_open_function;
- zend_stream_open_function = persistent_stream_open_function;
- /* Override path resolver function (to eliminate stat() calls caused by
- * include_once/require_once statements */
- accelerator_orig_zend_resolve_path = zend_resolve_path;
- zend_resolve_path = persistent_zend_resolve_path;
- /* Override chdir() function */
- if ((func = zend_hash_str_find_ptr(CG(function_table), "chdir", sizeof("chdir")-1)) != NULL &&
- func->type == ZEND_INTERNAL_FUNCTION) {
- orig_chdir = func->internal_function.handler;
- func->internal_function.handler = ZEND_FN(accel_chdir);
- }
- ZCG(cwd) = NULL;
- ZCG(include_path) = NULL;
- /* Override "include_path" modifier callback */
- if ((ini_entry = zend_hash_str_find_ptr(EG(ini_directives), "include_path", sizeof("include_path")-1)) != NULL) {
- ZCG(include_path) = ini_entry->value;
- orig_include_path_on_modify = ini_entry->on_modify;
- ini_entry->on_modify = accel_include_path_on_modify;
- }
- accel_startup_ok = 1;
- /* Override file_exists(), is_file() and is_readable() */
- zend_accel_override_file_functions();
- /* Load black list */
- accel_blacklist.entries = NULL;
- if (ZCG(enabled) && accel_startup_ok &&
- ZCG(accel_directives).user_blacklist_filename &&
- *ZCG(accel_directives.user_blacklist_filename)) {
- zend_accel_blacklist_init(&accel_blacklist);
- zend_accel_blacklist_load(&accel_blacklist, ZCG(accel_directives.user_blacklist_filename));
- }
- if (!file_cache_only && ZCG(accel_directives).interned_strings_buffer) {
- accel_use_shm_interned_strings();
- }
- if (accel_finish_startup() != SUCCESS) {
- return FAILURE;
- }
- if (ZCG(enabled) && accel_startup_ok) {
- /* Override inheritance cache callbaks */
- accelerator_orig_inheritance_cache_get = zend_inheritance_cache_get;
- accelerator_orig_inheritance_cache_add = zend_inheritance_cache_add;
- zend_inheritance_cache_get = zend_accel_inheritance_cache_get;
- zend_inheritance_cache_add = zend_accel_inheritance_cache_add;
- }
- return SUCCESS;
- }
- static void (*orig_post_shutdown_cb)(void);
- static void accel_post_shutdown(void)
- {
- zend_shared_alloc_shutdown();
- }
- void accel_shutdown(void)
- {
- zend_ini_entry *ini_entry;
- bool _file_cache_only = 0;
- #ifdef HAVE_JIT
- zend_jit_shutdown();
- #endif
- zend_accel_blacklist_shutdown(&accel_blacklist);
- if (!ZCG(enabled) || !accel_startup_ok) {
- #ifdef ZTS
- ts_free_id(accel_globals_id);
- #endif
- return;
- }
- if (ZCSG(preload_script)) {
- preload_shutdown();
- }
- _file_cache_only = file_cache_only;
- accel_reset_pcre_cache();
- #ifdef ZTS
- ts_free_id(accel_globals_id);
- #endif
- if (!_file_cache_only) {
- /* Delay SHM detach */
- orig_post_shutdown_cb = zend_post_shutdown_cb;
- zend_post_shutdown_cb = accel_post_shutdown;
- }
- zend_compile_file = accelerator_orig_compile_file;
- zend_inheritance_cache_get = accelerator_orig_inheritance_cache_get;
- zend_inheritance_cache_add = accelerator_orig_inheritance_cache_add;
- if ((ini_entry = zend_hash_str_find_ptr(EG(ini_directives), "include_path", sizeof("include_path")-1)) != NULL) {
- ini_entry->on_modify = orig_include_path_on_modify;
- }
- }
- void zend_accel_schedule_restart(zend_accel_restart_reason reason)
- {
- const char *zend_accel_restart_reason_text[ACCEL_RESTART_USER + 1] = {
- "out of memory",
- "hash overflow",
- "user",
- };
- if (ZCSG(restart_pending)) {
- /* don't schedule twice */
- return;
- }
- zend_accel_error(ACCEL_LOG_DEBUG, "Restart Scheduled! Reason: %s",
- zend_accel_restart_reason_text[reason]);
- HANDLE_BLOCK_INTERRUPTIONS();
- SHM_UNPROTECT();
- ZCSG(restart_pending) = 1;
- ZCSG(restart_reason) = reason;
- ZCSG(cache_status_before_restart) = ZCSG(accelerator_enabled);
- ZCSG(accelerator_enabled) = 0;
- if (ZCG(accel_directives).force_restart_timeout) {
- ZCSG(force_restart_time) = zend_accel_get_time() + ZCG(accel_directives).force_restart_timeout;
- } else {
- ZCSG(force_restart_time) = 0;
- }
- SHM_PROTECT();
- HANDLE_UNBLOCK_INTERRUPTIONS();
- }
- /* this is needed because on WIN32 lock is not decreased unless ZCG(counted) is set */
- #ifdef ZEND_WIN32
- #define accel_deactivate_now() ZCG(counted) = 1; accel_deactivate_sub()
- #else
- #define accel_deactivate_now() accel_deactivate_sub()
- #endif
- /* ensures it is OK to read SHM
- if it's not OK (restart in progress) returns FAILURE
- if OK returns SUCCESS
- MUST call accelerator_shm_read_unlock after done lock operations
- */
- int accelerator_shm_read_lock(void)
- {
- if (ZCG(counted)) {
- /* counted means we are holding read lock for SHM, so that nothing bad can happen */
- return SUCCESS;
- } else {
- /* here accelerator is active but we do not hold SHM lock. This means restart was scheduled
- or is in progress now */
- if (accel_activate_add() == FAILURE) { /* acquire usage lock */
- return FAILURE;
- }
- /* Now if we weren't inside restart, restart would not begin until we remove usage lock */
- if (ZCSG(restart_in_progress)) {
- /* we already were inside restart this means it's not safe to touch shm */
- accel_deactivate_now(); /* drop usage lock */
- return FAILURE;
- }
- ZCG(counted) = 1;
- }
- return SUCCESS;
- }
- /* must be called ONLY after SUCCESSFUL accelerator_shm_read_lock */
- void accelerator_shm_read_unlock(void)
- {
- if (!ZCG(counted)) {
- /* counted is 0 - meaning we had to readlock manually, release readlock now */
- accel_deactivate_now();
- }
- }
- /* Preloading */
- static HashTable *preload_scripts = NULL;
- static zend_op_array *(*preload_orig_compile_file)(zend_file_handle *file_handle, int type);
- static void preload_shutdown(void)
- {
- zval *zv;
- #if 0
- if (EG(zend_constants)) {
- ZEND_HASH_REVERSE_FOREACH_VAL(EG(zend_constants), zv) {
- zend_constant *c = Z_PTR_P(zv);
- if (ZEND_CONSTANT_FLAGS(c) & CONST_PERSISTENT) {
- break;
- }
- } ZEND_HASH_FOREACH_END_DEL();
- }
- #endif
- if (EG(function_table)) {
- ZEND_HASH_REVERSE_FOREACH_VAL(EG(function_table), zv) {
- zend_function *func = Z_PTR_P(zv);
- if (func->type == ZEND_INTERNAL_FUNCTION) {
- break;
- }
- } ZEND_HASH_FOREACH_END_DEL();
- }
- if (EG(class_table)) {
- ZEND_HASH_REVERSE_FOREACH_VAL(EG(class_table), zv) {
- zend_class_entry *ce = Z_PTR_P(zv);
- if (ce->type == ZEND_INTERNAL_CLASS) {
- break;
- }
- } ZEND_HASH_FOREACH_END_DEL();
- }
- }
- static void preload_activate(void)
- {
- if (ZCSG(preload_script)->ping_auto_globals_mask & ~ZCG(auto_globals_mask)) {
- zend_accel_set_auto_globals(ZCSG(preload_script)->ping_auto_globals_mask & ~ZCG(auto_globals_mask));
- }
- }
- static void preload_restart(void)
- {
- zend_accel_hash_update(&ZCSG(hash), ZCSG(preload_script)->script.filename, 0, ZCSG(preload_script));
- if (ZCSG(saved_scripts)) {
- zend_persistent_script **p = ZCSG(saved_scripts);
- while (*p) {
- zend_accel_hash_update(&ZCSG(hash), (*p)->script.filename, 0, *p);
- p++;
- }
- }
- }
- static size_t preload_try_strip_filename(zend_string *filename) {
- /*FIXME: better way to hanlde eval()'d code? see COMPILED_STRING_DESCRIPTION_FORMAT */
- if (ZSTR_LEN(filename) > sizeof(" eval()'d code")
- && *(ZSTR_VAL(filename) + ZSTR_LEN(filename) - sizeof(" eval()'d code")) == ':') {
- const char *cfilename = ZSTR_VAL(filename);
- size_t cfilenamelen = ZSTR_LEN(filename) - sizeof(" eval()'d code") - 1 /*:*/;
- while (cfilenamelen && cfilename[--cfilenamelen] != '(');
- return cfilenamelen;
- }
- return 0;
- }
- static void preload_move_user_functions(HashTable *src, HashTable *dst)
- {
- Bucket *p;
- dtor_func_t orig_dtor = src->pDestructor;
- zend_string *filename = NULL;
- int copy = 0;
- src->pDestructor = NULL;
- zend_hash_extend(dst, dst->nNumUsed + src->nNumUsed, 0);
- ZEND_HASH_REVERSE_FOREACH_BUCKET(src, p) {
- zend_function *function = Z_PTR(p->val);
- if (EXPECTED(function->type == ZEND_USER_FUNCTION)) {
- if (function->op_array.filename != filename) {
- filename = function->op_array.filename;
- if (filename) {
- if (!(copy = zend_hash_exists(preload_scripts, filename))) {
- size_t eval_len = preload_try_strip_filename(filename);
- if (eval_len) {
- copy = zend_hash_str_exists(preload_scripts, ZSTR_VAL(filename), eval_len);
- }
- }
- } else {
- copy = 0;
- }
- }
- if (copy) {
- _zend_hash_append_ptr(dst, p->key, function);
- } else {
- orig_dtor(&p->val);
- }
- zend_hash_del_bucket(src, p);
- } else {
- break;
- }
- } ZEND_HASH_FOREACH_END();
- src->pDestructor = orig_dtor;
- }
- static void preload_move_user_classes(HashTable *src, HashTable *dst)
- {
- Bucket *p;
- dtor_func_t orig_dtor = src->pDestructor;
- zend_string *filename = NULL;
- int copy = 0;
- src->pDestructor = NULL;
- zend_hash_extend(dst, dst->nNumUsed + src->nNumUsed, 0);
- ZEND_HASH_FOREACH_BUCKET_FROM(src, p, EG(persistent_classes_count)) {
- zend_class_entry *ce = Z_PTR(p->val);
- ZEND_ASSERT(ce->type == ZEND_USER_CLASS);
- if (ce->info.user.filename != filename) {
- filename = ce->info.user.filename;
- if (filename) {
- if (!(copy = zend_hash_exists(preload_scripts, filename))) {
- size_t eval_len = preload_try_strip_filename(filename);
- if (eval_len) {
- copy = zend_hash_str_exists(preload_scripts, ZSTR_VAL(filename), eval_len);
- }
- }
- } else {
- copy = 0;
- }
- }
- if (copy) {
- _zend_hash_append(dst, p->key, &p->val);
- } else {
- orig_dtor(&p->val);
- }
- zend_hash_del_bucket(src, p);
- } ZEND_HASH_FOREACH_END();
- src->pDestructor = orig_dtor;
- }
- static zend_op_array *preload_compile_file(zend_file_handle *file_handle, int type)
- {
- zend_op_array *op_array = preload_orig_compile_file(file_handle, type);
- if (op_array && op_array->refcount) {
- zend_persistent_script *script;
- script = create_persistent_script();
- script->script.first_early_binding_opline = (uint32_t)-1;
- script->script.filename = zend_string_copy(op_array->filename);
- zend_string_hash_val(script->script.filename);
- script->script.main_op_array = *op_array;
- //??? efree(op_array->refcount);
- op_array->refcount = NULL;
- zend_hash_add_ptr(preload_scripts, script->script.filename, script);
- }
- return op_array;
- }
- static void preload_sort_classes(void *base, size_t count, size_t siz, compare_func_t compare, swap_func_t swp)
- {
- Bucket *b1 = base;
- Bucket *b2;
- Bucket *end = b1 + count;
- Bucket tmp;
- zend_class_entry *ce, *p;
- while (b1 < end) {
- try_again:
- ce = (zend_class_entry*)Z_PTR(b1->val);
- if (ce->parent && (ce->ce_flags & ZEND_ACC_LINKED)) {
- p = ce->parent;
- if (p->type == ZEND_USER_CLASS) {
- b2 = b1 + 1;
- while (b2 < end) {
- if (p == Z_PTR(b2->val)) {
- tmp = *b1;
- *b1 = *b2;
- *b2 = tmp;
- goto try_again;
- }
- b2++;
- }
- }
- }
- if (ce->num_interfaces && (ce->ce_flags & ZEND_ACC_LINKED)) {
- uint32_t i = 0;
- for (i = 0; i < ce->num_interfaces; i++) {
- p = ce->interfaces[i];
- if (p->type == ZEND_USER_CLASS) {
- b2 = b1 + 1;
- while (b2 < end) {
- if (p == Z_PTR(b2->val)) {
- tmp = *b1;
- *b1 = *b2;
- *b2 = tmp;
- goto try_again;
- }
- b2++;
- }
- }
- }
- }
- b1++;
- }
- }
- typedef struct {
- const char *kind;
- const char *name;
- } preload_error;
- static zend_result preload_resolve_deps(preload_error *error, const zend_class_entry *ce)
- {
- memset(error, 0, sizeof(preload_error));
- if (ce->parent_name) {
- zend_string *key = zend_string_tolower(ce->parent_name);
- zend_class_entry *parent = zend_hash_find_ptr(EG(class_table), key);
- zend_string_release(key);
- if (!parent) {
- error->kind = "Unknown parent ";
- error->name = ZSTR_VAL(ce->parent_name);
- return FAILURE;
- }
- }
- if (ce->num_interfaces) {
- for (uint32_t i = 0; i < ce->num_interfaces; i++) {
- zend_class_entry *interface =
- zend_hash_find_ptr(EG(class_table), ce->interface_names[i].lc_name);
- if (!interface) {
- error->kind = "Unknown interface ";
- error->name = ZSTR_VAL(ce->interface_names[i].name);
- return FAILURE;
- }
- }
- }
- if (ce->num_traits) {
- for (uint32_t i = 0; i < ce->num_traits; i++) {
- zend_class_entry *trait =
- zend_hash_find_ptr(EG(class_table), ce->trait_names[i].lc_name);
- if (!trait) {
- error->kind = "Unknown trait ";
- error->name = ZSTR_VAL(ce->trait_names[i].name);
- return FAILURE;
- }
- }
- }
- return SUCCESS;
- }
- static bool preload_try_resolve_constants(zend_class_entry *ce)
- {
- bool ok, changed, was_changed = 0;
- zend_class_constant *c;
- zval *val;
- EG(exception) = (void*)(uintptr_t)-1; /* prevent error reporting */
- do {
- ok = 1;
- changed = 0;
- ZEND_HASH_FOREACH_PTR(&ce->constants_table, c) {
- val = &c->value;
- if (Z_TYPE_P(val) == IS_CONSTANT_AST) {
- if (EXPECTED(zval_update_constant_ex(val, c->ce) == SUCCESS)) {
- was_changed = changed = 1;
- } else {
- ok = 0;
- }
- }
- } ZEND_HASH_FOREACH_END();
- if (ok) {
- ce->ce_flags &= ~ZEND_ACC_HAS_AST_CONSTANTS;
- }
- if (ce->default_properties_count) {
- uint32_t i;
- bool resolved = 1;
- for (i = 0; i < ce->default_properties_count; i++) {
- val = &ce->default_properties_table[i];
- if (Z_TYPE_P(val) == IS_CONSTANT_AST) {
- zend_property_info *prop = ce->properties_info_table[i];
- if (UNEXPECTED(zval_update_constant_ex(val, prop->ce) != SUCCESS)) {
- resolved = ok = 0;
- }
- }
- }
- if (resolved) {
- ce->ce_flags &= ~ZEND_ACC_HAS_AST_PROPERTIES;
- }
- }
- if (ce->default_static_members_count) {
- uint32_t count = ce->parent ? ce->default_static_members_count - ce->parent->default_static_members_count : ce->default_static_members_count;
- bool resolved = 1;
- val = ce->default_static_members_table + ce->default_static_members_count - 1;
- while (count) {
- if (Z_TYPE_P(val) == IS_CONSTANT_AST) {
- if (UNEXPECTED(zval_update_constant_ex(val, ce) != SUCCESS)) {
- resolved = ok = 0;
- }
- }
- val--;
- count--;
- }
- if (resolved) {
- ce->ce_flags &= ~ZEND_ACC_HAS_AST_STATICS;
- }
- }
- } while (changed && !ok);
- EG(exception) = NULL;
- CG(in_compilation) = 0;
- if (ok) {
- ce->ce_flags |= ZEND_ACC_CONSTANTS_UPDATED;
- }
- return ok || was_changed;
- }
- static void (*orig_error_cb)(int type, zend_string *error_filename, const uint32_t error_lineno, zend_string *message);
- static void preload_error_cb(int type, zend_string *error_filename, const uint32_t error_lineno, zend_string *message)
- {
- /* Suppress printing of the error, only bail out for fatal errors. */
- if (type & E_FATAL_ERRORS) {
- zend_bailout();
- }
- }
- /* Remove DECLARE opcodes and dynamic defs. */
- static void preload_remove_declares(zend_op_array *op_array)
- {
- zend_op *opline = op_array->opcodes;
- zend_op *end = opline + op_array->last;
- uint32_t skip_dynamic_func_count = 0;
- zend_string *key;
- zend_op_array *func;
- while (opline != end) {
- switch (opline->opcode) {
- case ZEND_DECLARE_CLASS:
- case ZEND_DECLARE_CLASS_DELAYED:
- key = Z_STR_P(RT_CONSTANT(opline, opline->op1) + 1);
- if (!zend_hash_exists(CG(class_table), key)) {
- MAKE_NOP(opline);
- }
- break;
- case ZEND_DECLARE_FUNCTION:
- opline->op2.num -= skip_dynamic_func_count;
- key = Z_STR_P(RT_CONSTANT(opline, opline->op1));
- func = zend_hash_find_ptr(EG(function_table), key);
- if (func && func == op_array->dynamic_func_defs[opline->op2.num]) {
- zend_op_array **dynamic_func_defs;
- op_array->num_dynamic_func_defs--;
- if (op_array->num_dynamic_func_defs == 0) {
- dynamic_func_defs = NULL;
- } else {
- dynamic_func_defs = emalloc(sizeof(zend_op_array*) * op_array->num_dynamic_func_defs);
- if (opline->op2.num > 0) {
- memcpy(
- dynamic_func_defs,
- op_array->dynamic_func_defs,
- sizeof(zend_op_array*) * opline->op2.num);
- }
- if (op_array->num_dynamic_func_defs - opline->op2.num > 0) {
- memcpy(
- dynamic_func_defs + opline->op2.num,
- op_array->dynamic_func_defs + (opline->op2.num + 1),
- sizeof(zend_op_array*) * (op_array->num_dynamic_func_defs - opline->op2.num));
- }
- }
- efree(op_array->dynamic_func_defs);
- op_array->dynamic_func_defs = dynamic_func_defs;
- skip_dynamic_func_count++;
- MAKE_NOP(opline);
- }
- break;
- case ZEND_DECLARE_LAMBDA_FUNCTION:
- opline->op2.num -= skip_dynamic_func_count;
- break;
- }
- opline++;
- }
- }
- static void preload_link(void)
- {
- zval *zv;
- zend_persistent_script *script;
- zend_class_entry *ce;
- zend_string *key;
- bool changed;
- HashTable errors;
- zend_hash_init(&errors, 0, NULL, NULL, 0);
- /* Resolve class dependencies */
- do {
- changed = 0;
- ZEND_HASH_FOREACH_STR_KEY_VAL_FROM(EG(class_table), key, zv, EG(persistent_classes_count)) {
- ce = Z_PTR_P(zv);
- ZEND_ASSERT(ce->type != ZEND_INTERNAL_CLASS);
- if ((ce->ce_flags & (ZEND_ACC_TOP_LEVEL|ZEND_ACC_ANON_CLASS))
- && !(ce->ce_flags & ZEND_ACC_LINKED)) {
- zend_string *lcname = zend_string_tolower(ce->name);
- if (!(ce->ce_flags & ZEND_ACC_ANON_CLASS)) {
- if (zend_hash_exists(EG(class_table), lcname)) {
- zend_string_release(lcname);
- continue;
- }
- }
- preload_error error_info;
- if (preload_resolve_deps(&error_info, ce) == FAILURE) {
- zend_string_release(lcname);
- continue;
- }
- zv = zend_hash_set_bucket_key(EG(class_table), (Bucket*)zv, lcname);
- if (EXPECTED(zv)) {
- /* Set the FILE_CACHED flag to force a lazy load, and the CACHED flag to
- * prevent freeing of interface names. */
- void *checkpoint = zend_arena_checkpoint(CG(arena));
- zend_class_entry *orig_ce = ce;
- uint32_t temporary_flags = ZEND_ACC_FILE_CACHED|ZEND_ACC_CACHED;
- ce->ce_flags |= temporary_flags;
- if (ce->parent_name) {
- zend_string_addref(ce->parent_name);
- }
- /* Record and suppress errors during inheritance. */
- orig_error_cb = zend_error_cb;
- zend_error_cb = preload_error_cb;
- zend_begin_record_errors();
- /* Set filename & lineno information for inheritance errors */
- CG(in_compilation) = 1;
- CG(compiled_filename) = ce->info.user.filename;
- CG(zend_lineno) = ce->info.user.line_start;
- zend_try {
- ce = zend_do_link_class(ce, NULL, lcname);
- if (!ce) {
- ZEND_ASSERT(0 && "Class linking failed?");
- }
- ce->ce_flags &= ~temporary_flags;
- changed = true;
- /* Inheritance successful, print out any warnings. */
- zend_error_cb = orig_error_cb;
- zend_emit_recorded_errors();
- } zend_catch {
- /* Clear variance obligations that were left behind on bailout. */
- if (CG(delayed_variance_obligations)) {
- zend_hash_index_del(
- CG(delayed_variance_obligations), (uintptr_t) Z_CE_P(zv));
- }
- /* Restore the original class. */
- zv = zend_hash_set_bucket_key(EG(class_table), (Bucket*)zv, key);
- Z_CE_P(zv) = orig_ce;
- orig_ce->ce_flags &= ~temporary_flags;
- zend_arena_release(&CG(arena), checkpoint);
- /* Remember the last error. */
- zend_error_cb = orig_error_cb;
- EG(record_errors) = false;
- ZEND_ASSERT(EG(num_errors) > 0);
- zend_hash_update_ptr(&errors, key, EG(errors)[EG(num_errors)-1]);
- EG(num_errors)--;
- } zend_end_try();
- CG(in_compilation) = 0;
- CG(compiled_filename) = NULL;
- zend_free_recorded_errors();
- }
- zend_string_release(lcname);
- }
- } ZEND_HASH_FOREACH_END();
- } while (changed);
- do {
- changed = 0;
- ZEND_HASH_REVERSE_FOREACH_VAL(EG(class_table), zv) {
- ce = Z_PTR_P(zv);
- if (ce->type == ZEND_INTERNAL_CLASS) {
- break;
- }
- if (!(ce->ce_flags & ZEND_ACC_CONSTANTS_UPDATED)) {
- if (!(ce->ce_flags & ZEND_ACC_TRAIT)) { /* don't update traits */
- CG(in_compilation) = 1; /* prevent autoloading */
- if (preload_try_resolve_constants(ce)) {
- changed = 1;
- }
- CG(in_compilation) = 0;
- }
- }
- } ZEND_HASH_FOREACH_END();
- } while (changed);
- /* Warn for classes that could not be linked. */
- ZEND_HASH_FOREACH_STR_KEY_VAL_FROM(
- EG(class_table), key, zv, EG(persistent_classes_count)) {
- ce = Z_PTR_P(zv);
- ZEND_ASSERT(ce->type != ZEND_INTERNAL_CLASS);
- if ((ce->ce_flags & (ZEND_ACC_TOP_LEVEL|ZEND_ACC_ANON_CLASS))
- && !(ce->ce_flags & ZEND_ACC_LINKED)) {
- zend_string *lcname = zend_string_tolower(ce->name);
- preload_error error;
- if (!(ce->ce_flags & ZEND_ACC_ANON_CLASS)
- && zend_hash_exists(EG(class_table), lcname)) {
- zend_error_at(
- E_WARNING, ce->info.user.filename, ce->info.user.line_start,
- "Can't preload already declared class %s", ZSTR_VAL(ce->name));
- } else if (preload_resolve_deps(&error, ce)) {
- zend_error_at(
- E_WARNING, ce->info.user.filename, ce->info.user.line_start,
- "Can't preload unlinked class %s: %s%s",
- ZSTR_VAL(ce->name), error.kind, error.name);
- } else {
- zend_error_info *error = zend_hash_find_ptr(&errors, key);
- zend_error_at(
- E_WARNING, error->filename, error->lineno,
- "Can't preload unlinked class %s: %s",
- ZSTR_VAL(ce->name), ZSTR_VAL(error->message));
- }
- zend_string_release(lcname);
- }
- } ZEND_HASH_FOREACH_END();
- zend_hash_destroy(&errors);
- ZEND_HASH_FOREACH_PTR(preload_scripts, script) {
- zend_op_array *op_array = &script->script.main_op_array;
- preload_remove_declares(op_array);
- if (op_array->fn_flags & ZEND_ACC_EARLY_BINDING) {
- script->script.first_early_binding_opline = zend_build_delayed_early_binding_list(op_array);
- if (script->script.first_early_binding_opline == (uint32_t)-1) {
- op_array->fn_flags &= ~ZEND_ACC_EARLY_BINDING;
- }
- }
- } ZEND_HASH_FOREACH_END();
- /* Dynamic defs inside functions and methods need to be removed as well. */
- zend_op_array *op_array;
- ZEND_HASH_FOREACH_PTR_FROM(EG(function_table), op_array, EG(persistent_functions_count)) {
- ZEND_ASSERT(op_array->type == ZEND_USER_FUNCTION);
- preload_remove_declares(op_array);
- } ZEND_HASH_FOREACH_END();
- ZEND_HASH_FOREACH_PTR_FROM(EG(class_table), ce, EG(persistent_classes_count)) {
- ZEND_HASH_FOREACH_PTR(&ce->function_table, op_array) {
- if (op_array->type == ZEND_USER_FUNCTION) {
- preload_remove_declares(op_array);
- }
- } ZEND_HASH_FOREACH_END();
- } ZEND_HASH_FOREACH_END();
- }
- static zend_string *preload_resolve_path(zend_string *filename)
- {
- if (is_stream_path(ZSTR_VAL(filename))) {
- return NULL;
- }
- return zend_resolve_path(filename);
- }
- static void preload_remove_empty_includes(void)
- {
- zend_persistent_script *script;
- bool changed;
- /* mark all as empty */
- ZEND_HASH_FOREACH_PTR(preload_scripts, script) {
- script->empty = 1;
- } ZEND_HASH_FOREACH_END();
- /* find non empty scripts */
- do {
- changed = 0;
- ZEND_HASH_FOREACH_PTR(preload_scripts, script) {
- if (script->empty) {
- int empty = 1;
- zend_op *opline = script->script.main_op_array.opcodes;
- zend_op *end = opline + script->script.main_op_array.last;
- while (opline < end) {
- if (opline->opcode == ZEND_INCLUDE_OR_EVAL &&
- opline->extended_value != ZEND_EVAL &&
- opline->op1_type == IS_CONST &&
- Z_TYPE_P(RT_CONSTANT(opline, opline->op1)) == IS_STRING &&
- opline->result_type == IS_UNUSED) {
- zend_string *resolved_path = preload_resolve_path(Z_STR_P(RT_CONSTANT(opline, opline->op1)));
- if (resolved_path) {
- zend_persistent_script *incl = zend_hash_find_ptr(preload_scripts, resolved_path);
- zend_string_release(resolved_path);
- if (!incl || !incl->empty) {
- empty = 0;
- break;
- }
- } else {
- empty = 0;
- break;
- }
- } else if (opline->opcode != ZEND_NOP &&
- opline->opcode != ZEND_RETURN &&
- opline->opcode != ZEND_HANDLE_EXCEPTION) {
- empty = 0;
- break;
- }
- opline++;
- }
- if (!empty) {
- script->empty = 0;
- changed = 1;
- }
- }
- } ZEND_HASH_FOREACH_END();
- } while (changed);
- /* remove empty includes */
- ZEND_HASH_FOREACH_PTR(preload_scripts, script) {
- zend_op *opline = script->script.main_op_array.opcodes;
- zend_op *end = opline + script->script.main_op_array.last;
- while (opline < end) {
- if (opline->opcode == ZEND_INCLUDE_OR_EVAL &&
- opline->extended_value != ZEND_EVAL &&
- opline->op1_type == IS_CONST &&
- Z_TYPE_P(RT_CONSTANT(opline, opline->op1)) == IS_STRING) {
- zend_string *resolved_path = preload_resolve_path(Z_STR_P(RT_CONSTANT(opline, opline->op1)));
- if (resolved_path) {
- zend_persistent_script *incl = zend_hash_find_ptr(preload_scripts, resolved_path);
- if (incl && incl->empty && opline->result_type == IS_UNUSED) {
- MAKE_NOP(opline);
- } else {
- if (!IS_ABSOLUTE_PATH(Z_STRVAL_P(RT_CONSTANT(opline, opline->op1)), Z_STRLEN_P(RT_CONSTANT(opline, opline->op1)))) {
- /* replace relative patch with absolute one */
- zend_string_release(Z_STR_P(RT_CONSTANT(opline, opline->op1)));
- ZVAL_STR_COPY(RT_CONSTANT(opline, opline->op1), resolved_path);
- }
- }
- zend_string_release(resolved_path);
- }
- }
- opline++;
- }
- } ZEND_HASH_FOREACH_END();
- }
- static void preload_register_trait_methods(zend_class_entry *ce) {
- zend_op_array *op_array;
- ZEND_HASH_FOREACH_PTR(&ce->function_table, op_array) {
- if (!(op_array->fn_flags & ZEND_ACC_TRAIT_CLONE)) {
- ZEND_ASSERT(op_array->refcount && "Must have refcount pointer");
- zend_shared_alloc_register_xlat_entry(op_array->refcount, op_array);
- }
- } ZEND_HASH_FOREACH_END();
- }
- static void preload_fix_trait_methods(zend_class_entry *ce)
- {
- zend_op_array *op_array;
- ZEND_HASH_FOREACH_PTR(&ce->function_table, op_array) {
- if (op_array->fn_flags & ZEND_ACC_TRAIT_CLONE) {
- zend_op_array *orig_op_array = zend_shared_alloc_get_xlat_entry(op_array->refcount);
- ZEND_ASSERT(orig_op_array && "Must be in xlat table");
- zend_string *function_name = op_array->function_name;
- zend_class_entry *scope = op_array->scope;
- uint32_t fn_flags = op_array->fn_flags;
- zend_function *prototype = op_array->prototype;
- HashTable *ht = op_array->static_variables;
- *op_array = *orig_op_array;
- op_array->function_name = function_name;
- op_array->scope = scope;
- op_array->fn_flags = fn_flags;
- op_array->prototype = prototype;
- op_array->static_variables = ht;
- }
- } ZEND_HASH_FOREACH_END();
- }
- static int preload_optimize(zend_persistent_script *script)
- {
- zend_class_entry *ce;
- zend_persistent_script *tmp_script;
- zend_shared_alloc_init_xlat_table();
- ZEND_HASH_FOREACH_PTR(&script->script.class_table, ce) {
- if (ce->ce_flags & ZEND_ACC_TRAIT) {
- preload_register_trait_methods(ce);
- }
- } ZEND_HASH_FOREACH_END();
- ZEND_HASH_FOREACH_PTR(preload_scripts, tmp_script) {
- ZEND_HASH_FOREACH_PTR(&tmp_script->script.class_table, ce) {
- if (ce->ce_flags & ZEND_ACC_TRAIT) {
- preload_register_trait_methods(ce);
- }
- } ZEND_HASH_FOREACH_END();
- } ZEND_HASH_FOREACH_END();
- if (!zend_optimize_script(&script->script, ZCG(accel_directives).optimization_level, ZCG(accel_directives).opt_debug_level)) {
- return FAILURE;
- }
- ZEND_HASH_FOREACH_PTR(&script->script.class_table, ce) {
- preload_fix_trait_methods(ce);
- } ZEND_HASH_FOREACH_END();
- ZEND_HASH_FOREACH_PTR(preload_scripts, script) {
- ZEND_HASH_FOREACH_PTR(&script->script.class_table, ce) {
- preload_fix_trait_methods(ce);
- } ZEND_HASH_FOREACH_END();
- } ZEND_HASH_FOREACH_END();
- zend_shared_alloc_destroy_xlat_table();
- ZEND_HASH_FOREACH_PTR(preload_scripts, script) {
- if (!zend_optimize_script(&script->script, ZCG(accel_directives).optimization_level, ZCG(accel_directives).opt_debug_level)) {
- return FAILURE;
- }
- } ZEND_HASH_FOREACH_END();
- return SUCCESS;
- }
- static zend_persistent_script* preload_script_in_shared_memory(zend_persistent_script *new_persistent_script)
- {
- zend_accel_hash_entry *bucket;
- uint32_t memory_used;
- uint32_t checkpoint;
- if (zend_accel_hash_is_full(&ZCSG(hash))) {
- zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Not enough entries in hash table for preloading. Consider increasing the value for the opcache.max_accelerated_files directive in php.ini.");
- return NULL;
- }
- checkpoint = zend_shared_alloc_checkpoint_xlat_table();
- /* Calculate the required memory size */
- memory_used = zend_accel_script_persist_calc(new_persistent_script, 1);
- /* Allocate shared memory */
- #if defined(__AVX__) || defined(__SSE2__)
- /* Align to 64-byte boundary */
- ZCG(mem) = zend_shared_alloc(memory_used + 64);
- if (ZCG(mem)) {
- ZCG(mem) = (void*)(((zend_uintptr_t)ZCG(mem) + 63L) & ~63L);
- #if defined(__x86_64__)
- memset(ZCG(mem), 0, memory_used);
- #elif defined(__AVX__)
- {
- char *p = (char*)ZCG(mem);
- char *end = p + memory_used;
- __m256i ymm0 = _mm256_setzero_si256();
- while (p < end) {
- _mm256_store_si256((__m256i*)p, ymm0);
- _mm256_store_si256((__m256i*)(p+32), ymm0);
- p += 64;
- }
- }
- #else
- {
- char *p = (char*)ZCG(mem);
- char *end = p + memory_used;
- __m128i xmm0 = _mm_setzero_si128();
- while (p < end) {
- _mm_store_si128((__m128i*)p, xmm0);
- _mm_store_si128((__m128i*)(p+16), xmm0);
- _mm_store_si128((__m128i*)(p+32), xmm0);
- _mm_store_si128((__m128i*)(p+48), xmm0);
- p += 64;
- }
- }
- #endif
- }
- #else
- ZCG(mem) = zend_shared_alloc(memory_used);
- if (ZCG(mem)) {
- memset(ZCG(mem), 0, memory_used);
- }
- #endif
- if (!ZCG(mem)) {
- zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Not enough shared memory for preloading. Consider increasing the value for the opcache.memory_consumption directive in php.ini.");
- return NULL;
- }
- zend_shared_alloc_restore_xlat_table(checkpoint);
- /* Copy into shared memory */
- new_persistent_script = zend_accel_script_persist(new_persistent_script, 1);
- new_persistent_script->is_phar = is_phar_file(new_persistent_script->script.filename);
- /* Consistency check */
- if ((char*)new_persistent_script->mem + new_persistent_script->size != (char*)ZCG(mem)) {
- zend_accel_error(
- ((char*)new_persistent_script->mem + new_persistent_script->size < (char*)ZCG(mem)) ? ACCEL_LOG_ERROR : ACCEL_LOG_WARNING,
- "Internal error: wrong size calculation: %s start=" ZEND_ADDR_FMT ", end=" ZEND_ADDR_FMT ", real=" ZEND_ADDR_FMT "\n",
- ZSTR_VAL(new_persistent_script->script.filename),
- (size_t)new_persistent_script->mem,
- (size_t)((char *)new_persistent_script->mem + new_persistent_script->size),
- (size_t)ZCG(mem));
- }
- new_persistent_script->dynamic_members.checksum = zend_accel_script_checksum(new_persistent_script);
- /* store script structure in the hash table */
- bucket = zend_accel_hash_update(&ZCSG(hash), new_persistent_script->script.filename, 0, new_persistent_script);
- if (bucket) {
- zend_accel_error(ACCEL_LOG_INFO, "Cached script '%s'", ZSTR_VAL(new_persistent_script->script.filename));
- }
- new_persistent_script->dynamic_members.memory_consumption = ZEND_ALIGNED_SIZE(new_persistent_script->size);
- return new_persistent_script;
- }
- static void preload_load(void)
- {
- /* Load into process tables */
- zend_script *script = &ZCSG(preload_script)->script;
- if (zend_hash_num_elements(&script->function_table)) {
- Bucket *p = script->function_table.arData;
- Bucket *end = p + script->function_table.nNumUsed;
- zend_hash_extend(CG(function_table),
- CG(function_table)->nNumUsed + script->function_table.nNumUsed, 0);
- for (; p != end; p++) {
- _zend_hash_append_ptr_ex(CG(function_table), p->key, Z_PTR(p->val), 1);
- }
- }
- if (zend_hash_num_elements(&script->class_table)) {
- Bucket *p = script->class_table.arData;
- Bucket *end = p + script->class_table.nNumUsed;
- zend_hash_extend(CG(class_table),
- CG(class_table)->nNumUsed + script->class_table.nNumUsed, 0);
- for (; p != end; p++) {
- _zend_hash_append_ex(CG(class_table), p->key, &p->val, 1);
- }
- }
- if (EG(zend_constants)) {
- EG(persistent_constants_count) = EG(zend_constants)->nNumUsed;
- }
- if (EG(function_table)) {
- EG(persistent_functions_count) = EG(function_table)->nNumUsed;
- }
- if (EG(class_table)) {
- EG(persistent_classes_count) = EG(class_table)->nNumUsed;
- }
- if (CG(map_ptr_last) != ZCSG(map_ptr_last)) {
- size_t old_map_ptr_last = CG(map_ptr_last);
- CG(map_ptr_last) = ZCSG(map_ptr_last);
- CG(map_ptr_size) = ZEND_MM_ALIGNED_SIZE_EX(CG(map_ptr_last) + 1, 4096);
- CG(map_ptr_real_base) = perealloc(CG(map_ptr_real_base), CG(map_ptr_size) * sizeof(void*), 1);
- CG(map_ptr_base) = ZEND_MAP_PTR_BIASED_BASE(CG(map_ptr_real_base));
- memset((void **) CG(map_ptr_real_base) + old_map_ptr_last, 0,
- (CG(map_ptr_last) - old_map_ptr_last) * sizeof(void *));
- }
- }
- static int accel_preload(const char *config, bool in_child)
- {
- zend_file_handle file_handle;
- int ret;
- char *orig_open_basedir;
- size_t orig_map_ptr_last;
- uint32_t orig_compiler_options;
- ZCG(enabled) = 0;
- ZCG(accelerator_enabled) = 0;
- orig_open_basedir = PG(open_basedir);
- PG(open_basedir) = NULL;
- preload_orig_compile_file = accelerator_orig_compile_file;
- accelerator_orig_compile_file = preload_compile_file;
- orig_map_ptr_last = CG(map_ptr_last);
- /* Compile and execute proloading script */
- zend_stream_init_filename(&file_handle, (char *) config);
- preload_scripts = emalloc(sizeof(HashTable));
- zend_hash_init(preload_scripts, 0, NULL, NULL, 0);
- orig_compiler_options = CG(compiler_options);
- if (in_child) {
- CG(compiler_options) |= ZEND_COMPILE_PRELOAD_IN_CHILD;
- }
- CG(compiler_options) |= ZEND_COMPILE_PRELOAD;
- CG(compiler_options) |= ZEND_COMPILE_HANDLE_OP_ARRAY;
- CG(compiler_options) |= ZEND_COMPILE_DELAYED_BINDING;
- CG(compiler_options) |= ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION;
- CG(compiler_options) |= ZEND_COMPILE_IGNORE_OTHER_FILES;
- CG(skip_shebang) = 1;
- zend_try {
- zend_op_array *op_array;
- ret = SUCCESS;
- op_array = zend_compile_file(&file_handle, ZEND_REQUIRE);
- if (file_handle.opened_path) {
- zend_hash_add_empty_element(&EG(included_files), file_handle.opened_path);
- }
- zend_destroy_file_handle(&file_handle);
- if (op_array) {
- zend_execute(op_array, NULL);
- zend_exception_restore();
- if (UNEXPECTED(EG(exception))) {
- if (Z_TYPE(EG(user_exception_handler)) != IS_UNDEF) {
- zend_user_exception_handler();
- }
- if (EG(exception)) {
- ret = zend_exception_error(EG(exception), E_ERROR);
- if (ret == FAILURE) {
- CG(unclean_shutdown) = 1;
- }
- }
- }
- destroy_op_array(op_array);
- efree_size(op_array, sizeof(zend_op_array));
- } else {
- if (EG(exception)) {
- zend_exception_error(EG(exception), E_ERROR);
- }
- CG(unclean_shutdown) = 1;
- ret = FAILURE;
- }
- } zend_catch {
- ret = FAILURE;
- } zend_end_try();
- PG(open_basedir) = orig_open_basedir;
- accelerator_orig_compile_file = preload_orig_compile_file;
- ZCG(enabled) = 1;
- zend_destroy_file_handle(&file_handle);
- if (ret == SUCCESS) {
- zend_persistent_script *script;
- int ping_auto_globals_mask;
- int i;
- if (PG(auto_globals_jit)) {
- ping_auto_globals_mask = zend_accel_get_auto_globals();
- }
- if (EG(zend_constants)) {
- /* Remember __COMPILER_HALT_OFFSET__(s). Do this early,
- * as zend_shutdown_executor_values() destroys constants. */
- ZEND_HASH_FOREACH_PTR(preload_scripts, script) {
- zend_execute_data *orig_execute_data = EG(current_execute_data);
- zend_execute_data fake_execute_data;
- zval *offset;
- memset(&fake_execute_data, 0, sizeof(fake_execute_data));
- fake_execute_data.func = (zend_function*)&script->script.main_op_array;
- EG(current_execute_data) = &fake_execute_data;
- if ((offset = zend_get_constant_str("__COMPILER_HALT_OFFSET__", sizeof("__COMPILER_HALT_OFFSET__") - 1)) != NULL) {
- script->compiler_halt_offset = Z_LVAL_P(offset);
- }
- EG(current_execute_data) = orig_execute_data;
- } ZEND_HASH_FOREACH_END();
- }
- /* Cleanup executor */
- EG(flags) |= EG_FLAGS_IN_SHUTDOWN;
- php_call_shutdown_functions();
- zend_call_destructors();
- php_output_end_all();
- php_free_shutdown_functions();
- /* Release stored values to avoid dangling pointers */
- zend_shutdown_executor_values(/* fast_shutdown */ false);
- /* We don't want to preload constants.
- * Check that zend_shutdown_executor_values() also destroys constants. */
- ZEND_ASSERT(zend_hash_num_elements(EG(zend_constants)) == EG(persistent_constants_count));
- zend_hash_init(&EG(symbol_table), 0, NULL, ZVAL_PTR_DTOR, 0);
- CG(map_ptr_last) = orig_map_ptr_last;
- if (EG(full_tables_cleanup)) {
- zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Preloading is not compatible with dl() function.");
- ret = FAILURE;
- goto finish;
- }
- /* Inheritance errors may be thrown during linking */
- zend_try {
- preload_link();
- } zend_catch {
- CG(map_ptr_last) = orig_map_ptr_last;
- ret = FAILURE;
- goto finish;
- } zend_end_try();
- preload_remove_empty_includes();
- script = create_persistent_script();
- script->ping_auto_globals_mask = ping_auto_globals_mask;
- /* Store all functions and classes in a single pseudo-file */
- CG(compiled_filename) = zend_string_init("$PRELOAD$", sizeof("$PRELOAD$") - 1, 0);
- #if ZEND_USE_ABS_CONST_ADDR
- init_op_array(&script->script.main_op_array, ZEND_USER_FUNCTION, 1);
- #else
- init_op_array(&script->script.main_op_array, ZEND_USER_FUNCTION, 2);
- #endif
- script->script.main_op_array.fn_flags |= ZEND_ACC_DONE_PASS_TWO;
- script->script.main_op_array.last = 1;
- script->script.main_op_array.last_literal = 1;
- #if ZEND_USE_ABS_CONST_ADDR
- script->script.main_op_array.literals = (zval*)emalloc(sizeof(zval));
- #else
- script->script.main_op_array.literals = (zval*)(script->script.main_op_array.opcodes + 1);
- #endif
- ZVAL_NULL(script->script.main_op_array.literals);
- memset(script->script.main_op_array.opcodes, 0, sizeof(zend_op));
- script->script.main_op_array.opcodes[0].opcode = ZEND_RETURN;
- script->script.main_op_array.opcodes[0].op1_type = IS_CONST;
- script->script.main_op_array.opcodes[0].op1.constant = 0;
- ZEND_PASS_TWO_UPDATE_CONSTANT(&script->script.main_op_array, script->script.main_op_array.opcodes, script->script.main_op_array.opcodes[0].op1);
- zend_vm_set_opcode_handler(script->script.main_op_array.opcodes);
- script->script.filename = CG(compiled_filename);
- CG(compiled_filename) = NULL;
- script->script.first_early_binding_opline = (uint32_t)-1;
- preload_move_user_functions(CG(function_table), &script->script.function_table);
- preload_move_user_classes(CG(class_table), &script->script.class_table);
- zend_hash_sort_ex(&script->script.class_table, preload_sort_classes, NULL, 0);
- if (preload_optimize(script) != SUCCESS) {
- zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Optimization error during preloading!");
- return FAILURE;
- }
- zend_shared_alloc_init_xlat_table();
- HANDLE_BLOCK_INTERRUPTIONS();
- SHM_UNPROTECT();
- ZCSG(preload_script) = preload_script_in_shared_memory(script);
- SHM_PROTECT();
- HANDLE_UNBLOCK_INTERRUPTIONS();
- preload_load();
- /* Store individual scripts with unlinked classes */
- HANDLE_BLOCK_INTERRUPTIONS();
- SHM_UNPROTECT();
- i = 0;
- ZCSG(saved_scripts) = zend_shared_alloc((zend_hash_num_elements(preload_scripts) + 1) * sizeof(void*));
- ZEND_HASH_FOREACH_PTR(preload_scripts, script) {
- if (zend_hash_num_elements(&script->script.class_table) > 1) {
- zend_hash_sort_ex(&script->script.class_table, preload_sort_classes, NULL, 0);
- }
- ZCSG(saved_scripts)[i++] = preload_script_in_shared_memory(script);
- } ZEND_HASH_FOREACH_END();
- ZCSG(saved_scripts)[i] = NULL;
- zend_shared_alloc_save_state();
- accel_interned_strings_save_state();
- SHM_PROTECT();
- HANDLE_UNBLOCK_INTERRUPTIONS();
- zend_shared_alloc_destroy_xlat_table();
- } else {
- CG(map_ptr_last) = orig_map_ptr_last;
- }
- finish:
- CG(compiler_options) = orig_compiler_options;
- zend_hash_destroy(preload_scripts);
- efree(preload_scripts);
- preload_scripts = NULL;
- return ret;
- }
- static size_t preload_ub_write(const char *str, size_t str_length)
- {
- return fwrite(str, 1, str_length, stdout);
- }
- static void preload_flush(void *server_context)
- {
- fflush(stdout);
- }
- static int preload_header_handler(sapi_header_struct *h, sapi_header_op_enum op, sapi_headers_struct *s)
- {
- return 0;
- }
- static int preload_send_headers(sapi_headers_struct *sapi_headers)
- {
- return SAPI_HEADER_SENT_SUCCESSFULLY;
- }
- static void preload_send_header(sapi_header_struct *sapi_header, void *server_context)
- {
- }
- static int accel_finish_startup(void)
- {
- if (!ZCG(enabled) || !accel_startup_ok) {
- return SUCCESS;
- }
- if (ZCG(accel_directives).preload && *ZCG(accel_directives).preload) {
- #ifdef ZEND_WIN32
- zend_accel_error_noreturn(ACCEL_LOG_ERROR, "Preloading is not supported on Windows");
- return FAILURE;
- #else
- int in_child = 0;
- int ret = SUCCESS;
- int rc;
- int orig_error_reporting;
- int (*orig_activate)(void) = sapi_module.activate;
- int (*orig_deactivate)(void) = sapi_module.deactivate;
- void (*orig_register_server_variables)(zval *track_vars_array) = sapi_module.register_server_variables;
- int (*orig_header_handler)(sapi_header_struct *sapi_header, sapi_header_op_enum op, sapi_headers_struct *sapi_headers) = sapi_module.header_handler;
- int (*orig_send_headers)(sapi_headers_struct *sapi_headers) = sapi_module.send_headers;
- void (*orig_send_header)(sapi_header_struct *sapi_header, void *server_context)= sapi_module.send_header;
- char *(*orig_getenv)(const char *name, size_t name_len) = sapi_module.getenv;
- size_t (*orig_ub_write)(const char *str, size_t str_length) = sapi_module.ub_write;
- void (*orig_flush)(void *server_context) = sapi_module.flush;
- #ifdef ZEND_SIGNALS
- bool old_reset_signals = SIGG(reset);
- #endif
- if (UNEXPECTED(file_cache_only)) {
- zend_accel_error(ACCEL_LOG_WARNING, "Preloading doesn't work in \"file_cache_only\" mode");
- return SUCCESS;
- }
- /* exclusive lock */
- zend_shared_alloc_lock();
- if (ZCSG(preload_script)) {
- /* Preloading was done in another process */
- preload_load();
- zend_shared_alloc_unlock();
- return SUCCESS;
- }
- if (geteuid() == 0) {
- pid_t pid;
- struct passwd *pw;
- if (!ZCG(accel_directives).preload_user
- || !*ZCG(accel_directives).preload_user) {
- zend_shared_alloc_unlock();
- zend_accel_error_noreturn(ACCEL_LOG_FATAL, "\"opcache.preload_user\" has not been defined");
- return FAILURE;
- }
- pw = getpwnam(ZCG(accel_directives).preload_user);
- if (pw == NULL) {
- zend_shared_alloc_unlock();
- zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Preloading failed to getpwnam(\"%s\")", ZCG(accel_directives).preload_user);
- return FAILURE;
- }
- pid = fork();
- if (pid == -1) {
- zend_shared_alloc_unlock();
- zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Preloading failed to fork()");
- return FAILURE;
- } else if (pid == 0) { /* children */
- if (setgid(pw->pw_gid) < 0) {
- zend_accel_error(ACCEL_LOG_WARNING, "Preloading failed to setgid(%d)", pw->pw_gid);
- exit(1);
- }
- if (initgroups(pw->pw_name, pw->pw_gid) < 0) {
- zend_accel_error(ACCEL_LOG_WARNING, "Preloading failed to initgroups(\"%s\", %d)", pw->pw_name, pw->pw_uid);
- exit(1);
- }
- if (setuid(pw->pw_uid) < 0) {
- zend_accel_error(ACCEL_LOG_WARNING, "Preloading failed to setuid(%d)", pw->pw_uid);
- exit(1);
- }
- in_child = 1;
- } else { /* parent */
- int status;
- if (waitpid(pid, &status, 0) < 0) {
- zend_shared_alloc_unlock();
- zend_accel_error_noreturn(ACCEL_LOG_FATAL, "Preloading failed to waitpid(%d)", pid);
- return FAILURE;
- }
- if (ZCSG(preload_script)) {
- preload_load();
- }
- zend_shared_alloc_unlock();
- if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
- return SUCCESS;
- } else {
- return FAILURE;
- }
- }
- } else {
- if (ZCG(accel_directives).preload_user
- && *ZCG(accel_directives).preload_user) {
- zend_accel_error(ACCEL_LOG_WARNING, "\"opcache.preload_user\" is ignored");
- }
- }
- sapi_module.activate = NULL;
- sapi_module.deactivate = NULL;
- sapi_module.register_server_variables = NULL;
- sapi_module.header_handler = preload_header_handler;
- sapi_module.send_headers = preload_send_headers;
- sapi_module.send_header = preload_send_header;
- sapi_module.getenv = NULL;
- sapi_module.ub_write = preload_ub_write;
- sapi_module.flush = preload_flush;
- zend_interned_strings_switch_storage(1);
- #ifdef ZEND_SIGNALS
- SIGG(reset) = 0;
- #endif
- orig_error_reporting = EG(error_reporting);
- EG(error_reporting) = 0;
- rc = php_request_startup();
- EG(error_reporting) = orig_error_reporting;
- if (rc == SUCCESS) {
- bool orig_report_memleaks;
- /* don't send headers */
- SG(headers_sent) = 1;
- SG(request_info).no_headers = 1;
- php_output_set_status(0);
- ZCG(auto_globals_mask) = 0;
- ZCG(request_time) = (time_t)sapi_get_request_time();
- ZCG(cache_opline) = NULL;
- ZCG(cache_persistent_script) = NULL;
- ZCG(include_path_key_len) = 0;
- ZCG(include_path_check) = 1;
- ZCG(cwd) = NULL;
- ZCG(cwd_key_len) = 0;
- ZCG(cwd_check) = 1;
- if (accel_preload(ZCG(accel_directives).preload, in_child) != SUCCESS) {
- ret = FAILURE;
- }
- preload_flush(NULL);
- orig_report_memleaks = PG(report_memleaks);
- PG(report_memleaks) = 0;
- #ifdef ZEND_SIGNALS
- /* We may not have registered signal handlers due to SIGG(reset)=0, so
- * also disable the check that they are registered. */
- SIGG(check) = 0;
- #endif
- php_request_shutdown(NULL); /* calls zend_shared_alloc_unlock(); */
- PG(report_memleaks) = orig_report_memleaks;
- } else {
- zend_shared_alloc_unlock();
- ret = FAILURE;
- }
- #ifdef ZEND_SIGNALS
- SIGG(reset) = old_reset_signals;
- #endif
- sapi_module.activate = orig_activate;
- sapi_module.deactivate = orig_deactivate;
- sapi_module.register_server_variables = orig_register_server_variables;
- sapi_module.header_handler = orig_header_handler;
- sapi_module.send_headers = orig_send_headers;
- sapi_module.send_header = orig_send_header;
- sapi_module.getenv = orig_getenv;
- sapi_module.ub_write = orig_ub_write;
- sapi_module.flush = orig_flush;
- sapi_activate();
- if (in_child) {
- if (ret == SUCCESS) {
- exit(0);
- } else {
- exit(2);
- }
- }
- return ret;
- #endif
- }
- return SUCCESS;
- }
- ZEND_EXT_API zend_extension zend_extension_entry = {
- ACCELERATOR_PRODUCT_NAME, /* name */
- PHP_VERSION, /* version */
- "Zend Technologies", /* author */
- "http://www.zend.com/", /* URL */
- "Copyright (c)", /* copyright */
- accel_startup, /* startup */
- NULL, /* shutdown */
- NULL, /* per-script activation */
- #ifdef HAVE_JIT
- accel_deactivate, /* per-script deactivation */
- #else
- NULL, /* per-script deactivation */
- #endif
- NULL, /* message handler */
- NULL, /* op_array handler */
- NULL, /* extended statement handler */
- NULL, /* extended fcall begin handler */
- NULL, /* extended fcall end handler */
- NULL, /* op_array ctor */
- NULL, /* op_array dtor */
- STANDARD_ZEND_EXTENSION_PROPERTIES
- };
|