From 9b916b2f14f56d6543c5ef50401e4ab7aeb2ad5c Mon Sep 17 00:00:00 2001 From: Martin Kustermann Date: Wed, 2 Jul 2025 00:17:33 -0700 Subject: [PATCH] [io] Avoid uncatchable error in RawDatagramSocket.bind() Currently the error happens very late in C code which throws a `Dart_NewApiError()` which isn't catchable via try/catch in Dart. Our `dart:io` APIs should never result in uncatchable errors being thrown. This CL adds the verification that the address is a IPv4/IPv6 address (and not a unix domain socket address) before actually binding the code. Issue https://github.com/dart-lang/sdk/issues/60421 TEST=standalone/io/datagram_error_test Change-Id: I0ead36b8c90dd8b04523f9e64d3be63a8e66a56c Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/438140 Commit-Queue: Martin Kustermann Reviewed-by: Slava Egorov --- sdk/lib/_internal/vm/bin/socket_patch.dart | 7 +++++ tests/standalone/io/datagram_error.dart | 30 ------------------ tests/standalone/io/datagram_error_test.dart | 33 ++++++++------------ 3 files changed, 20 insertions(+), 50 deletions(-) delete mode 100644 tests/standalone/io/datagram_error.dart diff --git a/sdk/lib/_internal/vm/bin/socket_patch.dart b/sdk/lib/_internal/vm/bin/socket_patch.dart index 46e83151be8..45be821586d 100644 --- a/sdk/lib/_internal/vm/bin/socket_patch.dart +++ b/sdk/lib/_internal/vm/bin/socket_patch.dart @@ -1241,6 +1241,13 @@ base class _NativeSocket extends _NativeSocketNativeWrapper final address = await _resolveHost(host); + if (address.type != InternetAddressType.IPv6 && + address.type != InternetAddressType.IPv4) { + throw SocketException( + 'Cannot bind datagram socket on non-IPv4/IPv6 address (was: $address)', + ); + } + var socket = _NativeSocket.datagram(address); var result = socket._nativeCreateBindDatagram( address._in_addr, diff --git a/tests/standalone/io/datagram_error.dart b/tests/standalone/io/datagram_error.dart deleted file mode 100644 index fd54aa44513..00000000000 --- a/tests/standalone/io/datagram_error.dart +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file -// for details. All rights reserved. Use of this source code is governed by a -// BSD-style license that can be found in the LICENSE file. -// -// Dart test program for testing error path in datagram bind call. - -import 'dart:io'; - -import "package:expect/expect.dart"; - -void main() async { - try { - final socket = await RawDatagramSocket.bind( - InternetAddress('/tmp/test_socket', type: InternetAddressType.unix), - 0, - ); - Expect.fail( - "Should not reach this: " - "the bind call above should have failed", - ); - socket.listen((data) { - print(data); - }); - } catch (e) { - Expect.fail( - "Should not reach this: " - "the bind call above throws unhandled exception", - ); - } -} diff --git a/tests/standalone/io/datagram_error_test.dart b/tests/standalone/io/datagram_error_test.dart index f5fa6b8b5f2..f701e597298 100644 --- a/tests/standalone/io/datagram_error_test.dart +++ b/tests/standalone/io/datagram_error_test.dart @@ -1,31 +1,24 @@ // Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file // for details. All rights reserved. Use of this source code is governed by a // BSD-style license that can be found in the LICENSE file. -// -// Dart test program for testing error path in datagram bind call. -// -// OtherResources=datagram_error.dart import 'dart:io'; +import "package:async_helper/async_helper.dart"; import "package:expect/expect.dart"; -import 'package:path/path.dart' as path; void main() async { - var sdkPath = path.absolute(path.dirname(Platform.executable)); - var dartPath = path.absolute( - sdkPath, - Platform.isWindows ? 'dart.exe' : 'dart', - ); - // Get the Dart script file that generates output. - var scriptFile = new File( - Platform.script.resolve("datagram_error.dart").toFilePath(), - ); - var args = [scriptFile.path]; - ProcessResult syncResult = Process.runSync(dartPath, args); - Expect.notEquals(0, syncResult.exitCode); - Expect.stringEquals( - syncResult.stderr, - "Unexpected type for socket address" + Platform.lineTerminator, + SocketException? error; + try { + await RawDatagramSocket.bind( + InternetAddress('/tmp/test_socket', type: InternetAddressType.unix), + 0, + ); + } on SocketException catch (e) { + error = e; + } + Expect.contains( + 'Cannot bind datagram socket on non-IPv4/IPv6 address', + '$error', ); }