mirror of
https://github.com/zebrajr/pytorch.git
synced 2025-12-07 12:21:27 +01:00
Summary: We have encountered `std::bad_cast` error when running PyTorch binary built with cxx11 abi on CentOS7, stack trace: ``` #0 0x00007fec10160207 in raise () from /lib64/libc.so.6 #1 0x00007fec101618f8 in abort () from /lib64/libc.so.6 #2 0x00007fec015767d5 in __gnu_cxx::__verbose_terminate_handler() () from /lib64/libstdc++.so.6 #3 0x00007fec01574746 in ?? () from /lib64/libstdc++.so.6 #4 0x00007fec01574773 in std::terminate() () from /lib64/libstdc++.so.6 #5 0x00007fec01574993 in __cxa_throw () from /lib64/libstdc++.so.6 #6 0x00007fec015c94d2 in std::__throw_bad_cast() () from /lib64/libstdc++.so.6 #7 0x00007feb2ab3c2d7 in std::__cxx11::numpunct<char> const& std::use_facet<std::__cxx11::numpunct<char> >(std::locale const&) () from /root/.local/lib/python2.7/site-packages/torch/lib/libcaffe2.so #8 0x00007feb28643d62 in torch::jit::script::strtod_c(char const*, char**) () from /root/.local/lib/python2.7/site-packages/torch/lib/libcaffe2.so ``` We are suspecting this line will get compiled to gcc abi dependent symbol: ``` char decimal_point = std::use_facet<std::numpunct<char>>(std::locale()).decimal_point(); ``` Pull Request resolved: https://github.com/pytorch/pytorch/pull/21293 Differential Revision: D15609910 Pulled By: bddppq fbshipit-source-id: e247059729863868e4b36d6fec4fcbc36fbc4bb1
267 lines
6.7 KiB
C++
267 lines
6.7 KiB
C++
// Taken from https://github.com/JuliaLang/julia/blob/v1.1.0/src/support/strtod.c
|
|
|
|
#include <stdlib.h>
|
|
#include <locale.h>
|
|
#include <ATen/core/Macros.h>
|
|
|
|
#if defined(__APPLE__) || defined(__FreeBSD__)
|
|
#include <xlocale.h>
|
|
#endif
|
|
|
|
// The following code is derived from the Python function _PyOS_ascii_strtod
|
|
// see http://hg.python.org/cpython/file/default/Python/pystrtod.c
|
|
//
|
|
// Copyright © 2001-2014 Python Software Foundation; All Rights Reserved
|
|
//
|
|
// The following modifications have been made:
|
|
// - Leading spaces are ignored
|
|
// - Parsing of hex floats is supported in the derived version
|
|
// - Python functions for tolower, isdigit and malloc have been replaced by the respective
|
|
// C stdlib functions
|
|
|
|
#include <ctype.h>
|
|
#include <errno.h>
|
|
#include <math.h>
|
|
#include <string.h>
|
|
#include <locale>
|
|
|
|
#define D_PNAN ((double)+NAN)
|
|
#define D_PINF ((double)+INFINITY)
|
|
|
|
namespace {
|
|
int case_insensitive_match(const char *s, const char *t)
|
|
{
|
|
while (*t && tolower(*s) == *t) {
|
|
s++;
|
|
t++;
|
|
}
|
|
return *t ? 0 : 1;
|
|
}
|
|
|
|
double parse_inf_or_nan(const char *p, char **endptr)
|
|
{
|
|
double retval;
|
|
const char *s;
|
|
int negate = 0;
|
|
|
|
s = p;
|
|
if (*s == '-') {
|
|
negate = 1;
|
|
s++;
|
|
}
|
|
else if (*s == '+') {
|
|
s++;
|
|
}
|
|
if (case_insensitive_match(s, "inf")) {
|
|
s += 3;
|
|
if (case_insensitive_match(s, "inity"))
|
|
s += 5;
|
|
retval = negate ? -D_PINF : D_PINF;
|
|
}
|
|
else if (case_insensitive_match(s, "nan")) {
|
|
s += 3;
|
|
retval = negate ? -D_PNAN : D_PNAN;
|
|
}
|
|
else {
|
|
s = p;
|
|
retval = -1.0;
|
|
}
|
|
*endptr = (char *)s;
|
|
return retval;
|
|
}
|
|
|
|
}
|
|
|
|
namespace torch {
|
|
namespace jit {
|
|
namespace script {
|
|
|
|
#ifdef _MSC_VER
|
|
C10_EXPORT double strtod_c(const char *nptr, char **endptr)
|
|
{
|
|
static _locale_t loc = _create_locale(LC_ALL, "C");
|
|
return _strtod_l(nptr, endptr, loc);
|
|
}
|
|
#elif defined(__ANDROID__)
|
|
C10_EXPORT double strtod_c(const char *nptr, char **endptr)
|
|
{
|
|
char *fail_pos;
|
|
double val;
|
|
const char *p, *decimal_point_pos;
|
|
const char *end = NULL; /* Silence gcc */
|
|
const char *digits_pos = NULL;
|
|
int negate = 0;
|
|
|
|
fail_pos = NULL;
|
|
|
|
char decimal_point = std::use_facet<std::numpunct<char>>(std::locale()).decimal_point();
|
|
|
|
decimal_point_pos = NULL;
|
|
|
|
/* Parse infinities and nans */
|
|
val = parse_inf_or_nan(nptr, endptr);
|
|
if (*endptr != nptr)
|
|
return val;
|
|
|
|
/* Set errno to zero, so that we can distinguish zero results
|
|
and underflows */
|
|
errno = 0;
|
|
|
|
/* We process the optional sign manually, then pass the remainder to
|
|
the system strtod. This ensures that the result of an underflow
|
|
has the correct sign. */
|
|
p = nptr;
|
|
|
|
/* parse leading spaces */
|
|
while (isspace((unsigned char)*p)) {
|
|
p++;
|
|
}
|
|
|
|
/* Process leading sign, if present */
|
|
if (*p == '-') {
|
|
negate = 1;
|
|
p++;
|
|
}
|
|
else if (*p == '+') {
|
|
p++;
|
|
}
|
|
|
|
/* This code path is used for hex floats */
|
|
if (*p == '0' && (*(p+1) == 'x' || *(p+1) == 'X')) {
|
|
digits_pos = p;
|
|
p += 2;
|
|
/* Check that what's left begins with a digit or decimal point */
|
|
if (!isxdigit(*p) && *p != '.')
|
|
goto invalid_string;
|
|
|
|
|
|
if (decimal_point != '.') {
|
|
/* Look for a '.' in the input; if present, it'll need to be
|
|
swapped for the current locale's decimal point before we
|
|
call strtod. On the other hand, if we find the current
|
|
locale's decimal point then the input is invalid. */
|
|
while (isxdigit(*p))
|
|
p++;
|
|
|
|
if (*p == '.') {
|
|
decimal_point_pos = p++;
|
|
|
|
/* locate end of number */
|
|
while (isxdigit(*p))
|
|
p++;
|
|
|
|
if (*p == 'p' || *p == 'P')
|
|
p++;
|
|
if (*p == '+' || *p == '-')
|
|
p++;
|
|
while (isdigit(*p))
|
|
p++;
|
|
end = p;
|
|
}
|
|
else if (*p == decimal_point)
|
|
goto invalid_string;
|
|
/* For the other cases, we need not convert the decimal point */
|
|
}
|
|
}
|
|
else {
|
|
/* Check that what's left begins with a digit or decimal point */
|
|
if (!isdigit(*p) && *p != '.')
|
|
goto invalid_string;
|
|
|
|
digits_pos = p;
|
|
if (decimal_point != '.') {
|
|
/* Look for a '.' in the input; if present, it'll need to be
|
|
swapped for the current locale's decimal point before we
|
|
call strtod. On the other hand, if we find the current
|
|
locale's decimal point then the input is invalid. */
|
|
while (isdigit(*p))
|
|
p++;
|
|
|
|
if (*p == '.') {
|
|
decimal_point_pos = p++;
|
|
|
|
/* locate end of number */
|
|
while (isdigit(*p))
|
|
p++;
|
|
|
|
if (*p == 'e' || *p == 'E')
|
|
p++;
|
|
if (*p == '+' || *p == '-')
|
|
p++;
|
|
while (isdigit(*p))
|
|
p++;
|
|
end = p;
|
|
}
|
|
else if (*p == decimal_point)
|
|
goto invalid_string;
|
|
/* For the other cases, we need not convert the decimal point */
|
|
}
|
|
}
|
|
|
|
if (decimal_point_pos) {
|
|
char *copy, *c;
|
|
/* Create a copy of the input, with the '.' converted to the
|
|
locale-specific decimal point */
|
|
copy = (char *)malloc(end - digits_pos + 2);
|
|
if (copy == NULL) {
|
|
*endptr = (char *)nptr;
|
|
errno = ENOMEM;
|
|
return val;
|
|
}
|
|
|
|
c = copy;
|
|
memcpy(c, digits_pos, decimal_point_pos - digits_pos);
|
|
c += decimal_point_pos - digits_pos;
|
|
memcpy(c, &decimal_point, 1);
|
|
c += 1;
|
|
memcpy(c, decimal_point_pos + 1,
|
|
end - (decimal_point_pos + 1));
|
|
c += end - (decimal_point_pos + 1);
|
|
*c = 0;
|
|
|
|
val = strtod(copy, &fail_pos);
|
|
|
|
if (fail_pos)
|
|
{
|
|
fail_pos = (char *)digits_pos +
|
|
(fail_pos - copy);
|
|
}
|
|
|
|
free(copy);
|
|
}
|
|
else {
|
|
val = strtod(digits_pos, &fail_pos);
|
|
}
|
|
|
|
if (fail_pos == digits_pos)
|
|
goto invalid_string;
|
|
|
|
if (negate && fail_pos != nptr)
|
|
val = -val;
|
|
*endptr = fail_pos;
|
|
|
|
return val;
|
|
|
|
invalid_string:
|
|
*endptr = (char*)nptr;
|
|
errno = EINVAL;
|
|
return -1.0;
|
|
}
|
|
#else
|
|
C10_EXPORT double strtod_c(const char* nptr, char** endptr) {
|
|
/// NOLINTNEXTLINE(hicpp-signed-bitwise)
|
|
static locale_t loc = newlocale(LC_ALL_MASK, "C", nullptr);
|
|
return strtod_l(nptr, endptr, loc);
|
|
}
|
|
#endif
|
|
|
|
|
|
C10_EXPORT float strtof_c(const char *nptr, char **endptr)
|
|
{
|
|
return (float) strtod_c(nptr, endptr);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|