static void io_loop_handle_timeouts_real(struct ioloop *ioloop) { struct priorityq_item *item; struct timeval tv, tv_call; unsigned int t_id; if (gettimeofday(&ioloop_timeval, NULL) < 0) i_fatal("gettimeofday(): %m"); /* Don't bother comparing usecs. */ if (unlikely(ioloop_time > ioloop_timeval.tv_sec)) { /* time moved backwards */ io_loops_timeouts_update(-(long)(ioloop_time - ioloop_timeval.tv_sec)); ioloop->time_moved_callback(ioloop_time, ioloop_timeval.tv_sec); /* the callback may have slept, so check the time again. */ if (gettimeofday(&ioloop_timeval, NULL) < 0) i_fatal("gettimeofday(): %m"); } else if (unlikely(ioloop_timeval.tv_sec > ioloop->next_max_time)) { io_loops_timeouts_update(ioloop_timeval.tv_sec - ioloop->next_max_time); /* time moved forwards */ ioloop->time_moved_callback(ioloop->next_max_time, ioloop_timeval.tv_sec); } ioloop_time = ioloop_timeval.tv_sec; tv_call = ioloop_timeval; while ((item = priorityq_peek(ioloop->timeouts)) != NULL) { struct timeout *timeout = (struct timeout *)item; /* use tv_call to make sure we don't get to infinite loop in case callbacks update ioloop_timeval. */ if (timeout_get_wait_time(timeout, &tv, &tv_call) > 0) break; /* update timeout's next_run and reposition it in the queue */ timeout_reset_timeval(timeout, &tv_call); if (timeout->log != NULL) { ioloop->cur_log = timeout->log; io_loop_log_ref(ioloop->cur_log); i_set_failure_prefix(timeout->log->prefix); } t_id = t_push(); timeout->callback(timeout->context); if (t_pop() != t_id) { i_panic("Leaked a t_pop() call in timeout handler %p", (void *)timeout->callback); } if (ioloop->cur_log != NULL) { io_loop_log_unref(&ioloop->cur_log); i_set_failure_prefix(ioloop->default_log_prefix); } } }
void data_stack_deinit(void) { (void)t_pop(); if (frame_pos != BLOCK_FRAME_COUNT-1) i_panic("Missing t_pop() call"); #ifndef USE_GC while (unused_frame_blocks != NULL) { struct stack_frame_block *frame_block = unused_frame_blocks; unused_frame_blocks = unused_frame_blocks->prev; free(frame_block); } free(current_block); free(unused_block); #endif unused_frame_blocks = NULL; current_block = NULL; unused_block = NULL; }
static void test_ds_recurse(int depth, int number, size_t size) { int i; char **ps; char tag[2] = { depth+1, '\0' }; int try_fails = 0; data_stack_frame_t t_id = t_push_named("test_ds_recurse[%i]", depth); ps = t_buffer_get(sizeof(char *) * number); i_assert(ps != NULL); t_buffer_alloc(sizeof(char *) * number); for (i = 0; i < number; i++) { ps[i] = t_malloc_no0(size/2); bool re = t_try_realloc(ps[i], size); i_assert(ps[i] != NULL); if (!re) { try_fails++; ps[i] = t_malloc_no0(size); } /* drop our own canaries */ memset(ps[i], tag[0], size); ps[i][size-2] = 0; } /* Do not expect a high failure rate from t_try_realloc */ test_assert_idx(try_fails <= number / 20, depth); /* Now recurse... */ if(depth>0) test_ds_recurse(depth-1, number, size); /* Test our canaries are still intact */ for (i = 0; i < number; i++) { test_assert_idx(strspn(ps[i], tag) == size - 2, i); test_assert_idx(ps[i][size-1] == tag[0], i); } test_assert_idx(t_pop(&t_id), depth); }
enum fatal_test_state fatal_data_stack(unsigned int stage) { #ifdef DEBUG #define NONEXISTENT_STACK_FRAME_ID (data_stack_frame_t)999999999 /* If we abort, then we'll be left with a dangling t_push() keep a record of our temporary stack id, so we can clean up. */ static data_stack_frame_t t_id = NONEXISTENT_STACK_FRAME_ID; static unsigned char *undo_ptr = NULL; static unsigned char undo_data; static bool things_are_messed_up = FALSE; if (stage != 0) { /* Presume that we need to clean up from the prior test: undo the evil write, then we will be able to t_pop cleanly, and finally we can end the test stanza. */ if (things_are_messed_up || undo_ptr == NULL) return FATAL_TEST_ABORT; /* abort, things are messed up with t_pop */ *undo_ptr = undo_data; undo_ptr = NULL; /* t_pop mustn't abort, that would cause recursion */ things_are_messed_up = TRUE; if (t_id != NONEXISTENT_STACK_FRAME_ID && !t_pop(&t_id)) return FATAL_TEST_ABORT; /* abort, things are messed up with us */ things_are_messed_up = FALSE; t_id = NONEXISTENT_STACK_FRAME_ID; test_end(); } switch(stage) { case 0: { unsigned char *p; test_begin("fatal data-stack underrun"); t_id = t_push_named("fatal_data_stack underrun"); size_t left = t_get_bytes_available(); p = t_malloc_no0(left-80); /* will fit */ p = t_malloc_no0(100); /* won't fit, will get new block */ int seek = 0; /* Seek back for the canary, don't assume endianness */ while(seek > -60 && ((p[seek+1] != 0xDB) || ((p[seek] != 0xBA || p[seek+2] != 0xAD) && (p[seek+2] != 0xBA || p[seek] != 0xAD)))) seek--; if (seek <= -60) return FATAL_TEST_ABORT; /* abort, couldn't find header */ undo_ptr = p + seek; undo_data = *undo_ptr; *undo_ptr = '*'; /* t_malloc_no0 will panic block header corruption */ test_expect_fatal_string("Corrupted data stack canary"); (void)t_malloc_no0(10); return FATAL_TEST_FAILURE; } case 1: case 2: { test_begin(stage == 1 ? "fatal t_malloc_no0 overrun near" : "fatal t_malloc_no0 overrun far"); t_id = t_push_named(stage == 1 ? "fatal t_malloc_no0 overrun first" : "fatal t_malloc_no0 overrun far"); unsigned char *p = t_malloc_no0(10); undo_ptr = p + 10 + (stage == 1 ? 0 : 8*4-1); /* presumes sentry size */ undo_data = *undo_ptr; *undo_ptr = '*'; /* t_pop will now fail */ test_expect_fatal_string("buffer overflow"); (void)t_pop(&t_id); t_id = NONEXISTENT_STACK_FRAME_ID; /* We're FUBAR, mustn't pop next entry */ return FATAL_TEST_FAILURE; } case 3: case 4: { test_begin(stage == 3 ? "fatal t_buffer_get overrun near" : "fatal t_buffer_get overrun far"); t_id = t_push_named(stage == 3 ? "fatal t_buffer overrun near" : "fatal t_buffer_get overrun far"); unsigned char *p = t_buffer_get(10); undo_ptr = p + 10 + (stage == 3 ? 0 : 8*4-1); undo_data = *undo_ptr; *undo_ptr = '*'; /* t_pop will now fail */ test_expect_fatal_string("buffer overflow"); (void)t_pop(&t_id); t_id = NONEXISTENT_STACK_FRAME_ID; /* We're FUBAR, mustn't pop next entry */ return FATAL_TEST_FAILURE; } default: things_are_messed_up = TRUE; return FATAL_TEST_FINISHED; } #else return stage == 0 ? FATAL_TEST_FINISHED : FATAL_TEST_ABORT; #endif }
void conv(register FILE *fp) { register int c, k; int m, n, n1, m1; char str[4096], buf[4096]; while ((c = getc(fp)) != EOF) { switch (c) { case '\n': /* when input is text */ case ' ': case 0: /* occasional noise creeps in */ break; case '{': /* push down current environment */ t_push(); break; case '}': t_pop(); break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': /* two motion digits plus a character */ hmot((c-'0')*10 + getc(fp)-'0'); put1(getc(fp)); break; case 'c': /* single ascii character */ put1(getc(fp)); break; case 'C': sget(str, sizeof str, fp); put1s(str); break; case 't': /* straight text */ fgets(buf, sizeof(buf), fp); t_text(buf); break; case 'D': /* draw function */ fgets(buf, sizeof(buf), fp); switch (buf[0]) { case 'l': /* draw a line */ sscanf(buf+1, "%d %d", &n, &m); drawline(n, m, "."); break; case 'c': /* circle */ sscanf(buf+1, "%d", &n); drawcirc(n); break; case 'e': /* ellipse */ sscanf(buf+1, "%d %d", &m, &n); drawellip(m, n); break; case 'a': /* arc */ sscanf(buf+1, "%d %d %d %d", &n, &m, &n1, &m1); drawarc(n, m, n1, m1); break; case '~': /* wiggly line */ drawwig(buf+1); break; default: error(FATAL, "unknown drawing function %s\n", buf); break; } break; case 's': fscanf(fp, "%d", &n); if (n == -23) { float f; fscanf(fp, "%f", &f); setsize(f); } else setsize(t_size(n));/* ignore fractional sizes */ break; case 'f': sget(str, sizeof str, fp); setfont(t_font(str)); break; case 'H': /* absolute horizontal motion */ /* fscanf(fp, "%d", &n); */ while ((c = getc(fp)) == ' ') ; k = 0; do { k = 10 * k + c - '0'; } while (isdigit(c = getc(fp))); ungetc(c, fp); hgoto(k); break; case 'h': /* relative horizontal motion */ /* fscanf(fp, "%d", &n); */ while ((c = getc(fp)) == ' ') ; k = 0; do { k = 10 * k + c - '0'; } while (isdigit(c = getc(fp))); ungetc(c, fp); hmot(k); break; case 'w': /* word space */ putc(' ', stdout); break; case 'V': fscanf(fp, "%d", &n); vgoto(n); break; case 'v': fscanf(fp, "%d", &n); vmot(n); break; case 'p': /* new page */ fscanf(fp, "%d", &n); t_page(n); break; case 'n': /* end of line */ while (getc(fp) != '\n') ; t_newline(); break; case '#': /* comment */ while (getc(fp) != '\n') ; break; case 'x': /* device control */ devcntrl(fp); break; default: error(!FATAL, "unknown input character %o %c\n", c, c); done(); } } }
void t_pop_check(unsigned int *id) { if (unlikely(t_pop() != *id)) i_panic("Leaked t_pop() call"); *id = 0; }