mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-27 17:06:05 +00:00

This pull request is the third iteration aiming to integrate short string annotations. This commit includes: - Enabling basic_string annotations for short strings. - Setting a value of `__trivially_relocatable` in `std::basic_string` to `false_type` when compiling with ASan (nothing changes when compiling without ASan). Short string annotations make `std::basic_string` to not be trivially relocatable, because memory has to be unpoisoned. - Adding a `_LIBCPP_STRING_INTERNAL_MEMORY_ACCESS` modifier to two functions. - Creating a macro `_LIBCPP_ASAN_VOLATILE_WRAPPER` to prevent problematic stack optimizations (the macro modifies code behavior only when compiling with ASan). Previously we had issues with compiler optimization, which we understand thanks to @vitalybuka. This commit also addresses smaller changes in short string, since previous upstream attempts. Problematic optimization was loading two values in code similar to: ``` __is_long() ? __get_long_size() : __get_short_size(); ``` We aim to resolve it with the volatile wrapper. This commit is built on top of two previous attempts which descriptions are below. Additionally, in the meantime, annotations were updated (but it shouldn't have any impact on anything): - https://github.com/llvm/llvm-project/pull/79292 --- Previous PR: https://github.com/llvm/llvm-project/pull/79049 Reverted:a16f81f5e3
Previous description: Originally merged here: https://github.com/llvm/llvm-project/pull/75882 Reverted here: https://github.com/llvm/llvm-project/pull/78627 Reverted due to failing buildbots. The problem was not caused by the annotations code, but by code in the `UniqueFunctionBase` class and in the `JSON.h` file. That code caused the program to write to memory that was already being used by string objects, which resulted in an ASan error. Fixes are implemented in: - https://github.com/llvm/llvm-project/pull/79065 - https://github.com/llvm/llvm-project/pull/79066 Problematic code from `UniqueFunctionBase` for example: ```cpp // In debug builds, we also scribble across the rest of the storage. memset(RHS.getInlineStorage(), 0xAD, InlineStorageSize); ``` --- Original description: This commit turns on ASan annotations in `std::basic_string` for short stings (SSO case). Originally suggested here: https://reviews.llvm.org/D147680 String annotations added here: https://github.com/llvm/llvm-project/pull/72677 Requires to pass CI without fails: - https://github.com/llvm/llvm-project/pull/75845 - https://github.com/llvm/llvm-project/pull/75858 Annotating `std::basic_string` with default allocator is implemented in https://github.com/llvm/llvm-project/pull/72677 but annotations for short strings (SSO - Short String Optimization) are turned off there. This commit turns them on. This also removes `_LIBCPP_SHORT_STRING_ANNOTATIONS_ALLOWED`, because we do not plan to support turning on and off short string annotations. Support in ASan API exists sincedd1b7b797a
. You can turn off annotations for a specific allocator based on changes from2fa1bec7a2
. This PR is a part of a series of patches extending AddressSanitizer C++ container overflow detection capabilities by adding annotations, similar to those existing in `std::vector` and `std::deque` collections. These enhancements empower ASan to effectively detect instances where the instrumented program attempts to access memory within a collection's internal allocation that remains unused. This includes cases where access occurs before or after the stored elements in `std::deque`, or between the `std::basic_string`'s size (including the null terminator) and capacity bounds. The introduction of these annotations was spurred by a real-world software bug discovered by Trail of Bits, involving an out-of-bounds memory access during the comparison of two strings using the `std::equals` function. This function was taking iterators (`iter1_begin`, `iter1_end`, `iter2_begin`) to perform the comparison, using a custom comparison function. When the `iter1` object exceeded the length of `iter2`, an out-of-bounds read could occur on the `iter2` object. Container sanitization, upon enabling these annotations, would effectively identify and flag this potential vulnerability. If you have any questions, please email: - advenam.tacet@trailofbits.com - disconnect3d@trailofbits.com
78 lines
2.8 KiB
C++
78 lines
2.8 KiB
C++
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef ASAN_TESTING_H
|
|
#define ASAN_TESTING_H
|
|
|
|
#include "test_macros.h"
|
|
#include <vector>
|
|
#include <string>
|
|
#include <memory>
|
|
#include <type_traits>
|
|
|
|
#if TEST_HAS_FEATURE(address_sanitizer)
|
|
extern "C" int __sanitizer_verify_contiguous_container(const void* beg, const void* mid, const void* end);
|
|
|
|
template <typename T, typename Alloc>
|
|
TEST_CONSTEXPR bool is_contiguous_container_asan_correct(const std::vector<T, Alloc>& c) {
|
|
if (TEST_IS_CONSTANT_EVALUATED)
|
|
return true;
|
|
if (std::is_same<Alloc, std::allocator<T> >::value && c.data() != NULL)
|
|
return __sanitizer_verify_contiguous_container(c.data(), c.data() + c.size(), c.data() + c.capacity()) != 0;
|
|
return true;
|
|
}
|
|
#else
|
|
template <typename T, typename Alloc>
|
|
TEST_CONSTEXPR bool is_contiguous_container_asan_correct(const std::vector<T, Alloc>&) {
|
|
return true;
|
|
}
|
|
#endif // TEST_HAS_FEATURE(address_sanitizer)
|
|
|
|
#if TEST_HAS_FEATURE(address_sanitizer)
|
|
extern "C" int __sanitizer_verify_double_ended_contiguous_container(
|
|
const void* beg, const void* con_beg, const void* con_end, const void* end);
|
|
extern "C" bool __sanitizer_is_annotable(const void* address, const unsigned long size);
|
|
#include <deque>
|
|
|
|
template <class T, class Alloc>
|
|
TEST_CONSTEXPR bool is_double_ended_contiguous_container_asan_correct(const std::deque<T, Alloc>& c) {
|
|
if (TEST_IS_CONSTANT_EVALUATED)
|
|
return true;
|
|
if (std::is_same<Alloc, std::allocator<T> >::value)
|
|
return c.__verify_asan_annotations();
|
|
return true;
|
|
}
|
|
#else
|
|
# include <deque>
|
|
template <class T, class Alloc>
|
|
TEST_CONSTEXPR bool is_double_ended_contiguous_container_asan_correct(const std::deque<T, Alloc>&) {
|
|
return true;
|
|
}
|
|
#endif
|
|
|
|
#if TEST_HAS_FEATURE(address_sanitizer)
|
|
template <typename ChrT, typename TraitsT, typename Alloc>
|
|
TEST_CONSTEXPR bool is_string_asan_correct(const std::basic_string<ChrT, TraitsT, Alloc>& c) {
|
|
if (TEST_IS_CONSTANT_EVALUATED)
|
|
return true;
|
|
|
|
if (std::__asan_annotate_container_with_allocator<Alloc>::value)
|
|
return __sanitizer_verify_contiguous_container(c.data(), c.data() + c.size() + 1, c.data() + c.capacity() + 1) != 0;
|
|
else
|
|
return __sanitizer_verify_contiguous_container(
|
|
c.data(), c.data() + c.capacity() + 1, c.data() + c.capacity() + 1) != 0;
|
|
}
|
|
#else
|
|
# include <string>
|
|
template <typename ChrT, typename TraitsT, typename Alloc>
|
|
TEST_CONSTEXPR bool is_string_asan_correct(const std::basic_string<ChrT, TraitsT, Alloc>&) {
|
|
return true;
|
|
}
|
|
#endif // TEST_HAS_FEATURE(address_sanitizer)
|
|
#endif // ASAN_TESTING_H
|