Bug #76107 [Opn]: SplFileInfo returns incorrect information on large file in 32bit architecture

From: 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

« previous php.bugs (#226621) next »