Bug #908
strerror_r gives no error message back
100%
Description
I tried to open a file which doesn't exist, but exiv2 doesn't gave a proper error message.
Here is what I saw in the console:
"/windows/Users/[...]/IMG_1734.JPG: Failed to open the data source: (errno = 2) "
As you can see, there's nothing before the "(errno=2)" string. I debugged a bit and I saw that the execution goes from futils.cpp:104 (strerror_r(error, buf, n);) to :106 (os << buf;), but the buf is full of zeroes all the time.
System: openSUSE 12.3, GCC 4.7.2, x64.
Associated revisions
History
Updated by Robin Mills over 8 years ago
- Status changed from New to Assigned
- Assignee set to Robin Mills
- Target version set to 0.24
- % Done changed from 0 to 50
- Estimated time set to 2.00 h
Can you help me to understand this issue, please? I'm not convinced that this is an Exiv2 issue - as it concerns the library function strerror_r. I've run the following little test on Kubuntu 13.04
#include <error.h> #include <errno.h> #include <stdio.h> #include <string.h> int main(int argc,const char* argv[]) { const size_t n = 1024; char buf[n]; int e = 2; strerror_r(e,buf,n-1); printf("strerror_r e=%d,l=%lu,%s\n",e,strlen(buf),buf); strcpy(buf,strerror(e)); printf("strerror_r e=%d,l=%lu,%s\n",e,strlen(buf),buf); return 0; // unused argc; argv; }
And the output is:
842 rmills@rmills-ubuntu:~/temp $ ./foo strerror_r e=2,l=0, strerror_r e=2,l=25,No such file or directory
In your linux example, the filename has been reported. I've done something similar on Windows (and Kubuntu) and again the error and the filename have been reported.
I understand that you are expecting strerror_r to return a string, The man page says:
DESCRIPTION `strerror_r' converts the error number ERRNUM into a string and copies the result into the supplied BUFFER for a length up to N, including the NUL terminator. The value of ERRNUM is usually a copy of `errno'. If `errnum' is not a known error number, the result is the empty string.
I agree that it is strange that strerror_r returns an empty string when errno=2(ENOENT in ./include/asm-generic/errno-base.h) and strerror reports in a reasonable manner.
C:\Users\rmills\Downloads>exiv2 ..\Pictures\SummerTrip\RockyMountainNP\IMG_2167.jpg File name : ..\Pictures\SummerTrip\RockyMountainNP\IMG_2167.jpg File size : 4287016 Bytes MIME type : image/jpeg Image size : 3264 x 2448 Camera make : Canon Camera model : Canon PowerShot S5 IS Image timestamp : 2013:06:17 10:00:20 Image number : 104-2167 Exposure time : 1/500 s Aperture : F4 Exposure bias : 0 EV Flash : No, compulsory Flash bias : 0 EV Focal length : 9.7 mm Subject distance: 2358 ISO speed : 80 Exposure mode : Easy shooting (Auto) Metering mode : Multi-segment Macro mode : Off Image quality : Superfine Exif Resolution : 3264 x 2448 White balance : Auto Thumbnail : image/jpeg, 5369 Bytes Copyright : Exif comment : C:\Users\rmills\Downloads>exiv2 ..\Pictures\SummerTrip\RockyMountainNP\IMG_2167.jpgxx ..\Pictures\SummerTrip\RockyMountainNP\IMG_2167.jpgxx: Failed to open the file C:\Users\rmills\Downloads>
Updated by Ákos Szőts over 8 years ago
For me the example runs great, producing the same output.
The problem is with the API. Here is the strError() implementation from futils.cpp:
std::string strError()
{
int error = errno;
std::ostringstream os;
#ifdef EXV_HAVE_STRERROR_R
const size_t n = 1024;
// _GNU_SOURCE: See Debian bug #485135
# if defined EXV_STRERROR_R_CHAR_P && defined _GNU_SOURCE
char *buf = 0;
char buf2[n];
std::memset(buf2, 0x0, n);
buf = strerror_r(error, buf2, n);
# else
char buf[n];
std::memset(buf, 0x0, n);
strerror_r(error, buf, n);
# endif
os << buf;
#else
os << std::strerror(error);
#endif
os << " (errno = " << error << ")";
return os.str();
} // strError
On a "File not found" error the "errno" is 2 (in line 3). After that the execution goes to line 14, 15 and 16. When I was „inside” the strerror_r function I saw that the error number was converted somehow to the "File not found" string; but I didn't observe whether it was copied back to the buffer also.
Then in line 18 the "buf" variable is full of zeroes again.
If you try to run the following, do you get the error message?
Exiv2::ImageFactory::open("wrong_path.jpg");
For me it says:
wrong_path.jpg: Failed to open the data source: (errno = 2)
The right one would be:
wrong_path.jpg: Failed to open the data source: No such file or directory (errno = 2)
Updated by Robin Mills over 8 years ago
Thanks for clarifying this so quickly.
It's easy to become confused here because:
1) my strerror_r appears to be behaving in an unexpected way (and different from you).
2) there's a maze involving EXV_HAVE_STRERROR_R EXV_STRERROR_R_CHAR_P and _GNU_SOURCE
3) I didn't write the code and haven't looked at this before today!
Can you try adding a line following 106:
os << buf;
if ( !buf0 ) os << strerror(error); // report strerror() if strerror_r() returns empty
If that doesn't fix it, can you add cout statements to determine which route you are taking through the maze!
Updated by Robin Mills over 8 years ago
The formatting gods are angry:
os << buf; if ( !buf[0] ) os << strerror(error); // report strerror() if strerror_r() returns empty
Updated by Ákos Szőts over 8 years ago
Without the patch:
LD_LIBRARY_PATH=/home/aki/[...]/exiv2-0.23/src/.libs/ ./a.out wrong_path Caught Exiv2 exception 'wrong_path: Failed to open the data source: (errno = 2)'
With the patch:
LD_LIBRARY_PATH=/home/aki/[...]/exiv2-0.23/src/.libs/ ./a.out wrong_path Caught Exiv2 exception 'wrong_path: Failed to open the data source: No such file or directory (errno = 2)'
So, it works :)
As far as I can tell "buf" is zero, but I don't know why. Just a wild hint, but maybe we use different versions of strerror_r. From its manual:
The XSI-compliant version of strerror_r() is provided if: (_POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600) && ! _GNU_SOURCE Otherwise, the GNU-specific version is provided.
Updated by Robin Mills over 8 years ago
- Status changed from Assigned to Resolved
- % Done changed from 50 to 100
Ákos:
You have the right idea here concerning the version of strerror_r. The maze is determined by ./configure (and CMake) to compile the code that matches the version of strerror_r on the build machine.
Anyway, I've submitted the fix: r3061 and marked this "resolved". If you discover anything about this, please update this issue report. This issue will eventually be "closed" when all issues are reviewed for the 0.24 release (expected about the end of 2013).
Issue: #908. futils.cpp strError() does not report correct error string.