[php-src] Issue #24235: DateTime::createFromFormat() segfaults when "!" follows a parsed time zone and the passed zone is an abbreviation or offset
| From: | zonuexe | Date: | Sat, 10 Oct 2026 08:07:06 +0000 |
| Subject: | [php-src] Issue #24235: DateTime::createFromFormat() segfaults when "!" follows a parsed time zone and the passed zone is an abbreviation or offset | ||
| Groups: | php.bugs | ||
| Request: | Send a blank email to php-bugs+get-252964@lists.php.net to get a copy of this message | ||
Issue: https://github.com/php/php-src/issues/24235
Author: zonuexe
### Description
The following code:
```php
<?php
date_default_timezone_set('Europe/London');
var_dump(DateTime::createFromFormat('e !Y-m-d H:i', 'Europe/London 2024-10-27
01:30', new DateTimeZone('EST')));
```
Resulted in this output:
```
Segmentation fault (exit status 139)
```
But I expected this output instead:
```
object(DateTime)#2 (3) {
["date"]=>
string(26) "2024-10-27 01:30:00.000000"
["timezone_type"]=>
int(2)
["timezone"]=>
string(3) "EST"
}
```
The input is valid and matches the format. It is not malformed input that the parser fails to
reject. Invalid input is handled correctly, and the same input works in every other combination:
| Call | Result |
| --- | --- |
|
createFromFormat('e !Y-m-d H:i', 'Nowhere/Invalid 2024-10-27 01:30', new
DateTimeZone('EST')) | false |
| createFromFormat('e !Y-m-d H:i', 'Europe/London 2024-10-27
01:30') | works |
| createFromFormat('e !Y-m-d H:i', 'Europe/London 2024-10-27 01:30', new
DateTimeZone('UTC')) | works |
| createFromFormat('!Y-m-d H:i', '2024-10-27 01:30', new
DateTimeZone('EST')) | works |
| createFromFormat('e !Y-m-d H:i', 'Europe/London 2024-10-27 01:30', new
DateTimeZone('EST')) | **segfault** |
The crash needs all three of these together:
- a zone parsed from the string;
- a later ! (or a trailing !, as in 'Y-m-d H:i
e!');
- a passed or default zone that is an abbreviation (EST) or an offset
(+01:00) rather than an identifier.
DateTimeImmutable::createFromFormat() and date_create_from_format() crash
the same way.
The cause is in timelib's timelib_time_reset_fields(), which runs for
!. It clears tz_info but keeps the zone type of the zone parsed before it.
When the fallback zone is not an identifier, nothing refills tz_info. The result is an
identifier-type zone with a NULL tz_info, which date_format() dereferences
in timelib_fetch_timezone_offset().
### PHP Version
```
PHP 8.5.11 (cli) (built: Sep 22 2026 13:32:06) (NTS)
Copyright (c) The PHP Group
Built by Homebrew
Zend Engine v4.5.11, Copyright (c) Zend Technologies
with Zend OPcache v8.5.11, Copyright (c), by Zend Technologies
```
Also reproduced on PHP 8.4.25 and on debug builds of PHP-8.4 and master.
### Operating System
macOS (arm64); not platform specific