Skip to content

Commit b46f000

Browse files
committed
ts: improve coverage of Tcl ext library on OSX
Test Modules Tcl extended C library on Mac OSX against broken syscall that are injected through DYLD, using its interposing mechanism [1]. [1] http://toves.freeshell.org/interpose/ Signed-off-by: Xavier Delaruelle <xavier.delaruelle@cea.fr>
1 parent facea59 commit b46f000

10 files changed

Lines changed: 159 additions & 21 deletions

File tree

.github/workflows/macos_tests.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ jobs:
1313
env:
1414
CONFIGURE_OPTS: --prefix=/tmp/modules --with-loadedmodules=null:dot --with-tcl=/opt/homebrew/lib --with-tclsh=/opt/homebrew/bin/tclsh
1515
COVERAGE: y
16+
EXTRA_SCRIPT_PRETEST: make install-testsiteconfig-1 && export TESTSUITE_ENABLE_SITECONFIG=1
17+
EXTRA_SCRIPT_POSTTEST: unset TESTSUITE_ENABLE_SITECONFIG
1618
steps:
1719
- uses: actions/checkout@v6
1820
with:
@@ -30,8 +32,15 @@ jobs:
3032
make
3133
- name: Test Modules build
3234
run: |
35+
# specific compiling to enable DYLD library insertion
36+
for f in lib/testutil-*.c; do
37+
n=$(basename "$f" .c)
38+
clang -dynamiclib -arch arm64 -arch arm64e -o lib/lib${n}.dylib lib/${n}.c
39+
done
40+
eval $EXTRA_SCRIPT_PRETEST
3341
make test-deps
3442
script/mt
43+
eval $EXTRA_SCRIPT_POSTTEST
3544
- name: Install Modules
3645
run: |
3746
make install

.hunspell.en.dic

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1334,3 +1334,5 @@ YYYYMMDD
13341334
roadmap
13351335
CI
13361336
GHA
1337+
ts
1338+
OSX

lib/testutil-0getgroups.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*************************************************************************
22
*
33
* TESTUTIL-GETGROUPS.C, Superseded getgroups function for test purpose
4-
* Copyright (C) 2020-2021 Xavier Delaruelle
4+
* Copyright (C) 2020-2026 Xavier Delaruelle
55
*
66
* This program is free software: you can redistribute it and/or modify
77
* it under the terms of the GNU General Public License as published by
@@ -22,7 +22,7 @@
2222

2323
int getgroups(int size, gid_t list[])
2424
{
25-
return 0;
25+
return 0;
2626
}
2727

2828
/* vim:set tabstop=3 shiftwidth=3 expandtab autoindent: */

lib/testutil-closedir.c

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*************************************************************************
22
*
33
* TESTUTIL-CLOSEDIR.C, Superseded closedir function for test purpose
4-
* Copyright (C) 2019-2021 Xavier Delaruelle
4+
* Copyright (C) 2019-2026 Xavier Delaruelle
55
*
66
* This program is free software: you can redistribute it and/or modify
77
* it under the terms of the GNU General Public License as published by
@@ -20,9 +20,30 @@
2020

2121
#include <dirent.h>
2222

23+
#if defined (__APPLE__)
24+
25+
int my_closedir(DIR *dirp)
26+
{
27+
return -1;
28+
}
29+
30+
/* Code injection with DYLD interposing */
31+
__attribute__((used))
32+
static struct {
33+
const void *replacement;
34+
const void *replacee;
35+
} interposers[]
36+
__attribute__((section("__DATA,__interpose"))) = {
37+
{ (const void *)my_closedir, (const void *)closedir }
38+
};
39+
40+
#else
41+
2342
int closedir(DIR *dirp)
2443
{
25-
return -1;
44+
return -1;
2645
}
2746

47+
#endif
48+
2849
/* vim:set tabstop=3 shiftwidth=3 expandtab autoindent: */

lib/testutil-getgroups.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*************************************************************************
22
*
33
* TESTUTIL-GETGROUPS.C, Superseded getgroups function for test purpose
4-
* Copyright (C) 2020-2021 Xavier Delaruelle
4+
* Copyright (C) 2020-2026 Xavier Delaruelle
55
*
66
* This program is free software: you can redistribute it and/or modify
77
* it under the terms of the GNU General Public License as published by
@@ -22,7 +22,7 @@
2222

2323
int getgroups(int size, gid_t list[])
2424
{
25-
return -1;
25+
return -1;
2626
}
2727

2828
/* vim:set tabstop=3 shiftwidth=3 expandtab autoindent: */

lib/testutil-getpwuid.c

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*************************************************************************
22
*
33
* TESTUTIL-GETPWUID.C, Superseded getpwuid function for test purpose
4-
* Copyright (C) 2020-2021 Xavier Delaruelle
4+
* Copyright (C) 2020-2026 Xavier Delaruelle
55
*
66
* This program is free software: you can redistribute it and/or modify
77
* it under the terms of the GNU General Public License as published by
@@ -21,9 +21,30 @@
2121
#include <stddef.h>
2222
#include <pwd.h>
2323

24+
#if defined (__APPLE__)
25+
26+
struct passwd *my_getpwuid(uid_t uid)
27+
{
28+
return NULL;
29+
}
30+
31+
/* Code injection with DYLD interposing */
32+
__attribute__((used))
33+
static struct {
34+
const void *replacement;
35+
const void *replacee;
36+
} interposers[]
37+
__attribute__((section("__DATA,__interpose"))) = {
38+
{ (const void *)my_getpwuid, (const void *)getpwuid }
39+
};
40+
41+
#else
42+
2443
struct passwd *getpwuid(uid_t uid)
2544
{
26-
return NULL;
45+
return NULL;
2746
}
2847

48+
#endif
49+
2950
/* vim:set tabstop=3 shiftwidth=3 expandtab autoindent: */

lib/testutil-mktime.c

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*************************************************************************
22
*
33
* TESTUTIL-MKTIME.C, Superseded mktime function for test purpose
4-
* Copyright (C) 2020-2021 Xavier Delaruelle
4+
* Copyright (C) 2020-2026 Xavier Delaruelle
55
*
66
* This program is free software: you can redistribute it and/or modify
77
* it under the terms of the GNU General Public License as published by
@@ -20,9 +20,30 @@
2020

2121
#include <time.h>
2222

23+
#if defined (__APPLE__)
24+
25+
time_t my_mktime(struct tm *tm)
26+
{
27+
return -1;
28+
}
29+
30+
/* Code injection with DYLD interposing */
31+
__attribute__((used))
32+
static struct {
33+
const void *replacement;
34+
const void *replacee;
35+
} interposers[]
36+
__attribute__((section("__DATA,__interpose"))) = {
37+
{ (const void *)my_mktime, (const void *)mktime }
38+
};
39+
40+
#else
41+
2342
time_t mktime(struct tm *tm)
2443
{
25-
return -1;
44+
return -1;
2645
}
2746

47+
#endif
48+
2849
/* vim:set tabstop=3 shiftwidth=3 expandtab autoindent: */

lib/testutil-time.c

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*************************************************************************
22
*
33
* TESTUTIL-TIME.C, Superseded time function for test purpose
4-
* Copyright (C) 2020-2021 Xavier Delaruelle
4+
* Copyright (C) 2020-2026 Xavier Delaruelle
55
*
66
* This program is free software: you can redistribute it and/or modify
77
* it under the terms of the GNU General Public License as published by
@@ -20,9 +20,30 @@
2020

2121
#include <time.h>
2222

23+
#if defined (__APPLE__)
24+
25+
time_t my_time(time_t *tloc)
26+
{
27+
return -1;
28+
}
29+
30+
/* Code injection with DYLD interposing */
31+
__attribute__((used))
32+
static struct {
33+
const void *replacement;
34+
const void *replacee;
35+
} interposers[]
36+
__attribute__((section("__DATA,__interpose"))) = {
37+
{ (const void *)my_time, (const void *)time }
38+
};
39+
40+
#else
41+
2342
time_t time(time_t *tloc)
2443
{
25-
return -1;
44+
return -1;
2645
}
2746

47+
#endif
48+
2849
/* vim:set tabstop=3 shiftwidth=3 expandtab autoindent: */

testsuite/example/siteconfig.tcl-1

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,11 @@ if {[info exists env(TESTSUITE_ENABLE_SITECONFIG_TCLEXTLIBFAILEDGETPWUID)]} {
145145
if {[catch {initStateUsername} errMsg]} {
146146
reportError $errMsg
147147
}
148+
if {$tcl_platform(os) eq "Darwin"} {
149+
if {[catch {[initStateUsergroups]} errMsg]} {
150+
reportError $errMsg
151+
}
152+
}
148153
}
149154

150155
# test tcl ext lib procedures against a failed getgroups call

testsuite/modules.00-init/120-siteconfig.exp

Lines changed: 47 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -410,33 +410,54 @@ if {[info exists tclextlib_file]} {
410410
# test tcl ext lib procedures against a failed closedir call
411411
if {[info exists closedirlib_file] && [file exists $closedirlib_file]} {
412412
setenv_var TESTSUITE_ENABLE_SITECONFIG_TCLEXTLIBFAILEDCLOSEDIR 1
413-
setenv_var LD_PRELOAD $closedirlib_file
413+
if {$tcl_platform(os) ne "Darwin"} {
414+
setenv_var LD_PRELOAD $closedirlib_file
415+
} else {
416+
setenv_var DYLD_INSERT_LIBRARIES $closedirlib_file
417+
}
414418
set ans [list]
415-
lappend ans "$error_msgs: couldn't close directory \"$modpathre\": Success"
419+
lappend ans "$error_msgs: couldn't close directory \"$modpathre\": .*"
416420
lappend ans $vers_reportre
417421
testouterr_cmd_re sh -V OK [join $ans \n]
418422

419423
unsetenv_var TESTSUITE_ENABLE_SITECONFIG_TCLEXTLIBFAILEDCLOSEDIR
420-
unsetenv_var LD_PRELOAD
424+
if {$tcl_platform(os) ne "Darwin"} {
425+
unsetenv_var LD_PRELOAD
426+
} else {
427+
unsetenv_var DYLD_INSERT_LIBRARIES
428+
}
421429
} elseif {$verbose} {
422430
send_user "\tSkip tcl ext lib erroneous procedure calls as closedir test lib is not available\n"
423431
}
424432

425433
# test tcl ext lib procedures against a failed getpwuid call
426434
if {[info exists getpwuidlib_file] && [file exists $getpwuidlib_file]} {
427435
setenv_var TESTSUITE_ENABLE_SITECONFIG_TCLEXTLIBFAILEDGETPWUID 1
428-
setenv_var LD_PRELOAD $getpwuidlib_file
436+
if {$tcl_platform(os) ne "Darwin"} {
437+
setenv_var LD_PRELOAD $getpwuidlib_file
438+
} else {
439+
setenv_var DYLD_INSERT_LIBRARIES $getpwuidlib_file
440+
}
429441
set ans [list]
430442
lappend ans "$error_msgs: couldn't find name for user id \"$userid\": .*"
443+
if {$tcl_platform(os) eq "Darwin"} {
444+
lappend ans "$error_msgs: couldn't find name for user id \"$userid\": .*"
445+
}
431446
lappend ans $vers_reportre
432447
testouterr_cmd_re sh -V OK [join $ans \n]
433448

434449
unsetenv_var TESTSUITE_ENABLE_SITECONFIG_TCLEXTLIBFAILEDGETPWUID
435-
unsetenv_var LD_PRELOAD
450+
if {$tcl_platform(os) ne "Darwin"} {
451+
unsetenv_var LD_PRELOAD
452+
} else {
453+
unsetenv_var DYLD_INSERT_LIBRARIES
454+
}
436455
} elseif {$verbose} {
437456
send_user "\tSkip tcl ext lib erroneous procedure calls as getpwuid test lib is not available\n"
438457
}
439458

459+
# getgroups syscall is not used on Darwin
460+
if {$tcl_platform(os) ne "Darwin"} {
440461
# test tcl ext lib procedures against a failed getgroups call
441462
if {[info exists getgroupslib_file] && [file exists $getgroupslib_file]} {
442463
setenv_var TESTSUITE_ENABLE_SITECONFIG_TCLEXTLIBFAILEDGETGROUPS 1
@@ -481,18 +502,27 @@ if {[info exists dupgetgroupslib_file] && [file exists $dupgetgroupslib_file]} {
481502
} elseif {$verbose} {
482503
send_user "\tSkip tcl ext lib erroneous procedure calls as dupgetgroups test lib is not available\n"
483504
}
505+
}
484506

485507
# test tcl ext lib procedures against a failed time call
486508
if {[info exists timelib_file] && [file exists $timelib_file]} {
487509
setenv_var TESTSUITE_ENABLE_SITECONFIG_TCLEXTLIBFAILEDTIME 1
488-
setenv_var LD_PRELOAD $timelib_file
510+
if {$tcl_platform(os) ne "Darwin"} {
511+
setenv_var LD_PRELOAD $timelib_file
512+
} else {
513+
setenv_var DYLD_INSERT_LIBRARIES $timelib_file
514+
}
489515
set ans [list]
490516
lappend ans "$error_msgs: couldn't get Epoch time: .*"
491517
lappend ans $vers_reportre
492518
testouterr_cmd_re sh -V OK [join $ans \n]
493519

494520
unsetenv_var TESTSUITE_ENABLE_SITECONFIG_TCLEXTLIBFAILEDTIME
495-
unsetenv_var LD_PRELOAD
521+
if {$tcl_platform(os) ne "Darwin"} {
522+
unsetenv_var LD_PRELOAD
523+
} else {
524+
unsetenv_var DYLD_INSERT_LIBRARIES
525+
}
496526
} elseif {$verbose} {
497527
send_user "\tSkip tcl ext lib erroneous procedure calls as time test lib is not available\n"
498528
}
@@ -508,14 +538,22 @@ unsetenv_var TESTSUITE_ENABLE_SITECONFIG_PARSEDATETIMEARG_NOARG
508538
# test tcl ext lib procedures against a failed mktime call
509539
if {[info exists mktimelib_file] && [file exists $mktimelib_file]} {
510540
setenv_var TESTSUITE_ENABLE_SITECONFIG_TCLEXTLIBFAILEDMKTIME 1
511-
setenv_var LD_PRELOAD $mktimelib_file
541+
if {$tcl_platform(os) ne "Darwin"} {
542+
setenv_var LD_PRELOAD $mktimelib_file
543+
} else {
544+
setenv_var DYLD_INSERT_LIBRARIES $mktimelib_file
545+
}
512546
set ans [list]
513547
lappend ans "$error_msgs: couldn't convert to Epoch time: .*"
514548
lappend ans $vers_reportre
515549
testouterr_cmd_re sh -V OK [join $ans \n]
516550

517551
unsetenv_var TESTSUITE_ENABLE_SITECONFIG_TCLEXTLIBFAILEDMKTIME
518-
unsetenv_var LD_PRELOAD
552+
if {$tcl_platform(os) ne "Darwin"} {
553+
unsetenv_var LD_PRELOAD
554+
} else {
555+
unsetenv_var DYLD_INSERT_LIBRARIES
556+
}
519557
} elseif {$verbose} {
520558
send_user "\tSkip tcl ext lib erroneous procedure calls as mktime test lib is not available\n"
521559
}

0 commit comments

Comments
 (0)