Skip to content

Bug: Multiple potential bugs in source code #231

Description

@terasakisatoshi

Summary

Code review identified 12 potential bugs across the RustCall.jl source code.

1. Nested generics regex failure in _parse_fn_arg_types (generics.jl:755)

File: src/generics.jl:755

fn_pattern = Regex("fn\\s+$(func_name)\\s*(?:<[^{]*?>)?\s*\(")

<[^{]*?> uses non-greedy matching which fails on deeply nested generics like Vec<Option<T>>. The > inside Option< would incorrectly match before the closing > of Vec<. This violates the project's own documented rule: "Never use regex alone to match angle brackets (< >) in Rust code."

2. Incorrect bracket depth tracking for [ and > (structs.jl:64-68, julia_functions.jl:206-215, ruststr.jl:1003-1031)

Files: src/structs.jl:64-68, src/julia_functions.jl:206-215, src/ruststr.jl:1003-1031

elseif c == '>'
    angle_depth = max(0, angle_depth - 1)
elseif c == ']'
    bracket_depth = max(0, bracket_depth - 1)

Using max(0, ...) for bracket depth clamping causes [-delimited brackets and >-delimited brackets to be tracked independently of each other. This means a < inside an array literal [a < b] would still increment angle_depth, and a > inside [a < b] would decrement it, leading to incorrect depth tracking when arrays contain comparison operators.

3. Unusual return value from drop! fallback (types.jl:837-843)

File: src/types.jl:837-843

function drop!(x::Union{RustBox, RustRc, RustArc, RustVec})
    lock(x.drop_lock) do
        x.dropped = true
        x.ptr = C_NULL
    end
    return nothing
end

Julia convention for !-suffixed mutation functions is to return nothing (not the tuple (nothing)). While this works due to implicit tuple return, it is non-idiomatic.

4. String literal brace counting causes false positives (exceptions.jl:559-565)

File: src/exceptions.jl:559-565

open_braces = count(c -> c == '{', source_code)
close_braces = count(c -> c == '}', source_code)
if open_braces > close_braces
    push!(suggestions, "Found $(open_braces - close_braces) more opening brace(s)...")

Brace counting includes braces inside string literals like s = "{test}", causing false positive suggestions for mismatched braces when none exist.

5. RustStr incorrectly mapped to Cstring in codegen (codegen.jl:125)

File: src/codegen.jl:125

julia_to_c_type(::Type{RustStr}) = Cstring

RustStr is a fat pointer (ptr + len) representing &str. Mapping it to Cstring (null-terminated string) loses the length information and causes ABI mismatch for FFI calls expecting &str.

6. Generic return type inference is oversimplified (generics.jl:973-1003)

File: src/generics.jl:973-1003

ret_type = length(type_params) > 0 ? first(values(type_params)) : Any

The first type parameter is assumed as the return type. For functions like fn transform<T, U>(x: T) -> U, this returns T instead of U, causing type mismatches.

7. readdir vs walkdir inconsistency in cache size calculation (cache.jl:459-464, cache.jl:485)

File: src/cache.jl:485

for file in readdir(cache_dir)
    if endswith(file, lib_ext)

list_cached_libraries uses readdir (non-recursive), while get_cache_size uses walkdir (recursive). This means .dylib files in subdirectories of the cache would be counted by get_cache_size but missed by list_cached_libraries.

8. _count_trailing_backslashes uses unsafe indexing (dependencies.jl:288)

File: src/dependencies.jl:288

for i in lastindex(s):-1:firstindex(s)
    s[i] == '\\' || break

Using linear index iteration on multi-byte strings is unsafe. Should use prevind-based iteration or iterate bytes instead.

9. lib_name / cache key mismatch (ruststr.jl:239-244, ruststr.jl:273-278)

File: src/ruststr.jl:239-244

code_hash = stable_content_hash(wrapped_code)[1:16]
lib_name = "rust_$(code_hash)"

The library registration key uses the first 16 hex chars of a stable content hash. The cache key uses a different computation path. If the compilation pipeline changes between cache save/load, the lookup could fail while the cache file exists.

10. found_libs duplicate potential in fallback search (ruststr.jl:86-106)

File: src/ruststr.jl:86-106

The fallback search in get_function_pointer doesn't guard against the same library being queried multiple times if RUST_LIBRARIES contains duplicate handles (through different keys pointing to the same library).

Expected Behavior

  • Regex-based angle bracket matching should be replaced with bracket-counting in all Rust code parsing
  • String literals must be skipped when counting braces/special characters
  • RustStr should map to a fat pointer type (Cstruct with ptr + len), not Cstring
  • Generic return type inference should parse the actual return type from function signature, not use first type param
  • readdir calls in cache code should use walkdir for recursive search
  • String indexing should use character-safe iteration with prevind/nextind

Related Files

  • src/structs.jl
  • src/julia_functions.jl
  • src/ruststr.jl
  • src/codegen.jl
  • src/generics.jl
  • src/cache.jl
  • src/exceptions.jl
  • src/dependencies.jl
  • src/types.jl

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions