Skip to content

Commit 3acecd9

Browse files
ErjieWuclaude
andcommitted
fix: restore Linux link of FFT_CPU<float> and harden parse_expression
Two issues from code review of the Windows-port commits: 1. FFT_CPU<float> undefined references on Linux (regression). The port removed __attribute__((weak)) from the FFT virtuals (it left null vtable slots on PE/MinGW and crashed). But the real FFT_CPU<float> methods live in fft_cpu_float.cpp, which is compiled only when ENABLE_FLOAT_FFTW=ON. With weak gone and float off (the Linux default), the FFT_CPU<float> vtable -- still emitted wherever the class is constructed (FFT_Bundle) -- referenced undefined symbols: undefined reference to `ModuleBase::FFT_CPU<float>::setupFFT()' ... Provide trivial FFT_CPU<float> method definitions in the always-compiled fft_cpu.cpp, guarded by `#if !defined(__ENABLE_FLOAT_FFTW)`, so every vtable slot is valid on any ABI without weak and without pulling in libfftw3f. The float CPU path stays unreachable at runtime (FFT_Bundle::setupFFT WARNING_QUITs for single/mixing CPU FFT unless the macro is set). When the macro is on, the stubs are excluded and fft_cpu_float.cpp supplies the real definitions -- no duplicate symbols. Verified by linking the float vtable TU against fft_cpu.o in both macro states (off: links via stubs; on: links via fft_cpu_float.o), and that dropping both reproduces the reported errors. 2. parse_expression (input_conv.h) could push indeterminate values into vec. If std::regex_search found no match, sub_str stayed empty and was parsed anyway; in the non-multiplication branch `T occ` was uninitialized and the `convert >> occ` extraction was unchecked. Now: a no-match token is an input error (WARNING_QUIT), occ is value-initialized, and a failed extraction fails fast. Consistent with the other expression parsers. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
1 parent 763f788 commit 3acecd9

2 files changed

Lines changed: 47 additions & 7 deletions

File tree

source/source_base/module_fft/fft_cpu.cpp

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -508,13 +508,38 @@ void FFT_CPU<double>::fftxyc2r(std::complex<double> *in,double *out) const
508508
}
509509
}
510510

511-
template <> double*
511+
template <> double*
512512
FFT_CPU<double>::get_rspace_data() const {return d_rspace;}
513-
template <> std::complex<double>*
513+
template <> std::complex<double>*
514514
FFT_CPU<double>::get_auxr_data() const {return z_auxr;}
515-
template <> std::complex<double>*
515+
template <> std::complex<double>*
516516
FFT_CPU<double>::get_auxg_data() const {return z_auxg;}
517517

518+
#if !defined(__ENABLE_FLOAT_FFTW)
519+
// When single-precision FFTW is disabled, the real FFT_CPU<float> methods
520+
// (in fft_cpu_float.cpp) are not compiled -- but the FFT_CPU<float> vtable is
521+
// still emitted wherever the class is constructed (e.g. FFT_Bundle::setupFFT,
522+
// and the explicit ctor/dtor instantiations below). Provide trivial
523+
// definitions so every vtable slot is valid on any linker/ABI. This replaces
524+
// the former __attribute__((weak)) declarations, which relied on the ELF
525+
// linker resolving undefined weak symbols to null -- a behaviour PE/MinGW does
526+
// not share (it left null vtable slots and crashed on first dispatch). The
527+
// float CPU path is never taken at runtime without __ENABLE_FLOAT_FFTW:
528+
// FFT_Bundle::setupFFT calls WARNING_QUIT for a single/mixing CPU FFT first.
529+
template <> void FFT_CPU<float>::setupFFT() {}
530+
template <> void FFT_CPU<float>::cleanFFT() {}
531+
template <> void FFT_CPU<float>::clear() {}
532+
template <> float* FFT_CPU<float>::get_rspace_data() const { return nullptr; }
533+
template <> std::complex<float>* FFT_CPU<float>::get_auxr_data() const { return nullptr; }
534+
template <> std::complex<float>* FFT_CPU<float>::get_auxg_data() const { return nullptr; }
535+
template <> void FFT_CPU<float>::fftxyfor(std::complex<float>*, std::complex<float>*) const {}
536+
template <> void FFT_CPU<float>::fftxybac(std::complex<float>*, std::complex<float>*) const {}
537+
template <> void FFT_CPU<float>::fftzfor(std::complex<float>*, std::complex<float>*) const {}
538+
template <> void FFT_CPU<float>::fftzbac(std::complex<float>*, std::complex<float>*) const {}
539+
template <> void FFT_CPU<float>::fftxyr2c(float*, std::complex<float>*) const {}
540+
template <> void FFT_CPU<float>::fftxyc2r(std::complex<float>*, float*) const {}
541+
#endif
542+
518543
template FFT_CPU<float>::FFT_CPU();
519544
template FFT_CPU<float>::~FFT_CPU();
520545
template FFT_CPU<double>::FFT_CPU();

source/source_io/module_parameter/input_conv.h

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -91,13 +91,22 @@ void parse_expression(const std::string& fn, std::vector<T>& vec)
9191
sub_str = match[0].str();
9292
}
9393

94+
// A token that matches nothing is invalid input. Fail fast instead of
95+
// feeding an empty string to the parsers below, which would push an
96+
// indeterminate value into vec.
97+
if (sub_str.empty())
98+
{
99+
ModuleBase::WARNING_QUIT("Input_Conv::parse_expression",
100+
"invalid token in expression: \"" + str[i] + "\"");
101+
}
102+
94103
// Check if the substring contains multiplication (e.g., "2*3.14")
95104
if (sub_str.find('*') != std::string::npos)
96105
{
97106
size_t pos = sub_str.find("*");
98107
int num = stoi(sub_str.substr(0, pos));
99108
assert(num >= 0);
100-
T occ = stof(sub_str.substr(pos + 1, sub_str.size()));
109+
T occ = static_cast<T>(stof(sub_str.substr(pos + 1, sub_str.size())));
101110

102111
// Add the value to the vector `num` times
103112
for (size_t k = 0; k != num; k++)
@@ -107,11 +116,17 @@ void parse_expression(const std::string& fn, std::vector<T>& vec)
107116
}
108117
else
109118
{
110-
// Handle scientific notation and convert to T
119+
// Handle scientific notation and convert to T. Initialize occ and
120+
// check the extraction so a malformed token fails fast rather than
121+
// pushing an indeterminate value.
111122
std::stringstream convert;
112123
convert << sub_str;
113-
T occ;
114-
convert >> occ;
124+
T occ{};
125+
if (!(convert >> occ))
126+
{
127+
ModuleBase::WARNING_QUIT("Input_Conv::parse_expression",
128+
"failed to parse number: \"" + sub_str + "\"");
129+
}
115130
vec.emplace_back(occ);
116131
}
117132
}

0 commit comments

Comments
 (0)