Bug #908

strerror_r gives no error message back

Added by Ákos Szőts over 4 years ago. Updated over 4 years ago.

Status:ClosedStart date:18 Jun 2013
Priority:NormalDue date:
Assignee:Robin Mills% Done:

100%

Category:apiEstimated time:2.00 hours
Target version:0.24

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

Revision 3061
Added by Robin Mills over 4 years ago

Issue: #908. futils.cpp strError() does not report correct error string.

History

#1 Updated by Robin Mills over 4 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

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>

#2 Updated by Ákos Szőts over 4 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) 

#3 Updated by Robin Mills over 4 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!

#4 Updated by Robin Mills over 4 years ago

The formatting gods are angry:

os << buf;
if ( !buf[0] ) os << strerror(error); // report strerror() if strerror_r() returns empty

#5 Updated by Ákos Szőts over 4 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.

#6 Updated by Robin Mills over 4 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).

#7 Updated by Robin Mills over 4 years ago

  • Status changed from Resolved to Closed

Fixed in 0.24.

Also available in: Atom PDF

Redmine Appliance - Powered by TurnKey Linux