Ловля segfaults в C

Возможно, проще всего использовать мощь CSS, а не пытаться делать это самостоятельно.

Вы можете создать фиктивный элемент div, добавить в него тег < span> и увеличивать его размер шрифта, пока он больше не будет соответствовать.
Размер шрифта до этого был правильным.

Затем вы можете просмотреть текстовое содержимое этого < span>, используя объект Range , чтобы получить разрывы строк, которые сгенерирует CSS. Range API предоставляет удобный метод getBoundingClientRect , позволяющий нам найти, где находится курсор. Нам просто нужно запомнить последнюю позицию y, и когда она меняется, мы знаем, что символ раньше был последним в строке.

Однако у этой техники есть некоторые недостатки.

  • В DOM несколько пробелов сжимаются в один. CanvasContext API не имеет такого поведения, поэтому мы должны избавиться от них перед анализом текста.

  • Меры сделаны на основе ограничивающих рамок контейнеров, это означает, что он не проверяет окрашенные пиксели, поэтому некоторые символы могут быть переполнены (например, Zalgo͚̠͓ͣ̔͐̽), а некоторые другие не подходят идеально. в поле (в зависимости от подъема и спуска каждого персонажа).

  • ... , вероятно, другие.

function getBestFontSize(text, width, height, userstyles) {
  if(!text) return null;
  
  const cont = document.createElement('div');
  cont.classList.add('best-font-size-tester');
  const style = cont.style;

  if(typeof width === 'number') width += 'px';
  if(typeof height === 'number') height += 'px';
  Object.assign(style, {width, height}, userstyles);

  const span = document.createElement('span');
  span.textContent = text;
  cont.appendChild(span);
  document.body.appendChild(cont);
  
  let size = 0;
  
  const max = cont.getBoundingClientRect();
  while(true) {
    style.fontSize = size + 'px';
    let rect = span.getBoundingClientRect();
    if(rect.bottom > max.bottom || rect.right > max.right) {
      // overflown
      size -= 1; // the correct size was the one before
      break;
    }
    size++;
  }
  if(size === 0) {
    // even at 0 it doesn't fit...
    return null;
  }
  // now we'll get the line breaks by walking through our text content
  style.fontSize = size + 'px';
  const lines = getLineBreaks(span.childNodes[0], max.top);
  // cleanup
  document.body.removeChild(cont);

  return {
    fontSize: size,
    lines: lines
  };
}

function getLineBreaks(node, contTop) {
  if(!node) return [];
  const range = document.createRange();
  const lines = [];
  range.setStart(node, 0);
  let prevBottom = range.getBoundingClientRect().bottom;
  let str = node.textContent;
  let current = 1;
  let lastFound = 0;
  let bottom = 0;
  while(current <= str.length) {
    range.setStart(node, current);
    bottom = range.getBoundingClientRect().bottom;
    if(bottom > prevBottom) {
      lines.push({
        y: prevBottom - (contTop || 0),
        text: str.substr(lastFound , (current - 1) - lastFound)
      });
      prevBottom = bottom;
      lastFound = current - 1;
    }
    current++;
  }
  // push the last line
  lines.push({
    y: bottom - (contTop || 0),
    text: str.substr(lastFound)
  });

  return lines;
}

const ctx = canvas.getContext('2d');
ctx.textBaseline = 'bottom';
txt_area.oninput = e => {
  const input = txt_area.value
    .replace(/(\s)(?=\1)/g, ''); // remove all double spaces
  ctx.setTransform(1,0,0,1,0,0);
  ctx.clearRect(0,0,canvas.width,canvas.height);
  ctx.translate(19.5,19.5);
  ctx.strokeRect(0,0,100,100);

  if(!input.length) return;
  const bestFit = getBestFontSize(input, 100, 100, {
    fontFamily: 'sans-serif',
    fontWeight: '600',
    textAlign: 'center'
  });
  // apply thesame options we passed
  ctx.font = '600 ' + bestFit.fontSize + 'px sans-serif';
  ctx.textAlign = 'center';
  // translate again because text-align: center
  ctx.translate(50.5,0);
  bestFit.lines.forEach(({text, y}) => ctx.fillText(text, 0, y));
};
txt_area.oninput();
.best-font-size-tester {
  border: 1px solid;
  position: absolute;
  overflow: visible;
  opacity: 0;
  z-index: -1;
  pointer-events: none;
}

9
задан arul 16 February 2009 в 18:43
поделиться

8 ответов

Необходимо определить обработчик сигналов. Это сделано в системах Unix с помощью функции sigaction. Я сделал это с тем же кодом Fedora 64-и 32-разрядный, и Sun Solaris.

9
ответ дан 4 December 2019 в 06:01
поделиться

Ну, SIGSEGV trappable, и это - POSIX, таким образом, это портативно в этом смысле.

Bu я обеспокоен, что Вы, кажется, хотите обработать segfault, а не решить проблему, которая вызывает segfault. Если я должен был выбрать, было ли это ОС в отказе или моим собственным кодом, я знаю, который я выбрал бы. Я предлагаю, чтобы Вы выследили ту ошибку, зафиксировали ее, затем записали тестовый сценарий, чтобы удостовериться, что она никогда не кусает Вас снова.

21
ответ дан 4 December 2019 в 06:01
поделиться

Можно использовать функциональный сигнал установить новый обработчик сигналов для сигнала:

   #include <signal.h>
   void (*signal(int signum, void (*sighandler)(int)))(int);

Что-то как следующий код:

signal(SIGINT , clean_exit_on_sig);
signal(SIGABRT , clean_exit_on_sig);
signal(SIGILL , clean_exit_on_sig);
signal(SIGFPE , clean_exit_on_sig);
signal(SIGSEGV, clean_exit_on_sig); // <-- this one is for segmentation fault
signal(SIGTERM , clean_exit_on_sig);

void 
clean_exit_on_sig(int sig_num)
{
        printf ("\n Signal %d received",sig_num);
}
12
ответ дан 4 December 2019 в 06:01
поделиться

Безопасные действия в обработчике сигналов очень ограничены. Небезопасно назвать любую библиотечную функцию не известной быть повторно используемым, который исключит, например, free() и printf(). Лучшая практика должна установить переменную и возврат, но это не помогает Вам очень. Также безопасно использовать системные вызовы такой как write().

Обратите внимание на это в двух примерах следа, данных здесь, backtrace_symbols_fd() функция будет безопасна, потому что она использует сырые данные fd непосредственно, но вызов к fprintf() является неправильным, и должен быть заменен использованием write().

5
ответ дан 4 December 2019 в 06:01
поделиться

Я думаю, что Вы пытаетесь решить проблему, которая не существует. По крайней мере, Вы работаете над неправильным концом. Вы не сможете поймать отказ сегментации, поскольку эта ошибка/исключение брошена ОС (это вызывается Вашей программой, ОС просто ловит его).

Я советовал бы Вам заново продумать свою стратегию относительно входа: Почему невозможно санировать его? Самой важной, чтобы сделать является проверка размера для этого, C stdlib имеет соответствующие функции. Затем, конечно, необходимо было бы проверить на допустимый вход относительно содержания. Да, это, вероятно, приведет к большой работе, но это - единственный способ записать устойчивую программу.

Править: Я не большая часть эксперта C, не знал, что даже отказ сегментации мог быть обработан обработчиком сигналов. Однако, я думаю, что это не правильный способ пойти по упомянутым выше причинам.

1
ответ дан 4 December 2019 в 06:01
поделиться

обработка сигнала является (относительно) портативной через машины Unix (это включает Mac и Linux). Большие различия находятся в деталях исключения, которые передаются как аргумент стандартной программе обработки сигнала. Sorrty, но Вам, вероятно, будет нужен набор #ifdefs для этого, если Вы захотите распечатать более разумные сообщения об ошибках (такой как, где и из-за которого адреса отказ произошел)...

хорошо, вот фрагмент кода для Вас для запуска с:

#include <signal.h>

/* reached when a segv occurrs */
void
SEGVFunction( SIGARGS )
{
     ...
}

...
main(...) {
    signal(SIGSEGV, SEGVFunction); /* tell the OS, where to go in case... */
    ...
    ... do your work ...
}

Ваша задача к:

  • проверьте то, что SIGARGS (Зависимый от операционной системы, так используйте ifdef),
  • посмотрите, как извлечь адресный отказом и ПК от информации об исключении в sigArgs
  • распечатайте разумное сообщение
  • выход

в теории Вы могли даже исправить ПК в обработчике сигналов (к после дающей сбой инструкции) и продолжить двигаться. Однако типичные обработчики сигналов любой выход () или к longjmp () назад в сохранение помещают в основном.

с уважением

1
ответ дан 4 December 2019 в 06:01
поделиться

Необходимо будет обеспечить обработчик SIGSEGV, эти довольно достойные взгляды.

1
ответ дан 4 December 2019 в 06:01
поделиться

Существует пример того, как поймать SIGSEGV и распечатать отслеживание стека с помощью следа glibc () здесь:

как генерировать stacktrace когда мои сбои приложения C++

Можно использовать это, чтобы поймать segfault и вымыться, но быть предупрежденными: Вы не должны делать слишком большого количества материала в обработчике сигналов, особенно вещи, которые включают звонки совершения как malloc (). Существует много вызовов, которые не являются безопасным сигналом, и можно закончить тем, что стреляли себе в ногу при создании, скажем, вызова к malloc из malloc.

1
ответ дан 4 December 2019 в 06:01
поделиться
Другие вопросы по тегам:

Похожие вопросы: