@@ -58,96 +58,103 @@ static void *find_prefered_mmap_base(size_t requested_size)
5858#if defined(__linux__ )
5959 FILE * f ;
6060 char buffer [MAXPATHLEN ];
61-
61+
6262 f = fopen ("/proc/self/maps" , "r" );
6363 if (!f ) {
6464 return MAP_FAILED ;
6565 }
6666
67- while (fgets (buffer , MAXPATHLEN , f ) && sscanf (buffer , "%lx-%lx" , & start , & end ) == 2 ) {
68- if ((uintptr_t )execute_ex >= start ) {
69- /* the current segment lays before PHP .text segment or PHP .text segment itself */
70- if (last_free_addr + requested_size <= start ) {
71- last_candidate = last_free_addr ;
72- }
73- if ((uintptr_t )execute_ex < end ) {
74- /* the current segment is PHP .text segment itself */
75- if (last_candidate != (uintptr_t )MAP_FAILED ) {
76- if (end - last_candidate < UINT32_MAX ) {
77- /* we have found a big enough hole before the text segment */
78- break ;
79- }
80- last_candidate = (uintptr_t )MAP_FAILED ;
67+ while (fgets (buffer , MAXPATHLEN , f ) && sscanf (buffer , "%lx-%lx" , & start , & end ) == 2 ) {
68+ if ((uintptr_t )execute_ex >= start ) {
69+ /* the current segment lays before PHP .text segment or PHP .text segment itself */
70+ /*Search for candidates at the end of the free segment near the .text segment
71+ to prevent candidates from being missed due to large hole*/
72+ if (last_free_addr + requested_size <= start ) {
73+ last_candidate = ZEND_MM_ALIGNED_SIZE_EX (start - requested_size , huge_page_size );
74+ if (last_candidate + requested_size > start ) {
75+ last_candidate -= huge_page_size ;
8176 }
82- text_start = start ;
83- }
84- } else {
85- /* the current segment lays after PHP .text segment */
86- if (last_free_addr + requested_size - text_start > UINT32_MAX ) {
87- /* the current segment and the following segments lay too far from PHP .text segment */
88- break ;
89- }
90- if (last_free_addr + requested_size <= start ) {
91- last_candidate = last_free_addr ;
92- break ;
93- }
94- }
95- last_free_addr = ZEND_MM_ALIGNED_SIZE_EX (end , huge_page_size );
96-
77+ }
78+ if ((uintptr_t )execute_ex < end ) {
79+ /* the current segment is PHP .text segment itself */
80+ if (last_candidate != (uintptr_t )MAP_FAILED ) {
81+ if (end - last_candidate < UINT32_MAX ) {
82+ /* we have found a big enough hole before the .text segment */
83+ break ;
84+ }
85+ last_candidate = (uintptr_t )MAP_FAILED ;
86+ }
87+ text_start = start ;
88+ }
89+ } else {
90+ /* the current segment lays after PHP .text segment */
91+ if (last_free_addr + requested_size - text_start > UINT32_MAX ) {
92+ /* the current segment and the following segments lay too far from PHP .text segment */
93+ break ;
94+ }
95+ if (last_free_addr + requested_size <= start ) {
96+ last_candidate = last_free_addr ;
97+ break ;
98+ }
99+ }
100+ last_free_addr = ZEND_MM_ALIGNED_SIZE_EX (end , huge_page_size );
97101 }
98102 fclose (f );
99103#elif defined(__FreeBSD__ )
100- size_t s = 0 ;
101- int mib [4 ] = {CTL_KERN , KERN_PROC , KERN_PROC_VMMAP , getpid ()};
102- if (sysctl (mib , 4 , NULL , & s , NULL , 0 ) == 0 ) {
103- s = s * 4 / 3 ;
104- void * addr = mmap (NULL , s , PROT_READ | PROT_WRITE , MAP_SHARED | MAP_ANON , -1 , 0 );
105- if (addr != MAP_FAILED ) {
106- if (sysctl (mib , 4 , addr , & s , NULL , 0 ) == 0 ) {
107- start = (uintptr_t )addr ;
108- end = start + s ;
109- while (start < end ) {
110- struct kinfo_vmentry * entry = (struct kinfo_vmentry * )start ;
111- size_t sz = entry -> kve_structsize ;
112- if (sz == 0 ) {
113- break ;
114- }
115- uintptr_t e_start = entry -> kve_start ;
116- uintptr_t e_end = entry -> kve_end ;
117- if ((uintptr_t )execute_ex >= e_start ) {
118- /* the current segment lays before PHP .text segment or PHP .text segment itself */
119- if (last_free_addr + requested_size <= e_start ) {
120- last_candidate = last_free_addr ;
121- }
122- if ((uintptr_t )execute_ex < e_end ) {
123- /* the current segment is PHP .text segment itself */
124- if (last_candidate != (uintptr_t )MAP_FAILED ) {
125- if (e_end - last_candidate < UINT32_MAX ) {
126- /* we have found a big enough hole before the text segment */
127- break ;
128- }
129- last_candidate = (uintptr_t )MAP_FAILED ;
104+ size_t s = 0 ;
105+ int mib [4 ] = {CTL_KERN , KERN_PROC , KERN_PROC_VMMAP , getpid ()};
106+ if (sysctl (mib , 4 , NULL , & s , NULL , 0 ) == 0 ) {
107+ s = s * 4 / 3 ;
108+ void * addr = mmap (NULL , s , PROT_READ | PROT_WRITE , MAP_SHARED | MAP_ANON , -1 , 0 );
109+ if (addr != MAP_FAILED ) {
110+ if (sysctl (mib , 4 , addr , & s , NULL , 0 ) == 0 ) {
111+ start = (uintptr_t )addr ;
112+ end = start + s ;
113+ while (start < end ) {
114+ struct kinfo_vmentry * entry = (struct kinfo_vmentry * )start ;
115+ size_t sz = entry -> kve_structsize ;
116+ if (sz == 0 ) {
117+ break ;
118+ }
119+ uintptr_t e_start = entry -> kve_start ;
120+ uintptr_t e_end = entry -> kve_end ;
121+ if ((uintptr_t )execute_ex >= e_start ) {
122+ /* the current segment lays before PHP .text segment or PHP .text segment itself */
123+ if (last_free_addr + requested_size <= e_start ) {
124+ last_candidate = ZEND_MM_ALIGNED_SIZE_EX (e_start - requested_size , huge_page_size );
125+ if (last_candidate + requested_size > e_start ) {
126+ last_candidate -= huge_page_size ;
130127 }
131- text_start = e_start ;
132- }
133- } else {
134- /* the current segment lays after PHP .text segment */
135- if (last_free_addr + requested_size - text_start > UINT32_MAX ) {
136- /* the current segment and the following segments lay too far from PHP .text segment */
137- break ;
138- }
139- if (last_free_addr + requested_size <= e_start ) {
140- last_candidate = last_free_addr ;
141- break ;
142- }
143- }
144- last_free_addr = ZEND_MM_ALIGNED_SIZE_EX (e_end , huge_page_size );
145- start += sz ;
146- }
147- }
148- munmap (addr , s );
149- }
150- }
128+ }
129+ if ((uintptr_t )execute_ex < e_end ) {
130+ /* the current segment is PHP .text segment itself */
131+ if (last_candidate != (uintptr_t )MAP_FAILED ) {
132+ if (e_end - last_candidate < UINT32_MAX ) {
133+ /* we have found a big enough hole before the text segment */
134+ break ;
135+ }
136+ last_candidate = (uintptr_t )MAP_FAILED ;
137+ }
138+ text_start = e_start ;
139+ }
140+ } else {
141+ /* the current segment lays after PHP .text segment */
142+ if (last_free_addr + requested_size - text_start > UINT32_MAX ) {
143+ /* the current segment and the following segments lay too far from PHP .text segment */
144+ break ;
145+ }
146+ if (last_free_addr + requested_size <= e_start ) {
147+ last_candidate = last_free_addr ;
148+ break ;
149+ }
150+ }
151+ last_free_addr = ZEND_MM_ALIGNED_SIZE_EX (e_end , huge_page_size );
152+ start += sz ;
153+ }
154+ }
155+ munmap (addr , s );
156+ }
157+ }
151158#endif
152159
153160 return (void * )last_candidate ;
0 commit comments