1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903490449054906490749084909491049114912491349144915491649174918491949204921492249234924492549264927492849294930493149324933493449354936493749384939494049414942494349444945494649474948494949504951495249534954495549564957495849594960496149624963496449654966496749684969497049714972497349744975497649774978497949804981498249834984498549864987498849894990499149924993499449954996499749984999500050015002500350045005500650075008500950105011501250135014501550165017501850195020502150225023502450255026502750285029503050315032503350345035503650375038503950405041504250435044504550465047504850495050505150525053505450555056505750585059506050615062506350645065506650675068506950705071507250735074507550765077507850795080508150825083508450855086508750885089509050915092509350945095509650975098509951005101510251035104510551065107510851095110511151125113511451155116511751185119512051215122512351245125512651275128512951305131513251335134513551365137513851395140514151425143514451455146514751485149515051515152515351545155515651575158515951605161516251635164516551665167516851695170517151725173517451755176517751785179518051815182518351845185518651875188518951905191519251935194519551965197519851995200520152025203520452055206520752085209521052115212521352145215521652175218521952205221522252235224522552265227522852295230523152325233523452355236523752385239524052415242524352445245524652475248524952505251525252535254525552565257525852595260526152625263526452655266526752685269527052715272527352745275527652775278527952805281528252835284528552865287528852895290529152925293529452955296529752985299530053015302530353045305530653075308530953105311531253135314531553165317531853195320532153225323532453255326532753285329533053315332533353345335533653375338533953405341534253435344534553465347534853495350535153525353535453555356535753585359536053615362536353645365536653675368536953705371537253735374537553765377537853795380538153825383538453855386538753885389539053915392539353945395539653975398539954005401540254035404540554065407540854095410541154125413541454155416541754185419542054215422542354245425542654275428542954305431543254335434543554365437543854395440544154425443544454455446544754485449545054515452545354545455545654575458545954605461546254635464546554665467546854695470547154725473547454755476547754785479548054815482548354845485548654875488548954905491549254935494549554965497549854995500550155025503550455055506550755085509551055115512551355145515551655175518551955205521552255235524552555265527552855295530553155325533553455355536553755385539554055415542554355445545554655475548554955505551555255535554555555565557555855595560556155625563556455655566556755685569557055715572557355745575557655775578557955805581558255835584558555865587558855895590559155925593559455955596559755985599560056015602560356045605560656075608560956105611561256135614561556165617561856195620562156225623562456255626562756285629563056315632563356345635563656375638563956405641564256435644564556465647564856495650565156525653565456555656565756585659566056615662566356645665566656675668566956705671567256735674567556765677567856795680568156825683568456855686568756885689569056915692569356945695569656975698569957005701570257035704570557065707570857095710571157125713571457155716571757185719572057215722572357245725572657275728572957305731573257335734573557365737573857395740574157425743574457455746574757485749575057515752575357545755575657575758575957605761576257635764576557665767576857695770577157725773577457755776577757785779578057815782578357845785578657875788578957905791579257935794579557965797579857995800580158025803580458055806580758085809581058115812581358145815581658175818581958205821582258235824582558265827582858295830583158325833583458355836583758385839584058415842584358445845584658475848584958505851585258535854585558565857585858595860586158625863586458655866586758685869587058715872587358745875587658775878587958805881588258835884588558865887588858895890589158925893589458955896589758985899590059015902590359045905590659075908590959105911591259135914591559165917591859195920592159225923592459255926592759285929593059315932593359345935593659375938593959405941594259435944594559465947594859495950595159525953595459555956595759585959596059615962596359645965596659675968596959705971597259735974597559765977597859795980598159825983598459855986598759885989599059915992599359945995599659975998599960006001600260036004600560066007600860096010601160126013601460156016601760186019602060216022602360246025602660276028602960306031603260336034603560366037603860396040604160426043604460456046604760486049605060516052605360546055605660576058605960606061606260636064606560666067606860696070607160726073607460756076607760786079608060816082608360846085608660876088608960906091609260936094609560966097609860996100610161026103610461056106610761086109611061116112611361146115611661176118611961206121612261236124612561266127612861296130613161326133613461356136613761386139614061416142614361446145614661476148614961506151615261536154615561566157615861596160616161626163616461656166616761686169617061716172617361746175617661776178617961806181618261836184618561866187618861896190619161926193619461956196619761986199620062016202620362046205620662076208620962106211621262136214621562166217621862196220622162226223622462256226622762286229623062316232623362346235623662376238623962406241624262436244624562466247624862496250625162526253625462556256625762586259626062616262626362646265626662676268626962706271627262736274627562766277627862796280628162826283628462856286628762886289629062916292629362946295629662976298629963006301630263036304630563066307630863096310631163126313631463156316631763186319632063216322632363246325632663276328632963306331633263336334633563366337633863396340634163426343634463456346634763486349635063516352635363546355635663576358635963606361636263636364636563666367636863696370637163726373637463756376637763786379638063816382638363846385638663876388638963906391639263936394639563966397639863996400640164026403640464056406640764086409641064116412641364146415641664176418641964206421642264236424642564266427642864296430643164326433643464356436643764386439644064416442644364446445644664476448644964506451645264536454645564566457645864596460646164626463646464656466646764686469647064716472647364746475647664776478647964806481648264836484648564866487648864896490649164926493649464956496649764986499650065016502650365046505650665076508650965106511651265136514651565166517651865196520652165226523652465256526652765286529653065316532653365346535653665376538653965406541654265436544654565466547654865496550655165526553655465556556655765586559656065616562656365646565656665676568656965706571657265736574657565766577657865796580658165826583658465856586658765886589659065916592659365946595659665976598659966006601660266036604660566066607660866096610661166126613661466156616661766186619662066216622662366246625662666276628662966306631663266336634663566366637663866396640664166426643664466456646664766486649665066516652665366546655665666576658665966606661666266636664666566666667666866696670667166726673667466756676667766786679668066816682668366846685668666876688668966906691669266936694669566966697669866996700670167026703670467056706670767086709671067116712671367146715671667176718671967206721672267236724672567266727672867296730673167326733673467356736673767386739674067416742674367446745674667476748674967506751675267536754675567566757675867596760676167626763676467656766676767686769677067716772677367746775677667776778677967806781678267836784678567866787678867896790679167926793679467956796679767986799680068016802680368046805680668076808680968106811681268136814681568166817681868196820682168226823682468256826682768286829683068316832683368346835683668376838683968406841684268436844684568466847684868496850685168526853685468556856685768586859686068616862686368646865686668676868686968706871687268736874687568766877687868796880688168826883688468856886688768886889689068916892689368946895689668976898689969006901690269036904690569066907690869096910691169126913691469156916691769186919692069216922692369246925692669276928692969306931693269336934693569366937693869396940694169426943694469456946694769486949695069516952695369546955695669576958695969606961696269636964696569666967696869696970697169726973697469756976697769786979698069816982698369846985698669876988698969906991699269936994699569966997699869997000700170027003700470057006700770087009701070117012701370147015701670177018701970207021702270237024702570267027702870297030703170327033703470357036703770387039704070417042704370447045704670477048704970507051705270537054705570567057705870597060706170627063706470657066706770687069707070717072707370747075707670777078707970807081708270837084708570867087708870897090709170927093709470957096709770987099710071017102710371047105710671077108710971107111711271137114711571167117711871197120712171227123712471257126712771287129713071317132713371347135713671377138713971407141714271437144714571467147714871497150715171527153715471557156715771587159716071617162716371647165716671677168716971707171717271737174717571767177717871797180718171827183718471857186718771887189719071917192719371947195719671977198719972007201720272037204720572067207720872097210721172127213721472157216721772187219722072217222722372247225722672277228722972307231723272337234723572367237723872397240724172427243724472457246724772487249725072517252725372547255725672577258725972607261726272637264726572667267726872697270727172727273727472757276727772787279728072817282728372847285728672877288728972907291729272937294729572967297729872997300730173027303730473057306730773087309731073117312731373147315731673177318731973207321732273237324732573267327732873297330733173327333733473357336733773387339734073417342734373447345734673477348734973507351735273537354735573567357735873597360736173627363736473657366736773687369737073717372737373747375737673777378737973807381738273837384738573867387738873897390739173927393739473957396739773987399740074017402740374047405740674077408740974107411741274137414741574167417741874197420742174227423742474257426742774287429743074317432743374347435743674377438743974407441744274437444744574467447744874497450745174527453745474557456745774587459746074617462746374647465746674677468746974707471747274737474747574767477747874797480748174827483748474857486748774887489749074917492749374947495749674977498749975007501750275037504750575067507750875097510751175127513751475157516751775187519752075217522752375247525752675277528752975307531753275337534753575367537753875397540754175427543754475457546754775487549755075517552755375547555755675577558755975607561756275637564756575667567756875697570757175727573757475757576757775787579758075817582758375847585758675877588758975907591759275937594759575967597759875997600760176027603760476057606760776087609761076117612761376147615761676177618761976207621762276237624762576267627762876297630763176327633763476357636763776387639764076417642764376447645764676477648764976507651765276537654765576567657765876597660766176627663766476657666766776687669767076717672767376747675767676777678767976807681768276837684768576867687768876897690769176927693769476957696769776987699770077017702770377047705770677077708770977107711771277137714771577167717771877197720772177227723772477257726772777287729773077317732773377347735773677377738773977407741774277437744774577467747774877497750775177527753775477557756 |
- /*
- +----------------------------------------------------------------------+
- | 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. |
- +----------------------------------------------------------------------+
- | Author: Dmitry Stogov <dmitry@zend.com> |
- +----------------------------------------------------------------------+
- */
- #ifdef HAVE_CONFIG_H
- # include "config.h"
- #endif
- #include "php.h"
- #include "php_ffi.h"
- #include "ext/standard/info.h"
- #include "php_scandir.h"
- #include "zend_exceptions.h"
- #include "zend_closures.h"
- #include "main/SAPI.h"
- #include "ffi_arginfo.h"
- #include <ffi.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #ifdef HAVE_GLOB
- #ifdef PHP_WIN32
- #include "win32/glob.h"
- #else
- #include <glob.h>
- #endif
- #endif
- #ifndef __BIGGEST_ALIGNMENT__
- /* XXX need something better, perhaps with regard to SIMD, etc. */
- # define __BIGGEST_ALIGNMENT__ sizeof(size_t)
- #endif
- ZEND_DECLARE_MODULE_GLOBALS(ffi)
- typedef enum _zend_ffi_tag_kind {
- ZEND_FFI_TAG_ENUM,
- ZEND_FFI_TAG_STRUCT,
- ZEND_FFI_TAG_UNION
- } zend_ffi_tag_kind;
- static const char *zend_ffi_tag_kind_name[3] = {"enum", "struct", "union"};
- typedef struct _zend_ffi_tag {
- zend_ffi_tag_kind kind;
- zend_ffi_type *type;
- } zend_ffi_tag;
- typedef enum _zend_ffi_type_kind {
- ZEND_FFI_TYPE_VOID,
- ZEND_FFI_TYPE_FLOAT,
- ZEND_FFI_TYPE_DOUBLE,
- #ifdef HAVE_LONG_DOUBLE
- ZEND_FFI_TYPE_LONGDOUBLE,
- #endif
- ZEND_FFI_TYPE_UINT8,
- ZEND_FFI_TYPE_SINT8,
- ZEND_FFI_TYPE_UINT16,
- ZEND_FFI_TYPE_SINT16,
- ZEND_FFI_TYPE_UINT32,
- ZEND_FFI_TYPE_SINT32,
- ZEND_FFI_TYPE_UINT64,
- ZEND_FFI_TYPE_SINT64,
- ZEND_FFI_TYPE_ENUM,
- ZEND_FFI_TYPE_BOOL,
- ZEND_FFI_TYPE_CHAR,
- ZEND_FFI_TYPE_POINTER,
- ZEND_FFI_TYPE_FUNC,
- ZEND_FFI_TYPE_ARRAY,
- ZEND_FFI_TYPE_STRUCT,
- } zend_ffi_type_kind;
- typedef enum _zend_ffi_flags {
- ZEND_FFI_FLAG_CONST = (1 << 0),
- ZEND_FFI_FLAG_OWNED = (1 << 1),
- ZEND_FFI_FLAG_PERSISTENT = (1 << 2),
- } zend_ffi_flags;
- struct _zend_ffi_type {
- zend_ffi_type_kind kind;
- size_t size;
- uint32_t align;
- uint32_t attr;
- union {
- struct {
- zend_string *tag_name;
- zend_ffi_type_kind kind;
- } enumeration;
- struct {
- zend_ffi_type *type;
- zend_long length;
- } array;
- struct {
- zend_ffi_type *type;
- } pointer;
- struct {
- zend_string *tag_name;
- HashTable fields;
- } record;
- struct {
- zend_ffi_type *ret_type;
- HashTable *args;
- ffi_abi abi;
- } func;
- };
- };
- typedef struct _zend_ffi_field {
- size_t offset;
- bool is_const;
- bool is_nested; /* part of nested anonymous struct */
- uint8_t first_bit;
- uint8_t bits;
- zend_ffi_type *type;
- } zend_ffi_field;
- typedef enum _zend_ffi_symbol_kind {
- ZEND_FFI_SYM_TYPE,
- ZEND_FFI_SYM_CONST,
- ZEND_FFI_SYM_VAR,
- ZEND_FFI_SYM_FUNC
- } zend_ffi_symbol_kind;
- typedef struct _zend_ffi_symbol {
- zend_ffi_symbol_kind kind;
- bool is_const;
- zend_ffi_type *type;
- union {
- void *addr;
- int64_t value;
- };
- } zend_ffi_symbol;
- typedef struct _zend_ffi_scope {
- HashTable *symbols;
- HashTable *tags;
- } zend_ffi_scope;
- typedef struct _zend_ffi {
- zend_object std;
- DL_HANDLE lib;
- HashTable *symbols;
- HashTable *tags;
- bool persistent;
- } zend_ffi;
- #define ZEND_FFI_TYPE_OWNED (1<<0)
- #define ZEND_FFI_TYPE(t) \
- ((zend_ffi_type*)(((uintptr_t)(t)) & ~ZEND_FFI_TYPE_OWNED))
- #define ZEND_FFI_TYPE_IS_OWNED(t) \
- (((uintptr_t)(t)) & ZEND_FFI_TYPE_OWNED)
- #define ZEND_FFI_TYPE_MAKE_OWNED(t) \
- ((zend_ffi_type*)(((uintptr_t)(t)) | ZEND_FFI_TYPE_OWNED))
- #define ZEND_FFI_SIZEOF_ARG \
- MAX(FFI_SIZEOF_ARG, sizeof(double))
- typedef struct _zend_ffi_cdata {
- zend_object std;
- zend_ffi_type *type;
- void *ptr;
- void *ptr_holder;
- zend_ffi_flags flags;
- } zend_ffi_cdata;
- typedef struct _zend_ffi_ctype {
- zend_object std;
- zend_ffi_type *type;
- } zend_ffi_ctype;
- static zend_class_entry *zend_ffi_exception_ce;
- static zend_class_entry *zend_ffi_parser_exception_ce;
- static zend_class_entry *zend_ffi_ce;
- static zend_class_entry *zend_ffi_cdata_ce;
- static zend_class_entry *zend_ffi_ctype_ce;
- static zend_object_handlers zend_ffi_handlers;
- static zend_object_handlers zend_ffi_cdata_handlers;
- static zend_object_handlers zend_ffi_cdata_value_handlers;
- static zend_object_handlers zend_ffi_cdata_free_handlers;
- static zend_object_handlers zend_ffi_ctype_handlers;
- static zend_internal_function zend_ffi_new_fn;
- static zend_internal_function zend_ffi_cast_fn;
- static zend_internal_function zend_ffi_type_fn;
- /* forward declarations */
- static void _zend_ffi_type_dtor(zend_ffi_type *type);
- static void zend_ffi_finalize_type(zend_ffi_dcl *dcl);
- static int zend_ffi_is_same_type(zend_ffi_type *type1, zend_ffi_type *type2);
- static zend_ffi_type *zend_ffi_remember_type(zend_ffi_type *type);
- static char *zend_ffi_parse_directives(const char *filename, char *code_pos, char **scope_name, char **lib, bool preload);
- static ZEND_FUNCTION(ffi_trampoline);
- static ZEND_COLD void zend_ffi_return_unsupported(zend_ffi_type *type);
- static ZEND_COLD void zend_ffi_pass_unsupported(zend_ffi_type *type);
- static ZEND_COLD void zend_ffi_assign_incompatible(zval *arg, zend_ffi_type *type);
- #if FFI_CLOSURES
- static void *zend_ffi_create_callback(zend_ffi_type *type, zval *value);
- #endif
- static zend_always_inline void zend_ffi_type_dtor(zend_ffi_type *type) /* {{{ */
- {
- if (UNEXPECTED(ZEND_FFI_TYPE_IS_OWNED(type))) {
- _zend_ffi_type_dtor(type);
- return;
- }
- }
- /* }}} */
- static zend_always_inline void zend_ffi_object_init(zend_object *object, zend_class_entry *ce) /* {{{ */
- {
- GC_SET_REFCOUNT(object, 1);
- GC_TYPE_INFO(object) = GC_OBJECT | (IS_OBJ_DESTRUCTOR_CALLED << GC_FLAGS_SHIFT);
- object->ce = ce;
- object->properties = NULL;
- zend_objects_store_put(object);
- }
- /* }}} */
- static zend_object *zend_ffi_cdata_new(zend_class_entry *class_type) /* {{{ */
- {
- zend_ffi_cdata *cdata;
- cdata = emalloc(sizeof(zend_ffi_cdata));
- zend_ffi_object_init(&cdata->std, class_type);
- cdata->std.handlers = &zend_ffi_cdata_handlers;
- cdata->type = NULL;
- cdata->ptr = NULL;
- cdata->flags = 0;
- return &cdata->std;
- }
- /* }}} */
- static int zend_ffi_is_compatible_type(zend_ffi_type *dst_type, zend_ffi_type *src_type) /* {{{ */
- {
- while (1) {
- if (dst_type == src_type) {
- return 1;
- } else if (dst_type->kind == src_type->kind) {
- if (dst_type->kind < ZEND_FFI_TYPE_POINTER) {
- return 1;
- } else if (dst_type->kind == ZEND_FFI_TYPE_POINTER) {
- dst_type = ZEND_FFI_TYPE(dst_type->pointer.type);
- src_type = ZEND_FFI_TYPE(src_type->pointer.type);
- if (dst_type->kind == ZEND_FFI_TYPE_VOID ||
- src_type->kind == ZEND_FFI_TYPE_VOID) {
- return 1;
- }
- } else if (dst_type->kind == ZEND_FFI_TYPE_ARRAY &&
- (dst_type->array.length == src_type->array.length ||
- dst_type->array.length == 0)) {
- dst_type = ZEND_FFI_TYPE(dst_type->array.type);
- src_type = ZEND_FFI_TYPE(src_type->array.type);
- } else {
- break;
- }
- } else if (dst_type->kind == ZEND_FFI_TYPE_POINTER &&
- src_type->kind == ZEND_FFI_TYPE_ARRAY) {
- dst_type = ZEND_FFI_TYPE(dst_type->pointer.type);
- src_type = ZEND_FFI_TYPE(src_type->array.type);
- if (dst_type->kind == ZEND_FFI_TYPE_VOID) {
- return 1;
- }
- } else {
- break;
- }
- }
- return 0;
- }
- /* }}} */
- static ffi_type* zend_ffi_face_struct_add_fields(ffi_type* t, zend_ffi_type *type, int *i, size_t size)
- {
- zend_ffi_field *field;
- ZEND_HASH_FOREACH_PTR(&type->record.fields, field) {
- switch (ZEND_FFI_TYPE(field->type)->kind) {
- case ZEND_FFI_TYPE_FLOAT:
- t->elements[(*i)++] = &ffi_type_float;
- break;
- case ZEND_FFI_TYPE_DOUBLE:
- t->elements[(*i)++] = &ffi_type_double;
- break;
- #ifdef HAVE_LONG_DOUBLE
- case ZEND_FFI_TYPE_LONGDOUBLE:
- t->elements[(*i)++] = &ffi_type_longdouble;
- break;
- #endif
- case ZEND_FFI_TYPE_SINT8:
- case ZEND_FFI_TYPE_UINT8:
- case ZEND_FFI_TYPE_BOOL:
- case ZEND_FFI_TYPE_CHAR:
- t->elements[(*i)++] = &ffi_type_uint8;
- break;
- case ZEND_FFI_TYPE_SINT16:
- case ZEND_FFI_TYPE_UINT16:
- t->elements[(*i)++] = &ffi_type_uint16;
- break;
- case ZEND_FFI_TYPE_SINT32:
- case ZEND_FFI_TYPE_UINT32:
- t->elements[(*i)++] = &ffi_type_uint32;
- break;
- case ZEND_FFI_TYPE_SINT64:
- case ZEND_FFI_TYPE_UINT64:
- t->elements[(*i)++] = &ffi_type_uint64;
- break;
- case ZEND_FFI_TYPE_POINTER:
- t->elements[(*i)++] = &ffi_type_pointer;
- break;
- case ZEND_FFI_TYPE_STRUCT: {
- zend_ffi_type *field_type = ZEND_FFI_TYPE(field->type);
- /* for unions we use only the first field */
- int num_fields = !(field_type->attr & ZEND_FFI_ATTR_UNION) ?
- zend_hash_num_elements(&field_type->record.fields) : 1;
- if (num_fields > 1) {
- size += sizeof(ffi_type*) * (num_fields - 1);
- t = erealloc(t, size);
- t->elements = (ffi_type**)(t + 1);
- }
- t = zend_ffi_face_struct_add_fields(t, field_type, i, size);
- break;
- }
- default:
- t->elements[(*i)++] = &ffi_type_void;
- break;
- }
- if (type->attr & ZEND_FFI_ATTR_UNION) {
- /* for unions we use only the first field */
- break;
- }
- } ZEND_HASH_FOREACH_END();
- return t;
- }
- static ffi_type *zend_ffi_make_fake_struct_type(zend_ffi_type *type) /* {{{ */
- {
- /* for unions we use only the first field */
- int num_fields = !(type->attr & ZEND_FFI_ATTR_UNION) ?
- zend_hash_num_elements(&type->record.fields) : 1;
- size_t size = sizeof(ffi_type) + sizeof(ffi_type*) * (num_fields + 1);
- ffi_type *t = emalloc(size);
- int i;
- t->size = type->size;
- t->alignment = type->align;
- t->type = FFI_TYPE_STRUCT;
- t->elements = (ffi_type**)(t + 1);
- i = 0;
- t = zend_ffi_face_struct_add_fields(t, type, &i, size);
- t->elements[i] = NULL;
- return t;
- }
- /* }}} */
- static ffi_type *zend_ffi_get_type(zend_ffi_type *type) /* {{{ */
- {
- zend_ffi_type_kind kind = type->kind;
- again:
- switch (kind) {
- case ZEND_FFI_TYPE_FLOAT:
- return &ffi_type_float;
- case ZEND_FFI_TYPE_DOUBLE:
- return &ffi_type_double;
- #ifdef HAVE_LONG_DOUBLE
- case ZEND_FFI_TYPE_LONGDOUBLE:
- return &ffi_type_longdouble;
- #endif
- case ZEND_FFI_TYPE_UINT8:
- return &ffi_type_uint8;
- case ZEND_FFI_TYPE_SINT8:
- return &ffi_type_sint8;
- case ZEND_FFI_TYPE_UINT16:
- return &ffi_type_uint16;
- case ZEND_FFI_TYPE_SINT16:
- return &ffi_type_sint16;
- case ZEND_FFI_TYPE_UINT32:
- return &ffi_type_uint32;
- case ZEND_FFI_TYPE_SINT32:
- return &ffi_type_sint32;
- case ZEND_FFI_TYPE_UINT64:
- return &ffi_type_uint64;
- case ZEND_FFI_TYPE_SINT64:
- return &ffi_type_sint64;
- case ZEND_FFI_TYPE_POINTER:
- return &ffi_type_pointer;
- case ZEND_FFI_TYPE_VOID:
- return &ffi_type_void;
- case ZEND_FFI_TYPE_BOOL:
- return &ffi_type_uint8;
- case ZEND_FFI_TYPE_CHAR:
- return &ffi_type_sint8;
- case ZEND_FFI_TYPE_ENUM:
- kind = type->enumeration.kind;
- goto again;
- case ZEND_FFI_TYPE_STRUCT:
- return zend_ffi_make_fake_struct_type(type);
- default:
- break;
- }
- return NULL;
- }
- /* }}} */
- static zend_never_inline zend_ffi_cdata *zend_ffi_cdata_to_zval_slow(void *ptr, zend_ffi_type *type, zend_ffi_flags flags) /* {{{ */
- {
- zend_ffi_cdata *cdata = emalloc(sizeof(zend_ffi_cdata));
- zend_ffi_object_init(&cdata->std, zend_ffi_cdata_ce);
- cdata->std.handlers =
- (type->kind < ZEND_FFI_TYPE_POINTER) ?
- &zend_ffi_cdata_value_handlers :
- &zend_ffi_cdata_handlers;
- cdata->type = type;
- cdata->flags = flags;
- cdata->ptr = ptr;
- return cdata;
- }
- /* }}} */
- static zend_never_inline zend_ffi_cdata *zend_ffi_cdata_to_zval_slow_ptr(void *ptr, zend_ffi_type *type, zend_ffi_flags flags) /* {{{ */
- {
- zend_ffi_cdata *cdata = emalloc(sizeof(zend_ffi_cdata));
- zend_ffi_object_init(&cdata->std, zend_ffi_cdata_ce);
- cdata->std.handlers = &zend_ffi_cdata_handlers;
- cdata->type = type;
- cdata->flags = flags;
- cdata->ptr = (void*)&cdata->ptr_holder;
- *(void**)cdata->ptr = *(void**)ptr;
- return cdata;
- }
- /* }}} */
- static zend_never_inline zend_ffi_cdata *zend_ffi_cdata_to_zval_slow_ret(void *ptr, zend_ffi_type *type, zend_ffi_flags flags) /* {{{ */
- {
- zend_ffi_cdata *cdata = emalloc(sizeof(zend_ffi_cdata));
- zend_ffi_object_init(&cdata->std, zend_ffi_cdata_ce);
- cdata->std.handlers =
- (type->kind < ZEND_FFI_TYPE_POINTER) ?
- &zend_ffi_cdata_value_handlers :
- &zend_ffi_cdata_handlers;
- cdata->type = type;
- cdata->flags = flags;
- if (type->kind == ZEND_FFI_TYPE_POINTER) {
- cdata->ptr = (void*)&cdata->ptr_holder;
- *(void**)cdata->ptr = *(void**)ptr;
- } else if (type->kind == ZEND_FFI_TYPE_STRUCT) {
- cdata->ptr = emalloc(type->size);
- cdata->flags |= ZEND_FFI_FLAG_OWNED;
- memcpy(cdata->ptr, ptr, type->size);
- } else {
- cdata->ptr = ptr;
- }
- return cdata;
- }
- /* }}} */
- static zend_always_inline void zend_ffi_cdata_to_zval(zend_ffi_cdata *cdata, void *ptr, zend_ffi_type *type, int read_type, zval *rv, zend_ffi_flags flags, bool is_ret, bool debug_union) /* {{{ */
- {
- if (read_type == BP_VAR_R) {
- zend_ffi_type_kind kind = type->kind;
- again:
- switch (kind) {
- case ZEND_FFI_TYPE_FLOAT:
- ZVAL_DOUBLE(rv, *(float*)ptr);
- return;
- case ZEND_FFI_TYPE_DOUBLE:
- ZVAL_DOUBLE(rv, *(double*)ptr);
- return;
- #ifdef HAVE_LONG_DOUBLE
- case ZEND_FFI_TYPE_LONGDOUBLE:
- ZVAL_DOUBLE(rv, *(long double*)ptr);
- return;
- #endif
- case ZEND_FFI_TYPE_UINT8:
- ZVAL_LONG(rv, *(uint8_t*)ptr);
- return;
- case ZEND_FFI_TYPE_SINT8:
- ZVAL_LONG(rv, *(int8_t*)ptr);
- return;
- case ZEND_FFI_TYPE_UINT16:
- ZVAL_LONG(rv, *(uint16_t*)ptr);
- return;
- case ZEND_FFI_TYPE_SINT16:
- ZVAL_LONG(rv, *(int16_t*)ptr);
- return;
- case ZEND_FFI_TYPE_UINT32:
- ZVAL_LONG(rv, *(uint32_t*)ptr);
- return;
- case ZEND_FFI_TYPE_SINT32:
- ZVAL_LONG(rv, *(int32_t*)ptr);
- return;
- case ZEND_FFI_TYPE_UINT64:
- ZVAL_LONG(rv, *(uint64_t*)ptr);
- return;
- case ZEND_FFI_TYPE_SINT64:
- ZVAL_LONG(rv, *(int64_t*)ptr);
- return;
- case ZEND_FFI_TYPE_BOOL:
- ZVAL_BOOL(rv, *(uint8_t*)ptr);
- return;
- case ZEND_FFI_TYPE_CHAR:
- ZVAL_CHAR(rv, *(char*)ptr);
- return;
- case ZEND_FFI_TYPE_ENUM:
- kind = type->enumeration.kind;
- goto again;
- case ZEND_FFI_TYPE_POINTER:
- if (*(void**)ptr == NULL) {
- ZVAL_NULL(rv);
- return;
- } else if (debug_union) {
- ZVAL_STR(rv, zend_strpprintf(0, "%p", *(void**)ptr));
- return;
- } else if ((type->attr & ZEND_FFI_ATTR_CONST) && ZEND_FFI_TYPE(type->pointer.type)->kind == ZEND_FFI_TYPE_CHAR) {
- ZVAL_STRING(rv, *(char**)ptr);
- return;
- }
- if (!cdata) {
- if (is_ret) {
- cdata = zend_ffi_cdata_to_zval_slow_ret(ptr, type, flags);
- } else {
- cdata = zend_ffi_cdata_to_zval_slow_ptr(ptr, type, flags);
- }
- } else {
- GC_ADDREF(&cdata->std);
- }
- ZVAL_OBJ(rv, &cdata->std);
- return;
- default:
- break;
- }
- }
- if (!cdata) {
- if (is_ret) {
- cdata = zend_ffi_cdata_to_zval_slow_ret(ptr, type, flags);
- } else {
- cdata = zend_ffi_cdata_to_zval_slow(ptr, type, flags);
- }
- } else {
- GC_ADDREF(&cdata->std);
- }
- ZVAL_OBJ(rv, &cdata->std);
- }
- /* }}} */
- static uint64_t zend_ffi_bit_field_read(void *ptr, zend_ffi_field *field) /* {{{ */
- {
- size_t bit = field->first_bit;
- size_t last_bit = bit + field->bits - 1;
- uint8_t *p = (uint8_t *) ptr + bit / 8;
- uint8_t *last_p = (uint8_t *) ptr + last_bit / 8;
- size_t pos = bit % 8;
- size_t insert_pos = 0;
- uint8_t mask;
- uint64_t val = 0;
- /* Bitfield fits into a single byte */
- if (p == last_p) {
- mask = (1U << field->bits) - 1U;
- return (*p >> pos) & mask;
- }
- /* Read partial prefix byte */
- if (pos != 0) {
- size_t num_bits = 8 - pos;
- mask = ((1U << num_bits) - 1U) << pos;
- val = (*p++ >> pos) & mask;
- insert_pos += num_bits;
- }
- /* Read full bytes */
- while (p < last_p) {
- val |= *p++ << insert_pos;
- insert_pos += 8;
- }
- /* Read partial suffix byte */
- if (p == last_p) {
- size_t num_bits = last_bit % 8 + 1;
- mask = (1U << num_bits) - 1U;
- val |= (*p & mask) << insert_pos;
- }
- return val;
- }
- /* }}} */
- static void zend_ffi_bit_field_to_zval(void *ptr, zend_ffi_field *field, zval *rv) /* {{{ */
- {
- uint64_t val = zend_ffi_bit_field_read(ptr, field);
- if (ZEND_FFI_TYPE(field->type)->kind == ZEND_FFI_TYPE_CHAR
- || ZEND_FFI_TYPE(field->type)->kind == ZEND_FFI_TYPE_SINT8
- || ZEND_FFI_TYPE(field->type)->kind == ZEND_FFI_TYPE_SINT16
- || ZEND_FFI_TYPE(field->type)->kind == ZEND_FFI_TYPE_SINT32
- || ZEND_FFI_TYPE(field->type)->kind == ZEND_FFI_TYPE_SINT64) {
- /* Sign extend */
- uint64_t shift = 64 - (field->bits % 64);
- if (shift != 0) {
- val = (int64_t)(val << shift) >> shift;
- }
- }
- ZVAL_LONG(rv, val);
- }
- /* }}} */
- static int zend_ffi_zval_to_bit_field(void *ptr, zend_ffi_field *field, zval *value) /* {{{ */
- {
- uint64_t val = zval_get_long(value);
- size_t bit = field->first_bit;
- size_t last_bit = bit + field->bits - 1;
- uint8_t *p = (uint8_t *) ptr + bit / 8;
- uint8_t *last_p = (uint8_t *) ptr + last_bit / 8;
- size_t pos = bit % 8;
- uint8_t mask;
- /* Bitfield fits into a single byte */
- if (p == last_p) {
- mask = ((1U << field->bits) - 1U) << pos;
- *p = (*p & ~mask) | ((val << pos) & mask);
- return SUCCESS;
- }
- /* Write partial prefix byte */
- if (pos != 0) {
- size_t num_bits = 8 - pos;
- mask = ((1U << num_bits) - 1U) << pos;
- *p = (*p & ~mask) | ((val << pos) & mask);
- p++;
- val >>= num_bits;
- }
- /* Write full bytes */
- while (p < last_p) {
- *p++ = val;
- val >>= 8;
- }
- /* Write partial suffix byte */
- if (p == last_p) {
- size_t num_bits = last_bit % 8 + 1;
- mask = (1U << num_bits) - 1U;
- *p = (*p & ~mask) | (val & mask);
- }
- return SUCCESS;
- }
- /* }}} */
- static zend_always_inline int zend_ffi_zval_to_cdata(void *ptr, zend_ffi_type *type, zval *value) /* {{{ */
- {
- zend_long lval;
- double dval;
- zend_string *tmp_str;
- zend_string *str;
- zend_ffi_type_kind kind = type->kind;
- again:
- switch (kind) {
- case ZEND_FFI_TYPE_FLOAT:
- dval = zval_get_double(value);
- *(float*)ptr = dval;
- break;
- case ZEND_FFI_TYPE_DOUBLE:
- dval = zval_get_double(value);
- *(double*)ptr = dval;
- break;
- #ifdef HAVE_LONG_DOUBLE
- case ZEND_FFI_TYPE_LONGDOUBLE:
- dval = zval_get_double(value);
- *(long double*)ptr = dval;
- break;
- #endif
- case ZEND_FFI_TYPE_UINT8:
- lval = zval_get_long(value);
- *(uint8_t*)ptr = lval;
- break;
- case ZEND_FFI_TYPE_SINT8:
- lval = zval_get_long(value);
- *(int8_t*)ptr = lval;
- break;
- case ZEND_FFI_TYPE_UINT16:
- lval = zval_get_long(value);
- *(uint16_t*)ptr = lval;
- break;
- case ZEND_FFI_TYPE_SINT16:
- lval = zval_get_long(value);
- *(int16_t*)ptr = lval;
- break;
- case ZEND_FFI_TYPE_UINT32:
- lval = zval_get_long(value);
- *(uint32_t*)ptr = lval;
- break;
- case ZEND_FFI_TYPE_SINT32:
- lval = zval_get_long(value);
- *(int32_t*)ptr = lval;
- break;
- case ZEND_FFI_TYPE_UINT64:
- lval = zval_get_long(value);
- *(uint64_t*)ptr = lval;
- break;
- case ZEND_FFI_TYPE_SINT64:
- lval = zval_get_long(value);
- *(int64_t*)ptr = lval;
- break;
- case ZEND_FFI_TYPE_BOOL:
- *(uint8_t*)ptr = zend_is_true(value);
- break;
- case ZEND_FFI_TYPE_CHAR:
- str = zval_get_tmp_string(value, &tmp_str);
- if (ZSTR_LEN(str) == 1) {
- *(char*)ptr = ZSTR_VAL(str)[0];
- } else {
- zend_ffi_assign_incompatible(value, type);
- return FAILURE;
- }
- zend_tmp_string_release(tmp_str);
- break;
- case ZEND_FFI_TYPE_ENUM:
- kind = type->enumeration.kind;
- goto again;
- case ZEND_FFI_TYPE_POINTER:
- if (Z_TYPE_P(value) == IS_NULL) {
- *(void**)ptr = NULL;
- break;
- } else if (Z_TYPE_P(value) == IS_OBJECT && Z_OBJCE_P(value) == zend_ffi_cdata_ce) {
- zend_ffi_cdata *cdata = (zend_ffi_cdata*)Z_OBJ_P(value);
- if (zend_ffi_is_compatible_type(type, ZEND_FFI_TYPE(cdata->type))) {
- if (ZEND_FFI_TYPE(cdata->type)->kind == ZEND_FFI_TYPE_POINTER) {
- *(void**)ptr = *(void**)cdata->ptr;
- } else {
- if (cdata->flags & ZEND_FFI_FLAG_OWNED) {
- zend_throw_error(zend_ffi_exception_ce, "Attempt to perform assign of owned C pointer");
- return FAILURE;
- }
- *(void**)ptr = cdata->ptr;
- }
- return SUCCESS;
- /* Allow transparent assignment of not-owned CData to compatible pointers */
- } else if (ZEND_FFI_TYPE(cdata->type)->kind != ZEND_FFI_TYPE_POINTER
- && zend_ffi_is_compatible_type(ZEND_FFI_TYPE(type->pointer.type), ZEND_FFI_TYPE(cdata->type))) {
- if (cdata->flags & ZEND_FFI_FLAG_OWNED) {
- zend_throw_error(zend_ffi_exception_ce, "Attempt to perform assign pointer to owned C data");
- return FAILURE;
- }
- *(void**)ptr = cdata->ptr;
- return SUCCESS;
- }
- #if FFI_CLOSURES
- } else if (ZEND_FFI_TYPE(type->pointer.type)->kind == ZEND_FFI_TYPE_FUNC) {
- void *callback = zend_ffi_create_callback(ZEND_FFI_TYPE(type->pointer.type), value);
- if (callback) {
- *(void**)ptr = callback;
- break;
- } else {
- return FAILURE;
- }
- #endif
- }
- zend_ffi_assign_incompatible(value, type);
- return FAILURE;
- case ZEND_FFI_TYPE_STRUCT:
- case ZEND_FFI_TYPE_ARRAY:
- default:
- if (Z_TYPE_P(value) == IS_OBJECT && Z_OBJCE_P(value) == zend_ffi_cdata_ce) {
- zend_ffi_cdata *cdata = (zend_ffi_cdata*)Z_OBJ_P(value);
- if (zend_ffi_is_compatible_type(type, ZEND_FFI_TYPE(cdata->type)) &&
- type->size == ZEND_FFI_TYPE(cdata->type)->size) {
- memcpy(ptr, cdata->ptr, type->size);
- return SUCCESS;
- }
- }
- zend_ffi_assign_incompatible(value, type);
- return FAILURE;
- }
- return SUCCESS;
- }
- /* }}} */
- #if defined(ZEND_WIN32) && (defined(HAVE_FFI_FASTCALL) || defined(HAVE_FFI_STDCALL) || defined(HAVE_FFI_VECTORCALL_PARTIAL))
- static size_t zend_ffi_arg_size(zend_ffi_type *type) /* {{{ */
- {
- zend_ffi_type *arg_type;
- size_t arg_size = 0;
- ZEND_HASH_FOREACH_PTR(type->func.args, arg_type) {
- arg_size += MAX(ZEND_FFI_TYPE(arg_type)->size, sizeof(size_t));
- } ZEND_HASH_FOREACH_END();
- return arg_size;
- }
- /* }}} */
- #endif
- static zend_always_inline zend_string *zend_ffi_mangled_func_name(zend_string *name, zend_ffi_type *type) /* {{{ */
- {
- #ifdef ZEND_WIN32
- switch (type->func.abi) {
- # ifdef HAVE_FFI_FASTCALL
- case FFI_FASTCALL:
- return strpprintf(0, "@%s@%zu", ZSTR_VAL(name), zend_ffi_arg_size(type));
- # endif
- # ifdef HAVE_FFI_STDCALL
- case FFI_STDCALL:
- return strpprintf(0, "_%s@%zu", ZSTR_VAL(name), zend_ffi_arg_size(type));
- # endif
- # ifdef HAVE_FFI_VECTORCALL_PARTIAL
- case FFI_VECTORCALL_PARTIAL:
- return strpprintf(0, "%s@@%zu", ZSTR_VAL(name), zend_ffi_arg_size(type));
- # endif
- }
- #endif
- return zend_string_copy(name);
- }
- /* }}} */
- #if FFI_CLOSURES
- typedef struct _zend_ffi_callback_data {
- zend_fcall_info_cache fcc;
- zend_ffi_type *type;
- void *code;
- void *callback;
- ffi_cif cif;
- uint32_t arg_count;
- ffi_type *ret_type;
- ffi_type *arg_types[0];
- } zend_ffi_callback_data;
- static void zend_ffi_callback_hash_dtor(zval *zv) /* {{{ */
- {
- zend_ffi_callback_data *callback_data = Z_PTR_P(zv);
- ffi_closure_free(callback_data->callback);
- if (callback_data->fcc.function_handler->common.fn_flags & ZEND_ACC_CLOSURE) {
- OBJ_RELEASE(ZEND_CLOSURE_OBJECT(callback_data->fcc.function_handler));
- }
- for (int i = 0; i < callback_data->arg_count; ++i) {
- if (callback_data->arg_types[i]->type == FFI_TYPE_STRUCT) {
- efree(callback_data->arg_types[i]);
- }
- }
- if (callback_data->ret_type->type == FFI_TYPE_STRUCT) {
- efree(callback_data->ret_type);
- }
- efree(callback_data);
- }
- /* }}} */
- static void zend_ffi_callback_trampoline(ffi_cif* cif, void* ret, void** args, void* data) /* {{{ */
- {
- zend_ffi_callback_data *callback_data = (zend_ffi_callback_data*)data;
- zend_fcall_info fci;
- zend_ffi_type *ret_type;
- zval retval;
- ALLOCA_FLAG(use_heap)
- fci.size = sizeof(zend_fcall_info);
- ZVAL_UNDEF(&fci.function_name);
- fci.retval = &retval;
- fci.params = do_alloca(sizeof(zval) *callback_data->arg_count, use_heap);
- fci.object = NULL;
- fci.param_count = callback_data->arg_count;
- fci.named_params = NULL;
- if (callback_data->type->func.args) {
- int n = 0;
- zend_ffi_type *arg_type;
- ZEND_HASH_FOREACH_PTR(callback_data->type->func.args, arg_type) {
- arg_type = ZEND_FFI_TYPE(arg_type);
- zend_ffi_cdata_to_zval(NULL, args[n], arg_type, BP_VAR_R, &fci.params[n], (zend_ffi_flags)(arg_type->attr & ZEND_FFI_ATTR_CONST), 0, 0);
- n++;
- } ZEND_HASH_FOREACH_END();
- }
- ZVAL_UNDEF(&retval);
- if (zend_call_function(&fci, &callback_data->fcc) != SUCCESS) {
- zend_throw_error(zend_ffi_exception_ce, "Cannot call callback");
- }
- if (callback_data->arg_count) {
- int n = 0;
- for (n = 0; n < callback_data->arg_count; n++) {
- zval_ptr_dtor(&fci.params[n]);
- }
- }
- free_alloca(fci.params, use_heap);
- if (EG(exception)) {
- zend_error(E_ERROR, "Throwing from FFI callbacks is not allowed");
- }
- ret_type = ZEND_FFI_TYPE(callback_data->type->func.ret_type);
- if (ret_type->kind != ZEND_FFI_TYPE_VOID) {
- zend_ffi_zval_to_cdata(ret, ret_type, &retval);
- }
- zval_ptr_dtor(&retval);
- }
- /* }}} */
- static void *zend_ffi_create_callback(zend_ffi_type *type, zval *value) /* {{{ */
- {
- zend_fcall_info_cache fcc;
- char *error = NULL;
- uint32_t arg_count;
- void *code;
- void *callback;
- zend_ffi_callback_data *callback_data;
- if (type->attr & ZEND_FFI_ATTR_VARIADIC) {
- zend_throw_error(zend_ffi_exception_ce, "Variadic function closures are not supported");
- return NULL;
- }
- if (!zend_is_callable_ex(value, NULL, 0, NULL, &fcc, &error)) {
- zend_throw_error(zend_ffi_exception_ce, "Attempt to assign an invalid callback, %s", error);
- return NULL;
- }
- arg_count = type->func.args ? zend_hash_num_elements(type->func.args) : 0;
- if (arg_count < fcc.function_handler->common.required_num_args) {
- zend_throw_error(zend_ffi_exception_ce, "Attempt to assign an invalid callback, insufficient number of arguments");
- return NULL;
- }
- callback = ffi_closure_alloc(sizeof(ffi_closure), &code);
- if (!callback) {
- zend_throw_error(zend_ffi_exception_ce, "Cannot allocate callback");
- return NULL;
- }
- callback_data = emalloc(sizeof(zend_ffi_callback_data) + sizeof(ffi_type*) * arg_count);
- memcpy(&callback_data->fcc, &fcc, sizeof(zend_fcall_info_cache));
- callback_data->type = type;
- callback_data->callback = callback;
- callback_data->code = code;
- callback_data->arg_count = arg_count;
- if (type->func.args) {
- int n = 0;
- zend_ffi_type *arg_type;
- ZEND_HASH_FOREACH_PTR(type->func.args, arg_type) {
- arg_type = ZEND_FFI_TYPE(arg_type);
- callback_data->arg_types[n] = zend_ffi_get_type(arg_type);
- if (!callback_data->arg_types[n]) {
- zend_ffi_pass_unsupported(arg_type);
- for (int i = 0; i < n; ++i) {
- if (callback_data->arg_types[i]->type == FFI_TYPE_STRUCT) {
- efree(callback_data->arg_types[i]);
- }
- }
- efree(callback_data);
- ffi_closure_free(callback);
- return NULL;
- }
- n++;
- } ZEND_HASH_FOREACH_END();
- }
- callback_data->ret_type = zend_ffi_get_type(ZEND_FFI_TYPE(type->func.ret_type));
- if (!callback_data->ret_type) {
- zend_ffi_return_unsupported(type->func.ret_type);
- for (int i = 0; i < callback_data->arg_count; ++i) {
- if (callback_data->arg_types[i]->type == FFI_TYPE_STRUCT) {
- efree(callback_data->arg_types[i]);
- }
- }
- efree(callback_data);
- ffi_closure_free(callback);
- return NULL;
- }
- if (ffi_prep_cif(&callback_data->cif, type->func.abi, callback_data->arg_count, callback_data->ret_type, callback_data->arg_types) != FFI_OK) {
- zend_throw_error(zend_ffi_exception_ce, "Cannot prepare callback CIF");
- goto free_on_failure;
- }
- if (ffi_prep_closure_loc(callback, &callback_data->cif, zend_ffi_callback_trampoline, callback_data, code) != FFI_OK) {
- zend_throw_error(zend_ffi_exception_ce, "Cannot prepare callback");
- free_on_failure: ;
- for (int i = 0; i < callback_data->arg_count; ++i) {
- if (callback_data->arg_types[i]->type == FFI_TYPE_STRUCT) {
- efree(callback_data->arg_types[i]);
- }
- }
- if (callback_data->ret_type->type == FFI_TYPE_STRUCT) {
- efree(callback_data->ret_type);
- }
- efree(callback_data);
- ffi_closure_free(callback);
- return NULL;
- }
- if (!FFI_G(callbacks)) {
- FFI_G(callbacks) = emalloc(sizeof(HashTable));
- zend_hash_init(FFI_G(callbacks), 0, NULL, zend_ffi_callback_hash_dtor, 0);
- }
- zend_hash_next_index_insert_ptr(FFI_G(callbacks), callback_data);
- if (fcc.function_handler->common.fn_flags & ZEND_ACC_CLOSURE) {
- GC_ADDREF(ZEND_CLOSURE_OBJECT(fcc.function_handler));
- }
- return code;
- }
- /* }}} */
- #endif
- static zval *zend_ffi_cdata_get(zend_object *obj, zend_string *member, int read_type, void **cache_slot, zval *rv) /* {{{ */
- {
- zend_ffi_cdata *cdata = (zend_ffi_cdata*)obj;
- zend_ffi_type *type = ZEND_FFI_TYPE(cdata->type);
- #if 0
- if (UNEXPECTED(!cdata->ptr)) {
- zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
- return &EG(uninitialized_zval);
- }
- #endif
- if (UNEXPECTED(!zend_string_equals_literal(member, "cdata"))) {
- zend_throw_error(zend_ffi_exception_ce, "Only 'cdata' property may be read");
- return &EG(uninitialized_zval);;
- }
- zend_ffi_cdata_to_zval(cdata, cdata->ptr, type, BP_VAR_R, rv, 0, 0, 0);
- return rv;
- }
- /* }}} */
- static zval *zend_ffi_cdata_set(zend_object *obj, zend_string *member, zval *value, void **cache_slot) /* {{{ */
- {
- zend_ffi_cdata *cdata = (zend_ffi_cdata*)obj;
- zend_ffi_type *type = ZEND_FFI_TYPE(cdata->type);
- #if 0
- if (UNEXPECTED(!cdata->ptr)) {
- zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
- return &EG(uninitialized_zval);;
- }
- #endif
- if (UNEXPECTED(!zend_string_equals_literal(member, "cdata"))) {
- zend_throw_error(zend_ffi_exception_ce, "Only 'cdata' property may be set");
- return &EG(uninitialized_zval);;
- }
- zend_ffi_zval_to_cdata(cdata->ptr, type, value);
- return value;
- }
- /* }}} */
- static int zend_ffi_cdata_cast_object(zend_object *readobj, zval *writeobj, int type) /* {{{ */
- {
- if (type == IS_STRING) {
- zend_ffi_cdata *cdata = (zend_ffi_cdata*)readobj;
- zend_ffi_type *ctype = ZEND_FFI_TYPE(cdata->type);
- void *ptr = cdata->ptr;
- zend_ffi_type_kind kind = ctype->kind;
- again:
- switch (kind) {
- case ZEND_FFI_TYPE_FLOAT:
- ZVAL_DOUBLE(writeobj, *(float*)ptr);
- break;
- case ZEND_FFI_TYPE_DOUBLE:
- ZVAL_DOUBLE(writeobj, *(double*)ptr);
- break;
- #ifdef HAVE_LONG_DOUBLE
- case ZEND_FFI_TYPE_LONGDOUBLE:
- ZVAL_DOUBLE(writeobj, *(long double*)ptr);
- break;
- #endif
- case ZEND_FFI_TYPE_UINT8:
- ZVAL_LONG(writeobj, *(uint8_t*)ptr);
- break;
- case ZEND_FFI_TYPE_SINT8:
- ZVAL_LONG(writeobj, *(int8_t*)ptr);
- break;
- case ZEND_FFI_TYPE_UINT16:
- ZVAL_LONG(writeobj, *(uint16_t*)ptr);
- break;
- case ZEND_FFI_TYPE_SINT16:
- ZVAL_LONG(writeobj, *(int16_t*)ptr);
- break;
- case ZEND_FFI_TYPE_UINT32:
- ZVAL_LONG(writeobj, *(uint32_t*)ptr);
- break;
- case ZEND_FFI_TYPE_SINT32:
- ZVAL_LONG(writeobj, *(int32_t*)ptr);
- break;
- case ZEND_FFI_TYPE_UINT64:
- ZVAL_LONG(writeobj, *(uint64_t*)ptr);
- break;
- case ZEND_FFI_TYPE_SINT64:
- ZVAL_LONG(writeobj, *(int64_t*)ptr);
- break;
- case ZEND_FFI_TYPE_BOOL:
- ZVAL_BOOL(writeobj, *(uint8_t*)ptr);
- break;
- case ZEND_FFI_TYPE_CHAR:
- ZVAL_CHAR(writeobj, *(char*)ptr);
- return SUCCESS;
- case ZEND_FFI_TYPE_ENUM:
- kind = ctype->enumeration.kind;
- goto again;
- case ZEND_FFI_TYPE_POINTER:
- if (*(void**)ptr == NULL) {
- ZVAL_NULL(writeobj);
- break;
- } else if ((ctype->attr & ZEND_FFI_ATTR_CONST) && ZEND_FFI_TYPE(ctype->pointer.type)->kind == ZEND_FFI_TYPE_CHAR) {
- ZVAL_STRING(writeobj, *(char**)ptr);
- return SUCCESS;
- }
- return FAILURE;
- default:
- return FAILURE;
- }
- convert_to_string(writeobj);
- return SUCCESS;
- } else if (type == _IS_BOOL) {
- ZVAL_TRUE(writeobj);
- return SUCCESS;
- }
- return FAILURE;
- }
- /* }}} */
- static zval *zend_ffi_cdata_read_field(zend_object *obj, zend_string *field_name, int read_type, void **cache_slot, zval *rv) /* {{{ */
- {
- zend_ffi_cdata *cdata = (zend_ffi_cdata*)obj;
- zend_ffi_type *type = ZEND_FFI_TYPE(cdata->type);
- void *ptr = cdata->ptr;
- zend_ffi_field *field;
- if (cache_slot && *cache_slot == type) {
- field = *(cache_slot + 1);
- } else {
- if (type->kind == ZEND_FFI_TYPE_POINTER) {
- type = ZEND_FFI_TYPE(type->pointer.type);
- }
- if (UNEXPECTED(type->kind != ZEND_FFI_TYPE_STRUCT)) {
- if (UNEXPECTED(type->kind != ZEND_FFI_TYPE_STRUCT)) {
- zend_throw_error(zend_ffi_exception_ce, "Attempt to read field '%s' of non C struct/union", ZSTR_VAL(field_name));
- return &EG(uninitialized_zval);
- }
- }
- field = zend_hash_find_ptr(&type->record.fields, field_name);
- if (UNEXPECTED(!field)) {
- zend_throw_error(zend_ffi_exception_ce, "Attempt to read undefined field '%s' of C struct/union", ZSTR_VAL(field_name));
- return &EG(uninitialized_zval);
- }
- if (cache_slot) {
- *cache_slot = type;
- *(cache_slot + 1) = field;
- }
- }
- if (ZEND_FFI_TYPE(cdata->type)->kind == ZEND_FFI_TYPE_POINTER) {
- /* transparently dereference the pointer */
- if (UNEXPECTED(!ptr)) {
- zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
- return &EG(uninitialized_zval);
- }
- ptr = (void*)(*(char**)ptr);
- if (UNEXPECTED(!ptr)) {
- zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
- return &EG(uninitialized_zval);
- }
- type = ZEND_FFI_TYPE(type->pointer.type);
- }
- #if 0
- if (UNEXPECTED(!ptr)) {
- zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
- return &EG(uninitialized_zval);
- }
- #endif
- if (EXPECTED(!field->bits)) {
- zend_ffi_type *field_type = field->type;
- if (ZEND_FFI_TYPE_IS_OWNED(field_type)) {
- field_type = ZEND_FFI_TYPE(field_type);
- if (!(field_type->attr & ZEND_FFI_ATTR_STORED)
- && field_type->kind == ZEND_FFI_TYPE_POINTER) {
- field->type = field_type = zend_ffi_remember_type(field_type);
- }
- }
- ptr = (void*)(((char*)ptr) + field->offset);
- zend_ffi_cdata_to_zval(NULL, ptr, field_type, read_type, rv, (cdata->flags & ZEND_FFI_FLAG_CONST) | (zend_ffi_flags)field->is_const, 0, 0);
- } else {
- zend_ffi_bit_field_to_zval(ptr, field, rv);
- }
- return rv;
- }
- /* }}} */
- static zval *zend_ffi_cdata_write_field(zend_object *obj, zend_string *field_name, zval *value, void **cache_slot) /* {{{ */
- {
- zend_ffi_cdata *cdata = (zend_ffi_cdata*)obj;
- zend_ffi_type *type = ZEND_FFI_TYPE(cdata->type);
- void *ptr = cdata->ptr;
- zend_ffi_field *field;
- if (cache_slot && *cache_slot == type) {
- field = *(cache_slot + 1);
- } else {
- if (type->kind == ZEND_FFI_TYPE_POINTER) {
- type = ZEND_FFI_TYPE(type->pointer.type);
- }
- if (UNEXPECTED(type->kind != ZEND_FFI_TYPE_STRUCT)) {
- if (UNEXPECTED(type->kind != ZEND_FFI_TYPE_STRUCT)) {
- zend_throw_error(zend_ffi_exception_ce, "Attempt to assign field '%s' of non C struct/union", ZSTR_VAL(field_name));
- return value;
- }
- }
- field = zend_hash_find_ptr(&type->record.fields, field_name);
- if (UNEXPECTED(!field)) {
- zend_throw_error(zend_ffi_exception_ce, "Attempt to assign undefined field '%s' of C struct/union", ZSTR_VAL(field_name));
- return value;
- }
- if (cache_slot) {
- *cache_slot = type;
- *(cache_slot + 1) = field;
- }
- }
- if (ZEND_FFI_TYPE(cdata->type)->kind == ZEND_FFI_TYPE_POINTER) {
- /* transparently dereference the pointer */
- if (UNEXPECTED(!ptr)) {
- zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
- return value;
- }
- ptr = (void*)(*(char**)ptr);
- if (UNEXPECTED(!ptr)) {
- zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
- return value;
- }
- }
- #if 0
- if (UNEXPECTED(!ptr)) {
- zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
- return value;
- }
- #endif
- if (UNEXPECTED(cdata->flags & ZEND_FFI_FLAG_CONST)) {
- zend_throw_error(zend_ffi_exception_ce, "Attempt to assign read-only location");
- return value;
- } else if (UNEXPECTED(field->is_const)) {
- zend_throw_error(zend_ffi_exception_ce, "Attempt to assign read-only field '%s'", ZSTR_VAL(field_name));
- return value;
- }
- if (EXPECTED(!field->bits)) {
- ptr = (void*)(((char*)ptr) + field->offset);
- zend_ffi_zval_to_cdata(ptr, ZEND_FFI_TYPE(field->type), value);
- } else {
- zend_ffi_zval_to_bit_field(ptr, field, value);
- }
- return value;
- }
- /* }}} */
- static zval *zend_ffi_cdata_read_dim(zend_object *obj, zval *offset, int read_type, zval *rv) /* {{{ */
- {
- zend_ffi_cdata *cdata = (zend_ffi_cdata*)obj;
- zend_ffi_type *type = ZEND_FFI_TYPE(cdata->type);
- zend_long dim = zval_get_long(offset);
- zend_ffi_type *dim_type;
- void *ptr;
- zend_ffi_flags is_const;
- if (EXPECTED(type->kind == ZEND_FFI_TYPE_ARRAY)) {
- if (UNEXPECTED((zend_ulong)(dim) >= (zend_ulong)type->array.length)
- && (UNEXPECTED(dim < 0) || UNEXPECTED(type->array.length != 0))) {
- zend_throw_error(zend_ffi_exception_ce, "C array index out of bounds");
- return &EG(uninitialized_zval);
- }
- is_const = (cdata->flags & ZEND_FFI_FLAG_CONST) | (zend_ffi_flags)(type->attr & ZEND_FFI_ATTR_CONST);
- dim_type = type->array.type;
- if (ZEND_FFI_TYPE_IS_OWNED(dim_type)) {
- dim_type = ZEND_FFI_TYPE(dim_type);
- if (!(dim_type->attr & ZEND_FFI_ATTR_STORED)
- && dim_type->kind == ZEND_FFI_TYPE_POINTER) {
- type->array.type = dim_type = zend_ffi_remember_type(dim_type);
- }
- }
- #if 0
- if (UNEXPECTED(!cdata->ptr)) {
- zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
- return &EG(uninitialized_zval);
- }
- #endif
- ptr = (void*)(((char*)cdata->ptr) + dim_type->size * dim);
- } else if (EXPECTED(type->kind == ZEND_FFI_TYPE_POINTER)) {
- is_const = (cdata->flags & ZEND_FFI_FLAG_CONST) | (zend_ffi_flags)(type->attr & ZEND_FFI_ATTR_CONST);
- dim_type = type->pointer.type;
- if (ZEND_FFI_TYPE_IS_OWNED(dim_type)) {
- dim_type = ZEND_FFI_TYPE(dim_type);
- if (!(dim_type->attr & ZEND_FFI_ATTR_STORED)
- && dim_type->kind == ZEND_FFI_TYPE_POINTER) {
- type->pointer.type = dim_type = zend_ffi_remember_type(dim_type);
- }
- }
- if (UNEXPECTED(!cdata->ptr)) {
- zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
- return &EG(uninitialized_zval);
- }
- ptr = (void*)((*(char**)cdata->ptr) + dim_type->size * dim);
- } else {
- zend_throw_error(zend_ffi_exception_ce, "Attempt to read element of non C array");
- return &EG(uninitialized_zval);
- }
- zend_ffi_cdata_to_zval(NULL, ptr, dim_type, read_type, rv, is_const, 0, 0);
- return rv;
- }
- /* }}} */
- static void zend_ffi_cdata_write_dim(zend_object *obj, zval *offset, zval *value) /* {{{ */
- {
- zend_ffi_cdata *cdata = (zend_ffi_cdata*)obj;
- zend_ffi_type *type = ZEND_FFI_TYPE(cdata->type);
- zend_long dim;
- void *ptr;
- zend_ffi_flags is_const;
- if (offset == NULL) {
- zend_throw_error(zend_ffi_exception_ce, "Cannot add next element to object of type FFI\\CData");
- return;
- }
- dim = zval_get_long(offset);
- if (EXPECTED(type->kind == ZEND_FFI_TYPE_ARRAY)) {
- if (UNEXPECTED((zend_ulong)(dim) >= (zend_ulong)type->array.length)
- && (UNEXPECTED(dim < 0) || UNEXPECTED(type->array.length != 0))) {
- zend_throw_error(zend_ffi_exception_ce, "C array index out of bounds");
- return;
- }
- is_const = (cdata->flags & ZEND_FFI_FLAG_CONST) | (zend_ffi_flags)(type->attr & ZEND_FFI_ATTR_CONST);
- type = ZEND_FFI_TYPE(type->array.type);
- #if 0
- if (UNEXPECTED(!cdata->ptr)) {
- zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
- return;
- }
- #endif
- ptr = (void*)(((char*)cdata->ptr) + type->size * dim);
- } else if (EXPECTED(type->kind == ZEND_FFI_TYPE_POINTER)) {
- is_const = (cdata->flags & ZEND_FFI_FLAG_CONST) | (zend_ffi_flags)(type->attr & ZEND_FFI_ATTR_CONST);
- type = ZEND_FFI_TYPE(type->pointer.type);
- if (UNEXPECTED(!cdata->ptr)) {
- zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
- return;
- }
- ptr = (void*)((*(char**)cdata->ptr) + type->size * dim);
- } else {
- zend_throw_error(zend_ffi_exception_ce, "Attempt to assign element of non C array");
- return;
- }
- if (UNEXPECTED(is_const)) {
- zend_throw_error(zend_ffi_exception_ce, "Attempt to assign read-only location");
- return;
- }
- zend_ffi_zval_to_cdata(ptr, type, value);
- }
- /* }}} */
- #define MAX_TYPE_NAME_LEN 256
- typedef struct _zend_ffi_ctype_name_buf {
- char *start;
- char *end;
- char buf[MAX_TYPE_NAME_LEN];
- } zend_ffi_ctype_name_buf;
- static int zend_ffi_ctype_name_prepend(zend_ffi_ctype_name_buf *buf, const char *str, size_t len) /* {{{ */
- {
- buf->start -= len;
- if (buf->start < buf->buf) {
- return 0;
- }
- memcpy(buf->start, str, len);
- return 1;
- }
- /* }}} */
- static int zend_ffi_ctype_name_append(zend_ffi_ctype_name_buf *buf, const char *str, size_t len) /* {{{ */
- {
- if (buf->end + len > buf->buf + MAX_TYPE_NAME_LEN) {
- return 0;
- }
- memcpy(buf->end, str, len);
- buf->end += len;
- return 1;
- }
- /* }}} */
- static int zend_ffi_ctype_name(zend_ffi_ctype_name_buf *buf, const zend_ffi_type *type) /* {{{ */
- {
- const char *name = NULL;
- int is_ptr = 0;
- while (1) {
- switch (type->kind) {
- case ZEND_FFI_TYPE_VOID:
- name = "void";
- break;
- case ZEND_FFI_TYPE_FLOAT:
- name = "float";
- break;
- case ZEND_FFI_TYPE_DOUBLE:
- name = "double";
- break;
- #ifdef HAVE_LONG_DOUBLE
- case ZEND_FFI_TYPE_LONGDOUBLE:
- name = "long double";
- break;
- #endif
- case ZEND_FFI_TYPE_UINT8:
- name = "uint8_t";
- break;
- case ZEND_FFI_TYPE_SINT8:
- name = "int8_t";
- break;
- case ZEND_FFI_TYPE_UINT16:
- name = "uint16_t";
- break;
- case ZEND_FFI_TYPE_SINT16:
- name = "int16_t";
- break;
- case ZEND_FFI_TYPE_UINT32:
- name = "uint32_t";
- break;
- case ZEND_FFI_TYPE_SINT32:
- name = "int32_t";
- break;
- case ZEND_FFI_TYPE_UINT64:
- name = "uint64_t";
- break;
- case ZEND_FFI_TYPE_SINT64:
- name = "int64_t";
- break;
- case ZEND_FFI_TYPE_ENUM:
- if (type->enumeration.tag_name) {
- zend_ffi_ctype_name_prepend(buf, ZSTR_VAL(type->enumeration.tag_name), ZSTR_LEN(type->enumeration.tag_name));
- } else {
- zend_ffi_ctype_name_prepend(buf, "<anonymous>", sizeof("<anonymous>")-1);
- }
- name = "enum ";
- break;
- case ZEND_FFI_TYPE_BOOL:
- name = "bool";
- break;
- case ZEND_FFI_TYPE_CHAR:
- name = "char";
- break;
- case ZEND_FFI_TYPE_POINTER:
- if (!zend_ffi_ctype_name_prepend(buf, "*", 1)) {
- return 0;
- }
- is_ptr = 1;
- type = ZEND_FFI_TYPE(type->pointer.type);
- break;
- case ZEND_FFI_TYPE_FUNC:
- if (is_ptr) {
- is_ptr = 0;
- if (!zend_ffi_ctype_name_prepend(buf, "(", 1)
- || !zend_ffi_ctype_name_append(buf, ")", 1)) {
- return 0;
- }
- }
- if (!zend_ffi_ctype_name_append(buf, "(", 1)
- || !zend_ffi_ctype_name_append(buf, ")", 1)) {
- return 0;
- }
- type = ZEND_FFI_TYPE(type->func.ret_type);
- break;
- case ZEND_FFI_TYPE_ARRAY:
- if (is_ptr) {
- is_ptr = 0;
- if (!zend_ffi_ctype_name_prepend(buf, "(", 1)
- || !zend_ffi_ctype_name_append(buf, ")", 1)) {
- return 0;
- }
- }
- if (!zend_ffi_ctype_name_append(buf, "[", 1)) {
- return 0;
- }
- if (type->attr & ZEND_FFI_ATTR_VLA) {
- if (!zend_ffi_ctype_name_append(buf, "*", 1)) {
- return 0;
- }
- } else if (!(type->attr & ZEND_FFI_ATTR_INCOMPLETE_ARRAY)) {
- char str[MAX_LENGTH_OF_LONG + 1];
- char *s = zend_print_long_to_buf(str + sizeof(str) - 1, type->array.length);
- if (!zend_ffi_ctype_name_append(buf, s, strlen(s))) {
- return 0;
- }
- }
- if (!zend_ffi_ctype_name_append(buf, "]", 1)) {
- return 0;
- }
- type = ZEND_FFI_TYPE(type->array.type);
- break;
- case ZEND_FFI_TYPE_STRUCT:
- if (type->attr & ZEND_FFI_ATTR_UNION) {
- if (type->record.tag_name) {
- zend_ffi_ctype_name_prepend(buf, ZSTR_VAL(type->record.tag_name), ZSTR_LEN(type->record.tag_name));
- } else {
- zend_ffi_ctype_name_prepend(buf, "<anonymous>", sizeof("<anonymous>")-1);
- }
- name = "union ";
- } else {
- if (type->record.tag_name) {
- zend_ffi_ctype_name_prepend(buf, ZSTR_VAL(type->record.tag_name), ZSTR_LEN(type->record.tag_name));
- } else {
- zend_ffi_ctype_name_prepend(buf, "<anonymous>", sizeof("<anonymous>")-1);
- }
- name = "struct ";
- }
- break;
- default:
- ZEND_UNREACHABLE();
- }
- if (name) {
- break;
- }
- }
- // if (buf->start != buf->end && *buf->start != '[') {
- // if (!zend_ffi_ctype_name_prepend(buf, " ", 1)) {
- // return 0;
- // }
- // }
- return zend_ffi_ctype_name_prepend(buf, name, strlen(name));
- }
- /* }}} */
- static ZEND_COLD void zend_ffi_return_unsupported(zend_ffi_type *type) /* {{{ */
- {
- type = ZEND_FFI_TYPE(type);
- if (type->kind == ZEND_FFI_TYPE_STRUCT) {
- zend_throw_error(zend_ffi_exception_ce, "FFI return struct/union is not implemented");
- } else if (type->kind == ZEND_FFI_TYPE_ARRAY) {
- zend_throw_error(zend_ffi_exception_ce, "FFI return array is not implemented");
- } else {
- zend_throw_error(zend_ffi_exception_ce, "FFI internal error. Unsupported return type");
- }
- }
- /* }}} */
- static ZEND_COLD void zend_ffi_pass_unsupported(zend_ffi_type *type) /* {{{ */
- {
- type = ZEND_FFI_TYPE(type);
- if (type->kind == ZEND_FFI_TYPE_STRUCT) {
- zend_throw_error(zend_ffi_exception_ce, "FFI passing struct/union is not implemented");
- } else if (type->kind == ZEND_FFI_TYPE_ARRAY) {
- zend_throw_error(zend_ffi_exception_ce, "FFI passing array is not implemented");
- } else {
- zend_throw_error(zend_ffi_exception_ce, "FFI internal error. Unsupported parameter type");
- }
- }
- /* }}} */
- static ZEND_COLD void zend_ffi_pass_incompatible(zval *arg, zend_ffi_type *type, uint32_t n, zend_execute_data *execute_data) /* {{{ */
- {
- zend_ffi_ctype_name_buf buf1, buf2;
- buf1.start = buf1.end = buf1.buf + ((MAX_TYPE_NAME_LEN * 3) / 4);
- if (!zend_ffi_ctype_name(&buf1, type)) {
- zend_throw_error(zend_ffi_exception_ce, "Passing incompatible argument %d of C function '%s'", n + 1, ZSTR_VAL(EX(func)->internal_function.function_name));
- } else {
- *buf1.end = 0;
- if (Z_TYPE_P(arg) == IS_OBJECT && Z_OBJCE_P(arg) == zend_ffi_cdata_ce) {
- zend_ffi_cdata *cdata = (zend_ffi_cdata*)Z_OBJ_P(arg);
- type = ZEND_FFI_TYPE(cdata->type);
- buf2.start = buf2.end = buf2.buf + ((MAX_TYPE_NAME_LEN * 3) / 4);
- if (!zend_ffi_ctype_name(&buf2, type)) {
- zend_throw_error(zend_ffi_exception_ce, "Passing incompatible argument %d of C function '%s', expecting '%s'", n + 1, ZSTR_VAL(EX(func)->internal_function.function_name), buf1.start);
- } else {
- *buf2.end = 0;
- zend_throw_error(zend_ffi_exception_ce, "Passing incompatible argument %d of C function '%s', expecting '%s', found '%s'", n + 1, ZSTR_VAL(EX(func)->internal_function.function_name), buf1.start, buf2.start);
- }
- } else {
- zend_throw_error(zend_ffi_exception_ce, "Passing incompatible argument %d of C function '%s', expecting '%s', found PHP '%s'", n + 1, ZSTR_VAL(EX(func)->internal_function.function_name), buf1.start, zend_zval_type_name(arg));
- }
- }
- }
- /* }}} */
- static ZEND_COLD void zend_ffi_assign_incompatible(zval *arg, zend_ffi_type *type) /* {{{ */
- {
- zend_ffi_ctype_name_buf buf1, buf2;
- buf1.start = buf1.end = buf1.buf + ((MAX_TYPE_NAME_LEN * 3) / 4);
- if (!zend_ffi_ctype_name(&buf1, type)) {
- zend_throw_error(zend_ffi_exception_ce, "Incompatible types when assigning");
- } else {
- *buf1.end = 0;
- if (Z_TYPE_P(arg) == IS_OBJECT && Z_OBJCE_P(arg) == zend_ffi_cdata_ce) {
- zend_ffi_cdata *cdata = (zend_ffi_cdata*)Z_OBJ_P(arg);
- type = ZEND_FFI_TYPE(cdata->type);
- buf2.start = buf2.end = buf2.buf + ((MAX_TYPE_NAME_LEN * 3) / 4);
- if (!zend_ffi_ctype_name(&buf2, type)) {
- zend_throw_error(zend_ffi_exception_ce, "Incompatible types when assigning to type '%s'", buf1.start);
- } else {
- *buf2.end = 0;
- zend_throw_error(zend_ffi_exception_ce, "Incompatible types when assigning to type '%s' from type '%s'", buf1.start, buf2.start);
- }
- } else {
- zend_throw_error(zend_ffi_exception_ce, "Incompatible types when assigning to type '%s' from PHP '%s'", buf1.start, zend_zval_type_name(arg));
- }
- }
- }
- /* }}} */
- static zend_string *zend_ffi_get_class_name(zend_string *prefix, const zend_ffi_type *type) /* {{{ */
- {
- zend_ffi_ctype_name_buf buf;
- buf.start = buf.end = buf.buf + ((MAX_TYPE_NAME_LEN * 3) / 4);
- if (!zend_ffi_ctype_name(&buf, type)) {
- return zend_string_copy(prefix);
- } else {
- return zend_string_concat3(
- ZSTR_VAL(prefix), ZSTR_LEN(prefix), ":", 1, buf.start, buf.end - buf.start);
- }
- }
- /* }}} */
- static zend_string *zend_ffi_cdata_get_class_name(const zend_object *zobj) /* {{{ */
- {
- zend_ffi_cdata *cdata = (zend_ffi_cdata*)zobj;
- return zend_ffi_get_class_name(zobj->ce->name, ZEND_FFI_TYPE(cdata->type));
- }
- /* }}} */
- static int zend_ffi_cdata_compare_objects(zval *o1, zval *o2) /* {{{ */
- {
- if (Z_TYPE_P(o1) == IS_OBJECT && Z_OBJCE_P(o1) == zend_ffi_cdata_ce &&
- Z_TYPE_P(o2) == IS_OBJECT && Z_OBJCE_P(o2) == zend_ffi_cdata_ce) {
- zend_ffi_cdata *cdata1 = (zend_ffi_cdata*)Z_OBJ_P(o1);
- zend_ffi_cdata *cdata2 = (zend_ffi_cdata*)Z_OBJ_P(o2);
- zend_ffi_type *type1 = ZEND_FFI_TYPE(cdata1->type);
- zend_ffi_type *type2 = ZEND_FFI_TYPE(cdata2->type);
- if (type1->kind == ZEND_FFI_TYPE_POINTER && type2->kind == ZEND_FFI_TYPE_POINTER) {
- void *ptr1 = *(void**)cdata1->ptr;
- void *ptr2 = *(void**)cdata2->ptr;
- if (!ptr1 || !ptr2) {
- zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
- return 0;
- }
- return ptr1 == ptr2 ? 0 : (ptr1 < ptr2 ? -1 : 1);
- }
- }
- zend_throw_error(zend_ffi_exception_ce, "Comparison of incompatible C types");
- return 0;
- }
- /* }}} */
- static int zend_ffi_cdata_count_elements(zend_object *obj, zend_long *count) /* {{{ */
- {
- zend_ffi_cdata *cdata = (zend_ffi_cdata*)obj;
- zend_ffi_type *type = ZEND_FFI_TYPE(cdata->type);
- if (type->kind != ZEND_FFI_TYPE_ARRAY) {
- zend_throw_error(zend_ffi_exception_ce, "Attempt to count() on non C array");
- return FAILURE;
- } else {
- *count = type->array.length;
- return SUCCESS;
- }
- }
- /* }}} */
- static zend_object* zend_ffi_add(zend_ffi_cdata *base_cdata, zend_ffi_type *base_type, zend_long offset) /* {{{ */
- {
- char *ptr;
- zend_ffi_type *ptr_type;
- zend_ffi_cdata *cdata =
- (zend_ffi_cdata*)zend_ffi_cdata_new(zend_ffi_cdata_ce);
- if (base_type->kind == ZEND_FFI_TYPE_POINTER) {
- if (ZEND_FFI_TYPE_IS_OWNED(base_cdata->type)) {
- if (!(base_type->attr & ZEND_FFI_ATTR_STORED)) {
- if (GC_REFCOUNT(&base_cdata->std) == 1) {
- /* transfer type ownership */
- base_cdata->type = base_type;
- base_type = ZEND_FFI_TYPE_MAKE_OWNED(base_type);
- } else {
- base_cdata->type = base_type = zend_ffi_remember_type(base_type);
- }
- }
- }
- cdata->type = base_type;
- ptr = (char*)(*(void**)base_cdata->ptr);
- ptr_type = ZEND_FFI_TYPE(base_type)->pointer.type;
- } else {
- zend_ffi_type *new_type = emalloc(sizeof(zend_ffi_type));
- new_type->kind = ZEND_FFI_TYPE_POINTER;
- new_type->attr = 0;
- new_type->size = sizeof(void*);
- new_type->align = _Alignof(void*);
- ptr_type = base_type->array.type;
- if (ZEND_FFI_TYPE_IS_OWNED(ptr_type)) {
- ptr_type = ZEND_FFI_TYPE(ptr_type);
- if (!(ptr_type->attr & ZEND_FFI_ATTR_STORED)) {
- if (GC_REFCOUNT(&base_cdata->std) == 1) {
- /* transfer type ownership */
- base_type->array.type = ptr_type;
- ptr_type = ZEND_FFI_TYPE_MAKE_OWNED(ptr_type);
- } else {
- base_type->array.type = ptr_type = zend_ffi_remember_type(ptr_type);
- }
- }
- }
- new_type->pointer.type = ptr_type;
- cdata->type = ZEND_FFI_TYPE_MAKE_OWNED(new_type);
- ptr = (char*)base_cdata->ptr;
- }
- cdata->ptr = &cdata->ptr_holder;
- cdata->ptr_holder = ptr +
- (ptrdiff_t) (offset * ZEND_FFI_TYPE(ptr_type)->size);
- cdata->flags = base_cdata->flags & ZEND_FFI_FLAG_CONST;
- return &cdata->std;
- }
- /* }}} */
- static int zend_ffi_cdata_do_operation(zend_uchar opcode, zval *result, zval *op1, zval *op2) /* {{{ */
- {
- zend_long offset;
- ZVAL_DEREF(op1);
- ZVAL_DEREF(op2);
- if (Z_TYPE_P(op1) == IS_OBJECT && Z_OBJCE_P(op1) == zend_ffi_cdata_ce) {
- zend_ffi_cdata *cdata1 = (zend_ffi_cdata*)Z_OBJ_P(op1);
- zend_ffi_type *type1 = ZEND_FFI_TYPE(cdata1->type);
- if (type1->kind == ZEND_FFI_TYPE_POINTER || type1->kind == ZEND_FFI_TYPE_ARRAY) {
- if (opcode == ZEND_ADD) {
- offset = zval_get_long(op2);
- ZVAL_OBJ(result, zend_ffi_add(cdata1, type1, offset));
- if (result == op1) {
- OBJ_RELEASE(&cdata1->std);
- }
- return SUCCESS;
- } else if (opcode == ZEND_SUB) {
- if (Z_TYPE_P(op2) == IS_OBJECT && Z_OBJCE_P(op2) == zend_ffi_cdata_ce) {
- zend_ffi_cdata *cdata2 = (zend_ffi_cdata*)Z_OBJ_P(op2);
- zend_ffi_type *type2 = ZEND_FFI_TYPE(cdata2->type);
- if (type2->kind == ZEND_FFI_TYPE_POINTER || type2->kind == ZEND_FFI_TYPE_ARRAY) {
- zend_ffi_type *t1, *t2;
- char *p1, *p2;
- if (type1->kind == ZEND_FFI_TYPE_POINTER) {
- t1 = ZEND_FFI_TYPE(type1->pointer.type);
- p1 = (char*)(*(void**)cdata1->ptr);
- } else {
- t1 = ZEND_FFI_TYPE(type1->array.type);
- p1 = cdata1->ptr;
- }
- if (type2->kind == ZEND_FFI_TYPE_POINTER) {
- t2 = ZEND_FFI_TYPE(type2->pointer.type);
- p2 = (char*)(*(void**)cdata2->ptr);
- } else {
- t2 = ZEND_FFI_TYPE(type2->array.type);
- p2 = cdata2->ptr;
- }
- if (zend_ffi_is_same_type(t1, t2)) {
- ZVAL_LONG(result,
- (zend_long)(p1 - p2) / (zend_long)t1->size);
- return SUCCESS;
- }
- }
- }
- offset = zval_get_long(op2);
- ZVAL_OBJ(result, zend_ffi_add(cdata1, type1, -offset));
- if (result == op1) {
- OBJ_RELEASE(&cdata1->std);
- }
- return SUCCESS;
- }
- }
- } else if (Z_TYPE_P(op2) == IS_OBJECT && Z_OBJCE_P(op2) == zend_ffi_cdata_ce) {
- zend_ffi_cdata *cdata2 = (zend_ffi_cdata*)Z_OBJ_P(op2);
- zend_ffi_type *type2 = ZEND_FFI_TYPE(cdata2->type);
- if (type2->kind == ZEND_FFI_TYPE_POINTER || type2->kind == ZEND_FFI_TYPE_ARRAY) {
- if (opcode == ZEND_ADD) {
- offset = zval_get_long(op1);
- ZVAL_OBJ(result, zend_ffi_add(cdata2, type2, offset));
- return SUCCESS;
- }
- }
- }
- return FAILURE;
- }
- /* }}} */
- typedef struct _zend_ffi_cdata_iterator {
- zend_object_iterator it;
- zend_long key;
- zval value;
- bool by_ref;
- } zend_ffi_cdata_iterator;
- static void zend_ffi_cdata_it_dtor(zend_object_iterator *iter) /* {{{ */
- {
- zval_ptr_dtor(&((zend_ffi_cdata_iterator*)iter)->value);
- zval_ptr_dtor(&iter->data);
- }
- /* }}} */
- static int zend_ffi_cdata_it_valid(zend_object_iterator *it) /* {{{ */
- {
- zend_ffi_cdata_iterator *iter = (zend_ffi_cdata_iterator*)it;
- zend_ffi_cdata *cdata = (zend_ffi_cdata*)Z_OBJ(iter->it.data);
- zend_ffi_type *type = ZEND_FFI_TYPE(cdata->type);
- return (iter->key >= 0 && iter->key < type->array.length) ? SUCCESS : FAILURE;
- }
- /* }}} */
- static zval *zend_ffi_cdata_it_get_current_data(zend_object_iterator *it) /* {{{ */
- {
- zend_ffi_cdata_iterator *iter = (zend_ffi_cdata_iterator*)it;
- zend_ffi_cdata *cdata = (zend_ffi_cdata*)Z_OBJ(iter->it.data);
- zend_ffi_type *type = ZEND_FFI_TYPE(cdata->type);
- zend_ffi_type *dim_type;
- void *ptr;
- if (!cdata->ptr) {
- zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
- return &EG(uninitialized_zval);
- }
- dim_type = type->array.type;
- if (ZEND_FFI_TYPE_IS_OWNED(dim_type)) {
- dim_type = ZEND_FFI_TYPE(dim_type);
- if (!(dim_type->attr & ZEND_FFI_ATTR_STORED)
- && dim_type->kind == ZEND_FFI_TYPE_POINTER) {
- type->array.type = dim_type = zend_ffi_remember_type(dim_type);
- }
- }
- ptr = (void*)((char*)cdata->ptr + dim_type->size * iter->it.index);
- zval_ptr_dtor(&iter->value);
- zend_ffi_cdata_to_zval(NULL, ptr, dim_type, iter->by_ref ? BP_VAR_RW : BP_VAR_R, &iter->value, (cdata->flags & ZEND_FFI_FLAG_CONST) | (zend_ffi_flags)(type->attr & ZEND_FFI_ATTR_CONST), 0, 0);
- return &iter->value;
- }
- /* }}} */
- static void zend_ffi_cdata_it_get_current_key(zend_object_iterator *it, zval *key) /* {{{ */
- {
- zend_ffi_cdata_iterator *iter = (zend_ffi_cdata_iterator*)it;
- ZVAL_LONG(key, iter->key);
- }
- /* }}} */
- static void zend_ffi_cdata_it_move_forward(zend_object_iterator *it) /* {{{ */
- {
- zend_ffi_cdata_iterator *iter = (zend_ffi_cdata_iterator*)it;
- iter->key++;
- }
- /* }}} */
- static void zend_ffi_cdata_it_rewind(zend_object_iterator *it) /* {{{ */
- {
- zend_ffi_cdata_iterator *iter = (zend_ffi_cdata_iterator*)it;
- iter->key = 0;
- }
- /* }}} */
- static const zend_object_iterator_funcs zend_ffi_cdata_it_funcs = {
- zend_ffi_cdata_it_dtor,
- zend_ffi_cdata_it_valid,
- zend_ffi_cdata_it_get_current_data,
- zend_ffi_cdata_it_get_current_key,
- zend_ffi_cdata_it_move_forward,
- zend_ffi_cdata_it_rewind,
- NULL,
- NULL, /* get_gc */
- };
- static zend_object_iterator *zend_ffi_cdata_get_iterator(zend_class_entry *ce, zval *object, int by_ref) /* {{{ */
- {
- zend_ffi_cdata *cdata = (zend_ffi_cdata*)Z_OBJ_P(object);
- zend_ffi_type *type = ZEND_FFI_TYPE(cdata->type);
- zend_ffi_cdata_iterator *iter;
- if (type->kind != ZEND_FFI_TYPE_ARRAY) {
- zend_throw_error(zend_ffi_exception_ce, "Attempt to iterate on non C array");
- return NULL;
- }
- iter = emalloc(sizeof(zend_ffi_cdata_iterator));
- zend_iterator_init(&iter->it);
- Z_ADDREF_P(object);
- ZVAL_OBJ(&iter->it.data, Z_OBJ_P(object));
- iter->it.funcs = &zend_ffi_cdata_it_funcs;
- iter->key = 0;
- iter->by_ref = by_ref;
- ZVAL_UNDEF(&iter->value);
- return &iter->it;
- }
- /* }}} */
- static HashTable *zend_ffi_cdata_get_debug_info(zend_object *obj, int *is_temp) /* {{{ */
- {
- zend_ffi_cdata *cdata = (zend_ffi_cdata*)obj;
- zend_ffi_type *type = ZEND_FFI_TYPE(cdata->type);
- void *ptr = cdata->ptr;
- HashTable *ht = NULL;
- zend_string *key;
- zend_ffi_field *f;
- zend_long n;
- zval tmp;
- if (!cdata->ptr) {
- zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
- return NULL;
- }
- switch (type->kind) {
- case ZEND_FFI_TYPE_BOOL:
- case ZEND_FFI_TYPE_CHAR:
- case ZEND_FFI_TYPE_ENUM:
- case ZEND_FFI_TYPE_FLOAT:
- case ZEND_FFI_TYPE_DOUBLE:
- #ifdef HAVE_LONG_DOUBLE
- case ZEND_FFI_TYPE_LONGDOUBLE:
- #endif
- case ZEND_FFI_TYPE_UINT8:
- case ZEND_FFI_TYPE_SINT8:
- case ZEND_FFI_TYPE_UINT16:
- case ZEND_FFI_TYPE_SINT16:
- case ZEND_FFI_TYPE_UINT32:
- case ZEND_FFI_TYPE_SINT32:
- case ZEND_FFI_TYPE_UINT64:
- case ZEND_FFI_TYPE_SINT64:
- zend_ffi_cdata_to_zval(cdata, ptr, type, BP_VAR_R, &tmp, ZEND_FFI_FLAG_CONST, 0, 0);
- ht = zend_new_array(1);
- zend_hash_str_add(ht, "cdata", sizeof("cdata")-1, &tmp);
- *is_temp = 1;
- return ht;
- break;
- case ZEND_FFI_TYPE_POINTER:
- if (*(void**)ptr == NULL) {
- ZVAL_NULL(&tmp);
- ht = zend_new_array(1);
- zend_hash_index_add_new(ht, 0, &tmp);
- *is_temp = 1;
- return ht;
- } else if (ZEND_FFI_TYPE(type->pointer.type)->kind == ZEND_FFI_TYPE_VOID) {
- ZVAL_LONG(&tmp, (uintptr_t)*(void**)ptr);
- ht = zend_new_array(1);
- zend_hash_index_add_new(ht, 0, &tmp);
- *is_temp = 1;
- return ht;
- } else {
- zend_ffi_cdata_to_zval(NULL, *(void**)ptr, ZEND_FFI_TYPE(type->pointer.type), BP_VAR_R, &tmp, ZEND_FFI_FLAG_CONST, 0, 0);
- ht = zend_new_array(1);
- zend_hash_index_add_new(ht, 0, &tmp);
- *is_temp = 1;
- return ht;
- }
- break;
- case ZEND_FFI_TYPE_STRUCT:
- ht = zend_new_array(zend_hash_num_elements(&type->record.fields));
- ZEND_HASH_FOREACH_STR_KEY_PTR(&type->record.fields, key, f) {
- if (key) {
- if (!f->bits) {
- void *f_ptr = (void*)(((char*)ptr) + f->offset);
- zend_ffi_cdata_to_zval(NULL, f_ptr, ZEND_FFI_TYPE(f->type), BP_VAR_R, &tmp, ZEND_FFI_FLAG_CONST, 0, type->attr & ZEND_FFI_ATTR_UNION);
- zend_hash_add(ht, key, &tmp);
- } else {
- zend_ffi_bit_field_to_zval(ptr, f, &tmp);
- zend_hash_add(ht, key, &tmp);
- }
- }
- } ZEND_HASH_FOREACH_END();
- *is_temp = 1;
- return ht;
- case ZEND_FFI_TYPE_ARRAY:
- ht = zend_new_array(type->array.length);
- for (n = 0; n < type->array.length; n++) {
- zend_ffi_cdata_to_zval(NULL, ptr, ZEND_FFI_TYPE(type->array.type), BP_VAR_R, &tmp, ZEND_FFI_FLAG_CONST, 0, 0);
- zend_hash_index_add(ht, n, &tmp);
- ptr = (void*)(((char*)ptr) + ZEND_FFI_TYPE(type->array.type)->size);
- }
- *is_temp = 1;
- return ht;
- case ZEND_FFI_TYPE_FUNC:
- ht = zend_new_array(0);
- // TODO: function name ???
- *is_temp = 1;
- return ht;
- break;
- default:
- ZEND_UNREACHABLE();
- break;
- }
- return NULL;
- }
- /* }}} */
- static int zend_ffi_cdata_get_closure(zend_object *obj, zend_class_entry **ce_ptr, zend_function **fptr_ptr, zend_object **obj_ptr, bool check_only) /* {{{ */
- {
- zend_ffi_cdata *cdata = (zend_ffi_cdata*)obj;
- zend_ffi_type *type = ZEND_FFI_TYPE(cdata->type);
- zend_function *func;
- if (type->kind != ZEND_FFI_TYPE_POINTER) {
- if (!check_only) {
- zend_throw_error(zend_ffi_exception_ce, "Attempt to call non C function pointer");
- }
- return FAILURE;
- }
- type = ZEND_FFI_TYPE(type->pointer.type);
- if (type->kind != ZEND_FFI_TYPE_FUNC) {
- if (!check_only) {
- zend_throw_error(zend_ffi_exception_ce, "Attempt to call non C function pointer");
- }
- return FAILURE;
- }
- if (!cdata->ptr) {
- if (!check_only) {
- zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
- }
- return FAILURE;
- }
- if (EXPECTED(EG(trampoline).common.function_name == NULL)) {
- func = &EG(trampoline);
- } else {
- func = ecalloc(sizeof(zend_internal_function), 1);
- }
- func->type = ZEND_INTERNAL_FUNCTION;
- func->common.arg_flags[0] = 0;
- func->common.arg_flags[1] = 0;
- func->common.arg_flags[2] = 0;
- func->common.fn_flags = ZEND_ACC_CALL_VIA_TRAMPOLINE;
- func->common.function_name = ZSTR_KNOWN(ZEND_STR_MAGIC_INVOKE);
- /* set to 0 to avoid arg_info[] allocation, because all values are passed by value anyway */
- func->common.num_args = 0;
- func->common.required_num_args = type->func.args ? zend_hash_num_elements(type->func.args) : 0;
- func->common.scope = NULL;
- func->common.prototype = NULL;
- func->common.arg_info = NULL;
- func->internal_function.handler = ZEND_FN(ffi_trampoline);
- func->internal_function.module = NULL;
- func->internal_function.reserved[0] = type;
- func->internal_function.reserved[1] = *(void**)cdata->ptr;
- *ce_ptr = NULL;
- *fptr_ptr= func;
- *obj_ptr = NULL;
- return SUCCESS;
- }
- /* }}} */
- static zend_object *zend_ffi_ctype_new(zend_class_entry *class_type) /* {{{ */
- {
- zend_ffi_ctype *ctype;
- ctype = emalloc(sizeof(zend_ffi_ctype));
- zend_ffi_object_init(&ctype->std, class_type);
- ctype->std.handlers = &zend_ffi_ctype_handlers;
- ctype->type = NULL;
- return &ctype->std;
- }
- /* }}} */
- static void zend_ffi_ctype_free_obj(zend_object *object) /* {{{ */
- {
- zend_ffi_ctype *ctype = (zend_ffi_ctype*)object;
- zend_ffi_type_dtor(ctype->type);
- }
- /* }}} */
- static int zend_ffi_is_same_type(zend_ffi_type *type1, zend_ffi_type *type2) /* {{{ */
- {
- while (1) {
- if (type1 == type2) {
- return 1;
- } else if (type1->kind == type2->kind) {
- if (type1->kind < ZEND_FFI_TYPE_POINTER) {
- return 1;
- } else if (type1->kind == ZEND_FFI_TYPE_POINTER) {
- type1 = ZEND_FFI_TYPE(type1->pointer.type);
- type2 = ZEND_FFI_TYPE(type2->pointer.type);
- if (type1->kind == ZEND_FFI_TYPE_VOID ||
- type2->kind == ZEND_FFI_TYPE_VOID) {
- return 1;
- }
- } else if (type1->kind == ZEND_FFI_TYPE_ARRAY &&
- type1->array.length == type2->array.length) {
- type1 = ZEND_FFI_TYPE(type1->array.type);
- type2 = ZEND_FFI_TYPE(type2->array.type);
- } else {
- break;
- }
- } else {
- break;
- }
- }
- return 0;
- }
- /* }}} */
- static zend_string *zend_ffi_ctype_get_class_name(const zend_object *zobj) /* {{{ */
- {
- zend_ffi_ctype *ctype = (zend_ffi_ctype*)zobj;
- return zend_ffi_get_class_name(zobj->ce->name, ZEND_FFI_TYPE(ctype->type));
- }
- /* }}} */
- static int zend_ffi_ctype_compare_objects(zval *o1, zval *o2) /* {{{ */
- {
- if (Z_TYPE_P(o1) == IS_OBJECT && Z_OBJCE_P(o1) == zend_ffi_ctype_ce &&
- Z_TYPE_P(o2) == IS_OBJECT && Z_OBJCE_P(o2) == zend_ffi_ctype_ce) {
- zend_ffi_ctype *ctype1 = (zend_ffi_ctype*)Z_OBJ_P(o1);
- zend_ffi_ctype *ctype2 = (zend_ffi_ctype*)Z_OBJ_P(o2);
- zend_ffi_type *type1 = ZEND_FFI_TYPE(ctype1->type);
- zend_ffi_type *type2 = ZEND_FFI_TYPE(ctype2->type);
- if (zend_ffi_is_same_type(type1, type2)) {
- return 0;
- } else {
- return 1;
- }
- }
- zend_throw_error(zend_ffi_exception_ce, "Comparison of incompatible C types");
- return 0;
- }
- /* }}} */
- static HashTable *zend_ffi_ctype_get_debug_info(zend_object *obj, int *is_temp) /* {{{ */
- {
- return NULL;
- }
- /* }}} */
- static zend_object *zend_ffi_new(zend_class_entry *class_type) /* {{{ */
- {
- zend_ffi *ffi;
- ffi = emalloc(sizeof(zend_ffi));
- zend_ffi_object_init(&ffi->std, class_type);
- ffi->std.handlers = &zend_ffi_handlers;
- ffi->lib = NULL;
- ffi->symbols = NULL;
- ffi->tags = NULL;
- ffi->persistent = 0;
- return &ffi->std;
- }
- /* }}} */
- static void _zend_ffi_type_dtor(zend_ffi_type *type) /* {{{ */
- {
- type = ZEND_FFI_TYPE(type);
- switch (type->kind) {
- case ZEND_FFI_TYPE_ENUM:
- if (type->enumeration.tag_name) {
- zend_string_release(type->enumeration.tag_name);
- }
- break;
- case ZEND_FFI_TYPE_STRUCT:
- if (type->record.tag_name) {
- zend_string_release(type->record.tag_name);
- }
- zend_hash_destroy(&type->record.fields);
- break;
- case ZEND_FFI_TYPE_POINTER:
- zend_ffi_type_dtor(type->pointer.type);
- break;
- case ZEND_FFI_TYPE_ARRAY:
- zend_ffi_type_dtor(type->array.type);
- break;
- case ZEND_FFI_TYPE_FUNC:
- if (type->func.args) {
- zend_hash_destroy(type->func.args);
- pefree(type->func.args, type->attr & ZEND_FFI_ATTR_PERSISTENT);
- }
- zend_ffi_type_dtor(type->func.ret_type);
- break;
- default:
- break;
- }
- pefree(type, type->attr & ZEND_FFI_ATTR_PERSISTENT);
- }
- /* }}} */
- static void zend_ffi_type_hash_dtor(zval *zv) /* {{{ */
- {
- zend_ffi_type *type = Z_PTR_P(zv);
- zend_ffi_type_dtor(type);
- }
- /* }}} */
- static void zend_ffi_field_hash_dtor(zval *zv) /* {{{ */
- {
- zend_ffi_field *field = Z_PTR_P(zv);
- zend_ffi_type_dtor(field->type);
- efree(field);
- }
- /* }}} */
- static void zend_ffi_field_hash_persistent_dtor(zval *zv) /* {{{ */
- {
- zend_ffi_field *field = Z_PTR_P(zv);
- zend_ffi_type_dtor(field->type);
- free(field);
- }
- /* }}} */
- static void zend_ffi_symbol_hash_dtor(zval *zv) /* {{{ */
- {
- zend_ffi_symbol *sym = Z_PTR_P(zv);
- zend_ffi_type_dtor(sym->type);
- efree(sym);
- }
- /* }}} */
- static void zend_ffi_symbol_hash_persistent_dtor(zval *zv) /* {{{ */
- {
- zend_ffi_symbol *sym = Z_PTR_P(zv);
- zend_ffi_type_dtor(sym->type);
- free(sym);
- }
- /* }}} */
- static void zend_ffi_tag_hash_dtor(zval *zv) /* {{{ */
- {
- zend_ffi_tag *tag = Z_PTR_P(zv);
- zend_ffi_type_dtor(tag->type);
- efree(tag);
- }
- /* }}} */
- static void zend_ffi_tag_hash_persistent_dtor(zval *zv) /* {{{ */
- {
- zend_ffi_tag *tag = Z_PTR_P(zv);
- zend_ffi_type_dtor(tag->type);
- free(tag);
- }
- /* }}} */
- static void zend_ffi_cdata_dtor(zend_ffi_cdata *cdata) /* {{{ */
- {
- zend_ffi_type_dtor(cdata->type);
- if (cdata->flags & ZEND_FFI_FLAG_OWNED) {
- if (cdata->ptr != (void*)&cdata->ptr_holder) {
- pefree(cdata->ptr, cdata->flags & ZEND_FFI_FLAG_PERSISTENT);
- } else {
- pefree(cdata->ptr_holder, cdata->flags & ZEND_FFI_FLAG_PERSISTENT);
- }
- }
- }
- /* }}} */
- static void zend_ffi_scope_hash_dtor(zval *zv) /* {{{ */
- {
- zend_ffi_scope *scope = Z_PTR_P(zv);
- if (scope->symbols) {
- zend_hash_destroy(scope->symbols);
- free(scope->symbols);
- }
- if (scope->tags) {
- zend_hash_destroy(scope->tags);
- free(scope->tags);
- }
- free(scope);
- }
- /* }}} */
- static void zend_ffi_free_obj(zend_object *object) /* {{{ */
- {
- zend_ffi *ffi = (zend_ffi*)object;
- if (ffi->persistent) {
- return;
- }
- if (ffi->lib) {
- DL_UNLOAD(ffi->lib);
- ffi->lib = NULL;
- }
- if (ffi->symbols) {
- zend_hash_destroy(ffi->symbols);
- efree(ffi->symbols);
- }
- if (ffi->tags) {
- zend_hash_destroy(ffi->tags);
- efree(ffi->tags);
- }
- }
- /* }}} */
- static void zend_ffi_cdata_free_obj(zend_object *object) /* {{{ */
- {
- zend_ffi_cdata *cdata = (zend_ffi_cdata*)object;
- zend_ffi_cdata_dtor(cdata);
- }
- /* }}} */
- static zend_object *zend_ffi_cdata_clone_obj(zend_object *obj) /* {{{ */
- {
- zend_ffi_cdata *old_cdata = (zend_ffi_cdata*)obj;
- zend_ffi_type *type = ZEND_FFI_TYPE(old_cdata->type);
- zend_ffi_cdata *new_cdata;
- new_cdata = (zend_ffi_cdata*)zend_ffi_cdata_new(zend_ffi_cdata_ce);
- if (type->kind < ZEND_FFI_TYPE_POINTER) {
- new_cdata->std.handlers = &zend_ffi_cdata_value_handlers;
- }
- new_cdata->type = type;
- new_cdata->ptr = emalloc(type->size);
- memcpy(new_cdata->ptr, old_cdata->ptr, type->size);
- new_cdata->flags |= ZEND_FFI_FLAG_OWNED;
- return &new_cdata->std;
- }
- /* }}} */
- static zval *zend_ffi_read_var(zend_object *obj, zend_string *var_name, int read_type, void **cache_slot, zval *rv) /* {{{ */
- {
- zend_ffi *ffi = (zend_ffi*)obj;
- zend_ffi_symbol *sym = NULL;
- if (ffi->symbols) {
- sym = zend_hash_find_ptr(ffi->symbols, var_name);
- if (sym && sym->kind != ZEND_FFI_SYM_VAR && sym->kind != ZEND_FFI_SYM_CONST && sym->kind != ZEND_FFI_SYM_FUNC) {
- sym = NULL;
- }
- }
- if (!sym) {
- zend_throw_error(zend_ffi_exception_ce, "Attempt to read undefined C variable '%s'", ZSTR_VAL(var_name));
- return &EG(uninitialized_zval);
- }
- if (sym->kind == ZEND_FFI_SYM_VAR) {
- zend_ffi_cdata_to_zval(NULL, sym->addr, ZEND_FFI_TYPE(sym->type), read_type, rv, (zend_ffi_flags)sym->is_const, 0, 0);
- } else if (sym->kind == ZEND_FFI_SYM_FUNC) {
- zend_ffi_cdata *cdata;
- zend_ffi_type *new_type = emalloc(sizeof(zend_ffi_type));
- new_type->kind = ZEND_FFI_TYPE_POINTER;
- new_type->attr = 0;
- new_type->size = sizeof(void*);
- new_type->align = _Alignof(void*);
- new_type->pointer.type = ZEND_FFI_TYPE(sym->type);
- cdata = emalloc(sizeof(zend_ffi_cdata));
- zend_ffi_object_init(&cdata->std, zend_ffi_cdata_ce);
- cdata->std.handlers = &zend_ffi_cdata_handlers;
- cdata->type = ZEND_FFI_TYPE_MAKE_OWNED(new_type);
- cdata->flags = ZEND_FFI_FLAG_CONST;
- cdata->ptr_holder = sym->addr;
- cdata->ptr = &cdata->ptr_holder;
- ZVAL_OBJ(rv, &cdata->std);
- } else {
- ZVAL_LONG(rv, sym->value);
- }
- return rv;
- }
- /* }}} */
- static zval *zend_ffi_write_var(zend_object *obj, zend_string *var_name, zval *value, void **cache_slot) /* {{{ */
- {
- zend_ffi *ffi = (zend_ffi*)obj;
- zend_ffi_symbol *sym = NULL;
- if (ffi->symbols) {
- sym = zend_hash_find_ptr(ffi->symbols, var_name);
- if (sym && sym->kind != ZEND_FFI_SYM_VAR) {
- sym = NULL;
- }
- }
- if (!sym) {
- zend_throw_error(zend_ffi_exception_ce, "Attempt to assign undefined C variable '%s'", ZSTR_VAL(var_name));
- return value;
- }
- if (sym->is_const) {
- zend_throw_error(zend_ffi_exception_ce, "Attempt to assign read-only C variable '%s'", ZSTR_VAL(var_name));
- return value;
- }
- zend_ffi_zval_to_cdata(sym->addr, ZEND_FFI_TYPE(sym->type), value);
- return value;
- }
- /* }}} */
- static int zend_ffi_pass_arg(zval *arg, zend_ffi_type *type, ffi_type **pass_type, void **arg_values, uint32_t n, zend_execute_data *execute_data) /* {{{ */
- {
- zend_long lval;
- double dval;
- zend_string *str, *tmp_str;
- zend_ffi_type_kind kind = type->kind;
- ZVAL_DEREF(arg);
- again:
- switch (kind) {
- case ZEND_FFI_TYPE_FLOAT:
- dval = zval_get_double(arg);
- *pass_type = &ffi_type_float;
- *(float*)arg_values[n] = (float)dval;
- break;
- case ZEND_FFI_TYPE_DOUBLE:
- dval = zval_get_double(arg);
- *pass_type = &ffi_type_double;
- *(double*)arg_values[n] = dval;
- break;
- #ifdef HAVE_LONG_DOUBLE
- case ZEND_FFI_TYPE_LONGDOUBLE:
- dval = zval_get_double(arg);
- *pass_type = &ffi_type_double;
- *(long double*)arg_values[n] = (long double)dval;
- break;
- #endif
- case ZEND_FFI_TYPE_UINT8:
- lval = zval_get_long(arg);
- *pass_type = &ffi_type_uint8;
- *(uint8_t*)arg_values[n] = (uint8_t)lval;
- break;
- case ZEND_FFI_TYPE_SINT8:
- lval = zval_get_long(arg);
- *pass_type = &ffi_type_sint8;
- *(int8_t*)arg_values[n] = (int8_t)lval;
- break;
- case ZEND_FFI_TYPE_UINT16:
- lval = zval_get_long(arg);
- *pass_type = &ffi_type_uint16;
- *(uint16_t*)arg_values[n] = (uint16_t)lval;
- break;
- case ZEND_FFI_TYPE_SINT16:
- lval = zval_get_long(arg);
- *pass_type = &ffi_type_sint16;
- *(int16_t*)arg_values[n] = (int16_t)lval;
- break;
- case ZEND_FFI_TYPE_UINT32:
- lval = zval_get_long(arg);
- *pass_type = &ffi_type_uint32;
- *(uint32_t*)arg_values[n] = (uint32_t)lval;
- break;
- case ZEND_FFI_TYPE_SINT32:
- lval = zval_get_long(arg);
- *pass_type = &ffi_type_sint32;
- *(int32_t*)arg_values[n] = (int32_t)lval;
- break;
- case ZEND_FFI_TYPE_UINT64:
- lval = zval_get_long(arg);
- *pass_type = &ffi_type_uint64;
- *(uint64_t*)arg_values[n] = (uint64_t)lval;
- break;
- case ZEND_FFI_TYPE_SINT64:
- lval = zval_get_long(arg);
- *pass_type = &ffi_type_sint64;
- *(int64_t*)arg_values[n] = (int64_t)lval;
- break;
- case ZEND_FFI_TYPE_POINTER:
- *pass_type = &ffi_type_pointer;
- if (Z_TYPE_P(arg) == IS_NULL) {
- *(void**)arg_values[n] = NULL;
- return SUCCESS;
- } else if (Z_TYPE_P(arg) == IS_STRING
- && ((ZEND_FFI_TYPE(type->pointer.type)->kind == ZEND_FFI_TYPE_CHAR)
- || (ZEND_FFI_TYPE(type->pointer.type)->kind == ZEND_FFI_TYPE_VOID))) {
- *(void**)arg_values[n] = Z_STRVAL_P(arg);
- return SUCCESS;
- } else if (Z_TYPE_P(arg) == IS_OBJECT && Z_OBJCE_P(arg) == zend_ffi_cdata_ce) {
- zend_ffi_cdata *cdata = (zend_ffi_cdata*)Z_OBJ_P(arg);
- if (zend_ffi_is_compatible_type(type, ZEND_FFI_TYPE(cdata->type))) {
- if (ZEND_FFI_TYPE(cdata->type)->kind == ZEND_FFI_TYPE_POINTER) {
- if (!cdata->ptr) {
- zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
- return FAILURE;
- }
- *(void**)arg_values[n] = *(void**)cdata->ptr;
- } else {
- *(void**)arg_values[n] = cdata->ptr;
- }
- return SUCCESS;
- }
- #if FFI_CLOSURES
- } else if (ZEND_FFI_TYPE(type->pointer.type)->kind == ZEND_FFI_TYPE_FUNC) {
- void *callback = zend_ffi_create_callback(ZEND_FFI_TYPE(type->pointer.type), arg);
- if (callback) {
- *(void**)arg_values[n] = callback;
- break;
- } else {
- return FAILURE;
- }
- #endif
- }
- zend_ffi_pass_incompatible(arg, type, n, execute_data);
- return FAILURE;
- case ZEND_FFI_TYPE_BOOL:
- *pass_type = &ffi_type_uint8;
- *(uint8_t*)arg_values[n] = zend_is_true(arg);
- break;
- case ZEND_FFI_TYPE_CHAR:
- str = zval_get_tmp_string(arg, &tmp_str);
- *pass_type = &ffi_type_sint8;
- *(char*)arg_values[n] = ZSTR_VAL(str)[0];
- if (ZSTR_LEN(str) != 1) {
- zend_ffi_pass_incompatible(arg, type, n, execute_data);
- }
- zend_tmp_string_release(tmp_str);
- break;
- case ZEND_FFI_TYPE_ENUM:
- kind = type->enumeration.kind;
- goto again;
- case ZEND_FFI_TYPE_STRUCT:
- if (Z_TYPE_P(arg) == IS_OBJECT && Z_OBJCE_P(arg) == zend_ffi_cdata_ce) {
- zend_ffi_cdata *cdata = (zend_ffi_cdata*)Z_OBJ_P(arg);
- if (zend_ffi_is_compatible_type(type, ZEND_FFI_TYPE(cdata->type))) {
- *pass_type = zend_ffi_make_fake_struct_type(type);;
- arg_values[n] = cdata->ptr;
- break;
- }
- }
- zend_ffi_pass_incompatible(arg, type, n, execute_data);
- return FAILURE;
- default:
- zend_ffi_pass_unsupported(type);
- return FAILURE;
- }
- return SUCCESS;
- }
- /* }}} */
- static int zend_ffi_pass_var_arg(zval *arg, ffi_type **pass_type, void **arg_values, uint32_t n, zend_execute_data *execute_data) /* {{{ */
- {
- ZVAL_DEREF(arg);
- switch (Z_TYPE_P(arg)) {
- case IS_NULL:
- *pass_type = &ffi_type_pointer;
- *(void**)arg_values[n] = NULL;
- break;
- case IS_FALSE:
- *pass_type = &ffi_type_uint8;
- *(uint8_t*)arg_values[n] = 0;
- break;
- case IS_TRUE:
- *pass_type = &ffi_type_uint8;
- *(uint8_t*)arg_values[n] = 1;
- break;
- case IS_LONG:
- if (sizeof(zend_long) == 4) {
- *pass_type = &ffi_type_sint32;
- *(int32_t*)arg_values[n] = Z_LVAL_P(arg);
- } else {
- *pass_type = &ffi_type_sint64;
- *(int64_t*)arg_values[n] = Z_LVAL_P(arg);
- }
- break;
- case IS_DOUBLE:
- *pass_type = &ffi_type_double;
- *(double*)arg_values[n] = Z_DVAL_P(arg);
- break;
- case IS_STRING:
- *pass_type = &ffi_type_pointer;
- *(char**)arg_values[n] = Z_STRVAL_P(arg);
- break;
- case IS_OBJECT:
- if (Z_OBJCE_P(arg) == zend_ffi_cdata_ce) {
- zend_ffi_cdata *cdata = (zend_ffi_cdata*)Z_OBJ_P(arg);
- zend_ffi_type *type = ZEND_FFI_TYPE(cdata->type);
- return zend_ffi_pass_arg(arg, type, pass_type, arg_values, n, execute_data);
- }
- ZEND_FALLTHROUGH;
- default:
- zend_throw_error(zend_ffi_exception_ce, "Unsupported argument type");
- return FAILURE;
- }
- return SUCCESS;
- }
- /* }}} */
- static ZEND_FUNCTION(ffi_trampoline) /* {{{ */
- {
- zend_ffi_type *type = EX(func)->internal_function.reserved[0];
- void *addr = EX(func)->internal_function.reserved[1];
- ffi_cif cif;
- ffi_type *ret_type = NULL;
- ffi_type **arg_types = NULL;
- void **arg_values = NULL;
- uint32_t n, arg_count;
- void *ret;
- zend_ffi_type *arg_type;
- ALLOCA_FLAG(arg_types_use_heap = 0)
- ALLOCA_FLAG(arg_values_use_heap = 0)
- ALLOCA_FLAG(ret_use_heap = 0)
- ZEND_ASSERT(type->kind == ZEND_FFI_TYPE_FUNC);
- arg_count = type->func.args ? zend_hash_num_elements(type->func.args) : 0;
- if (type->attr & ZEND_FFI_ATTR_VARIADIC) {
- if (arg_count > EX_NUM_ARGS()) {
- zend_throw_error(zend_ffi_exception_ce, "Incorrect number of arguments for C function '%s', expecting at least %d parameter%s", ZSTR_VAL(EX(func)->internal_function.function_name), arg_count, (arg_count != 1) ? "s" : "");
- goto exit;
- }
- if (EX_NUM_ARGS()) {
- arg_types = do_alloca(
- sizeof(ffi_type*) * EX_NUM_ARGS(), arg_types_use_heap);
- arg_values = do_alloca(
- (sizeof(void*) + ZEND_FFI_SIZEOF_ARG) * EX_NUM_ARGS(), arg_values_use_heap);
- n = 0;
- if (type->func.args) {
- ZEND_HASH_FOREACH_PTR(type->func.args, arg_type) {
- arg_type = ZEND_FFI_TYPE(arg_type);
- arg_values[n] = ((char*)arg_values) + (sizeof(void*) * EX_NUM_ARGS()) + (ZEND_FFI_SIZEOF_ARG * n);
- if (zend_ffi_pass_arg(EX_VAR_NUM(n), arg_type, &arg_types[n], arg_values, n, execute_data) != SUCCESS) {
- free_alloca(arg_types, arg_types_use_heap);
- free_alloca(arg_values, arg_values_use_heap);
- goto exit;
- }
- n++;
- } ZEND_HASH_FOREACH_END();
- }
- for (; n < EX_NUM_ARGS(); n++) {
- arg_values[n] = ((char*)arg_values) + (sizeof(void*) * EX_NUM_ARGS()) + (ZEND_FFI_SIZEOF_ARG * n);
- if (zend_ffi_pass_var_arg(EX_VAR_NUM(n), &arg_types[n], arg_values, n, execute_data) != SUCCESS) {
- free_alloca(arg_types, arg_types_use_heap);
- free_alloca(arg_values, arg_values_use_heap);
- goto exit;
- }
- }
- }
- ret_type = zend_ffi_get_type(ZEND_FFI_TYPE(type->func.ret_type));
- if (!ret_type) {
- zend_ffi_return_unsupported(type->func.ret_type);
- free_alloca(arg_types, arg_types_use_heap);
- free_alloca(arg_values, arg_values_use_heap);
- goto exit;
- }
- if (ffi_prep_cif_var(&cif, type->func.abi, arg_count, EX_NUM_ARGS(), ret_type, arg_types) != FFI_OK) {
- zend_throw_error(zend_ffi_exception_ce, "Cannot prepare callback CIF");
- free_alloca(arg_types, arg_types_use_heap);
- free_alloca(arg_values, arg_values_use_heap);
- goto exit;
- }
- } else {
- if (arg_count != EX_NUM_ARGS()) {
- zend_throw_error(zend_ffi_exception_ce, "Incorrect number of arguments for C function '%s', expecting exactly %d parameter%s", ZSTR_VAL(EX(func)->internal_function.function_name), arg_count, (arg_count != 1) ? "s" : "");
- goto exit;
- }
- if (EX_NUM_ARGS()) {
- arg_types = do_alloca(
- (sizeof(ffi_type*) + sizeof(ffi_type)) * EX_NUM_ARGS(), arg_types_use_heap);
- arg_values = do_alloca(
- (sizeof(void*) + ZEND_FFI_SIZEOF_ARG) * EX_NUM_ARGS(), arg_values_use_heap);
- n = 0;
- if (type->func.args) {
- ZEND_HASH_FOREACH_PTR(type->func.args, arg_type) {
- arg_type = ZEND_FFI_TYPE(arg_type);
- arg_values[n] = ((char*)arg_values) + (sizeof(void*) * EX_NUM_ARGS()) + (ZEND_FFI_SIZEOF_ARG * n);
- if (zend_ffi_pass_arg(EX_VAR_NUM(n), arg_type, &arg_types[n], arg_values, n, execute_data) != SUCCESS) {
- free_alloca(arg_types, arg_types_use_heap);
- free_alloca(arg_values, arg_values_use_heap);
- goto exit;
- }
- n++;
- } ZEND_HASH_FOREACH_END();
- }
- }
- ret_type = zend_ffi_get_type(ZEND_FFI_TYPE(type->func.ret_type));
- if (!ret_type) {
- zend_ffi_return_unsupported(type->func.ret_type);
- free_alloca(arg_types, arg_types_use_heap);
- free_alloca(arg_values, arg_values_use_heap);
- goto exit;
- }
- if (ffi_prep_cif(&cif, type->func.abi, arg_count, ret_type, arg_types) != FFI_OK) {
- zend_throw_error(zend_ffi_exception_ce, "Cannot prepare callback CIF");
- free_alloca(arg_types, arg_types_use_heap);
- free_alloca(arg_values, arg_values_use_heap);
- goto exit;
- }
- }
- ret = do_alloca(MAX(ret_type->size, sizeof(ffi_arg)), ret_use_heap);
- ffi_call(&cif, addr, ret, arg_values);
- for (n = 0; n < arg_count; n++) {
- if (arg_types[n]->type == FFI_TYPE_STRUCT) {
- efree(arg_types[n]);
- }
- }
- if (ret_type->type == FFI_TYPE_STRUCT) {
- efree(ret_type);
- }
- if (EX_NUM_ARGS()) {
- free_alloca(arg_types, arg_types_use_heap);
- free_alloca(arg_values, arg_values_use_heap);
- }
- zend_ffi_cdata_to_zval(NULL, ret, ZEND_FFI_TYPE(type->func.ret_type), BP_VAR_R, return_value, 0, 1, 0);
- free_alloca(ret, ret_use_heap);
- exit:
- zend_string_release(EX(func)->common.function_name);
- if (EX(func)->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE) {
- zend_free_trampoline(EX(func));
- EX(func) = NULL;
- }
- }
- /* }}} */
- static zend_function *zend_ffi_get_func(zend_object **obj, zend_string *name, const zval *key) /* {{{ */
- {
- zend_ffi *ffi = (zend_ffi*)*obj;
- zend_ffi_symbol *sym = NULL;
- zend_function *func;
- zend_ffi_type *type;
- if (ZSTR_LEN(name) == sizeof("new") -1
- && (ZSTR_VAL(name)[0] == 'n' || ZSTR_VAL(name)[0] == 'N')
- && (ZSTR_VAL(name)[1] == 'e' || ZSTR_VAL(name)[1] == 'E')
- && (ZSTR_VAL(name)[2] == 'w' || ZSTR_VAL(name)[2] == 'W')) {
- return (zend_function*)&zend_ffi_new_fn;
- } else if (ZSTR_LEN(name) == sizeof("cast") -1
- && (ZSTR_VAL(name)[0] == 'c' || ZSTR_VAL(name)[0] == 'C')
- && (ZSTR_VAL(name)[1] == 'a' || ZSTR_VAL(name)[1] == 'A')
- && (ZSTR_VAL(name)[2] == 's' || ZSTR_VAL(name)[2] == 'S')
- && (ZSTR_VAL(name)[3] == 't' || ZSTR_VAL(name)[3] == 'T')) {
- return (zend_function*)&zend_ffi_cast_fn;
- } else if (ZSTR_LEN(name) == sizeof("type") -1
- && (ZSTR_VAL(name)[0] == 't' || ZSTR_VAL(name)[0] == 'T')
- && (ZSTR_VAL(name)[1] == 'y' || ZSTR_VAL(name)[1] == 'Y')
- && (ZSTR_VAL(name)[2] == 'p' || ZSTR_VAL(name)[2] == 'P')
- && (ZSTR_VAL(name)[3] == 'e' || ZSTR_VAL(name)[3] == 'E')) {
- return (zend_function*)&zend_ffi_type_fn;
- }
- if (ffi->symbols) {
- sym = zend_hash_find_ptr(ffi->symbols, name);
- if (sym && sym->kind != ZEND_FFI_SYM_FUNC) {
- sym = NULL;
- }
- }
- if (!sym) {
- zend_throw_error(zend_ffi_exception_ce, "Attempt to call undefined C function '%s'", ZSTR_VAL(name));
- return NULL;
- }
- type = ZEND_FFI_TYPE(sym->type);
- ZEND_ASSERT(type->kind == ZEND_FFI_TYPE_FUNC);
- if (EXPECTED(EG(trampoline).common.function_name == NULL)) {
- func = &EG(trampoline);
- } else {
- func = ecalloc(sizeof(zend_internal_function), 1);
- }
- func->common.type = ZEND_INTERNAL_FUNCTION;
- func->common.arg_flags[0] = 0;
- func->common.arg_flags[1] = 0;
- func->common.arg_flags[2] = 0;
- func->common.fn_flags = ZEND_ACC_CALL_VIA_TRAMPOLINE;
- func->common.function_name = zend_string_copy(name);
- /* set to 0 to avoid arg_info[] allocation, because all values are passed by value anyway */
- func->common.num_args = 0;
- func->common.required_num_args = type->func.args ? zend_hash_num_elements(type->func.args) : 0;
- func->common.scope = NULL;
- func->common.prototype = NULL;
- func->common.arg_info = NULL;
- func->internal_function.handler = ZEND_FN(ffi_trampoline);
- func->internal_function.module = NULL;
- func->internal_function.reserved[0] = type;
- func->internal_function.reserved[1] = sym->addr;
- return func;
- }
- /* }}} */
- static zend_never_inline int zend_ffi_disabled(void) /* {{{ */
- {
- zend_throw_error(zend_ffi_exception_ce, "FFI API is restricted by \"ffi.enable\" configuration directive");
- return 0;
- }
- /* }}} */
- static zend_always_inline int zend_ffi_validate_api_restriction(zend_execute_data *execute_data) /* {{{ */
- {
- if (EXPECTED(FFI_G(restriction) > ZEND_FFI_ENABLED)) {
- ZEND_ASSERT(FFI_G(restriction) == ZEND_FFI_PRELOAD);
- if (FFI_G(is_cli)
- || (execute_data->prev_execute_data
- && (execute_data->prev_execute_data->func->common.fn_flags & ZEND_ACC_PRELOADED))
- || (CG(compiler_options) & ZEND_COMPILE_PRELOAD)) {
- return 1;
- }
- } else if (EXPECTED(FFI_G(restriction) == ZEND_FFI_ENABLED)) {
- return 1;
- }
- return zend_ffi_disabled();
- }
- /* }}} */
- #define ZEND_FFI_VALIDATE_API_RESTRICTION() do { \
- if (UNEXPECTED(!zend_ffi_validate_api_restriction(execute_data))) { \
- RETURN_THROWS(); \
- } \
- } while (0)
- ZEND_METHOD(FFI, cdef) /* {{{ */
- {
- zend_string *code = NULL;
- zend_string *lib = NULL;
- zend_ffi *ffi = NULL;
- DL_HANDLE handle = NULL;
- void *addr;
- ZEND_FFI_VALIDATE_API_RESTRICTION();
- ZEND_PARSE_PARAMETERS_START(0, 2)
- Z_PARAM_OPTIONAL
- Z_PARAM_STR(code)
- Z_PARAM_STR_OR_NULL(lib)
- ZEND_PARSE_PARAMETERS_END();
- if (lib) {
- handle = DL_LOAD(ZSTR_VAL(lib));
- if (!handle) {
- zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s'", ZSTR_VAL(lib));
- RETURN_THROWS();
- }
- #ifdef RTLD_DEFAULT
- } else if (1) {
- // TODO: this might need to be disabled or protected ???
- handle = RTLD_DEFAULT;
- #endif
- }
- FFI_G(symbols) = NULL;
- FFI_G(tags) = NULL;
- if (code && ZSTR_LEN(code)) {
- /* Parse C definitions */
- FFI_G(default_type_attr) = ZEND_FFI_ATTR_STORED;
- if (zend_ffi_parse_decl(ZSTR_VAL(code), ZSTR_LEN(code)) != SUCCESS) {
- if (FFI_G(symbols)) {
- zend_hash_destroy(FFI_G(symbols));
- efree(FFI_G(symbols));
- FFI_G(symbols) = NULL;
- }
- if (FFI_G(tags)) {
- zend_hash_destroy(FFI_G(tags));
- efree(FFI_G(tags));
- FFI_G(tags) = NULL;
- }
- RETURN_THROWS();
- }
- if (FFI_G(symbols)) {
- zend_string *name;
- zend_ffi_symbol *sym;
- ZEND_HASH_FOREACH_STR_KEY_PTR(FFI_G(symbols), name, sym) {
- if (sym->kind == ZEND_FFI_SYM_VAR) {
- addr = DL_FETCH_SYMBOL(handle, ZSTR_VAL(name));
- if (!addr) {
- zend_throw_error(zend_ffi_exception_ce, "Failed resolving C variable '%s'", ZSTR_VAL(name));
- RETURN_THROWS();
- }
- sym->addr = addr;
- } else if (sym->kind == ZEND_FFI_SYM_FUNC) {
- zend_string *mangled_name = zend_ffi_mangled_func_name(name, ZEND_FFI_TYPE(sym->type));
- addr = DL_FETCH_SYMBOL(handle, ZSTR_VAL(mangled_name));
- zend_string_release(mangled_name);
- if (!addr) {
- zend_throw_error(zend_ffi_exception_ce, "Failed resolving C function '%s'", ZSTR_VAL(name));
- RETURN_THROWS();
- }
- sym->addr = addr;
- }
- } ZEND_HASH_FOREACH_END();
- }
- }
- ffi = (zend_ffi*)zend_ffi_new(zend_ffi_ce);
- ffi->lib = handle;
- ffi->symbols = FFI_G(symbols);
- ffi->tags = FFI_G(tags);
- FFI_G(symbols) = NULL;
- FFI_G(tags) = NULL;
- RETURN_OBJ(&ffi->std);
- }
- /* }}} */
- static int zend_ffi_same_types(zend_ffi_type *old, zend_ffi_type *type) /* {{{ */
- {
- if (old == type) {
- return 1;
- }
- if (old->kind != type->kind
- || old->size != type->size
- || old->align != type->align
- || old->attr != type->attr) {
- return 0;
- }
- switch (old->kind) {
- case ZEND_FFI_TYPE_ENUM:
- return old->enumeration.kind == type->enumeration.kind;
- case ZEND_FFI_TYPE_ARRAY:
- return old->array.length == type->array.length
- && zend_ffi_same_types(ZEND_FFI_TYPE(old->array.type), ZEND_FFI_TYPE(type->array.type));
- case ZEND_FFI_TYPE_POINTER:
- return zend_ffi_same_types(ZEND_FFI_TYPE(old->pointer.type), ZEND_FFI_TYPE(type->pointer.type));
- case ZEND_FFI_TYPE_STRUCT:
- if (zend_hash_num_elements(&old->record.fields) != zend_hash_num_elements(&type->record.fields)) {
- return 0;
- } else {
- zend_ffi_field *old_field, *field;
- zend_string *key;
- Bucket *b = type->record.fields.arData;
- ZEND_HASH_FOREACH_STR_KEY_PTR(&old->record.fields, key, old_field) {
- while (Z_TYPE(b->val) == IS_UNDEF) {
- b++;
- }
- if (key) {
- if (!b->key
- || !zend_string_equals(key, b->key)) {
- return 0;
- }
- } else if (b->key) {
- return 0;
- }
- field = Z_PTR(b->val);
- if (old_field->offset != field->offset
- || old_field->is_const != field->is_const
- || old_field->is_nested != field->is_nested
- || old_field->first_bit != field->first_bit
- || old_field->bits != field->bits
- || !zend_ffi_same_types(ZEND_FFI_TYPE(old_field->type), ZEND_FFI_TYPE(field->type))) {
- return 0;
- }
- b++;
- } ZEND_HASH_FOREACH_END();
- }
- break;
- case ZEND_FFI_TYPE_FUNC:
- if (old->func.abi != type->func.abi
- || ((old->func.args ? zend_hash_num_elements(old->func.args) : 0) != (type->func.args ? zend_hash_num_elements(type->func.args) : 0))
- || !zend_ffi_same_types(ZEND_FFI_TYPE(old->func.ret_type), ZEND_FFI_TYPE(type->func.ret_type))) {
- return 0;
- } else if (old->func.args) {
- zend_ffi_type *arg_type;
- Bucket *b = type->func.args->arData;
- ZEND_HASH_FOREACH_PTR(old->func.args, arg_type) {
- while (Z_TYPE(b->val) == IS_UNDEF) {
- b++;
- }
- if (!zend_ffi_same_types(ZEND_FFI_TYPE(arg_type), ZEND_FFI_TYPE(Z_PTR(b->val)))) {
- return 0;
- }
- b++;
- } ZEND_HASH_FOREACH_END();
- }
- break;
- default:
- break;
- }
- return 1;
- }
- /* }}} */
- static int zend_ffi_same_symbols(zend_ffi_symbol *old, zend_ffi_symbol *sym) /* {{{ */
- {
- if (old->kind != sym->kind || old->is_const != sym->is_const) {
- return 0;
- }
- if (old->kind == ZEND_FFI_SYM_CONST) {
- if (old->value != sym->value) {
- return 0;
- }
- }
- return zend_ffi_same_types(ZEND_FFI_TYPE(old->type), ZEND_FFI_TYPE(sym->type));
- }
- /* }}} */
- static int zend_ffi_same_tags(zend_ffi_tag *old, zend_ffi_tag *tag) /* {{{ */
- {
- if (old->kind != tag->kind) {
- return 0;
- }
- return zend_ffi_same_types(ZEND_FFI_TYPE(old->type), ZEND_FFI_TYPE(tag->type));
- }
- /* }}} */
- static int zend_ffi_subst_old_type(zend_ffi_type **dcl, zend_ffi_type *old, zend_ffi_type *type) /* {{{ */
- {
- zend_ffi_type *dcl_type;
- zend_ffi_field *field;
- if (ZEND_FFI_TYPE(*dcl) == type) {
- *dcl = old;
- return 1;
- }
- dcl_type = *dcl;
- switch (dcl_type->kind) {
- case ZEND_FFI_TYPE_POINTER:
- return zend_ffi_subst_old_type(&dcl_type->pointer.type, old, type);
- case ZEND_FFI_TYPE_ARRAY:
- return zend_ffi_subst_old_type(&dcl_type->array.type, old, type);
- case ZEND_FFI_TYPE_FUNC:
- if (zend_ffi_subst_old_type(&dcl_type->func.ret_type, old, type)) {
- return 1;
- }
- if (dcl_type->func.args) {
- zval *zv;
- ZEND_HASH_FOREACH_VAL(dcl_type->func.args, zv) {
- if (zend_ffi_subst_old_type((zend_ffi_type**)&Z_PTR_P(zv), old, type)) {
- return 1;
- }
- } ZEND_HASH_FOREACH_END();
- }
- break;
- case ZEND_FFI_TYPE_STRUCT:
- ZEND_HASH_FOREACH_PTR(&dcl_type->record.fields, field) {
- if (zend_ffi_subst_old_type(&field->type, old, type)) {
- return 1;
- }
- } ZEND_HASH_FOREACH_END();
- break;
- default:
- break;
- }
- return 0;
- } /* }}} */
- static void zend_ffi_cleanup_type(zend_ffi_type *old, zend_ffi_type *type) /* {{{ */
- {
- zend_ffi_symbol *sym;
- zend_ffi_tag *tag;
- if (FFI_G(symbols)) {
- ZEND_HASH_FOREACH_PTR(FFI_G(symbols), sym) {
- zend_ffi_subst_old_type(&sym->type, old, type);
- } ZEND_HASH_FOREACH_END();
- }
- if (FFI_G(tags)) {
- ZEND_HASH_FOREACH_PTR(FFI_G(tags), tag) {
- zend_ffi_subst_old_type(&tag->type, old, type);
- } ZEND_HASH_FOREACH_END();
- }
- }
- /* }}} */
- static zend_ffi_type *zend_ffi_remember_type(zend_ffi_type *type) /* {{{ */
- {
- if (!FFI_G(weak_types)) {
- FFI_G(weak_types) = emalloc(sizeof(HashTable));
- zend_hash_init(FFI_G(weak_types), 0, NULL, zend_ffi_type_hash_dtor, 0);
- }
- // TODO: avoid dups ???
- type->attr |= ZEND_FFI_ATTR_STORED;
- zend_hash_next_index_insert_ptr(FFI_G(weak_types), ZEND_FFI_TYPE_MAKE_OWNED(type));
- return type;
- }
- /* }}} */
- static zend_ffi *zend_ffi_load(const char *filename, bool preload) /* {{{ */
- {
- struct stat buf;
- int fd;
- char *code, *code_pos, *scope_name, *lib;
- size_t code_size, scope_name_len;
- zend_ffi *ffi;
- DL_HANDLE handle = NULL;
- zend_ffi_scope *scope = NULL;
- zend_string *name;
- zend_ffi_symbol *sym;
- zend_ffi_tag *tag;
- void *addr;
- if (stat(filename, &buf) != 0) {
- if (preload) {
- zend_error(E_WARNING, "FFI: failed pre-loading '%s', file doesn't exist", filename);
- } else {
- zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', file doesn't exist", filename);
- }
- return NULL;
- }
- if ((buf.st_mode & S_IFMT) != S_IFREG) {
- if (preload) {
- zend_error(E_WARNING, "FFI: failed pre-loading '%s', not a regular file", filename);
- } else {
- zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', not a regular file", filename);
- }
- return NULL;
- }
- code_size = buf.st_size;
- code = emalloc(code_size + 1);
- fd = open(filename, O_RDONLY, 0);
- if (fd < 0 || read(fd, code, code_size) != code_size) {
- if (preload) {
- zend_error(E_WARNING, "FFI: Failed pre-loading '%s', cannot read_file", filename);
- } else {
- zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', cannot read_file", filename);
- }
- efree(code);
- close(fd);
- return NULL;
- }
- close(fd);
- code[code_size] = 0;
- FFI_G(symbols) = NULL;
- FFI_G(tags) = NULL;
- FFI_G(persistent) = preload;
- FFI_G(default_type_attr) = preload ?
- ZEND_FFI_ATTR_STORED | ZEND_FFI_ATTR_PERSISTENT :
- ZEND_FFI_ATTR_STORED;
- scope_name = NULL;
- scope_name_len = 0;
- lib = NULL;
- code_pos = zend_ffi_parse_directives(filename, code, &scope_name, &lib, preload);
- if (!code_pos) {
- efree(code);
- FFI_G(persistent) = 0;
- return NULL;
- }
- code_size -= code_pos - code;
- if (zend_ffi_parse_decl(code_pos, code_size) != SUCCESS) {
- if (preload) {
- zend_error(E_WARNING, "FFI: failed pre-loading '%s'", filename);
- } else {
- zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s'", filename);
- }
- goto cleanup;
- }
- if (lib) {
- handle = DL_LOAD(lib);
- if (!handle) {
- if (preload) {
- zend_error(E_WARNING, "FFI: Failed pre-loading '%s'", lib);
- } else {
- zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s'", lib);
- }
- goto cleanup;
- }
- #ifdef RTLD_DEFAULT
- } else if (1) {
- // TODO: this might need to be disabled or protected ???
- handle = RTLD_DEFAULT;
- #endif
- }
- if (preload) {
- if (!scope_name) {
- scope_name = "C";
- }
- scope_name_len = strlen(scope_name);
- if (FFI_G(scopes)) {
- scope = zend_hash_str_find_ptr(FFI_G(scopes), scope_name, scope_name_len);
- }
- }
- if (FFI_G(symbols)) {
- ZEND_HASH_FOREACH_STR_KEY_PTR(FFI_G(symbols), name, sym) {
- if (sym->kind == ZEND_FFI_SYM_VAR) {
- addr = DL_FETCH_SYMBOL(handle, ZSTR_VAL(name));
- if (!addr) {
- if (preload) {
- zend_error(E_WARNING, "FFI: failed pre-loading '%s', cannot resolve C variable '%s'", filename, ZSTR_VAL(name));
- } else {
- zend_throw_error(zend_ffi_exception_ce, "Failed resolving C variable '%s'", ZSTR_VAL(name));
- }
- if (lib) {
- DL_UNLOAD(handle);
- }
- goto cleanup;
- }
- sym->addr = addr;
- } else if (sym->kind == ZEND_FFI_SYM_FUNC) {
- zend_string *mangled_name = zend_ffi_mangled_func_name(name, ZEND_FFI_TYPE(sym->type));
- addr = DL_FETCH_SYMBOL(handle, ZSTR_VAL(mangled_name));
- zend_string_release(mangled_name);
- if (!addr) {
- if (preload) {
- zend_error(E_WARNING, "failed pre-loading '%s', cannot resolve C function '%s'", filename, ZSTR_VAL(name));
- } else {
- zend_throw_error(zend_ffi_exception_ce, "Failed resolving C function '%s'", ZSTR_VAL(name));
- }
- if (lib) {
- DL_UNLOAD(handle);
- }
- goto cleanup;
- }
- sym->addr = addr;
- }
- if (scope && scope->symbols) {
- zend_ffi_symbol *old_sym = zend_hash_find_ptr(scope->symbols, name);
- if (old_sym) {
- if (zend_ffi_same_symbols(old_sym, sym)) {
- if (ZEND_FFI_TYPE_IS_OWNED(sym->type)
- && ZEND_FFI_TYPE(old_sym->type) != ZEND_FFI_TYPE(sym->type)) {
- zend_ffi_type *type = ZEND_FFI_TYPE(sym->type);
- zend_ffi_cleanup_type(ZEND_FFI_TYPE(old_sym->type), ZEND_FFI_TYPE(type));
- zend_ffi_type_dtor(type);
- }
- } else {
- zend_error(E_WARNING, "FFI: failed pre-loading '%s', redefinition of '%s'", filename, ZSTR_VAL(name));
- if (lib) {
- DL_UNLOAD(handle);
- }
- goto cleanup;
- }
- }
- }
- } ZEND_HASH_FOREACH_END();
- }
- if (preload) {
- if (scope && scope->tags && FFI_G(tags)) {
- ZEND_HASH_FOREACH_STR_KEY_PTR(FFI_G(tags), name, tag) {
- zend_ffi_tag *old_tag = zend_hash_find_ptr(scope->tags, name);
- if (old_tag) {
- if (zend_ffi_same_tags(old_tag, tag)) {
- if (ZEND_FFI_TYPE_IS_OWNED(tag->type)
- && ZEND_FFI_TYPE(old_tag->type) != ZEND_FFI_TYPE(tag->type)) {
- zend_ffi_type *type = ZEND_FFI_TYPE(tag->type);
- zend_ffi_cleanup_type(ZEND_FFI_TYPE(old_tag->type), ZEND_FFI_TYPE(type));
- zend_ffi_type_dtor(type);
- }
- } else {
- zend_error(E_WARNING, "FFI: failed pre-loading '%s', redefinition of '%s %s'", filename, zend_ffi_tag_kind_name[tag->kind], ZSTR_VAL(name));
- if (lib) {
- DL_UNLOAD(handle);
- }
- goto cleanup;
- }
- }
- } ZEND_HASH_FOREACH_END();
- }
- if (!scope) {
- scope = malloc(sizeof(zend_ffi_scope));
- scope->symbols = FFI_G(symbols);
- scope->tags = FFI_G(tags);
- if (!FFI_G(scopes)) {
- FFI_G(scopes) = malloc(sizeof(HashTable));
- zend_hash_init(FFI_G(scopes), 0, NULL, zend_ffi_scope_hash_dtor, 1);
- }
- zend_hash_str_add_ptr(FFI_G(scopes), scope_name, scope_name_len, scope);
- } else {
- if (FFI_G(symbols)) {
- if (!scope->symbols) {
- scope->symbols = FFI_G(symbols);
- FFI_G(symbols) = NULL;
- } else {
- ZEND_HASH_FOREACH_STR_KEY_PTR(FFI_G(symbols), name, sym) {
- if (!zend_hash_add_ptr(scope->symbols, name, sym)) {
- zend_ffi_type_dtor(sym->type);
- free(sym);
- }
- } ZEND_HASH_FOREACH_END();
- FFI_G(symbols)->pDestructor = NULL;
- zend_hash_destroy(FFI_G(symbols));
- }
- }
- if (FFI_G(tags)) {
- if (!scope->tags) {
- scope->tags = FFI_G(tags);
- FFI_G(tags) = NULL;
- } else {
- ZEND_HASH_FOREACH_STR_KEY_PTR(FFI_G(tags), name, tag) {
- if (!zend_hash_add_ptr(scope->tags, name, tag)) {
- zend_ffi_type_dtor(tag->type);
- free(tag);
- }
- } ZEND_HASH_FOREACH_END();
- FFI_G(tags)->pDestructor = NULL;
- zend_hash_destroy(FFI_G(tags));
- }
- }
- }
- if (EG(objects_store).object_buckets) {
- ffi = (zend_ffi*)zend_ffi_new(zend_ffi_ce);
- } else {
- ffi = ecalloc(1, sizeof(zend_ffi));
- }
- ffi->symbols = scope->symbols;
- ffi->tags = scope->tags;
- ffi->persistent = 1;
- } else {
- ffi = (zend_ffi*)zend_ffi_new(zend_ffi_ce);
- ffi->lib = handle;
- ffi->symbols = FFI_G(symbols);
- ffi->tags = FFI_G(tags);
- }
- efree(code);
- FFI_G(symbols) = NULL;
- FFI_G(tags) = NULL;
- FFI_G(persistent) = 0;
- return ffi;
- cleanup:
- efree(code);
- if (FFI_G(symbols)) {
- zend_hash_destroy(FFI_G(symbols));
- pefree(FFI_G(symbols), preload);
- FFI_G(symbols) = NULL;
- }
- if (FFI_G(tags)) {
- zend_hash_destroy(FFI_G(tags));
- pefree(FFI_G(tags), preload);
- FFI_G(tags) = NULL;
- }
- FFI_G(persistent) = 0;
- return NULL;
- }
- /* }}} */
- ZEND_METHOD(FFI, load) /* {{{ */
- {
- zend_string *fn;
- zend_ffi *ffi;
- ZEND_FFI_VALIDATE_API_RESTRICTION();
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_STR(fn)
- ZEND_PARSE_PARAMETERS_END();
- if (CG(compiler_options) & ZEND_COMPILE_PRELOAD_IN_CHILD) {
- zend_throw_error(zend_ffi_exception_ce, "FFI::load() doesn't work in conjunction with \"opcache.preload_user\". Use \"ffi.preload\" instead.");
- RETURN_THROWS();
- }
- ffi = zend_ffi_load(ZSTR_VAL(fn), (CG(compiler_options) & ZEND_COMPILE_PRELOAD) != 0);
- if (ffi) {
- RETURN_OBJ(&ffi->std);
- }
- }
- /* }}} */
- ZEND_METHOD(FFI, scope) /* {{{ */
- {
- zend_string *scope_name;
- zend_ffi_scope *scope = NULL;
- zend_ffi *ffi;
- ZEND_FFI_VALIDATE_API_RESTRICTION();
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_STR(scope_name)
- ZEND_PARSE_PARAMETERS_END();
- if (FFI_G(scopes)) {
- scope = zend_hash_find_ptr(FFI_G(scopes), scope_name);
- }
- if (!scope) {
- zend_throw_error(zend_ffi_exception_ce, "Failed loading scope '%s'", ZSTR_VAL(scope_name));
- RETURN_THROWS();
- }
- ffi = (zend_ffi*)zend_ffi_new(zend_ffi_ce);
- ffi->symbols = scope->symbols;
- ffi->tags = scope->tags;
- ffi->persistent = 1;
- RETURN_OBJ(&ffi->std);
- }
- /* }}} */
- static void zend_ffi_cleanup_dcl(zend_ffi_dcl *dcl) /* {{{ */
- {
- if (dcl) {
- zend_ffi_type_dtor(dcl->type);
- dcl->type = NULL;
- }
- }
- /* }}} */
- static void zend_ffi_throw_parser_error(const char *format, ...) /* {{{ */
- {
- va_list va;
- char *message = NULL;
- va_start(va, format);
- zend_vspprintf(&message, 0, format, va);
- if (EG(current_execute_data)) {
- zend_throw_exception(zend_ffi_parser_exception_ce, message, 0);
- } else {
- zend_error(E_WARNING, "FFI Parser: %s", message);
- }
- efree(message);
- va_end(va);
- }
- /* }}} */
- static int zend_ffi_validate_vla(zend_ffi_type *type) /* {{{ */
- {
- if (!FFI_G(allow_vla) && (type->attr & ZEND_FFI_ATTR_VLA)) {
- zend_ffi_throw_parser_error("\"[*]\" is not allowed in other than function prototype scope at line %d", FFI_G(line));
- return FAILURE;
- }
- return SUCCESS;
- }
- /* }}} */
- static int zend_ffi_validate_incomplete_type(zend_ffi_type *type, bool allow_incomplete_tag, bool allow_incomplete_array) /* {{{ */
- {
- if (!allow_incomplete_tag && (type->attr & ZEND_FFI_ATTR_INCOMPLETE_TAG)) {
- if (FFI_G(tags)) {
- zend_string *key;
- zend_ffi_tag *tag;
- ZEND_HASH_FOREACH_STR_KEY_PTR(FFI_G(tags), key, tag) {
- if (ZEND_FFI_TYPE(tag->type) == type) {
- if (type->kind == ZEND_FFI_TYPE_ENUM) {
- zend_ffi_throw_parser_error("Incomplete enum \"%s\" at line %d", ZSTR_VAL(key), FFI_G(line));
- } else if (type->attr & ZEND_FFI_ATTR_UNION) {
- zend_ffi_throw_parser_error("Incomplete union \"%s\" at line %d", ZSTR_VAL(key), FFI_G(line));
- } else {
- zend_ffi_throw_parser_error("Incomplete struct \"%s\" at line %d", ZSTR_VAL(key), FFI_G(line));
- }
- return FAILURE;
- }
- } ZEND_HASH_FOREACH_END();
- }
- if (FFI_G(symbols)) {
- zend_string *key;
- zend_ffi_symbol *sym;
- ZEND_HASH_FOREACH_STR_KEY_PTR(FFI_G(symbols), key, sym) {
- if (type == ZEND_FFI_TYPE(sym->type)) {
- zend_ffi_throw_parser_error("Incomplete C type %s at line %d", ZSTR_VAL(key), FFI_G(line));
- return FAILURE;
- }
- } ZEND_HASH_FOREACH_END();
- }
- zend_ffi_throw_parser_error("Incomplete type at line %d", FFI_G(line));
- return FAILURE;
- } else if (!allow_incomplete_array && (type->attr & ZEND_FFI_ATTR_INCOMPLETE_ARRAY)) {
- zend_ffi_throw_parser_error("\"[]\" is not allowed at line %d", FFI_G(line));
- return FAILURE;
- } else if (!FFI_G(allow_vla) && (type->attr & ZEND_FFI_ATTR_VLA)) {
- zend_ffi_throw_parser_error("\"[*]\" is not allowed in other than function prototype scope at line %d", FFI_G(line));
- return FAILURE;
- }
- return SUCCESS;
- }
- /* }}} */
- static int zend_ffi_validate_type(zend_ffi_type *type, bool allow_incomplete_tag, bool allow_incomplete_array) /* {{{ */
- {
- if (type->kind == ZEND_FFI_TYPE_VOID) {
- zend_ffi_throw_parser_error("void type is not allowed at line %d", FFI_G(line));
- return FAILURE;
- }
- return zend_ffi_validate_incomplete_type(type, allow_incomplete_tag, allow_incomplete_array);
- }
- /* }}} */
- static int zend_ffi_validate_var_type(zend_ffi_type *type, bool allow_incomplete_array) /* {{{ */
- {
- if (type->kind == ZEND_FFI_TYPE_FUNC) {
- zend_ffi_throw_parser_error("function type is not allowed at line %d", FFI_G(line));
- return FAILURE;
- }
- return zend_ffi_validate_type(type, 0, allow_incomplete_array);
- }
- /* }}} */
- void zend_ffi_validate_type_name(zend_ffi_dcl *dcl) /* {{{ */
- {
- zend_ffi_finalize_type(dcl);
- if (zend_ffi_validate_var_type(ZEND_FFI_TYPE(dcl->type), 0) != SUCCESS) {
- zend_ffi_cleanup_dcl(dcl);
- LONGJMP(FFI_G(bailout), FAILURE);
- }
- }
- /* }}} */
- static int zend_ffi_subst_type(zend_ffi_type **dcl, zend_ffi_type *type) /* {{{ */
- {
- zend_ffi_type *dcl_type;
- zend_ffi_field *field;
- if (*dcl == type) {
- *dcl = ZEND_FFI_TYPE_MAKE_OWNED(type);
- return 1;
- }
- dcl_type = *dcl;
- switch (dcl_type->kind) {
- case ZEND_FFI_TYPE_POINTER:
- return zend_ffi_subst_type(&dcl_type->pointer.type, type);
- case ZEND_FFI_TYPE_ARRAY:
- return zend_ffi_subst_type(&dcl_type->array.type, type);
- case ZEND_FFI_TYPE_FUNC:
- if (zend_ffi_subst_type(&dcl_type->func.ret_type, type)) {
- return 1;
- }
- if (dcl_type->func.args) {
- zval *zv;
- ZEND_HASH_FOREACH_VAL(dcl_type->func.args, zv) {
- if (zend_ffi_subst_type((zend_ffi_type**)&Z_PTR_P(zv), type)) {
- return 1;
- }
- } ZEND_HASH_FOREACH_END();
- }
- break;
- case ZEND_FFI_TYPE_STRUCT:
- ZEND_HASH_FOREACH_PTR(&dcl_type->record.fields, field) {
- if (zend_ffi_subst_type(&field->type, type)) {
- return 1;
- }
- } ZEND_HASH_FOREACH_END();
- break;
- default:
- break;
- }
- return 0;
- } /* }}} */
- static void zend_ffi_tags_cleanup(zend_ffi_dcl *dcl) /* {{{ */
- {
- zend_ffi_tag *tag;
- ZEND_HASH_FOREACH_PTR(FFI_G(tags), tag) {
- if (ZEND_FFI_TYPE_IS_OWNED(tag->type)) {
- zend_ffi_type *type = ZEND_FFI_TYPE(tag->type);
- zend_ffi_subst_type(&dcl->type, type);
- tag->type = type;
- }
- } ZEND_HASH_FOREACH_END();
- zend_hash_destroy(FFI_G(tags));
- efree(FFI_G(tags));
- }
- /* }}} */
- ZEND_METHOD(FFI, new) /* {{{ */
- {
- zend_string *type_def = NULL;
- zend_object *type_obj = NULL;
- zend_ffi_type *type, *type_ptr;
- zend_ffi_cdata *cdata;
- void *ptr;
- bool owned = 1;
- bool persistent = 0;
- bool is_const = 0;
- zend_ffi_flags flags = ZEND_FFI_FLAG_OWNED;
- ZEND_FFI_VALIDATE_API_RESTRICTION();
- ZEND_PARSE_PARAMETERS_START(1, 3)
- Z_PARAM_OBJ_OF_CLASS_OR_STR(type_obj, zend_ffi_ctype_ce, type_def)
- Z_PARAM_OPTIONAL
- Z_PARAM_BOOL(owned)
- Z_PARAM_BOOL(persistent)
- ZEND_PARSE_PARAMETERS_END();
- if (!owned) {
- flags &= ~ZEND_FFI_FLAG_OWNED;
- }
- if (persistent) {
- flags |= ZEND_FFI_FLAG_PERSISTENT;
- }
- if (type_def) {
- zend_ffi_dcl dcl = ZEND_FFI_ATTR_INIT;
- if (Z_TYPE(EX(This)) == IS_OBJECT) {
- zend_ffi *ffi = (zend_ffi*)Z_OBJ(EX(This));
- FFI_G(symbols) = ffi->symbols;
- FFI_G(tags) = ffi->tags;
- } else {
- FFI_G(symbols) = NULL;
- FFI_G(tags) = NULL;
- }
- FFI_G(default_type_attr) = 0;
- if (zend_ffi_parse_type(ZSTR_VAL(type_def), ZSTR_LEN(type_def), &dcl) != SUCCESS) {
- zend_ffi_type_dtor(dcl.type);
- if (Z_TYPE(EX(This)) != IS_OBJECT) {
- if (FFI_G(tags)) {
- zend_hash_destroy(FFI_G(tags));
- efree(FFI_G(tags));
- FFI_G(tags) = NULL;
- }
- if (FFI_G(symbols)) {
- zend_hash_destroy(FFI_G(symbols));
- efree(FFI_G(symbols));
- FFI_G(symbols) = NULL;
- }
- }
- return;
- }
- type = ZEND_FFI_TYPE(dcl.type);
- if (dcl.attr & ZEND_FFI_ATTR_CONST) {
- is_const = 1;
- }
- if (Z_TYPE(EX(This)) != IS_OBJECT) {
- if (FFI_G(tags)) {
- zend_ffi_tags_cleanup(&dcl);
- }
- if (FFI_G(symbols)) {
- zend_hash_destroy(FFI_G(symbols));
- efree(FFI_G(symbols));
- FFI_G(symbols) = NULL;
- }
- }
- FFI_G(symbols) = NULL;
- FFI_G(tags) = NULL;
- type_ptr = dcl.type;
- } else {
- zend_ffi_ctype *ctype = (zend_ffi_ctype*) type_obj;
- type_ptr = type = ctype->type;
- if (ZEND_FFI_TYPE_IS_OWNED(type)) {
- type = ZEND_FFI_TYPE(type);
- if (!(type->attr & ZEND_FFI_ATTR_STORED)) {
- if (GC_REFCOUNT(&ctype->std) == 1) {
- /* transfer type ownership */
- ctype->type = type;
- } else {
- ctype->type = type_ptr = type = zend_ffi_remember_type(type);
- }
- }
- }
- }
- if (type->size == 0) {
- zend_throw_error(zend_ffi_exception_ce, "Cannot instantiate FFI\\CData of zero size");
- zend_ffi_type_dtor(type_ptr);
- return;
- }
- ptr = pemalloc(type->size, flags & ZEND_FFI_FLAG_PERSISTENT);
- memset(ptr, 0, type->size);
- cdata = (zend_ffi_cdata*)zend_ffi_cdata_new(zend_ffi_cdata_ce);
- if (type->kind < ZEND_FFI_TYPE_POINTER) {
- cdata->std.handlers = &zend_ffi_cdata_value_handlers;
- }
- cdata->type = type_ptr;
- cdata->ptr = ptr;
- cdata->flags = flags;
- if (is_const) {
- cdata->flags |= ZEND_FFI_FLAG_CONST;
- }
- RETURN_OBJ(&cdata->std);
- }
- /* }}} */
- ZEND_METHOD(FFI, free) /* {{{ */
- {
- zval *zv;
- zend_ffi_cdata *cdata;
- ZEND_FFI_VALIDATE_API_RESTRICTION();
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_OBJECT_OF_CLASS_EX(zv, zend_ffi_cdata_ce, 0, 1);
- ZEND_PARSE_PARAMETERS_END();
- cdata = (zend_ffi_cdata*)Z_OBJ_P(zv);
- if (ZEND_FFI_TYPE(cdata->type)->kind == ZEND_FFI_TYPE_POINTER) {
- if (!cdata->ptr) {
- zend_throw_error(zend_ffi_exception_ce, "NULL pointer dereference");
- RETURN_THROWS();
- }
- if (cdata->ptr != (void*)&cdata->ptr_holder) {
- pefree(*(void**)cdata->ptr, cdata->flags & ZEND_FFI_FLAG_PERSISTENT);
- } else {
- pefree(cdata->ptr_holder, (cdata->flags & ZEND_FFI_FLAG_PERSISTENT) || !is_zend_ptr(cdata->ptr_holder));
- }
- *(void**)cdata->ptr = NULL;
- } else if (!(cdata->flags & ZEND_FFI_FLAG_OWNED)) {
- pefree(cdata->ptr, cdata->flags & ZEND_FFI_FLAG_PERSISTENT);
- cdata->ptr = NULL;
- cdata->flags &= ~(ZEND_FFI_FLAG_OWNED|ZEND_FFI_FLAG_PERSISTENT);
- cdata->std.handlers = &zend_ffi_cdata_free_handlers;
- } else {
- zend_throw_error(zend_ffi_exception_ce, "free() non a C pointer");
- }
- }
- /* }}} */
- ZEND_METHOD(FFI, cast) /* {{{ */
- {
- zend_string *type_def = NULL;
- zend_object *ztype = NULL;
- zend_ffi_type *old_type, *type, *type_ptr;
- zend_ffi_cdata *old_cdata, *cdata;
- bool is_const = 0;
- zval *zv, *arg;
- void *ptr;
- ZEND_FFI_VALIDATE_API_RESTRICTION();
- ZEND_PARSE_PARAMETERS_START(2, 2)
- Z_PARAM_OBJ_OF_CLASS_OR_STR(ztype, zend_ffi_ctype_ce, type_def)
- Z_PARAM_ZVAL(zv)
- ZEND_PARSE_PARAMETERS_END();
- arg = zv;
- ZVAL_DEREF(zv);
- if (type_def) {
- zend_ffi_dcl dcl = ZEND_FFI_ATTR_INIT;
- if (Z_TYPE(EX(This)) == IS_OBJECT) {
- zend_ffi *ffi = (zend_ffi*)Z_OBJ(EX(This));
- FFI_G(symbols) = ffi->symbols;
- FFI_G(tags) = ffi->tags;
- } else {
- FFI_G(symbols) = NULL;
- FFI_G(tags) = NULL;
- }
- FFI_G(default_type_attr) = 0;
- if (zend_ffi_parse_type(ZSTR_VAL(type_def), ZSTR_LEN(type_def), &dcl) != SUCCESS) {
- zend_ffi_type_dtor(dcl.type);
- if (Z_TYPE(EX(This)) != IS_OBJECT) {
- if (FFI_G(tags)) {
- zend_hash_destroy(FFI_G(tags));
- efree(FFI_G(tags));
- FFI_G(tags) = NULL;
- }
- if (FFI_G(symbols)) {
- zend_hash_destroy(FFI_G(symbols));
- efree(FFI_G(symbols));
- FFI_G(symbols) = NULL;
- }
- }
- return;
- }
- type = ZEND_FFI_TYPE(dcl.type);
- if (dcl.attr & ZEND_FFI_ATTR_CONST) {
- is_const = 1;
- }
- if (Z_TYPE(EX(This)) != IS_OBJECT) {
- if (FFI_G(tags)) {
- zend_ffi_tags_cleanup(&dcl);
- }
- if (FFI_G(symbols)) {
- zend_hash_destroy(FFI_G(symbols));
- efree(FFI_G(symbols));
- FFI_G(symbols) = NULL;
- }
- }
- FFI_G(symbols) = NULL;
- FFI_G(tags) = NULL;
- type_ptr = dcl.type;
- } else {
- zend_ffi_ctype *ctype = (zend_ffi_ctype*) ztype;
- type_ptr = type = ctype->type;
- if (ZEND_FFI_TYPE_IS_OWNED(type)) {
- type = ZEND_FFI_TYPE(type);
- if (!(type->attr & ZEND_FFI_ATTR_STORED)) {
- if (GC_REFCOUNT(&ctype->std) == 1) {
- /* transfer type ownership */
- ctype->type = type;
- } else {
- ctype->type = type_ptr = type = zend_ffi_remember_type(type);
- }
- }
- }
- }
- if (Z_TYPE_P(zv) != IS_OBJECT || Z_OBJCE_P(zv) != zend_ffi_cdata_ce) {
- if (type->kind < ZEND_FFI_TYPE_POINTER && Z_TYPE_P(zv) < IS_STRING) {
- /* numeric conversion */
- cdata = (zend_ffi_cdata*)zend_ffi_cdata_new(zend_ffi_cdata_ce);
- cdata->std.handlers = &zend_ffi_cdata_value_handlers;
- cdata->type = type_ptr;
- cdata->ptr = emalloc(type->size);
- zend_ffi_zval_to_cdata(cdata->ptr, type, zv);
- cdata->flags = ZEND_FFI_FLAG_OWNED;
- if (is_const) {
- cdata->flags |= ZEND_FFI_FLAG_CONST;
- }
- RETURN_OBJ(&cdata->std);
- } else if (type->kind == ZEND_FFI_TYPE_POINTER && Z_TYPE_P(zv) == IS_LONG) {
- /* number to pointer conversion */
- cdata = (zend_ffi_cdata*)zend_ffi_cdata_new(zend_ffi_cdata_ce);
- cdata->type = type_ptr;
- cdata->ptr = &cdata->ptr_holder;
- cdata->ptr_holder = (void*)(intptr_t)Z_LVAL_P(zv);
- if (is_const) {
- cdata->flags |= ZEND_FFI_FLAG_CONST;
- }
- RETURN_OBJ(&cdata->std);
- } else if (type->kind == ZEND_FFI_TYPE_POINTER && Z_TYPE_P(zv) == IS_NULL) {
- /* null -> pointer */
- cdata = (zend_ffi_cdata*)zend_ffi_cdata_new(zend_ffi_cdata_ce);
- cdata->type = type_ptr;
- cdata->ptr = &cdata->ptr_holder;
- cdata->ptr_holder = NULL;
- if (is_const) {
- cdata->flags |= ZEND_FFI_FLAG_CONST;
- }
- RETURN_OBJ(&cdata->std);
- } else {
- zend_wrong_parameter_class_error(2, "FFI\\CData", zv);
- RETURN_THROWS();
- }
- }
- old_cdata = (zend_ffi_cdata*)Z_OBJ_P(zv);
- old_type = ZEND_FFI_TYPE(old_cdata->type);
- ptr = old_cdata->ptr;
- cdata = (zend_ffi_cdata*)zend_ffi_cdata_new(zend_ffi_cdata_ce);
- if (type->kind < ZEND_FFI_TYPE_POINTER) {
- cdata->std.handlers = &zend_ffi_cdata_value_handlers;
- }
- cdata->type = type_ptr;
- if (old_type->kind == ZEND_FFI_TYPE_POINTER
- && type->kind != ZEND_FFI_TYPE_POINTER
- && ZEND_FFI_TYPE(old_type->pointer.type)->kind == ZEND_FFI_TYPE_VOID) {
- /* automatically dereference void* pointers ??? */
- cdata->ptr = *(void**)ptr;
- } else if (old_type->kind == ZEND_FFI_TYPE_ARRAY
- && type->kind == ZEND_FFI_TYPE_POINTER
- && zend_ffi_is_compatible_type(ZEND_FFI_TYPE(old_type->array.type), ZEND_FFI_TYPE(type->pointer.type))) { cdata->ptr = &cdata->ptr_holder;
- cdata->ptr = &cdata->ptr_holder;
- cdata->ptr_holder = old_cdata->ptr;
- } else if (old_type->kind == ZEND_FFI_TYPE_POINTER
- && type->kind == ZEND_FFI_TYPE_ARRAY
- && zend_ffi_is_compatible_type(ZEND_FFI_TYPE(old_type->pointer.type), ZEND_FFI_TYPE(type->array.type))) {
- cdata->ptr = old_cdata->ptr_holder;
- } else if (type->size > old_type->size) {
- zend_object_release(&cdata->std);
- zend_throw_error(zend_ffi_exception_ce, "attempt to cast to larger type");
- RETURN_THROWS();
- } else if (ptr != &old_cdata->ptr_holder) {
- cdata->ptr = ptr;
- } else {
- cdata->ptr = &cdata->ptr_holder;
- cdata->ptr_holder = old_cdata->ptr_holder;
- }
- if (is_const) {
- cdata->flags |= ZEND_FFI_FLAG_CONST;
- }
- if (old_cdata->flags & ZEND_FFI_FLAG_OWNED) {
- if (GC_REFCOUNT(&old_cdata->std) == 1 && Z_REFCOUNT_P(arg) == 1) {
- /* transfer ownership */
- old_cdata->flags &= ~ZEND_FFI_FLAG_OWNED;
- cdata->flags |= ZEND_FFI_FLAG_OWNED;
- } else {
- //???zend_throw_error(zend_ffi_exception_ce, "Attempt to cast owned C pointer");
- }
- }
- RETURN_OBJ(&cdata->std);
- }
- /* }}} */
- ZEND_METHOD(FFI, type) /* {{{ */
- {
- zend_ffi_ctype *ctype;
- zend_ffi_dcl dcl = ZEND_FFI_ATTR_INIT;
- zend_string *type_def;
- ZEND_FFI_VALIDATE_API_RESTRICTION();
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_STR(type_def);
- ZEND_PARSE_PARAMETERS_END();
- if (Z_TYPE(EX(This)) == IS_OBJECT) {
- zend_ffi *ffi = (zend_ffi*)Z_OBJ(EX(This));
- FFI_G(symbols) = ffi->symbols;
- FFI_G(tags) = ffi->tags;
- } else {
- FFI_G(symbols) = NULL;
- FFI_G(tags) = NULL;
- }
- FFI_G(default_type_attr) = 0;
- if (zend_ffi_parse_type(ZSTR_VAL(type_def), ZSTR_LEN(type_def), &dcl) != SUCCESS) {
- zend_ffi_type_dtor(dcl.type);
- if (Z_TYPE(EX(This)) != IS_OBJECT) {
- if (FFI_G(tags)) {
- zend_hash_destroy(FFI_G(tags));
- efree(FFI_G(tags));
- FFI_G(tags) = NULL;
- }
- if (FFI_G(symbols)) {
- zend_hash_destroy(FFI_G(symbols));
- efree(FFI_G(symbols));
- FFI_G(symbols) = NULL;
- }
- }
- return;
- }
- if (Z_TYPE(EX(This)) != IS_OBJECT) {
- if (FFI_G(tags)) {
- zend_ffi_tags_cleanup(&dcl);
- }
- if (FFI_G(symbols)) {
- zend_hash_destroy(FFI_G(symbols));
- efree(FFI_G(symbols));
- FFI_G(symbols) = NULL;
- }
- }
- FFI_G(symbols) = NULL;
- FFI_G(tags) = NULL;
- ctype = (zend_ffi_ctype*)zend_ffi_ctype_new(zend_ffi_ctype_ce);
- ctype->type = dcl.type;
- RETURN_OBJ(&ctype->std);
- }
- /* }}} */
- ZEND_METHOD(FFI, typeof) /* {{{ */
- {
- zval *zv, *arg;
- zend_ffi_ctype *ctype;
- zend_ffi_type *type;
- ZEND_FFI_VALIDATE_API_RESTRICTION();
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_ZVAL(zv);
- ZEND_PARSE_PARAMETERS_END();
- arg = zv;
- ZVAL_DEREF(zv);
- if (Z_TYPE_P(zv) == IS_OBJECT && Z_OBJCE_P(zv) == zend_ffi_cdata_ce) {
- zend_ffi_cdata *cdata = (zend_ffi_cdata*)Z_OBJ_P(zv);
- type = cdata->type;
- if (ZEND_FFI_TYPE_IS_OWNED(type)) {
- type = ZEND_FFI_TYPE(type);
- if (!(type->attr & ZEND_FFI_ATTR_STORED)) {
- if (GC_REFCOUNT(&cdata->std) == 1 && Z_REFCOUNT_P(arg) == 1) {
- /* transfer type ownership */
- cdata->type = type;
- type = ZEND_FFI_TYPE_MAKE_OWNED(type);
- } else {
- cdata->type = type = zend_ffi_remember_type(type);
- }
- }
- }
- } else {
- zend_wrong_parameter_class_error(1, "FFI\\CData", zv);
- RETURN_THROWS();
- }
- ctype = (zend_ffi_ctype*)zend_ffi_ctype_new(zend_ffi_ctype_ce);
- ctype->type = type;
- RETURN_OBJ(&ctype->std);
- }
- /* }}} */
- ZEND_METHOD(FFI, arrayType) /* {{{ */
- {
- zval *ztype;
- zend_ffi_ctype *ctype;
- zend_ffi_type *type;
- HashTable *dims;
- zval *val;
- ZEND_FFI_VALIDATE_API_RESTRICTION();
- ZEND_PARSE_PARAMETERS_START(2, 2)
- Z_PARAM_OBJECT_OF_CLASS(ztype, zend_ffi_ctype_ce)
- Z_PARAM_ARRAY_HT(dims)
- ZEND_PARSE_PARAMETERS_END();
- ctype = (zend_ffi_ctype*)Z_OBJ_P(ztype);
- type = ZEND_FFI_TYPE(ctype->type);
- if (type->kind == ZEND_FFI_TYPE_FUNC) {
- zend_throw_error(zend_ffi_exception_ce, "Array of functions is not allowed");
- RETURN_THROWS();
- } else if (type->kind == ZEND_FFI_TYPE_ARRAY && (type->attr & ZEND_FFI_ATTR_INCOMPLETE_ARRAY)) {
- zend_throw_error(zend_ffi_exception_ce, "Only the leftmost array can be undimensioned");
- RETURN_THROWS();
- } else if (type->kind == ZEND_FFI_TYPE_VOID) {
- zend_throw_error(zend_ffi_exception_ce, "Array of void type is not allowed");
- RETURN_THROWS();
- } else if (type->attr & ZEND_FFI_ATTR_INCOMPLETE_TAG) {
- zend_throw_error(zend_ffi_exception_ce, "Array of incomplete type is not allowed");
- RETURN_THROWS();
- }
- if (ZEND_FFI_TYPE_IS_OWNED(ctype->type)) {
- if (!(type->attr & ZEND_FFI_ATTR_STORED)) {
- if (GC_REFCOUNT(&ctype->std) == 1) {
- /* transfer type ownership */
- ctype->type = type;
- type = ZEND_FFI_TYPE_MAKE_OWNED(type);
- } else {
- ctype->type = type = zend_ffi_remember_type(type);
- }
- }
- }
- ZEND_HASH_REVERSE_FOREACH_VAL(dims, val) {
- zend_long n = zval_get_long(val);
- zend_ffi_type *new_type;
- if (n < 0) {
- zend_throw_error(zend_ffi_exception_ce, "negative array index");
- zend_ffi_type_dtor(type);
- RETURN_THROWS();
- } else if (ZEND_FFI_TYPE(type)->kind == ZEND_FFI_TYPE_ARRAY && (ZEND_FFI_TYPE(type)->attr & ZEND_FFI_ATTR_INCOMPLETE_ARRAY)) {
- zend_throw_error(zend_ffi_exception_ce, "only the leftmost array can be undimensioned");
- zend_ffi_type_dtor(type);
- RETURN_THROWS();
- }
- new_type = emalloc(sizeof(zend_ffi_type));
- new_type->kind = ZEND_FFI_TYPE_ARRAY;
- new_type->attr = 0;
- new_type->size = n * ZEND_FFI_TYPE(type)->size;
- new_type->align = ZEND_FFI_TYPE(type)->align;
- new_type->array.type = type;
- new_type->array.length = n;
- if (n == 0) {
- new_type->attr |= ZEND_FFI_ATTR_INCOMPLETE_ARRAY;
- }
- type = ZEND_FFI_TYPE_MAKE_OWNED(new_type);
- } ZEND_HASH_FOREACH_END();
- ctype = (zend_ffi_ctype*)zend_ffi_ctype_new(zend_ffi_ctype_ce);
- ctype->type = type;
- RETURN_OBJ(&ctype->std);
- }
- /* }}} */
- ZEND_METHOD(FFI, addr) /* {{{ */
- {
- zend_ffi_type *type, *new_type;
- zend_ffi_cdata *cdata, *new_cdata;
- zval *zv, *arg;
- ZEND_FFI_VALIDATE_API_RESTRICTION();
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_ZVAL(zv)
- ZEND_PARSE_PARAMETERS_END();
- arg = zv;
- ZVAL_DEREF(zv);
- if (Z_TYPE_P(zv) != IS_OBJECT || Z_OBJCE_P(zv) != zend_ffi_cdata_ce) {
- zend_wrong_parameter_class_error(1, "FFI\\CData", zv);
- RETURN_THROWS();
- }
- cdata = (zend_ffi_cdata*)Z_OBJ_P(zv);
- type = ZEND_FFI_TYPE(cdata->type);
- new_type = emalloc(sizeof(zend_ffi_type));
- new_type->kind = ZEND_FFI_TYPE_POINTER;
- new_type->attr = 0;
- new_type->size = sizeof(void*);
- new_type->align = _Alignof(void*);
- /* life-time (source must relive the resulting pointer) ??? */
- new_type->pointer.type = type;
- new_cdata = (zend_ffi_cdata*)zend_ffi_cdata_new(zend_ffi_cdata_ce);
- new_cdata->type = ZEND_FFI_TYPE_MAKE_OWNED(new_type);
- new_cdata->ptr_holder = cdata->ptr;
- new_cdata->ptr = &new_cdata->ptr_holder;
- if (GC_REFCOUNT(&cdata->std) == 1 && Z_REFCOUNT_P(arg) == 1) {
- if (ZEND_FFI_TYPE_IS_OWNED(cdata->type)) {
- /* transfer type ownership */
- cdata->type = type;
- new_type->pointer.type = ZEND_FFI_TYPE_MAKE_OWNED(type);
- }
- if (cdata->flags & ZEND_FFI_FLAG_OWNED) {
- /* transfer ownership */
- cdata->flags &= ~ZEND_FFI_FLAG_OWNED;
- new_cdata->flags |= ZEND_FFI_FLAG_OWNED;
- }
- }
- RETURN_OBJ(&new_cdata->std);
- }
- /* }}} */
- ZEND_METHOD(FFI, sizeof) /* {{{ */
- {
- zval *zv;
- zend_ffi_type *type;
- ZEND_FFI_VALIDATE_API_RESTRICTION();
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_ZVAL(zv);
- ZEND_PARSE_PARAMETERS_END();
- ZVAL_DEREF(zv);
- if (Z_TYPE_P(zv) == IS_OBJECT && Z_OBJCE_P(zv) == zend_ffi_cdata_ce) {
- zend_ffi_cdata *cdata = (zend_ffi_cdata*)Z_OBJ_P(zv);
- type = ZEND_FFI_TYPE(cdata->type);
- } else if (Z_TYPE_P(zv) == IS_OBJECT && Z_OBJCE_P(zv) == zend_ffi_ctype_ce) {
- zend_ffi_ctype *ctype = (zend_ffi_ctype*)Z_OBJ_P(zv);
- type = ZEND_FFI_TYPE(ctype->type);
- } else {
- zend_wrong_parameter_class_error(1, "FFI\\CData or FFI\\CType", zv);
- RETURN_THROWS();
- }
- RETURN_LONG(type->size);
- }
- /* }}} */
- ZEND_METHOD(FFI, alignof) /* {{{ */
- {
- zval *zv;
- zend_ffi_type *type;
- ZEND_FFI_VALIDATE_API_RESTRICTION();
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_ZVAL(zv);
- ZEND_PARSE_PARAMETERS_END();
- ZVAL_DEREF(zv);
- if (Z_TYPE_P(zv) == IS_OBJECT && Z_OBJCE_P(zv) == zend_ffi_cdata_ce) {
- zend_ffi_cdata *cdata = (zend_ffi_cdata*)Z_OBJ_P(zv);
- type = ZEND_FFI_TYPE(cdata->type);
- } else if (Z_TYPE_P(zv) == IS_OBJECT && Z_OBJCE_P(zv) == zend_ffi_ctype_ce) {
- zend_ffi_ctype *ctype = (zend_ffi_ctype*)Z_OBJ_P(zv);
- type = ZEND_FFI_TYPE(ctype->type);
- } else {
- zend_wrong_parameter_class_error(1, "FFI\\CData or FFI\\CType", zv);
- RETURN_THROWS();
- }
- RETURN_LONG(type->align);
- }
- /* }}} */
- ZEND_METHOD(FFI, memcpy) /* {{{ */
- {
- zval *zv1, *zv2;
- zend_ffi_cdata *cdata1, *cdata2;
- zend_ffi_type *type1, *type2;
- void *ptr1, *ptr2;
- zend_long size;
- ZEND_FFI_VALIDATE_API_RESTRICTION();
- ZEND_PARSE_PARAMETERS_START(3, 3)
- Z_PARAM_OBJECT_OF_CLASS_EX(zv1, zend_ffi_cdata_ce, 0, 1);
- Z_PARAM_ZVAL(zv2)
- Z_PARAM_LONG(size)
- ZEND_PARSE_PARAMETERS_END();
- cdata1 = (zend_ffi_cdata*)Z_OBJ_P(zv1);
- type1 = ZEND_FFI_TYPE(cdata1->type);
- if (type1->kind == ZEND_FFI_TYPE_POINTER) {
- ptr1 = *(void**)cdata1->ptr;
- } else {
- ptr1 = cdata1->ptr;
- if (type1->kind != ZEND_FFI_TYPE_POINTER && size > type1->size) {
- zend_throw_error(zend_ffi_exception_ce, "Attempt to write over data boundary");
- RETURN_THROWS();
- }
- }
- ZVAL_DEREF(zv2);
- if (Z_TYPE_P(zv2) == IS_STRING) {
- ptr2 = Z_STRVAL_P(zv2);
- if (size > Z_STRLEN_P(zv2)) {
- zend_throw_error(zend_ffi_exception_ce, "Attempt to read over string boundary");
- RETURN_THROWS();
- }
- } else if (Z_TYPE_P(zv2) == IS_OBJECT && Z_OBJCE_P(zv2) == zend_ffi_cdata_ce) {
- cdata2 = (zend_ffi_cdata*)Z_OBJ_P(zv2);
- type2 = ZEND_FFI_TYPE(cdata2->type);
- if (type2->kind == ZEND_FFI_TYPE_POINTER) {
- ptr2 = *(void**)cdata2->ptr;
- } else {
- ptr2 = cdata2->ptr;
- if (type2->kind != ZEND_FFI_TYPE_POINTER && size > type2->size) {
- zend_throw_error(zend_ffi_exception_ce, "Attempt to read over data boundary");
- RETURN_THROWS();
- }
- }
- } else {
- zend_wrong_parameter_class_error(2, "FFI\\CData or string", zv2);
- RETURN_THROWS();
- }
- memcpy(ptr1, ptr2, size);
- }
- /* }}} */
- ZEND_METHOD(FFI, memcmp) /* {{{ */
- {
- zval *zv1, *zv2;
- zend_ffi_cdata *cdata1, *cdata2;
- zend_ffi_type *type1, *type2;
- void *ptr1, *ptr2;
- zend_long size;
- int ret;
- ZEND_FFI_VALIDATE_API_RESTRICTION();
- ZEND_PARSE_PARAMETERS_START(3, 3)
- Z_PARAM_ZVAL(zv1);
- Z_PARAM_ZVAL(zv2);
- Z_PARAM_LONG(size)
- ZEND_PARSE_PARAMETERS_END();
- ZVAL_DEREF(zv1);
- if (Z_TYPE_P(zv1) == IS_STRING) {
- ptr1 = Z_STRVAL_P(zv1);
- if (size > Z_STRLEN_P(zv1)) {
- zend_throw_error(zend_ffi_exception_ce, "attempt to read over string boundary");
- RETURN_THROWS();
- }
- } else if (Z_TYPE_P(zv1) == IS_OBJECT && Z_OBJCE_P(zv1) == zend_ffi_cdata_ce) {
- cdata1 = (zend_ffi_cdata*)Z_OBJ_P(zv1);
- type1 = ZEND_FFI_TYPE(cdata1->type);
- if (type1->kind == ZEND_FFI_TYPE_POINTER) {
- ptr1 = *(void**)cdata1->ptr;
- } else {
- ptr1 = cdata1->ptr;
- if (type1->kind != ZEND_FFI_TYPE_POINTER && size > type1->size) {
- zend_throw_error(zend_ffi_exception_ce, "attempt to read over data boundary");
- RETURN_THROWS();
- }
- }
- } else {
- zend_wrong_parameter_class_error(1, "FFI\\CData or string", zv1);
- RETURN_THROWS();
- }
- ZVAL_DEREF(zv2);
- if (Z_TYPE_P(zv2) == IS_STRING) {
- ptr2 = Z_STRVAL_P(zv2);
- if (size > Z_STRLEN_P(zv2)) {
- zend_throw_error(zend_ffi_exception_ce, "Attempt to read over string boundary");
- RETURN_THROWS();
- }
- } else if (Z_TYPE_P(zv2) == IS_OBJECT && Z_OBJCE_P(zv2) == zend_ffi_cdata_ce) {
- cdata2 = (zend_ffi_cdata*)Z_OBJ_P(zv2);
- type2 = ZEND_FFI_TYPE(cdata2->type);
- if (type2->kind == ZEND_FFI_TYPE_POINTER) {
- ptr2 = *(void**)cdata2->ptr;
- } else {
- ptr2 = cdata2->ptr;
- if (type2->kind != ZEND_FFI_TYPE_POINTER && size > type2->size) {
- zend_throw_error(zend_ffi_exception_ce, "Attempt to read over data boundary");
- RETURN_THROWS();
- }
- }
- } else {
- zend_wrong_parameter_class_error(2, "FFI\\CData or string", zv2);
- RETURN_THROWS();
- }
- ret = memcmp(ptr1, ptr2, size);
- if (ret == 0) {
- RETVAL_LONG(0);
- } else if (ret < 0) {
- RETVAL_LONG(-1);
- } else {
- RETVAL_LONG(1);
- }
- }
- /* }}} */
- ZEND_METHOD(FFI, memset) /* {{{ */
- {
- zval *zv;
- zend_ffi_cdata *cdata;
- zend_ffi_type *type;
- void *ptr;
- zend_long ch, size;
- ZEND_FFI_VALIDATE_API_RESTRICTION();
- ZEND_PARSE_PARAMETERS_START(3, 3)
- Z_PARAM_OBJECT_OF_CLASS_EX(zv, zend_ffi_cdata_ce, 0, 1);
- Z_PARAM_LONG(ch)
- Z_PARAM_LONG(size)
- ZEND_PARSE_PARAMETERS_END();
- cdata = (zend_ffi_cdata*)Z_OBJ_P(zv);
- type = ZEND_FFI_TYPE(cdata->type);
- if (type->kind == ZEND_FFI_TYPE_POINTER) {
- ptr = *(void**)cdata->ptr;
- } else {
- ptr = cdata->ptr;
- if (type->kind != ZEND_FFI_TYPE_POINTER && size > type->size) {
- zend_throw_error(zend_ffi_exception_ce, "attempt to write over data boundary");
- RETURN_THROWS();
- }
- }
- memset(ptr, ch, size);
- }
- /* }}} */
- ZEND_METHOD(FFI, string) /* {{{ */
- {
- zval *zv;
- zend_ffi_cdata *cdata;
- zend_ffi_type *type;
- void *ptr;
- zend_long size;
- bool size_is_null = 1;
- ZEND_FFI_VALIDATE_API_RESTRICTION();
- ZEND_PARSE_PARAMETERS_START(1, 2)
- Z_PARAM_OBJECT_OF_CLASS_EX(zv, zend_ffi_cdata_ce, 0, 1);
- Z_PARAM_OPTIONAL
- Z_PARAM_LONG_OR_NULL(size, size_is_null)
- ZEND_PARSE_PARAMETERS_END();
- cdata = (zend_ffi_cdata*)Z_OBJ_P(zv);
- type = ZEND_FFI_TYPE(cdata->type);
- if (!size_is_null) {
- if (type->kind == ZEND_FFI_TYPE_POINTER) {
- ptr = *(void**)cdata->ptr;
- } else {
- ptr = cdata->ptr;
- if (type->kind != ZEND_FFI_TYPE_POINTER && size > type->size) {
- zend_throw_error(zend_ffi_exception_ce, "attempt to read over data boundary");
- RETURN_THROWS();
- }
- }
- RETURN_STRINGL((char*)ptr, size);
- } else {
- if (type->kind == ZEND_FFI_TYPE_POINTER && ZEND_FFI_TYPE(type->pointer.type)->kind == ZEND_FFI_TYPE_CHAR) {
- ptr = *(void**)cdata->ptr;
- } else if (type->kind == ZEND_FFI_TYPE_ARRAY && ZEND_FFI_TYPE(type->array.type)->kind == ZEND_FFI_TYPE_CHAR) {
- ptr = cdata->ptr;
- } else {
- zend_throw_error(zend_ffi_exception_ce, "FFI\\Cdata is not a C string");
- RETURN_THROWS();
- }
- RETURN_STRING((char*)ptr);
- }
- }
- /* }}} */
- ZEND_METHOD(FFI, isNull) /* {{{ */
- {
- zval *zv;
- zend_ffi_cdata *cdata;
- zend_ffi_type *type;
- ZEND_FFI_VALIDATE_API_RESTRICTION();
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_ZVAL(zv);
- ZEND_PARSE_PARAMETERS_END();
- ZVAL_DEREF(zv);
- if (Z_TYPE_P(zv) != IS_OBJECT || Z_OBJCE_P(zv) != zend_ffi_cdata_ce) {
- zend_wrong_parameter_class_error(1, "FFI\\CData", zv);
- RETURN_THROWS();
- }
- cdata = (zend_ffi_cdata*)Z_OBJ_P(zv);
- type = ZEND_FFI_TYPE(cdata->type);
- if (type->kind != ZEND_FFI_TYPE_POINTER){
- zend_throw_error(zend_ffi_exception_ce, "FFI\\Cdata is not a pointer");
- RETURN_THROWS();
- }
- RETURN_BOOL(*(void**)cdata->ptr == NULL);
- }
- /* }}} */
- ZEND_METHOD(FFI_CType, getName) /* {{{ */
- {
- zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
- if (zend_parse_parameters_none() == FAILURE) {
- RETURN_THROWS();
- }
- zend_ffi_ctype_name_buf buf;
- buf.start = buf.end = buf.buf + ((MAX_TYPE_NAME_LEN * 3) / 4);
- if (!zend_ffi_ctype_name(&buf, ZEND_FFI_TYPE(ctype->type))) {
- RETURN_STR_COPY(Z_OBJ_P(ZEND_THIS)->ce->name);
- } else {
- size_t len = buf.end - buf.start;
- zend_string *res = zend_string_init(buf.start, len, 0);
- RETURN_STR(res);
- }
- }
- /* }}} */
- ZEND_METHOD(FFI_CType, getKind) /* {{{ */
- {
- zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
- zend_ffi_type *type;
- if (zend_parse_parameters_none() == FAILURE) {
- RETURN_THROWS();
- }
- type = ZEND_FFI_TYPE(ctype->type);
- RETURN_LONG(type->kind);
- }
- /* }}} */
- ZEND_METHOD(FFI_CType, getSize) /* {{{ */
- {
- zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
- zend_ffi_type *type;
- if (zend_parse_parameters_none() == FAILURE) {
- RETURN_THROWS();
- }
- type = ZEND_FFI_TYPE(ctype->type);
- RETURN_LONG(type->size);
- }
- /* }}} */
- ZEND_METHOD(FFI_CType, getAlignment) /* {{{ */
- {
- zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
- zend_ffi_type *type;
- if (zend_parse_parameters_none() == FAILURE) {
- RETURN_THROWS();
- }
- type = ZEND_FFI_TYPE(ctype->type);
- RETURN_LONG(type->align);
- }
- /* }}} */
- ZEND_METHOD(FFI_CType, getAttributes) /* {{{ */
- {
- zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
- zend_ffi_type *type;
- if (zend_parse_parameters_none() == FAILURE) {
- RETURN_THROWS();
- }
- type = ZEND_FFI_TYPE(ctype->type);
- RETURN_LONG(type->attr);
- }
- /* }}} */
- ZEND_METHOD(FFI_CType, getEnumKind) /* {{{ */
- {
- zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
- zend_ffi_type *type;
- if (zend_parse_parameters_none() == FAILURE) {
- RETURN_THROWS();
- }
- type = ZEND_FFI_TYPE(ctype->type);
- if (type->kind != ZEND_FFI_TYPE_ENUM) {
- zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not an enumeration");
- RETURN_THROWS();
- }
- RETURN_LONG(type->enumeration.kind);
- }
- /* }}} */
- ZEND_METHOD(FFI_CType, getArrayElementType) /* {{{ */
- {
- zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
- zend_ffi_type *type;
- zend_ffi_ctype *ret;
- if (zend_parse_parameters_none() == FAILURE) {
- RETURN_THROWS();
- }
- type = ZEND_FFI_TYPE(ctype->type);
- if (type->kind != ZEND_FFI_TYPE_ARRAY) {
- zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not an array");
- RETURN_THROWS();
- }
- ret = (zend_ffi_ctype*)zend_ffi_ctype_new(zend_ffi_ctype_ce);
- ret->type = ZEND_FFI_TYPE(type->array.type);
- RETURN_OBJ(&ret->std);
- }
- /* }}} */
- ZEND_METHOD(FFI_CType, getArrayLength) /* {{{ */
- {
- zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
- zend_ffi_type *type;
- if (zend_parse_parameters_none() == FAILURE) {
- RETURN_THROWS();
- }
- type = ZEND_FFI_TYPE(ctype->type);
- if (type->kind != ZEND_FFI_TYPE_ARRAY) {
- zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not an array");
- RETURN_THROWS();
- }
- RETURN_LONG(type->array.length);
- }
- /* }}} */
- ZEND_METHOD(FFI_CType, getPointerType) /* {{{ */
- {
- zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
- zend_ffi_ctype *ret;
- zend_ffi_type *type;
- if (zend_parse_parameters_none() == FAILURE) {
- RETURN_THROWS();
- }
- type = ZEND_FFI_TYPE(ctype->type);
- if (type->kind != ZEND_FFI_TYPE_POINTER) {
- zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not a pointer");
- RETURN_THROWS();
- }
- ret = (zend_ffi_ctype*)zend_ffi_ctype_new(zend_ffi_ctype_ce);
- ret->type = ZEND_FFI_TYPE(type->pointer.type);
- RETURN_OBJ(&ret->std);
- }
- /* }}} */
- ZEND_METHOD(FFI_CType, getStructFieldNames) /* {{{ */
- {
- zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
- zend_ffi_type *type;
- HashTable *ht;
- zend_string* name;
- zval zv;
- if (zend_parse_parameters_none() == FAILURE) {
- RETURN_THROWS();
- }
- type = ZEND_FFI_TYPE(ctype->type);
- if (type->kind != ZEND_FFI_TYPE_STRUCT) {
- zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not a structure");
- RETURN_THROWS();
- }
- ht = zend_new_array(zend_hash_num_elements(&type->record.fields));
- RETVAL_ARR(ht);
- ZEND_HASH_FOREACH_STR_KEY(&type->record.fields, name) {
- ZVAL_STR_COPY(&zv, name);
- zend_hash_next_index_insert_new(ht, &zv);
- } ZEND_HASH_FOREACH_END();
- }
- /* }}} */
- ZEND_METHOD(FFI_CType, getStructFieldOffset) /* {{{ */
- {
- zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
- zend_ffi_type *type;
- zend_string *name;
- zend_ffi_field *ptr;
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_STR(name)
- ZEND_PARSE_PARAMETERS_END();
- type = ZEND_FFI_TYPE(ctype->type);
- if (type->kind != ZEND_FFI_TYPE_STRUCT) {
- zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not a structure");
- RETURN_THROWS();
- }
- ptr = zend_hash_find_ptr(&type->record.fields, name);
- if (!ptr) {
- zend_throw_error(zend_ffi_exception_ce, "Wrong field name");
- RETURN_THROWS();
- }
- RETURN_LONG(ptr->offset);
- }
- /* }}} */
- ZEND_METHOD(FFI_CType, getStructFieldType) /* {{{ */
- {
- zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
- zend_ffi_type *type;
- zend_string *name;
- zend_ffi_field *ptr;
- zend_ffi_ctype *ret;
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_STR(name)
- ZEND_PARSE_PARAMETERS_END();
- type = ZEND_FFI_TYPE(ctype->type);
- if (type->kind != ZEND_FFI_TYPE_STRUCT) {
- zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not a structure");
- RETURN_THROWS();
- }
- ptr = zend_hash_find_ptr(&type->record.fields, name);
- if (!ptr) {
- zend_throw_error(zend_ffi_exception_ce, "Wrong field name");
- RETURN_THROWS();
- }
- ret = (zend_ffi_ctype*)zend_ffi_ctype_new(zend_ffi_ctype_ce);
- ret->type = ZEND_FFI_TYPE(ptr->type);
- RETURN_OBJ(&ret->std);
- }
- /* }}} */
- ZEND_METHOD(FFI_CType, getFuncABI) /* {{{ */
- {
- zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
- zend_ffi_type *type;
- if (zend_parse_parameters_none() == FAILURE) {
- RETURN_THROWS();
- }
- type = ZEND_FFI_TYPE(ctype->type);
- if (type->kind != ZEND_FFI_TYPE_FUNC) {
- zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not a function");
- RETURN_THROWS();
- }
- RETURN_LONG(type->func.abi);
- }
- /* }}} */
- ZEND_METHOD(FFI_CType, getFuncReturnType) /* {{{ */
- {
- zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
- zend_ffi_ctype *ret;
- zend_ffi_type *type;
- if (zend_parse_parameters_none() == FAILURE) {
- RETURN_THROWS();
- }
- type = ZEND_FFI_TYPE(ctype->type);
- if (type->kind != ZEND_FFI_TYPE_FUNC) {
- zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not a function");
- RETURN_THROWS();
- }
- ret = (zend_ffi_ctype*)zend_ffi_ctype_new(zend_ffi_ctype_ce);
- ret->type = ZEND_FFI_TYPE(type->func.ret_type);
- RETURN_OBJ(&ret->std);
- }
- /* }}} */
- ZEND_METHOD(FFI_CType, getFuncParameterCount) /* {{{ */
- {
- zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
- zend_ffi_type *type;
- if (zend_parse_parameters_none() == FAILURE) {
- RETURN_THROWS();
- }
- type = ZEND_FFI_TYPE(ctype->type);
- if (type->kind != ZEND_FFI_TYPE_FUNC) {
- zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not a function");
- RETURN_THROWS();
- }
- RETURN_LONG(type->func.args ? zend_hash_num_elements(type->func.args) : 0);
- }
- /* }}} */
- ZEND_METHOD(FFI_CType, getFuncParameterType) /* {{{ */
- {
- zend_ffi_ctype *ctype = (zend_ffi_ctype*)(Z_OBJ_P(ZEND_THIS));
- zend_ffi_type *type, *ptr;
- zend_long n;
- zend_ffi_ctype *ret;
- ZEND_PARSE_PARAMETERS_START(1, 1)
- Z_PARAM_LONG(n)
- ZEND_PARSE_PARAMETERS_END();
- type = ZEND_FFI_TYPE(ctype->type);
- if (type->kind != ZEND_FFI_TYPE_FUNC) {
- zend_throw_error(zend_ffi_exception_ce, "FFI\\CType is not a function");
- RETURN_THROWS();
- }
- if (!type->func.args) {
- zend_throw_error(zend_ffi_exception_ce, "Wrong argument number");
- RETURN_THROWS();
- }
- ptr = zend_hash_index_find_ptr(type->func.args, n);
- if (!ptr) {
- zend_throw_error(zend_ffi_exception_ce, "Wrong argument number");
- RETURN_THROWS();
- }
- ret = (zend_ffi_ctype*)zend_ffi_ctype_new(zend_ffi_ctype_ce);
- ret->type = ZEND_FFI_TYPE(ptr);
- RETURN_OBJ(&ret->std);
- }
- /* }}} */
- static char *zend_ffi_parse_directives(const char *filename, char *code_pos, char **scope_name, char **lib, bool preload) /* {{{ */
- {
- char *p;
- *scope_name = NULL;
- *lib = NULL;
- while (*code_pos == '#') {
- if (strncmp(code_pos, "#define FFI_SCOPE", sizeof("#define FFI_SCOPE") - 1) == 0
- && (code_pos[sizeof("#define FFI_SCOPE") - 1] == ' '
- || code_pos[sizeof("#define FFI_SCOPE") - 1] == '\t')) {
- p = code_pos + sizeof("#define FFI_SCOPE");
- while (*p == ' ' || *p == '\t') {
- p++;
- }
- if (*p != '"') {
- if (preload) {
- zend_error(E_WARNING, "FFI: failed pre-loading '%s', bad FFI_SCOPE define", filename);
- } else {
- zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', bad FFI_SCOPE define", filename);
- }
- return NULL;
- }
- p++;
- if (*scope_name) {
- if (preload) {
- zend_error(E_WARNING, "FFI: failed pre-loading '%s', FFI_SCOPE defined twice", filename);
- } else {
- zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', FFI_SCOPE defined twice", filename);
- }
- return NULL;
- }
- *scope_name = p;
- while (1) {
- if (*p == '\"') {
- *p = 0;
- p++;
- break;
- } else if (*p <= ' ') {
- if (preload) {
- zend_error(E_WARNING, "FFI: failed pre-loading '%s', bad FFI_SCOPE define", filename);
- } else {
- zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', bad FFI_SCOPE define", filename);
- }
- return NULL;
- }
- p++;
- }
- while (*p == ' ' || *p == '\t') {
- p++;
- }
- while (*p == '\r' || *p == '\n') {
- p++;
- }
- code_pos = p;
- } else if (strncmp(code_pos, "#define FFI_LIB", sizeof("#define FFI_LIB") - 1) == 0
- && (code_pos[sizeof("#define FFI_LIB") - 1] == ' '
- || code_pos[sizeof("#define FFI_LIB") - 1] == '\t')) {
- p = code_pos + sizeof("#define FFI_LIB");
- while (*p == ' ' || *p == '\t') {
- p++;
- }
- if (*p != '"') {
- if (preload) {
- zend_error(E_WARNING, "FFI: failed pre-loading '%s', bad FFI_LIB define", filename);
- } else {
- zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', bad FFI_LIB define", filename);
- }
- return NULL;
- }
- p++;
- if (*lib) {
- if (preload) {
- zend_error(E_WARNING, "FFI: failed pre-loading '%s', FFI_LIB defined twice", filename);
- } else {
- zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', FFI_LIB defined twice", filename);
- }
- return NULL;
- }
- *lib = p;
- while (1) {
- if (*p == '\"') {
- *p = 0;
- p++;
- break;
- } else if (*p <= ' ') {
- if (preload) {
- zend_error(E_WARNING, "FFI: failed pre-loading '%s', bad FFI_LIB define", filename);
- } else {
- zend_throw_error(zend_ffi_exception_ce, "Failed loading '%s', bad FFI_LIB define", filename);
- }
- return NULL;
- }
- p++;
- }
- while (*p == ' ' || *p == '\t') {
- p++;
- }
- while (*p == '\r' || *p == '\n') {
- p++;
- }
- code_pos = p;
- } else {
- break;
- }
- }
- return code_pos;
- }
- /* }}} */
- static ZEND_COLD zend_function *zend_fake_get_constructor(zend_object *object) /* {{{ */
- {
- zend_throw_error(NULL, "Instantiation of %s is not allowed", ZSTR_VAL(object->ce->name));
- return NULL;
- }
- /* }}} */
- static ZEND_COLD zend_never_inline void zend_bad_array_access(zend_class_entry *ce) /* {{{ */
- {
- zend_throw_error(NULL, "Cannot use object of type %s as array", ZSTR_VAL(ce->name));
- }
- /* }}} */
- static ZEND_COLD zval *zend_fake_read_dimension(zend_object *obj, zval *offset, int type, zval *rv) /* {{{ */
- {
- zend_bad_array_access(obj->ce);
- return NULL;
- }
- /* }}} */
- static ZEND_COLD void zend_fake_write_dimension(zend_object *obj, zval *offset, zval *value) /* {{{ */
- {
- zend_bad_array_access(obj->ce);
- }
- /* }}} */
- static ZEND_COLD int zend_fake_has_dimension(zend_object *obj, zval *offset, int check_empty) /* {{{ */
- {
- zend_bad_array_access(obj->ce);
- return 0;
- }
- /* }}} */
- static ZEND_COLD void zend_fake_unset_dimension(zend_object *obj, zval *offset) /* {{{ */
- {
- zend_bad_array_access(obj->ce);
- }
- /* }}} */
- static ZEND_COLD zend_never_inline void zend_bad_property_access(zend_class_entry *ce) /* {{{ */
- {
- zend_throw_error(NULL, "Cannot access property of object of type %s", ZSTR_VAL(ce->name));
- }
- /* }}} */
- static ZEND_COLD zval *zend_fake_read_property(zend_object *obj, zend_string *member, int type, void **cache_slot, zval *rv) /* {{{ */
- {
- zend_bad_property_access(obj->ce);
- return &EG(uninitialized_zval);
- }
- /* }}} */
- static ZEND_COLD zval *zend_fake_write_property(zend_object *obj, zend_string *member, zval *value, void **cache_slot) /* {{{ */
- {
- zend_bad_array_access(obj->ce);
- return value;
- }
- /* }}} */
- static ZEND_COLD int zend_fake_has_property(zend_object *obj, zend_string *member, int has_set_exists, void **cache_slot) /* {{{ */
- {
- zend_bad_array_access(obj->ce);
- return 0;
- }
- /* }}} */
- static ZEND_COLD void zend_fake_unset_property(zend_object *obj, zend_string *member, void **cache_slot) /* {{{ */
- {
- zend_bad_array_access(obj->ce);
- }
- /* }}} */
- static zval *zend_fake_get_property_ptr_ptr(zend_object *obj, zend_string *member, int type, void **cache_slot) /* {{{ */
- {
- return NULL;
- }
- /* }}} */
- static ZEND_COLD zend_function *zend_fake_get_method(zend_object **obj_ptr, zend_string *method_name, const zval *key) /* {{{ */
- {
- zend_class_entry *ce = (*obj_ptr)->ce;
- zend_throw_error(NULL, "Object of type %s does not support method calls", ZSTR_VAL(ce->name));
- return NULL;
- }
- /* }}} */
- static HashTable *zend_fake_get_properties(zend_object *obj) /* {{{ */
- {
- return (HashTable*)&zend_empty_array;
- }
- /* }}} */
- static HashTable *zend_fake_get_gc(zend_object *ob, zval **table, int *n) /* {{{ */
- {
- *table = NULL;
- *n = 0;
- return NULL;
- }
- /* }}} */
- static int zend_fake_cast_object(zend_object *obj, zval *result, int type)
- {
- switch (type) {
- case _IS_BOOL:
- ZVAL_TRUE(result);
- return SUCCESS;
- default:
- return FAILURE;
- }
- }
- static ZEND_COLD zend_never_inline void zend_ffi_use_after_free(void) /* {{{ */
- {
- zend_throw_error(zend_ffi_exception_ce, "Use after free()");
- }
- /* }}} */
- static zend_object *zend_ffi_free_clone_obj(zend_object *obj) /* {{{ */
- {
- zend_ffi_use_after_free();
- return NULL;
- }
- /* }}} */
- static ZEND_COLD zval *zend_ffi_free_read_dimension(zend_object *obj, zval *offset, int type, zval *rv) /* {{{ */
- {
- zend_ffi_use_after_free();
- return NULL;
- }
- /* }}} */
- static ZEND_COLD void zend_ffi_free_write_dimension(zend_object *obj, zval *offset, zval *value) /* {{{ */
- {
- zend_ffi_use_after_free();
- }
- /* }}} */
- static ZEND_COLD int zend_ffi_free_has_dimension(zend_object *obj, zval *offset, int check_empty) /* {{{ */
- {
- zend_ffi_use_after_free();
- return 0;
- }
- /* }}} */
- static ZEND_COLD void zend_ffi_free_unset_dimension(zend_object *obj, zval *offset) /* {{{ */
- {
- zend_ffi_use_after_free();
- }
- /* }}} */
- static ZEND_COLD zval *zend_ffi_free_read_property(zend_object *obj, zend_string *member, int type, void **cache_slot, zval *rv) /* {{{ */
- {
- zend_ffi_use_after_free();
- return &EG(uninitialized_zval);
- }
- /* }}} */
- static ZEND_COLD zval *zend_ffi_free_write_property(zend_object *obj, zend_string *member, zval *value, void **cache_slot) /* {{{ */
- {
- zend_ffi_use_after_free();
- return value;
- }
- /* }}} */
- static ZEND_COLD int zend_ffi_free_has_property(zend_object *obj, zend_string *member, int has_set_exists, void **cache_slot) /* {{{ */
- {
- zend_ffi_use_after_free();
- return 0;
- }
- /* }}} */
- static ZEND_COLD void zend_ffi_free_unset_property(zend_object *obj, zend_string *member, void **cache_slot) /* {{{ */
- {
- zend_ffi_use_after_free();
- }
- /* }}} */
- static HashTable *zend_ffi_free_get_debug_info(zend_object *obj, int *is_temp) /* {{{ */
- {
- zend_ffi_use_after_free();
- return NULL;
- }
- /* }}} */
- static ZEND_INI_MH(OnUpdateFFIEnable) /* {{{ */
- {
- if (zend_string_equals_literal_ci(new_value, "preload")) {
- FFI_G(restriction) = ZEND_FFI_PRELOAD;
- } else {
- FFI_G(restriction) = (zend_ffi_api_restriction)zend_ini_parse_bool(new_value);
- }
- return SUCCESS;
- }
- /* }}} */
- static ZEND_INI_DISP(zend_ffi_enable_displayer_cb) /* {{{ */
- {
- if (FFI_G(restriction) == ZEND_FFI_PRELOAD) {
- ZEND_PUTS("preload");
- } else if (FFI_G(restriction) == ZEND_FFI_ENABLED) {
- ZEND_PUTS("On");
- } else {
- ZEND_PUTS("Off");
- }
- }
- /* }}} */
- ZEND_INI_BEGIN()
- ZEND_INI_ENTRY3_EX("ffi.enable", "preload", ZEND_INI_SYSTEM, OnUpdateFFIEnable, NULL, NULL, NULL, zend_ffi_enable_displayer_cb)
- STD_ZEND_INI_ENTRY("ffi.preload", NULL, ZEND_INI_SYSTEM, OnUpdateString, preload, zend_ffi_globals, ffi_globals)
- ZEND_INI_END()
- static int zend_ffi_preload_glob(const char *filename) /* {{{ */
- {
- #ifdef HAVE_GLOB
- glob_t globbuf;
- int ret;
- unsigned int i;
- memset(&globbuf, 0, sizeof(glob_t));
- ret = glob(filename, 0, NULL, &globbuf);
- #ifdef GLOB_NOMATCH
- if (ret == GLOB_NOMATCH || !globbuf.gl_pathc) {
- #else
- if (!globbuf.gl_pathc) {
- #endif
- /* pass */
- } else {
- for(i=0 ; i<globbuf.gl_pathc; i++) {
- zend_ffi *ffi = zend_ffi_load(globbuf.gl_pathv[i], 1);
- if (!ffi) {
- globfree(&globbuf);
- return FAILURE;
- }
- efree(ffi);
- }
- globfree(&globbuf);
- }
- #else
- zend_ffi *ffi = zend_ffi_load(filename, 1);
- if (!ffi) {
- return FAILURE;
- }
- efree(ffi);
- #endif
- return SUCCESS;
- }
- /* }}} */
- static int zend_ffi_preload(char *preload) /* {{{ */
- {
- zend_ffi *ffi;
- char *s = NULL, *e, *filename;
- bool is_glob = 0;
- e = preload;
- while (*e) {
- switch (*e) {
- case ZEND_PATHS_SEPARATOR:
- if (s) {
- filename = estrndup(s, e-s);
- s = NULL;
- if (!is_glob) {
- ffi = zend_ffi_load(filename, 1);
- efree(filename);
- if (!ffi) {
- return FAILURE;
- }
- efree(ffi);
- } else {
- int ret = zend_ffi_preload_glob(filename);
- efree(filename);
- if (ret != SUCCESS) {
- return FAILURE;
- }
- is_glob = 0;
- }
- }
- break;
- case '*':
- case '?':
- case '[':
- is_glob = 1;
- break;
- default:
- if (!s) {
- s = e;
- }
- break;
- }
- e++;
- }
- if (s) {
- filename = estrndup(s, e-s);
- if (!is_glob) {
- ffi = zend_ffi_load(filename, 1);
- efree(filename);
- if (!ffi) {
- return FAILURE;
- }
- efree(ffi);
- } else {
- int ret = zend_ffi_preload_glob(filename);
- efree(filename);
- if (ret != SUCCESS) {
- return FAILURE;
- }
- }
- }
- return SUCCESS;
- }
- /* }}} */
- #define REGISTER_FFI_TYPE_CONSTANT(name) \
- zend_declare_class_constant_long(zend_ffi_ctype_ce, #name, sizeof(#name) - 1, ZEND_FFI_ ## name)
- /* {{{ ZEND_MINIT_FUNCTION */
- ZEND_MINIT_FUNCTION(ffi)
- {
- REGISTER_INI_ENTRIES();
- FFI_G(is_cli) = strcmp(sapi_module.name, "cli") == 0;
- zend_ffi_exception_ce = register_class_FFI_Exception(zend_ce_error);
- zend_ffi_parser_exception_ce = register_class_FFI_ParserException(zend_ffi_exception_ce);
- zend_ffi_ce = register_class_FFI();
- zend_ffi_ce->create_object = zend_ffi_new;
- memcpy(&zend_ffi_new_fn, zend_hash_str_find_ptr(&zend_ffi_ce->function_table, "new", sizeof("new")-1), sizeof(zend_internal_function));
- zend_ffi_new_fn.fn_flags &= ~ZEND_ACC_STATIC;
- memcpy(&zend_ffi_cast_fn, zend_hash_str_find_ptr(&zend_ffi_ce->function_table, "cast", sizeof("cast")-1), sizeof(zend_internal_function));
- zend_ffi_cast_fn.fn_flags &= ~ZEND_ACC_STATIC;
- memcpy(&zend_ffi_type_fn, zend_hash_str_find_ptr(&zend_ffi_ce->function_table, "type", sizeof("type")-1), sizeof(zend_internal_function));
- zend_ffi_type_fn.fn_flags &= ~ZEND_ACC_STATIC;
- memcpy(&zend_ffi_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
- zend_ffi_handlers.get_constructor = zend_fake_get_constructor;
- zend_ffi_handlers.free_obj = zend_ffi_free_obj;
- zend_ffi_handlers.clone_obj = NULL;
- zend_ffi_handlers.read_property = zend_ffi_read_var;
- zend_ffi_handlers.write_property = zend_ffi_write_var;
- zend_ffi_handlers.read_dimension = zend_fake_read_dimension;
- zend_ffi_handlers.write_dimension = zend_fake_write_dimension;
- zend_ffi_handlers.get_property_ptr_ptr = zend_fake_get_property_ptr_ptr;
- zend_ffi_handlers.has_property = zend_fake_has_property;
- zend_ffi_handlers.unset_property = zend_fake_unset_property;
- zend_ffi_handlers.has_dimension = zend_fake_has_dimension;
- zend_ffi_handlers.unset_dimension = zend_fake_unset_dimension;
- zend_ffi_handlers.get_method = zend_ffi_get_func;
- zend_ffi_handlers.compare = NULL;
- zend_ffi_handlers.cast_object = zend_fake_cast_object;
- zend_ffi_handlers.get_debug_info = NULL;
- zend_ffi_handlers.get_closure = NULL;
- zend_ffi_handlers.get_properties = zend_fake_get_properties;
- zend_ffi_handlers.get_gc = zend_fake_get_gc;
- zend_declare_class_constant_long(zend_ffi_ce, "__BIGGEST_ALIGNMENT__", sizeof("__BIGGEST_ALIGNMENT__")-1, __BIGGEST_ALIGNMENT__);
- zend_ffi_cdata_ce = register_class_FFI_CData();
- zend_ffi_cdata_ce->create_object = zend_ffi_cdata_new;
- zend_ffi_cdata_ce->get_iterator = zend_ffi_cdata_get_iterator;
- memcpy(&zend_ffi_cdata_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
- zend_ffi_cdata_handlers.get_constructor = zend_fake_get_constructor;
- zend_ffi_cdata_handlers.free_obj = zend_ffi_cdata_free_obj;
- zend_ffi_cdata_handlers.clone_obj = zend_ffi_cdata_clone_obj;
- zend_ffi_cdata_handlers.read_property = zend_ffi_cdata_read_field;
- zend_ffi_cdata_handlers.write_property = zend_ffi_cdata_write_field;
- zend_ffi_cdata_handlers.read_dimension = zend_ffi_cdata_read_dim;
- zend_ffi_cdata_handlers.write_dimension = zend_ffi_cdata_write_dim;
- zend_ffi_cdata_handlers.get_property_ptr_ptr = zend_fake_get_property_ptr_ptr;
- zend_ffi_cdata_handlers.has_property = zend_fake_has_property;
- zend_ffi_cdata_handlers.unset_property = zend_fake_unset_property;
- zend_ffi_cdata_handlers.has_dimension = zend_fake_has_dimension;
- zend_ffi_cdata_handlers.unset_dimension = zend_fake_unset_dimension;
- zend_ffi_cdata_handlers.get_method = zend_fake_get_method;
- zend_ffi_cdata_handlers.get_class_name = zend_ffi_cdata_get_class_name;
- zend_ffi_cdata_handlers.do_operation = zend_ffi_cdata_do_operation;
- zend_ffi_cdata_handlers.compare = zend_ffi_cdata_compare_objects;
- zend_ffi_cdata_handlers.cast_object = zend_ffi_cdata_cast_object;
- zend_ffi_cdata_handlers.count_elements = zend_ffi_cdata_count_elements;
- zend_ffi_cdata_handlers.get_debug_info = zend_ffi_cdata_get_debug_info;
- zend_ffi_cdata_handlers.get_closure = zend_ffi_cdata_get_closure;
- zend_ffi_cdata_handlers.get_properties = zend_fake_get_properties;
- zend_ffi_cdata_handlers.get_gc = zend_fake_get_gc;
- memcpy(&zend_ffi_cdata_value_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
- zend_ffi_cdata_value_handlers.get_constructor = zend_fake_get_constructor;
- zend_ffi_cdata_value_handlers.free_obj = zend_ffi_cdata_free_obj;
- zend_ffi_cdata_value_handlers.clone_obj = zend_ffi_cdata_clone_obj;
- zend_ffi_cdata_value_handlers.read_property = zend_ffi_cdata_get;
- zend_ffi_cdata_value_handlers.write_property = zend_ffi_cdata_set;
- zend_ffi_cdata_value_handlers.read_dimension = zend_fake_read_dimension;
- zend_ffi_cdata_value_handlers.write_dimension = zend_fake_write_dimension;
- zend_ffi_cdata_value_handlers.get_property_ptr_ptr = zend_fake_get_property_ptr_ptr;
- zend_ffi_cdata_value_handlers.has_property = zend_fake_has_property;
- zend_ffi_cdata_value_handlers.unset_property = zend_fake_unset_property;
- zend_ffi_cdata_value_handlers.has_dimension = zend_fake_has_dimension;
- zend_ffi_cdata_value_handlers.unset_dimension = zend_fake_unset_dimension;
- zend_ffi_cdata_value_handlers.get_method = zend_fake_get_method;
- zend_ffi_cdata_value_handlers.get_class_name = zend_ffi_cdata_get_class_name;
- zend_ffi_cdata_value_handlers.compare = zend_ffi_cdata_compare_objects;
- zend_ffi_cdata_value_handlers.cast_object = zend_ffi_cdata_cast_object;
- zend_ffi_cdata_value_handlers.count_elements = NULL;
- zend_ffi_cdata_value_handlers.get_debug_info = zend_ffi_cdata_get_debug_info;
- zend_ffi_cdata_value_handlers.get_closure = NULL;
- zend_ffi_cdata_value_handlers.get_properties = zend_fake_get_properties;
- zend_ffi_cdata_value_handlers.get_gc = zend_fake_get_gc;
- memcpy(&zend_ffi_cdata_free_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
- zend_ffi_cdata_free_handlers.get_constructor = zend_fake_get_constructor;
- zend_ffi_cdata_free_handlers.free_obj = zend_ffi_cdata_free_obj;
- zend_ffi_cdata_free_handlers.clone_obj = zend_ffi_free_clone_obj;
- zend_ffi_cdata_free_handlers.read_property = zend_ffi_free_read_property;
- zend_ffi_cdata_free_handlers.write_property = zend_ffi_free_write_property;
- zend_ffi_cdata_free_handlers.read_dimension = zend_ffi_free_read_dimension;
- zend_ffi_cdata_free_handlers.write_dimension = zend_ffi_free_write_dimension;
- zend_ffi_cdata_free_handlers.get_property_ptr_ptr = zend_fake_get_property_ptr_ptr;
- zend_ffi_cdata_free_handlers.has_property = zend_ffi_free_has_property;
- zend_ffi_cdata_free_handlers.unset_property = zend_ffi_free_unset_property;
- zend_ffi_cdata_free_handlers.has_dimension = zend_ffi_free_has_dimension;
- zend_ffi_cdata_free_handlers.unset_dimension = zend_ffi_free_unset_dimension;
- zend_ffi_cdata_free_handlers.get_method = zend_fake_get_method;
- zend_ffi_cdata_free_handlers.get_class_name = zend_ffi_cdata_get_class_name;
- zend_ffi_cdata_free_handlers.compare = zend_ffi_cdata_compare_objects;
- zend_ffi_cdata_free_handlers.cast_object = zend_fake_cast_object;
- zend_ffi_cdata_free_handlers.count_elements = NULL;
- zend_ffi_cdata_free_handlers.get_debug_info = zend_ffi_free_get_debug_info;
- zend_ffi_cdata_free_handlers.get_closure = NULL;
- zend_ffi_cdata_free_handlers.get_properties = zend_fake_get_properties;
- zend_ffi_cdata_free_handlers.get_gc = zend_fake_get_gc;
- zend_ffi_ctype_ce = register_class_FFI_CType();
- zend_ffi_ctype_ce->create_object = zend_ffi_ctype_new;
- memcpy(&zend_ffi_ctype_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
- zend_ffi_ctype_handlers.get_constructor = zend_fake_get_constructor;
- zend_ffi_ctype_handlers.free_obj = zend_ffi_ctype_free_obj;
- zend_ffi_ctype_handlers.clone_obj = NULL;
- zend_ffi_ctype_handlers.read_property = zend_fake_read_property;
- zend_ffi_ctype_handlers.write_property = zend_fake_write_property;
- zend_ffi_ctype_handlers.read_dimension = zend_fake_read_dimension;
- zend_ffi_ctype_handlers.write_dimension = zend_fake_write_dimension;
- zend_ffi_ctype_handlers.get_property_ptr_ptr = zend_fake_get_property_ptr_ptr;
- zend_ffi_ctype_handlers.has_property = zend_fake_has_property;
- zend_ffi_ctype_handlers.unset_property = zend_fake_unset_property;
- zend_ffi_ctype_handlers.has_dimension = zend_fake_has_dimension;
- zend_ffi_ctype_handlers.unset_dimension = zend_fake_unset_dimension;
- //zend_ffi_ctype_handlers.get_method = zend_fake_get_method;
- zend_ffi_ctype_handlers.get_class_name = zend_ffi_ctype_get_class_name;
- zend_ffi_ctype_handlers.compare = zend_ffi_ctype_compare_objects;
- zend_ffi_ctype_handlers.cast_object = zend_fake_cast_object;
- zend_ffi_ctype_handlers.count_elements = NULL;
- zend_ffi_ctype_handlers.get_debug_info = zend_ffi_ctype_get_debug_info;
- zend_ffi_ctype_handlers.get_closure = NULL;
- zend_ffi_ctype_handlers.get_properties = zend_fake_get_properties;
- zend_ffi_ctype_handlers.get_gc = zend_fake_get_gc;
- REGISTER_FFI_TYPE_CONSTANT(TYPE_VOID);
- REGISTER_FFI_TYPE_CONSTANT(TYPE_FLOAT);
- REGISTER_FFI_TYPE_CONSTANT(TYPE_DOUBLE);
- #ifdef HAVE_LONG_DOUBLE
- REGISTER_FFI_TYPE_CONSTANT(TYPE_LONGDOUBLE);
- #endif
- REGISTER_FFI_TYPE_CONSTANT(TYPE_UINT8);
- REGISTER_FFI_TYPE_CONSTANT(TYPE_SINT8);
- REGISTER_FFI_TYPE_CONSTANT(TYPE_UINT16);
- REGISTER_FFI_TYPE_CONSTANT(TYPE_SINT16);
- REGISTER_FFI_TYPE_CONSTANT(TYPE_UINT32);
- REGISTER_FFI_TYPE_CONSTANT(TYPE_SINT32);
- REGISTER_FFI_TYPE_CONSTANT(TYPE_UINT64);
- REGISTER_FFI_TYPE_CONSTANT(TYPE_SINT64);
- REGISTER_FFI_TYPE_CONSTANT(TYPE_ENUM);
- REGISTER_FFI_TYPE_CONSTANT(TYPE_BOOL);
- REGISTER_FFI_TYPE_CONSTANT(TYPE_CHAR);
- REGISTER_FFI_TYPE_CONSTANT(TYPE_POINTER);
- REGISTER_FFI_TYPE_CONSTANT(TYPE_FUNC);
- REGISTER_FFI_TYPE_CONSTANT(TYPE_ARRAY);
- REGISTER_FFI_TYPE_CONSTANT(TYPE_STRUCT);
- REGISTER_FFI_TYPE_CONSTANT(ATTR_CONST);
- REGISTER_FFI_TYPE_CONSTANT(ATTR_INCOMPLETE_TAG);
- REGISTER_FFI_TYPE_CONSTANT(ATTR_VARIADIC);
- REGISTER_FFI_TYPE_CONSTANT(ATTR_INCOMPLETE_ARRAY);
- REGISTER_FFI_TYPE_CONSTANT(ATTR_VLA);
- REGISTER_FFI_TYPE_CONSTANT(ATTR_UNION);
- REGISTER_FFI_TYPE_CONSTANT(ATTR_PACKED);
- REGISTER_FFI_TYPE_CONSTANT(ATTR_MS_STRUCT);
- REGISTER_FFI_TYPE_CONSTANT(ATTR_GCC_STRUCT);
- REGISTER_FFI_TYPE_CONSTANT(ABI_DEFAULT);
- REGISTER_FFI_TYPE_CONSTANT(ABI_CDECL);
- REGISTER_FFI_TYPE_CONSTANT(ABI_FASTCALL);
- REGISTER_FFI_TYPE_CONSTANT(ABI_THISCALL);
- REGISTER_FFI_TYPE_CONSTANT(ABI_STDCALL);
- REGISTER_FFI_TYPE_CONSTANT(ABI_PASCAL);
- REGISTER_FFI_TYPE_CONSTANT(ABI_REGISTER);
- REGISTER_FFI_TYPE_CONSTANT(ABI_MS);
- REGISTER_FFI_TYPE_CONSTANT(ABI_SYSV);
- REGISTER_FFI_TYPE_CONSTANT(ABI_VECTORCALL);
- if (FFI_G(preload)) {
- if (zend_ffi_preload(FFI_G(preload)) != SUCCESS) {
- return FAILURE;
- }
- }
- return SUCCESS;
- }
- /* }}} */
- /* {{{ ZEND_RSHUTDOWN_FUNCTION */
- ZEND_RSHUTDOWN_FUNCTION(ffi)
- {
- if (FFI_G(callbacks)) {
- zend_hash_destroy(FFI_G(callbacks));
- efree(FFI_G(callbacks));
- FFI_G(callbacks) = NULL;
- }
- if (FFI_G(weak_types)) {
- #if 0
- fprintf(stderr, "WeakTypes: %d\n", zend_hash_num_elements(FFI_G(weak_types)));
- #endif
- zend_hash_destroy(FFI_G(weak_types));
- efree(FFI_G(weak_types));
- FFI_G(weak_types) = NULL;
- }
- return SUCCESS;
- }
- /* }}} */
- /* {{{ ZEND_MINFO_FUNCTION */
- ZEND_MINFO_FUNCTION(ffi)
- {
- php_info_print_table_start();
- php_info_print_table_header(2, "FFI support", "enabled");
- php_info_print_table_end();
- DISPLAY_INI_ENTRIES();
- }
- /* }}} */
- static const zend_ffi_type zend_ffi_type_void = {.kind=ZEND_FFI_TYPE_VOID, .size=1, .align=1};
- static const zend_ffi_type zend_ffi_type_char = {.kind=ZEND_FFI_TYPE_CHAR, .size=1, .align=_Alignof(char)};
- static const zend_ffi_type zend_ffi_type_bool = {.kind=ZEND_FFI_TYPE_BOOL, .size=1, .align=_Alignof(uint8_t)};
- static const zend_ffi_type zend_ffi_type_sint8 = {.kind=ZEND_FFI_TYPE_SINT8, .size=1, .align=_Alignof(int8_t)};
- static const zend_ffi_type zend_ffi_type_uint8 = {.kind=ZEND_FFI_TYPE_UINT8, .size=1, .align=_Alignof(uint8_t)};
- static const zend_ffi_type zend_ffi_type_sint16 = {.kind=ZEND_FFI_TYPE_SINT16, .size=2, .align=_Alignof(int16_t)};
- static const zend_ffi_type zend_ffi_type_uint16 = {.kind=ZEND_FFI_TYPE_UINT16, .size=2, .align=_Alignof(uint16_t)};
- static const zend_ffi_type zend_ffi_type_sint32 = {.kind=ZEND_FFI_TYPE_SINT32, .size=4, .align=_Alignof(int32_t)};
- static const zend_ffi_type zend_ffi_type_uint32 = {.kind=ZEND_FFI_TYPE_UINT32, .size=4, .align=_Alignof(uint32_t)};
- static const zend_ffi_type zend_ffi_type_sint64 = {.kind=ZEND_FFI_TYPE_SINT64, .size=8, .align=_Alignof(int64_t)};
- static const zend_ffi_type zend_ffi_type_uint64 = {.kind=ZEND_FFI_TYPE_UINT64, .size=8, .align=_Alignof(uint64_t)};
- static const zend_ffi_type zend_ffi_type_float = {.kind=ZEND_FFI_TYPE_FLOAT, .size=sizeof(float), .align=_Alignof(float)};
- static const zend_ffi_type zend_ffi_type_double = {.kind=ZEND_FFI_TYPE_DOUBLE, .size=sizeof(double), .align=_Alignof(double)};
- #ifdef HAVE_LONG_DOUBLE
- static const zend_ffi_type zend_ffi_type_long_double = {.kind=ZEND_FFI_TYPE_LONGDOUBLE, .size=sizeof(long double), .align=_Alignof(long double)};
- #endif
- static const zend_ffi_type zend_ffi_type_ptr = {.kind=ZEND_FFI_TYPE_POINTER, .size=sizeof(void*), .align=_Alignof(void*), .pointer.type = (zend_ffi_type*)&zend_ffi_type_void};
- const struct {
- const char *name;
- const zend_ffi_type *type;
- } zend_ffi_types[] = {
- {"void", &zend_ffi_type_void},
- {"char", &zend_ffi_type_char},
- {"bool", &zend_ffi_type_bool},
- {"int8_t", &zend_ffi_type_sint8},
- {"uint8_t", &zend_ffi_type_uint8},
- {"int16_t", &zend_ffi_type_sint16},
- {"uint16_t", &zend_ffi_type_uint16},
- {"int32_t", &zend_ffi_type_sint32},
- {"uint32_t", &zend_ffi_type_uint32},
- {"int64_t", &zend_ffi_type_sint64},
- {"uint64_t", &zend_ffi_type_uint64},
- {"float", &zend_ffi_type_float},
- {"double", &zend_ffi_type_double},
- #ifdef HAVE_LONG_DOUBLE
- {"long double", &zend_ffi_type_long_double},
- #endif
- #if SIZEOF_SIZE_T == 4
- {"uintptr_t", &zend_ffi_type_uint32},
- {"intptr_t", &zend_ffi_type_sint32},
- {"size_t", &zend_ffi_type_uint32},
- {"ssize_t", &zend_ffi_type_sint32},
- {"ptrdiff_t", &zend_ffi_type_sint32},
- #else
- {"uintptr_t", &zend_ffi_type_uint64},
- {"intptr_t", &zend_ffi_type_sint64},
- {"size_t", &zend_ffi_type_uint64},
- {"ssize_t", &zend_ffi_type_sint64},
- {"ptrdiff_t", &zend_ffi_type_sint64},
- #endif
- #if SIZEOF_OFF_T == 4
- {"off_t", &zend_ffi_type_sint32},
- #else
- {"off_t", &zend_ffi_type_sint64},
- #endif
- {"va_list", &zend_ffi_type_ptr},
- {"__builtin_va_list", &zend_ffi_type_ptr},
- {"__gnuc_va_list", &zend_ffi_type_ptr},
- };
- /* {{{ ZEND_GINIT_FUNCTION */
- static ZEND_GINIT_FUNCTION(ffi)
- {
- size_t i;
- #if defined(COMPILE_DL_FFI) && defined(ZTS)
- ZEND_TSRMLS_CACHE_UPDATE();
- #endif
- memset(ffi_globals, 0, sizeof(*ffi_globals));
- zend_hash_init(&ffi_globals->types, 0, NULL, NULL, 1);
- for (i = 0; i < sizeof(zend_ffi_types)/sizeof(zend_ffi_types[0]); i++) {
- zend_hash_str_add_new_ptr(&ffi_globals->types, zend_ffi_types[i].name, strlen(zend_ffi_types[i].name), (void*)zend_ffi_types[i].type);
- }
- }
- /* }}} */
- /* {{{ ZEND_GINIT_FUNCTION */
- static ZEND_GSHUTDOWN_FUNCTION(ffi)
- {
- if (ffi_globals->scopes) {
- zend_hash_destroy(ffi_globals->scopes);
- free(ffi_globals->scopes);
- }
- zend_hash_destroy(&ffi_globals->types);
- }
- /* }}} */
- /* {{{ ffi_module_entry */
- zend_module_entry ffi_module_entry = {
- STANDARD_MODULE_HEADER,
- "FFI", /* Extension name */
- NULL, /* zend_function_entry */
- ZEND_MINIT(ffi), /* ZEND_MINIT - Module initialization */
- NULL, /* ZEND_MSHUTDOWN - Module shutdown */
- NULL, /* ZEND_RINIT - Request initialization */
- ZEND_RSHUTDOWN(ffi), /* ZEND_RSHUTDOWN - Request shutdown */
- ZEND_MINFO(ffi), /* ZEND_MINFO - Module info */
- PHP_VERSION, /* Version */
- ZEND_MODULE_GLOBALS(ffi),
- ZEND_GINIT(ffi),
- ZEND_GSHUTDOWN(ffi),
- NULL,
- STANDARD_MODULE_PROPERTIES_EX
- };
- /* }}} */
- #ifdef COMPILE_DL_FFI
- # ifdef ZTS
- ZEND_TSRMLS_CACHE_DEFINE()
- # endif
- ZEND_GET_MODULE(ffi)
- #endif
- /* parser callbacks */
- void zend_ffi_parser_error(const char *format, ...) /* {{{ */
- {
- va_list va;
- char *message = NULL;
- va_start(va, format);
- zend_vspprintf(&message, 0, format, va);
- if (EG(current_execute_data)) {
- zend_throw_exception(zend_ffi_parser_exception_ce, message, 0);
- } else {
- zend_error(E_WARNING, "FFI Parser: %s", message);
- }
- efree(message);
- va_end(va);
- LONGJMP(FFI_G(bailout), FAILURE);
- }
- /* }}} */
- static void zend_ffi_finalize_type(zend_ffi_dcl *dcl) /* {{{ */
- {
- if (!dcl->type) {
- switch (dcl->flags & ZEND_FFI_DCL_TYPE_SPECIFIERS) {
- case ZEND_FFI_DCL_VOID:
- dcl->type = (zend_ffi_type*)&zend_ffi_type_void;
- break;
- case ZEND_FFI_DCL_CHAR:
- dcl->type = (zend_ffi_type*)&zend_ffi_type_char;
- break;
- case ZEND_FFI_DCL_CHAR|ZEND_FFI_DCL_SIGNED:
- dcl->type = (zend_ffi_type*)&zend_ffi_type_sint8;
- break;
- case ZEND_FFI_DCL_CHAR|ZEND_FFI_DCL_UNSIGNED:
- case ZEND_FFI_DCL_BOOL:
- dcl->type = (zend_ffi_type*)&zend_ffi_type_uint8;
- break;
- case ZEND_FFI_DCL_SHORT:
- case ZEND_FFI_DCL_SHORT|ZEND_FFI_DCL_SIGNED:
- case ZEND_FFI_DCL_SHORT|ZEND_FFI_DCL_INT:
- case ZEND_FFI_DCL_SHORT|ZEND_FFI_DCL_SIGNED|ZEND_FFI_DCL_INT:
- dcl->type = (zend_ffi_type*)&zend_ffi_type_sint16;
- break;
- case ZEND_FFI_DCL_SHORT|ZEND_FFI_DCL_UNSIGNED:
- case ZEND_FFI_DCL_SHORT|ZEND_FFI_DCL_UNSIGNED|ZEND_FFI_DCL_INT:
- dcl->type = (zend_ffi_type*)&zend_ffi_type_uint16;
- break;
- case ZEND_FFI_DCL_INT:
- case ZEND_FFI_DCL_SIGNED:
- case ZEND_FFI_DCL_SIGNED|ZEND_FFI_DCL_INT:
- dcl->type = (zend_ffi_type*)&zend_ffi_type_sint32;
- break;
- case ZEND_FFI_DCL_UNSIGNED:
- case ZEND_FFI_DCL_UNSIGNED|ZEND_FFI_DCL_INT:
- dcl->type = (zend_ffi_type*)&zend_ffi_type_uint32;
- break;
- case ZEND_FFI_DCL_LONG:
- case ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_SIGNED:
- case ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_INT:
- case ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_SIGNED|ZEND_FFI_DCL_INT:
- if (sizeof(long) == 4) {
- dcl->type = (zend_ffi_type*)&zend_ffi_type_sint32;
- } else {
- dcl->type = (zend_ffi_type*)&zend_ffi_type_sint64;
- }
- break;
- case ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_UNSIGNED:
- case ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_UNSIGNED|ZEND_FFI_DCL_INT:
- if (sizeof(long) == 4) {
- dcl->type = (zend_ffi_type*)&zend_ffi_type_uint32;
- } else {
- dcl->type = (zend_ffi_type*)&zend_ffi_type_uint64;
- }
- break;
- case ZEND_FFI_DCL_LONG_LONG|ZEND_FFI_DCL_LONG:
- case ZEND_FFI_DCL_LONG_LONG|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_SIGNED:
- case ZEND_FFI_DCL_LONG_LONG|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_INT:
- case ZEND_FFI_DCL_LONG_LONG|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_SIGNED|ZEND_FFI_DCL_INT:
- dcl->type = (zend_ffi_type*)&zend_ffi_type_sint64;
- break;
- case ZEND_FFI_DCL_LONG_LONG|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_UNSIGNED:
- case ZEND_FFI_DCL_LONG_LONG|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_UNSIGNED|ZEND_FFI_DCL_INT:
- dcl->type = (zend_ffi_type*)&zend_ffi_type_uint64;
- break;
- case ZEND_FFI_DCL_FLOAT:
- dcl->type = (zend_ffi_type*)&zend_ffi_type_float;
- break;
- case ZEND_FFI_DCL_DOUBLE:
- dcl->type = (zend_ffi_type*)&zend_ffi_type_double;
- break;
- case ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_DOUBLE:
- #ifdef _WIN32
- dcl->type = (zend_ffi_type*)&zend_ffi_type_double;
- #else
- dcl->type = (zend_ffi_type*)&zend_ffi_type_long_double;
- #endif
- break;
- case ZEND_FFI_DCL_FLOAT|ZEND_FFI_DCL_COMPLEX:
- case ZEND_FFI_DCL_DOUBLE|ZEND_FFI_DCL_COMPLEX:
- case ZEND_FFI_DCL_DOUBLE|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_COMPLEX:
- zend_ffi_parser_error("Unsupported type _Complex at line %d", FFI_G(line));
- break;
- default:
- zend_ffi_parser_error("Unsupported type specifier combination at line %d", FFI_G(line));
- break;
- }
- dcl->flags &= ~ZEND_FFI_DCL_TYPE_SPECIFIERS;
- dcl->flags |= ZEND_FFI_DCL_TYPEDEF_NAME;
- }
- }
- /* }}} */
- int zend_ffi_is_typedef_name(const char *name, size_t name_len) /* {{{ */
- {
- zend_ffi_symbol *sym;
- zend_ffi_type *type;
- if (FFI_G(symbols)) {
- sym = zend_hash_str_find_ptr(FFI_G(symbols), name, name_len);
- if (sym) {
- return (sym->kind == ZEND_FFI_SYM_TYPE);
- }
- }
- type = zend_hash_str_find_ptr(&FFI_G(types), name, name_len);
- if (type) {
- return 1;
- }
- return 0;
- }
- /* }}} */
- void zend_ffi_resolve_typedef(const char *name, size_t name_len, zend_ffi_dcl *dcl) /* {{{ */
- {
- zend_ffi_symbol *sym;
- zend_ffi_type *type;
- if (FFI_G(symbols)) {
- sym = zend_hash_str_find_ptr(FFI_G(symbols), name, name_len);
- if (sym && sym->kind == ZEND_FFI_SYM_TYPE) {
- dcl->type = ZEND_FFI_TYPE(sym->type);;
- if (sym->is_const) {
- dcl->attr |= ZEND_FFI_ATTR_CONST;
- }
- return;
- }
- }
- type = zend_hash_str_find_ptr(&FFI_G(types), name, name_len);
- if (type) {
- dcl->type = type;
- return;
- }
- zend_ffi_parser_error("Undefined C type \"%.*s\" at line %d", name_len, name, FFI_G(line));
- }
- /* }}} */
- void zend_ffi_resolve_const(const char *name, size_t name_len, zend_ffi_val *val) /* {{{ */
- {
- zend_ffi_symbol *sym;
- if (UNEXPECTED(FFI_G(attribute_parsing))) {
- val->kind = ZEND_FFI_VAL_NAME;
- val->str = name;
- val->len = name_len;
- return;
- } else if (FFI_G(symbols)) {
- sym = zend_hash_str_find_ptr(FFI_G(symbols), name, name_len);
- if (sym && sym->kind == ZEND_FFI_SYM_CONST) {
- val->i64 = sym->value;
- switch (sym->type->kind) {
- case ZEND_FFI_TYPE_SINT8:
- case ZEND_FFI_TYPE_SINT16:
- case ZEND_FFI_TYPE_SINT32:
- val->kind = ZEND_FFI_VAL_INT32;
- break;
- case ZEND_FFI_TYPE_SINT64:
- val->kind = ZEND_FFI_VAL_INT64;
- break;
- case ZEND_FFI_TYPE_UINT8:
- case ZEND_FFI_TYPE_UINT16:
- case ZEND_FFI_TYPE_UINT32:
- val->kind = ZEND_FFI_VAL_UINT32;
- break;
- case ZEND_FFI_TYPE_UINT64:
- val->kind = ZEND_FFI_VAL_UINT64;
- break;
- default:
- ZEND_UNREACHABLE();
- }
- return;
- }
- }
- val->kind = ZEND_FFI_VAL_ERROR;
- }
- /* }}} */
- void zend_ffi_make_enum_type(zend_ffi_dcl *dcl) /* {{{ */
- {
- zend_ffi_type *type = pemalloc(sizeof(zend_ffi_type), FFI_G(persistent));
- type->kind = ZEND_FFI_TYPE_ENUM;
- type->attr = FFI_G(default_type_attr) | (dcl->attr & ZEND_FFI_ENUM_ATTRS);
- type->enumeration.tag_name = NULL;
- if (type->attr & ZEND_FFI_ATTR_PACKED) {
- type->size = zend_ffi_type_uint8.size;
- type->align = zend_ffi_type_uint8.align;
- type->enumeration.kind = ZEND_FFI_TYPE_UINT8;
- } else {
- type->size = zend_ffi_type_uint32.size;
- type->align = zend_ffi_type_uint32.align;
- type->enumeration.kind = ZEND_FFI_TYPE_UINT32;
- }
- dcl->type = ZEND_FFI_TYPE_MAKE_OWNED(type);
- dcl->attr &= ~ZEND_FFI_ENUM_ATTRS;
- }
- /* }}} */
- void zend_ffi_add_enum_val(zend_ffi_dcl *enum_dcl, const char *name, size_t name_len, zend_ffi_val *val, int64_t *min, int64_t *max, int64_t *last) /* {{{ */
- {
- zend_ffi_symbol *sym;
- const zend_ffi_type *sym_type;
- int64_t value;
- zend_ffi_type *enum_type = ZEND_FFI_TYPE(enum_dcl->type);
- bool overflow = 0;
- bool is_signed =
- (enum_type->enumeration.kind == ZEND_FFI_TYPE_SINT8 ||
- enum_type->enumeration.kind == ZEND_FFI_TYPE_SINT16 ||
- enum_type->enumeration.kind == ZEND_FFI_TYPE_SINT32 ||
- enum_type->enumeration.kind == ZEND_FFI_TYPE_SINT64);
- ZEND_ASSERT(enum_type && enum_type->kind == ZEND_FFI_TYPE_ENUM);
- if (val->kind == ZEND_FFI_VAL_EMPTY) {
- if (is_signed) {
- if (*last == 0x7FFFFFFFFFFFFFFFLL) {
- overflow = 1;
- }
- } else {
- if ((*min != 0 || *max != 0)
- && (uint64_t)*last == 0xFFFFFFFFFFFFFFFFULL) {
- overflow = 1;
- }
- }
- value = *last + 1;
- } else if (val->kind == ZEND_FFI_VAL_CHAR) {
- if (!is_signed && val->ch < 0) {
- if ((uint64_t)*max > 0x7FFFFFFFFFFFFFFFULL) {
- overflow = 1;
- } else {
- is_signed = 1;
- }
- }
- value = val->ch;
- } else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
- if (!is_signed && val->i64 < 0) {
- if ((uint64_t)*max > 0x7FFFFFFFFFFFFFFFULL) {
- overflow = 1;
- } else {
- is_signed = 1;
- }
- }
- value = val->i64;
- } else if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) {
- if (is_signed && val->u64 > 0x7FFFFFFFFFFFFFFFULL) {
- overflow = 1;
- }
- value = val->u64;
- } else {
- zend_ffi_parser_error("Enumerator value \"%.*s\" must be an integer at line %d", name_len, name, FFI_G(line));
- return;
- }
- if (overflow) {
- zend_ffi_parser_error("Overflow in enumeration values \"%.*s\" at line %d", name_len, name, FFI_G(line));
- return;
- }
- if (is_signed) {
- *min = MIN(*min, value);
- *max = MAX(*max, value);
- if ((enum_type->attr & ZEND_FFI_ATTR_PACKED)
- && *min >= -0x7FLL-1 && *max <= 0x7FLL) {
- sym_type = &zend_ffi_type_sint8;
- } else if ((enum_type->attr & ZEND_FFI_ATTR_PACKED)
- && *min >= -0x7FFFLL-1 && *max <= 0x7FFFLL) {
- sym_type = &zend_ffi_type_sint16;
- } else if (*min >= -0x7FFFFFFFLL-1 && *max <= 0x7FFFFFFFLL) {
- sym_type = &zend_ffi_type_sint32;
- } else {
- sym_type = &zend_ffi_type_sint64;
- }
- } else {
- *min = MIN((uint64_t)*min, (uint64_t)value);
- *max = MAX((uint64_t)*max, (uint64_t)value);
- if ((enum_type->attr & ZEND_FFI_ATTR_PACKED)
- && (uint64_t)*max <= 0xFFULL) {
- sym_type = &zend_ffi_type_uint8;
- } else if ((enum_type->attr & ZEND_FFI_ATTR_PACKED)
- && (uint64_t)*max <= 0xFFFFULL) {
- sym_type = &zend_ffi_type_uint16;
- } else if ((uint64_t)*max <= 0xFFFFFFFFULL) {
- sym_type = &zend_ffi_type_uint32;
- } else {
- sym_type = &zend_ffi_type_uint64;
- }
- }
- enum_type->enumeration.kind = sym_type->kind;
- enum_type->size = sym_type->size;
- enum_type->align = sym_type->align;
- *last = value;
- if (!FFI_G(symbols)) {
- FFI_G(symbols) = pemalloc(sizeof(HashTable), FFI_G(persistent));
- zend_hash_init(FFI_G(symbols), 0, NULL, FFI_G(persistent) ? zend_ffi_symbol_hash_persistent_dtor : zend_ffi_symbol_hash_dtor, FFI_G(persistent));
- }
- sym = zend_hash_str_find_ptr(FFI_G(symbols), name, name_len);
- if (sym) {
- zend_ffi_parser_error("Redeclaration of \"%.*s\" at line %d", name_len, name, FFI_G(line));
- } else {
- sym = pemalloc(sizeof(zend_ffi_symbol), FFI_G(persistent));
- sym->kind = ZEND_FFI_SYM_CONST;
- sym->type = (zend_ffi_type*)sym_type;
- sym->value = value;
- zend_hash_str_add_new_ptr(FFI_G(symbols), name, name_len, sym);
- }
- }
- /* }}} */
- void zend_ffi_make_struct_type(zend_ffi_dcl *dcl) /* {{{ */
- {
- zend_ffi_type *type = pemalloc(sizeof(zend_ffi_type), FFI_G(persistent));
- type->kind = ZEND_FFI_TYPE_STRUCT;
- type->attr = FFI_G(default_type_attr) | (dcl->attr & ZEND_FFI_STRUCT_ATTRS);
- type->size = 0;
- type->align = dcl->align > 1 ? dcl->align : 1;
- if (dcl->flags & ZEND_FFI_DCL_UNION) {
- type->attr |= ZEND_FFI_ATTR_UNION;
- }
- dcl->type = ZEND_FFI_TYPE_MAKE_OWNED(type);
- type->record.tag_name = NULL;
- zend_hash_init(&type->record.fields, 0, NULL, FFI_G(persistent) ? zend_ffi_field_hash_persistent_dtor :zend_ffi_field_hash_dtor, FFI_G(persistent));
- dcl->attr &= ~ZEND_FFI_STRUCT_ATTRS;
- dcl->align = 0;
- }
- /* }}} */
- static int zend_ffi_validate_prev_field_type(zend_ffi_type *struct_type) /* {{{ */
- {
- if (zend_hash_num_elements(&struct_type->record.fields) > 0) {
- zend_ffi_field *field = NULL;
- ZEND_HASH_REVERSE_FOREACH_PTR(&struct_type->record.fields, field) {
- break;
- } ZEND_HASH_FOREACH_END();
- if (ZEND_FFI_TYPE(field->type)->attr & ZEND_FFI_ATTR_INCOMPLETE_ARRAY) {
- zend_ffi_throw_parser_error("Flexible array member not at end of struct at line %d", FFI_G(line));
- return FAILURE;
- }
- }
- return SUCCESS;
- }
- /* }}} */
- static int zend_ffi_validate_field_type(zend_ffi_type *type, zend_ffi_type *struct_type) /* {{{ */
- {
- if (type == struct_type) {
- zend_ffi_throw_parser_error("Struct/union can't contain an instance of itself at line %d", FFI_G(line));
- return FAILURE;
- } else if (zend_ffi_validate_var_type(type, 1) != SUCCESS) {
- return FAILURE;
- } else if (struct_type->attr & ZEND_FFI_ATTR_UNION) {
- if (type->attr & ZEND_FFI_ATTR_INCOMPLETE_ARRAY) {
- zend_ffi_throw_parser_error("Flexible array member in union at line %d", FFI_G(line));
- return FAILURE;
- }
- }
- return zend_ffi_validate_prev_field_type(struct_type);
- }
- /* }}} */
- void zend_ffi_add_field(zend_ffi_dcl *struct_dcl, const char *name, size_t name_len, zend_ffi_dcl *field_dcl) /* {{{ */
- {
- zend_ffi_field *field;
- zend_ffi_type *struct_type = ZEND_FFI_TYPE(struct_dcl->type);
- zend_ffi_type *field_type;
- ZEND_ASSERT(struct_type && struct_type->kind == ZEND_FFI_TYPE_STRUCT);
- zend_ffi_finalize_type(field_dcl);
- field_type = ZEND_FFI_TYPE(field_dcl->type);
- if (zend_ffi_validate_field_type(field_type, struct_type) != SUCCESS) {
- zend_ffi_cleanup_dcl(field_dcl);
- LONGJMP(FFI_G(bailout), FAILURE);
- }
- field = pemalloc(sizeof(zend_ffi_field), FFI_G(persistent));
- if (!(struct_type->attr & ZEND_FFI_ATTR_PACKED) && !(field_dcl->attr & ZEND_FFI_ATTR_PACKED)) {
- struct_type->align = MAX(struct_type->align, MAX(field_type->align, field_dcl->align));
- }
- if (struct_type->attr & ZEND_FFI_ATTR_UNION) {
- field->offset = 0;
- struct_type->size = MAX(struct_type->size, field_type->size);
- } else {
- if (!(struct_type->attr & ZEND_FFI_ATTR_PACKED) && !(field_dcl->attr & ZEND_FFI_ATTR_PACKED)) {
- uint32_t field_align = MAX(field_type->align, field_dcl->align);
- struct_type->size = ((struct_type->size + (field_align - 1)) / field_align) * field_align;
- }
- field->offset = struct_type->size;
- struct_type->size += field_type->size;
- }
- field->type = field_dcl->type;
- field->is_const = (bool)(field_dcl->attr & ZEND_FFI_ATTR_CONST);
- field->is_nested = 0;
- field->first_bit = 0;
- field->bits = 0;
- field_dcl->type = field_type; /* reset "owned" flag */
- if (!zend_hash_str_add_ptr(&struct_type->record.fields, name, name_len, field)) {
- zend_ffi_type_dtor(field->type);
- pefree(field, FFI_G(persistent));
- zend_ffi_parser_error("Duplicate field name \"%.*s\" at line %d", name_len, name, FFI_G(line));
- }
- }
- /* }}} */
- void zend_ffi_add_anonymous_field(zend_ffi_dcl *struct_dcl, zend_ffi_dcl *field_dcl) /* {{{ */
- {
- zend_ffi_type *struct_type = ZEND_FFI_TYPE(struct_dcl->type);
- zend_ffi_type *field_type;
- zend_ffi_field *field;
- zend_string *key;
- ZEND_ASSERT(struct_type && struct_type->kind == ZEND_FFI_TYPE_STRUCT);
- zend_ffi_finalize_type(field_dcl);
- field_type = ZEND_FFI_TYPE(field_dcl->type);
- if (field_type->kind != ZEND_FFI_TYPE_STRUCT) {
- zend_ffi_cleanup_dcl(field_dcl);
- zend_ffi_parser_error("Declaration does not declare anything at line %d", FFI_G(line));
- return;
- }
- if (!(struct_type->attr & ZEND_FFI_ATTR_PACKED) && !(field_dcl->attr & ZEND_FFI_ATTR_PACKED)) {
- struct_type->align = MAX(struct_type->align, MAX(field_type->align, field_dcl->align));
- }
- if (!(struct_type->attr & ZEND_FFI_ATTR_UNION)) {
- if (zend_ffi_validate_prev_field_type(struct_type) != SUCCESS) {
- zend_ffi_cleanup_dcl(field_dcl);
- LONGJMP(FFI_G(bailout), FAILURE);
- }
- if (!(struct_type->attr & ZEND_FFI_ATTR_PACKED) && !(field_dcl->attr & ZEND_FFI_ATTR_PACKED)) {
- uint32_t field_align = MAX(field_type->align, field_dcl->align);
- struct_type->size = ((struct_type->size + (field_align - 1)) / field_align) * field_align;
- }
- }
- ZEND_HASH_FOREACH_STR_KEY_PTR(&field_type->record.fields, key, field) {
- zend_ffi_field *new_field = pemalloc(sizeof(zend_ffi_field), FFI_G(persistent));
- if (struct_type->attr & ZEND_FFI_ATTR_UNION) {
- new_field->offset = field->offset;
- } else {
- new_field->offset = struct_type->size + field->offset;
- }
- new_field->type = field->type;
- new_field->is_const = field->is_const;
- new_field->is_nested = 1;
- new_field->first_bit = field->first_bit;
- new_field->bits = field->bits;
- field->type = ZEND_FFI_TYPE(field->type); /* reset "owned" flag */
- if (key) {
- if (!zend_hash_add_ptr(&struct_type->record.fields, key, new_field)) {
- zend_ffi_type_dtor(new_field->type);
- pefree(new_field, FFI_G(persistent));
- zend_ffi_parser_error("Duplicate field name \"%s\" at line %d", ZSTR_VAL(key), FFI_G(line));
- return;
- }
- } else {
- zend_hash_next_index_insert_ptr(&struct_type->record.fields, field);
- }
- } ZEND_HASH_FOREACH_END();
- if (struct_type->attr & ZEND_FFI_ATTR_UNION) {
- struct_type->size = MAX(struct_type->size, field_type->size);
- } else {
- struct_type->size += field_type->size;
- }
- zend_ffi_type_dtor(field_dcl->type);
- field_dcl->type = NULL;
- }
- /* }}} */
- void zend_ffi_add_bit_field(zend_ffi_dcl *struct_dcl, const char *name, size_t name_len, zend_ffi_dcl *field_dcl, zend_ffi_val *bits) /* {{{ */
- {
- zend_ffi_type *struct_type = ZEND_FFI_TYPE(struct_dcl->type);
- zend_ffi_type *field_type;
- zend_ffi_field *field;
- ZEND_ASSERT(struct_type && struct_type->kind == ZEND_FFI_TYPE_STRUCT);
- zend_ffi_finalize_type(field_dcl);
- field_type = ZEND_FFI_TYPE(field_dcl->type);
- if (zend_ffi_validate_field_type(field_type, struct_type) != SUCCESS) {
- zend_ffi_cleanup_dcl(field_dcl);
- LONGJMP(FFI_G(bailout), FAILURE);
- }
- if (field_type->kind < ZEND_FFI_TYPE_UINT8 || field_type->kind > ZEND_FFI_TYPE_BOOL) {
- zend_ffi_cleanup_dcl(field_dcl);
- zend_ffi_parser_error("Wrong type of bit field \"%.*s\" at line %d", name ? name_len : sizeof("<anonymous>")-1, name ? name : "<anonymous>", FFI_G(line));
- }
- if (bits->kind == ZEND_FFI_VAL_INT32 || bits->kind == ZEND_FFI_VAL_INT64) {
- if (bits->i64 < 0) {
- zend_ffi_cleanup_dcl(field_dcl);
- zend_ffi_parser_error("Negative width in bit-field \"%.*s\" at line %d", name ? name_len : sizeof("<anonymous>")-1, name ? name : "<anonymous>", FFI_G(line));
- } else if (bits->i64 == 0) {
- zend_ffi_cleanup_dcl(field_dcl);
- if (name) {
- zend_ffi_parser_error("Zero width in bit-field \"%.*s\" at line %d", name ? name_len : sizeof("<anonymous>")-1, name ? name : "<anonymous>", FFI_G(line));
- }
- return;
- } else if (bits->i64 > field_type->size * 8) {
- zend_ffi_cleanup_dcl(field_dcl);
- zend_ffi_parser_error("Width of \"%.*s\" exceeds its type at line %d", name ? name_len : sizeof("<anonymous>")-1, name ? name : "<anonymous>", FFI_G(line));
- }
- } else if (bits->kind == ZEND_FFI_VAL_UINT32 || bits->kind == ZEND_FFI_VAL_UINT64) {
- if (bits->u64 == 0) {
- zend_ffi_cleanup_dcl(field_dcl);
- if (name) {
- zend_ffi_parser_error("Zero width in bit-field \"%.*s\" at line %d", name ? name_len : sizeof("<anonymous>")-1, name ? name : "<anonymous>", FFI_G(line));
- }
- return;
- } else if (bits->u64 > field_type->size * 8) {
- zend_ffi_cleanup_dcl(field_dcl);
- zend_ffi_parser_error("Width of \"%.*s\" exceeds its type at line %d", name ? name_len : sizeof("<anonymous>")-1, name ? name : "<anonymous>", FFI_G(line));
- }
- } else {
- zend_ffi_cleanup_dcl(field_dcl);
- zend_ffi_parser_error("Bit field \"%.*s\" width not an integer constant at line %d", name ? name_len : sizeof("<anonymous>")-1, name ? name : "<anonymous>", FFI_G(line));
- }
- field = pemalloc(sizeof(zend_ffi_field), FFI_G(persistent));
- if (!(struct_type->attr & ZEND_FFI_ATTR_PACKED)) {
- struct_type->align = MAX(struct_type->align, sizeof(uint32_t));
- }
- if (struct_type->attr & ZEND_FFI_ATTR_UNION) {
- field->offset = 0;
- field->first_bit = 0;
- field->bits = bits->u64;
- if (struct_type->attr & ZEND_FFI_ATTR_PACKED) {
- struct_type->size = MAX(struct_type->size, (bits->u64 + 7) / 8);
- } else {
- struct_type->size = MAX(struct_type->size, ((bits->u64 + 31) / 32) * 4);
- }
- } else {
- zend_ffi_field *prev_field = NULL;
- if (zend_hash_num_elements(&struct_type->record.fields) > 0) {
- ZEND_HASH_REVERSE_FOREACH_PTR(&struct_type->record.fields, prev_field) {
- break;
- } ZEND_HASH_FOREACH_END();
- }
- if (prev_field && prev_field->bits) {
- field->offset = prev_field->offset;
- field->first_bit = prev_field->first_bit + prev_field->bits;
- field->bits = bits->u64;
- } else {
- field->offset = struct_type->size;
- field->first_bit = 0;
- field->bits = bits->u64;
- }
- if (struct_type->attr & ZEND_FFI_ATTR_PACKED) {
- struct_type->size = field->offset + ((field->first_bit + field->bits) + 7) / 8;
- } else {
- struct_type->size = field->offset + (((field->first_bit + field->bits) + 31) / 32) * 4;
- }
- }
- field->type = field_dcl->type;
- field->is_const = (bool)(field_dcl->attr & ZEND_FFI_ATTR_CONST);
- field->is_nested = 0;
- field_dcl->type = field_type; /* reset "owned" flag */
- if (name) {
- if (!zend_hash_str_add_ptr(&struct_type->record.fields, name, name_len, field)) {
- zend_ffi_type_dtor(field->type);
- pefree(field, FFI_G(persistent));
- zend_ffi_parser_error("Duplicate field name \"%.*s\" at line %d", name_len, name, FFI_G(line));
- }
- } else {
- zend_hash_next_index_insert_ptr(&struct_type->record.fields, field);
- }
- }
- /* }}} */
- void zend_ffi_adjust_struct_size(zend_ffi_dcl *dcl) /* {{{ */
- {
- zend_ffi_type *struct_type = ZEND_FFI_TYPE(dcl->type);
- ZEND_ASSERT(struct_type->kind == ZEND_FFI_TYPE_STRUCT);
- if (dcl->align > struct_type->align) {
- struct_type->align = dcl->align;
- }
- if (!(struct_type->attr & ZEND_FFI_ATTR_PACKED)) {
- struct_type->size = ((struct_type->size + (struct_type->align - 1)) / struct_type->align) * struct_type->align;
- }
- dcl->align = 0;
- }
- /* }}} */
- void zend_ffi_make_pointer_type(zend_ffi_dcl *dcl) /* {{{ */
- {
- zend_ffi_type *type = pemalloc(sizeof(zend_ffi_type), FFI_G(persistent));
- type->kind = ZEND_FFI_TYPE_POINTER;
- type->attr = FFI_G(default_type_attr) | (dcl->attr & ZEND_FFI_POINTER_ATTRS);
- type->size = sizeof(void*);
- type->align = _Alignof(void*);
- zend_ffi_finalize_type(dcl);
- if (zend_ffi_validate_vla(ZEND_FFI_TYPE(dcl->type)) != SUCCESS) {
- zend_ffi_cleanup_dcl(dcl);
- LONGJMP(FFI_G(bailout), FAILURE);
- }
- type->pointer.type = dcl->type;
- dcl->type = ZEND_FFI_TYPE_MAKE_OWNED(type);
- dcl->flags &= ~ZEND_FFI_DCL_TYPE_QUALIFIERS;
- dcl->attr &= ~ZEND_FFI_POINTER_ATTRS;
- dcl->align = 0;
- }
- /* }}} */
- static int zend_ffi_validate_array_element_type(zend_ffi_type *type) /* {{{ */
- {
- if (type->kind == ZEND_FFI_TYPE_FUNC) {
- zend_ffi_throw_parser_error("Array of functions is not allowed at line %d", FFI_G(line));
- return FAILURE;
- } else if (type->kind == ZEND_FFI_TYPE_ARRAY && (type->attr & ZEND_FFI_ATTR_INCOMPLETE_ARRAY)) {
- zend_ffi_throw_parser_error("Only the leftmost array can be undimensioned at line %d", FFI_G(line));
- return FAILURE;
- }
- return zend_ffi_validate_type(type, 0, 1);
- }
- /* }}} */
- void zend_ffi_make_array_type(zend_ffi_dcl *dcl, zend_ffi_val *len) /* {{{ */
- {
- int length = 0;
- zend_ffi_type *element_type;
- zend_ffi_type *type;
- zend_ffi_finalize_type(dcl);
- element_type = ZEND_FFI_TYPE(dcl->type);
- if (len->kind == ZEND_FFI_VAL_EMPTY) {
- length = 0;
- } else if (len->kind == ZEND_FFI_VAL_UINT32 || len->kind == ZEND_FFI_VAL_UINT64) {
- length = len->u64;
- } else if (len->kind == ZEND_FFI_VAL_INT32 || len->kind == ZEND_FFI_VAL_INT64) {
- length = len->i64;
- } else if (len->kind == ZEND_FFI_VAL_CHAR) {
- length = len->ch;
- } else {
- zend_ffi_cleanup_dcl(dcl);
- zend_ffi_parser_error("Unsupported array index type at line %d", FFI_G(line));
- return;
- }
- if (length < 0) {
- zend_ffi_cleanup_dcl(dcl);
- zend_ffi_parser_error("Negative array index at line %d", FFI_G(line));
- return;
- }
- if (zend_ffi_validate_array_element_type(element_type) != SUCCESS) {
- zend_ffi_cleanup_dcl(dcl);
- LONGJMP(FFI_G(bailout), FAILURE);
- }
- type = pemalloc(sizeof(zend_ffi_type), FFI_G(persistent));
- type->kind = ZEND_FFI_TYPE_ARRAY;
- type->attr = FFI_G(default_type_attr) | (dcl->attr & ZEND_FFI_ARRAY_ATTRS);
- type->size = length * element_type->size;
- type->align = element_type->align;
- type->array.type = dcl->type;
- type->array.length = length;
- dcl->type = ZEND_FFI_TYPE_MAKE_OWNED(type);
- dcl->flags &= ~ZEND_FFI_DCL_TYPE_QUALIFIERS;
- dcl->attr &= ~ZEND_FFI_ARRAY_ATTRS;
- dcl->align = 0;
- }
- /* }}} */
- static int zend_ffi_validate_func_ret_type(zend_ffi_type *type) /* {{{ */
- {
- if (type->kind == ZEND_FFI_TYPE_FUNC) {
- zend_ffi_throw_parser_error("Function returning function is not allowed at line %d", FFI_G(line));
- return FAILURE;
- } else if (type->kind == ZEND_FFI_TYPE_ARRAY) {
- zend_ffi_throw_parser_error("Function returning array is not allowed at line %d", FFI_G(line));
- return FAILURE;
- }
- return zend_ffi_validate_incomplete_type(type, 1, 0);
- }
- /* }}} */
- void zend_ffi_make_func_type(zend_ffi_dcl *dcl, HashTable *args, zend_ffi_dcl *nested_dcl) /* {{{ */
- {
- zend_ffi_type *type;
- zend_ffi_type *ret_type;
- zend_ffi_finalize_type(dcl);
- ret_type = ZEND_FFI_TYPE(dcl->type);
- if (args) {
- int no_args = 0;
- zend_ffi_type *arg_type;
- ZEND_HASH_FOREACH_PTR(args, arg_type) {
- arg_type = ZEND_FFI_TYPE(arg_type);
- if (arg_type->kind == ZEND_FFI_TYPE_VOID) {
- if (zend_hash_num_elements(args) != 1) {
- zend_ffi_cleanup_dcl(nested_dcl);
- zend_ffi_cleanup_dcl(dcl);
- zend_hash_destroy(args);
- pefree(args, FFI_G(persistent));
- zend_ffi_parser_error("void type is not allowed at line %d", FFI_G(line));
- return;
- } else {
- no_args = 1;
- }
- }
- } ZEND_HASH_FOREACH_END();
- if (no_args) {
- zend_hash_destroy(args);
- pefree(args, FFI_G(persistent));
- args = NULL;
- }
- }
- #ifdef HAVE_FFI_VECTORCALL_PARTIAL
- if (dcl->abi == ZEND_FFI_ABI_VECTORCALL && args) {
- zend_ulong i;
- zend_ffi_type *arg_type;
- ZEND_HASH_FOREACH_NUM_KEY_PTR(args, i, arg_type) {
- arg_type = ZEND_FFI_TYPE(arg_type);
- # ifdef _WIN64
- if (i >= 4 && i <= 5 && (arg_type->kind == ZEND_FFI_TYPE_FLOAT || arg_type->kind == ZEND_FFI_TYPE_DOUBLE)) {
- # else
- if (i < 6 && (arg_type->kind == ZEND_FFI_TYPE_FLOAT || arg_type->kind == ZEND_FFI_TYPE_DOUBLE)) {
- # endif
- zend_ffi_cleanup_dcl(nested_dcl);
- zend_ffi_cleanup_dcl(dcl);
- zend_hash_destroy(args);
- pefree(args, FFI_G(persistent));
- zend_ffi_parser_error("Type float/double is not allowed at position " ZEND_ULONG_FMT " with __vectorcall at line %d", i+1, FFI_G(line));
- return;
- }
- } ZEND_HASH_FOREACH_END();
- }
- #endif
- if (zend_ffi_validate_func_ret_type(ret_type) != SUCCESS) {
- zend_ffi_cleanup_dcl(nested_dcl);
- zend_ffi_cleanup_dcl(dcl);
- if (args) {
- zend_hash_destroy(args);
- pefree(args, FFI_G(persistent));
- }
- LONGJMP(FFI_G(bailout), FAILURE);
- }
- type = pemalloc(sizeof(zend_ffi_type), FFI_G(persistent));
- type->kind = ZEND_FFI_TYPE_FUNC;
- type->attr = FFI_G(default_type_attr) | (dcl->attr & ZEND_FFI_FUNC_ATTRS);
- type->size = sizeof(void*);
- type->align = 1;
- type->func.ret_type = dcl->type;
- switch (dcl->abi) {
- case ZEND_FFI_ABI_DEFAULT:
- case ZEND_FFI_ABI_CDECL:
- type->func.abi = FFI_DEFAULT_ABI;
- break;
- #ifdef HAVE_FFI_FASTCALL
- case ZEND_FFI_ABI_FASTCALL:
- type->func.abi = FFI_FASTCALL;
- break;
- #endif
- #ifdef HAVE_FFI_THISCALL
- case ZEND_FFI_ABI_THISCALL:
- type->func.abi = FFI_THISCALL;
- break;
- #endif
- #ifdef HAVE_FFI_STDCALL
- case ZEND_FFI_ABI_STDCALL:
- type->func.abi = FFI_STDCALL;
- break;
- #endif
- #ifdef HAVE_FFI_PASCAL
- case ZEND_FFI_ABI_PASCAL:
- type->func.abi = FFI_PASCAL;
- break;
- #endif
- #ifdef HAVE_FFI_REGISTER
- case ZEND_FFI_ABI_REGISTER:
- type->func.abi = FFI_REGISTER;
- break;
- #endif
- #ifdef HAVE_FFI_MS_CDECL
- case ZEND_FFI_ABI_MS:
- type->func.abi = FFI_MS_CDECL;
- break;
- #endif
- #ifdef HAVE_FFI_SYSV
- case ZEND_FFI_ABI_SYSV:
- type->func.abi = FFI_SYSV;
- break;
- #endif
- #ifdef HAVE_FFI_VECTORCALL_PARTIAL
- case ZEND_FFI_ABI_VECTORCALL:
- type->func.abi = FFI_VECTORCALL_PARTIAL;
- break;
- #endif
- default:
- type->func.abi = FFI_DEFAULT_ABI;
- zend_ffi_cleanup_dcl(nested_dcl);
- if (args) {
- zend_hash_destroy(args);
- pefree(args, FFI_G(persistent));
- }
- type->func.args = NULL;
- _zend_ffi_type_dtor(type);
- zend_ffi_parser_error("Unsupported calling convention line %d", FFI_G(line));
- break;
- }
- type->func.args = args;
- dcl->type = ZEND_FFI_TYPE_MAKE_OWNED(type);
- dcl->attr &= ~ZEND_FFI_FUNC_ATTRS;
- dcl->align = 0;
- dcl->abi = 0;
- }
- /* }}} */
- void zend_ffi_add_arg(HashTable **args, const char *name, size_t name_len, zend_ffi_dcl *arg_dcl) /* {{{ */
- {
- zend_ffi_type *type;
- if (!*args) {
- *args = pemalloc(sizeof(HashTable), FFI_G(persistent));
- zend_hash_init(*args, 0, NULL, zend_ffi_type_hash_dtor, FFI_G(persistent));
- }
- zend_ffi_finalize_type(arg_dcl);
- type = ZEND_FFI_TYPE(arg_dcl->type);
- if (type->kind == ZEND_FFI_TYPE_ARRAY) {
- if (ZEND_FFI_TYPE_IS_OWNED(arg_dcl->type)) {
- type->kind = ZEND_FFI_TYPE_POINTER;
- type->size = sizeof(void*);
- } else {
- zend_ffi_type *new_type = pemalloc(sizeof(zend_ffi_type), FFI_G(persistent));
- new_type->kind = ZEND_FFI_TYPE_POINTER;
- new_type->attr = FFI_G(default_type_attr) | (type->attr & ZEND_FFI_POINTER_ATTRS);
- new_type->size = sizeof(void*);
- new_type->align = _Alignof(void*);
- new_type->pointer.type = ZEND_FFI_TYPE(type->array.type);
- arg_dcl->type = ZEND_FFI_TYPE_MAKE_OWNED(new_type);
- }
- } else if (type->kind == ZEND_FFI_TYPE_FUNC) {
- zend_ffi_type *new_type = pemalloc(sizeof(zend_ffi_type), FFI_G(persistent));
- new_type->kind = ZEND_FFI_TYPE_POINTER;
- new_type->attr = FFI_G(default_type_attr);
- new_type->size = sizeof(void*);
- new_type->align = _Alignof(void*);
- new_type->pointer.type = arg_dcl->type;
- arg_dcl->type = ZEND_FFI_TYPE_MAKE_OWNED(new_type);
- }
- if (zend_ffi_validate_incomplete_type(type, 1, 1) != SUCCESS) {
- zend_ffi_cleanup_dcl(arg_dcl);
- zend_hash_destroy(*args);
- pefree(*args, FFI_G(persistent));
- *args = NULL;
- LONGJMP(FFI_G(bailout), FAILURE);
- }
- zend_hash_next_index_insert_ptr(*args, (void*)arg_dcl->type);
- }
- /* }}} */
- void zend_ffi_declare(const char *name, size_t name_len, zend_ffi_dcl *dcl) /* {{{ */
- {
- zend_ffi_symbol *sym;
- if (!FFI_G(symbols)) {
- FFI_G(symbols) = pemalloc(sizeof(HashTable), FFI_G(persistent));
- zend_hash_init(FFI_G(symbols), 0, NULL, FFI_G(persistent) ? zend_ffi_symbol_hash_persistent_dtor : zend_ffi_symbol_hash_dtor, FFI_G(persistent));
- }
- zend_ffi_finalize_type(dcl);
- sym = zend_hash_str_find_ptr(FFI_G(symbols), name, name_len);
- if (sym) {
- if ((dcl->flags & ZEND_FFI_DCL_STORAGE_CLASS) == ZEND_FFI_DCL_TYPEDEF
- && sym->kind == ZEND_FFI_SYM_TYPE
- && zend_ffi_is_same_type(ZEND_FFI_TYPE(sym->type), ZEND_FFI_TYPE(dcl->type))
- && sym->is_const == (bool)(dcl->attr & ZEND_FFI_ATTR_CONST)) {
- /* allowed redeclaration */
- zend_ffi_type_dtor(dcl->type);
- return;
- } else if ((dcl->flags & ZEND_FFI_DCL_STORAGE_CLASS) == 0
- || (dcl->flags & ZEND_FFI_DCL_STORAGE_CLASS) == ZEND_FFI_DCL_EXTERN) {
- zend_ffi_type *type = ZEND_FFI_TYPE(dcl->type);
- if (type->kind == ZEND_FFI_TYPE_FUNC) {
- if (sym->kind == ZEND_FFI_SYM_FUNC
- && zend_ffi_same_types(ZEND_FFI_TYPE(sym->type), type)) {
- /* allowed redeclaration */
- zend_ffi_type_dtor(dcl->type);
- return;
- }
- } else {
- if (sym->kind == ZEND_FFI_SYM_VAR
- && zend_ffi_is_same_type(ZEND_FFI_TYPE(sym->type), type)
- && sym->is_const == (bool)(dcl->attr & ZEND_FFI_ATTR_CONST)) {
- /* allowed redeclaration */
- zend_ffi_type_dtor(dcl->type);
- return;
- }
- }
- }
- zend_ffi_parser_error("Redeclaration of \"%.*s\" at line %d", name_len, name, FFI_G(line));
- } else {
- if ((dcl->flags & ZEND_FFI_DCL_STORAGE_CLASS) == ZEND_FFI_DCL_TYPEDEF) {
- if (zend_ffi_validate_vla(ZEND_FFI_TYPE(dcl->type)) != SUCCESS) {
- zend_ffi_cleanup_dcl(dcl);
- LONGJMP(FFI_G(bailout), FAILURE);
- }
- if (dcl->align && dcl->align > ZEND_FFI_TYPE(dcl->type)->align) {
- if (ZEND_FFI_TYPE_IS_OWNED(dcl->type)) {
- ZEND_FFI_TYPE(dcl->type)->align = dcl->align;
- } else {
- zend_ffi_type *type = pemalloc(sizeof(zend_ffi_type), FFI_G(persistent));
- memcpy(type, ZEND_FFI_TYPE(dcl->type), sizeof(zend_ffi_type));
- type->attr |= FFI_G(default_type_attr);
- type->align = dcl->align;
- dcl->type = ZEND_FFI_TYPE_MAKE_OWNED(type);
- }
- }
- sym = pemalloc(sizeof(zend_ffi_symbol), FFI_G(persistent));
- sym->kind = ZEND_FFI_SYM_TYPE;
- sym->type = dcl->type;
- sym->is_const = (bool)(dcl->attr & ZEND_FFI_ATTR_CONST);
- dcl->type = ZEND_FFI_TYPE(dcl->type); /* reset "owned" flag */
- zend_hash_str_add_new_ptr(FFI_G(symbols), name, name_len, sym);
- } else {
- zend_ffi_type *type;
- type = ZEND_FFI_TYPE(dcl->type);
- if (zend_ffi_validate_type(type, (dcl->flags & ZEND_FFI_DCL_STORAGE_CLASS) == ZEND_FFI_DCL_EXTERN, 1) != SUCCESS) {
- zend_ffi_cleanup_dcl(dcl);
- LONGJMP(FFI_G(bailout), FAILURE);
- }
- if ((dcl->flags & ZEND_FFI_DCL_STORAGE_CLASS) == 0 ||
- (dcl->flags & ZEND_FFI_DCL_STORAGE_CLASS) == ZEND_FFI_DCL_EXTERN) {
- sym = pemalloc(sizeof(zend_ffi_symbol), FFI_G(persistent));
- sym->kind = (type->kind == ZEND_FFI_TYPE_FUNC) ? ZEND_FFI_SYM_FUNC : ZEND_FFI_SYM_VAR;
- sym->type = dcl->type;
- sym->is_const = (bool)(dcl->attr & ZEND_FFI_ATTR_CONST);
- dcl->type = type; /* reset "owned" flag */
- zend_hash_str_add_new_ptr(FFI_G(symbols), name, name_len, sym);
- } else {
- /* useless declarartion */
- zend_ffi_type_dtor(dcl->type);
- }
- }
- }
- }
- /* }}} */
- void zend_ffi_declare_tag(const char *name, size_t name_len, zend_ffi_dcl *dcl, bool incomplete) /* {{{ */
- {
- zend_ffi_tag *tag;
- zend_ffi_type *type;
- if (!FFI_G(tags)) {
- FFI_G(tags) = pemalloc(sizeof(HashTable), FFI_G(persistent));
- zend_hash_init(FFI_G(tags), 0, NULL, FFI_G(persistent) ? zend_ffi_tag_hash_persistent_dtor : zend_ffi_tag_hash_dtor, FFI_G(persistent));
- }
- tag = zend_hash_str_find_ptr(FFI_G(tags), name, name_len);
- if (tag) {
- zend_ffi_type *type = ZEND_FFI_TYPE(tag->type);
- if (dcl->flags & ZEND_FFI_DCL_STRUCT) {
- if (tag->kind != ZEND_FFI_TAG_STRUCT) {
- zend_ffi_parser_error("\"%.*s\" defined as wrong kind of tag at line %d", name_len, name, FFI_G(line));
- return;
- } else if (!incomplete && !(type->attr & ZEND_FFI_ATTR_INCOMPLETE_TAG)) {
- zend_ffi_parser_error("Redefinition of \"struct %.*s\" at line %d", name_len, name, FFI_G(line));
- return;
- }
- } else if (dcl->flags & ZEND_FFI_DCL_UNION) {
- if (tag->kind != ZEND_FFI_TAG_UNION) {
- zend_ffi_parser_error("\"%.*s\" defined as wrong kind of tag at line %d", name_len, name, FFI_G(line));
- return;
- } else if (!incomplete && !(type->attr & ZEND_FFI_ATTR_INCOMPLETE_TAG)) {
- zend_ffi_parser_error("Redefinition of \"union %.*s\" at line %d", name_len, name, FFI_G(line));
- return;
- }
- } else if (dcl->flags & ZEND_FFI_DCL_ENUM) {
- if (tag->kind != ZEND_FFI_TAG_ENUM) {
- zend_ffi_parser_error("\"%.*s\" defined as wrong kind of tag at line %d", name_len, name, FFI_G(line));
- return;
- } else if (!incomplete && !(type->attr & ZEND_FFI_ATTR_INCOMPLETE_TAG)) {
- zend_ffi_parser_error("Redefinition of \"enum %.*s\" at line %d", name_len, name, FFI_G(line));
- return;
- }
- } else {
- ZEND_UNREACHABLE();
- return;
- }
- dcl->type = type;
- if (!incomplete) {
- type->attr &= ~ZEND_FFI_ATTR_INCOMPLETE_TAG;
- }
- } else {
- zend_ffi_tag *tag = pemalloc(sizeof(zend_ffi_tag), FFI_G(persistent));
- zend_string *tag_name = zend_string_init(name, name_len, FFI_G(persistent));
- if (dcl->flags & ZEND_FFI_DCL_STRUCT) {
- tag->kind = ZEND_FFI_TAG_STRUCT;
- zend_ffi_make_struct_type(dcl);
- type = ZEND_FFI_TYPE(dcl->type);
- type->record.tag_name = zend_string_copy(tag_name);
- } else if (dcl->flags & ZEND_FFI_DCL_UNION) {
- tag->kind = ZEND_FFI_TAG_UNION;
- zend_ffi_make_struct_type(dcl);
- type = ZEND_FFI_TYPE(dcl->type);
- type->record.tag_name = zend_string_copy(tag_name);
- } else if (dcl->flags & ZEND_FFI_DCL_ENUM) {
- tag->kind = ZEND_FFI_TAG_ENUM;
- zend_ffi_make_enum_type(dcl);
- type = ZEND_FFI_TYPE(dcl->type);
- type->enumeration.tag_name = zend_string_copy(tag_name);
- } else {
- ZEND_UNREACHABLE();
- }
- tag->type = ZEND_FFI_TYPE_MAKE_OWNED(dcl->type);
- dcl->type = ZEND_FFI_TYPE(dcl->type);
- if (incomplete) {
- dcl->type->attr |= ZEND_FFI_ATTR_INCOMPLETE_TAG;
- }
- zend_hash_add_new_ptr(FFI_G(tags), tag_name, tag);
- zend_string_release(tag_name);
- }
- }
- /* }}} */
- void zend_ffi_set_abi(zend_ffi_dcl *dcl, uint16_t abi) /* {{{ */
- {
- if (dcl->abi != ZEND_FFI_ABI_DEFAULT) {
- zend_ffi_parser_error("Multiple calling convention specifiers at line %d", FFI_G(line));
- } else {
- dcl->abi = abi;
- }
- }
- /* }}} */
- #define SIMPLE_ATTRIBUTES(_) \
- _(cdecl) \
- _(fastcall) \
- _(thiscall) \
- _(stdcall) \
- _(ms_abi) \
- _(sysv_abi) \
- _(vectorcall) \
- _(aligned) \
- _(packed) \
- _(ms_struct) \
- _(gcc_struct) \
- _(const) \
- _(malloc) \
- _(deprecated) \
- _(nothrow) \
- _(leaf) \
- _(pure) \
- _(noreturn) \
- _(warn_unused_result)
- #define ATTR_ID(name) attr_ ## name,
- #define ATTR_NAME(name) {sizeof(#name)-1, #name},
- void zend_ffi_add_attribute(zend_ffi_dcl *dcl, const char *name, size_t name_len) /* {{{ */
- {
- enum {
- SIMPLE_ATTRIBUTES(ATTR_ID)
- attr_unsupported
- };
- static const struct {
- size_t len;
- const char * const name;
- } names[] = {
- SIMPLE_ATTRIBUTES(ATTR_NAME)
- {0, NULL}
- };
- int id;
- if (name_len > 4
- && name[0] == '_'
- && name[1] == '_'
- && name[name_len-2] == '_'
- && name[name_len-1] == '_') {
- name += 2;
- name_len -= 4;
- }
- for (id = 0; names[id].len != 0; id++) {
- if (name_len == names[id].len) {
- if (memcmp(name, names[id].name, name_len) == 0) {
- break;
- }
- }
- }
- switch (id) {
- case attr_cdecl:
- zend_ffi_set_abi(dcl, ZEND_FFI_ABI_CDECL);
- break;
- case attr_fastcall:
- zend_ffi_set_abi(dcl, ZEND_FFI_ABI_FASTCALL);
- break;
- case attr_thiscall:
- zend_ffi_set_abi(dcl, ZEND_FFI_ABI_THISCALL);
- break;
- case attr_stdcall:
- zend_ffi_set_abi(dcl, ZEND_FFI_ABI_STDCALL);
- break;
- case attr_ms_abi:
- zend_ffi_set_abi(dcl, ZEND_FFI_ABI_MS);
- break;
- case attr_sysv_abi:
- zend_ffi_set_abi(dcl, ZEND_FFI_ABI_SYSV);
- break;
- case attr_vectorcall:
- zend_ffi_set_abi(dcl, ZEND_FFI_ABI_VECTORCALL);
- break;
- case attr_aligned:
- dcl->align = __BIGGEST_ALIGNMENT__;
- break;
- case attr_packed:
- dcl->attr |= ZEND_FFI_ATTR_PACKED;
- break;
- case attr_ms_struct:
- dcl->attr |= ZEND_FFI_ATTR_MS_STRUCT;
- break;
- case attr_gcc_struct:
- dcl->attr |= ZEND_FFI_ATTR_GCC_STRUCT;
- break;
- case attr_unsupported:
- zend_ffi_parser_error("Unsupported attribute \"%.*s\" at line %d", name_len, name, FFI_G(line));
- break;
- default:
- /* ignore */
- break;
- }
- }
- /* }}} */
- #define VALUE_ATTRIBUTES(_) \
- _(regparam) \
- _(aligned) \
- _(mode) \
- _(nonnull) \
- _(alloc_size) \
- _(format) \
- _(deprecated)
- void zend_ffi_add_attribute_value(zend_ffi_dcl *dcl, const char *name, size_t name_len, int n, zend_ffi_val *val) /* {{{ */
- {
- enum {
- VALUE_ATTRIBUTES(ATTR_ID)
- attr_unsupported
- };
- static const struct {
- size_t len;
- const char * const name;
- } names[] = {
- VALUE_ATTRIBUTES(ATTR_NAME)
- {0, NULL}
- };
- int id;
- if (name_len > 4
- && name[0] == '_'
- && name[1] == '_'
- && name[name_len-2] == '_'
- && name[name_len-1] == '_') {
- name += 2;
- name_len -= 4;
- }
- for (id = 0; names[id].len != 0; id++) {
- if (name_len == names[id].len) {
- if (memcmp(name, names[id].name, name_len) == 0) {
- break;
- }
- }
- }
- switch (id) {
- case attr_regparam:
- if (n == 0
- && (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_INT64 || val->kind == ZEND_FFI_VAL_UINT64)
- && val->i64 == 3) {
- zend_ffi_set_abi(dcl, ZEND_FFI_ABI_REGISTER);
- } else {
- zend_ffi_parser_error("Incorrect \"regparam\" value at line %d", FFI_G(line));
- }
- break;
- case attr_aligned:
- if (n == 0
- && (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_INT64 || val->kind == ZEND_FFI_VAL_UINT64)
- && val->i64 > 0 && val->i64 <= 0x80000000 && (val->i64 & (val->i64 - 1)) == 0) {
- dcl->align = val->i64;
- } else {
- zend_ffi_parser_error("Incorrect \"alignment\" value at line %d", FFI_G(line));
- }
- break;
- case attr_mode:
- if (n == 0
- && (val->kind == ZEND_FFI_VAL_NAME)) {
- const char *str = val->str;
- size_t len = val->len;
- if (len > 4
- && str[0] == '_'
- && str[1] == '_'
- && str[len-2] == '_'
- && str[len-1] == '_') {
- str += 2;
- len -= 4;
- }
- // TODO: Add support for vector type 'VnXX' ???
- if (len == 2) {
- if (str[1] == 'I') {
- if (dcl->flags & (ZEND_FFI_DCL_TYPE_SPECIFIERS-(ZEND_FFI_DCL_CHAR|ZEND_FFI_DCL_SHORT|ZEND_FFI_DCL_INT|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_LONG_LONG|ZEND_FFI_DCL_SIGNED|ZEND_FFI_DCL_UNSIGNED))) {
- /* inappropriate type */
- } else if (str[0] == 'Q') {
- dcl->flags &= ~(ZEND_FFI_DCL_CHAR|ZEND_FFI_DCL_SHORT|ZEND_FFI_DCL_INT|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_LONG_LONG);
- dcl->flags |= ZEND_FFI_DCL_CHAR;
- break;
- } else if (str[0] == 'H') {
- dcl->flags &= ~(ZEND_FFI_DCL_CHAR|ZEND_FFI_DCL_SHORT|ZEND_FFI_DCL_INT|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_LONG_LONG);
- dcl->flags |= ZEND_FFI_DCL_SHORT;
- break;
- } else if (str[0] == 'S') {
- dcl->flags &= ~(ZEND_FFI_DCL_CHAR|ZEND_FFI_DCL_SHORT|ZEND_FFI_DCL_INT|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_LONG_LONG);
- dcl->flags |= ZEND_FFI_DCL_INT;
- break;
- } else if (str[0] == 'D') {
- dcl->flags &= ~(ZEND_FFI_DCL_CHAR|ZEND_FFI_DCL_SHORT|ZEND_FFI_DCL_INT|ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_LONG_LONG);
- if (sizeof(long) == 8) {
- dcl->flags |= ZEND_FFI_DCL_LONG;
- } else {
- dcl->flags |= ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_LONG_LONG;
- }
- break;
- }
- } else if (str[1] == 'F') {
- if (dcl->flags & (ZEND_FFI_DCL_TYPE_SPECIFIERS-(ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_FLOAT|ZEND_FFI_DCL_DOUBLE))) {
- /* inappropriate type */
- } else if (str[0] == 'S') {
- dcl->flags &= ~(ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_FLOAT|ZEND_FFI_DCL_DOUBLE);
- dcl->flags |= ZEND_FFI_DCL_FLOAT;
- break;
- } else if (str[0] == 'D') {
- dcl->flags &= ~(ZEND_FFI_DCL_LONG|ZEND_FFI_DCL_FLOAT|ZEND_FFI_DCL_DOUBLE);
- dcl->flags |= ZEND_FFI_DCL_DOUBLE;
- break;
- }
- }
- }
- }
- zend_ffi_parser_error("Unsupported \"mode\" value at line %d", FFI_G(line));
- // TODO: ???
- case attr_unsupported:
- zend_ffi_parser_error("Unsupported attribute \"%.*s\" at line %d", name_len, name, FFI_G(line));
- break;
- default:
- /* ignore */
- break;
- }
- }
- /* }}} */
- void zend_ffi_add_msvc_attribute_value(zend_ffi_dcl *dcl, const char *name, size_t name_len, zend_ffi_val *val) /* {{{ */
- {
- if (name_len == sizeof("align")-1 && memcmp(name, "align", sizeof("align")-1) == 0) {
- if ((val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_INT64 || val->kind == ZEND_FFI_VAL_UINT64)
- && val->i64 > 0 && val->i64 <= 0x80000000 && (val->i64 & (val->i64 - 1)) == 0) {
- dcl->align = val->i64;
- } else {
- zend_ffi_parser_error("Incorrect \"alignment\" value at line %d", FFI_G(line));
- }
- } else {
- /* ignore */
- }
- }
- /* }}} */
- static int zend_ffi_nested_type(zend_ffi_type *type, zend_ffi_type *nested_type) /* {{{ */
- {
- nested_type = ZEND_FFI_TYPE(nested_type);
- switch (nested_type->kind) {
- case ZEND_FFI_TYPE_POINTER:
- /* "char" is used as a terminator of nested declaration */
- if (nested_type->pointer.type == &zend_ffi_type_char) {
- nested_type->pointer.type = type;
- return zend_ffi_validate_vla(ZEND_FFI_TYPE(type));
- } else {
- return zend_ffi_nested_type(type, nested_type->pointer.type);
- }
- break;
- case ZEND_FFI_TYPE_ARRAY:
- /* "char" is used as a terminator of nested declaration */
- if (nested_type->array.type == &zend_ffi_type_char) {
- nested_type->array.type = type;
- if (zend_ffi_validate_array_element_type(ZEND_FFI_TYPE(type)) != SUCCESS) {
- return FAILURE;
- }
- } else {
- if (zend_ffi_nested_type(type, nested_type->array.type) != SUCCESS) {
- return FAILURE;
- }
- }
- nested_type->size = nested_type->array.length * ZEND_FFI_TYPE(nested_type->array.type)->size;
- nested_type->align = ZEND_FFI_TYPE(nested_type->array.type)->align;
- return SUCCESS;
- break;
- case ZEND_FFI_TYPE_FUNC:
- /* "char" is used as a terminator of nested declaration */
- if (nested_type->func.ret_type == &zend_ffi_type_char) {
- nested_type->func.ret_type = type;
- return zend_ffi_validate_func_ret_type(ZEND_FFI_TYPE(type));
- } else {
- return zend_ffi_nested_type(type, nested_type->func.ret_type);
- }
- break;
- default:
- ZEND_UNREACHABLE();
- }
- }
- /* }}} */
- void zend_ffi_nested_declaration(zend_ffi_dcl *dcl, zend_ffi_dcl *nested_dcl) /* {{{ */
- {
- /* "char" is used as a terminator of nested declaration */
- zend_ffi_finalize_type(dcl);
- if (!nested_dcl->type || nested_dcl->type == &zend_ffi_type_char) {
- nested_dcl->type = dcl->type;
- } else {
- if (zend_ffi_nested_type(dcl->type, nested_dcl->type) != SUCCESS) {
- zend_ffi_cleanup_dcl(nested_dcl);
- LONGJMP(FFI_G(bailout), FAILURE);
- }
- }
- dcl->type = nested_dcl->type;
- }
- /* }}} */
- void zend_ffi_align_as_type(zend_ffi_dcl *dcl, zend_ffi_dcl *align_dcl) /* {{{ */
- {
- zend_ffi_finalize_type(align_dcl);
- dcl->align = MAX(align_dcl->align, ZEND_FFI_TYPE(align_dcl->type)->align);
- }
- /* }}} */
- void zend_ffi_align_as_val(zend_ffi_dcl *dcl, zend_ffi_val *align_val) /* {{{ */
- {
- switch (align_val->kind) {
- case ZEND_FFI_VAL_INT32:
- case ZEND_FFI_VAL_UINT32:
- dcl->align = zend_ffi_type_uint32.align;
- break;
- case ZEND_FFI_VAL_INT64:
- case ZEND_FFI_VAL_UINT64:
- dcl->align = zend_ffi_type_uint64.align;
- break;
- case ZEND_FFI_VAL_FLOAT:
- dcl->align = zend_ffi_type_float.align;
- break;
- case ZEND_FFI_VAL_DOUBLE:
- dcl->align = zend_ffi_type_double.align;
- break;
- #ifdef HAVE_LONG_DOUBLE
- case ZEND_FFI_VAL_LONG_DOUBLE:
- dcl->align = zend_ffi_type_long_double.align;
- break;
- #endif
- case ZEND_FFI_VAL_CHAR:
- case ZEND_FFI_VAL_STRING:
- dcl->align = zend_ffi_type_char.align;
- break;
- default:
- break;
- }
- }
- /* }}} */
- #define zend_ffi_expr_bool(val) do { \
- if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) { \
- val->kind = ZEND_FFI_VAL_INT32; \
- val->i64 = !!val->u64; \
- } else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) { \
- val->kind = ZEND_FFI_VAL_INT32; \
- val->i64 = !!val->i64; \
- } else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
- val->kind = ZEND_FFI_VAL_INT32; \
- val->i64 = !!val->d; \
- } else if (val->kind == ZEND_FFI_VAL_CHAR) { \
- val->kind = ZEND_FFI_VAL_INT32; \
- val->i64 = !!val->ch; \
- } else { \
- val->kind = ZEND_FFI_VAL_ERROR; \
- } \
- } while (0)
- #define zend_ffi_expr_math(val, op2, OP) do { \
- if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) { \
- if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
- val->kind = MAX(val->kind, op2->kind); \
- val->u64 = val->u64 OP op2->u64; \
- } else if (op2->kind == ZEND_FFI_VAL_INT32) { \
- val->u64 = val->u64 OP op2->i64; \
- } else if (op2->kind == ZEND_FFI_VAL_INT64) { \
- val->u64 = val->u64 OP op2->i64; \
- } else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
- val->kind = op2->kind; \
- val->d = (zend_ffi_double)val->u64 OP op2->d; \
- } else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
- val->u64 = val->u64 OP op2->ch; \
- } else { \
- val->kind = ZEND_FFI_VAL_ERROR; \
- } \
- } else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) { \
- if (op2->kind == ZEND_FFI_VAL_UINT32) { \
- val->i64 = val->i64 OP op2->u64; \
- } else if (op2->kind == ZEND_FFI_VAL_UINT64) { \
- val->i64 = val->i64 OP op2->u64; \
- } else if (op2->kind == ZEND_FFI_VAL_INT32 || op2->kind == ZEND_FFI_VAL_INT64) { \
- val->kind = MAX(val->kind, op2->kind); \
- val->i64 = val->i64 OP op2->i64; \
- } else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
- val->kind = op2->kind; \
- val->d = (zend_ffi_double)val->i64 OP op2->d; \
- } else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
- val->i64 = val->i64 OP op2->ch; \
- } else { \
- val->kind = ZEND_FFI_VAL_ERROR; \
- } \
- } else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
- if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
- val->d = val->d OP (zend_ffi_double)op2->u64; \
- } else if (op2->kind == ZEND_FFI_VAL_INT32 ||op2->kind == ZEND_FFI_VAL_INT64) { \
- val->d = val->d OP (zend_ffi_double)op2->i64; \
- } else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
- val->kind = MAX(val->kind, op2->kind); \
- val->d = val->d OP op2->d; \
- } else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
- val->d = val->d OP (zend_ffi_double)op2->ch; \
- } else { \
- val->kind = ZEND_FFI_VAL_ERROR; \
- } \
- } else if (val->kind == ZEND_FFI_VAL_CHAR) { \
- if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
- val->kind = op2->kind; \
- val->u64 = val->ch OP op2->u64; \
- } else if (op2->kind == ZEND_FFI_VAL_INT32 || op2->kind == ZEND_FFI_VAL_INT64) { \
- val->kind = ZEND_FFI_VAL_INT64; \
- val->i64 = val->ch OP op2->i64; \
- } else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
- val->kind = op2->kind; \
- val->d = (zend_ffi_double)val->ch OP op2->d; \
- } else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
- val->ch = val->ch OP op2->ch; \
- } else { \
- val->kind = ZEND_FFI_VAL_ERROR; \
- } \
- } else { \
- val->kind = ZEND_FFI_VAL_ERROR; \
- } \
- } while (0)
- #define zend_ffi_expr_int_math(val, op2, OP) do { \
- if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) { \
- if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
- val->kind = MAX(val->kind, op2->kind); \
- val->u64 = val->u64 OP op2->u64; \
- } else if (op2->kind == ZEND_FFI_VAL_INT32) { \
- val->u64 = val->u64 OP op2->i64; \
- } else if (op2->kind == ZEND_FFI_VAL_INT64) { \
- val->u64 = val->u64 OP op2->i64; \
- } else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
- val->u64 = val->u64 OP (uint64_t)op2->d; \
- } else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
- val->u64 = val->u64 OP op2->ch; \
- } else { \
- val->kind = ZEND_FFI_VAL_ERROR; \
- } \
- } else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) { \
- if (op2->kind == ZEND_FFI_VAL_UINT32) { \
- val->i64 = val->i64 OP op2->u64; \
- } else if (op2->kind == ZEND_FFI_VAL_UINT64) { \
- val->i64 = val->i64 OP op2->u64; \
- } else if (op2->kind == ZEND_FFI_VAL_INT32 || op2->kind == ZEND_FFI_VAL_INT64) { \
- val->kind = MAX(val->kind, op2->kind); \
- val->i64 = val->i64 OP op2->i64; \
- } else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
- val->u64 = val->u64 OP (int64_t)op2->d; \
- } else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
- val->i64 = val->i64 OP op2->ch; \
- } else { \
- val->kind = ZEND_FFI_VAL_ERROR; \
- } \
- } else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
- if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
- val->kind = op2->kind; \
- val->u64 = (uint64_t)val->d OP op2->u64; \
- } else if (op2->kind == ZEND_FFI_VAL_INT32 || op2->kind == ZEND_FFI_VAL_INT64) { \
- val->kind = op2->kind; \
- val->i64 = (int64_t)val->d OP op2->i64; \
- } else { \
- val->kind = ZEND_FFI_VAL_ERROR; \
- } \
- } else if (val->kind == ZEND_FFI_VAL_CHAR) { \
- if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
- val->kind = op2->kind; \
- val->u64 = (uint64_t)val->ch OP op2->u64; \
- } else if (op2->kind == ZEND_FFI_VAL_INT32 || op2->kind == ZEND_FFI_VAL_INT64) { \
- val->kind = op2->kind; \
- val->i64 = (int64_t)val->ch OP op2->u64; \
- } else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
- val->ch = val->ch OP op2->ch; \
- } else { \
- val->kind = ZEND_FFI_VAL_ERROR; \
- } \
- } else { \
- val->kind = ZEND_FFI_VAL_ERROR; \
- } \
- } while (0)
- #define zend_ffi_expr_cmp(val, op2, OP) do { \
- if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) { \
- if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
- val->kind = ZEND_FFI_VAL_INT32; \
- val->i64 = val->u64 OP op2->u64; \
- } else if (op2->kind == ZEND_FFI_VAL_INT32 || op2->kind == ZEND_FFI_VAL_INT64) { \
- val->kind = ZEND_FFI_VAL_INT32; \
- val->i64 = val->u64 OP op2->u64; /*signed/unsigned */ \
- } else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
- val->kind = ZEND_FFI_VAL_INT32; \
- val->i64 = (zend_ffi_double)val->u64 OP op2->d; \
- } else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
- val->kind = ZEND_FFI_VAL_INT32; \
- val->i64 = val->u64 OP op2->d; \
- } else { \
- val->kind = ZEND_FFI_VAL_ERROR; \
- } \
- } else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) { \
- if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
- val->kind = ZEND_FFI_VAL_INT32; \
- val->i64 = val->i64 OP op2->i64; /* signed/unsigned */ \
- } else if (op2->kind == ZEND_FFI_VAL_INT32 || op2->kind == ZEND_FFI_VAL_INT64) { \
- val->kind = ZEND_FFI_VAL_INT32; \
- val->i64 = val->i64 OP op2->i64; \
- } else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
- val->kind = ZEND_FFI_VAL_INT32; \
- val->i64 = (zend_ffi_double)val->i64 OP op2->d; \
- } else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
- val->kind = ZEND_FFI_VAL_INT32; \
- val->i64 = val->i64 OP op2->ch; \
- } else { \
- val->kind = ZEND_FFI_VAL_ERROR; \
- } \
- } else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
- if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
- val->kind = ZEND_FFI_VAL_INT32; \
- val->i64 = val->d OP (zend_ffi_double)op2->u64; \
- } else if (op2->kind == ZEND_FFI_VAL_INT32 ||op2->kind == ZEND_FFI_VAL_INT64) { \
- val->kind = ZEND_FFI_VAL_INT32; \
- val->i64 = val->d OP (zend_ffi_double)op2->i64; \
- } else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
- val->kind = ZEND_FFI_VAL_INT32; \
- val->i64 = val->d OP op2->d; \
- } else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
- val->kind = ZEND_FFI_VAL_INT32; \
- val->i64 = val->d OP (zend_ffi_double)op2->ch; \
- } else { \
- val->kind = ZEND_FFI_VAL_ERROR; \
- } \
- } else if (val->kind == ZEND_FFI_VAL_CHAR) { \
- if (op2->kind == ZEND_FFI_VAL_UINT32 || op2->kind == ZEND_FFI_VAL_UINT64) { \
- val->kind = ZEND_FFI_VAL_INT32; \
- val->i64 = val->ch OP op2->i64; /* signed/unsigned */ \
- } else if (op2->kind == ZEND_FFI_VAL_INT32 || op2->kind == ZEND_FFI_VAL_INT64) { \
- val->kind = ZEND_FFI_VAL_INT32; \
- val->i64 = val->ch OP op2->i64; \
- } else if (op2->kind == ZEND_FFI_VAL_FLOAT || op2->kind == ZEND_FFI_VAL_DOUBLE || op2->kind == ZEND_FFI_VAL_LONG_DOUBLE) { \
- val->kind = ZEND_FFI_VAL_INT32; \
- val->i64 = (zend_ffi_double)val->ch OP op2->d; \
- } else if (op2->kind == ZEND_FFI_VAL_CHAR) { \
- val->kind = ZEND_FFI_VAL_INT32; \
- val->i64 = val->ch OP op2->ch; \
- } else { \
- val->kind = ZEND_FFI_VAL_ERROR; \
- } \
- } else { \
- val->kind = ZEND_FFI_VAL_ERROR; \
- } \
- } while (0)
- void zend_ffi_expr_conditional(zend_ffi_val *val, zend_ffi_val *op2, zend_ffi_val *op3) /* {{{ */
- {
- zend_ffi_expr_bool(val);
- if (val->kind == ZEND_FFI_VAL_INT32) {
- if (val->i64) {
- *val = *op2;
- } else {
- *val = *op3;
- }
- }
- }
- /* }}} */
- void zend_ffi_expr_bool_or(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
- {
- zend_ffi_expr_bool(val);
- zend_ffi_expr_bool(op2);
- if (val->kind == ZEND_FFI_VAL_INT32 && op2->kind == ZEND_FFI_VAL_INT32) {
- val->i64 = val->i64 || op2->i64;
- } else {
- val->kind = ZEND_FFI_VAL_ERROR;
- }
- }
- /* }}} */
- void zend_ffi_expr_bool_and(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
- {
- zend_ffi_expr_bool(val);
- zend_ffi_expr_bool(op2);
- if (val->kind == ZEND_FFI_VAL_INT32 && op2->kind == ZEND_FFI_VAL_INT32) {
- val->i64 = val->i64 && op2->i64;
- } else {
- val->kind = ZEND_FFI_VAL_ERROR;
- }
- }
- /* }}} */
- void zend_ffi_expr_bw_or(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
- {
- zend_ffi_expr_int_math(val, op2, |);
- }
- /* }}} */
- void zend_ffi_expr_bw_xor(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
- {
- zend_ffi_expr_int_math(val, op2, ^);
- }
- /* }}} */
- void zend_ffi_expr_bw_and(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
- {
- zend_ffi_expr_int_math(val, op2, &);
- }
- /* }}} */
- void zend_ffi_expr_is_equal(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
- {
- zend_ffi_expr_cmp(val, op2, ==);
- }
- /* }}} */
- void zend_ffi_expr_is_not_equal(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
- {
- zend_ffi_expr_cmp(val, op2, !=);
- }
- /* }}} */
- void zend_ffi_expr_is_less(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
- {
- zend_ffi_expr_cmp(val, op2, <);
- }
- /* }}} */
- void zend_ffi_expr_is_greater(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
- {
- zend_ffi_expr_cmp(val, op2, >);
- }
- /* }}} */
- void zend_ffi_expr_is_less_or_equal(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
- {
- zend_ffi_expr_cmp(val, op2, <=);
- }
- /* }}} */
- void zend_ffi_expr_is_greater_or_equal(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
- {
- zend_ffi_expr_cmp(val, op2, >=);
- }
- /* }}} */
- void zend_ffi_expr_shift_left(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
- {
- zend_ffi_expr_int_math(val, op2, <<);
- }
- /* }}} */
- void zend_ffi_expr_shift_right(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
- {
- zend_ffi_expr_int_math(val, op2, >>);
- }
- /* }}} */
- void zend_ffi_expr_add(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
- {
- zend_ffi_expr_math(val, op2, +);
- }
- /* }}} */
- void zend_ffi_expr_sub(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
- {
- zend_ffi_expr_math(val, op2, -);
- }
- /* }}} */
- void zend_ffi_expr_mul(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
- {
- zend_ffi_expr_math(val, op2, *);
- }
- /* }}} */
- void zend_ffi_expr_div(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
- {
- zend_ffi_expr_math(val, op2, /);
- }
- /* }}} */
- void zend_ffi_expr_mod(zend_ffi_val *val, zend_ffi_val *op2) /* {{{ */
- {
- zend_ffi_expr_int_math(val, op2, %); // ???
- }
- /* }}} */
- void zend_ffi_expr_cast(zend_ffi_val *val, zend_ffi_dcl *dcl) /* {{{ */
- {
- zend_ffi_finalize_type(dcl);
- switch (ZEND_FFI_TYPE(dcl->type)->kind) {
- case ZEND_FFI_TYPE_FLOAT:
- if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) {
- val->kind = ZEND_FFI_VAL_FLOAT;
- val->d = val->u64;
- } else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
- val->kind = ZEND_FFI_VAL_FLOAT;
- val->d = val->i64;
- } else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
- val->kind = ZEND_FFI_VAL_FLOAT;
- } else if (val->kind == ZEND_FFI_VAL_CHAR) {
- val->kind = ZEND_FFI_VAL_FLOAT;
- val->d = val->ch;
- } else {
- val->kind = ZEND_FFI_VAL_ERROR;
- }
- break;
- case ZEND_FFI_TYPE_DOUBLE:
- if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) {
- val->kind = ZEND_FFI_VAL_DOUBLE;
- val->d = val->u64;
- } else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
- val->kind = ZEND_FFI_VAL_DOUBLE;
- val->d = val->i64;
- } else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
- val->kind = ZEND_FFI_VAL_DOUBLE;
- } else if (val->kind == ZEND_FFI_VAL_CHAR) {
- val->kind = ZEND_FFI_VAL_DOUBLE;
- val->d = val->ch;
- } else {
- val->kind = ZEND_FFI_VAL_ERROR;
- }
- break;
- #ifdef HAVE_LONG_DOUBLE
- case ZEND_FFI_TYPE_LONGDOUBLE:
- if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) {
- val->kind = ZEND_FFI_VAL_LONG_DOUBLE;
- val->d = val->u64;
- } else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
- val->kind = ZEND_FFI_VAL_LONG_DOUBLE;
- val->d = val->i64;
- } else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
- val->kind = ZEND_FFI_VAL_LONG_DOUBLE;
- } else if (val->kind == ZEND_FFI_VAL_CHAR) {
- val->kind = ZEND_FFI_VAL_LONG_DOUBLE;
- val->d = val->ch;
- } else {
- val->kind = ZEND_FFI_VAL_ERROR;
- }
- break;
- #endif
- case ZEND_FFI_TYPE_UINT8:
- case ZEND_FFI_TYPE_UINT16:
- case ZEND_FFI_TYPE_UINT32:
- case ZEND_FFI_TYPE_BOOL:
- if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64 || val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
- val->kind = ZEND_FFI_VAL_UINT32;
- } else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
- val->kind = ZEND_FFI_VAL_UINT32;
- val->u64 = val->d;
- } else if (val->kind == ZEND_FFI_VAL_CHAR) {
- val->kind = ZEND_FFI_VAL_UINT32;
- val->u64 = val->ch;
- } else {
- val->kind = ZEND_FFI_VAL_ERROR;
- }
- break;
- case ZEND_FFI_TYPE_SINT8:
- case ZEND_FFI_TYPE_SINT16:
- case ZEND_FFI_TYPE_SINT32:
- if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64 || val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
- val->kind = ZEND_FFI_VAL_INT32;
- } else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
- val->kind = ZEND_FFI_VAL_INT32;
- val->i64 = val->d;
- } else if (val->kind == ZEND_FFI_VAL_CHAR) {
- val->kind = ZEND_FFI_VAL_INT32;
- val->i64 = val->ch;
- } else {
- val->kind = ZEND_FFI_VAL_ERROR;
- }
- break;
- case ZEND_FFI_TYPE_UINT64:
- if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64 || val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
- val->kind = ZEND_FFI_VAL_UINT64;
- } else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
- val->kind = ZEND_FFI_VAL_UINT64;
- val->u64 = val->d;
- } else if (val->kind == ZEND_FFI_VAL_CHAR) {
- val->kind = ZEND_FFI_VAL_UINT64;
- val->u64 = val->ch;
- } else {
- val->kind = ZEND_FFI_VAL_ERROR;
- }
- break;
- case ZEND_FFI_TYPE_SINT64:
- if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) {
- val->kind = ZEND_FFI_VAL_CHAR;
- val->ch = val->u64;
- } else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
- val->kind = ZEND_FFI_VAL_CHAR;
- val->ch = val->i64;
- } else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
- val->kind = ZEND_FFI_VAL_CHAR;
- val->ch = val->d;
- } else if (val->kind == ZEND_FFI_VAL_CHAR) {
- } else {
- val->kind = ZEND_FFI_VAL_ERROR;
- }
- break;
- case ZEND_FFI_TYPE_CHAR:
- if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64 || val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
- val->kind = ZEND_FFI_VAL_UINT32;
- } else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
- val->kind = ZEND_FFI_VAL_UINT32;
- val->u64 = val->d;
- } else if (val->kind == ZEND_FFI_VAL_CHAR) {
- val->kind = ZEND_FFI_VAL_UINT32;
- val->u64 = val->ch;
- } else {
- val->kind = ZEND_FFI_VAL_ERROR;
- }
- break;
- default:
- val->kind = ZEND_FFI_VAL_ERROR;
- break;
- }
- zend_ffi_type_dtor(dcl->type);
- }
- /* }}} */
- void zend_ffi_expr_plus(zend_ffi_val *val) /* {{{ */
- {
- if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) {
- } else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
- } else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
- } else if (val->kind == ZEND_FFI_VAL_CHAR) {
- } else {
- val->kind = ZEND_FFI_VAL_ERROR;
- }
- }
- /* }}} */
- void zend_ffi_expr_neg(zend_ffi_val *val) /* {{{ */
- {
- if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) {
- val->u64 = -val->u64;
- } else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
- val->i64 = -val->i64;
- } else if (val->kind == ZEND_FFI_VAL_FLOAT || val->kind == ZEND_FFI_VAL_DOUBLE || val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
- val->d = -val->d;
- } else if (val->kind == ZEND_FFI_VAL_CHAR) {
- val->ch = -val->ch;
- } else {
- val->kind = ZEND_FFI_VAL_ERROR;
- }
- }
- /* }}} */
- void zend_ffi_expr_bw_not(zend_ffi_val *val) /* {{{ */
- {
- if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_UINT64) {
- val->u64 = ~val->u64;
- } else if (val->kind == ZEND_FFI_VAL_INT32 || val->kind == ZEND_FFI_VAL_INT64) {
- val->i64 = ~val->i64;
- } else if (val->kind == ZEND_FFI_VAL_CHAR) {
- val->ch = ~val->ch;
- } else {
- val->kind = ZEND_FFI_VAL_ERROR;
- }
- }
- /* }}} */
- void zend_ffi_expr_bool_not(zend_ffi_val *val) /* {{{ */
- {
- zend_ffi_expr_bool(val);
- if (val->kind == ZEND_FFI_VAL_INT32) {
- val->i64 = !val->i64;
- }
- }
- /* }}} */
- void zend_ffi_expr_sizeof_val(zend_ffi_val *val) /* {{{ */
- {
- if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_INT32) {
- val->kind = ZEND_FFI_VAL_UINT32;
- val->u64 = zend_ffi_type_uint32.size;
- } else if (val->kind == ZEND_FFI_VAL_UINT64 || val->kind == ZEND_FFI_VAL_INT64) {
- val->kind = ZEND_FFI_VAL_UINT32;
- val->u64 = zend_ffi_type_uint64.size;
- } else if (val->kind == ZEND_FFI_VAL_FLOAT) {
- val->kind = ZEND_FFI_VAL_UINT32;
- val->u64 = zend_ffi_type_float.size;
- } else if (val->kind == ZEND_FFI_VAL_DOUBLE) {
- val->kind = ZEND_FFI_VAL_UINT32;
- val->u64 = zend_ffi_type_double.size;
- } else if (val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
- val->kind = ZEND_FFI_VAL_UINT32;
- #ifdef _WIN32
- val->u64 = zend_ffi_type_double.size;
- #else
- val->u64 = zend_ffi_type_long_double.size;
- #endif
- } else if (val->kind == ZEND_FFI_VAL_CHAR) {
- val->kind = ZEND_FFI_VAL_UINT32;
- val->u64 = zend_ffi_type_char.size;
- } else if (val->kind == ZEND_FFI_VAL_STRING) {
- if (memchr(val->str, '\\', val->len)) {
- // TODO: support for escape sequences ???
- val->kind = ZEND_FFI_VAL_ERROR;
- } else {
- val->kind = ZEND_FFI_VAL_UINT32;
- val->u64 = val->len + 1;
- }
- } else {
- val->kind = ZEND_FFI_VAL_ERROR;
- }
- }
- /* }}} */
- void zend_ffi_expr_sizeof_type(zend_ffi_val *val, zend_ffi_dcl *dcl) /* {{{ */
- {
- zend_ffi_type *type;
- zend_ffi_finalize_type(dcl);
- type = ZEND_FFI_TYPE(dcl->type);
- val->kind = (type->size > 0xffffffff) ? ZEND_FFI_VAL_UINT64 : ZEND_FFI_VAL_UINT32;
- val->u64 = type->size;
- zend_ffi_type_dtor(dcl->type);
- }
- /* }}} */
- void zend_ffi_expr_alignof_val(zend_ffi_val *val) /* {{{ */
- {
- if (val->kind == ZEND_FFI_VAL_UINT32 || val->kind == ZEND_FFI_VAL_INT32) {
- val->kind = ZEND_FFI_VAL_UINT32;
- val->u64 = zend_ffi_type_uint32.align;
- } else if (val->kind == ZEND_FFI_VAL_UINT64 || val->kind == ZEND_FFI_VAL_INT64) {
- val->kind = ZEND_FFI_VAL_UINT32;
- val->u64 = zend_ffi_type_uint64.align;
- } else if (val->kind == ZEND_FFI_VAL_FLOAT) {
- val->kind = ZEND_FFI_VAL_UINT32;
- val->u64 = zend_ffi_type_float.align;
- } else if (val->kind == ZEND_FFI_VAL_DOUBLE) {
- val->kind = ZEND_FFI_VAL_UINT32;
- val->u64 = zend_ffi_type_double.align;
- #ifdef HAVE_LONG_DOUBLE
- } else if (val->kind == ZEND_FFI_VAL_LONG_DOUBLE) {
- val->kind = ZEND_FFI_VAL_UINT32;
- val->u64 = zend_ffi_type_long_double.align;
- #endif
- } else if (val->kind == ZEND_FFI_VAL_CHAR) {
- val->kind = ZEND_FFI_VAL_UINT32;
- val->u64 = zend_ffi_type_char.size;
- } else if (val->kind == ZEND_FFI_VAL_STRING) {
- val->kind = ZEND_FFI_VAL_UINT32;
- val->u64 = _Alignof(char*);
- } else {
- val->kind = ZEND_FFI_VAL_ERROR;
- }
- }
- /* }}} */
- void zend_ffi_expr_alignof_type(zend_ffi_val *val, zend_ffi_dcl *dcl) /* {{{ */
- {
- zend_ffi_finalize_type(dcl);
- val->kind = ZEND_FFI_VAL_UINT32;
- val->u64 = ZEND_FFI_TYPE(dcl->type)->align;
- zend_ffi_type_dtor(dcl->type);
- }
- /* }}} */
- void zend_ffi_val_number(zend_ffi_val *val, int base, const char *str, size_t str_len) /* {{{ */
- {
- int u = 0;
- int l = 0;
- if (str[str_len-1] == 'u' || str[str_len-1] == 'U') {
- u = 1;
- if (str[str_len-2] == 'l' || str[str_len-2] == 'L') {
- l = 1;
- if (str[str_len-3] == 'l' || str[str_len-3] == 'L') {
- l = 2;
- }
- }
- } else if (str[str_len-1] == 'l' || str[str_len-1] == 'L') {
- l = 1;
- if (str[str_len-2] == 'l' || str[str_len-2] == 'L') {
- l = 2;
- if (str[str_len-3] == 'u' || str[str_len-3] == 'U') {
- u = 1;
- }
- } else if (str[str_len-2] == 'u' || str[str_len-2] == 'U') {
- u = 1;
- }
- }
- if (u) {
- val->u64 = strtoull(str, NULL, base);
- if (l == 0) {
- val->kind = ZEND_FFI_VAL_UINT32;
- } else if (l == 1) {
- val->kind = (sizeof(long) == 4) ? ZEND_FFI_VAL_UINT32 : ZEND_FFI_VAL_UINT64;
- } else if (l == 2) {
- val->kind = ZEND_FFI_VAL_UINT64;
- }
- } else {
- val->i64 = strtoll(str, NULL, base);
- if (l == 0) {
- val->kind = ZEND_FFI_VAL_INT32;
- } else if (l == 1) {
- val->kind = (sizeof(long) == 4) ? ZEND_FFI_VAL_INT32 : ZEND_FFI_VAL_INT64;
- } else if (l == 2) {
- val->kind = ZEND_FFI_VAL_INT64;
- }
- }
- }
- /* }}} */
- void zend_ffi_val_float_number(zend_ffi_val *val, const char *str, size_t str_len) /* {{{ */
- {
- val->d = strtold(str, NULL);
- if (str[str_len-1] == 'f' || str[str_len-1] == 'F') {
- val->kind = ZEND_FFI_VAL_FLOAT;
- } else if (str[str_len-1] == 'l' || str[str_len-1] == 'L') {
- val->kind = ZEND_FFI_VAL_LONG_DOUBLE;
- } else {
- val->kind = ZEND_FFI_VAL_DOUBLE;
- }
- }
- /* }}} */
- void zend_ffi_val_string(zend_ffi_val *val, const char *str, size_t str_len) /* {{{ */
- {
- if (str[0] != '\"') {
- val->kind = ZEND_FFI_VAL_ERROR;
- } else {
- val->kind = ZEND_FFI_VAL_STRING;
- val->str = str + 1;
- val->len = str_len - 2;
- }
- }
- /* }}} */
- void zend_ffi_val_character(zend_ffi_val *val, const char *str, size_t str_len) /* {{{ */
- {
- int n;
- if (str[0] != '\'') {
- val->kind = ZEND_FFI_VAL_ERROR;
- } else {
- val->kind = ZEND_FFI_VAL_CHAR;
- if (str_len == 3) {
- val->ch = str[1];
- } else if (str[1] == '\\') {
- if (str[2] == 'a') {
- } else if (str[2] == 'b' && str_len == 4) {
- val->ch = '\b';
- } else if (str[2] == 'f' && str_len == 4) {
- val->ch = '\f';
- } else if (str[2] == 'n' && str_len == 4) {
- val->ch = '\n';
- } else if (str[2] == 'r' && str_len == 4) {
- val->ch = '\r';
- } else if (str[2] == 't' && str_len == 4) {
- val->ch = '\t';
- } else if (str[2] == 'v' && str_len == 4) {
- val->ch = '\v';
- } else if (str[2] >= '0' && str[2] <= '7') {
- n = str[2] - '0';
- if (str[3] >= '0' && str[3] <= '7') {
- n = n * 8 + (str[3] - '0');
- if ((str[4] >= '0' && str[4] <= '7') && str_len == 6) {
- n = n * 8 + (str[4] - '0');
- } else if (str_len != 5) {
- val->kind = ZEND_FFI_VAL_ERROR;
- }
- } else if (str_len != 4) {
- val->kind = ZEND_FFI_VAL_ERROR;
- }
- if (n <= 0xff) {
- val->ch = n;
- } else {
- val->kind = ZEND_FFI_VAL_ERROR;
- }
- } else if (str[2] == 'x') {
- if (str[3] >= '0' && str[3] <= '9') {
- n = str[3] - '0';
- } else if (str[3] >= 'A' && str[3] <= 'F') {
- n = str[3] - 'A';
- } else if (str[3] >= 'a' && str[3] <= 'f') {
- n = str[3] - 'a';
- } else {
- val->kind = ZEND_FFI_VAL_ERROR;
- return;
- }
- if ((str[4] >= '0' && str[4] <= '9') && str_len == 6) {
- n = n * 16 + (str[4] - '0');
- } else if ((str[4] >= 'A' && str[4] <= 'F') && str_len == 6) {
- n = n * 16 + (str[4] - 'A');
- } else if ((str[4] >= 'a' && str[4] <= 'f') && str_len == 6) {
- n = n * 16 + (str[4] - 'a');
- } else if (str_len != 5) {
- val->kind = ZEND_FFI_VAL_ERROR;
- return;
- }
- val->ch = n;
- } else if (str_len == 4) {
- val->ch = str[2];
- } else {
- val->kind = ZEND_FFI_VAL_ERROR;
- }
- } else {
- val->kind = ZEND_FFI_VAL_ERROR;
- }
- }
- }
- /* }}} */
|