简体   繁体   中英

Crash on android x86_64 not happening on x86 (Android API30, API31)

Former title was: crash on vsprintf starting from Android12 (api >= 31)

My Android app uses a native library (libexif) built with NDK. At some time in my native code (adapted from exif), I call the vsprintf function which makes the app crash. Formerly in exif, it was a call to vfprintf (stderr, format, args); that I replaced by vsprintf so as to store the string for later use.

static void
log_func (ExifLog *log, ExifLogCode code, const char *domain,
          const char *format, va_list args, void *data)
{
  char dest[1024] = {0, };
  vsprintf(dest, format, args);
}

The message (as per the output from an API where it works) should be:

The tag 'ComponentsConfiguration' contains an invalid number of components (3, expected 4).

The format variable contains: " The tag '%s' contains an invalid number of components (%i, expected %i). "

I couldn't check the values of the arguments (haven't found how to print them to check their values).

This works without any problems up to API30 (on the emulator). On an image using API31 it crashes at the call of the vsprintf function.

Updating NDK to 25b doesn't fix either. My API30 image is x86, the API31 image is x86_64.

Any idea to fix/workaround this?

Other parts of code that may be of interest:

#ifndef NO_VERBOSE_TAG_STRINGS
static void
exif_entry_log (ExifEntry *e, ExifLogCode code, const char *format, ...)
{
    va_list args;
    ExifLog *l = NULL;

    if (e && e->parent && e->parent->parent)
        l = exif_data_get_log (e->parent->parent);
    va_start (args, format);
    exif_logv (l, code, "ExifEntry", format, args);
    va_end (args);
}
#else
#if defined(__STDC_VERSION__) &&  __STDC_VERSION__ >= 199901L
#define exif_entry_log(...) do { } while (0)
#elif defined(__GNUC__)
#define exif_entry_log(x...) do { } while (0)
#else
#define exif_entry_log (void)
#endif
#endif

#define CC(entry,target,v,maxlen)                   \
{                                   \
    if (entry->components != target) {              \
        exif_entry_log (entry, EXIF_LOG_CODE_CORRUPT_DATA,  \
            _("The tag '%s' contains an invalid number of " \
              "components (%i, expected %i)."),     \
            exif_tag_get_name (entry->tag),     \
            (int) entry->components, (int) target);     \
        break;                          \
    }                               \
}

// Then this call later

  CC (e, 4, val, maxlen);

Update:

  • In the meantime since API30 images have x86 arch, and API31 images are x86_64 I just tried API30 with a x86_64. For now:

    • API 30 x86 → no crash in app
    • API 30 x86_64 → crash in app
    • API 31 x86_64 → crash in app

So this looks like it is x86 vs x86_64 emulator image related.

  • On a real arm8 device, there is no crash either.

  • I also found that the args passed to vsprintf don't have the expected values. And If a simulate vsprintf with the expected values, vsprintf works fine. So the problem is likely not vsprintf .

The cause of the problem was that I was using args twice: Once in vsprintf and once in vsprintf .

This is now allowed according to https://stackoverflow.com/a/10807375/15401262 and leads to undefined behavior.

It can't be used twice and one has to use va_copy in that case.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM