|
@@ -3191,6 +3191,61 @@ tor_join_win_cmdline(const char *argv[])
|
|
|
return joined_argv;
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * Helper function to output hex numbers, called by
|
|
|
+ * format_helper_exit_status(). This writes the hexadecimal digits of x into
|
|
|
+ * buf, up to max_len digits, and returns the actual number of digits written.
|
|
|
+ * If there is insufficient space, it will write nothing and return 0.
|
|
|
+ *
|
|
|
+ * This accepts an unsigned int because format_helper_exit_status() needs to
|
|
|
+ * call it with a signed int and an unsigned char, and since the C standard
|
|
|
+ * does not guarantee that an int is wider than a char (an int must be at
|
|
|
+ * least 16 bits but it is permitted for a char to be that wide as well), we
|
|
|
+ * can't assume a signed int is sufficient to accomodate an unsigned char.
|
|
|
+ * Thus, format_helper_exit_status() will still need to emit any require '-'
|
|
|
+ * on its own.
|
|
|
+ */
|
|
|
+
|
|
|
+int
|
|
|
+format_hex_number_for_helper_exit_status(unsigned int x, char *buf,
|
|
|
+ int max_len)
|
|
|
+{
|
|
|
+ int len;
|
|
|
+ unsigned int tmp;
|
|
|
+ char *cur;
|
|
|
+
|
|
|
+ /* Sanity check */
|
|
|
+ if (!buf || max_len <= 0)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ /* How many chars do we need for x? */
|
|
|
+ if (x > 0) {
|
|
|
+ len = 0;
|
|
|
+ tmp = x;
|
|
|
+ while (tmp > 0) {
|
|
|
+ tmp >>= 4;
|
|
|
+ ++len;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ else len = 1;
|
|
|
+
|
|
|
+ /* Bail if we would go past the end of the buffer */
|
|
|
+ if (len > max_len)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ /* Point to last one */
|
|
|
+ cur = buf + len - 1;
|
|
|
+
|
|
|
+ /* Convert x to hex */
|
|
|
+ do {
|
|
|
+ *cur-- = "0123456789ABCDEF"[x & 0xf];
|
|
|
+ x >>= 4;
|
|
|
+ } while (x != 0 && cur >= buf);
|
|
|
+
|
|
|
+ /* Return len */
|
|
|
+ return len;
|
|
|
+}
|
|
|
+
|
|
|
/** Format <b>child_state</b> and <b>saved_errno</b> as a hex string placed in
|
|
|
* <b>hex_errno</b>. Called between fork and _exit, so must be signal-handler
|
|
|
* safe.
|
|
@@ -3208,9 +3263,9 @@ void
|
|
|
format_helper_exit_status(unsigned char child_state, int saved_errno,
|
|
|
char *hex_errno)
|
|
|
{
|
|
|
- unsigned int unsigned_errno, len, tmp_uint;
|
|
|
- char *cur, *tmp;
|
|
|
- unsigned char tmp_uchar;
|
|
|
+ unsigned int unsigned_errno;
|
|
|
+ int written, left;
|
|
|
+ char *cur;
|
|
|
size_t i;
|
|
|
|
|
|
/* Fill hex_errno with spaces, and a trailing newline (memset may
|
|
@@ -3226,87 +3281,72 @@ format_helper_exit_status(unsigned char child_state, int saved_errno,
|
|
|
unsigned_errno = (unsigned int) saved_errno;
|
|
|
}
|
|
|
|
|
|
- /* How many chars do we need for child_state ? */
|
|
|
- if ( child_state > 0 ) {
|
|
|
- len = 0;
|
|
|
- tmp_uchar = child_state;
|
|
|
- while (tmp_uchar > 0) {
|
|
|
- tmp_uchar >>= 4;
|
|
|
- ++len;
|
|
|
- }
|
|
|
- }
|
|
|
- else len = 1;
|
|
|
+ /*
|
|
|
+ * Count how many chars of space we have left, and keep a pointer into the
|
|
|
+ * current point in the buffer.
|
|
|
+ */
|
|
|
+ left = HEX_ERRNO_SIZE;
|
|
|
+ cur = hex_errno;
|
|
|
|
|
|
- /* Bail if we would go past the end (on this or the '/') */
|
|
|
- if ( len + 2 > HEX_ERRNO_SIZE)
|
|
|
+ /* Emit child_state */
|
|
|
+ written = format_hex_number_for_helper_exit_status(child_state,
|
|
|
+ cur, left);
|
|
|
+ if (written <= 0)
|
|
|
goto err;
|
|
|
|
|
|
- /* Point to last one */
|
|
|
- cur = hex_errno + len - 1;
|
|
|
-
|
|
|
- /* Convert child_state to hex */
|
|
|
- do {
|
|
|
- *cur-- = "0123456789ABCDEF"[child_state & 0xf];
|
|
|
- child_state >>= 4;
|
|
|
- } while (child_state != 0 && cur >= hex_errno);
|
|
|
-
|
|
|
- /* Check for overflow on first iteration of the loop */
|
|
|
- if (cur + 1 < hex_errno)
|
|
|
+ /* Adjust left and cur */
|
|
|
+ left -= written;
|
|
|
+ cur += written;
|
|
|
+ if (left <= 0)
|
|
|
goto err;
|
|
|
|
|
|
/* Now the '/' */
|
|
|
- hex_errno[len] = '/';
|
|
|
-
|
|
|
- /* Save a pointer to the start of second number */
|
|
|
- tmp = hex_errno + len;
|
|
|
+ *cur = '/';
|
|
|
|
|
|
- /* How many chars do we need for unsigned_errno? */
|
|
|
- if ( unsigned_errno > 0 ) {
|
|
|
- len = 0;
|
|
|
- tmp_uint = unsigned_errno;
|
|
|
- while (tmp_uint > 0) {
|
|
|
- tmp_uint >>= 4;
|
|
|
- ++len;
|
|
|
- }
|
|
|
- }
|
|
|
- else len = 1;
|
|
|
+ /* Adjust left and cur */
|
|
|
+ ++cur;
|
|
|
+ --left;
|
|
|
+ if (left <= 0)
|
|
|
+ goto err;
|
|
|
|
|
|
/* Need minus? */
|
|
|
if (saved_errno < 0) {
|
|
|
- if ( tmp + 1 - hex_errno > (ptrdiff_t)(HEX_ERRNO_SIZE) )
|
|
|
+ *cur = '-';
|
|
|
+ ++cur;
|
|
|
+ --left;
|
|
|
+ if (left <= 0)
|
|
|
goto err;
|
|
|
-
|
|
|
- *(++tmp) = '-';
|
|
|
}
|
|
|
|
|
|
- /* Last check for space */
|
|
|
- if ( tmp + len + 2 - hex_errno > (ptrdiff_t)(HEX_ERRNO_SIZE) )
|
|
|
+ /* Emit unsigned_errno */
|
|
|
+ written = format_hex_number_for_helper_exit_status(unsigned_errno,
|
|
|
+ cur, left);
|
|
|
+
|
|
|
+ if (written <= 0)
|
|
|
goto err;
|
|
|
|
|
|
- /* Point to last one */
|
|
|
- cur = tmp + len;
|
|
|
+ /* Adjust left and cur */
|
|
|
+ left -= written;
|
|
|
+ cur += written;
|
|
|
|
|
|
- /* Convert unsigned_errno to hex */
|
|
|
- do {
|
|
|
- *cur-- = "0123456789ABCDEF"[unsigned_errno & 0xf];
|
|
|
- unsigned_errno >>= 4;
|
|
|
- } while (unsigned_errno != 0 && cur >= tmp);
|
|
|
+ /* Check that we have enough space left for a newline */
|
|
|
+ if (left <= 0)
|
|
|
+ goto err;
|
|
|
|
|
|
/* Emit the newline and NUL */
|
|
|
- cur = tmp + len;
|
|
|
- *(++cur) = '\n';
|
|
|
- *(++cur) = '\0';
|
|
|
+ *cur++ = '\n';
|
|
|
+ *cur++ = '\0';
|
|
|
|
|
|
goto done;
|
|
|
|
|
|
-err:
|
|
|
+ err:
|
|
|
/*
|
|
|
* In error exit, just write a '\0' in the first char so whatever called
|
|
|
* this at least won't fall off the end.
|
|
|
*/
|
|
|
*hex_errno = '\0';
|
|
|
|
|
|
-done:
|
|
|
+ done:
|
|
|
return;
|
|
|
}
|
|
|
|