bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Heap corruption in putenv (Was: JIT crash on simple while-loop [MSVC])


From: Michael Goffioul
Subject: Heap corruption in putenv (Was: JIT crash on simple while-loop [MSVC])
Date: Wed, 13 Feb 2013 21:54:16 -0500

On Wed, Feb 13, 2013 at 12:35 PM, Michael Goffioul <address@hidden> wrote:


On Tue, Feb 12, 2013 at 11:34 PM, Max Brister <address@hidden> wrote:
On Mon, Feb 11, 2013 at 7:47 PM, Michael Goffioul
<address@hidden> wrote:
> Hi Max,
>
> Today I recompiled the default branch with MSVC, and although the full test
> suite runs fine, I still get a crash on a very simple for loop. I ran octave
> with --jit-debug and types the following commands:
>
> rot_z = -150;
> while (rot_z < 0), rot_z += 360; endwhile
>
> Then the output was the following (with a crash at the end). I can't produce
> a backtrace at the moment as this version was compiled with optimization
> enabled. I'll try to recompile with debug enabled and reproduce the crash.
> But in the meantime, maybe this will give you a hint (I doubt it, but you
> never know...).
>
> Michael.
>
> -------------------- Compiling tree --------------------
> while (rot_z < 0)
>   rot_z += 360;
> endwhile
> -------------------- octave jit ir --------------------
> body0:        %pred =
>         scalar: rot_z#1 = extract rot_z
>         branch: [live] while_cond_check1
> while_cond_check1:        %pred = body0, interrupt_check6
>         scalar: rot_z#17 phi | body0 -> scalar: rot_z#1
>                              | interrupt_check6 -> scalar: rot_z#11
>         scalar: #2 = call  (scalar: rot_z#17)
>         bool: #3 = call binary< (scalar: #2, scalar: 0)
>         branch: [live] while_cond_check2
> while_cond_check2:        %pred = while_cond_check1
>         bool: #5 = call logically_true (bool: #3)
>         branch: [live] while_cond_check3
> while_cond_check3:        %pred = while_cond_check2
>         cond_branch: bool: #5, [live] while_body4, [live] while_tail7
> while_body4:        %pred = while_cond_check3
>         scalar: #8 = call  (scalar: rot_z#17)
>         scalar: #9 = call binary+ (scalar: #8, scalar: 360)
>         branch: [live] while_body5
> while_body5:        %pred = while_body4
>         scalar: rot_z#11 = scalar: #9
>         branch: [live] interrupt_check6
> interrupt_check6:        %pred = while_body5
>         error_check interrupt, <normal> [live] while_cond_check1, <error>
> [live] final8
> while_tail7:        %pred = while_cond_check3
>         branch: [live] final8
> final8:        %pred = interrupt_check6, while_tail7
>         scalar: rot_z#18 phi | interrupt_check6 -> scalar: rot_z#11
>                              | while_tail7 -> scalar: rot_z#17
>         store rot_z = scalar: rot_z#18
>         return
>
> -------------------- llvm ir --------------------
> define void @foobar(%octave_base_value**) {
> prelude:
>   %1 = getelementptr inbounds %octave_base_value** %0, i32 0
>   br label %body
>
> body:                                             ; preds = %prelude
>   %2 = load %octave_base_value** %1
>   %3 = call double @octave_jit_cast_scalar_any(%octave_base_value* %2)
>   br label %while_cond_check
>
> while_cond_check:                                 ; preds =
> %interrupt_check, %body
>   %4 = phi double [ %3, %body ], [ %9, %interrupt_check ]
>   %5 = call double @id_scalar(double %4)
>   %6 = call i1 @"octave_jit<_scalar"(double %5, double 0.000000e+00)
>   br label %while_cond_check1
>
> while_cond_check1:                                ; preds =
> %while_cond_check
>   %7 = call i1 @id_bool(i1 %6)
>   br label %while_cond_check2
>
> while_cond_check2:                                ; preds =
> %while_cond_check1
>   br i1 %7, label %while_body, label %while_tail
>
> while_body:                                       ; preds =
> %while_cond_check2
>   %8 = call double @id_scalar(double %4)
>   %9 = call double @"octave_jit_+_scalar"(double %8, double 3.600000e+02)
>   br label %while_body3
>
> while_body3:                                      ; preds = %while_body
>   br label %interrupt_check
>
> interrupt_check:                                  ; preds = %while_body3
>   %10 = load volatile i32* @octave_interrupt_state
>   %11 = icmp sgt i32 %10, 0
>   br i1 %11, label %final, label %while_cond_check
>
> while_tail:                                       ; preds =
> %while_cond_check2
>   br label %final
>
> final:                                            ; preds = %while_tail,
> %interrupt_check
>   %12 = phi double [ %9, %interrupt_check ], [ %4, %while_tail ]
>   %13 = call %octave_base_value* @octave_jit_cast_any_scalar(double %12)
>   store %octave_base_value* %13, %octave_base_value** %1
>   ret void
> }
>
> -------------------- optimized llvm ir --------------------
>
> define void @foobar(%octave_base_value**) {
> prelude:
>   %1 = load %octave_base_value** %0, align 4
>   %2 = call double @octave_jit_cast_scalar_any(%octave_base_value* %1)
>   br label %while_cond_check
>
> while_cond_check:                                 ; preds = %while_body,
> %prelude
>   %3 = phi double [ %2, %prelude ], [ %5, %while_body ]
>   %4 = fcmp ult double %3, 0.000000e+00
>   br i1 %4, label %while_body, label %final
>
> while_body:                                       ; preds =
> %while_cond_check
>   %5 = fadd double %3, 3.600000e+02
>   %6 = load volatile i32* @octave_interrupt_state, align 4
>   %7 = icmp sgt i32 %6, 0
>   br i1 %7, label %final, label %while_cond_check
>
> final:                                            ; preds =
> %while_cond_check, %while_body
>   %8 = phi double [ %5, %while_body ], [ %3, %while_cond_check ]
>   %9 = call %octave_base_value* @octave_jit_cast_any_scalar(double %8)
>   store %octave_base_value* %9, %octave_base_value** %0, align 4
>   ret void
> }
>
> panic: Segmentation violation -- stopping myself...
> attempting to save variables to 'octave-workspace'...
> save to 'octave-workspace' complete
>

A stack trace would be helpful, I can't reproduce the problem on the
default branch (119ce9f5e1a3) in linux with llvm 3.2.

I've attached 2 backtrace's. Although I don't think it'll help that much, as it seems the crash occurs at different place, depending on what has been executed in octave. In the first case, I use the stock octaverc file and execute:

putenv("GNUTERM", "wxt")
rot_z = -150;
while (rot_z < 0), rot_z += 360; endwhile

While in the second, I use my custom octaverc file (attached) and only execute the last 2 lines of the snippet above. Long story short, I suspect a stack corruption somewhere.

I've debugged the problem further and it appears the problem might not be the JIT at all, but gnulib's putenv. I've used the MS appverifier tool and it detected a heap corruption in gnulib's putenv (re)implementation.

As far as I can see, the way it works when defining a new environment variable is:
1) allocate a new char**, large enough to contain the current environment + 1
2) copy the current environment in the newly allocated array
3) assign the new array to the POSIX "environ" variable
4) keep track of the newly created array into a static variable such that it can be free'ed on the next envvar addition

And the problem lies in this last bit, if you link this code with some 3rd party code that calls the native CRT putenv implementation. The native putenv implementation will do a realloc of the array created in 1), effectively trashing it. On the next gnulib's putenv call, at step 4), it will try to free the static pointer (stored during the previous gnulib's putenv call), but that memory already has been de-allocated by the native putenv call.

In practice in my case, octave first calls gnulib::putenv to add OCTAVE_HOME, then my readline DLL calls crt::putenv to add LINES and COLUMNS, then octave calls again gnulib::putenv to add GNUTERM. And boom, it can crash on any further heap allocation.

Does the scenario above make sense? And what would be the correct fix?

Thanks,
Michael.


reply via email to

[Prev in Thread] Current Thread [Next in Thread]