原标题为:vsprintf
从Android12开始崩溃(api〉= 31)
我的Android应用使用NDK构建的本机库(libexif)。在我的本机代码(改编自exif)中的某个时候,我调用了vsprintf
函数,导致应用崩溃。以前在exif中,它是对vfprintf (stderr, format, args);
的调用,我将其替换为vsprintf
,以便存储字符串供以后使用。
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);
}
消息(根据其工作的API的输出)应为:
The tag 'ComponentsConfiguration' contains an invalid number of components (3, expected 4).
format
变量包含:"The tag '%s' contains an invalid number of components (%i, expected %i).
"
我无法检查参数的值(还没有找到如何打印它们来检查它们的值)。
这在API30(在模拟器上)之前没有任何问题。在使用API31的映像上,它在调用vsprintf
函数时崩溃。
更新NDK到25b也不能修复。我的API30映像是x86,API31映像是x86_64。
- 是否有解决/解决此问题的方法?**
可能感兴趣的其他代码部分:
#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);
更新:
- 同时,由于API30映像具有x86架构,而API31映像是x86_64,我刚刚尝试了API30与x86_64。
- API 30 x86 →无应用程序崩溃
- API 30 x86_64 →应用程序崩溃
- API 31 x86_64 →应用程序崩溃
因此,这看起来像是x86与x86_64模拟器映像相关。
- 在真正的arm8设备上,也没有崩溃。
- 我还发现传递给
vsprintf
的参数没有预期的值。如果用预期的值模拟vsprintf
,vsprintf
工作正常。所以问题可能不是vsprintf
。
1条答案
按热度按时间xdyibdwo1#
问题的原因是我使用了两次
args
:一次在vsprintf
,一次在vsprintf
。根据https://stackoverflow.com/a/10807375/15401262,这现在是允许的,并导致未定义的行为。
它不能使用两次,在这种情况下必须使用va_copy。