[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 <kustermann@google.com>
Reviewed-by: Slava Egorov <vegorov@google.com>
This commit is contained in:
Martin Kustermann
2025-07-02 00:17:33 -07:00
committed by Commit Queue
parent 9918fa0593
commit 9b916b2f14
3 changed files with 20 additions and 50 deletions
@@ -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,
-30
View File
@@ -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",
);
}
}
+13 -20
View File
@@ -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 = <String>[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',
);
}