mirror of
https://github.com/KhronosGroup/OpenCL-CTS.git
synced 2026-03-19 06:09:01 +00:00
The maintenance of the conformance tests is moving to Github. This commit contains all the changes that have been done in Gitlab since the first public release of the conformance tests. Signed-off-by: Kevin Petit <kevin.petit@arm.com>
565 lines
16 KiB
C++
565 lines
16 KiB
C++
//
|
|
// Copyright (c) 2017 The Khronos Group Inc.
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
//
|
|
#include "os_helpers.h"
|
|
#include "errorHelpers.h"
|
|
|
|
// =================================================================================================
|
|
// C++ interface.
|
|
// =================================================================================================
|
|
|
|
#include <cerrno> // errno, error constants
|
|
#include <climits> // PATH_MAX
|
|
#include <cstdlib> // abort, _splitpath, _makepath
|
|
#include <cstring> // strdup, strerror_r
|
|
#include <sstream>
|
|
|
|
#include <vector>
|
|
|
|
#define CHECK_PTR( ptr ) \
|
|
if ( (ptr) == NULL ) { \
|
|
abort(); \
|
|
}
|
|
|
|
typedef std::vector< char > buffer_t;
|
|
|
|
#if ! defined( PATH_MAX )
|
|
#define PATH_MAX 1000
|
|
#endif
|
|
|
|
int const _size = PATH_MAX + 1; // Initial buffer size for path.
|
|
int const _count = 8; // How many times we will try to double buffer size.
|
|
|
|
// -------------------------------------------------------------------------------------------------
|
|
// MacOS X
|
|
// -------------------------------------------------------------------------------------------------
|
|
|
|
#if defined( __APPLE__ )
|
|
|
|
|
|
#include <mach-o/dyld.h> // _NSGetExecutablePath
|
|
#include <libgen.h> // dirname
|
|
|
|
|
|
static
|
|
std::string
|
|
_err_msg(
|
|
int err, // Error number (e. g. errno).
|
|
int level // Nesting level, for avoiding infinite recursion.
|
|
) {
|
|
|
|
/*
|
|
There are 3 incompatible versions of strerror_r:
|
|
|
|
char * strerror_r( int, char *, size_t ); // GNU version
|
|
int strerror_r( int, char *, size_t ); // BSD version
|
|
int strerror_r( int, char *, size_t ); // XSI version
|
|
|
|
BSD version returns error code, while XSI version returns 0 or -1 and sets errno.
|
|
|
|
*/
|
|
|
|
// BSD version of strerror_r.
|
|
buffer_t buffer( 100 );
|
|
int count = _count;
|
|
for ( ; ; ) {
|
|
int rc = strerror_r( err, & buffer.front(), buffer.size() );
|
|
if ( rc == EINVAL ) {
|
|
// Error code is not recognized, but anyway we got the message.
|
|
return & buffer.front();
|
|
} else if ( rc == ERANGE ) {
|
|
// Buffer is not enough.
|
|
if ( count > 0 ) {
|
|
// Enlarge the buffer.
|
|
-- count;
|
|
buffer.resize( buffer.size() * 2 );
|
|
} else {
|
|
std::stringstream ostr;
|
|
ostr
|
|
<< "Error " << err << " "
|
|
<< "(Getting error message failed: "
|
|
<< "Buffer of " << buffer.size() << " bytes is still too small"
|
|
<< ")";
|
|
return ostr.str();
|
|
}; // if
|
|
} else if ( rc == 0 ) {
|
|
// We got the message.
|
|
return & buffer.front();
|
|
} else {
|
|
std::stringstream ostr;
|
|
ostr
|
|
<< "Error " << err << " "
|
|
<< "(Getting error message failed: "
|
|
<< ( level < 2 ? _err_msg( rc, level + 1 ) : "Oops" )
|
|
<< ")";
|
|
return ostr.str();
|
|
}; // if
|
|
}; // forever
|
|
|
|
} // _err_msg
|
|
|
|
|
|
std::string
|
|
dir_sep(
|
|
) {
|
|
return "/";
|
|
} // dir_sep
|
|
|
|
|
|
std::string
|
|
exe_path(
|
|
) {
|
|
buffer_t path( _size );
|
|
int count = _count;
|
|
for ( ; ; ) {
|
|
uint32_t size = path.size();
|
|
int rc = _NSGetExecutablePath( & path.front(), & size );
|
|
if ( rc == 0 ) {
|
|
break;
|
|
}; // if
|
|
if ( count > 0 ) {
|
|
-- count;
|
|
path.resize( size );
|
|
} else {
|
|
log_error(
|
|
"ERROR: Getting executable path failed: "
|
|
"_NSGetExecutablePath failed: Buffer of %lu bytes is still too small\n",
|
|
(unsigned long) path.size()
|
|
);
|
|
exit( 2 );
|
|
}; // if
|
|
}; // forever
|
|
return & path.front();
|
|
} // exe_path
|
|
|
|
|
|
std::string
|
|
exe_dir(
|
|
) {
|
|
std::string path = exe_path();
|
|
// We cannot pass path.c_str() to `dirname' bacause `dirname' modifies its argument.
|
|
buffer_t buffer( path.c_str(), path.c_str() + path.size() + 1 ); // Copy with trailing zero.
|
|
return dirname( & buffer.front() );
|
|
} // exe_dir
|
|
|
|
|
|
#endif // __APPLE__
|
|
|
|
// -------------------------------------------------------------------------------------------------
|
|
// Linux
|
|
// -------------------------------------------------------------------------------------------------
|
|
|
|
#if defined( __linux__ )
|
|
|
|
|
|
#include <cerrno> // errno
|
|
#include <libgen.h> // dirname
|
|
#include <unistd.h> // readlink
|
|
|
|
|
|
static
|
|
std::string
|
|
_err_msg(
|
|
int err,
|
|
int level
|
|
) {
|
|
|
|
/*
|
|
There are 3 incompatible versions of strerror_r:
|
|
|
|
char * strerror_r( int, char *, size_t ); // GNU version
|
|
int strerror_r( int, char *, size_t ); // BSD version
|
|
int strerror_r( int, char *, size_t ); // XSI version
|
|
|
|
BSD version returns error code, while XSI version returns 0 or -1 and sets errno.
|
|
|
|
*/
|
|
|
|
#if defined(__ANDROID__) || ( ( _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE >= 600 ) && ! _GNU_SOURCE )
|
|
|
|
// XSI version of strerror_r.
|
|
#warning Not tested!
|
|
buffer_t buffer( 200 );
|
|
int count = _count;
|
|
for ( ; ; ) {
|
|
int rc = strerror_r( err, & buffer.front(), buffer.size() );
|
|
if ( rc == -1 ) {
|
|
int _err = errno;
|
|
if ( _err == ERANGE ) {
|
|
if ( count > 0 ) {
|
|
// Enlarge the buffer.
|
|
-- count;
|
|
buffer.resize( buffer.size() * 2 );
|
|
} else {
|
|
std::stringstream ostr;
|
|
ostr
|
|
<< "Error " << err << " "
|
|
<< "(Getting error message failed: "
|
|
<< "Buffer of " << buffer.size() << " bytes is still too small"
|
|
<< ")";
|
|
return ostr.str();
|
|
}; // if
|
|
} else {
|
|
std::stringstream ostr;
|
|
ostr
|
|
<< "Error " << err << " "
|
|
<< "(Getting error message failed: "
|
|
<< ( level < 2 ? _err_msg( _err, level + 1 ) : "Oops" )
|
|
<< ")";
|
|
return ostr.str();
|
|
}; // if
|
|
} else {
|
|
// We got the message.
|
|
return & buffer.front();
|
|
}; // if
|
|
}; // forever
|
|
|
|
#else
|
|
|
|
// GNU version of strerror_r.
|
|
char buffer[ 2000 ];
|
|
return strerror_r( err, buffer, sizeof( buffer ) );
|
|
|
|
#endif
|
|
|
|
} // _err_msg
|
|
|
|
|
|
std::string
|
|
dir_sep(
|
|
) {
|
|
return "/";
|
|
} // dir_sep
|
|
|
|
|
|
std::string
|
|
exe_path(
|
|
) {
|
|
|
|
static std::string const exe = "/proc/self/exe";
|
|
|
|
buffer_t path( _size );
|
|
int count = _count; // Max number of iterations.
|
|
|
|
for ( ; ; ) {
|
|
|
|
ssize_t len = readlink( exe.c_str(), & path.front(), path.size() );
|
|
|
|
if ( len < 0 ) {
|
|
// Oops.
|
|
int err = errno;
|
|
log_error(
|
|
"ERROR: Getting executable path failed: "
|
|
"Reading symlink `%s' failed: %s\n",
|
|
exe.c_str(), err_msg( err ).c_str()
|
|
);
|
|
exit( 2 );
|
|
}; // if
|
|
|
|
if ( len < path.size() ) {
|
|
// We got the path.
|
|
path.resize( len );
|
|
break;
|
|
}; // if
|
|
|
|
// Oops, buffer is too small.
|
|
if ( count > 0 ) {
|
|
-- count;
|
|
// Enlarge the buffer.
|
|
path.resize( path.size() * 2 );
|
|
} else {
|
|
log_error(
|
|
"ERROR: Getting executable path failed: "
|
|
"Reading symlink `%s' failed: Buffer of %lu bytes is still too small\n",
|
|
exe.c_str(),
|
|
(unsigned long) path.size()
|
|
);
|
|
exit( 2 );
|
|
}; // if
|
|
|
|
}; // forever
|
|
|
|
return std::string( & path.front(), path.size() );
|
|
|
|
} // exe_path
|
|
|
|
|
|
std::string
|
|
exe_dir(
|
|
) {
|
|
std::string path = exe_path();
|
|
// We cannot pass path.c_str() to `dirname' bacause `dirname' modifies its argument.
|
|
buffer_t buffer( path.c_str(), path.c_str() + path.size() + 1 ); // Copy with trailing zero.
|
|
return dirname( & buffer.front() );
|
|
} // exe_dir
|
|
|
|
#endif // __linux__
|
|
|
|
// -------------------------------------------------------------------------------------------------
|
|
// MS Windows
|
|
// -------------------------------------------------------------------------------------------------
|
|
|
|
#if defined( _WIN32 )
|
|
|
|
|
|
#include <windows.h>
|
|
#if defined( max )
|
|
#undef max
|
|
#endif
|
|
|
|
#include <cctype>
|
|
#include <algorithm>
|
|
|
|
|
|
static
|
|
std::string
|
|
_err_msg(
|
|
int err,
|
|
int level
|
|
) {
|
|
|
|
std::string msg;
|
|
|
|
LPSTR buffer = NULL;
|
|
DWORD flags =
|
|
FORMAT_MESSAGE_ALLOCATE_BUFFER |
|
|
FORMAT_MESSAGE_FROM_SYSTEM |
|
|
FORMAT_MESSAGE_IGNORE_INSERTS;
|
|
|
|
DWORD len =
|
|
FormatMessageA(
|
|
flags,
|
|
NULL,
|
|
err,
|
|
LANG_USER_DEFAULT,
|
|
reinterpret_cast< LPSTR >( & buffer ),
|
|
0,
|
|
NULL
|
|
);
|
|
|
|
if ( buffer == NULL || len == 0 ) {
|
|
|
|
int _err = GetLastError();
|
|
char str[1024] = { 0 };
|
|
snprintf(str, sizeof(str), "Error 0x%08x (Getting error message failed: %s )", err, ( level < 2 ? _err_msg( _err, level + 1 ).c_str() : "Oops" ));
|
|
msg = std::string(str);
|
|
|
|
} else {
|
|
|
|
// Trim trailing whitespace (including `\r' and `\n').
|
|
while ( len > 0 && isspace( buffer[ len - 1 ] ) ) {
|
|
-- len;
|
|
}; // while
|
|
|
|
// Drop trailing full stop.
|
|
if ( len > 0 && buffer[ len - 1 ] == '.' ) {
|
|
-- len;
|
|
}; // if
|
|
|
|
msg.assign( buffer, len );
|
|
|
|
}; //if
|
|
|
|
if ( buffer != NULL ) {
|
|
LocalFree( buffer );
|
|
}; // if
|
|
|
|
return msg;
|
|
|
|
} // _get_err_msg
|
|
|
|
|
|
std::string
|
|
dir_sep(
|
|
) {
|
|
return "\\";
|
|
} // dir_sep
|
|
|
|
|
|
std::string
|
|
exe_path(
|
|
) {
|
|
|
|
buffer_t path( _size );
|
|
int count = _count;
|
|
|
|
for ( ; ; ) {
|
|
|
|
DWORD len = GetModuleFileNameA( NULL, & path.front(), path.size() );
|
|
|
|
if ( len == 0 ) {
|
|
int err = GetLastError();
|
|
log_error( "ERROR: Getting executable path failed: %s\n", err_msg( err ).c_str() );
|
|
exit( 2 );
|
|
}; // if
|
|
|
|
if ( len < path.size() ) {
|
|
path.resize( len );
|
|
break;
|
|
}; // if
|
|
|
|
// Buffer too small.
|
|
if ( count > 0 ) {
|
|
-- count;
|
|
path.resize( path.size() * 2 );
|
|
} else {
|
|
log_error(
|
|
"ERROR: Getting executable path failed: "
|
|
"Buffer of %lu bytes is still too small\n",
|
|
(unsigned long) path.size()
|
|
);
|
|
exit( 2 );
|
|
}; // if
|
|
|
|
}; // forever
|
|
|
|
return std::string( & path.front(), path.size() );
|
|
|
|
} // exe_path
|
|
|
|
|
|
std::string
|
|
exe_dir(
|
|
) {
|
|
|
|
std::string exe = exe_path();
|
|
int count = 0;
|
|
|
|
// Splitting path into components.
|
|
buffer_t drv( _MAX_DRIVE );
|
|
buffer_t dir( _MAX_DIR );
|
|
count = _count;
|
|
#if defined(_MSC_VER)
|
|
for ( ; ; ) {
|
|
int rc =
|
|
_splitpath_s(
|
|
exe.c_str(),
|
|
& drv.front(), drv.size(),
|
|
& dir.front(), dir.size(),
|
|
NULL, 0, // We need neither name
|
|
NULL, 0 // nor extension
|
|
);
|
|
if ( rc == 0 ) {
|
|
break;
|
|
} else if ( rc == ERANGE ) {
|
|
if ( count > 0 ) {
|
|
-- count;
|
|
// Buffer is too small, but it is not clear which one.
|
|
// So we have to enlarge all.
|
|
drv.resize( drv.size() * 2 );
|
|
dir.resize( dir.size() * 2 );
|
|
} else {
|
|
log_error(
|
|
"ERROR: Getting executable path failed: "
|
|
"Splitting path `%s' to components failed: "
|
|
"Buffers of %lu and %lu bytes are still too small\n",
|
|
exe.c_str(),
|
|
(unsigned long) drv.size(),
|
|
(unsigned long) dir.size()
|
|
);
|
|
exit( 2 );
|
|
}; // if
|
|
} else {
|
|
log_error(
|
|
"ERROR: Getting executable path failed: "
|
|
"Splitting path `%s' to components failed: %s\n",
|
|
exe.c_str(),
|
|
err_msg( rc ).c_str()
|
|
);
|
|
exit( 2 );
|
|
}; // if
|
|
}; // forever
|
|
|
|
#else // __MINGW32__
|
|
|
|
// MinGW does not have the "secure" _splitpath_s, use the insecure version instead.
|
|
_splitpath(
|
|
exe.c_str(),
|
|
& drv.front(),
|
|
& dir.front(),
|
|
NULL, // We need neither name
|
|
NULL // nor extension
|
|
);
|
|
#endif // __MINGW32__
|
|
|
|
// Combining components back to path.
|
|
// I failed with "secure" `_makepath_s'. If buffer is too small, instead of returning
|
|
// ERANGE, `_makepath_s' pops up dialog box and offers to debug the program. D'oh!
|
|
// So let us try to guess the size of result and go with insecure `_makepath'.
|
|
buffer_t path( std::max( drv.size() + dir.size(), size_t( _MAX_PATH ) ) + 10 );
|
|
_makepath( & path.front(), & drv.front(), & dir.front(), NULL, NULL );
|
|
|
|
return & path.front();
|
|
|
|
} // exe_dir
|
|
|
|
|
|
#endif // _WIN32
|
|
|
|
|
|
std::string
|
|
err_msg(
|
|
int err
|
|
) {
|
|
|
|
return _err_msg( err, 0 );
|
|
|
|
} // err_msg
|
|
|
|
|
|
// =================================================================================================
|
|
// C interface.
|
|
// =================================================================================================
|
|
|
|
|
|
char *
|
|
get_err_msg(
|
|
int err
|
|
) {
|
|
char * msg = strdup( err_msg( err ).c_str() );
|
|
CHECK_PTR( msg );
|
|
return msg;
|
|
} // get_err_msg
|
|
|
|
|
|
char *
|
|
get_dir_sep(
|
|
) {
|
|
char * sep = strdup( dir_sep().c_str() );
|
|
CHECK_PTR( sep );
|
|
return sep;
|
|
} // get_dir_sep
|
|
|
|
|
|
char *
|
|
get_exe_path(
|
|
) {
|
|
char * path = strdup( exe_path().c_str() );
|
|
CHECK_PTR( path );
|
|
return path;
|
|
} // get_exe_path
|
|
|
|
|
|
char *
|
|
get_exe_dir(
|
|
) {
|
|
char * dir = strdup( exe_dir().c_str() );
|
|
CHECK_PTR( dir );
|
|
return dir;
|
|
} // get_exe_dir
|
|
|
|
|
|
// end of file //
|