Introduce __asan_set_error_report_callback() to allow the client program post-process the error reports.

If the callback is set, Report() and Printf() print the reports into a buffer (together with stderr), which is then passed to the client.

llvm-svn: 151528
This commit is contained in:
Alexander Potapenko 2012-02-27 14:06:48 +00:00
parent 169f436870
commit 7e07f56811
6 changed files with 59 additions and 1 deletions

View File

@ -222,6 +222,13 @@ int internal_strcmp(const char *s1, const char *s2) {
return 0;
}
char *internal_strncpy(char *dst, const char *src, size_t n) {
size_t i;
for (i = 0; i < n && src[i]; i++)
dst[i] = src[i];
return dst;
}
} // namespace __asan
// ---------------------- Wrappers ---------------- {{{1

View File

@ -40,6 +40,7 @@ int internal_memcmp(const void* s1, const void* s2, size_t n);
char *internal_strstr(const char *haystack, const char *needle);
char *internal_strncat(char *dst, const char *src, size_t n);
int internal_strcmp(const char *s1, const char *s2);
char *internal_strncpy(char *dst, const char *src, size_t n);
// Works only for base=10 and doesn't set errno.
int64_t internal_simple_strtoll(const char *nptr, char **endptr, int base);

View File

@ -121,6 +121,9 @@ extern "C" {
void __asan_set_death_callback(void (*callback)(void))
ASAN_INTERFACE_FUNCTION_ATTRIBUTE;
void __asan_set_error_report_callback(void (*callback)(const char*))
ASAN_INTERFACE_FUNCTION_ATTRIBUTE;
// Returns the estimated number of bytes that will be reserved by allocator
// for request of "size" bytes. If ASan allocator can't allocate that much
// memory, returns the maximal possible allocation size, otherwise returns

View File

@ -22,6 +22,9 @@
namespace __asan {
extern char *error_message_buffer;
extern size_t error_message_buffer_pos, error_message_buffer_size;
void RawWrite(const char *buffer) {
static const char *kRawWriteError = "RawWrite can't output requested buffer!";
size_t length = (size_t)internal_strlen(buffer);
@ -29,6 +32,14 @@ void RawWrite(const char *buffer) {
AsanWrite(2, kRawWriteError, internal_strlen(kRawWriteError));
AsanDie();
}
if (error_message_buffer) {
int remaining = error_message_buffer_size - error_message_buffer_pos;
internal_strncpy(error_message_buffer + error_message_buffer_pos,
buffer, remaining);
error_message_buffer[error_message_buffer_size - 1] = '\0';
// FIXME: reallocate the buffer instead of truncating the message.
error_message_buffer_pos += remaining > length ? length : remaining;
}
}
static inline int AppendChar(char **buff, const char *buff_end, char c) {

View File

@ -52,6 +52,10 @@ int FLAG_sleep_before_dying;
int asan_inited;
bool asan_init_is_running;
static void (*death_callback)(void);
static void (*error_report_callback)(const char*);
char *error_message_buffer = NULL;
size_t error_message_buffer_pos = 0;
size_t error_message_buffer_size = 0;
// -------------------------- Misc ---------------- {{{1
void ShowStatsAndAbort() {
@ -237,7 +241,7 @@ ASAN_REPORT_ERROR(store, true, 16)
// dynamic libraries access the symbol even if it is not used by the executable
// itself. This should help if the build system is removing dead code at link
// time.
static void force_interface_symbols() {
static NOINLINE void force_interface_symbols() {
volatile int fake_condition = 0; // prevent dead condition elimination.
if (fake_condition) {
__asan_report_load1(NULL);
@ -253,6 +257,7 @@ static void force_interface_symbols() {
__asan_register_global(0, 0, NULL);
__asan_register_globals(NULL, 0);
__asan_unregister_globals(NULL, 0);
__asan_set_error_report_callback(NULL);
}
}
@ -300,6 +305,16 @@ void __asan_set_death_callback(void (*callback)(void)) {
death_callback = callback;
}
void NOINLINE __asan_set_error_report_callback(void (*callback)(const char*)) {
error_report_callback = callback;
if (callback) {
error_message_buffer_size = 1 << 14;
error_message_buffer =
(char*)AsanMmapSomewhereOrDie(error_message_buffer_size, __FUNCTION__);
error_message_buffer_pos = 0;
}
}
void __asan_report_error(uintptr_t pc, uintptr_t bp, uintptr_t sp,
uintptr_t addr, bool is_write, size_t access_size) {
// Do not print more than one report, otherwise they will mix up.
@ -389,6 +404,9 @@ void __asan_report_error(uintptr_t pc, uintptr_t bp, uintptr_t sp,
PrintBytes(" ", (uintptr_t*)(aligned_shadow+2*kWordSize));
PrintBytes(" ", (uintptr_t*)(aligned_shadow+3*kWordSize));
PrintBytes(" ", (uintptr_t*)(aligned_shadow+4*kWordSize));
if (error_report_callback) {
error_report_callback(error_message_buffer);
}
AsanDie();
}

View File

@ -342,3 +342,21 @@ TEST(AddressSanitizerInterface, DISABLED_InvalidPoisonAndUnpoisonCallsTest) {
kInvalidPoisonMessage);
free(array);
}
static void ErrorReportCallbackOneToZ(const char *report) {
int len = strlen(report);
char *dup = (char*)malloc(len);
strcpy(dup, report);
for (int i = 0; i < len; i++) {
if (dup[i] == '1') dup[i] = 'Z';
}
write(2, dup, len);
free(dup);
}
TEST(AddressSanitizerInterface, SetErrorReportCallbackTest) {
__asan_set_error_report_callback(ErrorReportCallbackOneToZ);
char *array = Ident((char*)malloc(120));
EXPECT_DEATH(ACCESS(array, 120), "size Z");
__asan_set_error_report_callback(NULL);
}