AWS SDK for C++
AWS SDK for C++
Loading...
Searching...
No Matches
AWSString.h
Go to the documentation of this file.
1
6#pragma once
7
9
11
12#include <functional>
13#include <string>
14
15namespace Aws
16{
17
18#if defined(_GLIBCXX_FULLY_DYNAMIC_STRING) && _GLIBCXX_FULLY_DYNAMIC_STRING == 0 && defined(__ANDROID__)
19
20/*
21using std::string with shared libraries is broken on android when using gnustl
22due to the platform-level decision to set _GLIBCXX_FULLY_DYNAMIC_STRING to 0
23
24The problem:
25
26(1) _GLIBCXX_FULLY_DYNAMIC_STRING is set to 0 in Android's c++config.h for gnustl
27(2) The optimization that this enables is completely broken if using shared libraries and there is no way to opt out of using it.
28 An optimization that uses a comparison to a static memory address is death for shared libraries.
29
30Supposing you have a shared library B that depends on another shared library A. There are a variety of innocuous scenarios where you end up crashing
31in the std::basic_string destructor because it's attempting to free a static memory address (&std::string::_Rep_Base::_S_empty_rep_storage -- you'll need to temporarily
32flip the struct to "public:" in order to take this address from your code).
33If you take the address of this location, you will get two
34different answers depending on whether you query it in library A or library B (oddly enough, if you look the symbol itself up, it only shows up as public weak in
35libgnustl_shared.so). When the string destructor is run from the context of library B, the _Rep::_M_dispose function will end up attempting to free
36an address that is static memory (from library A).
37
38
39Lessons (with the empty string optimization forced on you):
40 (1) You can't move std::strings across shared libraries (as a part of another class, Outcome in our case)
41 (2) If you default initialize a std::string member variable, you can't have a mismatched constructor/destructor pair such that one is in a cpp file and the other
42 is missing/implicit or defined in the header file
43
44Solutions:
45
46Use libc++ rather than gnustl
47
48For those who must use gnustl, we have provided a working solution by cobbling together a set of hacks:
49
50We prevent the empty string optimization from ever being run on our strings by:
51 (1) Make Aws::Allocator always fail equality checks with itself; this check is part of the empty string optimization in several std::basic_string constructors
52 (2) All other cases are prevented by turning Aws::String into a subclass whose default constructor and move operations go to baseclass versions which will not
53 perform the empty string optimization
54
55Those changes prevent crashes, but lead to very poor performance when using a string stream; every character added will result in multiple copies of the entire
56string (ie, quadratic).
57
58To fix the performance problems, we have put together a set of replacement classes, SimpleStreamBuf and SimpleStringStream, that
59replace std::stringstream and std::stringbuf in SDK code. These replacements use raw buffers rather than strings in order to
60avoid the performance issues.
61
62This solution is only enabled if using gnustl on Android. In all other situations, normal STL types are used.
63*/
64
65using AndroidBasicString = std::basic_string< char, std::char_traits< char >, Aws::Allocator< char > >;
66
67class String : public AndroidBasicString
68{
69 public:
70 using Base = AndroidBasicString;
71
72 String() : Base("") {} // allocator comparison failure will cause empty string optimisation to be skipped
73 String(const String& rhs ) : Base(rhs) {}
74 String(String&& rhs) : Base(rhs) {} // DO NOT CALL std::move, let this go to the const ref constructor
75 String(const AndroidBasicString& rhs) : Base(rhs) {}
76 String(AndroidBasicString&& rhs) : Base(rhs) {} // DO NOT CALL std::move, let this go to the const ref constructor
77 String(const char* str) : Base(str) {}
78 String(const char* str_begin, const char* str_end) : Base(str_begin, str_end) {}
79 String(const AndroidBasicString& str, size_type pos, size_type count) : Base(str, pos, count) {}
80 String(const String& str, size_type pos, size_type count) : Base(str, pos, count) {}
81 String(const char* str, size_type count) : Base(str, count) {}
82 String(size_type count, char c) : Base(count, c) {}
83 String(std::initializer_list<char> __l) : Base(__l) {}
84
85 template<class _InputIterator>
86 String(_InputIterator __beg, _InputIterator __end) : Base(__beg, __end) {}
87
88 String& operator=(const String& rhs) { Base::operator=(rhs); return *this; }
89 String& operator=(String&& rhs) { Base::operator=(rhs); return *this; } // might be ok to use std::move (base class uses swap) but let's be safe
90 String& operator=(const AndroidBasicString& rhs) { Base::operator=(rhs); return *this; }
91 String& operator=(AndroidBasicString&& rhs) { Base::operator=(rhs); return *this; } // might be ok to use std::move (base class uses swap) but let's be safe
92 String& operator=(const char* str) { Base::operator=(str); return *this; }
93};
94
95#else
96
97using String = std::basic_string< char, std::char_traits< char >, Aws::Allocator< char > >;
98
99#ifdef _WIN32
100using WString = std::basic_string< wchar_t, std::char_traits< wchar_t >, Aws::Allocator< wchar_t > >;
101#endif
102
103#endif // __ANDROID
104
105} // namespace Aws
106
107#ifdef USE_AWS_MEMORY_MANAGEMENT
108#include <aws/crt/StringUtils.h>
109
110/* Inject hash method for an Aws::String with a custom allocator to workaround original C++ defect:
111 * "hash support for std::basic_string with customized allocators was not enabled"
112 * see LWG 3705: https://en.cppreference.com/w/cpp/string/basic_string/hash */
113namespace std
114{
115 template<>
116 struct hash<Aws::String>
117 {
118 size_t operator()(const Aws::String& t) const { return Aws::Crt::HashString(t.c_str()); }
119 };
120}
121#endif
int count
Definition: cJSON.h:230
std::allocator< T > Allocator
Definition: AWSAllocator.h:39
std::basic_string< char, std::char_traits< char >, Aws::Allocator< char > > String
Definition: AWSString.h:97