Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Recursive call crashes program. Fibonacci simplest function #2270

Closed
@polkovnikov

Description

@polkovnikov

Under Windows lpython I tried to compile/run following fib.py file:

def fib(n: i32) -> i32:
    return fib(n - 1) + fib(n - 2) if n >= 3 else 1
print(fib(30))

above program silently crashes. In regular CPython code above works well!

While same non-recursive variant

def fib(n: i32) -> i32:
    a: i32 = 1
    b: i32 = 1
    i: i32 = 0
    for i in range(n - 2):
        a, b = b, a + b
    return b
print(fib(30))

runs in LPython without any problem and outputs correct answer 832040

================== UPDATE 1 ==================

It appeared that only LLVM IR assembly is damaged by recursive crash, but C++ code doesn't.

I.e. if you do --show-llvm and compile .ll file manually through CLang then it crashes, but if you do --show-cpp and compile .cpp through CLang then it doesn't crash and produces correct output.

It appeared that most probably Python's default IF-ELSE inline statement is not interpreted correctly. Because following rewrite of code

def fib(n: i32) -> i32:
    if n >= 3:
        return fib(n - 1) + fib(n - 2)
    else:
        return 1
print(fib(30))

works correctly and doesn't crash.

It means that A if B else C is converted to LLVM by LPython incorrectly. As you should know this statement should be lazy, meaning that you can't compute both A and C beforehand and then use one of results.

But if you look into LLVM IR assembly of the very first program of this post then you'll see something like this:

define i32 @__module___main___fib(i32* %n) {
  ...................................
  %1 = icmp sge i32 %0, 3
  ......... LOTS OF LINES computing both clauses of IF-ELSE beforehand without using %1 ...........
  %9 = select i1 %1, i32 %8, i32 1
  store i32 %9, i32* %_lpython_return_variable, align 4
  br label %return
  ....................

So you'll see that first it computes condition, then doesn't use this condition but computes both clauses of IF-ELSE without using result of condition, and at the very end it returns one of computed clause.

This is incorrect for Python's IF-ELSE and even for C++'s ternary B ? A : C, both Python and C++ SHOULD be lazy for this ternary operator.

Without LAZY evaluation of IF-ELSE of course fib() function will go into Infinite recursion and thus crash stack through overflow.

Metadata

Metadata

Assignees

No one assigned

    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