Bug #76107 [Opn]: SplFileInfo returns incorrect information on large file in 32bit architecture
| From: | VeryCrazyDog at gmail dot com | Date: | Thu, 16 Apr 2020 14:34:20 +0000 |
| Subject: | Bug #76107 [Opn]: SplFileInfo returns incorrect information on large file in 32bit architecture | ||
| References: | 1 | Groups: | php.bugs |
| Request: | Send a blank email to php-bugs+get-226621@lists.php.net to get a copy of this message | ||
Edit report at https://bugs.php.net/bug.php?id=76107&edit=1
ID: 76107
User updated by: VeryCrazyDog at gmail dot com
Reported by: VeryCrazyDog at gmail dot com
Summary: SplFileInfo returns incorrect information on large
file in 32bit architecture
Status: Open
Type: Bug
Package: SPL related
Operating System: Arch Linux ARMv7
PHP Version: 7.2.3
Block user comment: N
Private report: N
New Comment:
I tested using your source code, indeed yes, EOVERFLOW returned without result. Agreed that nothing
can be done here. Shall I close this bug or shall I leave it open for improving the error message?
A side question, since "stat" Linux command works, there should have a way to get the file
info (such as modified date), but I can imagine the change will be huge which may not be justify to
do, right?
Output:
------------
result: -1, errno: 75, EOVERFLOW: 75
File type: regular file
I-node number: 1697634
Mode: 100644 (octal)
Link count: 1
Ownership: UID=1000 GID=100
Preferred I/O block size: 0 bytes
File size: -1573452886 bytes
Blocks allocated: 0
Last status change: Thu Jan 1 08:00:00 1970
Last file access: Thu Jan 1 08:00:00 1970
Last file modification: Thu Jan 1 08:00:00 1970
------------
Source code:
------------
#include <stdio.h>
#include <sys/stat.h>
#include <errno.h>
#include <time.h>
int main()
{
struct stat sb = {0};
int res = stat("/home/vcd/tmp/LARGE_FILE", &sb);
printf("result: %d, errno: %d, EOVERFLOW: %d\n\n", res, errno, EOVERFLOW);
printf("File type: ");
switch (sb.st_mode & S_IFMT) {
case S_IFBLK: printf("block device\n"); break;
case S_IFCHR: printf("character device\n"); break;
case S_IFDIR: printf("directory\n"); break;
case S_IFIFO: printf("FIFO/pipe\n"); break;
case S_IFLNK: printf("symlink\n"); break;
case S_IFREG: printf("regular file\n"); break;
case S_IFSOCK: printf("socket\n"); break;
default: printf("unknown?\n"); break;
}
printf("I-node number: %ld\n", (long) sb.st_ino);
printf("Mode: %lo (octal)\n", (unsigned long) sb.st_mode);
printf("Link count: %ld\n", (long) sb.st_nlink);
printf("Ownership: UID=%ld GID=%ld\n", (long) sb.st_uid, (long)
sb.st_gid);
printf("Preferred I/O block size: %ld bytes\n", (long) sb.st_blksize);
printf("File size: %lld bytes\n", (long long) sb.st_size);
printf("Blocks allocated: %lld\n", (long long) sb.st_blocks);
printf("Last status change: %s", ctime(&sb.st_ctime));
printf("Last file access: %s", ctime(&sb.st_atime));
printf("Last file modification: %s", ctime(&sb.st_mtime));
return 0;
}
------------
Previous Comments:
------------------------------------------------------------------------
[2020-04-16 13:55:34] cmb@php.net
You can try something like the following (untested):
#include <stdio.h>
#include <sys/stat.h>
int main()
{
struct stat ssb;
int res = stat("/path/to/large/file", &ssb);
printf("result: %d, errno: %d, EOVERFLOW: %d", res, errno, EOVERFLOW);
return 0;
}
I assume that will show that errno is EOVERFLOW.
Anyhow, I don't think we can really fix this, since the stat()
call is important, and if it fails there's not much we can do,
besides giving a better error message.
------------------------------------------------------------------------
[2020-04-16 12:29:13] VeryCrazyDog at gmail dot com
I tried to run the following C program, but no error occurred, maybe the error is throw somewhere
else?
---------------
#include <stdio.h>
#include <stdint.h>
typedef int32_t zend_long;
int main (void) {
zend_long l = 2147483647;
// Print: long: 2147483647
printf("long: %d\n", l);
l++;
// Print: long: -2147483648
printf("long: %d\n", l);
long long int ll = 2721514410;
// Print: long long: 2721514410
printf("long long: %lld\n", ll);
l = (zend_long)ll;
// Print: long: -1573452886
printf("long: %d\n", l);
return 0;
}
---------------
I am now running PHP 7.4.3 and the same result and same error occurred. Besides a more descriptive
error message, is that possible to give correct output when isFile() and getMTime() are called?
------------------------------------------------------------------------
[2020-04-15 17:00:04] cmb@php.net
Presumably, stat() fails with EOVERFLOW here, what could at least
trigger a more descriptive error message.
Interestingly, the given script mostly works on Windows x86,
albeit the reported size is wrong due to overflow[1].
[1] <https://github.com/php/php-src/blob/php-7.3.17/Zend/zend_virtual_cwd.c#L352-L355>
------------------------------------------------------------------------
[2018-03-17 06:45:44] VeryCrazyDog at gmail dot com
Description:
------------
When calling SplFileInfo::isFile() on a large file, false is returned instead of true.
When calling SplFileInfo::getMTime() and SplFileInfo::getSize() on a large file, RuntimeException is
throw.
This problem does not happens on Windows 7 64bit running same PHP version. It seems that it is
related the maximum value of int, because the file size which I used in the test is
"2939977728" which cannot be fit in 32bit OS.
Although it may not be possible to report the file size, it is expected at least, isFile() and
getMTime() should return the correct result.
Test script:
---------------
<?php
$info = new SplFileInfo('/path/to/large_file');
var_dump($info);
var_dump($info->isFile()); // This returns false
var_dump($info->isReadable());
var_dump($info->getMTime()); // This throws RuntimeException
var_dump($info->getSize()); // This throws RuntimeException
if ($info->isFile()) {
echo $info->getRealPath();
}
Expected result:
----------------
vcd@server ~$ php -f test.php
object(SplFileInfo)#1 (2) {
["pathName":"SplFileInfo":private]=>
string(24) "/home/vcd/tmp/large_file"
["fileName":"SplFileInfo":private]=>
string(10) "large_file"
}
bool(true)
bool(true)
int(1515414305)
bool(false)
/home/vcd/tmp/large_file
Actual result:
--------------
vcd@server ~$ php -f test.php
object(SplFileInfo)#1 (2) {
["pathName":"SplFileInfo":private]=>
string(24) "/home/vcd/tmp/large_file"
["fileName":"SplFileInfo":private]=>
string(10) "large_file"
}
bool(false)
bool(true)
PHP Fatal error: Uncaught RuntimeException: SplFileInfo::getMTime(): stat failed for
/home/vcd/tmp/large_file in /home/vcd/test.php:6
Stack trace:
#0 /home/vcd/test.php(6): SplFileInfo->getMTime()
#1 {main}
thrown in /home/vcd/test.php on line 6
------------------------------------------------------------------------
--
Edit this bug report at https://bugs.php.net/bug.php?id=76107&edit=1