From 1d19e211c3195cf2283b101afc390e52dc1a9bb0 Mon Sep 17 00:00:00 2001 From: Don Cross Date: Mon, 23 Oct 2023 19:50:01 -0400 Subject: [PATCH] Fixed #323 - checks time pointers for NULL. Prevents crashes due to dereferencing NULL time pointers. Passing in NULL for a `time` pointer will no longer cause a crash in an Astronomy Engine function. Wherever possible, a NULL time pointer will result in a status code `ASTRO_INVALID_PARAMETER`. `Astronomy_Horizon` has no way to report a status code, so a null pointer causes it to return all NAN values. Perhaps it should return a status code (considering for separate commit). Thanks to [Steven Booth](https://github.com/sbooth) for suggesting this! --- generate/template/astronomy.c | 155 +++++++++++++++++++++++++++------- source/c/README.md | 2 +- source/c/astronomy.c | 155 +++++++++++++++++++++++++++------- 3 files changed, 247 insertions(+), 65 deletions(-) diff --git a/generate/template/astronomy.c b/generate/template/astronomy.c index 1eecda0b..78914b06 100644 --- a/generate/template/astronomy.c +++ b/generate/template/astronomy.c @@ -1370,7 +1370,7 @@ static void iau2000b(astro_time_t *time) { /* Truncated and hand-optimized nutation model. */ - if (isnan(time->psi)) + if ((time != NULL) && isnan(time->psi)) { double t, elp, f, d, om, arg, dp, de, sarg, carg; @@ -1443,6 +1443,8 @@ static earth_tilt_t e_tilt(astro_time_t *time) { earth_tilt_t et; + /* There is no good answer for what to do if time==NULL. Callers must prevent! */ + iau2000b(time); et.dpsi = time->psi; et.deps = time->eps; @@ -1656,26 +1658,33 @@ static astro_rotation_t nutation_rot(astro_time_t *time, precess_dir_t dir) */ astro_rotation_t rotation; - earth_tilt_t tilt = e_tilt(time); - double oblm = tilt.mobl * DEG2RAD; - double oblt = tilt.tobl * DEG2RAD; - double psi = tilt.dpsi * ASEC2RAD; - double cobm = cos(oblm); - double sobm = sin(oblm); - double cobt = cos(oblt); - double sobt = sin(oblt); - double cpsi = cos(psi); - double spsi = sin(psi); - - double xx = cpsi; - double yx = -spsi * cobm; - double zx = -spsi * sobm; - double xy = spsi * cobt; - double yy = cpsi * cobm * cobt + sobm * sobt; - double zy = cpsi * sobm * cobt - cobm * sobt; - double xz = spsi * sobt; - double yz = cpsi * cobm * sobt - sobm * cobt; - double zz = cpsi * sobm * sobt + cobm * cobt; + earth_tilt_t tilt; + double oblm, oblt, psi, cobm, sobm, cobt, sobt, cpsi, spsi; + double xx, yx, zx, xy, yy, zy, xz, yz, zz; + + if (time == NULL) + return RotationErr(ASTRO_INVALID_PARAMETER); + + tilt = e_tilt(time); + oblm = tilt.mobl * DEG2RAD; + oblt = tilt.tobl * DEG2RAD; + psi = tilt.dpsi * ASEC2RAD; + cobm = cos(oblm); + sobm = sin(oblm); + cobt = cos(oblt); + sobt = sin(oblt); + cpsi = cos(psi); + spsi = sin(psi); + + xx = cpsi; + yx = -spsi * cobm; + zx = -spsi * sobm; + xy = spsi * cobt; + yy = cpsi * cobm * cobt + sobm * sobt; + zy = cpsi * sobm * cobt - cobm * sobt; + xz = spsi * sobt; + yz = cpsi * cobm * sobt - sobm * cobt; + zz = cpsi * sobm * sobt + cobm * cobt; if (dir == FROM_2000) { @@ -1765,11 +1774,15 @@ static double era(double ut) /* Earth Rotation Angle */ * The parameter is passed by address because it can be modified by the call: * As an optimization, this function caches the sidereal time value in `time`, * unless it has already been cached, in which case the cached value is reused. + * If the `time` pointer is NULL, this function returns a NAN value. * * @returns {number} */ double Astronomy_SiderealTime(astro_time_t *time) { + if (time == NULL) + return NAN; + if (isnan(time->st)) { double t = time->tt / 36525.0; @@ -1906,10 +1919,17 @@ static void geo_pos(astro_time_t *time, astro_observer_t observer, double pos[3] double gast; double pos1[3], pos2[3]; - gast = Astronomy_SiderealTime(time); - terra(observer, gast, pos1, NULL); - nutation(pos1, time, INTO_2000, pos2); - precession(pos2, *time, INTO_2000, pos); + if (time == NULL) + { + pos[0] = pos[1] = pos[2] = NAN; + } + else + { + gast = Astronomy_SiderealTime(time); + terra(observer, gast, pos1, NULL); + nutation(pos1, time, INTO_2000, pos2); + precession(pos2, *time, INTO_2000, pos); + } } static void spin(double angle, const double pos1[3], double vec2[3]) @@ -4898,6 +4918,9 @@ astro_equatorial_t Astronomy_Equator( double temp[3]; double datevect[3]; + if (time == NULL) + return EquError(ASTRO_INVALID_PARAMETER); + /* Calculate the geocentric location of the observer. */ geo_pos(time, observer, gc_observer); @@ -4973,6 +4996,9 @@ astro_vector_t Astronomy_ObserverVector( astro_vector_t vec; double gast, pos[3], temp[3]; + if (time == NULL) + return VecError(ASTRO_INVALID_PARAMETER, TimeError()); + gast = Astronomy_SiderealTime(time); terra(observer, gast, pos, NULL); @@ -5050,6 +5076,9 @@ astro_state_vector_t Astronomy_ObserverState( astro_state_vector_t state; double gast, pos[3], vel[3], postemp[3], veltemp[3]; + if (time == NULL) + return StateVecError(ASTRO_INVALID_PARAMETER, TimeError()); + gast = Astronomy_SiderealTime(time); terra(observer, gast, pos, vel); @@ -5212,7 +5241,11 @@ double Astronomy_ObserverGravity(double latitude, double height) * The body's apparent horizontal coordinates and equatorial coordinates, both optionally corrected for refraction. */ astro_horizon_t Astronomy_Horizon( - astro_time_t *time, astro_observer_t observer, double ra, double dec, astro_refraction_t refraction) + astro_time_t *time, + astro_observer_t observer, + double ra, + double dec, + astro_refraction_t refraction) { astro_horizon_t hor; double latrad, lonrad, decrad, rarad; @@ -5222,6 +5255,17 @@ astro_horizon_t Astronomy_Horizon( double az, zd; double spin_angle; + if (time == NULL) + { + /* The best we can do is return an invalid state. */ + /* It would break external dependencies to expect them to check for errors. */ + hor.altitude = NAN; + hor.azimuth = NAN; + hor.ra = NAN; + hor.dec = NAN; + return hor; + } + latrad = observer.latitude * DEG2RAD; lonrad = observer.longitude * DEG2RAD; decrad = dec * DEG2RAD; @@ -5831,8 +5875,11 @@ static int QuadInterp( static astro_status_t FindSeasonChange(double targetLon, int year, int month, int day, astro_time_t *time) { - astro_time_t startTime = Astronomy_MakeTime(year, month, day, 0, 0, 0.0); - astro_search_result_t result = Astronomy_SearchSunLongitude(targetLon, startTime, 20.0); + astro_time_t startTime; + astro_search_result_t result; + + startTime = Astronomy_MakeTime(year, month, day, 0, 0, 0.0); + result = Astronomy_SearchSunLongitude(targetLon, startTime, 20.0); *time = result.time; return result.status; } @@ -6759,6 +6806,9 @@ astro_func_result_t Astronomy_HourAngle(astro_body_t body, astro_time_t *time, a astro_equatorial_t ofdate; double gast; + if (time == NULL) + return FuncError(ASTRO_INVALID_PARAMETER); + /* Calculate Greenwich Apparent Sidereal Time (GAST) at the given time. */ gast = Astronomy_SiderealTime(time); @@ -8990,6 +9040,9 @@ astro_rotation_t Astronomy_Rotation_EQJ_EQD(astro_time_t *time) { astro_rotation_t prec, nut; + if (time == NULL) + return RotationErr(ASTRO_INVALID_PARAMETER); + prec = precession_rot(*time, FROM_2000); nut = nutation_rot(time, FROM_2000); return Astronomy_CombineRotation(prec, nut); @@ -9015,6 +9068,9 @@ astro_rotation_t Astronomy_Rotation_EQJ_ECT(astro_time_t *time) { astro_rotation_t rot, step; + if (time == NULL) + return RotationErr(ASTRO_INVALID_PARAMETER); + rot = Astronomy_Rotation_EQJ_EQD(time); step = Astronomy_Rotation_EQD_ECT(time); return Astronomy_CombineRotation(rot, step); @@ -9040,6 +9096,9 @@ astro_rotation_t Astronomy_Rotation_ECT_EQJ(astro_time_t *time) { astro_rotation_t rot, step; + if (time == NULL) + return RotationErr(ASTRO_INVALID_PARAMETER); + rot = Astronomy_Rotation_ECT_EQD(time); step = Astronomy_Rotation_EQD_EQJ(time); return Astronomy_CombineRotation(rot, step); @@ -9065,6 +9124,9 @@ astro_rotation_t Astronomy_Rotation_EQD_EQJ(astro_time_t *time) { astro_rotation_t prec, nut; + if (time == NULL) + return RotationErr(ASTRO_INVALID_PARAMETER); + nut = nutation_rot(time, INTO_2000); prec = precession_rot(*time, INTO_2000); return Astronomy_CombineRotation(nut, prec); @@ -9100,6 +9162,9 @@ astro_rotation_t Astronomy_Rotation_EQD_HOR(astro_time_t *time, astro_observer_t double uz[3], un[3], uw[3]; double spin_angle; + if (time == NULL) + return RotationErr(ASTRO_INVALID_PARAMETER); + double sinlat = sin(observer.latitude * DEG2RAD); double coslat = cos(observer.latitude * DEG2RAD); double sinlon = sin(observer.longitude * DEG2RAD); @@ -9178,6 +9243,9 @@ astro_rotation_t Astronomy_Rotation_HOR_EQJ(astro_time_t *time, astro_observer_t { astro_rotation_t hor_eqd, eqd_eqj; + if (time == NULL) + return RotationErr(ASTRO_INVALID_PARAMETER); + hor_eqd = Astronomy_Rotation_HOR_EQD(time, observer); eqd_eqj = Astronomy_Rotation_EQD_EQJ(time); return Astronomy_CombineRotation(hor_eqd, eqd_eqj); @@ -9233,6 +9301,9 @@ astro_rotation_t Astronomy_Rotation_EQD_ECL(astro_time_t *time) astro_rotation_t eqd_eqj; astro_rotation_t eqj_ecl; + if (time == NULL) + return RotationErr(ASTRO_INVALID_PARAMETER); + eqd_eqj = Astronomy_Rotation_EQD_EQJ(time); eqj_ecl = Astronomy_Rotation_EQJ_ECL(); return Astronomy_CombineRotation(eqd_eqj, eqj_ecl); @@ -9284,8 +9355,14 @@ astro_rotation_t Astronomy_Rotation_ECL_EQD(astro_time_t *time) */ astro_rotation_t Astronomy_Rotation_ECL_HOR(astro_time_t *time, astro_observer_t observer) { - astro_rotation_t ecl_eqd = Astronomy_Rotation_ECL_EQD(time); - astro_rotation_t eqd_hor = Astronomy_Rotation_EQD_HOR(time, observer); + astro_rotation_t ecl_eqd; + astro_rotation_t eqd_hor; + + if (time == NULL) + return RotationErr(ASTRO_INVALID_PARAMETER); + + ecl_eqd = Astronomy_Rotation_ECL_EQD(time); + eqd_hor = Astronomy_Rotation_EQD_HOR(time, observer); return Astronomy_CombineRotation(ecl_eqd, eqd_hor); } @@ -9413,6 +9490,9 @@ astro_rotation_t Astronomy_Rotation_ECT_EQD(astro_time_t *time) earth_tilt_t et; double tobl, cos_tobl, sin_tobl; + if (time == NULL) + return RotationErr(ASTRO_INVALID_PARAMETER); + /* Find true ecliptic obliquity for this time. */ et = e_tilt(time); tobl = et.tobl * DEG2RAD; @@ -9460,6 +9540,9 @@ astro_rotation_t Astronomy_Rotation_EQD_ECT(astro_time_t *time) earth_tilt_t et; double tobl, cos_tobl, sin_tobl; + if (time == NULL) + return RotationErr(ASTRO_INVALID_PARAMETER); + /* Find true ecliptic obliquity for this time. */ et = e_tilt(time); tobl = et.tobl * DEG2RAD; @@ -11079,6 +11162,9 @@ static astro_axis_t EarthRotationAxis(astro_time_t *time) double pos2[3]; astro_equatorial_t equ; + if (time == NULL) + return AxisErr(ASTRO_INVALID_PARAMETER, TimeError()); + /* Unlike the other planets, we have a model of precession and nutation for the Earth's axis that provides a north pole vector. @@ -11147,8 +11233,13 @@ astro_axis_t Astronomy_RotationAxis(astro_body_t body, astro_time_t *time) double radlat, radlon, rcoslat; double Ja, Jb, Jc, Jd, Je, N; double E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13; - const double d = time->tt; - const double T = d / 36525.0; + double d, T; + + if (time == NULL) + return AxisErr(ASTRO_INVALID_PARAMETER, TimeError()); + + d = time->tt; + T = d / 36525.0; switch (body) { diff --git a/source/c/README.md b/source/c/README.md index 1c3acb1b..d710c706 100644 --- a/source/c/README.md +++ b/source/c/README.md @@ -3068,7 +3068,7 @@ Given a date and time, this function calculates the rotation of the Earth, repre | Type | Parameter | Description | | --- | --- | --- | -| astro_time_t * | `time` | The date and time for which to find GAST. The parameter is passed by address because it can be modified by the call: As an optimization, this function caches the sidereal time value in `time`, unless it has already been cached, in which case the cached value is reused. | +| astro_time_t * | `time` | The date and time for which to find GAST. The parameter is passed by address because it can be modified by the call: As an optimization, this function caches the sidereal time value in `time`, unless it has already been cached, in which case the cached value is reused. If the `time` pointer is NULL, this function returns a NAN value. | diff --git a/source/c/astronomy.c b/source/c/astronomy.c index 318f0723..713bc1ae 100644 --- a/source/c/astronomy.c +++ b/source/c/astronomy.c @@ -1376,7 +1376,7 @@ static void iau2000b(astro_time_t *time) { /* Truncated and hand-optimized nutation model. */ - if (isnan(time->psi)) + if ((time != NULL) && isnan(time->psi)) { double t, elp, f, d, om, arg, dp, de, sarg, carg; @@ -1449,6 +1449,8 @@ static earth_tilt_t e_tilt(astro_time_t *time) { earth_tilt_t et; + /* There is no good answer for what to do if time==NULL. Callers must prevent! */ + iau2000b(time); et.dpsi = time->psi; et.deps = time->eps; @@ -1662,26 +1664,33 @@ static astro_rotation_t nutation_rot(astro_time_t *time, precess_dir_t dir) */ astro_rotation_t rotation; - earth_tilt_t tilt = e_tilt(time); - double oblm = tilt.mobl * DEG2RAD; - double oblt = tilt.tobl * DEG2RAD; - double psi = tilt.dpsi * ASEC2RAD; - double cobm = cos(oblm); - double sobm = sin(oblm); - double cobt = cos(oblt); - double sobt = sin(oblt); - double cpsi = cos(psi); - double spsi = sin(psi); - - double xx = cpsi; - double yx = -spsi * cobm; - double zx = -spsi * sobm; - double xy = spsi * cobt; - double yy = cpsi * cobm * cobt + sobm * sobt; - double zy = cpsi * sobm * cobt - cobm * sobt; - double xz = spsi * sobt; - double yz = cpsi * cobm * sobt - sobm * cobt; - double zz = cpsi * sobm * sobt + cobm * cobt; + earth_tilt_t tilt; + double oblm, oblt, psi, cobm, sobm, cobt, sobt, cpsi, spsi; + double xx, yx, zx, xy, yy, zy, xz, yz, zz; + + if (time == NULL) + return RotationErr(ASTRO_INVALID_PARAMETER); + + tilt = e_tilt(time); + oblm = tilt.mobl * DEG2RAD; + oblt = tilt.tobl * DEG2RAD; + psi = tilt.dpsi * ASEC2RAD; + cobm = cos(oblm); + sobm = sin(oblm); + cobt = cos(oblt); + sobt = sin(oblt); + cpsi = cos(psi); + spsi = sin(psi); + + xx = cpsi; + yx = -spsi * cobm; + zx = -spsi * sobm; + xy = spsi * cobt; + yy = cpsi * cobm * cobt + sobm * sobt; + zy = cpsi * sobm * cobt - cobm * sobt; + xz = spsi * sobt; + yz = cpsi * cobm * sobt - sobm * cobt; + zz = cpsi * sobm * sobt + cobm * cobt; if (dir == FROM_2000) { @@ -1771,11 +1780,15 @@ static double era(double ut) /* Earth Rotation Angle */ * The parameter is passed by address because it can be modified by the call: * As an optimization, this function caches the sidereal time value in `time`, * unless it has already been cached, in which case the cached value is reused. + * If the `time` pointer is NULL, this function returns a NAN value. * * @returns {number} */ double Astronomy_SiderealTime(astro_time_t *time) { + if (time == NULL) + return NAN; + if (isnan(time->st)) { double t = time->tt / 36525.0; @@ -1912,10 +1925,17 @@ static void geo_pos(astro_time_t *time, astro_observer_t observer, double pos[3] double gast; double pos1[3], pos2[3]; - gast = Astronomy_SiderealTime(time); - terra(observer, gast, pos1, NULL); - nutation(pos1, time, INTO_2000, pos2); - precession(pos2, *time, INTO_2000, pos); + if (time == NULL) + { + pos[0] = pos[1] = pos[2] = NAN; + } + else + { + gast = Astronomy_SiderealTime(time); + terra(observer, gast, pos1, NULL); + nutation(pos1, time, INTO_2000, pos2); + precession(pos2, *time, INTO_2000, pos); + } } static void spin(double angle, const double pos1[3], double vec2[3]) @@ -6059,6 +6079,9 @@ astro_equatorial_t Astronomy_Equator( double temp[3]; double datevect[3]; + if (time == NULL) + return EquError(ASTRO_INVALID_PARAMETER); + /* Calculate the geocentric location of the observer. */ geo_pos(time, observer, gc_observer); @@ -6134,6 +6157,9 @@ astro_vector_t Astronomy_ObserverVector( astro_vector_t vec; double gast, pos[3], temp[3]; + if (time == NULL) + return VecError(ASTRO_INVALID_PARAMETER, TimeError()); + gast = Astronomy_SiderealTime(time); terra(observer, gast, pos, NULL); @@ -6211,6 +6237,9 @@ astro_state_vector_t Astronomy_ObserverState( astro_state_vector_t state; double gast, pos[3], vel[3], postemp[3], veltemp[3]; + if (time == NULL) + return StateVecError(ASTRO_INVALID_PARAMETER, TimeError()); + gast = Astronomy_SiderealTime(time); terra(observer, gast, pos, vel); @@ -6373,7 +6402,11 @@ double Astronomy_ObserverGravity(double latitude, double height) * The body's apparent horizontal coordinates and equatorial coordinates, both optionally corrected for refraction. */ astro_horizon_t Astronomy_Horizon( - astro_time_t *time, astro_observer_t observer, double ra, double dec, astro_refraction_t refraction) + astro_time_t *time, + astro_observer_t observer, + double ra, + double dec, + astro_refraction_t refraction) { astro_horizon_t hor; double latrad, lonrad, decrad, rarad; @@ -6383,6 +6416,17 @@ astro_horizon_t Astronomy_Horizon( double az, zd; double spin_angle; + if (time == NULL) + { + /* The best we can do is return an invalid state. */ + /* It would break external dependencies to expect them to check for errors. */ + hor.altitude = NAN; + hor.azimuth = NAN; + hor.ra = NAN; + hor.dec = NAN; + return hor; + } + latrad = observer.latitude * DEG2RAD; lonrad = observer.longitude * DEG2RAD; decrad = dec * DEG2RAD; @@ -6992,8 +7036,11 @@ static int QuadInterp( static astro_status_t FindSeasonChange(double targetLon, int year, int month, int day, astro_time_t *time) { - astro_time_t startTime = Astronomy_MakeTime(year, month, day, 0, 0, 0.0); - astro_search_result_t result = Astronomy_SearchSunLongitude(targetLon, startTime, 20.0); + astro_time_t startTime; + astro_search_result_t result; + + startTime = Astronomy_MakeTime(year, month, day, 0, 0, 0.0); + result = Astronomy_SearchSunLongitude(targetLon, startTime, 20.0); *time = result.time; return result.status; } @@ -7920,6 +7967,9 @@ astro_func_result_t Astronomy_HourAngle(astro_body_t body, astro_time_t *time, a astro_equatorial_t ofdate; double gast; + if (time == NULL) + return FuncError(ASTRO_INVALID_PARAMETER); + /* Calculate Greenwich Apparent Sidereal Time (GAST) at the given time. */ gast = Astronomy_SiderealTime(time); @@ -10151,6 +10201,9 @@ astro_rotation_t Astronomy_Rotation_EQJ_EQD(astro_time_t *time) { astro_rotation_t prec, nut; + if (time == NULL) + return RotationErr(ASTRO_INVALID_PARAMETER); + prec = precession_rot(*time, FROM_2000); nut = nutation_rot(time, FROM_2000); return Astronomy_CombineRotation(prec, nut); @@ -10176,6 +10229,9 @@ astro_rotation_t Astronomy_Rotation_EQJ_ECT(astro_time_t *time) { astro_rotation_t rot, step; + if (time == NULL) + return RotationErr(ASTRO_INVALID_PARAMETER); + rot = Astronomy_Rotation_EQJ_EQD(time); step = Astronomy_Rotation_EQD_ECT(time); return Astronomy_CombineRotation(rot, step); @@ -10201,6 +10257,9 @@ astro_rotation_t Astronomy_Rotation_ECT_EQJ(astro_time_t *time) { astro_rotation_t rot, step; + if (time == NULL) + return RotationErr(ASTRO_INVALID_PARAMETER); + rot = Astronomy_Rotation_ECT_EQD(time); step = Astronomy_Rotation_EQD_EQJ(time); return Astronomy_CombineRotation(rot, step); @@ -10226,6 +10285,9 @@ astro_rotation_t Astronomy_Rotation_EQD_EQJ(astro_time_t *time) { astro_rotation_t prec, nut; + if (time == NULL) + return RotationErr(ASTRO_INVALID_PARAMETER); + nut = nutation_rot(time, INTO_2000); prec = precession_rot(*time, INTO_2000); return Astronomy_CombineRotation(nut, prec); @@ -10261,6 +10323,9 @@ astro_rotation_t Astronomy_Rotation_EQD_HOR(astro_time_t *time, astro_observer_t double uz[3], un[3], uw[3]; double spin_angle; + if (time == NULL) + return RotationErr(ASTRO_INVALID_PARAMETER); + double sinlat = sin(observer.latitude * DEG2RAD); double coslat = cos(observer.latitude * DEG2RAD); double sinlon = sin(observer.longitude * DEG2RAD); @@ -10339,6 +10404,9 @@ astro_rotation_t Astronomy_Rotation_HOR_EQJ(astro_time_t *time, astro_observer_t { astro_rotation_t hor_eqd, eqd_eqj; + if (time == NULL) + return RotationErr(ASTRO_INVALID_PARAMETER); + hor_eqd = Astronomy_Rotation_HOR_EQD(time, observer); eqd_eqj = Astronomy_Rotation_EQD_EQJ(time); return Astronomy_CombineRotation(hor_eqd, eqd_eqj); @@ -10394,6 +10462,9 @@ astro_rotation_t Astronomy_Rotation_EQD_ECL(astro_time_t *time) astro_rotation_t eqd_eqj; astro_rotation_t eqj_ecl; + if (time == NULL) + return RotationErr(ASTRO_INVALID_PARAMETER); + eqd_eqj = Astronomy_Rotation_EQD_EQJ(time); eqj_ecl = Astronomy_Rotation_EQJ_ECL(); return Astronomy_CombineRotation(eqd_eqj, eqj_ecl); @@ -10445,8 +10516,14 @@ astro_rotation_t Astronomy_Rotation_ECL_EQD(astro_time_t *time) */ astro_rotation_t Astronomy_Rotation_ECL_HOR(astro_time_t *time, astro_observer_t observer) { - astro_rotation_t ecl_eqd = Astronomy_Rotation_ECL_EQD(time); - astro_rotation_t eqd_hor = Astronomy_Rotation_EQD_HOR(time, observer); + astro_rotation_t ecl_eqd; + astro_rotation_t eqd_hor; + + if (time == NULL) + return RotationErr(ASTRO_INVALID_PARAMETER); + + ecl_eqd = Astronomy_Rotation_ECL_EQD(time); + eqd_hor = Astronomy_Rotation_EQD_HOR(time, observer); return Astronomy_CombineRotation(ecl_eqd, eqd_hor); } @@ -10574,6 +10651,9 @@ astro_rotation_t Astronomy_Rotation_ECT_EQD(astro_time_t *time) earth_tilt_t et; double tobl, cos_tobl, sin_tobl; + if (time == NULL) + return RotationErr(ASTRO_INVALID_PARAMETER); + /* Find true ecliptic obliquity for this time. */ et = e_tilt(time); tobl = et.tobl * DEG2RAD; @@ -10621,6 +10701,9 @@ astro_rotation_t Astronomy_Rotation_EQD_ECT(astro_time_t *time) earth_tilt_t et; double tobl, cos_tobl, sin_tobl; + if (time == NULL) + return RotationErr(ASTRO_INVALID_PARAMETER); + /* Find true ecliptic obliquity for this time. */ et = e_tilt(time); tobl = et.tobl * DEG2RAD; @@ -12695,6 +12778,9 @@ static astro_axis_t EarthRotationAxis(astro_time_t *time) double pos2[3]; astro_equatorial_t equ; + if (time == NULL) + return AxisErr(ASTRO_INVALID_PARAMETER, TimeError()); + /* Unlike the other planets, we have a model of precession and nutation for the Earth's axis that provides a north pole vector. @@ -12763,8 +12849,13 @@ astro_axis_t Astronomy_RotationAxis(astro_body_t body, astro_time_t *time) double radlat, radlon, rcoslat; double Ja, Jb, Jc, Jd, Je, N; double E1, E2, E3, E4, E5, E6, E7, E8, E9, E10, E11, E12, E13; - const double d = time->tt; - const double T = d / 36525.0; + double d, T; + + if (time == NULL) + return AxisErr(ASTRO_INVALID_PARAMETER, TimeError()); + + d = time->tt; + T = d / 36525.0; switch (body) {