flak rss random

backporting go on openbsd

The OpenBSD ports tree generally tracks current, but sometimes backports (and stable packages) are made for more serious issues. As was the case for git 2.50.1. However, the go port has not seen a backport in quite some time. The OpenBSD release schedule aligns with the go schedule such that we always get the latest release, but not minor revisions.

more...

Posted 08 Oct 2025 18:34 by tedu Updated: 08 Oct 2025 18:34
Tagged: openbsd

async dns

curl experimented with using pthread_cancel to timeout async DNS requests and it blew up. What else can we do?

more...

Posted 25 Sep 2025 18:33 by tedu Updated: 25 Sep 2025 18:33
Tagged: c programming

slice tails don't grow forever

In a garbage collected language, one needs to be cautious about leaks caused by errant references, but caution can turn to paranoia. In go, I like to make little fifo queues by appending to the tail of a slice. But does this grow forever?

s = append(s[1:], n)

One theory is that this will eventually consume all memory, as somehow the slice grows and grows. The garbage collector is unable to reduce its size because the head of the slice is still out there somewhere.

Another theory is no, the slice gets reallocated when it needs to expand, but only the referenced section gets copied.

We can test this!

package main

import (
    "fmt"
    "math/rand"
)

func main() {
    var s []int

    grow := false
    for i := 0; i < 10000000000; i++ {
        n := rand.Int()
        if grow || len(s) < 100 {
            s = append(s, n)
        } else {
            s = append(s[1:], n)
        }
    }
    fmt.Printf("%v\n", s)
}

This runs basically forever, but uses very little memory. Changing grow to true, it reliably explodes.

I knew this, and was already relying on it, but also in most cases a slow leak may take weeks to develop and go unnoticed. Thirty seconds to check.

Posted 23 Sep 2025 19:44 by tedu Updated: 23 Sep 2025 19:44
Tagged: go programming

humanely dealing with humungus crawlers

I host a bunch of hobby code on my server. I would think it’s really only interesting to me, but it turns out every day, thousands of people from all over the world are digging through my code, reviewing years old changesets. On the one hand, wow, thanks, this is very flattering. On the other hand, what the heck is wrong with you?

more...

Posted 10 Sep 2025 16:42 by tedu Updated: 10 Sep 2025 16:42
Tagged: project web

the boy who cried wolf

Once upon a time there was a boy who went out to guard the sheep. The villagers had warned him about the dangers of the wolf, about the kinds of things the wolf would do. As he is watching the flock, the moon passes overhead and its reflection in the lake catches his eye.

more...

Posted 07 Sep 2025 18:47 by tedu Updated: 08 Sep 2025 03:06
Tagged: rants

what the go proxy has been doing

A follow up to what is the go proxy even doing? now with more answers. Russ Cox (rsc) and I traded a few emails trying to work out what was going on. They’re going to make a few changes, and I also learned a few things it would have been helpful to know.

more...

Posted 03 Sep 2025 18:38 by tedu Updated: 03 Sep 2025 19:13
Tagged: go software web

is OpenBSD 10x faster than Linux?

Here’s a little benchmark complements of Jann Horn. It’s unexpectedly slow on Linux.

more...

Posted 15 Aug 2025 16:33 by tedu Updated: 15 Aug 2025 16:33
Tagged: openbsd

what is the go proxy even doing?

The go module proxy caches requests from users, so everyone has a consistent and reliable experience regardless of upstream host. But what if the go proxy is contributing to the instability of the upstream host? There have been other complaints about the go proxy, that’s just the way it works, but I collected a few minutes of logs to examine that may be interesting.

more...

Posted 14 Aug 2025 17:22 by tedu Updated: 03 Sep 2025 18:39
Tagged: go web

stylish bugs

Whenever a bug is discovered, it’s immediately apparent that three things have gone wrong. They used the wrong language, and this never would have happened if they’d written it in the bugfree language. They used the wrong development methodology, and this never would have happened if they’d used the prevent this bug technique. And finally, they ignored best practice and didn’t use the proper coding style. The bug would have been extremely obvious if only they’d replaced all v_w_ls with underscores in variable names. Just look at the word v_w_ls. It pops right out.

more...

Posted 12 Aug 2025 08:13 by tedu Updated: 12 Aug 2025 08:13
Tagged: programming thoughts

regexp/o

Perl has a regex option /o, which pretends to optimize your code, but actually introduces bugs. Go has been missing out. Until now.

We need regexp of course, but also text/template for interpolation. Add in runtime to get the pc, and we have all the elements for a cache of only once regex.

func Compile(s string, vals any) (*regexp.Regexp, error) {
        cacheMtx.Lock()
        defer cacheMtx.Unlock()
        pc, _, _, _ := runtime.Caller(1)
        k := key{s: s, pc: pc}
        re := cache[k]
        if re != nil {
                return re, nil
        }
        t := template.New("regex")
        t, err := t.Parse(s)
        if err != nil {
                return nil, err
        }
        var sb strings.Builder
        err = t.Execute(&sb, vals)
        if err != nil {
                return nil, err
        }
        re, err = regexp.Compile(sb.String())
        if err != nil {
                return nil, err
        }
        cache[k] = re
        return re, nil
}

type key struct {
        s  string
        pc uintptr
}

var cacheMtx sync.Mutex
var cache = make(map[key]*regexp.Regexp)

And a test program.

func main() {
        fmt.Printf("starting\n")
        inputs := []string{"Apple", "bananas", "42"}
        for i := 0; i < 3; i++ {
                re, err := regexpo.Compile("{{ call .Letters }}", map[string]any{
                        "Letters": func() string {
                                time.Sleep(1 * time.Second)
                                fmt.Printf("substitute\n")
                                return "[a-z]"
                        },
                })
                if err != nil {
                        fmt.Printf("failure: %s\n", err)
                        return
                }
                ok := re.MatchString(inputs[i])
                fmt.Printf("match: %v\n", ok)
        }
        fmt.Printf("done.\n")
}

The substitution is only done once.

Posted 04 Aug 2025 20:18 by tedu Updated: 04 Aug 2025 20:18
Tagged: go programming
V
V