when calling PQconnectdb in the main program all run very well, but if i call it inside a function a seg fault appears.
here the code that run
#include <stdio.h>
#include <stdlib.h>
#include <postgresql/libpq-fe.h>
#define PG_HOST "127.0.0.1"
#define PG_USER "postgres"
#define PG_DB "postgres"
#define PG_PASS "postgres"
#define PG_PORT 5432
static void
exit_nicely(PGconn *conn)
{
PQfinish(conn);
exit(1);
}
int main( void )
{
char conninfo[250];
PGconn *conn = NULL;
PGresult *pgres = NULL;
sprintf(conninfo, "user=%s password=%s dbname=%s hostaddr=%s port=%d", PG_USER, PG_PASS, PG_DB, PG_HOST, PG_PORT);
conn = PQconnectdb(conninfo);
if (PQstatus(conn) != CONNECTION_OK)
{
fprintf(stderr, "ERROR: Connection to database failed: %s", PQerrorMessage(conn));
exit_nicely(conn);
}
PQfinish(conn);
return 0;
}
this code run very well.
but when i put PQconnect inside a function, the program will generate a seg fault
int connect(char* conninfo, PGconn* conn)
{
conn = PQconnectdb(conninfo);
if (PQstatus(conn) != CONNECTION_OK)
{
fprintf(stderr, "ERROR: Connection to database failed: %s", PQerrorMessage(conn));
exit_nicely(conn);
}
return 1;
}
int main( void )
{
char conninfo[250];
PGconn *conn = NULL;
PGresult *pgres = NULL;
sprintf(conninfo, "user=%s password=%s dbname=%s hostaddr=%s port=%d", PG_USER, PG_PASS, PG_DB, PG_HOST, PG_PORT);
connect(conninfo, conn);
if(!conn)
fprintf(stderr, "conn is null.\n");
PQfinish(conn);
return 0;
}
herein the crash stack
(gdb) where
#0 __strlen_sse2 () at ../sysdeps/x86_64/multiarch/../strlen.S:32
#1 0x00007ffff7893086 in __GI___strdup (s=0x7 <Address 0x7 out of bounds>) at strdup.c:42
#2 0x00007ffff7bbbd87 in ?? () from /usr/lib/libpq.so.5
#3 0x00007ffff7bbc2a5 in ?? () from /usr/lib/libpq.so.5
#4 0x00007ffff7bbe389 in PQconnectStart () from /usr/lib/libpq.so.5
#5 0x00007ffff7bbe416 in PQconnectdb () from /usr/lib/libpq.so.5
#6 0x0000000000400912 in connect (conninfo=0x7 <Address 0x7 out of bounds>, conn=0x60a630) at pqconnect.c:25
#7 0x00007ffff7bbcadb in PQconnectPoll () from /usr/lib/libpq.so.5
#8 0x00007ffff7bbd77e in ?? () from /usr/lib/libpq.so.5
#9 0x00007ffff7bbe3b4 in PQconnectStart () from /usr/lib/libpq.so.5
#10 0x00007ffff7bbe416 in PQconnectdb () from /usr/lib/libpq.so.5
#11 0x0000000000400912 in connect (conninfo=0x7fffffffe600 "user=btel_user password=JwN5K9e18PsTb dbname=ULIC hostaddr=127.0.0.1 port=5432", conn=0x0) at pqconnect.c:25
#12 0x00000000004009e3 in main () at pqconnect.c:49
When i declare my function connect as static, the seg fault error doesn't occur but the returned pointer for the variable conn is NULL
WHY? :(
I think you have a mixup between your connect and the standard library connect. Your connect takes precedence, so when PQconnectdb tries to call connect, things would go bad.
Try to rename the function.
Making connect static also prevents the mixup, which explains why the crash is removed.
Also, you pass the conn parameter to connect incorrectly. It's passed by value, so the variable in main isn't changed, and stays NULL.
You need to pass it by reference.
Note: #Aleix ==> This code should run well.
int pg_connect(char* conninfo, PGconn** conn)
{
*conn = PQconnectdb(conninfo);
if (PQstatus(*conn) != CONNECTION_OK) {
fprintf(stderr,
"ERROR: Connection to database failed: %s",
PQerrorMessage(*conn));
return 0;
}
return 1;
}
/* set correctely your values here */
#define PG_HOST "127.0.0.1"
#define PG_USER "postgres"
#define PG_DB "postgres"
#define PG_PASS "postgres"
#define PG_PORT 5432
int main(int argc, char *argv[])
{
char conninfo[250];
PGconn *conn = NULL;
PGresult *pgres = NULL;
sprintf(conninfo,
"user=%s password=%s dbname=%s hostaddr=%s port=%d",
PG_USER, PG_PASS, PG_DB, PG_HOST, PG_PORT);
if (!pg_connect(conninfo, &conn)) {
goto end;
}
/*
Here fit your staff
*/
end:
PQfinish(conn);
return 0;
}
Related
Summary
When my code calls BIO_do_connect it jumps back to the start of the function that called it and then segfaults.
What Tried
Debugger, Valgrind, changing code
// compiled with:
// gcc -g -O0 -Wall -Wextra -o sslex sslex_main.c -fstack-protector -lssl -lcrypto
#include <stdio.h>
#include <string.h>
#include <openssl/ssl.h>
#include <openssl/bio.h>
#include <openssl/err.h>
// BIO handles communication including files and sockets.
static BIO* g_bio = NULL;
// holds SSL connection information
static SSL_CTX* g_sslContext = NULL;
char* g_trustedStore = "certs/trusted.pem";
void initialize() {
SSL_load_error_strings();
ERR_load_BIO_strings();
OpenSSL_add_all_algorithms();
}
int connect(char* hostnamePort) {
SSL* sslp = NULL;
BIO* out = NULL;
printf("Connect called\n");
printf("Connecting... to %s\n", hostnamePort);
g_sslContext = SSL_CTX_new(TLS_client_method());
// load trusted certificate store
if (! SSL_CTX_load_verify_locations(g_sslContext, g_trustedStore, NULL)) {
fprintf(stderr, "Failure loading certificats from trusted store %s!\n", g_trustedStore);
fprintf(stderr, "Error: %s\n", ERR_reason_error_string(ERR_get_error()));
return -1;
}
g_bio = BIO_new_ssl_connect(g_sslContext);
if (g_bio == NULL) {
fprintf(stderr, "Error cannot get BSD Input/Output\n");
return -1;
}
// retrieve ssl pointer of the BIO
BIO_get_ssl(g_bio, &sslp);
if (sslp == NULL) {
fprintf(stderr, "Could not locate SSL pointer\n");
fprintf(stderr, "Error: %s\n", ERR_reason_error_string(ERR_get_error()));
return -1;
}
// if server wants a new handshake, handle that in the background
SSL_set_mode(sslp, SSL_MODE_AUTO_RETRY);
// attempt to connect
BIO_set_conn_hostname(g_bio, hostnamePort);
out = BIO_new_fp(stdout, BIO_NOCLOSE);
printf("Connecting to: %s\n", BIO_get_conn_hostname(g_bio));
// THIS LINE CAUSES STACK SMASH
if (BIO_do_connect(g_bio) <= 0) { // BUGGY LINE
fprintf(stderr, "Error cannot connect to %s\n", hostnamePort);
fprintf(stderr, "Error: %s\n", ERR_reason_error_string(ERR_get_error()));
BIO_free_all(g_bio);
SSL_CTX_free(g_sslContext);
return -1;
}
return -1;
}
void close_connection() {
BIO_free_all(g_bio);
SSL_CTX_free(g_sslContext);
}
int main(int argc, char* argv[]) {
char* hostnamePort = argv[1];
initialize();
if (connect(hostnamePort) != 0)
return 0;
printf("Done connecting. doing operation\n");
close_connection();
return 0;
}
Expected Result:
"Connect called" should be displayed only once.
Program should not Segmentation fault.
Actual Output:
./sslex 192.168.11.141
Connect called
Connecting... to 192.168.11.141
Connecting to: 192.168.11.141
Connect called
Segmentation fault (core dumped)
Debugger Output and Backtrace:
Starting program: sslex 192.168.11.141
warning: Probes-based dynamic linker interface failed.
Reverting to original interface.
Connect called
Connecting... to 192.168.11.141
Connecting to: 192.168.11.141
Breakpoint 3, connect (hostnamePort=0x7fffffffe9db "192.168.11.141") at sslex_main.c:57
57 if (BIO_do_connect(g_bio) <= 0) { // BUGGY LINE
(gdb) bt
#0 connect (hostnamePort=0x7fffffffe9db "192.168.11.141") at sslex_main.c:57
#1 0x000055555555503a in main (argc=2, argv=0x7fffffffe698) at sslex_main.c:75
(gdb) s
Connect called
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff733d646 in ?? ()
(gdb) bt
#0 0x00007ffff733d646 in ?? ()
#1 0x00007ffff72e94d3 in ?? ()
#2 0x0000000000000000 in ?? ()
Your function connect() is hiding the standard neworking library function of the same name that OpenSSL is calling to make the actual TCP connection, but instead of getting the library one, it's calling yours.
Rename your function (say, to do_connect()) so it won't clash with the one from the library.
I have an issue where any Leak Sanitizer backtraces that go through dynamically loaded libraries report Unknown Module for any function calls within that library.
Direct leak of 48 byte(s) in 1 object(s) allocated from:
#0 0x4e3e36 in malloc (/usr/sbin/radiusd+0x4e3e36)
#1 0x7fb406e95f69 (<unknown module>)
#2 0x7fb406eafc36 (<unknown module>)
#3 0x7fb406eafd40 (<unknown module>)
#4 0x7fb406ea3364 (<unknown module>)
#5 0x7fb4063de7d4 (<unknown module>)
#6 0x7fb4063c61c4 (<unknown module>)
#7 0x7fb406617863 (<unknown module>)
#8 0x7fb415620681 in dl_load_func /usr/src/debug/freeradius-server-4.0.0/src/main/dl.c:194:34
#9 0x7fb41561edab in dl_symbol_init_walk /usr/src/debug/freeradius-server-4.0.0/src/main/dl.c:301:7
#10 0x7fb41561df1e in dl_module /usr/src/debug/freeradius-server-4.0.0/src/main/dl.c:748:6
#11 0x7fb41561f3db in dl_instance /usr/src/debug/freeradius-server-4.0.0/src/main/dl.c:853:20
#12 0x7fb41564f4ab in module_bootstrap /usr/src/debug/freeradius-server-4.0.0/src/main/module.c:827:6
#13 0x7fb41564ed56 in modules_bootstrap /usr/src/debug/freeradius-server-4.0.0/src/main/module.c:1070:14
#14 0x5352bb in main /usr/src/debug/freeradius-server-4.0.0/src/main/radiusd.c:561:6
#15 0x7fb41282ab34 in __libc_start_main (/lib64/libc.so.6+0x21b34)
#16 0x4204ab in _start (/usr/sbin/radiusd+0x4204ab)
I've had an almost identical issue with valgrind before, and I know it's due to the libraries being unloaded with dlclose on exit, and the symbols being unavailable when the symbolizer runs.
With valgrind the fix is simple
/*
* Only dlclose() handle if we're *NOT* running under valgrind
* as it unloads the symbols valgrind needs.
*/
if (!RUNNING_ON_VALGRIND) dlclose(module->handle); /* ignore any errors */
RUNNING_ON_VALGRIND being a macro provided by the valgrind library for detecting if the program is being valground.
I can't see anything in the LSAN docs for a similar feature for when ASAN_OPTIONS=detect_leaks=1 is set.
Does anyone know if it's possible to perform a runtime check for running under LSAN?
The LSAN interface headers allow the user to define a callback __lsan_is_turned_off to allow the program to disable the leak checker. This callback is only executed if LSAN is enabled.
#include <sanitizer/lsan_interface.h>
static bool running_under_lsan = false;
int __attribute__((used)) __lsan_is_turned_off(void)
{
running_under_lsan = true;
return 0;
}
EDIT: It's actually more complicated than that. As #yugr commented It appears __lsan_is_turned_off is only executed when a process or child process exits.
There is however a solution!
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sanitizer/common_interface_defs.h>
static int from_child[2] = {-1, -1};
static int pid;
int __attribute__((used)) __lsan_is_turned_off(void)
{
uint8_t ret = 1;
/* Parent */
if (pid != 0) return 0;
/* Child */
if (write(from_child[1], &ret, sizeof(ret)) < 0) {
fprintf(stderr, "Writing LSAN status failed: %s", strerror(errno));
}
close(from_child[1]);
return 0;
}
int main(int argc, char **argv)
{
uint8_t ret = 0;
if (pipe(from_child) < 0) {
fprintf(stderr, "Failed opening internal pipe: %s", strerror(errno));
exit(EXIT_FAILURE);
}
pid = fork();
if (pid == -1) {
fprintf(stderr, "Error forking: %s", strerror(errno));
exit(EXIT_FAILURE);
}
/* Child */
if (pid == 0) {
close(from_child[0]); /* Close parent's side */
exit(EXIT_SUCCESS);
}
/* Parent */
close(from_child[1]); /* Close child's side */
while ((read(from_child[0], &ret, sizeof(ret)) < 0) && (errno == EINTR));
close(from_child[0]); /* Close our side (so we don't leak FDs) */
/* Collect child */
waitpid(pid, NULL, 0);
if (ret) {
printf("Running under LSAN\n");
} else {
printf("Not running under LSAN\n");
}
exit(EXIT_SUCCESS);
}
Example:
clang -g3 -fsanitize=address foo.c
ASAN_OPTIONS='detect_leaks=1' ./a.out
Running under LSAN
ASAN_OPTIONS='detect_leaks=0' ./a.out
Not running under LSAN
First of all, not printing stacktraces on dlclose (or printing incorrect ones) is a known issue in all sanitizers (not just LSan).
Secondly, as of now there's no API to detect that LeakSanitizer is enabled at runtime so your best bet is to manually check that program is linked against Lsan and detect_leaks=0 isn't set in environment:
void (*__lsan_is_turned_off)() = dlsym(RTLD_DEFAULT, "__lsan_is_turned_off");
const char *lsan_opts = getenv("LSAN_OPTIONS");
const char *asan_opts = getenv("ASAN_OPTIONS");
int disable_dlclose = __lsan_is_turned_off != 0 && !__lsan_is_turned_off()
&& !(lsan_opts && (strstr(lsan_opts, "detect_leaks=0") || strstr(lsan_opts, "detect_leaks=false"))
&& !(asan_opts && (strstr(asan_opts, "detect_leaks=0") || strstr(asan_opts, "detect_leaks=false"));
(__lsan_is_turned_off is defined in sanitizer/lsan_interface.h).
If you enable LSan via -fsanitize=address, you can replace __lsan_is_turned_off check with #ifdef __SANITIZE_ADDRESS__.
I am trying to write my own wrapper function to libhiredis to use in my project but when i try to pass the redis_context into another function to issue commands from there. The code segfaults and reports this through gdb:
GDB Error:
Program received signal SIGSEGV, Segmentation fault.
sdscatlen (s=0x0, t=0x555555757690, len=22) at sds.c:239
239 sds.c: No such file or directory.
(gdb) backtrace
#0 sdscatlen (s=0x0, t=0x555555757690, len=22) at sds.c:239
#1 0x00007ffff7bcd300 in __redisAppendCommand (c=0x7fffffffddd0, cmd=<optimized out>, len=<optimized out>) at hiredis.c:910
#2 0x00007ffff7bcd38c in redisvAppendCommand (c=0x7fffffffddd0, format=<optimized out>, ap=<optimized out>) at hiredis.c:942
#3 0x00007ffff7bcd579 in redisvCommand (c=0x7fffffffddd0, format=<optimized out>, ap=ap#entry=0x7fffffffdcc0) at hiredis.c:1003
#4 0x00007ffff7bcd634 in redisCommand (c=<optimized out>, format=<optimized out>) at hiredis.c:1012
#5 0x0000555555554b9e in getnow (redis_context=0x7fffffffddd0) at src/testRedis.c:18
#6 0x0000555555554c14 in main () at src/testRedis.c:49
Here is the code:
RedisWrapper.h:
#ifndef REDIS_WRAPPER_H
#define REDIS_WRAPPER_H
int redis_wrapper_init(redisContext *redis_context, char *ip, int port);
int redis_wrapper_set(redisContext *redis_context, char *key, char *value);
int redis_wrapper_get(redisContext *redis_context, char *key, char *retrieved_value);
#endif
RedisWrapper.c:
#include <hiredis.h>
int redis_wrapper_init(redisContext *redis_context, char* ip, int port) {
redis_context = redisConnect(ip, port);
if (redis_context == NULL || redis_context->err) {
if (redis_context) {
fprintf(stderr, "cget: redis init error: %s\n", redis_context->errstr);
} else {
fprintf(stderr, "cget: can't allocate redis context\n");
}
return 1;
}
return 0;
}
int redis_wrapper_set(redisContext *redis_context, char *key, char *value) {
redisReply *reply = redisCommand(redis_context, "SET %s %s", key, value);
if(reply == NULL) {
fprintf(stderr, "cget: redis set error key: %s, val: %s\n", key, value);
fprintf(stderr, "cget: redis set error: %s\n", redis_context->errstr);
return 1;
}
freeReplyObject(reply);
return 0;
}
int redis_wrapper_get(redisContext *redis_context, char *key, char *retrieved_value) {
redisReply *reply = redisCommand(redis_context, "GET foo");
if(reply == NULL) {
fprintf(stderr, "cget: redis get error key: %s\n", key);
fprintf(stderr, "cget: redis get error: %s\n", redis_context->errstr);
return 1;
}
printf("GET: %s\n", reply->str);
retrieved_value = reply->str;
freeReplyObject(reply);
return 0;
}
Main.c
#include <stdio.h>
#include <string.h>
#include <hiredis.h>
#include "RedisWrapper.h"
void getnow(redisContext *redis_context) {
redisReply *reply = redisCommand(redis_context, "GET foo");
printf("GET foo: %s\n", reply->str);
freeReplyObject(reply);
}
int main() {
redisContext *redis_context;
redis_wrapper_init(redis_context, "127.0.0.1", 6379);
getnow(redis_context);
return 0;
}
My compile command:
gcc -Wall -g -o src/redisTest src/RedisWrapper.c `pkg-config --cflags hiredis` src/Main.c `pkg-config --libs hiredis`
More Details:
# uname -a
Linux node1 4.13.0-21-generic #24-Ubuntu SMP Mon Dec 17 17:29:16 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux
# locate libhiredis
/usr/lib/x86_64-linux-gnu/libhiredis.a
/usr/lib/x86_64-linux-gnu/libhiredis.so
/usr/lib/x86_64-linux-gnu/libhiredis.so.0.13
/usr/share/doc/libhiredis-dbg
/usr/share/doc/libhiredis-dev
/usr/share/doc/libhiredis0.13
/usr/share/doc/libhiredis-dbg/changelog.Debian.gz
/usr/share/doc/libhiredis-dbg/copyright
/usr/share/doc/libhiredis-dev/README.md.gz
/usr/share/doc/libhiredis-dev/changelog.Debian.gz
/usr/share/doc/libhiredis-dev/copyright
/usr/share/doc/libhiredis0.13/changelog.Debian.gz
/usr/share/doc/libhiredis0.13/copyright
/var/cache/apt/archives/libhiredis-dbg_0.13.3-2_amd64.deb
/var/cache/apt/archives/libhiredis0.13_0.13.3-2_amd64.deb
/var/lib/dpkg/info/libhiredis-dbg:amd64.list
/var/lib/dpkg/info/libhiredis-dbg:amd64.md5sums
/var/lib/dpkg/info/libhiredis-dev:amd64.list
/var/lib/dpkg/info/libhiredis-dev:amd64.md5sums
/var/lib/dpkg/info/libhiredis0.13:amd64.list
/var/lib/dpkg/info/libhiredis0.13:amd64.md5sums
/var/lib/dpkg/info/libhiredis0.13:amd64.shlibs
/var/lib/dpkg/info/libhiredis0.13:amd64.symbols
/var/lib/dpkg/info/libhiredis0.13:amd64.triggers
What i found strange is that if i do all the operations all in the Main.c and not use the wrapper files it works. That is not useful to my project though, i need to be able to pass the redis_context around and have it work.
redis_context in redis_wrapper_init should be passed by reference (in C by pointer) to keep result of assignment redis_context = redisConnect(ip, port); after calling this function. Without this, you assign pointer returned by redisConnect to local variable, which is destroyed when function returns.
So definition should be
int redis_wrapper_init(redisContext ** redis_context, char* ip, int port) {
*redis_context = redisConnect(ip, port);
if (*redis_context == NULL || (*redis_context)->err) {
if (*redis_context) {
fprintf(stderr, "cget: redis init error: %s\n", (*redis_context)->errstr);
}
...
}
}
in main you get address of redis_context variable and pass it to redis_wrapper_init
redisContext *redis_context = 0;
redis_wrapper_init(&redis_context, "127.0.0.1", 6379);
when calling a ONC-RPC-function that returns a char array I get (apparently) uninitialized memory on the first call. Subsequent calls give me the correct result.
This example showcases the issue:
ftp.x:
const BLOCKSIZE = 1024;
struct block {
char arr<BLOCKSIZE>;
};
program FILE_GET_BLOCK_PROG {
version FILE_GET_BLOCK_VERS {
block FILE_GET_BLOCK() = 1;
} = 1;
} = 0x42424243;
ftp_client.c:
#include "ftp.h"
#include <errno.h>
#include <string.h>
size_t
file_get_block_prog_1(char *host, char *buf)
{
CLIENT *clnt;
block *result_1;
#ifndef DEBUG
clnt = clnt_create (host, FILE_GET_BLOCK_PROG, FILE_GET_BLOCK_VERS, "udp");
if (clnt == NULL) {
clnt_pcreateerror (host);
exit (1);
}
#endif /* DEBUG */
result_1 = file_get_block_1(NULL, clnt);
if (result_1 == (block *) NULL) {
clnt_perror (clnt, "call failed");
}
#ifndef DEBUG
clnt_destroy (clnt);
#endif /* DEBUG */
memcpy(buf, result_1->arr.arr_val, result_1->arr.arr_len);
return result_1->arr.arr_len;
}
int
main (int argc, char *argv[])
{
char *host, *source_filename;
char buf[BLOCKSIZE+1];
int block_count;
size_t bytes_read;
if (argc < 2) {
printf ("usage: %s server_host\n", argv[0]);
exit (1);
}
host = argv[1];
bytes_read = file_get_block_prog_1 (host, buf);
buf[bytes_read] = '\0';
printf("%d bytes:\n%s\n", bytes_read, buf);
exit (0);
}
ftp_server.c:
#include "ftp.h"
#include <errno.h>
#include <string.h>
#include <sys/stat.h>
block *
file_get_block_1_svc(void *argp, struct svc_req *rqstp)
{
static block result;
static int request = 1;
char buf[BLOCKSIZE+1];
size_t bytes_read;
strcpy(buf, "This is just a simple test block. There is nothing relevant in here.");
result.arr.arr_len = strlen(buf);
result.arr.arr_val = buf;
printf("Request #%d:\n%s\n", request++, buf);
return &result;
}
When running the server and calling the client twice, this is my output:
client:
$ ./ftp_client localhost
68 bytes:
$ ./ftp_client localhost
68 bytes:
This is just a simple test bock. There is nothing relevant in here.
server:
Request #1:
This is just a simple test bock. There is nothing relevant in here.
Request #2:
This is just a simple test bock. There is nothing relevant in here.
Is there any initialization I missed that I need to do before the first request? What else would cause this behavior?
I'm trying to develop a simple echo client using unix pipes for the following example code: https://github.com/nikhilm/uvbook/blob/master/code/pipe-echo-server/main.c
this is my client code:
#include <uv.h>
#include <stdio.h>
#include <stdlib.h>
void OnConnect(uv_connect_t* connect, int status){
printf("Hi!");
}
int main(){
uv_pipe_t* handle = (uv_pipe_t*)malloc(sizeof(uv_pipe_t));
uv_connect_t* connect = (uv_connect_t*)malloc(sizeof(uv_connect_t));
uv_pipe_open(handle, socket(PF_UNIX, SOCK_STREAM, 0));
int r;
uv_pipe_connect(connect, handle, "echo.sock", OnConnect);
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
}
But as soon as I run it, it segfaults. The server does give me a message that a process has connected. A backtrace from GDB:
Program received signal SIGSEGV, Segmentation fault.
uv__io_start (loop=0x0, w=w#entry=0x602098, events=events#entry=5)
at src/unix/core.c:787
787 src/unix/core.c: No such file or directory.
(gdb) backtrace full
#0 uv__io_start (loop=0x0, w=w#entry=0x602098, events=events#entry=5)
at src/unix/core.c:787
__PRETTY_FUNCTION__ = "uv__io_start"
#1 0x00007ffff7bc7ed8 in uv_pipe_connect (req=0x602120, handle=0x602010,
name=<optimized out>, cb=0x400870 <OnConnect>) at src/unix/pipe.c:188
saddr = {sun_family = 1,
sun_path = "echo.sock", '\000' <repeats 98 times>}
new_sock = 0
---Type <return> to continue, or q <return> to quit---
err = <optimized out>
r = <optimized out>
#2 0x0000000000400918 in main () at client.c:16
handle = 0x602010
connect = 0x602120
r = 0
You need to initialize the pipe handle before you are allowed to use it.
Add this line before uv_pipe_open:
uv_pipe_init(uv_default_loop(), handle, 0);
Also, casting the result of malloc is unnecessary.
We must also use valid pipe names. eg:
#ifdef _WIN32
# define PIPENAME "\\\\?\\pipe\\some.name"
#elif defined(__android__)
# define PIPENAME "/data/local/tmp/some.name"
#else
# define PIPENAME "/tmp/some.name"
#endif
The libuv tests use this same approach
Working example:
#include <uv.h>
#include <stdio.h>
#include <stdlib.h>
#ifdef _WIN32
# define PIPENAME "\\\\?\\pipe\\echo.sock"
#else
# define PIPENAME "echo.sock"
#endif
typedef struct {
uv_write_t req;
uv_buf_t buf;
} write_req_t;
void free_write_req(uv_write_t *req) {
write_req_t *wr = (write_req_t*) req;
free(wr->buf.base);
free(wr);
}
void on_write(uv_write_t *req, int status) {
if (status < 0) {
fprintf(stderr, "write error %s\n", uv_err_name(status));
} else {
puts("done.");
}
free_write_req(req);
}
void on_connect(uv_connect_t* connect, int status){
if (status < 0) {
puts("failed!");
} else {
puts("connected! sending msg...");
write_req_t *req = (write_req_t*) malloc(sizeof(write_req_t));
req->buf = uv_buf_init("Hello World!", 13);
uv_write((uv_write_t*) req, connect->handle, &req->buf, 1, on_write);
}
}
int main(){
uv_loop_t *loop = uv_default_loop();
uv_pipe_t* handle = (uv_pipe_t*)malloc(sizeof(uv_pipe_t));
uv_connect_t* connect = (uv_connect_t*)malloc(sizeof(uv_connect_t));
uv_pipe_init(loop, handle, 0);
uv_pipe_connect(connect, handle, PIPENAME, on_connect);
uv_run(loop, UV_RUN_DEFAULT);
}