Nim icon indicating copy to clipboard operation
Nim copied to clipboard

UB calling `allocCStringArray([""])` with `--mm:refc`

Open tersec opened this issue 2 years ago • 1 comments

Description

discard allocCStringArray([""])

compiled with

nim c -r --mm:refc --passC="-fsanitize=undefined" --passL="-fsanitize=undefined" a.nim

Where allocCStringArray compiles to:

N_LIB_PRIVATE N_NIMCALL(NCSTRING*, allocCStringArray__system_u2460)(NimStringDesc** a_p0, NI a_p0Len_0) {
	NCSTRING* result;
	void* T1_;
	NimStringDesc** x;
	result = (NCSTRING*)0;
	T1_ = (void*)0;
	T1_ = alloc0Impl__system_u1800(((NI) ((NI)((NI)(a_p0Len_0 + ((NI)1)) * ((NI)8)))));
	result = ((NCSTRING*) (T1_));
	x = ((NimStringDesc**) (a_p0));
	{
		NI i;
		NI colontmp_;
		NI res;
		i = (NI)0;
		colontmp_ = (NI)0;
		colontmp_ = (a_p0Len_0-1);
		res = ((NI)0);
		{
			while (1) {
				void* T5_;
				if (!(res <= colontmp_)) goto LA4;
				i = res;
				T5_ = (void*)0;
				T5_ = alloc0Impl__system_u1800(((NI) ((NI)((x[i] ? x[i]->Sup.len : 0) + ((NI)1)))));
				result[i] = ((NCSTRING) (T5_));
				copyMem__system_u1782(((void*) (result[i])), ((void*) ((&x[i]->data[((NI)0)]))), ((NI) ((x[i] ? x[i]->Sup.len : 0))));
				res += ((NI)1);
			} LA4: ;
		}
	}
	return result;
}

...

static NIM_CONST tyArray__nHXaesL0DJZHyVS07ARPRA TM__R8RUzYq41iOx0I9bZH5Nyrw_2 = {((NimStringDesc*) NIM_NIL)}
;

...

N_LIB_PRIVATE N_NIMCALL(void, NimMainModule)(void) {
{
	NCSTRING* T1_;
	T1_ = (NCSTRING*)0;
	T1_ = allocCStringArray__system_u2460(TM__R8RUzYq41iOx0I9bZH5Nyrw_2, 1);
	(void)(T1_);
	popFrame();
}
}

and the current output occurs on

copyMem__system_u1782(((void*) (result[i])), ((void*) ((&x[i]->data[((NI)0)]))), ((NI) ((x[i] ? x[i]->Sup.len : 0))));

because ((void*) ((&x[i]->data[((NI)0)]))) is, as usual for this sort of offsetof approach, undefined behavior when x[i] == NULL, as is the case with the empty string here.

Nim Version

Nim Compiler Version 1.9.5 [Linux: amd64]
Compiled at 2023-06-25
Copyright (c) 2006-2023 by Andreas Rumpf

git hash: f718f295df3f6ee5d7fd6fc19e39ac663821b00a
active boot switches: -d:release
gcc (Debian 12.3.0-4) 12.3.0
Copyright (C) 2022 Free Software Foundation, Inc.
Debian clang version 14.0.6
Target: x86_64-pc-linux-gnu
Thread model: posix
InstalledDir: /usr/bin

Current Output

.cache/nim/a_d/@mNim@[email protected]:5983:61: runtime error: member access within null pointer of type 'struct NimStringDesc'

Expected Output

No undefined behavior detected by UBSAN

Possible Solution

No response

Additional Information

No response

tersec avatar Jun 25 '23 12:06 tersec

As I wrote elsewhere, these sanitizer rules are broken, against the spirit of C and against how address computations work on every CPU ever invented.

Araq avatar Jun 25 '23 15:06 Araq