Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Infinite loop and stack smash in ecma_errol0_dtoa #3724

Closed
anonpoet opened this issue May 7, 2020 · 3 comments
Closed

Infinite loop and stack smash in ecma_errol0_dtoa #3724

anonpoet opened this issue May 7, 2020 · 3 comments

Comments

@anonpoet
Copy link

anonpoet commented May 7, 2020

I've got a bug that only shows up when cross compiling for a raspberry pi target. The code base was cloned from github in October 2019. Unfortunately, the git information wasn't preserved when it was cloned. It looks like the relevant functions haven't changed since then. I'm not terribly familiar with the jerryscript code base so if someone could weigh in and help debug, that would be great.

On the raspberry pi target, I'm getting a stack smash in ecma_errol0_dtoa()
. The backtraces and whatnot are shown below. It appears that in ecma_errol0_dtoa() iterates around the loop "while (high_bound.value != 0.0 || high_bound.offset != 0.0)" adding 0x30 to the buffer until it walks up the stack and clobbers something that causes the crash.

The maddening thing is that this bug only shows up on the raspberry pi builds and only triggers every few builds. The X64 and ESP8266 targets never have the same crash.

r0 0x0 0
r1 0x0 0
r2 0x75dcf000 1977413632
r3 0x30 48
r4 0x0 0
r5 0x0 0
r6 0x0 0
r7 0xfff80000 4294443008
r8 0x7efff532 2130703666
r9 0x1 1
r10 0x1000 4096
r11 0x75dcde64 1977409124
r12 0x80000000 2147483648
sp 0x75dcda20 0x75dcda20
lr 0x37fa0 229280
pc 0x24c04 0x24c04 <ecma_errol0_dtoa+1472>
cpsr 0x30 48

Thread 4 "main.bad" received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x75dce470 (LWP 18880)]
0x00024c04 in ecma_errol0_dtoa ()
(gdb) bt
#0 0x00024c04 in ecma_errol0_dtoa ()
#1 0x000244f0 in ecma_number_to_utf8_string ()
#2 0x000255a8 in ecma_new_ecma_string_from_number ()
#3 0x30303030 in ?? (). <---smashed obviously :(
Backtrace stopped: previous frame identical to this frame (corrupt stack?)
(gdb)

(gdb) x/10i $pc
=> 0x24c04 <ecma_errol0_dtoa+1472>: strb r3, [r2, #0]
0x24c06 <ecma_errol0_dtoa+1474>: movs r0, r4
0x24c08 <ecma_errol0_dtoa+1476>: bl 0x38394 <____aeabi_i2d_from_thumb>
0x24c0c <ecma_errol0_dtoa+1480>: movs r2, r0
0x24c0e <ecma_errol0_dtoa+1482>: movs r3, r1
0x24c10 <ecma_errol0_dtoa+1484>: movs r0, r6
0x24c12 <ecma_errol0_dtoa+1486>: movs r1, r7
0x24c14 <ecma_errol0_dtoa+1488>: bl 0x38258 <____aeabi_dsub_from_thumb>
0x24c18 <ecma_errol0_dtoa+1492>: movs r2, #0
0x24c1a <ecma_errol0_dtoa+1494>: ldr r3, [pc, #304] ; (0x24d4c <ecma_errol0_dtoa+1800>)

(gdb) x/100bx $r2-80 <- 5200 0x30 written over the stack. This is the tail end of them.
0x75dcefb0: 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30
0x75dcefb8: 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30
0x75dcefc0: 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30
0x75dcefc8: 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30
0x75dcefd0: 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30
0x75dcefd8: 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30
0x75dcefe0: 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30
0x75dcefe8: 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30
0x75dceff0: 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30
0x75dceff8: 0x30 0x30 0x30 0x30 0x30 0x30 0x30 0x30
0x75dcf000: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x75dcf008: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x75dcf010: 0x00 0x00 0x00 0x00

Build platform

Mac OS X 10.14.6 (Darwin 18.7.0 x86_64)
arm-unknown-linux-gnueabi-gcc (crosstool-NG 1.24.0) 8.3.0

Build steps

python tools/build.py --profile=minimal --external-context=ON --verbose --clean --toolchain cmake/toolchain_raspberry_pi.cmake --lto off --jerry-cmdline off

Javascript

print('Task Init');
automation.thisDevice.deviceID="8acaf075-2edd-4c27-ab9b-74c62b14d41d";
var p=automation.points[0];
print("Initial point",JSON.stringify(p));

This is the output on a loop that didn't crash. The conversion is obviously bad here as well.

Initial point {"globalPointID":"20605adf-9566-80eb-7646-9a28c5fa3af3","localPointID":"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee","description":"Percent door open","value":0.0005000000249999986823290498705318896099925041198730468750,"type":7}

p is a structure created in C. The double that it's trying to convert to a string is created using this function.

jerry_value_t pointValueToJerryValue(PointValueVariant* v){
debug3("pointValueToJerryValue\n");

switch (v->type){
	case PointTypeInvalid:
	case PointTypeUnknown:
		return jerry_create_null();
	case PointTypeBoolean:
		return jerry_create_boolean(v->value.boolean);
	case PointTypeInteger:
		return jerry_create_number(v->value.integer);
	case PointTypeDouble:
		return jerry_create_number(v->value.dbl);
	default:
		error2("Cannot convert this point type to javascript\n");
		return jerry_create_undefined();
}

}

I'm happy to provide a test binary with the issue.

Thanks in advance!

@dbatyai
Copy link
Member

dbatyai commented May 7, 2020

Hi @anonpoet,

does the conversion always output incorrect results, or it works in general, and misbehaves in specific cases? If the latter, it would be great if you could post the hex value of a double that triggers the issue.

Additionally, could you try with one of the precompiled toolchains from the ARM Developer site, and see if the issue is persists?

One more thing, the cmake/toolchain_raspberry_pi.cmake toolchain file seems to be custom made, could you share the contents?

@anonpoet
Copy link
Author

anonpoet commented May 7, 2020

Here's the CMAKE file. I'll grab the compiler and post the results.


# Copyright JS Foundation and other contributors, http://js.foundation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set(CMAKE_SYSTEM_NAME Linux)
set(CMAKE_SYSTEM_PROCESSOR armv7l-el)

set(CMAKE_C_COMPILER TOP/device/architecture/raspberry_pi/arm-unknown-linux-gnueabi/bin/arm-unknown-linux-gnueabi-gcc)

set(FLAGS_COMMON_ARCH -mlittle-endian -mthumb)

@anonpoet
Copy link
Author

Sorry this took so long. Switching out compilers ended up being major surgery. I recompiled with a cross compiler that used the raspberry pi's hardware floating point unit. The version with the new compiler doesn't seem to have the bug.

I haven't stared at the code for long enough, but I suspect that what was happening is that the soft float division when dividing by 10.0 was using its prerogative and approximating a value. The resulting value isn't guaranteed to not set the least significant bits to a random value. This could cause an infinite loop.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants