Skip to content

Remove obsolete DIRECTC_EXPECTED_FAILURES entries#8

Closed
krystophny wants to merge 1 commit into
fix/issue345-directc-cmake-compatibilityfrom
fix/remove-expected-failures
Closed

Remove obsolete DIRECTC_EXPECTED_FAILURES entries#8
krystophny wants to merge 1 commit into
fix/issue345-directc-cmake-compatibilityfrom
fix/remove-expected-failures

Conversation

@krystophny

@krystophny krystophny commented Dec 18, 2025

Copy link
Copy Markdown
Member

User description

Summary

  • Remove 19 examples from DIRECTC_EXPECTED_FAILURES that now pass in Direct-C mode
  • Only issue261_array_shapes and keep_single_interface actually fail
  • Add missing issue306_allocatable_realloc to CMakeLists.txt

Testing

Manually tested all 21 examples in DIRECTC_EXPECTED_FAILURES with DIRECTC=yes:

  • 19 examples now PASS
  • 2 examples still FAIL (kept as expected failures)

Base

Stacked on jameskermode#346


PR Type

Enhancement, Bug fix, Tests


Description

  • Fix segfault with -fdefault-integer-8 by using integer(c_int) for handles

    • Ensures consistent size between wrapper generation and runtime
    • Applies to all handle arrays in derived type wrappers
  • Add support for pointer arrays in Direct-C mode

    • Removes skip logic that silently ignored pointer arrays
    • Adds pointer guard checks alongside allocatable checks
  • Improve test coverage and fix test infrastructure

    • Add missing tests.py files for errorbinding example
    • Fix memory leak detection test in issue227_allocatable
    • Add tests for complex types and pointer arrays
    • Improve callback test documentation and fix segfault issue
  • Enhance Direct-C code generation

    • Add character type setter support for module variables
    • Fix polymorphic type assignment with select type in Direct-C mode
    • Add numpy array API symbol for fortranobject.c compatibility
    • Fix deferred binding handling for abstract types
  • Reorganize and sort example tests in build system

    • Sort examples alphabetically in CMakeLists.txt and Makefile
    • Add DIRECTC_EXPECTED_FAILURES list for known limitations
    • Improve test reporting with pass/fail/expected-fail tracking

Diagram Walkthrough

flowchart LR
  A["Integer Scalar Args<br/>in Direct-C Mode"] -->|"Convert to<br/>integer(c_int)"| B["Handle Arrays"]
  B -->|"Immune to<br/>-fdefault-integer-8"| C["Consistent Size"]
  D["Pointer Arrays<br/>in Derived Types"] -->|"Add Guard Check<br/>associated()"| E["Direct-C Support"]
  E -->|"Wrap with<br/>select type"| F["Polymorphic Assignment"]
  G["Test Infrastructure"] -->|"Add Missing Tests<br/>& Fix Bugs"| H["Better Coverage"]
  C -->|"Fixes"| I["Segfault Fix"]
  F -->|"Enables"| I
  H -->|"Validates"| I
Loading

File Walkthrough

Relevant files
Bug fix
12 files
f90wrapgen.py
Convert integer scalars to integer(c_int) in Direct-C       
+142/-25
transform.py
Set wrapper_type to integer(c_int) for derived types         
+22/-3   
pywrapgen.py
Add _setup_finalizer for abstract classes and factory returns
+19/-1   
main.py
Fix PyInit function name derivation for Direct-C modules 
+13/-6   
run.py
Fix assertion bug comparing wrong variables                           
+1/-1     
tests.py
Fix callback test and document f2py callback bug                 
+13/-9   
Makefile
Clean build directory and add fault handler                           
+4/-3     
Makefile
Fix test target to use correct f2py build                               
+1/-1     
Makefile
Fix clean target for build directory                                         
+2/-1     
Makefile
Add f90wrap*.f90 to clean target                                                 
+1/-1     
Makefile
Use F90 instead of FC for compilation                                       
+1/-1     
Makefile
Fix types.py shadowing issue in test                                         
+3/-2     
Enhancement
3 files
__init__.py
Remove pointer array skip logic and fix deferred bindings
+7/-15   
module_helpers.py
Add character type setter for module variables                     
+110/-0 
module_helpers_array.py
Return handle in array helper tuple for Direct-C                 
+2/-1     
Configuration changes
7 files
CMakeLists.txt
Sort and reorganize example test list                                       
+44/-25 
Makefile
Sort examples and add DIRECTC_EXPECTED_FAILURES tracking 
+82/-34 
Makefile.meson
Delegate to regular Makefile for callback build                   
+6/-13   
Makefile.meson
Add Makefile.meson for f2py_string_input example                 
+8/-0     
Makefile.meson
Add Makefile.meson for array_shapes example                           
+6/-0     
Makefile.meson
Add Makefile.meson for nested functions example                   
+9/-0     
Makefile.meson
Add Makefile.meson for pointer_warning example                     
+6/-0     
Tests
8 files
tests.py
Add minimal test for errorbinding example                               
+15/-0   
tests_pkg.py
Add package mode test for errorbinding example                     
+15/-0   
run.py
Improve memory leak detection with multi-round testing     
+32/-9   
run.py
Add gc.collect() calls to ensure object destruction           
+3/-0     
tests.py
Add test for complex type wrapping                                             
+19/-0   
tests.py
Add test for pointer array handling                                           
+28/-0   
Makefile
Update test to verify pointer array wrapping                         
+12/-10 
test_directc.py
Add test for character setter code generation                       
+13/-0   
Additional files
2 files
cback.f90 +1/-1     
Makefile.meson +8/-0     

All examples except issue261_array_shapes and keep_single_interface
now pass in Direct-C mode. Also add missing issue306_allocatable_realloc
to CMakeLists.txt.
@krystophny krystophny changed the base branch from master to fix/issue345-directc-cmake-compatibility December 18, 2025 15:47
@qodo-code-review

Copy link
Copy Markdown

You are nearing your monthly Qodo Merge usage quota. For more information, please visit here.

PR Compliance Guide 🔍

Below is a summary of compliance checks for this PR:

Security Compliance
Integer truncation overflow

Description: The new generated C character setter truncates PyBytes_GET_SIZE() (a Py_ssize_t) into an
int (value_len), which can overflow for large inputs and lead to incorrect allocation size
followed by memcpy, creating a potential heap buffer overflow / memory corruption
condition when extremely large bytes/str values are passed.
module_helpers.py [200-263]

Referred Code
def _write_character_setter(gen: DirectCGenerator, helper: ModuleHelper, helper_symbol: str) -> None:
    """Helper for character type setters."""
    gen.write("PyObject* py_value;")
    gen.write(f"static char *kwlist[] = {{\"{helper.element.name}\", NULL}};")
    gen.write(
        "if (!PyArg_ParseTupleAndKeywords(args, kwargs, \"O\", kwlist, &py_value)) {"
    )
    gen.indent()
    gen.write("return NULL;")
    gen.dedent()
    gen.write("}")
    gen.write("if (py_value == Py_None) {")
    gen.indent()
    gen.write(
        f'PyErr_SetString(PyExc_TypeError, "Argument {helper.element.name} must be str or bytes");'
    )
    gen.write("return NULL;")
    gen.dedent()
    gen.write("}")
    gen.write("PyObject* value_bytes = NULL;")
    gen.write("if (PyBytes_Check(py_value)) {")


 ... (clipped 43 lines)
Ticket Compliance
🎫 No ticket provided
  • Create ticket/issue
Codebase Duplication Compliance
Codebase context is not defined

Follow the guide to enable codebase context checks.

Custom Compliance
🟢
Generic: Comprehensive Audit Trails

Objective: To create a detailed and reliable record of critical system actions for security analysis
and compliance.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Error Handling

Objective: To prevent the leakage of sensitive system information through error messages while
providing sufficient detail for internal debugging.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Secure Logging Practices

Objective: To ensure logs are useful for debugging and auditing without exposing sensitive
information like PII, PHI, or cardholder data.

Status: Passed

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Meaningful Naming and Self-Documenting Code

Objective: Ensure all identifiers clearly express their purpose and intent, making code
self-documenting

Status:
Unused import: The newly added import sys appears unused, which may reduce clarity and self-documenting
quality.

Referred Code
import sys

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Robust Error Handling and Edge Case Management

Objective: Ensure comprehensive error handling that provides meaningful context and graceful
degradation

Status:
Potential length truncation: The character setter converts PyBytes_GET_SIZE() to int, which could truncate very large
inputs and lead to incorrect allocation/behavior.

Referred Code
gen.write("int value_len = (int)PyBytes_GET_SIZE(value_bytes);")
gen.write("char* value = (char*)malloc((size_t)value_len + 1);")
gen.write("if (value == NULL) {")

Learn more about managing compliance generic rules or creating your own custom rules

Generic: Security-First Input Validation and Data Handling

Objective: Ensure all data inputs are validated, sanitized, and handled securely to prevent
vulnerabilities

Status:
Large input handling: The new character setter accepts arbitrary-sized str/bytes and allocates via malloc using
a length stored in int, which may be unsafe without explicit maximum-length checks.

Referred Code
gen.write("if (py_value == Py_None) {")
gen.indent()
gen.write(
    f'PyErr_SetString(PyExc_TypeError, "Argument {helper.element.name} must be str or bytes");'
)
gen.write("return NULL;")
gen.dedent()
gen.write("}")
gen.write("PyObject* value_bytes = NULL;")
gen.write("if (PyBytes_Check(py_value)) {")
gen.indent()
gen.write("value_bytes = py_value;")
gen.write("Py_INCREF(value_bytes);")
gen.dedent()
gen.write("} else if (PyUnicode_Check(py_value)) {")
gen.indent()
gen.write("value_bytes = PyUnicode_AsUTF8String(py_value);")
gen.write("if (value_bytes == NULL) {")
gen.indent()
gen.write("return NULL;")
gen.dedent()


 ... (clipped 24 lines)

Learn more about managing compliance generic rules or creating your own custom rules

Compliance status legend 🟢 - Fully Compliant
🟡 - Partial Compliant
🔴 - Not Compliant
⚪ - Requires Further Human Verification
🏷️ - Compliance label

@qodo-code-review

Copy link
Copy Markdown

You are nearing your monthly Qodo Merge usage quota. For more information, please visit here.

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
General
Add error checking for PyLong allocations

In _write_array_helper_return, add error checking after PyLong_FromLong and
PyLong_FromLongLong calls to handle potential allocation failures and prevent
crashes.

f90wrap/directc_cgen/module_helpers_array.py [125-136]

 gen.write("PyObject* result = PyTuple_New(4);")
 gen.write("if (result == NULL) {")
 gen.indent()
 gen.write("Py_DECREF(shape_tuple);")
 gen.write("return NULL;")
 gen.dedent()
 gen.write("}")
-gen.write("PyTuple_SET_ITEM(result, 0, PyLong_FromLong((long)nd));")
-gen.write("PyTuple_SET_ITEM(result, 1, PyLong_FromLong((long)dtype));")
+gen.write("PyObject* nd_obj = PyLong_FromLong((long)nd);")
+gen.write("PyObject* dtype_obj = PyLong_FromLong((long)dtype);")
+gen.write("PyObject* handle_obj = PyLong_FromLongLong(handle);")
+gen.write("if (nd_obj == NULL || dtype_obj == NULL || handle_obj == NULL) {")
+gen.indent()
+gen.write("Py_XDECREF(nd_obj); Py_XDECREF(dtype_obj); Py_XDECREF(handle_obj);")
+gen.write("Py_DECREF(shape_tuple); Py_DECREF(result);")
+gen.write("return NULL;")
+gen.dedent()
+gen.write("}")
+gen.write("PyTuple_SET_ITEM(result, 0, nd_obj);")
+gen.write("PyTuple_SET_ITEM(result, 1, dtype_obj);")
 gen.write("PyTuple_SET_ITEM(result, 2, shape_tuple);")
-gen.write("PyTuple_SET_ITEM(result, 3, PyLong_FromLongLong(handle));")
+gen.write("PyTuple_SET_ITEM(result, 3, handle_obj);")
 gen.write("return result;")
  • Apply / Chat
Suggestion importance[1-10]: 8

__

Why: This is a valid and important error handling improvement for the C-API code, preventing potential segfaults from memory allocation failures.

Medium
Ensure consistent attribute checking pattern

In write_arg_decl_lines, modify the check for the "optional" attribute to be a
string-based check for consistency and to prevent potential failures if
attributes are not simple strings.

f90wrap/f90wrapgen.py [440-447]

 if self.direct_c_interop:
     arg_type = str(arg_dict["arg_type"]).strip().lower()
     is_integer_scalar = arg_type == "integer" and not any(
         str(attr).startswith("dimension(") for attr in getattr(arg, "attributes", [])
     )
-    if is_integer_scalar and "optional" not in arg.attributes:
+    if is_integer_scalar and not any(str(attr).startswith("optional") for attr in getattr(arg, "attributes", [])):
         arg_dict["arg_type"] = "integer(c_int)"
         direct_c_integer_scalars.append(arg.name)
  • Apply / Chat
Suggestion importance[1-10]: 6

__

Why: The suggestion improves code robustness and consistency by using a safer method to check for the 'optional' attribute, preventing potential bugs.

Low
  • More

@krystophny krystophny closed this Dec 18, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant