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]
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;> };
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