Skip to content

Commit 8a90f04

Browse files
authored
[native_toolchain_c] Fix page size assertions in tests (#2838)
Fixes #2837 The tests that asserted on the page size started failing on macOS (see #2837). According to Gemini they weren't asserting on the right thing: The virtual memory address within a section (this is what the test was asserting) is not the same thing as the alignment of the ELF load segment (this is what the test supposedly wanted to test to verify that the page size setting was honored).
1 parent a442528 commit 8a90f04

File tree

2 files changed

+30
-35
lines changed

2 files changed

+30
-35
lines changed

pkgs/native_toolchain_c/test/cbuilder/cbuilder_cross_android_test.dart

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -91,11 +91,7 @@ void main() {
9191
linkMode,
9292
flags: ['-Wl,-z,max-page-size=$pageSize'],
9393
);
94-
if (Platform.isMacOS || Platform.isLinux) {
95-
final address = await textSectionAddress(libUri);
96-
expect(address, greaterThanOrEqualTo(pageSize));
97-
expect(address, isNot(greaterThanOrEqualTo(pageSize * 4)));
98-
}
94+
await expectPageSize(libUri, pageSize);
9995
});
10096
}
10197

pkgs/native_toolchain_c/test/helpers.dart

Lines changed: 29 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import 'dart:async';
66
import 'dart:ffi';
77
import 'dart:io';
8+
import 'dart:math' as math;
89

910
import 'package:code_assets/code_assets.dart';
1011
import 'package:logging/logging.dart';
@@ -245,47 +246,45 @@ Future<RunProcessResult?> _runDumpbin(
245246
);
246247
}
247248

248-
Future<int> textSectionAddress(Uri dylib) async {
249+
Future<void> expectPageSize(Uri dylib, int pageSize) async {
249250
if (Platform.isMacOS) {
250251
// Find the line in the objdump output that looks like:
251-
// 11 .text 00000046 00000000000045a0 TEXT
252+
// LOAD off 0x00000000 vaddr 0x00000000 paddr 0x00000000 align 2**14
252253
final result = await runProcess(
253254
executable: Uri.file('objdump'),
254-
arguments: ['--headers', dylib.toFilePath()],
255+
arguments: ['-p', dylib.toFilePath()],
255256
logger: logger,
256257
);
257258
expect(result.exitCode, 0);
258-
final textSection = result.stdout
259+
final loadHeader = result.stdout
259260
.split('\n')
260-
.firstWhere((e) => e.contains('.text'));
261-
final parsed = textSection.split(' ').where((e) => e.isNotEmpty).toList();
262-
expect(parsed[1], '.text');
263-
expect(parsed[4], 'TEXT');
264-
final vma = int.parse(parsed[3], radix: 16);
265-
return vma;
261+
.firstWhere((e) => e.contains('LOAD'));
262+
final parsed = loadHeader.split(' ').where((e) => e.isNotEmpty).toList();
263+
expect(parsed[7], 'align');
264+
expect(parsed[8], startsWith('2**'));
265+
final alignment = math.pow(2, int.parse(parsed[8].substring('2**'.length)));
266+
expect(alignment, pageSize);
266267
}
267268
if (Platform.isLinux) {
269+
// The readelf output has the following structure:
270+
// Type Offset VirtAddr PhysAddr
271+
// FileSiz MemSiz Flags Align
268272
// Find the line in the readelf output that looks like:
269-
// [11] .text PROGBITS 00004328 000328 000064 00 AX 0 0 4
270-
final result = await readelf(dylib.toFilePath(), 'S');
271-
final textSection = result
272-
.split('\n')
273-
.firstWhere((e) => e.contains('.text'));
274-
final parsed = textSection.split(' ').where((e) => e.isNotEmpty).toList();
275-
expect(parsed[1], '.text');
276-
expect(parsed[2], 'PROGBITS');
277-
final addr = int.parse(parsed[3], radix: 16);
278-
return addr;
279-
}
280-
throw UnimplementedError();
281-
}
282-
283-
Future<void> expectPageSize(Uri dylib, int pageSize) async {
284-
if (Platform.isMacOS || Platform.isLinux) {
285-
// If page size is 16kb, the `.text` section address should be
286-
// above 0x4000. With smaller page sizes it's above 0x1000.
287-
final vma = await textSectionAddress(dylib);
288-
expect(vma, greaterThanOrEqualTo(pageSize));
273+
// LOAD 0x0000000000000000 0x0000000000000000 0x0000000000000000
274+
// 0x0000000000000528 0x0000000000000528 R 0x1000
275+
final result = await readelf(dylib.toFilePath(), 'l');
276+
// Capture the line after the line that contains "LOAD".
277+
final regExp = RegExp('LOAD.*\n(.*)');
278+
final loadSegment = regExp.firstMatch(result)!.group(1)!;
279+
final alignment = int.parse(
280+
loadSegment
281+
.split(' ')
282+
.where((e) => e.isNotEmpty)
283+
.last
284+
.substring('0x'.length),
285+
radix: 16,
286+
);
287+
expect(alignment, pageSize);
289288
}
290289
}
291290

0 commit comments

Comments
 (0)