2011-11-15 04:50:16 +08:00
|
|
|
//===- llvm/unittest/Support/ManagedStatic.cpp - ManagedStatic tests ------===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
Report fatal error in the case of out of memory
Analysis of fails in the case of out of memory errors can be tricky on
Windows. Such error emerges at the point where memory allocation function
fails, but manifests itself when null pointer is used. These two points
may be distant from each other. Besides, next runs may not exhibit
allocation error.
Usual programming practice does not require checking result of 'operator
new' because it throws 'std::bad_alloc' in the case of allocation error.
However, LLVM is usually built with exceptions turned off, so 'new' can
return null pointer. This change installs custom new handler, which causes
fatal error in the case of out of memory. The handler is installed
automatically prior to call to 'main' during construction of a static
object defined in 'lib/Support/ErrorHandling.cpp'. If the application does
not use this file, the handler may be installed manually by a call to
'llvm::install_out_of_memory_new_handler', declared in
'include/llvm/Support/ErrorHandling.h".
There are calls to C allocation functions, malloc, calloc and realloc.
They are used for interoperability with C code, when allocated object has
variable size and when it is necessary to avoid call of constructors. In
many calls the result is not checked against null pointer. To simplify
checks, new functions are defined in the namespace 'llvm' with the
same names as these C function. These functions produce fatal error if
allocation fails. User should use 'llvm::malloc' instead of 'std::malloc'
in order to use the safe variant. This change replaces 'std::malloc'
in the cases when the result of allocation function is not checked against
null pointer.
Finally, there are plain C code, that uses malloc and similar functions. If
the result is not checked, assert statements are added.
Differential Revision: https://reviews.llvm.org/D43010
llvm-svn: 325224
2018-02-15 17:20:26 +08:00
|
|
|
|
|
|
|
#include "llvm/Support/Allocator.h"
|
2011-11-15 04:50:16 +08:00
|
|
|
#include "llvm/Support/ManagedStatic.h"
|
2011-11-15 06:10:23 +08:00
|
|
|
#include "llvm/Config/config.h"
|
|
|
|
#ifdef HAVE_PTHREAD_H
|
2011-11-15 04:50:16 +08:00
|
|
|
#include <pthread.h>
|
2011-11-15 06:10:23 +08:00
|
|
|
#endif
|
2011-11-15 04:50:16 +08:00
|
|
|
|
|
|
|
#include "gtest/gtest.h"
|
|
|
|
|
|
|
|
using namespace llvm;
|
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2013-05-14 21:29:16 +08:00
|
|
|
#if LLVM_ENABLE_THREADS != 0 && defined(HAVE_PTHREAD_H) && \
|
|
|
|
!__has_feature(memory_sanitizer)
|
2011-11-15 04:50:16 +08:00
|
|
|
namespace test1 {
|
|
|
|
llvm::ManagedStatic<int> ms;
|
|
|
|
void *helper(void*) {
|
|
|
|
*ms;
|
2014-06-09 06:29:17 +08:00
|
|
|
return nullptr;
|
2011-11-15 04:50:16 +08:00
|
|
|
}
|
2013-01-24 22:44:02 +08:00
|
|
|
|
|
|
|
// Valgrind's leak checker complains glibc's stack allocation.
|
|
|
|
// To appease valgrind, we provide our own stack for each thread.
|
|
|
|
void *allocate_stack(pthread_attr_t &a, size_t n = 65536) {
|
Report fatal error in the case of out of memory
Analysis of fails in the case of out of memory errors can be tricky on
Windows. Such error emerges at the point where memory allocation function
fails, but manifests itself when null pointer is used. These two points
may be distant from each other. Besides, next runs may not exhibit
allocation error.
Usual programming practice does not require checking result of 'operator
new' because it throws 'std::bad_alloc' in the case of allocation error.
However, LLVM is usually built with exceptions turned off, so 'new' can
return null pointer. This change installs custom new handler, which causes
fatal error in the case of out of memory. The handler is installed
automatically prior to call to 'main' during construction of a static
object defined in 'lib/Support/ErrorHandling.cpp'. If the application does
not use this file, the handler may be installed manually by a call to
'llvm::install_out_of_memory_new_handler', declared in
'include/llvm/Support/ErrorHandling.h".
There are calls to C allocation functions, malloc, calloc and realloc.
They are used for interoperability with C code, when allocated object has
variable size and when it is necessary to avoid call of constructors. In
many calls the result is not checked against null pointer. To simplify
checks, new functions are defined in the namespace 'llvm' with the
same names as these C function. These functions produce fatal error if
allocation fails. User should use 'llvm::malloc' instead of 'std::malloc'
in order to use the safe variant. This change replaces 'std::malloc'
in the cases when the result of allocation function is not checked against
null pointer.
Finally, there are plain C code, that uses malloc and similar functions. If
the result is not checked, assert statements are added.
Differential Revision: https://reviews.llvm.org/D43010
llvm-svn: 325224
2018-02-15 17:20:26 +08:00
|
|
|
void *stack = llvm::malloc(n);
|
2013-01-24 22:44:02 +08:00
|
|
|
pthread_attr_init(&a);
|
2013-01-24 23:29:27 +08:00
|
|
|
#if defined(__linux__)
|
2013-01-24 22:44:02 +08:00
|
|
|
pthread_attr_setstack(&a, stack, n);
|
2013-01-24 23:29:27 +08:00
|
|
|
#endif
|
2013-01-24 22:44:02 +08:00
|
|
|
return stack;
|
|
|
|
}
|
2011-11-15 04:50:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
TEST(Initialize, MultipleThreads) {
|
|
|
|
// Run this test under tsan: http://code.google.com/p/data-race-test/
|
|
|
|
|
2013-01-24 22:44:02 +08:00
|
|
|
pthread_attr_t a1, a2;
|
|
|
|
void *p1 = test1::allocate_stack(a1);
|
|
|
|
void *p2 = test1::allocate_stack(a2);
|
|
|
|
|
2011-11-15 04:50:16 +08:00
|
|
|
pthread_t t1, t2;
|
2014-06-09 06:29:17 +08:00
|
|
|
pthread_create(&t1, &a1, test1::helper, nullptr);
|
|
|
|
pthread_create(&t2, &a2, test1::helper, nullptr);
|
|
|
|
pthread_join(t1, nullptr);
|
|
|
|
pthread_join(t2, nullptr);
|
2013-01-24 22:44:02 +08:00
|
|
|
free(p1);
|
|
|
|
free(p2);
|
2011-11-15 04:50:16 +08:00
|
|
|
}
|
2011-11-15 06:10:23 +08:00
|
|
|
#endif
|
2011-11-15 04:50:16 +08:00
|
|
|
|
2017-05-29 22:05:26 +08:00
|
|
|
namespace NestedStatics {
|
|
|
|
static ManagedStatic<int> Ms1;
|
|
|
|
struct Nest {
|
|
|
|
Nest() {
|
|
|
|
++(*Ms1);
|
|
|
|
}
|
|
|
|
|
|
|
|
~Nest() {
|
|
|
|
assert(Ms1.isConstructed());
|
|
|
|
++(*Ms1);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
static ManagedStatic<Nest> Ms2;
|
|
|
|
|
|
|
|
TEST(ManagedStaticTest, NestedStatics) {
|
|
|
|
EXPECT_FALSE(Ms1.isConstructed());
|
|
|
|
EXPECT_FALSE(Ms2.isConstructed());
|
|
|
|
|
|
|
|
*Ms2;
|
|
|
|
EXPECT_TRUE(Ms1.isConstructed());
|
|
|
|
EXPECT_TRUE(Ms2.isConstructed());
|
|
|
|
}
|
|
|
|
} // namespace NestedStatics
|
|
|
|
|
|
|
|
namespace CustomCreatorDeletor {
|
2017-05-30 04:56:27 +08:00
|
|
|
struct CustomCreate {
|
|
|
|
static void *call() {
|
Report fatal error in the case of out of memory
Analysis of fails in the case of out of memory errors can be tricky on
Windows. Such error emerges at the point where memory allocation function
fails, but manifests itself when null pointer is used. These two points
may be distant from each other. Besides, next runs may not exhibit
allocation error.
Usual programming practice does not require checking result of 'operator
new' because it throws 'std::bad_alloc' in the case of allocation error.
However, LLVM is usually built with exceptions turned off, so 'new' can
return null pointer. This change installs custom new handler, which causes
fatal error in the case of out of memory. The handler is installed
automatically prior to call to 'main' during construction of a static
object defined in 'lib/Support/ErrorHandling.cpp'. If the application does
not use this file, the handler may be installed manually by a call to
'llvm::install_out_of_memory_new_handler', declared in
'include/llvm/Support/ErrorHandling.h".
There are calls to C allocation functions, malloc, calloc and realloc.
They are used for interoperability with C code, when allocated object has
variable size and when it is necessary to avoid call of constructors. In
many calls the result is not checked against null pointer. To simplify
checks, new functions are defined in the namespace 'llvm' with the
same names as these C function. These functions produce fatal error if
allocation fails. User should use 'llvm::malloc' instead of 'std::malloc'
in order to use the safe variant. This change replaces 'std::malloc'
in the cases when the result of allocation function is not checked against
null pointer.
Finally, there are plain C code, that uses malloc and similar functions. If
the result is not checked, assert statements are added.
Differential Revision: https://reviews.llvm.org/D43010
llvm-svn: 325224
2018-02-15 17:20:26 +08:00
|
|
|
void *Mem = llvm::malloc(sizeof(int));
|
2017-05-30 04:56:27 +08:00
|
|
|
*((int *)Mem) = 42;
|
|
|
|
return Mem;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
struct CustomDelete {
|
|
|
|
static void call(void *P) { std::free(P); }
|
|
|
|
};
|
|
|
|
static ManagedStatic<int, CustomCreate, CustomDelete> Custom;
|
2017-05-29 22:05:26 +08:00
|
|
|
TEST(ManagedStaticTest, CustomCreatorDeletor) {
|
|
|
|
EXPECT_EQ(42, *Custom);
|
|
|
|
}
|
|
|
|
} // namespace CustomCreatorDeletor
|
|
|
|
|
2011-11-15 04:50:16 +08:00
|
|
|
} // anonymous namespace
|