Skip to content

Commit da6097f

Browse files
committedSep 20, 2023
Fix GH-12215: Module entry being overwritten causes type errors in ext/dom (<= PHP 8.3)
When we try to load an extension multiple times, we still overwrite the type, module number, and handle. If the module number is used to indicate module boundaries (e.g. in reflection and in dom, see e.g. dom_objects_set_class_ex), then all sorts of error can happen. In the case of ext/dom, OP's error happens because the following happens: - The property handler is set up incorrectly in dom_objects_set_class_ex() because the wrong module number is specified. The class highest in the hierarchy is DOMNode, so the property handler is incorrectly set to that of DOMNode instead of DOMDocument. - The documentElement property doesn't exist on DOMNode, it only exists on DOMDocument, so it tries to read using zend_std_read_property(). As there is no user property called documentElement, that read operation returns an undef value. However, the type is still checked, resulting in the strange exception. Closes GH-12219.
1 parent 1a4e401 commit da6097f

File tree

2 files changed

+18
-1
lines changed

2 files changed

+18
-1
lines changed
 

‎NEWS

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ PHP NEWS
55
- Core:
66
. Fixed bug GH-12207 (memory leak when class using trait with doc block).
77
(rioderelfte)
8+
. Fixed bug GH-12215 (Module entry being overwritten causes type errors in
9+
ext/dom). (nielsdos)
810

911
- Filter:
1012
. Fix explicit FILTER_REQUIRE_SCALAR with FILTER_CALLBACK (ilutov)

‎ext/standard/dl.c

+16-1
Original file line numberDiff line numberDiff line change
@@ -225,15 +225,30 @@ PHPAPI int php_load_extension(const char *filename, int type, int start_now)
225225
DL_UNLOAD(handle);
226226
return FAILURE;
227227
}
228+
229+
int old_type = module_entry->type;
230+
int old_module_number = module_entry->module_number;
231+
void *old_handle = module_entry->handle;
232+
228233
module_entry->type = type;
229234
module_entry->module_number = zend_next_free_module();
230235
module_entry->handle = handle;
231236

232-
if ((module_entry = zend_register_module_ex(module_entry)) == NULL) {
237+
zend_module_entry *added_module_entry;
238+
if ((added_module_entry = zend_register_module_ex(module_entry)) == NULL) {
239+
/* Module loading failed, potentially because the module was already loaded.
240+
* It is especially important in that case to restore the old type, module_number, and handle.
241+
* Overwriting the values for an already-loaded module causes problem when these fields are used
242+
* to uniquely identify module boundaries (e.g. in dom and reflection). */
243+
module_entry->type = old_type;
244+
module_entry->module_number = old_module_number;
245+
module_entry->handle = old_handle;
233246
DL_UNLOAD(handle);
234247
return FAILURE;
235248
}
236249

250+
module_entry = added_module_entry;
251+
237252
if ((type == MODULE_TEMPORARY || start_now) && zend_startup_module_ex(module_entry) == FAILURE) {
238253
DL_UNLOAD(handle);
239254
return FAILURE;

0 commit comments

Comments
 (0)