Compare commits

..
Author SHA1 Message Date
Gordon Bolton 39cad74c43 Fix SIGSEGV in i1Pro 2 teardown and cleanup
Windows x86_64 Release Build / build (push) Successful in 8m50s
Linux x86_64 Release Build / build (push) Successful in 21m53s
- Relocate LED turn-off to i1pro_close_port() before closing communication port
- Guard LED turn-off and log updates against NULL pointers and closed ports in del_i1proimp()
- Ensure clean termination, unblock, and joining of i1pro switch and trigger threads in both i1pro_close_port() and del_i1proimp()
- Protect against NULL terminate callback on Unix/macOS
2026-09-04 14:39:59 +01:00
gronod d1bf83928d Merge pull request 'Fix update macos runners' (#35) from fix-update-macos-runners into development
Reviewed-on: #35
2026-09-01 12:10:00 +01:00
gronod e194514264 Update .github/workflows/build-macos.yml 2026-09-01 12:09:14 +01:00
gronod 2261ebd331 Merge pull request 'Development' (#34) from development into main
Windows x86_64 Release Build / build (push) Failing after 1m10s
Linux x86_64 Release Build / build (push) Successful in 9m58s
Reviewed-on: #34
2026-09-01 11:22:12 +01:00
gronod de3065f4cc Merge pull request 'Update .github/workflows/build-macos.yml' (#33) from update-macos-act-runner into development
Reviewed-on: #33
2026-09-01 11:21:15 +01:00
gronod 9c3982354d Update .github/workflows/build-macos.yml
Update action runner for MacOS to macos-latest
2026-09-01 11:20:43 +01:00
gronod 86e692ecda ci(macos): add ad-hoc codesigning and signature verification to macOS workflow 2026-09-01 10:18:18 +01:00
gronod f30d16816f fix(package): apply ad-hoc code signatures to macOS Mach-O binaries in makepackagebin.sh 2026-09-01 10:18:10 +01:00
gronod cf93305fdd ci(macos): add ad-hoc codesigning and signature verification to macOS workflow
Windows x86_64 Release Build / build (push) Successful in 8m21s
Linux x86_64 Release Build / build (push) Successful in 49m44s
2026-09-01 10:17:34 +01:00
gronod 1eb72e865b fix(package): apply ad-hoc code signatures to macOS Mach-O binaries in makepackagebin.sh 2026-09-01 10:17:06 +01:00
gronod e0f86eec29 Merge development into main (v3.5.0-ICCery.1.4)
Linux x86_64 Release Build / build (push) Successful in 9m37s
Windows x86_64 Release Build / build (push) Successful in 9m38s
Merge pull request 'Merge development into main (v3.5.0-ICCery.1.4)' (#31) from development into main
2026-09-01 00:16:56 +01:00
gronod c196912bed Fix: Handle non-Mach-O files during macOS universal binary lipo assembly
Merge pull request 'Fix: Handle non-Mach-O files during macOS universal binary lipo assembly' (#30) from fix/macos-universal-non-macho-lipo into development
2026-09-01 00:16:49 +01:00
gronod ebbc675297 fix(ci): handle non-Mach-O files like metainfo.xml during universal lipo assembly 2026-09-01 00:16:11 +01:00
5 changed files with 175 additions and 41 deletions
+39 -9
View File
@@ -11,11 +11,11 @@ jobs:
strategy:
matrix:
include:
- os: macos-15-intel
- os: macos-26-intel
arch: x86_64
machtype: x86_64-apple-darwin
artifact: macOS_x86_64_bin
- os: macos-15
- os: macos-latest
arch: arm64
machtype: arm64-apple-darwin
artifact: macOS_arm64_bin
@@ -43,6 +43,16 @@ jobs:
export CCOPTFLAG="-O0"
jam -q -d2 -fJambase -j1 -sBUILTIN_TIFF=true -sBUILTIN_JPEG=true -sBUILTIN_PNG=true -sBUILTIN_Z=true -sBUILTIN_SSL=true install
- name: Ad-hoc Sign & Verify Binaries
run: |
for f in bin/*; do
if [ -f "$f" ] && file "$f" | grep -q "Mach-O"; then
echo "Ad-hoc signing $f"
codesign -f -s - "$f"
codesign -dvv "$f"
fi
done
- name: Smoke Tests
env:
ARGYLL_NOT_INTERACTIVE: "1"
@@ -86,7 +96,7 @@ jobs:
universal:
needs: build
runs-on: macos-15
runs-on: macos-latest
permissions:
contents: write
@@ -112,24 +122,44 @@ jobs:
for file in raw-bin-arm64/*; do
bin_name=$(basename "$file")
if [ -f "raw-bin-x86_64/$bin_name" ]; then
echo "Creating universal binary with lipo: $bin_name"
lipo -create "raw-bin-x86_64/$bin_name" "raw-bin-arm64/$bin_name" -output "bin/$bin_name"
chmod +x "bin/$bin_name"
if file "raw-bin-arm64/$bin_name" | grep -q "Mach-O" && file "raw-bin-x86_64/$bin_name" | grep -q "Mach-O"; then
echo "Creating universal binary with lipo: $bin_name"
lipo -create "raw-bin-x86_64/$bin_name" "raw-bin-arm64/$bin_name" -output "bin/$bin_name"
chmod +x "bin/$bin_name"
codesign -f -s - "bin/$bin_name"
else
echo "Non Mach-O file, copying directly: $bin_name"
cp "$file" "bin/$bin_name"
fi
else
echo "Warning: $bin_name not found in raw-bin-x86_64, copying arm64 version"
cp "$file" "bin/$bin_name"
if file "bin/$bin_name" | grep -q "Mach-O"; then
codesign -f -s - "bin/$bin_name"
fi
fi
done
for file in raw-bin-x86_64/*; do
bin_name=$(basename "$file")
if [ ! -f "bin/$bin_name" ]; then
echo "Warning: $bin_name only found in raw-bin-x86_64, copying x86_64 version"
cp "$file" "bin/$bin_name"
if file "bin/$bin_name" | grep -q "Mach-O"; then
codesign -f -s - "bin/$bin_name"
fi
fi
done
- name: Verify Architecture & Smoke Tests
- name: Verify Architecture & Code Signatures
env:
ARGYLL_NOT_INTERACTIVE: "1"
ARGYLL_EXCLUDE_SERIAL_SCAN: "1"
run: |
echo "=== Binary Architecture Verification ==="
echo "=== Binary Architecture & Signature Verification ==="
for file in bin/*; do
if [ -f "$file" ]; then
if [ -f "$file" ] && file "$file" | grep -q "Mach-O"; then
file "$file"
codesign -dvv "$file"
fi
done
echo "=== Smoke Tests ==="
+12 -1
View File
@@ -7,7 +7,7 @@ echo "Script to invoke Jam and then package the binary release."
PRODUCT=Argyll
# Set the environment string VERSION from the #define, ie 1.0.0
VERSION=`grep ARGYLL_VERSION_STR h/aconfig.h | head -1 | sed 's/# define ARGYLL_VERSION_STR //' | sed 's/"//g'`
VERSION=`grep ARGYLL_VERSION_STR h/aconfig.h | head -1 | sed 's/# define ARGYLL_VERSION_STR //' | sed 's/\"//g'`
# Typical environment variables:
# (NOTE some systems don't export these ENV vars. by default !!!)
@@ -173,6 +173,17 @@ if [ X$NO_BUILD = "X" ] ; then
fi
fi
# Apply ad-hoc code signatures to macOS Mach-O binaries before staging
if [ "${OSTYPE#*darwin*}" != "$OSTYPE" ] ; then
echo "=== Applying ad-hoc code signatures to macOS Mach-O binaries ==="
for f in bin/* ; do
if [ -f "$f" ] && file "$f" | grep -q "Mach-O" ; then
echo "Signing $f..."
codesign -f -s - "$f" || true
fi
done
fi
rm -rf $TOPDIR
mkdir $TOPDIR
+2
View File
@@ -948,6 +948,8 @@ static void
i1pro_del(inst *pp) {
i1pro *p = (i1pro *)pp;
/* Shut down instrument hardware and close the port, then free state */
i1pro_close_port(p);
del_i1proimp(p);
if (p->icom != NULL)
p->icom->del(p->icom);
+119 -31
View File
@@ -389,8 +389,106 @@ i1pro_code add_i1proimp(i1pro *p) {
return I1PRO_OK;
}
/* Shutdown instrument, and then destroy */
/* implementation structure */
/* Stop background threads (switch monitoring & delayed trigger) */
static void
i1pro_stop_threads(i1pro *p) {
i1proimp *m;
int i;
if (p == NULL || p->m == NULL)
return;
m = (i1proimp *)p->m;
/* Stop the switch monitoring thread first so it isn't using the */
/* communication channel while we shut down the instrument. */
if (m->th != NULL) {
m->th_term = 1; /* Tell thread to exit on error */
/* Ask the instrument to stop sending switch events and cancel */
/* any outstanding switch read. Only do this if the port is still */
/* open and the required method pointers are valid. */
if (p->icom != NULL && p->icom->is_open
&& p->icom->usb_control != NULL
&& p->icom->usb_cancel_io != NULL) {
i1pro_terminate_switch(p);
}
/* Give the thread a chance to exit cleanly (up to 5 seconds). */
for (i = 0; m->th_termed == 0 && i < 100; i++)
msec_sleep(50);
if (m->th_termed == 0) {
a1logd(p->log,3,"i1pro switch thread did not terminate, forcing\n");
if (m->th->terminate != NULL)
m->th->terminate(m->th);
}
if (m->th->wait != NULL)
m->th->wait(m->th);
if (m->th->del != NULL)
m->th->del(m->th);
m->th = NULL;
usb_uninit_cancel(&m->sw_cancel); /* Don't need cancel token now */
usb_uninit_cancel(&m->rd_sync); /* Don't need sync token now */
a1logd(p->log,5,"i1pro switch thread terminated\n");
}
/* Stop the delayed trigger thread if it is still running */
if (m->trig_thread != NULL) {
if (m->trig_thread->wait != NULL)
m->trig_thread->wait(m->trig_thread);
if (m->trig_thread->del != NULL)
m->trig_thread->del(m->trig_thread);
m->trig_thread = NULL;
a1logd(p->log,5,"i1pro trigger thread terminated\n");
}
}
/* Stop any pending I/O, shut down the instrument hardware, and close the */
/* communication port. This is separate from freeing the implementation data. */
i1pro_code
i1pro_close_port(i1pro *p) {
i1pro_code ev = I1PRO_OK;
i1proimp *m;
a1logd(p->log,3,"i1pro_close_port: called\n");
if (p->m == NULL)
return I1PRO_OK;
m = (i1proimp *)p->m;
/* Stop the switch monitoring thread and trigger thread first so they */
/* aren't using the communication channel while we shut down the instrument. */
i1pro_stop_threads(p);
/* Update usage log/calibration for Rev A..D before closing the port */
if (p->dtype != instI1Pro2 && p->icom != NULL && p->icom->is_open
&& p->icom->usb_control != NULL && p->icom->usb_write != NULL) {
i1pro_code uev;
if ((uev = i1pro_update_log(p)) != I1PRO_OK) {
a1logd(p->log,2,"i1pro_update_log: Updating the cal and log parameters to"
" EEProm failed failed\n");
}
}
/* Turn off i1Pro2/Rev E indicator LEDs before closing the port. */
/* Only attempt the write if the port is still actively open and the */
/* required USB method pointers are valid. Rev A..D do not have LEDs. */
if (p->dtype == instI1Pro2 && p->icom != NULL && p->icom->is_open
&& p->icom->usb_control != NULL && p->icom->usb_write != NULL) {
i1pro2_indLEDoff(p); /* Ignore error - we're shutting down */
}
/* Close the underlying communication port */
if (p->icom != NULL && p->icom->is_open && p->icom->close_port != NULL) {
p->icom->close_port(p->icom);
}
return ev;
}
/* Destroy implementation structure */
void del_i1proimp(i1pro *p) {
a1logd(p->log,5,"i1pro_del called\n");
@@ -404,38 +502,28 @@ void del_i1proimp(i1pro *p) {
int i, j;
i1proimp *m = (i1proimp *)p->m;
i1pro_state *s;
i1pro_code ev;
if (p->dtype != instI1Pro2 && (ev = i1pro_update_log(p)) != I1PRO_OK) {
a1logd(p->log,2,"i1pro_update_log: Updating the cal and log parameters to"
" EEProm failed failed\n");
/* Defensive guard: ensure background threads are terminated and joined */
/* before freeing state, in case i1pro_close_port() was not called. */
i1pro_stop_threads(p);
/* Defensive guard: update usage log/cal for Rev A..D if port is still open */
if (p->dtype != instI1Pro2 && p->icom != NULL && p->icom->is_open
&& p->icom->usb_control != NULL && p->icom->usb_write != NULL) {
i1pro_code uev;
if ((uev = i1pro_update_log(p)) != I1PRO_OK) {
a1logd(p->log,2,"i1pro_update_log: Updating the cal and log parameters to"
" EEProm failed failed\n");
}
}
/* i1pro_terminate_switch() seems to fail on a rev A & Rev C ?? */
if (m->th != NULL) { /* Terminate switch monitor thread */
m->th_term = 1; /* Tell thread to exit on error */
i1pro_terminate_switch(p);
for (i = 0; m->th_termed == 0 && i < 5; i++)
msec_sleep(50); /* Wait for thread to terminate */
if (i >= 5) {
a1logd(p->log,5,"i1pro switch thread termination failed\n");
m->th->terminate(m->th); /* Try and force thread to terminate */
}
/* Strange Mac M2/rosetta bug ?? */
if (m->th->del == NULL) {
a1logd(p->log,1,"i1pro_del: ,m->th-del is NULL!!!");
} else {
m->th->del(m->th);
}
usb_uninit_cancel(&m->sw_cancel); /* Don't need cancel token now */
usb_uninit_cancel(&m->rd_sync); /* Don't need sync token now */
a1logd(p->log,5,"i1pro switch thread terminated\n");
}
if (m->trig_thread != NULL) {
m->trig_thread->del(m->trig_thread);
a1logd(p->log,5,"i1pro trigger thread terminated\n");
/* Defensive guard: if the com port is still open and this is an */
/* i1Pro2, make sure the indicator LEDs are turned off before any */
/* memory is freed. In normal teardown i1pro_close_port() has */
/* already done this, but the guard protects any direct call paths. */
if (p->dtype == instI1Pro2 && p->icom != NULL && p->icom->is_open
&& p->icom->usb_control != NULL && p->icom->usb_write != NULL) {
i1pro2_indLEDoff(p);
}
/* Free any per mode data */
+3
View File
@@ -348,6 +348,9 @@ i1pro_code add_i1proimp(i1pro *p);
/* Destroy implementation structure */
void del_i1proimp(i1pro *p);
/* Close instrument (stop threads, update log, turn off LEDs, close coms) */
i1pro_code i1pro_close_port(i1pro *p);
/* ============================================================ */
/* Error codes returned from i1pro_imp */