Skip to content

al_plugin_begin_timerange_action is unreachable from the public C ABI due to a declaration/definition signature mismatch #76

Description

@yohannmarguier

Title

al_plugin_begin_timerange_action is unreachable from the public C ABI due to a declaration/definition signature mismatch

Body

Summary

al_plugin_begin_timerange_action is declared in include/al_lowlevel.h with extern "C" linkage, but its definition in src/al_lowlevel.cpp uses a different parameter type for dtime_shape. Because the two signatures don't match, the compiler treats them as two unrelated overloads: the declared (extern "C") version is never defined, and the defined version gets ordinary C++ linkage instead. The net effect is that the function documented in the public header does not exist in the compiled library under a callable C symbol.

Evidence

Header declaration (include/al_lowlevel.h:345-353, on develop @ ad0f2e2):

IMAS_CORE_LIBRARY_API al_status_t al_plugin_begin_timerange_action(int ctx,
                     const char *dataobjectname,
                     int rwmode,
                     double tmin,
                     double tmax,
                     const double* dtime,
                     const double* dtime_shape,   // <-- double*
                     int interpmode,
                     int *opctx);

Definition (src/al_lowlevel.cpp:1045-1046):

al_status_t al_plugin_begin_timerange_action(int pctxID, const char* dataobjectname, int rwmode,
                   double tmin, double tmax, const double* dtime_buffer, const int* dtime_shape, int interpmode, int *octxID)
                                                                          // <-- int*

Both lines were changed in the same commit (1917f25c, 2024-07-03), which is presumably where the type diverged.

Confirmed via the compiled librarynm -gU on libal.dylib shows no plain-C symbol _al_plugin_begin_timerange_action. Instead there's a C++-mangled symbol:

__Z32al_plugin_begin_timerange_actioniPKciddPKdPKiiPi

i.e. the function that actually got compiled has C++ linkage, not the extern "C" linkage the header promises.

dtime_shape is clearly meant to be an element count, not a data value — inside al_begin_timerange_action (the sibling, correctly-working, publicly-callable function, src/al_lowlevel.cpp:1502-1510), the equivalent parameter is dereferenced as a count:

al_status_t al_begin_timerange_action(int pctxID, const char* dataobjectname, int rwmode,
                   double tmin, double tmax, const double* dtime_buffer, const int* dtime_shape, int interpmode, int *octxID)
{
  ...
  std::vector<double> dtime;
  if (*dtime_shape > 0)
    dtime = std::vector<double> (dtime_buffer, dtime_buffer + *dtime_shape);

al_begin_timerange_action itself already declares dtime_shape as const int* in both its header declaration (include/al_lowlevel.h:481) and its definition — consistent with the .cpp definition of al_plugin_begin_timerange_action, and inconsistent only with that one header declaration.

What this does not break

To be precise about scope: this does not break time-range reads/writes for ordinary callers, and it does not break plugin dispatch during a time-range operation. al_begin_timerange_action (the plain, User-facing function) calls al_plugin_begin_timerange_action internally — as an ordinary same-translation-unit C++ call, which resolves correctly regardless of the extern "C" mismatch — and separately dispatches to any bound plugin's begin_timerange_action via LLplugin::beginTimeRangeActionPlugin (al_lowlevel.cpp:471). Both of those paths work fine today.

Impact

al_plugin_begin_timerange_action mirrors a family of functions (al_plugin_begin_global_action, al_plugin_begin_slice_action, al_plugin_read_data, al_plugin_write_data, …) that exist so external code linked against this library — e.g. a plugin author's own compiled plugin — can re-enter the low-level layer (per docs/source/developers/plugins_architecture.rst, "Calling low level data access API functions from plugin code": these avoid infinite recursion when a plugin needs to fetch/write the underlying data from within its own read_data()/write_data()/begin_*_action() implementation). The sibling functions in this family are genuinely used this way today — e.g. access_layer_plugin_manager.cpp calls al_plugin_read_data/al_plugin_write_data externally across translation units for provenance metadata handling.

al_plugin_begin_timerange_action is not currently called this way by anything in this repository (no caller outside al_lowlevel.cpp itself, not wrapped in the Python bindings, no test exercises it), so today this bug has no observable effect — it's latent, not active. But it means the declared public capability is currently non-functional: if any external caller (an HLI, or a plugin author needing reentrant time-range access, matching the existing pattern for global/slice/read/write) ever links against al_plugin_begin_timerange_action as documented, they will get an undefined-symbol error at link time.

The three sibling al_plugin_begin_*_action functions (global, slice, arraystruct) are unaffected — their header/definition signatures match and they're confirmed present as plain C symbols in the compiled library.

Suggested fix

In include/al_lowlevel.h:351, change:

const double* dtime_shape,

to:

const int* dtime_shape,

matching the .cpp definition and the sibling al_begin_timerange_action declaration. This is a minimal, low-risk fix since it only affects a currently-unused declared symbol.

Alternatively, since nothing currently uses this reentry path, maintainers may prefer to confirm whether it's still intended to be supported at all before fixing vs. removing it — raising as an issue rather than a PR so that decision can be made first.

Environment

  • Found on develop @ ad0f2e2910dac8dfd552e1f8ec67e8b4ac70162c
  • macOS, Clang (Apple's nm/dlyib toolchain), but this is a source-level signature mismatch, not platform-specific

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions