Skip to content

Conversation

jonatack
Copy link
Member

@jonatack jonatack commented Mar 1, 2021

As noticed during review today in #20685 (comment) of the upcoming I2P network support, CService::port is uint16_t but is passed around the codebase and into the ctors as int, which causes uneeded conversions and casts. We can avoid these (including in the incoming I2P code without further changes to it) by using ports with the correct type. The remaining conversions are pushed out to the user input boundaries where they can be range-checked and raise with user feedback in the next patch.

@jonatack
Copy link
Member Author

jonatack commented Mar 2, 2021

Just discovered #8394, will check if it contains anything I've overlooked.

Copy link
Contributor

@vasild vasild left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK f8b1c21

I think this PR is good and safe as it is. Some non-blocker comments below. It would be even better if it adds some checks that ports given by the user are in range, like in https://github.com/bitcoin/bitcoin/pull/8394/files#diff-134ccc4e5308f84fb9c03a9a1e1599209560370e49e30c7f545fa7b9ba7e07deR153

@DrahtBot
Copy link
Contributor

DrahtBot commented Mar 2, 2021

The following sections might be updated with supplementary metadata relevant to reviewers and maintainers.

Conflicts

Reviewers, this pull request conflicts with the following ones:

If you consider this pull request important, please also help to review the conflicting pull requests. Ideally, start with the one that should be merged first.

@practicalswift
Copy link
Contributor

Strong Concept ACK

Thanks for removing this implicit conversion gotcha :)

uint16_t should be used consistently for port numbers.

Somewhat related: #19415 (comment)

@laanwj
Copy link
Member

laanwj commented Mar 3, 2021

I like the idea of using specific types. But if we're going to change this, I think I would feel slightly better defining a typedef Port for this. What if we want to support a protocol in the future with 32-bit ports? I do not see this as likely… my intuition is that things are moving to one-endpoint-per-address conceptually instead of ports… and yes the port as a concept is typical to current Internet protocols, where they're all 16 bits. But I guess it's clearer too to have a named type.

Anyhow concept ACK.

@jonatack jonatack force-pushed the pass-uint16_t-CService-port-as-uint16_t branch from f8b1c21 to c373a87 Compare March 6, 2021 21:35
@jonatack
Copy link
Member Author

jonatack commented Mar 6, 2021

Thank you @vasild, @practicalswift and @laanwj. Updated per all of your suggestions.

@practicalswift
Copy link
Contributor

practicalswift commented Mar 7, 2021

Not super excited by the introduction of Port TBH.

The problem is probably best illustrated by this UB quiz:

Q. Which of the two cases rely on undefined behaviour?

// Snippet 1
Port p;
if (p != other_p) {
}
// Snippet 2
uint16_t p;
if (p != other_p) {
}
Click for answer

Both snippets rely on undefined behaviour (they are technically equivalent thanks to the typedef).

But that's not the point.

The point is that while the UB in snippet 2 is immediately clear (read of uninitialized uint16_t) the UB in snippet 1 requires looking up information that is not available in the code snippet (more specifically the typedef).

Trying to make it as easy as possible to spot unsafe code is an important part of safe coding practice.

Personally I find that the introduction of Port makes it somewhat harder to spot unsafe code as illustrated above.

Copy link
Contributor

@vasild vasild left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK 9b7055f

Notice that this is not the last commit - I tend to agree with @practicalswift wrt uint16_t vs Port so I ACK the commit before those changes. Two more things to consider about Port:

  • The name Port may be too generic. I can imagine that "port" in some other context means something else, e.g. "usb port for connecting to a hardware wallet". Maybe IPPort would be a better name.
  • At one place we do Port n; ParseUInt16(..., &n); which kind of defeats the purpose of the Port abstraction. I don't see IP ports ever changing to something other than 16 bit unsigned integers.

@jonatack
Copy link
Member Author

jonatack commented Mar 9, 2021

Thanks for the feedback!

I agree that Port is less greppable than IPPort (and we do already have a ToStringIPPort() method).

No strong opinion, but here are a few reasons why I tend to agree with @laanwj and took the time to do it:

  • ISTM not having a type alias here is why we're in this situation in the first place (and since a long time)
  • I'm happy that we have an alias for CAmount, for example; it makes clear to contributors which type should be used for amounts and the same would be true for port id numbers
  • This was a somewhat tedious change to make and I don't plan to do it again, take advantage of it ;)
  • I think we'll be happier down the road if this is done than if we don't do it

I'm not sure whether to wait for more feedback or separate the type alias to another pull. Keep the feedback coming 🙏

@jonatack
Copy link
Member Author

Ah, the fuzz CI is signalling a needed change since the merge of #19415: "UndefinedBehaviorSanitizer: implicit-signed-integer-truncation test/fuzz/netbase_dns_lookup.cpp:48:45". Will update.

@jonatack jonatack force-pushed the pass-uint16_t-CService-port-as-uint16_t branch from a057361 to 52dd40a Compare March 16, 2021 18:54
@jonatack
Copy link
Member Author

Thanks @vasild! Updated one line per git diff a057361 52dd40a to make a change needed after the merge of #19415.

+++ b/src/test/fuzz/netbase_dns_lookup.cpp
@@ -18,7 +18,7 @@ FUZZ_TARGET(netbase_dns_lookup)
     const std::string name = fuzzed_data_provider.ConsumeRandomLengthString(512);
     const unsigned int max_results = fuzzed_data_provider.ConsumeIntegral<unsigned int>();
     const bool allow_lookup = fuzzed_data_provider.ConsumeBool();
-    const int default_port = fuzzed_data_provider.ConsumeIntegral<int>();
+    const uint16_t default_port = fuzzed_data_provider.ConsumeIntegral<uint16_t>();

@practicalswift
Copy link
Contributor

cr ACK 52dd40a: patch looks correct

Copy link
Contributor

@vasild vasild left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK 52dd40a

@vasild
Copy link
Contributor

vasild commented Mar 19, 2021

Looks like master (at 05757aa) has a problem that would be fixed by this PR - my "private" CI got this error:

netbase.cpp:212:37: runtime error: implicit conversion from type 'int' of value -2147483632 (32-bit, signed) to type 'uint16_t' (aka 'unsigned short') changed the value to 16 (16-bit, unsigned)

which seems unrelated to the changes I am testing there.

Edit: also in another PR: https://cirrus-ci.com/task/6488952220680192?command=ci#L3334

@sipa
Copy link
Member

sipa commented Mar 19, 2021

@vasild Conversions to unsigned types are actually well-defined in the lamguage. Our sanitizer runs in sort of an over-eager mode and triggers on that because such conversions are often a sign of bugs. But here I suspect it's intentional, and valid.

@vasild
Copy link
Contributor

vasild commented Mar 19, 2021

@sipa, I agree. However, a failing CI is a problem :) it would be fixed either by this PR or an explicit cast like CService(vIP[i], static_cast<uint16_t>(port)).

@maflcko
Copy link
Member

maflcko commented Mar 19, 2021

cr ACK 52dd40a

@maflcko maflcko merged commit 18cd088 into bitcoin:master Mar 19, 2021
@jonatack jonatack deleted the pass-uint16_t-CService-port-as-uint16_t branch March 19, 2021 19:51
sidhujag pushed a commit to syscoin/syscoin that referenced this pull request Mar 20, 2021
maflcko pushed a commit to maflcko/bitcoin-core that referenced this pull request Mar 21, 2021
3d086f4 test: add ParseUInt16() test coverage (Jon Atack)

Pull request description:

  `ParseUInt16()` was just added in bitcoin#21328.

ACKs for top commit:
  practicalswift:
    cr ACK 3d086f4: patch looks correct & more coverage is better than less coverage

Tree-SHA512: bf7f96deb7c1531419565907f0ea8a8e32b368d4b823a3e80928b2c118edbf643ea06e357b4b5504a89f855caeed289daa9f823c740231ed6ad1b8ed00285ce8
sidhujag pushed a commit to syscoin/syscoin that referenced this pull request Mar 21, 2021
3d086f4 test: add ParseUInt16() test coverage (Jon Atack)

Pull request description:

  `ParseUInt16()` was just added in bitcoin#21328.

ACKs for top commit:
  practicalswift:
    cr ACK 3d086f4: patch looks correct & more coverage is better than less coverage

Tree-SHA512: bf7f96deb7c1531419565907f0ea8a8e32b368d4b823a3e80928b2c118edbf643ea06e357b4b5504a89f855caeed289daa9f823c740231ed6ad1b8ed00285ce8
Fabcien pushed a commit to Bitcoin-ABC/bitcoin-abc that referenced this pull request Feb 21, 2022
Summary:
> As noticed during review of the I2P network support, `CService::port` is `uint16_t` but is passed around the codebase and into the ctors as `int`, which causes uneeded conversions and casts. We can avoid these (including in the incoming I2P code without further changes to it) by using ports with the correct type. The remaining conversions are pushed out to the user input boundaries where they can be range-checked and raise with user feedback in the next patch.

This is a backport of [[bitcoin/bitcoin#21328 | core#21328]] [1/3]
bitcoin/bitcoin@6423c81

Test Plan: `ninja all check-all`

Reviewers: #bitcoin_abc, Fabien

Reviewed By: #bitcoin_abc, Fabien

Differential Revision: https://reviews.bitcoinabc.org/D11077
Fabcien pushed a commit to Bitcoin-ABC/bitcoin-abc that referenced this pull request Feb 21, 2022
Summary:
This is a backport of [[bitcoin/bitcoin#21328 | core#21328]] [2/3] and [[bitcoin/bitcoin#21488 | core#21488]] (unit tests)
bitcoin/bitcoin@2875a76

Depends on D11077 and D11081

Test Plan: `ninja all check-all bitcoin-fuzzers`

Reviewers: #bitcoin_abc, Fabien

Reviewed By: #bitcoin_abc, Fabien

Subscribers: Fabien

Differential Revision: https://reviews.bitcoinabc.org/D11078
Fabcien pushed a commit to Bitcoin-ABC/bitcoin-abc that referenced this pull request Feb 21, 2022
Summary:
This is a backport of [[bitcoin/bitcoin#21328 | core#21328]] [3/3]
bitcoin/bitcoin@52dd40a

Depends on D11078

Test Plan: `ninja all check-all bitcoin-fuzzers`

Reviewers: #bitcoin_abc, Fabien

Reviewed By: #bitcoin_abc, Fabien

Differential Revision: https://reviews.bitcoinabc.org/D11079
@bitcoin bitcoin locked as resolved and limited conversation to collaborators Aug 16, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

7 participants