News for hackers. Stuff that matters.
Re:Making a Go program 70% faster with a one character change by amluto on Monday November 14, 2022 @12:43PM (#33597859)
In C, “discarding” a pointer in a way that leaves the value visible is quite common. At least if one doesn’t accidentally use the pointer, it’s harmless. (In the way that all manner of unsafeness is harmless in C as long as no actual UB occurs, which is to say it’s not great.)

But Go is a garbage collected language, and there is so such thing as “discarding” a pointer. Either it’s there or it isn’t, and this kind of leak has side effects. I find it baffling that the language designers and the community consider this acceptable.

(One thing I really like about Rust is that you can’t play fast and loose with lifetimes like this. If you have function taking &'a Vec<T> and you return &'a T, you can’t arbitrarily “discard” and leak that reference up the call chain. You need to genuinely get rid of it by the time the vector is gone.)

Re:Making a Go program 70% faster with a one character change by foldr on Tuesday November 15, 2022 @04:26AM (#33607053)
>and this kind of leak has side effects

Only if the calling function does something with the pointer (which it generally won't, if err is non-nil). If the calling code does do something with the pointer even when err is non-nil, then either

(a) the value of the pointer is meaningful, and this is fine; or

(b) there's a logic error in the calling code, which is a far more serious bug than a potential memory leak.

So I don't really see the problem here.

Re:Making a Go program 70% faster with a one character change by amluto on Tuesday November 15, 2022 @12:48PM (#33612530)
I should have been more explicit. Go is garbage collected. If you keep a pointer live, then it’s not garbage, which prevents it from being collected.

At least Go doesn’t use RAII, so inadvertently pinning a pointer won’t keep a socket open or a lock held.

Re:Making a Go program 70% faster with a one character change by foldr on Tuesday November 15, 2022 @04:42PM (#33615445)
Just returning the pointer doesn't keep the value that it points to live, unless the calling function does something with the pointer.

The following toy example doesn't leak memory. Are you thinking of some other pattern that would leak memory? If so, what is it? I can only think of patterns where a logic error is also involved. That is, where the meaningless value of 'val' is used in code paths where err != nil.

    func alwaysError() (*int, error) {
        var dummy int

        // We return &dummy even though it's a meaningless value.
        // Will this cause a memory leak?

        return &dummy, fmt.Errorf("An error")
    }

    func caller() {
        val, err := alwaysError()
        if err != nil {
            fmt.Printf("Error\n")

            // It won't! Because the value pointed to by 'val'
            // can be GCed from this point on.
            return
        }

        // never get here        

        fmt.Printf("Value %v\n", val)
        //
        // ...lots of code that uses *val...
        //
    }
You might think that you'd get a leak if the error branch was also long-lived, but Go's GC seems to be precise with respect to conditional branching (as far as I can tell by experimenting with runtime.SetFinalizer). That is, as long as the error branch doesn't refer to 'val', then the value pointed to by 'val' can be collected once the error branch is entered (and before 'caller' returns).
Re:Making a Go program 70% faster with a one character change by amluto on Wednesday November 16, 2022 @12:38PM (#33627106)
I haven't actually played with this, but if the same pattern of lazily (sloppily?) returning arbitrary pointers along with errors continues, the lifetime ought to be extended arbitrarily. The caller could itself return val, err, and so on up the chain.
Re:Making a Go program 70% faster with a one character change by foldr on Wednesday November 16, 2022 @01:00PM (#33627565)
I'm not seeing how that would cause a memory leak. It just means that the value might be GCed a bit later. Could you give an example?
Re:Making a Go program 70% faster with a one character change by amluto on Wednesday November 16, 2022 @04:33PM (#33630994)
It’s a temporary leak. My point is that it’s an actual side effect, unlike how in C it has no effect whatsoever if the value is ignored.

In a language where destruction of an object often releases external resources (C++, for example, or Python or Rust to a lesser extent), this effect would be more dramatic. Imagine someone doing this in Python:

    def func():
      f = tmpfile(…)
      err = do something
      return f, err
This style would be absurd and wrong — it keeps f alive to long.