cURL / Mailing Lists / curl-library / Single Mail

curl-library

Access violation in dprintf_formatf (on 100% progress?)

From: Thorsten Schöning <tschoening_at_am-soft.de>
Date: Sat, 26 Sep 2015 10:50:46 +0200

Hi all,

yesterday I built my first own version of cURL using a somewhat recent
7.44.0 using projects for the IDE Embarcadero C++ Builder 10 Seattle
targeting 32 Bit Windows applications. I've created two projects, one
for libcurl, one for curl.exe and my libcurl setup is to create a
static lib. In the end both built fine, so I ested a bit using
curl.exe and recognized an access violation in certain situations.

The problem only occurs if I call curl.exe in a mode in which it
prints progress output on STDERR, like in the following calls on the
shell:

> curl.exe http://www.example.org > test.html
> curl.exe -o test.html http://www.example.org

If no output redirection is used and curl prints HTML on STDOUT,
everything works and the application doesn't crash. The interesting
part is that even WITH output redirection and if progress is printed
on STDERR, curl successfully retrieves all of the data to download and
only crashes sometimes afterwards.

My IDE provides a debugging helper called CodeGuard which can be
enabled to replace some memory related functions with itself and check
for access violations. After activation, rebuilding and running
curl.exe, it provided me the following line as the source of the
problem:

> static int dprintf_formatf(
[...]
> case FORMAT_STRING:
[...]
> else
> len = strlen(str);

When the access violation occurs, the pointer str ALWAYS points to
address 0x64, no exceptions so far, and is invalid, especially it is
not NULL of course, but its value is not 0 to be an empty string as
well. What I find interesting is that 0x64 is 100 decimal, which seems
to be the value of the current progress and would fit to the fact,
that the HTML is saved successfully and completely before the access
violation occurs and some progress is output as well.

After applying the following little patch and checking for the
problematic state the access violation is gone:

> Index: mprintf.c
> ===================================================================
> --- mprintf.c (Revision 4088)
> +++ mprintf.c (Arbeitskopie)
> @@ -791,7 +791,12 @@
> size_t len;
>
> str = (char *) p->data.str;
> - if(str == NULL) {
> + if ((p->data.num.as_unsigned == 100) &&
> + (str == 100))
> + {
> + str = NULL;
> + }
> + if(str == NULL) {
> /* Write null[] if there's space. */
> if(prec == -1 || prec >= (long) sizeof(null) - 1) {
> str = null;

Obviously this is a only a workaround and the real problem is the
wrong pointer for str, but I don't understand enough about how the
caller works and such and I really doubt that I'm the first one
recognizing such a problem, which is reproducible to me.

So, do you have any idea on what might cause that problem? Thanks!

The following is the stack trace:

> :0cd16b09 ; C:\Program Files (x86)\Embarcadero\Studio\17.0\bin\CG32.DLL
> :0cd16dae ; C:\Program Files (x86)\Embarcadero\Studio\17.0\bin\CG32.DLL
> :0cd16604 ; C:\Program Files (x86)\Embarcadero\Studio\17.0\bin\CG32.DLL
> :0cd180e9 ; C:\Program Files (x86)\Embarcadero\Studio\17.0\bin\CG32.DLL
> :0cd142b4 ; C:\Program Files (x86)\Embarcadero\Studio\17.0\bin\CG32.DLL
> :0cd142f6 CG32._CG_VALIDATESTRING + 0x2a
> :0cd0474f CG32.__cg_strlen + 0x43
> :0047d799 strlen(const signed char *) + 0xD
> :004BC58A dprintf_formatf(data=:006DB768, stream=:0047DB88, format=:00686087, ap_save=:0018F814)
> :004BCCF5 curl_mfprintf(whereto=:006DB768, format=:00686087, ap_save=:0018F814)
> :004C74B9 Curl_pgrsUpdate(conn=:022A20D0)
> :004C6724 Curl_pgrsDone(conn=:022A20D0)
> :004E2204 Curl_done(connp=:022DF138, status=0 /* CURLE_OK */, premature=0 /* bool_false */)
> :004BF9CA multi_runsingle(multi=:022C9890, now={ 306284, 890000 }, data=:022DF130)
> :004BFC93 curl_multi_perform(multi_handle=:022C9890, running_handles=:0018FAA0)
> :0049E720 easy_transfer(multi=:022C9890)
> :0049E86E easy_perform(data=:022DF130, events=0 /* bool_false */)
> :0049E894 curl_easy_perform(easy=:022DF130)
> :004558D6 operate_do(global=:0018FEFC, config=:02333D60)
> :00456740 operate(config=:0018FEFC, argc=4, argv=:0235A680)
> :00447036 main(argc=4, argv=:0235A680)
> :0064a9ca ; __startup

Memory of "p" where str comes from, which is the same as "vto[3]":

> Name Wert
> p :0018EBD0
> type 1 /* FORMAT_STRING */
> flags 0 (0x00000000)
> width 0L (0x00000000)
> precision 0L (0x00000000)
> data { "", :00000064, { 100, 100 }, 4.94065645841247E-322 }
> str :00000064 ""
> [0] ????
> ptr :00000064
> num { 100, 100 }
> as_signed 100L (0x00000064)
> as_unsigned 100UL (0x00000064)
> dnum 4.94065645841247E-322

Memory of Curl_pgrsUpdate higher in the stack, which shows 100% progress:

> Name Wert
> now { 306284, 890000 }
> result 214968049 (0x0CD026F1)
> max5 { "13970\0\n\0\0\0", " 0\0Dû\x18\0", "13970\0\0\0Øø", "21295\0¼ø\x18\0", " 0\0\0\0’6", "74705\0€\x02\n\0"}
> dlpercen 100 (0x64)
> ulpercen 0 (0x0)
> total_percen 100 (0x64)
> total_transfer 13970 (0x3692)
> total_expected_transfer 13970 (0x3692)
> timespent 0 (0x0)
> data :022DF130
> nowindex 1 (0x00000001)
> checkindex 0 (0x00000000)
> countindex 1 (0x00000001)
> time_left "--:--:--\0\x1D"
> time_total "--:--:--\0Ý"
> time_spent "--:--:--\0\0"
> ulestimate 0 (0x0)
> dlestimate 0 (0x0)
> total_estimate 0 (0x0)
> shownow 1 /* bool_true */
> conn :022A20D0

Mit freundlichen Grüßen,

Thorsten Schöning

-- 
Thorsten Schöning       E-Mail: Thorsten.Schoening_at_AM-SoFT.de
AM-SoFT IT-Systeme      http://www.AM-SoFT.de/
Telefon...........05151-  9468- 55
Fax...............05151-  9468- 88
Mobil..............0178-8 9468- 04
AM-SoFT GmbH IT-Systeme, Brandenburger Str. 7c, 31789 Hameln
AG Hannover HRB 207 694 - Geschäftsführer: Andreas Muchow
-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette:  http://curl.haxx.se/mail/etiquette.html
Received on 2015-09-26