Skip to content

[DOC] Verify and document error message string lifetime semantics #25

@tazarov

Description

@tazarov

Description

The getErrorMessage() function's implementation assumes certain lifetime semantics for the string returned by ONNX Runtime's GetErrorMessage() C API. We need to verify these assumptions against the official documentation and add clarifying comments.

Current Implementation

File: ort/environment.go:32-38

func getErrorMessage(status uintptr) string {
    if status == 0 || getErrorMessageFunc == nil {
        return ""
    }
    
    msgPtr := getErrorMessageFunc(status)
    return CstringToGo(msgPtr)
}

Question: String Lifetime Semantics

The current code immediately converts the C string to Go string. This is correct IF one of these is true:

Option A: String is Valid Until ReleaseStatus() ✅

The error message pointer remains valid until ReleaseStatus(status) is called. This is the most common pattern in C APIs.

Current usage:

status := createEnv(...)
if status != 0 {
    errMsg := getErrorMessage(status)  // ✅ Safe before ReleaseStatus
    releaseStatus(status)              // After this, msgPtr would be invalid
    return fmt.Errorf("...: %s", errMsg)  // ✅ Safe, already copied to Go
}

Option B: String is Static/Global ✅

The error message is a static string that never needs freeing. Less common but possible.

Option C: String is Transient ⚠️

The pointer is only valid during the GetErrorMessage call itself, or becomes invalid on any other ORT API call.

If Option C is true, our current code might have a bug where the string gets invalidated between getErrorMessage() call and the CstringToGo() conversion.

Required Actions

1. Verify Against Official Documentation

Check the ONNX Runtime C API documentation:

  • Read onnxruntime_c_api.h
  • Look for lifetime documentation on OrtApi::GetErrorMessage
  • Check for any examples in official ORT repo

2. Add Documentation to Code

Once verified, add a comment explaining the semantics:

// getErrorMessage extracts the error message from an ORT status code.
// Returns empty string if status is 0 (success) or if the function is not initialized.
//
// String Lifetime: The error message pointer returned by ORT's GetErrorMessage 
// remains valid until ReleaseStatus() is called on the status object.
// We immediately copy it to a Go string, so it's safe to call ReleaseStatus 
// afterward without invalidating our copy.
//
// Reference: ORT C API documentation at onnxruntime_c_api.h
func getErrorMessage(status uintptr) string {
    // ...
}

3. Add Test If Necessary

If the semantics are unclear, add an integration test that:

  1. Creates an error condition
  2. Gets the error message
  3. Releases the status
  4. Verifies the Go string is still valid

Expected Outcome

Based on typical C API patterns and our code review, we expect Option A is correct:

  • Error message is valid until ReleaseStatus()
  • Our immediate copy to Go string is safe
  • No changes needed to implementation, just documentation

But we should verify this to be certain.

Impact

Risk Level: Low

  • Current code likely works correctly
  • This is defensive verification and documentation
  • Would only be a problem if ORT has unusual lifetime semantics

Priority: Low-Medium

  • Should be done before v1.0 for confidence
  • Not blocking for development/testing use

Related Issues

Acceptance Criteria

  • Verified error message lifetime from official ORT documentation
  • Added clear documentation comment to getErrorMessage()
  • If needed, added test to verify assumption
  • Documented in code review checklist for future ORT API additions

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions