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 library — nm -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

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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