AWS SDK for C++  0.12.9
AWS SDK for C++
AWSString.h
Go to the documentation of this file.
1 /*
2  * Copyright 2010-2015 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License").
5  * You may not use this file except in compliance with the License.
6  * A copy of the License is located at
7  *
8  * http://aws.amazon.com/apache2.0
9  *
10  * or in the "license" file accompanying this file. This file is distributed
11  * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12  * express or implied. See the License for the specific language governing
13  * permissions and limitations under the License.
14  */
15 
16 #pragma once
17 
18 #include <aws/core/Core_EXPORTS.h>
19 
21 
22 #include <functional>
23 #include <string>
24 
25 namespace Aws
26 {
27 
28 #if _GLIBCXX_FULLY_DYNAMIC_STRING == 0 && defined(__ANDROID__)
29 
30 /*
31 using std::string with shared libraries is broken on android due to the platform-level decision to set _GLIBCXX_FULLY_DYNAMIC_STRING to 0
32 
33 The problem:
34 
35 (1) gnustl is the only usable c++11-compliant c++ standard library on Android; it is our only choice
36 (2) _GLIBCXX_FULLY_DYNAMIC_STRING is set to 0 in Android's c++config.h for gnustl
37 (3) The optimization that this enables is completely broken if using shared libraries and there is no way to opt out of using it.
38  An optimization that uses a comparison to a static memory address is death for shared libraries.
39 
40 Supposing you have a shared library B that depends on another shared library A. There are a variety of inocuous scenarios where you end up crashing
41 in 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
42 flip the struct to "public:" in order to take this address from your code).
43 If you take the address of this location, you will get two
44 different 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
45 libgnustl_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
46 an address that is static memory (from library A).
47 
48 
49 Lessons (with the empty string optimization forced on you):
50  (1) You can't move std::strings across shared libraries (as a part of another class, Outcome in our case)
51  (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
52  is missing/implicit or defined in the header file
53 
54 After much trouble, we have the following ghetto solution that has stopped all of the crashes so far without having to scour our entire codebase for every Lesson violation above:
55 
56 We prevent the empty string optimization from ever being run on our strings by:
57  (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
58  (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
59  perform the empty string optimization
60 
61 
62 This does not prevent problems with Aws::StringBuf and Aws::StringStream. We do not appear to be violating any of the lessons with our usage of them though.
63 
64 */
65 using AndroidBasicString = std::basic_string< char, std::char_traits< char >, Aws::Allocator< char > >;
66 
67 class 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 
97 using String = std::basic_string< char, std::char_traits< char >, Aws::Allocator< char > >;
98 
99 #ifdef _WIN32
100 using 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 
108 
std::allocator< T > Allocator
Definition: AWSAllocator.h:94
std::basic_string< char, std::char_traits< char >, Aws::Allocator< char > > String
Definition: AWSString.h:97
JSON (JavaScript Object Notation).