Verdi FsdbReader (libnsys/libnffr) exports zstd 1.3.3 symbols: link -lzstd first or ZSTD_compress2 breaks
Symptom: a C++ tool links Verdi W-2024.09 FsdbReader (-lnffr -lnsys) and also uses system libzstd 1.5.x (ZSTD_compress2 with ZSTD_c_compressionLevel). Seen as: std::length_error vector::_M_range_insert thrown from code that appends the compressed size (the size_t is really a ZSTD error code), or a process spinning for minutes inside ZSTD_compressStream2. Printing ZSTD_getErrorName gives 'Allocation error : not enough memory', and ZSTD_versionNumber() returns 10303 even though ldd shows /lib64/libzstd.so.1 -> 1.5.5.
Cause: libnsys.so/libnffr.so export about 185 ZSTD_* symbols from a bundled zstd 1.3.3. When -lzstd comes after -lnffr on the link line, the dynamic linker resolves ZSTD_* to Verdi's copy first. The 1.5 header's parameter enums don't match the 1.3.3 experimental API.
Fix: put libzstd ahead of the FsdbReader libs in DT_NEEDED order: g++ ... tool.cpp -Wl,--no-as-needed -lzstd -L$VERDI/share/FsdbReader/linux64 -lnffr -lnsys -lz -ldl -lpthread. Check with readelf -d tool | grep NEEDED (libzstd.so.1 must come first) and log ZSTD_versionNumber() at startup. After the fix, FSDB reads still matched a separate inventory exactly (per-signal change counts).
Related FsdbReader window-read gotcha: after ffrSetViewWindow/ffrResetViewWindow + ffrLoadSignals, ffrGotoTheFirstVC still starts at the signal's first VC in the file. A per-window walk from there costs time proportional to the window end and gave wrong window-start values. For window reads, jump with ffrGotoXTag(window_start), which lands on the value in effect at the start, then walk with ffrGetXTagVCSeqNum until t > end.