Enviado em 03/07/2021 - 10:58h
Já analisei o código abaixo com o valgrind (na verdade não sei utilizar isso ainda direito), mas ainda não entendi qual erro de alocação específico que está levando ao programa dar segmentation fault em tempo de execução.
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <stdbool.h>
#include <netdb.h>
#include <unistd.h>
#include <sys/un.h>
#include <sys/times.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define MAXCONN 3
#define SNDTIMEO 5
union sockaddr_any{
struct sockaddr generic;
struct sockaddr_in in;
struct sockaddr_in6 in6;
struct sockaddr_un un;
};
static bool set_sock_opts(int sockfd, size_t sndtimeo, bool only_ipv6) {
const int optval = 1;
struct timeval tm = {sndtimeo, 0};
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0 ) {
return false;
}
if (setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &tm, sizeof(tm)) < 0 ) {
return false;
}
if (only_ipv6 == true) {
if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval)) < 0 ) {
return false;
}
}
return true;
}
static int make_server_socket(int addr_family, const char *service, bool only_ipv6, size_t sndtimeo, size_t somaxconn) {
int sockfd, errcode;
struct addrinfo hints, *result = NULL, *rp = NULL;
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_PASSIVE;
hints.ai_family = addr_family;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = 0;
if ((errcode = getaddrinfo(NULL, service, &hints, &result)) < 0 ) {
fprintf(stderr, "make_server_socket() -> getaddrinfo() -> ERROR: %s\n", gai_strerror(errcode));
exit(EXIT_FAILURE);
}
for (rp = result; rp != NULL; rp = rp->ai_next) {
if ((sockfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) < 0 ) {
continue;
}
if ((set_sock_opts(sockfd, sndtimeo, only_ipv6)) != true ) {
close(sockfd);
continue;
}
if ((bind(sockfd, rp->ai_addr, rp->ai_addrlen)) == 0 ) {
break;
}
close(sockfd);
}
if (!rp) {
fprintf(stderr, "make_server_socket() -> socket()/bind() -> ERROR: %s\n", strerror(errno));
freeaddrinfo(result);
exit(EXIT_FAILURE);
}
freeaddrinfo(result);
if (listen(sockfd, somaxconn) < 0 ) {
fprintf(stderr, "make_server_socket() -> listen() -> ERROR: %s\n", strerror(errno));
close(sockfd);
exit(EXIT_FAILURE);
}
return sockfd;
}
static bool check_addr(int addr_family, const union sockaddr_any *addr, void **cache, size_t cache_size) {
if (addr_family == AF_UNIX) {
for (size_t i = 0; i < cache_size; i++) {
struct sockaddr_un *tmp = cache[i];
if (memcmp(addr->un.sun_path, tmp->sun_path, sizeof(tmp->sun_path)) == 0 ) {
return true;
}
}
} else if (addr_family == AF_INET) {
for (size_t i = 0; i < cache_size; i++) {
struct sockaddr_in *tmp = cache[i];
if (memcmp(&addr->in.sin_addr.s_addr, &tmp->sin_addr.s_addr, sizeof(tmp->sin_addr.s_addr)) == 0 ) {
return true;
}
}
} else if (addr_family == AF_INET6) {
for (size_t i = 0; i < cache_size; i++) {
struct sockaddr_in6 *tmp = cache[i];
if (memcmp(&addr->in6.sin6_addr.s6_addr, &tmp->sin6_addr.s6_addr, sizeof(tmp->sin6_addr.s6_addr)) == 0 ) {
return true;
}
}
} else {
for (size_t i = 0; i < cache_size; i++) {
struct sockaddr *tmp = cache[i];
if (memcmp(&addr->generic.sa_data, &tmp->sa_data, sizeof(tmp->sa_data)) == 0 ) {
return true;
}
}
}
return false;
}
static void show_addr(int addr_family, union sockaddr_any addr) {
char buff[INET6_ADDRSTRLEN];
if (addr_family == AF_UNIX) {
printf("%s\n", addr.un.sun_path);
} else if (addr_family == AF_INET) {
if (inet_ntop(addr_family, &addr.in.sin_addr.s_addr, buff, sizeof(buff)) < 0 ) {
fprintf(stderr, "show_addr() -> inet_ntop() -> ERROR: %s\n", strerror(errno));
} else {
printf("%s\n", buff);
}
} else if (addr_family == AF_INET6) {
if (inet_ntop(addr_family, &addr.in6.sin6_addr.s6_addr, buff, sizeof(buff)) < 0 ) {
fprintf(stderr, "show_addr() -> inet_ntop() -> ERROR: %s\n", strerror(errno));
} else {
printf("%s\n", buff);
}
} else {
fprintf(stderr, "show_addr() -> ERROR: Unexpected socket type\n");
}
}
static bool add_new_table_addr(void **cache, size_t *cache_size, int addr_family, union sockaddr_any *addr) {
socklen_t addrlen;
switch(addr_family) {
case AF_UNIX:
addrlen = sizeof(addr->un);
break;
case AF_INET:
addrlen = sizeof(addr->in);
break;
case AF_INET6:
addrlen = sizeof(addr->in6);
break;
default:
addrlen = sizeof(addr->generic);
}
void *new_addr = malloc(addrlen);
if (!new_addr) {
fprintf(stderr, "ERROR: Memory allocation for %u bytes failed\nadd_new_table_addr() -> malloc() -> ERROR: %s",
addrlen, strerror(errno));
return false;
}
void **new_ptr = realloc(cache, (1 + *cache_size) * sizeof(*cache));
if (!new_ptr) {
fprintf(stderr, "ERROR: Memory allocation for %zu bytes failed\nadd_new_table_addr() -> malloc() -> ERROR: %s",
(1 + *cache_size) * sizeof(*cache), strerror(errno));
free(new_addr);
return false;
}
memcpy(new_addr, addr, addrlen);
cache = new_ptr;
cache[*cache_size] = new_addr;
++*cache_size;
return true;
}
static void free_table(void **cache, size_t cache_size) {
for (size_t i = 0; i < cache_size; i++) {
free(cache[i]);
}
free(cache);
}
static void search(char *argv[], size_t somaxconn, size_t sndtimeo, size_t maxconn) {
int addr_family;
bool only_ipv6 = false;
if (strcmp(argv[1], "-u") == 0 ) {
addr_family = AF_UNIX;
} else if (strcmp(argv[1], "-4") == 0 ) {
addr_family = AF_INET;
} else if (strcmp(argv[1], "-6") == 0 ) {
addr_family = AF_INET6;
only_ipv6 = true;
} else {
addr_family = AF_INET6;
}
int sockfd = make_server_socket(addr_family, argv[2], only_ipv6, sndtimeo, somaxconn);
size_t cache_size = 0;
void **cache = NULL;
char err_msg[] = "Internal server error!", msg_1[] = "Welcome!", msg_2[] = "Get out!";
while (cache_size != maxconn) {
union sockaddr_any client_addr;
socklen_t addrlen = sizeof(client_addr);
int cli_sockfd = accept(sockfd, &client_addr.generic, &addrlen);
if (cli_sockfd < 0 ) {
fprintf(stderr, "search() -> accept() -> ERROR: %s\n", strerror(errno));
} else {
if (check_addr(addr_family, &client_addr, cache, cache_size) != true ) {
if (add_new_table_addr(cache, &cache_size, addr_family, &client_addr) != true ) {
if (send(cli_sockfd, err_msg, sizeof(err_msg), 0) < 0 ) {
fprintf(stderr, "search() -> send() -> ERROR: %s\n", strerror(errno));
}
} else {
show_addr(addr_family, client_addr);
if (send(cli_sockfd, msg_1, sizeof(msg_1), 0) < 0 ) {
fprintf(stderr, "search() -> send() -> ERROR: %s\n", strerror(errno));
}
}
} else {
if (send(cli_sockfd, msg_2, sizeof(msg_2), 0) < 0 ) {
fprintf(stderr, "search() -> send() -> ERROR: %s\n", strerror(errno));
}
}
close(cli_sockfd);
}
}
close(sockfd);
free_table(cache, cache_size);
}
int main(int argc, char *argv[]) {
if (argc == 1) {
printf(" *** ERROR: No arguments! ***\n");
printf("Usage: %s [OPTION] [PORT/SERVICE] [SOMAXCONN] [SNDTIMEO] [MAXCONN]\n", argv[0]);
printf(" -u Use process comunication\n");
printf(" -4 Use IPv4\n");
printf(" -6 Use IPv6\n");
printf(" -M Use IPv4 and IPv6 (IPv4-Mapped IPv6 Adress)\n");
printf(" -h Show this page\n");
exit(EXIT_FAILURE);
}
int opt = getopt(argc, argv, "u46Mh");
if (strlen(argv[1]) > 2 ) {
printf("*** Invalid value for [OPTION] ***\n");
printf("Usage: %s [OPTION] [PORT/SERVICE] [SOMAXCONN] [SNDTIMEO] [MAXCONN]\n", argv[0]);
printf(" -u Use process comunication\n");
printf(" -4 Use IPv4\n");
printf(" -6 Use IPv6\n");
printf(" -M Use IPv4 and IPv6 (IPv4-Mapped IPv6 Adress)\n");
printf(" -h Show this page\n");
} else if (opt == 'h' || opt == '?') {
printf("Usage: %s [OPTION] [PORT/SERVICE] [SOMAXCONN] [SNDTIMEO] [MAXCONN]\n", argv[0]);
printf(" -u Use process comunication\n");
printf(" -4 Use IPv4\n");
printf(" -6 Use IPv6\n");
printf(" -M Use IPv4 and IPv6 (IPv4-Mapped IPv6 Adress)\n");
printf(" -h Show this page\n");
} else if ((argc > 6) || (argc < 6)) {
printf("*** Invalid arguments! ***\n");
printf("Usage: %s [OPTION] [PORT/SERVICE] [SOMAXCONN] [SNDTIMEO] [MAXCONN]\n", argv[0]);
printf(" -u Use process comunication\n");
printf(" -4 Use IPv4\n");
printf(" -6 Use IPv6\n");
printf(" -M Use IPv4 and IPv6 (IPv4-Mapped IPv6 Adress)\n");
printf(" -h Show this page\n");
} else {
size_t somaxconn = strtoull(argv[3], NULL, 10);
size_t sndtimeo = strtoull(argv[4], NULL, 10);
size_t maxconn = strtoull(argv[5], NULL, 10);
if (somaxconn > SOMAXCONN) {
printf("*** ERROR: The value passed for [SOMAXCONN] is too long! ***\n");
printf("The maximum allowed value is %d\n", SOMAXCONN);
} else if (sndtimeo > SNDTIMEO) {
printf("*** ERROR: The value passed for [SNDTIMEO] is too long! ***\n");
printf("The maximum allowed value is %d\n", SNDTIMEO);
} else if (maxconn > MAXCONN) {
printf("*** ERROR: The value passed for [MAXCONN] is too long! ***\n");
printf("The maximum allowed value is %d\n", MAXCONN);
} else {
search(argv, somaxconn, sndtimeo, maxconn);
}
}
return EXIT_SUCCESS;
}
$ valgrind --leak-check=full ./server -M 9009 4096 5 3
==10626== Memcheck, a memory error detector
==10626== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==10626== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==10626== Command: ./server -M 9009 4096 5 3
==10626==
::1
==10626== Invalid read of size 8
==10626== at 0x1098ED: check_addr (in /home/xubuntu/Documents/server)
==10626== by 0x109E2E: search (in /home/xubuntu/Documents/server)
==10626== by 0x10A2FA: main (in /home/xubuntu/Documents/server)
==10626== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==10626==
==10626==
==10626== Process terminating with default action of signal 11 (SIGSEGV)
==10626== Access not within mapped region at address 0x0
==10626== at 0x1098ED: check_addr (in /home/xubuntu/Documents/server)
==10626== by 0x109E2E: search (in /home/xubuntu/Documents/server)
==10626== by 0x10A2FA: main (in /home/xubuntu/Documents/server)
==10626== If you believe this happened as a result of a stack
==10626== overflow in your program's main thread (unlikely but
==10626== possible), you can try to increase the size of the
==10626== main thread stack using the --main-stacksize= flag.
==10626== The main thread stack size used in this run was 8388608.
==10626==
==10626== HEAP SUMMARY:
==10626== in use at exit: 36 bytes in 2 blocks
==10626== total heap usage: 4 allocs, 2 frees, 1,136 bytes allocated
==10626==
==10626== 36 (8 direct, 28 indirect) bytes in 1 blocks are definitely lost in loss record 2 of 2
==10626== at 0x483B723: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==10626== by 0x483E017: realloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==10626== by 0x109B1B: add_new_table_addr (in /home/xubuntu/Documents/server)
==10626== by 0x109E5C: search (in /home/xubuntu/Documents/server)
==10626== by 0x10A2FA: main (in /home/xubuntu/Documents/server)
==10626==
==10626== LEAK SUMMARY:
==10626== definitely lost: 8 bytes in 1 blocks
==10626== indirectly lost: 28 bytes in 1 blocks
==10626== possibly lost: 0 bytes in 0 blocks
==10626== still reachable: 0 bytes in 0 blocks
==10626== suppressed: 0 bytes in 0 blocks
==10626==
==10626== For lists of detected and suppressed errors, rerun with: -s
==10626== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 0 from 0)
Segmentation fault (core dumped)
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <limits.h>
#include <stdbool.h>
#include <netdb.h>
#include <unistd.h>
#include <sys/un.h>
#include <sys/time.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#define SNDTIMEO 5
#define MAXCONN 10
static bool set_sock_opts(int sockfd, bool only_ipv6) {
bool ok = false;
const int optval = 1;
struct timeval timeout = {SNDTIMEO, 0};
do {
if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) != 0 ) {
break;
}
if (setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, &timeout, sizeof(timeout)) != 0 ) {
break;
}
if (only_ipv6 == true) {
if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval)) != 0 ) {
break;
}
}
ok = true;
} while (false);
return ok;
}
static int make_server_socket(int af, const char *service, bool only_ipv6, size_t somaxconn) {
int sockfd, ecode;
struct addrinfo hints, *result = NULL, *rp = NULL;
memset(&hints, 0, sizeof(hints));
hints.ai_flags = AI_PASSIVE;
hints.ai_family = af;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = 0;
if ((ecode = getaddrinfo(NULL, service, &hints, &result)) != 0 ) {
fprintf(stderr, "make_server_socket() -> getaddrinfo() -> ERROR: %s\n", gai_strerror(ecode));
exit(EXIT_FAILURE);
}
for (rp = result; rp != NULL; rp = rp->ai_next) {
if ((sockfd = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol)) < 0 ) {
continue;
}
if (set_sock_opts(sockfd, only_ipv6) != true ) {
close(sockfd);
continue;
}
if (bind(sockfd, rp->ai_addr, rp->ai_addrlen) != -1 ) {
break;
}
close(sockfd);
}
if (rp == NULL) {
fprintf(stderr, "make_server_socket() -> socket()/bind() -> ERROR: %s\n", strerror(errno));
freeaddrinfo(rp);
exit(EXIT_FAILURE);
}
freeaddrinfo(rp);
if (listen(sockfd, somaxconn) < 0 ) {
fprintf(stderr, "make_server_socket() -> listen() -> ERROR: %s\n", strerror(errno));
close(sockfd);
exit(EXIT_FAILURE);
}
return sockfd;
}
static bool check_addr(int af, void *addr, void **addr_table, size_t count) {
bool found = false;
if (af == AF_UNIX) {
struct sockaddr_un *un = addr;
for (size_t i = 0; i < count; i++) {
struct sockaddr_un *tmp = addr_table[i];
if (memcmp(un->sun_path, tmp->sun_path, sizeof(un->sun_path)) == 0 ) {
found = true;
break;
}
}
} else if (af == AF_INET) {
struct sockaddr_in *in = addr;
for (size_t i = 0; i < count; i++) {
struct sockaddr_in *tmp = addr_table[i];
if (memcmp(&in->sin_addr.s_addr, &tmp->sin_addr.s_addr, sizeof(in->sin_addr.s_addr)) == 0 ) {
found = true;
break;
}
}
} else {
struct sockaddr_in6 *in6 = addr;
for(size_t i = 0; i < count; i++) {
struct sockaddr_in6 *tmp = addr_table[i];
if (memcmp(&in6->sin6_addr.s6_addr, &tmp->sin6_addr.s6_addr, sizeof(in6->sin6_addr.s6_addr)) == 0 ) {
found = true;
break;
}
}
}
return found;
}
static void show_addr(int af, void *addr) {
char buff[INET6_ADDRSTRLEN];
if (af == AF_UNIX) {
struct sockaddr_un *un = addr;
printf("%s\n", un->sun_path);
} else if (af == AF_INET) {
struct sockaddr_in *in = addr;
if (inet_ntop(af, &in->sin_addr.s_addr, buff, INET_ADDRSTRLEN) < 0 ) {
fprintf(stderr, "show_addr() -> inet_ntop() -> ERROR: %s\n", strerror(errno));
} else {
printf("%s\n", buff);
}
} else {
struct sockaddr_in6 *in6 = addr;
if (inet_ntop(af, &in6->sin6_addr.s6_addr, buff, INET6_ADDRSTRLEN) < 0 ) {
fprintf(stderr, "show_addr() -> inet_ntop() -> ERROR: %s\n", strerror(errno));
} else {
printf("%s\n", buff);
}
}
}
static void **realloc_addr_table(void **addr_table, size_t count, socklen_t addrlen) {
void **tmp = realloc(addr_table, count * sizeof(*addr_table));
if (tmp == NULL) {
fprintf(stderr, "ERROR: Memory allocation for %zu bytes failed\nrealloc_addr_table() -> realloc() -> ERROR: %s\n",
count * sizeof(*addr_table), strerror(errno));
} else {
tmp[count-1] = malloc(addrlen);
if (tmp == NULL) {
fprintf(stderr, "ERROR: Memory allocation for %u bytes failed\nrealloc_addr_table -> realloc() -> ERROR: %s\n",
addrlen, strerror(errno));
}
}
return tmp;
}
static void free_addr_table(void **addr_table, size_t count) {
for (size_t i = 0; i < count; i++) {
free(addr_table[i]);
}
free(addr_table);
}
static void search(char **argv, size_t somaxconn, size_t maxconn) {
int af;
bool only_ipv6 = false;
socklen_t addrlen;
if (strcmp(argv[1], "-u") == 0 ) {
af = AF_UNIX;
addrlen = sizeof(struct sockaddr_un);
} else if (strcmp(argv[1], "-4") == 0 ) {
af = AF_INET;
addrlen = sizeof(struct sockaddr_in);
} else if (strcmp(argv[1], "-6") == 0 ) {
af = AF_INET6;
only_ipv6 = true;
addrlen = sizeof(struct sockaddr_in6);
} else {
af = AF_INET6;
addrlen = sizeof(struct sockaddr_in6);
}
size_t i = 0;
int sockfd = make_server_socket(af, argv[2], only_ipv6, somaxconn);
void *addr = malloc(addrlen);
void **addr_table = NULL;
const char msg_1[] = "Welcome!\n", err_msg[] = "Internal server error!", msg_2[] = "Get out!\n";
while (i < maxconn) {
int cli_sockfd;
if ((cli_sockfd = accept(sockfd, addr, &addrlen)) < 0 ) {
fprintf(stderr, "search() -> accept() -> ERROR: %s\n", strerror(errno));
} else {
if (check_addr(af, addr, addr_table, i) == false ) {
void **tmp = realloc_addr_table(addr_table, i+1, addrlen);
if (!tmp) {
send(cli_sockfd, err_msg, sizeof(err_msg), 0);
} else {
i++;
addr_table = tmp;
memcpy(addr_table[i-1], addr, addrlen);
show_addr(af, addr);
send(cli_sockfd, msg_1, sizeof(msg_1), 0);
}
}else{
send(cli_sockfd, msg_2, sizeof(msg_2), 0);
}
close(cli_sockfd);
}
}
free(addr);
free_addr_table(addr_table, i);
close(sockfd);
}
int main(int argc, char **argv) {
if (argc == 1) {
printf(" *** ERROR: No arguments! ***\n");
printf("Usage: %s [OPTION] [PORT/SERVICE] [SOMAXCONN] [MAXCONN]\n", argv[0]);
printf(" -u Use process comunication\n");
printf(" -4 Use IPv4\n");
printf(" -6 Use IPv6\n");
printf(" -M Use IPv4 and IPv6 (IPv4-Mapped IPv6 Adress)\n");
printf(" -h Show this page\n");
exit(EXIT_FAILURE);
}
int opt = getopt(argc, argv, "u46Mh");
if (strlen(argv[1]) > 2 ) {
printf("*** Invalid value for [OPTION]! ***\n");
printf("Usage: %s [OPTION] [PORT/SERVICE] [SOMAXCONN] [MAXCONN]\n", argv[0]);
printf(" -u Use process comunication\n");
printf(" -4 Use IPv4\n");
printf(" -6 Use IPv6\n");
printf(" -M Use IPv4 and IPv6 (IPv4-Mapped IPv6 Adress)\n");
printf(" -h Show this page\n");
} else if (opt == 'h' || opt == '?') {
printf("Usage: %s [OPTION] [PORT/SERVICE] [SOMAXCONN] [MAXCONN]\n", argv[0]);
printf(" -u Use process comunication\n");
printf(" -4 Use IPv4\n");
printf(" -6 Use IPv6\n");
printf(" -M Use IPv4 and IPv6 (IPv4-Mapped IPv6 Adress)\n");
printf(" -h Show this page\n");
} else if ((argc < 5) || (argc > 5)) {
printf("*** Invalid arguments! ***\n");
printf("Usage: %s [OPTION] [PORT/SERVICE] [SOMAXCONN] [MAXCONN]\n", argv[0]);
printf(" -u Use process comunication\n");
printf(" -4 Use IPv4\n");
printf(" -6 Use IPv6\n");
printf(" -M Use IPv4 and IPv6 (IPv4-Mapped IPv6 Adress)\n");
printf(" -h Show this page\n");
} else {
size_t somaxconn = strtoull(argv[3], NULL, 10);
size_t maxconn = strtoull(argv[4], NULL, 10);
if (somaxconn > SOMAXCONN) {
printf("*** ERROR: The value passed for [SOMAXCONN] is too long! ***\n");
printf("The maximum allowed value is %d\n", SOMAXCONN);
} else if (maxconn > MAXCONN) {
printf("*** ERROR: The value passed for [MAXCONN] is too long! ***\n");
printf("The maximum allowed value is %d\n", MAXCONN);
} else {
search(argv, somaxconn, maxconn);
}
}
return EXIT_SUCCESS;
}
$ gcc -Wall server_1.c -o server
$ valgrind --leak-check=full ./server -M 9009 4096 3
==6549== Memcheck, a memory error detector
==6549== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==6549== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==6549== Command: ./server -M 9009 4096 3
==6549==
::ffff:127.0.0.1
::1
::ffff:192.168.50.2
==6549==
==6549== HEAP SUMMARY:
==6549== in use at exit: 0 bytes in 0 blocks
==6549== total heap usage: 9 allocs, 9 frees, 1,260 bytes allocated
==6549==
==6549== All heap blocks were freed -- no leaks are possible
==6549==
==6549== For lists of detected and suppressed errors, rerun with: -s
==6549== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Passkeys: A Evolução da Autenticação Digital
Instalação de distro Linux em computadores, netbooks, etc, em rede com o Clonezilla
Título: Descobrindo o IP externo da VPN no Linux
Armazenando a senha de sua carteira Bitcoin de forma segura no Linux
Enviar mensagem ao usuário trabalhando com as opções do php.ini
Instalando Brave Browser no Linux Mint 22
vídeo pra quem quer saber como funciona Proteção de Memória:
Encontre seus arquivos facilmente com o Drill
Mouse Logitech MX Ergo Advanced Wireless Trackball no Linux
Compartilhamento de Rede com samba em modo Público/Anônimo de forma simples, rápido e fácil
Programa duplicado no "Abrir com" e na barra de pesquisa do ... (1)
VMs e Interfaces de Rede desapareceram (13)
Como abrir o pycharm no linux [RESOLVIDO] (4)