~sircmpwn/hare-users

2 2

crash on io::close on memio::dynamic even after duplicating buffer content

Details
Message ID
<6787b97b-36dd-433a-b5a2-0a3da7f4ec9a@yahoo.com>
DKIM signature
permerror
Download raw message
someone a few days ago posted a similar problem, but theirs was a 
compiler bug (non-exhaustive match block), and I'm not sure what's wrong 
with mine. the following should compile, at least, accordingly to what I 
read on the docs. is it a bug or something I didn't catch?

use io;
use fmt;
use memio;
use strings;

export fn main() void = {
     const buff = foo();
     const unbuff = memio::string(buff)!;
     const data = strings::dup(unbuff);
     io::close(buff)!;
};

fn foo() *memio::stream = {
     let buff = &memio::dynamic();
     fmt::fprintf(buff, "hi!\n")!;
     return buff;
};

Illegal pointer access (address not mapped to object) at address 0x4
Backtrace:
/home/mmd/io/handle.ha:49:28 io::close+0x72 [0x80098e2]
Lorenz (xha) <me@xha.li>
Details
Message ID
<Zm5oZXZSiNcyefZR@xha.li>
In-Reply-To
<6787b97b-36dd-433a-b5a2-0a3da7f4ec9a@yahoo.com> (view parent)
DKIM signature
pass
Download raw message
hi,

On Sat, Jun 15, 2024 at 11:41:50PM -0300, Mikaela Morais Dias de Souza wrote:
> someone a few days ago posted a similar problem, but theirs was a compiler
> bug (non-exhaustive match block), and I'm not sure what's wrong with mine.
> the following should compile, at least, accordingly to what I read on the
> docs. is it a bug or something I didn't catch?
> 
> use io;
> use fmt;
> use memio;
> use strings;
> 
> export fn main() void = {
>     const buff = foo();
>     const unbuff = memio::string(buff)!;
>     const data = strings::dup(unbuff);
>     io::close(buff)!;
> };
> 
> fn foo() *memio::stream = {
>     let buff = &memio::dynamic();

your problem is here: you are referencing a value that is on the
stack, i.e. storage, of this function "foo()". now, if you return
from this function, you return the pointer to the dynamic::stream,
which is no longer valid after the function, because it is pointing
to the foo's stack, which is no longer there.

by the way, the compiler would not even have the keep the result
of memio::dynamic around that long. it's just that harec does not
have optimizations yet so it just stores all function return values
on the stack; theoretically, the line below could already segfault
your program.

the right move here would be to just work with the memio::stream
directly instead of taking a pointer to it :)

>     fmt::fprintf(buff, "hi!\n")!;
>     return buff;
> };
Details
Message ID
<55d2bc88d2b23346b97b845ae47d9ddf834bc247@rosiesworkshop.net>
In-Reply-To
<Zm5oZXZSiNcyefZR@xha.li> (view parent)
DKIM signature
pass
Download raw message
Also Hi! I offer a small addition to Lorenz's comments, for you and for 
future hare learners.

> the right move here would be to just work with the memio::stream
> directly instead of taking a pointer to it :)

Indeed this is the more common pattern across the ecosystem. Alternatively,
you could also alloc() the stream and free() it after closing it.

With Lorenz's suggestion the stream is copied from foo's stack to main's.
Since the stream will not out-live main, you can safely take its address
there and use it as you had:

```
use io;
use fmt;
use memio;
use strings;

export fn main() void = {
     const buff = &foo();
     const unbuff = memio::string(buff)!;
     const data = strings::dup(unbuff);
     io::close(buff)!;
};

fn foo() memio::stream = {
     let buff = memio::dynamic();
     fmt::fprintf(&buff, "hi!\n")!;
     return buff;
};
```

With my suggestion of allocating it the types are unchanged from your 
original code; the stream is copied onto the heap immediately after 
initialization, only briefly living on foo's stack, and so it can (must) 
always be accessed by its address. Of course this comes with the need
to free the memory later:


```
use io;
use fmt;
use memio;
use strings;

export fn main() void = {
     const buff = foo();
     const unbuff = memio::string(buff)!;
     const data = strings::dup(unbuff);
     io::close(buff)!;
     free(buff);
};

fn foo() *memio::stream = {
     let buff = alloc(memio::dynamic());
     fmt::fprintf(buff, "hi!\n")!;
     return buff;
};
```

Cheers,
RKL
Reply to thread Export thread (mbox)