|
|||||||
|
|
|
![]() |
|
|
Strumenti |
|
|
#1 |
|
Senior Member
Iscritto dal: Oct 2005
Messaggi: 3306
|
[C++] Linux catch di stack overflow
Come realizzo su Linux qualcosa di equivalente a:
Codice:
void Loop()
{
static int count = 0;
cout << count++ << endl;
Loop();
}
int main(int argc, CHAR* argv[])
{
__try
{
Loop();
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
cout << "exception caught" << endl;
}
return 0;
}
|
|
|
|
|
|
#2 |
|
Bannato
Iscritto dal: Feb 2005
Città: Roma
Messaggi: 7029
|
non arriva il segnale di segmentation fault in questi casi?
|
|
|
|
|
|
#3 |
|
Senior Member
Iscritto dal: Apr 2000
Città: Roma
Messaggi: 15625
|
Dubito che un catch su uno stach overflow sia in ogni caso sicuro. Considera questo esempio, e immagina di eseguirlo quando hai solo una manciata di byte di stack disponibili:
Codice:
__try {
A a; // A e' una classe
char buf[128]; // stack overflow qui
...
} __except (ecc ecc)
E se il distruttore è qualcosa tipo Codice:
A::~A()
{
char buf[2048]; // stack overflow n.2 versione extralarge
...
}
Se rinunci alla mancata chiamata dei distruttori, puoi provare questa tecnica. Ho aggiunto qualche velato tentativo di supporto multithread e nested, il tutto rigorosamente non testato: Codice:
static __thread stack_t thread_sigstack;
static __thread stack_t old_thread_sigstack;
void sig_try_init()
{
thread_sigstack.ss_size = SIGSTKSZ;
thread_sigstack.ss_flags = 0;
thread_sigstack.ss_sp = malloc(thread_sigstack.ss_size);
thread_sigstack.ss_sp = (char *) thread_sigstack.ss_sp + thread_sigstack.ss_size;
sigaltstack(&thread_sigstack, &old_thread_sigstack);
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_ONSTACK;
sa.sa_sigaction = sighandler;
sigaction(SIGSEGV, &sa, NULL);
}
void sig_try_exit()
{
sigaltstack(&old_thread_sigstack, NULL);
free((char *) thread_sigstack.ss_sp - thread_sigstack.ss_size);
}
void overflow(char *v)
{
if (v)
memset(v, 0, 1024);
char a[1024];
overflow(a);
}
int main()
{
sig_try_init();
__try {
fprintf(stderr, "Start...\n");
overflow(NULL);
fprintf(stderr, "Stop\n");
} __catch() {
fprintf(stderr, "Exception caught\n");
}
sig_try_exit();
return 0;
}
Codice:
__thread sigjmp_buf *env = NULL;
void sighandler(int sig, siginfo_t *si, void *unused)
{
if (env!=NULL)
siglongjmp(*env, 1);
else
abort();
}
__thread bool __in_catch = false;
#define __try \
{ \
bool in_catch = false; \
sigjmp_buf ebuf; \
sigjmp_buf *old_ebuf = env; \
env = &ebuf; \
if (sigsetjmp(*env, 1)==0)
#define __catch() \
else \
in_catch = true; \
env = old_ebuf; \
__in_catch = in_catch; \
} \
if (__in_catch)
__________________
0: or %edi, %ecx; adc %eax, (%edx); popf; je 0b-22; pop %ebx; fadds 0x56(%ecx); lds 0x56(%ebx), %esp; mov %al, %al andeqs pc, r1, #147456; blpl 0xff8dd280; ldrgtb r4, [r6, #-472]; addgt r5, r8, r3, ror #12 |
|
|
|
|
|
#4 |
|
Senior Member
Iscritto dal: Apr 2000
Città: Roma
Messaggi: 15625
|
Il programma di test, compilabile, è questo.
Becca anche i segfault, ovviamente. Codice:
#include <stdlib.h>
#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <setjmp.h>
#include <string.h>
__thread sigjmp_buf *env = NULL;
static void sighandler(int sig, siginfo_t *si, void *unused)
{
if (env!=NULL)
siglongjmp(*env, 1);
else
abort();
}
static __thread stack_t thread_sigstack;
static __thread stack_t old_thread_sigstack;
void sig_try_init()
{
thread_sigstack.ss_size = SIGSTKSZ;
thread_sigstack.ss_flags = 0;
thread_sigstack.ss_sp = malloc(thread_sigstack.ss_size);
thread_sigstack.ss_sp = (char *) thread_sigstack.ss_sp + thread_sigstack.ss_size;
sigaltstack(&thread_sigstack, &old_thread_sigstack);
struct sigaction sa;
sigemptyset(&sa.sa_mask);
sa.sa_flags = SA_ONSTACK;
sa.sa_sigaction = sighandler;
sigaction(SIGSEGV, &sa, NULL);
}
void sig_try_exit()
{
sigaltstack(&old_thread_sigstack, NULL);
free((char *) thread_sigstack.ss_sp - thread_sigstack.ss_size);
}
__thread bool __in_catch = false;
#define __try \
{ \
bool in_catch = false; \
sigjmp_buf ebuf; \
sigjmp_buf *old_ebuf = env; \
env = &ebuf; \
if (sigsetjmp(*env, 1)==0)
#define __catch() \
else \
in_catch = true; \
env = old_ebuf; \
__in_catch = in_catch; \
} \
if (__in_catch)
void overflow(char *v)
{
if (v)
memset(v, 0, 1024);
char a[1024];
overflow(a);
}
int main()
{
sig_try_init();
__try {
fprintf(stderr, "Start...\n");
overflow(NULL);
fprintf(stderr, "Stop\n");
} __catch() {
fprintf(stderr, "Exception caught\n");
}
sig_try_exit();
return 0;
}
__________________
0: or %edi, %ecx; adc %eax, (%edx); popf; je 0b-22; pop %ebx; fadds 0x56(%ecx); lds 0x56(%ebx), %esp; mov %al, %al andeqs pc, r1, #147456; blpl 0xff8dd280; ldrgtb r4, [r6, #-472]; addgt r5, r8, r3, ror #12 Ultima modifica di ilsensine : 05-02-2008 alle 00:22. |
|
|
|
|
|
#5 | |
|
Senior Member
Iscritto dal: Jan 2002
Città: Germania
Messaggi: 26110
|
Quote:
__________________
Per iniziare a programmare c'è solo Python con questo o quest'altro (più avanzato) libro @LinkedIn Non parlo in alcun modo a nome dell'azienda per la quale lavoro Ho poco tempo per frequentare il forum; eventualmente, contattatemi in PVT o nel mio sito. Fanboys |
|
|
|
|
|
|
#6 |
|
Senior Member
Iscritto dal: Apr 2000
Città: Roma
Messaggi: 15625
|
No non è un double fault...
__________________
0: or %edi, %ecx; adc %eax, (%edx); popf; je 0b-22; pop %ebx; fadds 0x56(%ecx); lds 0x56(%ebx), %esp; mov %al, %al andeqs pc, r1, #147456; blpl 0xff8dd280; ldrgtb r4, [r6, #-472]; addgt r5, r8, r3, ror #12 |
|
|
|
|
|
#7 | |
|
Senior Member
Iscritto dal: Oct 2005
Messaggi: 3306
|
Quote:
Per quanto riguarda la gestione dello stack overflow, più che altro serve per debug su codice di produzione, per rilevare eventuali problemi ed avere modo di trovare la causa più facilmente. Si suppone che errori da terminazione immediata non siano così comuni, ma sporadici (e si spera inesistenti...), per cui se il tutto serve per trovare un bug di quelli nascostissimi, l'eventuale memory leak passa in secondo piano. Inoltre nel caso di una allocazione sullo stack in un distruttore, beh pace. Il codice che avevo postato è per Windows e in quel modo qualunque porcata commessa nel __try (dereferenziazione di puntatori nulli, doppia delete, stack overflow...) viene catturata da __except e con qualche riga di codice in più è facile avere anche lo stack trace. Esattamente come accade in C# o Java dove con un try catch sei sicuro che il software continua sempre e comunque a funzionare. Volevo riuscire a fare la stessa cosa anche su Linux. |
|
|
|
|
|
|
#8 |
|
Senior Member
Iscritto dal: Jan 2002
Città: Germania
Messaggi: 26110
|
Sicuramente sono un po' arrugginito con l'assembly 80x86
__________________
Per iniziare a programmare c'è solo Python con questo o quest'altro (più avanzato) libro @LinkedIn Non parlo in alcun modo a nome dell'azienda per la quale lavoro Ho poco tempo per frequentare il forum; eventualmente, contattatemi in PVT o nel mio sito. Fanboys |
|
|
|
|
|
#9 | |
|
Senior Member
Iscritto dal: Apr 2000
Città: Roma
Messaggi: 15625
|
Quote:
__________________
0: or %edi, %ecx; adc %eax, (%edx); popf; je 0b-22; pop %ebx; fadds 0x56(%ecx); lds 0x56(%ebx), %esp; mov %al, %al andeqs pc, r1, #147456; blpl 0xff8dd280; ldrgtb r4, [r6, #-472]; addgt r5, r8, r3, ror #12 |
|
|
|
|
|
|
#10 |
|
Senior Member
Iscritto dal: Jan 2002
Città: Germania
Messaggi: 26110
|
Ma allora come si fa a "intrappolare" uno stack fault? Dovrebbe esistere un qualche metodo per "ripassare" il controllo in user-space? Giusto per capire.
__________________
Per iniziare a programmare c'è solo Python con questo o quest'altro (più avanzato) libro @LinkedIn Non parlo in alcun modo a nome dell'azienda per la quale lavoro Ho poco tempo per frequentare il forum; eventualmente, contattatemi in PVT o nel mio sito. Fanboys |
|
|
|
|
|
#11 |
|
Senior Member
Iscritto dal: Apr 2000
Città: Roma
Messaggi: 15625
|
Un double fault capita quando per gestire una eccezione capita una seconda eccezione. In pratica, se il gate di eccezione punta a un segmenetno non valido o accade...un segfault nel tentativo di lanciare l'handler. Su linux solo un bug del kernel può provocare un double fault in quanto l'handler è sempre presente e su memoria persistente e valida.
L'eccezione di stack viene gestita correttamente dall'handler del kernel (quindi nessun double fault), che invia un segnale al processo. A seguito del segnale, il processo riparte dall'handler predisposto; se durante l'esecuzione di questo handler si verifica nuovamente la stessa eccezione, si ha un (ancora una volta singolo) fault.
__________________
0: or %edi, %ecx; adc %eax, (%edx); popf; je 0b-22; pop %ebx; fadds 0x56(%ecx); lds 0x56(%ebx), %esp; mov %al, %al andeqs pc, r1, #147456; blpl 0xff8dd280; ldrgtb r4, [r6, #-472]; addgt r5, r8, r3, ror #12 |
|
|
|
|
|
#12 |
|
Senior Member
Iscritto dal: Jan 2002
Città: Germania
Messaggi: 26110
|
Sì, le condizioni per il double fault me le ricordavo. Non sapevo invece com'era gestito lo stack fault.
Adesso mi è tutto chiaro e concordo con te, ovviamente, visto che l'eccezione di stack fault viene (dal kernel) "reindirizzata" in user-space all'applicazione. Grazie
__________________
Per iniziare a programmare c'è solo Python con questo o quest'altro (più avanzato) libro @LinkedIn Non parlo in alcun modo a nome dell'azienda per la quale lavoro Ho poco tempo per frequentare il forum; eventualmente, contattatemi in PVT o nel mio sito. Fanboys |
|
|
|
|
| Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 20:46.



















