Page 1 of 2

curl_easy_setopt fails on 64 bit CentOS 6

Posted: Fri Sep 13, 2013 11:21 am
by mariosk8s
The following code segfaults on 64 bit CentOS 6 running libcurl-7.19

It runs fine on 64 bit Ubuntu 11.10 with libcurl-7.21 and 32 bit Linux Ubuntu or CentOS 6, Mac and Windows.

footest.pb

Code: Select all

#CURLOPT_URL                  = 10002

Global CURL_LIBRARYID = 0
PrototypeC curl_easy_init()
PrototypeC curl_easy_setopt(handle.i, curlOpt, *value)
PrototypeC curl_easy_perform(handle.i)
PrototypeC curl_easy_cleanup(handle.i)

Global curl_easy_init.curl_easy_init
Global curl_easy_setopt.curl_easy_setopt
Global curl_easy_perform.curl_easy_perform
Global curl_easy_cleanup.curl_easy_cleanup

Procedure loadCurl()
  CURL_LIBRARYID = OpenLibrary(#PB_Any,  "libcurl.so.4")
  If CURL_LIBRARYID = 0
    ProcedureReturn #False
  EndIf
  
  curl_easy_init      = GetFunction(CURL_LIBRARYID, "curl_easy_init")
  curl_easy_setopt    = GetFunction(CURL_LIBRARYID, "curl_easy_setopt")
  curl_easy_perform   = GetFunction(CURL_LIBRARYID, "curl_easy_perform")
  curl_easy_cleanup   = GetFunction(CURL_LIBRARYID, "curl_easy_cleanup")

  ProcedureReturn #True
EndProcedure

If loadCurl()
  Define curl_Handle.i = curl_easy_init()
  Define stringValue.s =  "http://google.com"
  curl_easy_setopt(curl_Handle.i, #CURLOPT_URL, @stringValue.s)
  curl_easy_perform(curl_Handle)
  curl_easy_cleanup(curl_Handle)
EndIf
It seems it's set setopt call that knocks the stack to smitherines. The interface for setopt is

Code: Select all

CURLcode curl_easy_setopt(CURL *curl, CURLoption tag, ...)
It's not clear to me why this happens or how to work around this.

Re: curl_easy_setopt fails on 64 bit CentOS 6

Posted: Fri Sep 13, 2013 1:17 pm
by Fred
You can't call such variable argument functions in PB directly, you will need a wrapper.

Re: curl_easy_setopt fails on 64 bit CentOS 6

Posted: Fri Sep 13, 2013 1:33 pm
by mariosk8s
Then why is this working everywhere else? Luck?

Re: curl_easy_setopt fails on 64 bit CentOS 6

Posted: Fri Sep 13, 2013 1:41 pm
by Fred
Yes, just luck. PB doesn't support this notation, so args are arbitrary pushed on the stacks on x86 and using regs on x64, but the interpretation depends of the type. Better write a small wrapper in C to handle that.

Re: curl_easy_setopt fails on 64 bit CentOS 6

Posted: Fri Sep 13, 2013 2:02 pm
by mariosk8s
Thanks for the insight, Fred.

I already did.

Here's what i did for others, who fall into this trap, to read.

The c wrapper rfsetopt.c

Code: Select all

#include <curl/curl.h>

#if defined(WIN32) || defined(_WIN32)
# define API  __declspec(dllexport)
#else
# define API
#endif

#ifdef  __cplusplus
extern "C" {
#endif


API CURLcode
rf_curl_easy_setopt(CURL *curl, CURLoption tag, void* value) {
    return curl_easy_setopt(curl, tag, value);
}

#ifdef  __cplusplus
} /* extern "C" */
#endif

This puppy works.

Then i build it

Code: Select all

gcc -c rfsetopt.c -o rfsetopt.o -fPIC
Then here the updated footest.pb

Code: Select all

#CURLOPT_URL                  = 10002

Global CURL_LIBRARYID = 0
PrototypeC curl_easy_init()
PrototypeC curl_easy_perform(handle.i)
PrototypeC curl_easy_cleanup(handle.i)

Global curl_easy_init.curl_easy_init
Global curl_easy_perform.curl_easy_perform
Global curl_easy_cleanup.curl_easy_cleanup

ImportC "-lcurl" : EndImport
ImportC "rfsetopt.o"
  curl_easy_setopt.i(handle.i, curlOpt, *value) As "rf_curl_easy_setopt"
EndImport

Procedure loadCurl()
  CURL_LIBRARYID = OpenLibrary(#PB_Any,  "libcurl.so.4")
  If CURL_LIBRARYID = 0
    ProcedureReturn #False
  EndIf
  
  curl_easy_init      = GetFunction(CURL_LIBRARYID, "curl_easy_init")
  curl_easy_perform   = GetFunction(CURL_LIBRARYID, "curl_easy_perform")
  curl_easy_cleanup   = GetFunction(CURL_LIBRARYID, "curl_easy_cleanup")

  ProcedureReturn #True
EndProcedure

If loadCurl()
  Define curl_Handle.i = curl_easy_init()
  
  Define stringValue.s =  "http://google.com"
  curl_easy_setopt(curl_Handle.i, #CURLOPT_URL, @stringValue.s)
  curl_easy_perform(curl_Handle)
  curl_easy_cleanup(curl_Handle)
EndIf

Re: curl_easy_setopt fails on 64 bit CentOS 6

Posted: Fri Sep 13, 2013 2:15 pm
by Fred
Just perfect.

Re: curl_easy_setopt fails on 64 bit CentOS 6

Posted: Fri Sep 13, 2013 3:58 pm
by mariosk8s
Now i only need the windows version of

Code: Select all

ImportC "-lcurl" : EndImport

Re: curl_easy_setopt fails on 64 bit CentOS 6

Posted: Fri Sep 13, 2013 11:25 pm
by idle
when you import varargs functions, can't you just add a null to the import ?

CURLcode curl_easy_setopt(CURL *curl, CURLoption tag, ...)

PrototypeC curl_easy_setopt1(*curl,tag,void=0)
PrototypeC curl_easy_setopt2(*curl,tag,tag1,void=0)

Re: curl_easy_setopt fails on 64 bit CentOS 6

Posted: Sat Sep 14, 2013 9:17 am
by Fred
The problem is it won't work for all scenarios:

for example printf in C:

Code: Select all

printf("%f", 10.0f)
The first arg is a double, and then should be loaded in a double register in x64

now in PB:

Code: Select all

PrototypeC printf(format,arg,void=0) 

printf("%f", 10.0)
Your arg will still be an integer and the call will fail. So you would need a prototype for any combinations of your format string to have this work. That said, it could work if you just need to pass integer var args.

Re: curl_easy_setopt fails on 64 bit CentOS 6

Posted: Mon Sep 16, 2013 7:37 am
by mariosk8s
Those are great tips. I'll use those on Windows for now as still don't know how to get linking to work.

Code: Select all

ImportC "/DEFAULTLIB:" + "c:/path/to/libcurl.dll" : EndImport
Fails :cry:

Re: curl_easy_setopt fails on 64 bit CentOS 6

Posted: Mon Sep 16, 2013 7:43 am
by mariosk8s
Oh, yeah, let me define "Fails".

Code: Select all

Error: Linker
POLINK: warning: No subsystem specified; assuming CONSOLE.
POLINK: fatal error: Corrupt library: 'c:/path/to/libcurl.dll'.

Re: curl_easy_setopt fails on 64 bit CentOS 6

Posted: Mon Sep 16, 2013 7:49 am
by sec
.o is for object
.lib is for windows?

Re: curl_easy_setopt fails on 64 bit CentOS 6

Posted: Mon Sep 16, 2013 8:02 am
by idle
you can only use Import on a lib, if you don't have a lib for the dll you can make one with polib
from pellesC, can't remember the command for it, something like >Polib foo.dll /OUT:foo.lib

Re: curl_easy_setopt fails on 64 bit CentOS 6

Posted: Mon Sep 16, 2013 2:22 pm
by mariosk8s
@sec Yeah, just the object file worked for posix.

@idle thanks for that tip. So ran

Code: Select all

polib.exe libcurl.dll /OUT:libcurl.lib
Then i updated the c wrapper to include the cdecl stuff.

The trying to link gives me:

Code: Select all

polink.exe -DLL rfsetopt.o -OUT:rfsetopt.dll -DEFAULTLIB:/path/to/libcurl.lib
POLINK: error: Unresolved external symbol '_curl_easy_setopt'.
POLINK: error: Unresolved external symbol '___DllMainCRTStartup@12'.
POLINK: fatal error: 2 unresolved external(s).
I'm not sure about the polink call being correct as google is completely void of polink examples in this regard.

Re: curl_easy_setopt fails on 64 bit CentOS 6

Posted: Mon Sep 16, 2013 3:19 pm
by Shardik
You shouldn't need to generate a libcurl.lib for Linux. Just install the developer version of libcurl (tested on Kubuntu 12.04 LTS x86) and import libcurl with

Code: Select all

ImportC "-lcurl"
...
EndImport
http://www.purebasic.fr/english/viewtop ... 4&start=11