Irssi: Segfault no envio de mensagens grandes

Criado em 30 nov. 2017  ·  47Comentários  ·  Fonte: irssi/irssi

Quando tento imprimir toda a Bíblia cristã em um canal (com a proteção contra inundação desativada no servidor e no cliente), o irssi falha em parte do caminho.

Se eu usar /exec -out cat bible.txt para imprimir a bíblia, irssi segfaults. Se eu usar um comando diferente que divide o arquivo em aproximadamente 10 partes e dorme por dois segundos entre as partes de impressão, tudo é enviado com sucesso.

Passos para reproduzir:

  • execute o comando acima com um arquivo aproximadamente do mesmo tamanho de toda a Bíblia.

Comportamento esperado:

  • A Bíblia inteira é enviada para o canal
  • irssi não faz segfault

Comportamento real:

  • Parte da Bíblia é enviada para o canal
  • Segfaults irssi

Estou usando o irssi 1.0.5-1 (20171020 1715) dos repositórios de teste debian, mas esse problema persistiu em várias versões.

Informe se houver alguma informação adicional que possa ser útil para mim.

WIP bug memory

Comentários muito úteis

Ah, sim, um servidor cristão.

Consegui reproduzir o acidente. Obrigado!

A versão curta (pontos de interrupção em server_connect_init , server->connection_lost = TRUE , glog_func , server_disconnect ), já conta praticamente toda a história. Registro maior com backtraces: log.txt

0x00007f095e233f30 in _start () from /lib64/ld-linux-x86-64.so.2
(rr) c
Continuing.

Breakpoint 9, server_connect_init (server=0x558ecd4099a0) at servers.c:357
357             g_return_if_fail(server != NULL);
(rr)
Continuing.
[New Thread 29950.29980]

Thread 1 hit Breakpoint 12, glog_func (log_domain=0x0, log_level=G_LOG_LEVEL_WARNING, message=0x558ecd88a9d0
    "Dropping some data on an outgoing connection") at fe-common-core.c:253
253             switch (log_level) {
(rr)
Continuing.

Thread 1 hit Breakpoint 11, irc_server_send_data (server=0x558ecd4099a0, data=<optimized out>, len=94) at irc-servers.c:529
529                     server->connection_lost = TRUE;
(rr)
Continuing.

Thread 1 hit Breakpoint 4, server_disconnect (server=0x558ecd4099a0) at servers.c:462
462     {
(rr)
Continuing.

Thread 1 hit Breakpoint 12, glog_func (log_domain=0x7f095d55efc5 "GLib", log_level=G_LOG_LEVEL_CRITICAL, message=0x558ecd5876b0
    "g_hash_table_lookup: assertion 'hash_table != NULL' failed") at fe-common-core.c:253
253             switch (log_level) {
(rr)
Continuing.

Thread 1 hit Breakpoint 12, glog_func (log_domain=0x7f095d55efc5 "GLib", log_level=G_LOG_LEVEL_CRITICAL, message=0x558ecd9f0200
    "g_hash_table_lookup: assertion 'hash_table != NULL' failed") at fe-common-core.c:253
253             switch (log_level) {
(rr)
Continuing.

[...]

Thread 1 received signal SIGSEGV, Segmentation fault.
flood_newmsg (server=0x558ecd4099a0, level=4, nick=0x558ecd40acd1 "|\237U",
    host=0x558ecd40acd9 "ble_lookup: assertion 'hash_table != NULL' failed",
    target=0x558ecd594720 "#christianity") at flood.c:196
196             flood = g_hash_table_lookup(mserver->floodlist, nick);
(rr)

O server->connection_lost = TRUE acontece alguns frames de pilha acima do mesmo caminho que Dropping some data on an outgoing connection

A mensagem de entrada enviada do segundo irssi é tratada pelo sig_public do nickcolor.pl que faz $server->command(...) , que chama parse_command que nota server->connection_lost e se desconecta.

server_disconnect ainda não o mata, mas emite o sinal de "servidor desconectado" que limpa coisas como server->isupport que resulta nessas mensagens de tabela de hash NULL e chama flood_deinit_server que remove os dados do módulo dessa inundação.

Então, quando chega a flood_newmsg ele faz mserver = MODULE_DATA(server); , não consegue encontrá-lo e retorna NULL, e mserver->floodlist trava.

Acho que não adianta nada depois do free aqui, o que é muito legal. No momento em que ele falha, o refcount do servidor é 1, tudo está bem lá. É apenas um punhado de coisas sendo chamadas depois que a parte irc do servidor está cheia de NULLs.

Todos 47 comentários

@dequis

#0  flood_newmsg (server=0x555555b96a10, level=4, nick=0x5555559b6c41 "iled", host=0x5555559b6c4a "", target=0x555556f25600 "#test") at flood.c:196
#1  0x00005555555e053f in flood_privmsg (server=0x555555b96a10, data=<optimized out>, nick=0x5555559b6c41 "iled", addr=0x5555559b6c4a "") at flood.c:255
#2  0x00005555555fa0b6 in signal_emit_real (rec=rec@entry=0x555555870350, params=params@entry=4, va=va@entry=0x7fffffffe1d0, first_hook=<optimized out>) at signals.c:242
#3  0x00005555555fa60d in signal_emit (signal=<optimized out>, params=params@entry=4) at signals.c:286
#4  0x00005555555c0858 in irc_server_event (server=0x555555b96a10, line=0x5555559b6c6c "", nick=0x5555559b6c41 "iled", address=0x5555559b6c4a "") at irc.c:308
#5  0x00005555555fa0b6 in signal_emit_real (rec=rec@entry=0x5555558743d0, params=params@entry=4, va=va@entry=0x7fffffffe390, first_hook=<optimized out>) at signals.c:242
#6  0x00005555555fa6e5 in signal_emit_id (signal_id=<optimized out>, params=4) at signals.c:304
#7  0x00005555555fa0b6 in signal_emit_real (rec=rec@entry=0x55555586ed00, params=params@entry=2, va=va@entry=0x7fffffffe500, first_hook=<optimized out>) at signals.c:242
#8  0x00005555555fa6e5 in signal_emit_id (signal_id=<optimized out>, params=params@entry=2) at signals.c:304
#9  0x00005555555c09b5 in irc_parse_incoming (server=0x555555b96a10) at irc.c:383
#10 0x00005555555eb84d in irssi_io_invoke (source=<optimized out>, condition=<optimized out>, data=<optimized out>) at misc.c:55
#11 0x00007ffff6ba8dd5 in g_main_context_dispatch () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#12 0x00007ffff6ba91a0 in ?? () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#13 0x00007ffff6ba922c in g_main_context_iteration () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#14 0x000055555557701f in main (argc=<optimized out>, argv=<optimized out>) at irssi.c:335

Cheguei a 1 Reis 11:43 antes da queda

Que mensagem de saída as outras pessoas veem no canal?

Isso também acontece com um perfil limpo? irssi --home=~/.irssi-test/

Que mensagem de saída as outras pessoas veem no canal?

Alguns segundos depois que as mensagens param, os segfaults do irssi e -!- test [[email protected]] has quit [Connection closed] são enviados para o canal

Isso também acontece com um perfil limpo?

Com um perfil completamente limpo, a proteção contra inundações me impede de tentar isso. Depois de desligar a proteção contra inundação, envio tudo, mas apenas parte dele realmente aparece para outras pessoas no canal (o mesmo que estava acontecendo antes), mas alguns segundos depois, em vez de segfaulting, a conexão é encerrada. Irssi diz "Conexão perdida" e o canal exibe a mesma mensagem de encerramento que era quando ocorreu a falha de segmento (encerrou [Conexão fechada]).

Estou surpreso com a mudança de comportamento, já que as únicas mudanças reais em minha configuração além de desligar a proteção contra inundação são esquemas de cores e aliases.

Ok, isso é interessante. Para referência, estou testando isso com um cliente de "teste" de onde envio o texto da Bíblia, e outro cliente (o cliente de "visualização") ingressou no mesmo canal de onde observo externamente.

Quando envio o texto da Bíblia no cliente de teste, vejo que tudo é enviado ao canal em um ou dois segundos.
No cliente de visualização, vejo o texto fluindo rapidamente por vários segundos, antes de parar abruptamente em algum ponto bem antes do final do texto.

Nesse ponto, normalmente espero alguns segundos e então o cliente falha em segfa ou é desconectado (dependendo da configuração), mas acabei de perceber que isso sempre coincide com alguém no canal dizendo ou fazendo algo que é enviado para o cliente de teste . No caso da configuração original em que ocorre falha de segmento, qualquer pessoa que diga algo no canal ou saia do canal após a interrupção do texto aciona a falha de segmento. Com a configuração nova, ele aciona uma desconexão.

Aqui está outro backtrace

#0  flood_newmsg (server=0x555555b96c40, level=4, nick=0x5555559b6c41 "", host=0x5555559b6c4b "table_lookup: assertion 'hash_table != NULL' failed", 
    target=0x555555d6bf80 "#test") at flood.c:196
#1  0x00005555555e053f in flood_privmsg (server=0x555555b96c40, data=<optimized out>, nick=0x5555559b6c41 "", 
    addr=0x5555559b6c4b "table_lookup: assertion 'hash_table != NULL' failed") at flood.c:255
#2  0x00005555555fa0b6 in signal_emit_real (rec=rec@entry=0x555555870350, params=params@entry=4, va=va@entry=0x7fffffffe1d0, first_hook=<optimized out>) at signals.c:242
#3  0x00005555555fa60d in signal_emit (signal=<optimized out>, params=params@entry=4) at signals.c:286
#4  0x00005555555c0858 in irc_server_event (server=0x555555b96c40, line=0x5555559b6c6b "ble != NULL' failed", nick=0x5555559b6c41 "", 
    address=0x5555559b6c4b "table_lookup: assertion 'hash_table != NULL' failed") at irc.c:308
#5  0x00005555555fa0b6 in signal_emit_real (rec=rec@entry=0x5555558743d0, params=params@entry=4, va=va@entry=0x7fffffffe390, first_hook=<optimized out>) at signals.c:242
#6  0x00005555555fa6e5 in signal_emit_id (signal_id=<optimized out>, params=4) at signals.c:304
#7  0x00005555555fa0b6 in signal_emit_real (rec=rec@entry=0x55555586ed00, params=params@entry=2, va=va@entry=0x7fffffffe500, first_hook=<optimized out>) at signals.c:242
#8  0x00005555555fa6e5 in signal_emit_id (signal_id=<optimized out>, params=params@entry=2) at signals.c:304
#9  0x00005555555c09b5 in irc_parse_incoming (server=0x555555b96c40) at irc.c:383
#10 0x00005555555eb84d in irssi_io_invoke (source=<optimized out>, condition=<optimized out>, data=<optimized out>) at misc.c:55
#11 0x00007ffff6ba8dd5 in g_main_context_dispatch () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#12 0x00007ffff6ba91a0 in ?? () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#13 0x00007ffff6ba922c in g_main_context_iteration () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
#14 0x000055555557701f in main (argc=<optimized out>, argv=<optimized out>) at irssi.c:335

Há algum script carregado que possa explicar a diferença entre as configurações ou quaisquer outras diferenças de configuração?

qual cliente trava, aquele que manda a bíblia?

Há algum script carregado que possa explicar a diferença entre as configurações ou quaisquer outras diferenças de configuração?

Os únicos scripts que carreguei são algumas coisas simples que registram um comando. Nada que escute todas as linhas, de entrada ou saída, como eu esperaria que algo fizesse se isso causasse um segfault de texto de alto volume. As únicas diferenças de configuração também são muito pequenas - apenas alguns aliases e um esquema de cores. Quando eu tiver tempo mais tarde, tentarei habilitar as coisas em minha configuração normal, pouco a pouco, em uma configuração nova e ver em que ponto começa a travar.

qual cliente trava, aquele que manda a bíblia?

sim

o estranho em seu backtrace é que ele falha em alguma mensagem que chega, então não deve estar relacionado ao envio da Bíblia. (mas talvez esse envio cause alguma corrupção de memória em algum lugar? apenas especulação aleatória minha ..)

você está tentando com os dequis da Bíblia?

você tem a possibilidade de obter uma captura do WireChark do tráfego de rede antes que ele trave?

#4  0x00005555555c0858 in irc_server_event (server=0x555555b96c40, line=0x5555559b6c6b "ble != NULL' failed", nick=0x5555559b6c41 "", 
    address=0x5555559b6c4b "table_lookup: assertion 'hash_table != NULL' failed") at irc.c:308

não parece uma linha real que deveria estar vindo do servidor de IRC

se você for para o primeiro quadro (f 0) e p * servidor, o registro do servidor está intacto? você também pode tentar nos mostrar um bt full

o estranho no seu backtrace é que ele falha em alguma mensagem que chega

Sim, é sempre a primeira mensagem recebida depois que o texto da Bíblia para de ser enviado.

você está tentando com os dequis da Bíblia?

Eu não acho que eles sejam exatamente a mesma Bíblia, mas eles são quase do mesmo tamanho e é tudo apenas um texto ascii normal.

se você for para o primeiro quadro (f 0) e p * servidor, o registro do servidor está intacto?

(gdb) p *server
$1 = {type = 716, chat_type = 66, refcount = 1, connrec = 0x555555ab3680, connect_time = 1512491572, real_connect_time = 1512491574, tag = 0x555555c86b30 "test", 
  nick = 0x555555ccdde0 "test", connected = 1, disconnected = 1, connection_lost = 1, session_reconnect = 0, no_reconnect = 0, handle = 0x0, readtag = -1, connect_pipe = {0x0, 0x0}, 
  connect_tag = -1, connect_pid = 2281, rawlog = 0x555555c858e0, module_data = 0x555555a6a060, version = 0x555555ab4570 "InspIRCd-2.2", away_reason = 0x0, last_invite = 0x0, 
  server_operator = 1, usermode_away = 0, banned = 0, dns_error = 0, lag_sent = {tv_sec = 0, tv_usec = 0}, lag_last_check = 1512491575, lag = 132, channels = 0x0, queries = 0x0, 
  channels_join = 0x5555555c1980 <irc_channels_join>, isnickflag = 0x5555555c8670 <isnickflag_func>, ischannel = 0x5555555c9410 <ischannel_func>, 
  get_nick_flags = 0x5555555c6db0 <get_nick_flags>, send_message = 0x5555555c90e0 <send_message>, split_message = 0x5555555c8950 <split_message>, 
  channel_find_func = 0x5555555c1740 <irc_channel_find_server>, query_find_func = 0x5555555c8490 <irc_query_find>, mask_match_func = 0x0, nick_match_msg = 0x0, redirects = 0x0, 
  redirect_queue = 0x0, redirect_next = 0x0, redirect_active = 0x0, last_nick = 0x555555d6bcc0 "+i", real_address = 0x0, usermode = 0x0, wanted_usermode = 0x0, userhost = 0x0, 
  channels_formed = 30, whois_found = 0, whowas_found = 0, emode_known = 1, no_multi_mode = 0, no_multi_who = 0, one_endofwho = 0, disable_lag = 0, nick_collision = 0, motd_got = 1, 
  isupport_sent = 1, cap_complete = 1, sasl_success = 0, max_kicks_in_cmd = 1, max_modes_in_cmd = 20, max_whois_in_cmd = 4, max_msgs_in_cmd = 20, cap_supported = 0x0, 
  cap_active = 0x0, cap_queue = 0x0, sasl_buffer = 0x0, sasl_timeout = 0, cmdcount = 57070, cmdqueue = 0x0, wait_cmd = {tv_sec = 0, tv_usec = 346171}, last_cmd = {
    tv_sec = 1512491613, tv_usec = 92250}, max_cmds_at_once = 5, cmd_queue_speed = 0, max_query_chans = 1, idles = 0x0, ctcpqueue = 0x0, knockoutlist = 0x0, splits = 0x0, 
  split_servers = 0x0, rejoin_channels = 0x0, chanqueries = 0x0, isupport = 0x0, modes = {{func = 0x0, prefix = 0 '\000'} <repeats 65 times>, {func = 0x5555555cee90 <modes_type_d>, 
      prefix = 0 '\000'}, {func = 0x0, prefix = 0 '\000'}, {func = 0x0, prefix = 0 '\000'}, {func = 0x5555555cee90 <modes_type_d>, prefix = 0 '\000'}, {func = 0x0, 
      prefix = 0 '\000'}, {func = 0x0, prefix = 0 '\000'}, {func = 0x0, prefix = 0 '\000'}, {func = 0x0, prefix = 0 '\000'}, {func = 0x5555555ce3f0 <modes_type_a>, 
      prefix = 0 '\000'}, {func = 0x0, prefix = 0 '\000'}, {func = 0x0, prefix = 0 '\000'}, {func = 0x0, prefix = 0 '\000'}, {func = 0x5555555cee90 <modes_type_d>, 
      prefix = 0 '\000'}, {func = 0x0, prefix = 0 '\000'}, {func = 0x0, prefix = 0 '\000'}, {func = 0x5555555cee90 <modes_type_d>, prefix = 0 '\000'}, {func = 0x0, 
      prefix = 0 '\000'}, {func = 0x5555555cee90 <modes_type_d>, prefix = 0 '\000'}, {func = 0x0, prefix = 0 '\000'}, {func = 0x0, prefix = 0 '\000'}, {func = 0x0, 
      prefix = 0 '\000'}, {func = 0x0, prefix = 0 '\000'}, {func = 0x0, prefix = 0 '\000'}, {func = 0x0, prefix = 0 '\000'}, {func = 0x5555555cebb0 <modes_type_prefix>, 
      prefix = 33 '!'}, {func = 0x0, prefix = 0 '\000'}, {func = 0x0, prefix = 0 '\000'}, {func = 0x0, prefix = 0 '\000'}, {func = 0x0, prefix = 0 '\000'}, {func = 0x0, 
      prefix = 0 '\000'}, {func = 0x0, prefix = 0 '\000'}, {func = 0x0, prefix = 0 '\000'}, {func = 0x0, prefix = 0 '\000'}, {func = 0x5555555ce3f0 <modes_type_a>, 
      prefix = 0 '\000'}, {func = 0x0, prefix = 0 '\000'}, {func = 0x0, prefix = 0 '\000'}, {func = 0x5555555ce3f0 <modes_type_a>, prefix = 0 '\000'}, {func = 0x0, 
      prefix = 0 '\000'}, {func = 0x0, prefix = 0 '\000'}, {func = 0x5555555cebb0 <modes_type_prefix>, prefix = 37 '%'}, {func = 0x5555555cee90 <modes_type_d>, prefix = 0 '\000'}, {
      func = 0x0, prefix = 0 '\000'}, {func = 0x5555555ce950 <modes_type_b>, prefix = 0 '\000'}, {func = 0x5555555ce8d0 <modes_type_c>, prefix = 0 '\000'}, {
      func = 0x5555555cee90 <modes_type_d>, prefix = 0 '\000'}, {func = 0x5555555cee90 <modes_type_d>, prefix = 0 '\000'}, {func = 0x5555555cebb0 <modes_type_prefix>, 
      prefix = 64 '@'}, {func = 0x5555555cee90 <modes_type_d>, prefix = 0 '\000'}, {func = 0x0, prefix = 0 '\000'}, {func = 0x5555555cee90 <modes_type_d>, prefix = 0 '\000'}, {
      func = 0x5555555cee90 <modes_type_d>, prefix = 0 '\000'}, {func = 0x5555555cee90 <modes_type_d>, prefix = 0 '\000'}, {func = 0x5555555cee90 <modes_type_d>, prefix = 0 '\000'}, 
    {func = 0x5555555cebb0 <modes_type_prefix>, prefix = 43 '+'}, {func = 0x5555555ce3f0 <modes_type_a>, prefix = 0 '\000'}, {func = 0x0, prefix = 0 '\000'}, {func = 0x0, 
      prefix = 0 '\000'}, {func = 0x5555555cee90 <modes_type_d>, prefix = 0 '\000'}, {func = 0x0, prefix = 0 '\000'} <repeats 133 times>}, 
  prefix = '\000' <repeats 33 times>, "Y\000\000\000h\000\000\000\000\000v", '\000' <repeats 20 times>, "o", '\000' <repeats 190 times>, 
  nick_comp_func = 0x5555555c7ec0 <irc_nickcmp_rfc1459>}

você também pode tentar nos mostrar um bt full

(gdb) bt full
#0  flood_newmsg (server=0x555555b96ae0, level=4, nick=0x5555559b6c81 "le_lookup: assertion 'hash_table != NULL' failed", 
    host=0x5555559b6c8c "assertion 'hash_table != NULL' failed", target=0x555556b0d0c0 "#test") at flood.c:196
        mserver = <optimized out>
        flood = <optimized out>
        rec = <optimized out>
        now = <optimized out>
        ttime = <optimized out>
        times = <optimized out>
        tnext = <optimized out>
        __func__ = "flood_newmsg"
#1  0x00005555555e053f in flood_privmsg (server=0x555555b96ae0, data=<optimized out>, nick=0x5555559b6c81 "le_lookup: assertion 'hash_table != NULL' failed", 
    addr=0x5555559b6c8c "assertion 'hash_table != NULL' failed") at flood.c:255
        params = 0x555556b0d0c0 "#test"
        target = 0x555556b0d0c0 "#test"
        text = 0x555556b0d0cc "no one will see this"
        level = 4
        nick = 0x5555559b6c81 "le_lookup: assertion 'hash_table != NULL' failed"
        server = 0x555555b96ae0
        data = <optimized out>
        addr = 0x5555559b6c8c "assertion 'hash_table != NULL' failed"
#2  0x00005555555fa0b6 in signal_emit_real (rec=rec@entry=0x555555870350, params=params@entry=4, va=va@entry=0x7fffffffe1f0, first_hook=<optimized out>) at signals.c:242
        arglist = {0x555555b96ae0, 0x555555d7c0ce, 0x5555559b6c81, 0x5555559b6c8c, 0x0, 0x0}
        prev_emitted_signal = 0x5555558743d0
        hook = 0x555555877000
        prev_emitted_hook = 0x55555586e470
        i = <optimized out>
        stopped = 0
        stop_emit_count = 0
        continue_emit_count = 0
        __func__ = "signal_emit_real"
#3  0x00005555555fa60d in signal_emit (signal=<optimized out>, params=params@entry=4) at signals.c:286
        rec = 0x555555870350
        va = {{gp_offset = 48, fp_offset = 48, overflow_arg_area = 0x7fffffffe2e0, reg_save_area = 0x7fffffffe210}}
        signal_id = <optimized out>
        __func__ = "signal_emit"
#4  0x00005555555c0858 in irc_server_event (server=0x555555b96ae0, line=0x5555559b6cb5 "[", nick=0x5555559b6c81 "le_lookup: assertion 'hash_table != NULL' failed", 
    address=0x5555559b6c8c "assertion 'hash_table != NULL' failed") at irc.c:308
        signal = <optimized out>
        event = 0x555555d7c0c0 "event privmsg"
        args = <optimized out>
        __func__ = "irc_server_event"
#5  0x00005555555fa0b6 in signal_emit_real (rec=rec@entry=0x5555558743d0, params=params@entry=4, va=va@entry=0x7fffffffe3b0, first_hook=<optimized out>) at signals.c:242
        arglist = {0x555555b96ae0, 0x5555559b6cb5, 0x5555559b6c81, 0x5555559b6c8c, 0x0, 0x0}
        prev_emitted_signal = 0x55555586ed00
        hook = 0x55555586e470
        prev_emitted_hook = 0x55555586ed30
        i = <optimized out>
        stopped = 0
        stop_emit_count = 0
        continue_emit_count = 0
        __func__ = "signal_emit_real"
#6  0x00005555555fa6e5 in signal_emit_id (signal_id=<optimized out>, params=4) at signals.c:304
        rec = 0x5555558743d0
        va = {{gp_offset = 48, fp_offset = 48, overflow_arg_area = 0x7fffffffe4a0, reg_save_area = 0x7fffffffe3d0}}
        __func__ = "signal_emit_id"
#7  0x00005555555fa0b6 in signal_emit_real (rec=rec@entry=0x55555586ed00, params=params@entry=2, va=va@entry=0x7fffffffe520, first_hook=<optimized out>) at signals.c:242
        arglist = {0x555555b96ae0, 0x5555559b6c80, 0x0, 0x0, 0x0, 0x0}
        prev_emitted_signal = 0x0
        hook = 0x55555586ed30
        prev_emitted_hook = 0x0
        i = <optimized out>
        stopped = 0
        stop_emit_count = 0
        continue_emit_count = 0
        __func__ = "signal_emit_real"
#8  0x00005555555fa6e5 in signal_emit_id (signal_id=<optimized out>, params=params@entry=2) at signals.c:304
        rec = 0x55555586ed00
        va = {{gp_offset = 32, fp_offset = 48, overflow_arg_area = 0x7fffffffe610, reg_save_area = 0x7fffffffe540}}
        __func__ = "signal_emit_id"
#9  0x00005555555c09b5 in irc_parse_incoming (server=0x555555b96ae0) at irc.c:383
        str = 0x5555559b6c80 "ble_lookup: assertion 'hash_table != NULL' failed"
        count = 0
        ret = 0
        server = 0x555555b96ae0
        count = 0
        ret = 0
#10 0x00005555555eb84d in irssi_io_invoke (source=<optimized out>, condition=<optimized out>, data=<optimized out>) at misc.c:55
        rec = <optimized out>
        icond = <optimized out>
#11 0x00007ffff6ba8dd5 in g_main_context_dispatch () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
No symbol table info available.
#12 0x00007ffff6ba91a0 in ?? () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
No symbol table info available.
#13 0x00007ffff6ba922c in g_main_context_iteration () from /lib/x86_64-linux-gnu/libglib-2.0.so.0
No symbol table info available.
#14 0x000055555557701f in main (argc=<optimized out>, argv=<optimized out>) at irssi.c:335
        version = 0
        options = {{long_name = 0x55555560ef4e "version", short_name = 118 'v', flags = 0, arg = G_OPTION_ARG_NONE, arg_data = 0x555555854a60 <version>, 
            description = 0x55555560c515 "Display irssi version", arg_description = 0x0}, {long_name = 0x0, short_name = 0 '\000', flags = 0, arg = G_OPTION_ARG_NONE, 
            arg_data = 0x0, description = 0x0, arg_description = 0x0}}
        loglev = 5

Oh, aqui está um novo desenvolvimento.

Eu só travo quando envio o texto para um canal que tem outras pessoas nele. O que parece estar acontecendo é que enquanto o texto está inundando o canal e meu cliente está ocupado enviando-o, algum outro cliente no canal não consegue acompanhar e trava, e a mensagem do servidor sobre sua desconexão é enviada para mim e minha inundação da Bíblia para imediatamente. A próxima mensagem para mim é segfaults.

Se eu fizer isso em um canal vazio ou com outros usuários que sei que não vou dizer nada ou travar durante a inundação, não travo e todo o texto é enviado.

Eu realmente não consigo rastreá-lo, mesmo com todas as informações que você forneceu. você se sente confortável para compilar o irssi? você pode aplicar este patch https://github.com/ailin-nemui/irssi/commit/4e56675d2fea8aed59d91875f317ec228c94da85.patch e registrar um rastreamento de emissão de sinal como: irssi 2>signal_trace.log

@ailin-nemui Claro, me dê alguns minutos

Ok, então com a versão do irssi que compilei com o patch, ele nunca falha. Eu não tenho ideia do porquê.

Além disso, o arquivo signal_trace.log tem 645 MB.

bem .. obrigado por tentar .. meh. Gostaria de saber se você poderia executá-lo sob o verificador de memória valgrind (sem o patch de rastreamento de sinal); mas talvez também seja lento demais para travar. ou com outros métodos @josephbisch , você tem alguma sugestão de como fazer a melhor triagem desse problema?

Eu concordo com a sugestão de @ailin-nemui sobre tentar capturar o tráfego de rede se possível com o Wireshark para ver o que o servidor está enviando para o cliente com falha.

Então, podemos ser capazes de criar um servidor "falso" que envie os mesmos comandos com o netcat para evitar a necessidade de um servidor real e configuração de cliente (s) para reproduzir o problema do nosso lado (espero).

f wirehark é muito difícil, você pode tentar / conectar -rawlog arquivo e se tivermos sorte ele captura / grava o suficiente antes de travar

Assim, o irssi não falha com o patch de rastreamento de sinal ou quando executado em valgrind. Eu acho que ambos tornam isso muito lento?

Não acho que o wirehark seja viável. O servidor em que executo o irssi tem muitos usuários, causando muito tráfego de rede (incluindo outros clientes de irc). Não é tanto tráfego que eu ache que possa ter algo a ver com os travamentos, mas é o suficiente para que provavelmente seja difícil extrair qualquer coisa do log, a menos que o WireShark tenha algumas ferramentas de filtragem realmente boas que eu não conheço.

você pode tentar / conectar -arquivo de log de log

Certo. O que isso faz exatamente? Eu apenas tentei usá-lo e não parecia criar nenhum arquivo.

Para fins de reprodução, mencionarei novamente que isso só acontece se o ircd enviar uma mensagem para o cliente que está enviando a Bíblia enquanto ele está enviando a Bíblia. Se vocês estavam tentando reproduzi-lo em um canal vazio, provavelmente não funcionará. Ter um bot no mesmo canal que diz algo arbitrário a cada segundo deve funcionar, assim como ter um segundo cliente conectado onde você apenas envia manualmente algumas mensagens enquanto o primeiro cliente está enviando a Bíblia.

Vocês provavelmente podem descobrir o que está errado com muito mais facilidade do que eu, se ao menos pudesse ser reproduzido.

Tem certeza de que / connect -rawlog file não cria um arquivo chamado file no mesmo diretório em que você executa o irssi? Ele deve registrar as mensagens de IRC brutas que estão sendo enviadas.

Acho que se conseguirmos obter o rawlog de você, poderemos reproduzi-lo sem precisar tentar obter as mesmas condições com relação aos bots ou outros clientes que você tem.

Em última análise, o problema aqui é que o irssi está travando em resposta a algo que está sendo recebido do servidor, mesmo se a mensagem do servidor estiver sendo enviada para o irssi travado como resultado de uma mensagem de outro cliente. Portanto, realmente precisamos das mensagens entre o servidor e o cliente que está travando e, então, devemos ser capazes de reproduzir o bug.

Não consigo reproduzir o bug, mesmo com as instruções do seu último comentário. Acho que é mais complexo do que apenas ter um bot ou segundo cliente enviando mensagens ao mesmo tempo que a Bíblia está sendo enviada.

A propósito, @ spaghetti2514 o que exatamente você fez quando disse desativar a proteção contra inundações?

o que exatamente você fez quando disse desativar a proteção contra inundações?

Defino cmd_queue_speed como 0

Fiz o rawlog funcionar (estava dando a ele um caminho em vez de apenas um nome de arquivo porque queria o arquivo em outro lugar). Os resultados não são esclarecedores. É apenas um monte de PRIVMSGs saindo de mim para o servidor contendo passagens da Bíblia seguidas pela única mensagem que me mata, seja uma mensagem de um bot ou qualquer outra coisa. Não há nada depois disso.

Exemplo:

...
<< PRIVMSG #test :13:27 So the servants of the householder came and said unto him, Sir,
<< PRIVMSG #test :didst not thou sow good seed in thy field? from whence then hath it
>> :[email protected] PRIVMSG #test :aaa

Talvez vocês não consigam reproduzi-lo porque não conseguem preencher algum tipo de buffer rápido o suficiente? Se o disco IO está causando um gargalo em você, há um módulo do kernel que você pode compilar e carregar para obter um dispositivo de caractere do qual você pode ler a Bíblia diretamente.

Não acho que o disco IO deva ser um gargalo aqui. Você disse que em uma configuração ela não travou, mas apenas desconectou. Você teve a chance de investigar a diferença na configuração?

Ok, finalmente descobri qual é a diferença do perfil. Se nickcolor.pl estiver presente em scripts / autorun, irssi segfaults, caso contrário, não estará.

Seria possível obter uma cópia do seu diretório ~/.irssi (incluindo nickcolor.pl ) que você usa para causar a falha, por favor?

Além disso, você poderia me indicar uma cópia de bible.txt que está usando?

Seria possível testarmos no servidor IRC que você está usando também? Em caso afirmativo, você poderia nos fornecer as informações para conectar?

Talvez possamos reproduzi-lo se copiarmos tudo exatamente!

Obrigado por sua persistência em nos ajudar a descobrir isso!

Aqui está um zip contendo o diretório mínimo .irssi e o bible.txt

Estou testando isso no irc.oppaiti.me, que está executando o inspircd 2.2.0. Se você for se juntar, saiba que o motivo é todo o roteiro do filme das abelhas.

Ah, sim, um servidor cristão.

Consegui reproduzir o acidente. Obrigado!

A versão curta (pontos de interrupção em server_connect_init , server->connection_lost = TRUE , glog_func , server_disconnect ), já conta praticamente toda a história. Registro maior com backtraces: log.txt

0x00007f095e233f30 in _start () from /lib64/ld-linux-x86-64.so.2
(rr) c
Continuing.

Breakpoint 9, server_connect_init (server=0x558ecd4099a0) at servers.c:357
357             g_return_if_fail(server != NULL);
(rr)
Continuing.
[New Thread 29950.29980]

Thread 1 hit Breakpoint 12, glog_func (log_domain=0x0, log_level=G_LOG_LEVEL_WARNING, message=0x558ecd88a9d0
    "Dropping some data on an outgoing connection") at fe-common-core.c:253
253             switch (log_level) {
(rr)
Continuing.

Thread 1 hit Breakpoint 11, irc_server_send_data (server=0x558ecd4099a0, data=<optimized out>, len=94) at irc-servers.c:529
529                     server->connection_lost = TRUE;
(rr)
Continuing.

Thread 1 hit Breakpoint 4, server_disconnect (server=0x558ecd4099a0) at servers.c:462
462     {
(rr)
Continuing.

Thread 1 hit Breakpoint 12, glog_func (log_domain=0x7f095d55efc5 "GLib", log_level=G_LOG_LEVEL_CRITICAL, message=0x558ecd5876b0
    "g_hash_table_lookup: assertion 'hash_table != NULL' failed") at fe-common-core.c:253
253             switch (log_level) {
(rr)
Continuing.

Thread 1 hit Breakpoint 12, glog_func (log_domain=0x7f095d55efc5 "GLib", log_level=G_LOG_LEVEL_CRITICAL, message=0x558ecd9f0200
    "g_hash_table_lookup: assertion 'hash_table != NULL' failed") at fe-common-core.c:253
253             switch (log_level) {
(rr)
Continuing.

[...]

Thread 1 received signal SIGSEGV, Segmentation fault.
flood_newmsg (server=0x558ecd4099a0, level=4, nick=0x558ecd40acd1 "|\237U",
    host=0x558ecd40acd9 "ble_lookup: assertion 'hash_table != NULL' failed",
    target=0x558ecd594720 "#christianity") at flood.c:196
196             flood = g_hash_table_lookup(mserver->floodlist, nick);
(rr)

O server->connection_lost = TRUE acontece alguns frames de pilha acima do mesmo caminho que Dropping some data on an outgoing connection

A mensagem de entrada enviada do segundo irssi é tratada pelo sig_public do nickcolor.pl que faz $server->command(...) , que chama parse_command que nota server->connection_lost e se desconecta.

server_disconnect ainda não o mata, mas emite o sinal de "servidor desconectado" que limpa coisas como server->isupport que resulta nessas mensagens de tabela de hash NULL e chama flood_deinit_server que remove os dados do módulo dessa inundação.

Então, quando chega a flood_newmsg ele faz mserver = MODULE_DATA(server); , não consegue encontrá-lo e retorna NULL, e mserver->floodlist trava.

Acho que não adianta nada depois do free aqui, o que é muito legal. No momento em que ele falha, o refcount do servidor é 1, tudo está bem lá. É apenas um punhado de coisas sendo chamadas depois que a parte irc do servidor está cheia de NULLs.

@ spaghetti2514 você pode testar https://github.com/irssi/irssi/pull/803 e ver se isso corrige o problema?

Eu ficaria feliz em

@ailin-nemui
Surpreendentemente, não. O Irssi ainda apresenta falhas de segurança após seguir as mesmas etapas.

informações gdb e backtrace com # 803 aplicado

Thread 1 "irssi" received signal SIGSEGV, Segmentation fault.
flood_newmsg (server=0x5555559b60d0, level=4, 
    nick=0x5555559af021 "B\"\366\377\177", host=0x5555559af027 "", 
    target=0x555555b32000 "#test") at flood.c:196
196             flood = g_hash_table_lookup(mserver->floodlist, nick);

(gdb) bt
#0  flood_newmsg (server=0x5555559b60d0, level=4, 
    nick=0x5555559af021 "B\"\366\377\177", host=0x5555559af027 "", 
    target=0x555555b32000 "#test") at flood.c:196
#1  0x00005555555ddfff in flood_privmsg (server=0x5555559b60d0, 
    data=<optimized out>, nick=0x5555559af021 "B\"\366\377\177", 
    addr=0x5555559af027 "") at flood.c:255
#2  0x00005555555f7136 in signal_emit_real (rec=rec@entry=0x555555872340, 
    params=params@entry=4, va=va@entry=0x7fffffffe138, 
    first_hook=<optimized out>) at signals.c:242
#3  0x00005555555f7660 in signal_emit (signal=<optimized out>, 
    params=params@entry=4) at signals.c:286
#4  0x00005555555bf388 in irc_server_event (server=0x5555559b60d0, 
    line=0x5555559af040 "PRIVMSG #test :And all the prophets prophesied so, saying, Go up to Ramothgilead, and prosper: for the anime tiddies shall deliver it into the hand of the king.", nick=0x5555559af021 "B\"\366\377\177", 
    address=0x5555559af027 "") at irc.c:338
#5  0x00005555555f7136 in signal_emit_real (rec=rec@entry=0x555555876360, 
    params=params@entry=4, va=va@entry=0x7fffffffe2e8, 
    first_hook=<optimized out>) at signals.c:242
#6  0x00005555555f7738 in signal_emit_id (signal_id=<optimized out>, 
    params=4) at signals.c:304
#7  0x00005555555f7136 in signal_emit_real (rec=rec@entry=0x555555881210, 
    params=params@entry=2, va=va@entry=0x7fffffffe448,

@ spaghetti2514 :(

você pode tentar com este script? quanto ele imprime antes de travar?

sub print_signal {
Irssi::active_win->print(Irssi::signal_get_emitted) ;
} 
for ("server connected", "server disconnected", "server destroyed") {
Irssi::signal_add_first ( $_, "print_signal" ) ;
} 

@ ailin-nemui Em que é impresso? Não vejo nada extra impresso com este script carregado.

@ spaghetti2514 ímpar. ele deve imprimir na janela ativa. você pode alterar o código para

sub print_signal {
print STDERR Irssi::signal_get_emitted() . "\n";
} 

para imprimir em stderr ao invés e executar irssi 2>stderr.log

primeiro, teste-o sem a Bíblia:

/connect irc.oppaiti.me
/disconnect

deve imprimir algo assim, se tudo estiver funcionando

 -!- Irssi: Looking up irc.oppaiti.me
 -!- Irssi: server connected
 -!- Irssi: Connection to irc.oppaiti.me established
 !irc.oppaiti.me *** Looking up your hostname...
 -!- Your host is irc.oppaiti.me, running version InspIRCd-2.2
...
 -!- Irssi: Disconnecting from server irc.oppaiti.me: [leaving]
 -!- Irssi: server disconnected
 -!- Irssi: Connection lost to irc.oppaiti.me
 -!- Irssi: server destroyed

as 3 mensagens "Irssi: server ..." são deste pequeno script de depuração

Eu testei as mudanças no # 803 também. Do master em d85f86726115a2f80d878254dd9773470d6dd9c1, mesclei a ramificação. Antes de mesclar, vi o segfault de forma confiável. Depois de aplicar o branch, não há segfault.

Um ponto interessante: vejo isso na janela de status (mesmo antes de o Irssi ser atualizado para mostrar que não há conexão):

19:39 -!- Irssi: warning Dropping some data on an outgoing connection
19:39 -!- Irssi: process 0 (cat /will/t/t/bible.txt) terminated with return code 0

Embora não haja travamento, o comportamento depois é estranho. O Irssi fica sentado ali parecendo estar conectado até que outro cliente no canal faça algo (envie uma mensagem). Então Irssi desiste. Fazer qualquer outra coisa no Irssi, inclusive enviar uma mensagem para o canal, não faz com que ele seja encerrado, mas parece desconectado, pois se tento enviar uma mensagem para o canal parece que funcionou, mas nada mostra no canal no outro cliente. Isso é a mesma coisa que @ spaghetti2514 encontrou, pois algo deve acontecer externamente após a inundação, mas agora não travamos, apenas desconectamos.

A propósito, sou capaz de reproduzir a falha de forma confiável usando um servidor que coloquei para teste (não queria testar repetidamente no servidor @ spaghetti2514 mencionado).

obrigado pela análise detalhada @horgh , parece que devemos investigar melhor o que está acontecendo lá e por que ele não se desconecta (poderia ser um bug / efeito colateral da minha correção?)

@horgh

Antes de mesclar, vi o segfault de forma confiável. Depois de aplicar o branch, não há segfault.

Esquisito. Talvez eu apliquei o patch errado

@ailin-nemui

por que ele não desconecta (pode ser um bug / efeito colateral da minha correção?)

Não acho que seja um efeito colateral da sua correção. É o mesmo comportamento que eu via antes de seu patch sempre que nickcolor.pl não é carregado. Carregar nickcolor.pl apenas substitui a desconexão por um segfault. Qualquer um deles ainda é acionado pelo servidor enviando algo depois que o cliente fantasma se desconecta.

Também sinto muito se estou lento para tentar coisas ou ajudar, no momento estou viajando e estou muito ocupado.

Sim, acho que o estranho estado de semi-conexão não é causado pela correção, já que vimos o atraso antes.

Sobre a desconexão atrasada:

Acabamos definindo server->connection_lost true (em irc_server_send_data() ) depois de ver o aviso sobre "Eliminar alguns dados". Então, nesse ponto (ou o mais rápido possível), provavelmente devemos estar totalmente desconectados do servidor. Mas ainda não o fazemos.

A desconexão acontece em irc_parse_incoming() e parece: Quando uma mensagem (ou qualquer coisa do servidor) chega e vemos que server->connection_lost é verdadeiro, chamamos server_disconnect() .

Essas mudanças neste commit nos fazem chamar server_disconnect() imediatamente: horgh / irssi @ 9ce84040cf7308636ed6f7746f8bfa4e3ef82eb2

Funciona bem para este cenário. Se quisermos fazer isso, devemos verificar qualquer sinal que usa um SERVER_REC* que poderia nos levar a chamá-lo de server_disconnect() , pois sem segurar uma referência ele pode ser liberado e o SERVER_REC* pode se tornar inválido (e vamos travar de uma nova maneira). Portanto, pode haver uma maneira melhor de causar a desconexão.

Eu também tentei ter um cronômetro que desconectava todos os servidores sinalizados ->connection_lost . Uma função de cronômetro evita a preocupação de SERVER_REC* se tornar inválido no meio do evento, mas haveria uma janela de tempo em que o servidor estaria neste estado parcialmente conectado (entre quando obtemos ->connection_lost definido e quando o cronômetro dispara), por isso não parece ideal.

Edit: Provavelmente não podemos usar essa abordagem (matando SERVER_REC* naquele ponto), pois não acho que será possível proteger SERVER_REC* suficientemente (por exemplo, scripts Perl). Ligar para server_disconnect() algum lugar parece a coisa certa a fazer, mas não sei onde!

@ spaghetti2514 talvez você possa repetir o patch quando tiver tempo. verifique se o patch está funcionando primeiro, com o caso simples que mostrei em https://github.com/irssi/irssi/issues/796#issuecomment -355636720

@horgh Acho que chamar server_disconnect parece ser a solução certa (e única). A única outra ideia que tenho seria adicionar o cheque ao mainloop. Certa vez, tive esse plano de alterar o modelo do emissor de sinal (evento) para o padrão "após o evento", ou seja, você inseriu alguns eventos que serão executados após o

Sua ideia de ter uma maneira de executar as coisas após o término do processamento do sinal atual é legal! Eu estava olhando em volta para ver se havia uma API assim. Seria definitivamente útil aqui, e parece que houve outras situações em que teria sido útil.

Talvez algo tão simples como registrar funções de retorno de chamada para o loop principal disparar funcione. Vou dar uma olhada nesse loop!

Eu tenho uma solução para o aspecto de desconexão / segfault atrasada disso em horgh / irssi @ f8bdc01. Isso nos faz limpar o servidor da próxima vez por meio do loop de eventos. O intervalo é muito curto como você pode ver. A ideia era ser efetivamente instantâneo. Eu testei junto com as mudanças no # 803 e parece funcionar bem. Sem segfault e o Irssi mostra que o servidor está desconectado imediatamente.

Não consegui encontrar uma solução melhor, apesar de continuar insistindo nisso.

803 parece resolver bem a parte do segfault.

Acho que provavelmente deveríamos implementar nossa própria fonte de eventos para enfileirar eventos, em vez do tempo limite, 1 hack :-)

Sim, não é muito bom. Embora curto!

Não tenho certeza de como seria essa fila. Você tem uma ideia aproximada de como você acha que deveria ser? Não estou certo de como os eventos funcionam em geral: flushed:

Esta página foi útil?
0 / 5 - 0 avaliações