blob: bde2f37ef7c92747b42cc962d09a25fc45a2a757 [file] [log] [blame]
// 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
// RUN: cxx_compiler -c %s cxx_rtti -o %t1.o
// RUN: linker -o %t%exeext %t1.o
// RUN: runtool %t%exeext | grep "PASSED"
// check that __cxa_guard_acuire, __cxa_gaurd_release and __cxa_guard_abort are doing
// their jobs
//
//
extern "C" {
int printf(const char *, ...);
int __cxa_guard_acquire(long long *);
void __cxa_guard_release(long long *);
void __cxa_guard_abort(long long *);
}
#if 0
extern "C" int __cxa_guard_acquire ( __int64_t *guard_object );
Returns 1 if the initialization is not yet complete; 0 otherwise. This function is called before initialization takes place. If this function returns 1, either __cxa_guard_release or __cxa_guard_abort must be called with the same argument. The first byte of the guard_object is not modified by this function.
A thread-safe implementation will probably guard access to the first byte of the guard_object with a mutex. If this function returns 1, the mutex will have been acquired by the calling thread.
extern "C" void __cxa_guard_release ( __int64_t *guard_object );
Sets the first byte of the guard object to a non-zero value. This function is called after initialization is complete.
A thread-safe implementation will release the mutex acquired by __cxa_guard_acquire after setting the first byte of the guard object.
extern "C" void __cxa_guard_abort ( __int64_t *guard_object );
This function is called if the initialization terminates by throwing an exception.
A thread-safe implementation will release the mutex acquired by __cxa_guard_acquire.
<b>NOTE</b>:
#endif
static int nerr;
#define ERR(a) {printf("@%d %s\n", __LINE__, a); nerr++;}
int main()
{
long long gv = 0, gv2 = 0;
unsigned char *gp = (unsigned char *) &gv;
// simple case aquire should succeed and return 1.
if (!__cxa_guard_acquire(&gv)) ERR("FAILED TO ACQUIRE");
if (gp[0]) ERR("Lowest byte of the Guard var set prematurely");
// other buytes could be set at this point
// now release
__cxa_guard_release(&gv);
if (!gv) ERR("Guard var not set");
if (!gp[0]) ERR("first byte 0");
if (gp[1]||gp[2]||gp[3]||gp[4]||gp[5]||gp[6]||gp[7]) ERR("Other bytes set");
long long gs = gv;
// A second call should fail
if (__cxa_guard_acquire(&gv)) ERR("Acquired again")
// should not change gv
if (gs != gv) ERR("gv changed by a failing call");
// now test abort
gp = (unsigned char *)&gv2;
if (!__cxa_guard_acquire(&gv2)) ERR("FAILED TO ACQUIRE gv2");
if (gp[0]) ERR("Lowest byte of the Guard var set prematurely");
__cxa_guard_abort(&gv2);
if (gv2) ERR("Guard var set by abort ");
if (!__cxa_guard_acquire(&gv2)) ERR("FAILED TO ACQUIRE gv2");
if (gp[0]) ERR("Lowest byte of the Guard var set prematurely");
// now release
__cxa_guard_release(&gv2);
if (!gv2) ERR("Guard var not set");
if (!gp[0]) ERR("first byte 0");
if (gp[1]||gp[2]||gp[3]||gp[4]||gp[5]||gp[6]||gp[7]) ERR("Other bytes set");
printf("%s\n", nerr ? "FAILED" : "PASSED");
return nerr;
}