New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd/vet: flag using %s:%d to construct network addresses #28308

Open
stapelberg opened this Issue Oct 22, 2018 · 1 comment

Comments

Projects
None yet
3 participants
@stapelberg
Contributor

stapelberg commented Oct 22, 2018

I recently diagnosed a bug in someone’s Go program where a user reported that they couldn’t get the program to connect, and it turned out the issue was that the programmer used fmt.Sprintf("%s:%d", host, port) instead of net.JoinHostPort to construct a network address to pass to net.Dial: https://twitter.com/zekjur/status/1049642773278650368. The issue is subtle: net.JoinHostPort correctly handles IPv6 address literals (e.g. 2001:4860:4860::8888), whereas fmt.Sprintf doesn’t.

A very similar issue is to use strings.Split instead of net.SplitHostPort.

I noticed that both of these issues are fairly prevalent, likely because programmers aren’t that accustomed to using IPv6 literals yet, but I expect them to become more common as IPv6 adoption continues to grow.

I propose adding a vet check to flag using %s:%d format strings with arguments whose names contain port, addr, host, listen or bind. This heuristic will flag 12356 occurrences¹ I found on GitHub using BigQuery, and hopefully make programmers aware not only of net.JoinHostPort but also net.SplitHostPort, for which writing a check is significantly harder.

I can send a CL to implement this. Let me know what you think.

① The BigQuery query I used was:

WITH lines AS
  (SELECT
    id,
    SPLIT(content, "\n") AS line
  FROM `gocontents.gocontents`)
SELECT path, flattened_line
FROM lines
CROSS JOIN UNNEST(lines.line) AS flattened_line
JOIN `gocontents.gofiles` AS files ON files.id = lines.id
WHERE
  REGEXP_CONTAINS(flattened_line, r"fmt.Sprintf\(\"%s:%d\", (port|addr|host|listen|bind)")
@mvdan

This comment has been minimized.

Member

mvdan commented Oct 23, 2018

This definitely checks the correctness and frequency requirements for a vet check - the issue leads to bugs, and it happens often.

However, I'm not sure if it ticks off the precision requirement. If the check simply inspects the syntax tree, it could be prone to false positives or negatives. Dominik proposes a slightly different approach for his tooling in dominikh/go-tools#358, for example.

@bcmills bcmills added this to the Unplanned milestone Oct 23, 2018

@bcmills bcmills added the Proposal label Oct 23, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment