The following program fails to compile with address sanitization enabled:
class E1: Error { }
type E2 = E1;
proc throwingProc() throws {
throw new E2();
}
try {
throwingProc();
} catch e: E2 {
writeln(e);
}
The error appears to be originating from the fact that E2 (a type alias for E1) is being used in a catch statement. Using a type alias for an error class does not appear to create problems in other contexts (such as instantiating or passing to a procedure), but only produces this error when catch e: E2 is used.
Full compilation error message...
```
=================================================================
==14151==ERROR: AddressSanitizer: heap-use-after-free on address 0x612000646e78 at pc 0x000000587aba bp 0x7fff89d24d70 sp 0x7fff89d24d68
READ of size 8 at 0x612000646e78 thread T0
#0 0x587ab9 in CatchStmt::isCatchall() const ($CHPL_HOME/bin/linux64-x86_64/chpl+0x587ab9)
#1 0xb5148a in (anonymous namespace)::ErrorCheckingVisitor::exitTryStmt(TryStmt*) ($CHPL_HOME/bin/linux64-x86_64/chpl+0xb5148a)
#2 0x6d9926 in TryStmt::accept(AstVisitor*) ($CHPL_HOME/bin/linux64-x86_64/chpl+0x6d9926)
#3 0x6ade28 in BlockStmt::accept(AstVisitor*) ($CHPL_HOME/bin/linux64-x86_64/chpl+0x6ade28)
#4 0xb6139c in lowerErrorHandling() ($CHPL_HOME/bin/linux64-x86_64/chpl+0xb6139c)
#5 0x92dec5 in runPasses(PhaseTracker&) ($CHPL_HOME/bin/linux64-x86_64/chpl+0x92dec5)
#6 0x426f75 in main ($CHPL_HOME/bin/linux64-x86_64/chpl+0x426f75)
#7 0x7f215c0a529c in __libc_start_main (/lib64/libc.so.6+0x3529c)
#8 0x438d49 in _start ($CHPL_HOME/bin/linux64-x86_64/chpl+0x438d49)
0x612000646e78 is located 56 bytes inside of 264-byte region [0x612000646e40,0x612000646f48)
freed by thread T0 here:
#0 0x7f215d92fbb8 in operator delete(void*, unsigned long) (/usr/lib64/libasan.so.4+0xdebb8)
#1 0x51b6d1 in cleanAst() ($CHPL_HOME/bin/linux64-x86_64/chpl+0x51b6d1)
previously allocated by thread T0 here:
#0 0x7f215d92e830 in operator new(unsigned long) (/usr/lib64/libasan.so.4+0xdd830)
#1 0xb2bb8d in (anonymous namespace)::Converter::convertVariable(chpl::uast::Variable const*, bool) ($CHPL_HOME/bin/linux64-x86_64/chpl+0xb2bb8d)
#2 0x1cb9657 ($CHPL_HOME/bin/linux64-x86_64/chpl+0x1cb9657)
SUMMARY: AddressSanitizer: heap-use-after-free ($CHPL_HOME/bin/linux64-x86_64/chpl+0x587ab9) in CatchStmt::isCatchall() const
Shadow bytes around the buggy address:
0x0c24800c0d70: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c24800c0d80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c24800c0d90: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c24800c0da0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x0c24800c0db0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x0c24800c0dc0: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd[fd]
0x0c24800c0dd0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
0x0c24800c0de0: fd fd fd fd fd fd fd fd fd fa fa fa fa fa fa fa
0x0c24800c0df0: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
0x0c24800c0e00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
0x0c24800c0e10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==14151==ABORTING
```
printchplenv...
```
CHPL_HOST_PLATFORM: linux64
CHPL_HOST_COMPILER: gnu
CHPL_HOST_CC: gcc
CHPL_HOST_CXX: g++
CHPL_HOST_ARCH: x86_64
CHPL_TARGET_PLATFORM: linux64
CHPL_TARGET_COMPILER: gnu
CHPL_TARGET_CC: gcc
CHPL_TARGET_CXX: g++
CHPL_TARGET_LD: g++
CHPL_TARGET_ARCH: x86_64
CHPL_TARGET_CPU: native
CHPL_LOCALE_MODEL: flat
CHPL_COMM: none *
CHPL_TASKS: fifo *
CHPL_LAUNCHER: none
CHPL_TIMERS: generic
CHPL_UNWIND: none
CHPL_HOST_MEM: cstdlib *
CHPL_MEM: cstdlib *
CHPL_ATOMICS: cstdlib
CHPL_GMP: none *
CHPL_HWLOC: none
CHPL_RE2: none *
CHPL_LLVM: none *
CHPL_LLVM_SUPPORT: system
CHPL_LLVM_CONFIG: <...> *
CHPL_LLVM_VERSION: 14
CHPL_AUX_FILESYS: none
CHPL_LIB_PIC: none
CHPL_SANITIZE: address *
CHPL_SANITIZE_EXE: address
```
This same code also fails when compiling with --verify with an internal compiler error:.
Discussion
It is not clear whether we should support type aliases of classes being used in a catch statement; however this did come up recently when CodepointSplittingError was renamed and had to be deprecated (see: https://github.com/chapel-lang/chapel/pull/22678). The deprecation strategy was to make CodepointSplittingError a deprecated type-alias for the new error class. Functionally, this works correctly; however, it is not passing address sanitization so we may need to rethink the deprecation strategy, or address what appears to be a bug summarized in the above code.
Summary of Problem
The following program fails to compile with address sanitization enabled:
The error appears to be originating from the fact that
E2
(a type alias forE1
) is being used in a catch statement. Using a type alias for an error class does not appear to create problems in other contexts (such as instantiating or passing to a procedure), but only produces this error whencatch e: E2
is used.Full compilation error message...
``` ================================================================= ==14151==ERROR: AddressSanitizer: heap-use-after-free on address 0x612000646e78 at pc 0x000000587aba bp 0x7fff89d24d70 sp 0x7fff89d24d68 READ of size 8 at 0x612000646e78 thread T0 #0 0x587ab9 in CatchStmt::isCatchall() const ($CHPL_HOME/bin/linux64-x86_64/chpl+0x587ab9) #1 0xb5148a in (anonymous namespace)::ErrorCheckingVisitor::exitTryStmt(TryStmt*) ($CHPL_HOME/bin/linux64-x86_64/chpl+0xb5148a) #2 0x6d9926 in TryStmt::accept(AstVisitor*) ($CHPL_HOME/bin/linux64-x86_64/chpl+0x6d9926) #3 0x6ade28 in BlockStmt::accept(AstVisitor*) ($CHPL_HOME/bin/linux64-x86_64/chpl+0x6ade28) #4 0xb6139c in lowerErrorHandling() ($CHPL_HOME/bin/linux64-x86_64/chpl+0xb6139c) #5 0x92dec5 in runPasses(PhaseTracker&) ($CHPL_HOME/bin/linux64-x86_64/chpl+0x92dec5) #6 0x426f75 in main ($CHPL_HOME/bin/linux64-x86_64/chpl+0x426f75) #7 0x7f215c0a529c in __libc_start_main (/lib64/libc.so.6+0x3529c) #8 0x438d49 in _start ($CHPL_HOME/bin/linux64-x86_64/chpl+0x438d49) 0x612000646e78 is located 56 bytes inside of 264-byte region [0x612000646e40,0x612000646f48) freed by thread T0 here: #0 0x7f215d92fbb8 in operator delete(void*, unsigned long) (/usr/lib64/libasan.so.4+0xdebb8) #1 0x51b6d1 in cleanAst() ($CHPL_HOME/bin/linux64-x86_64/chpl+0x51b6d1) previously allocated by thread T0 here: #0 0x7f215d92e830 in operator new(unsigned long) (/usr/lib64/libasan.so.4+0xdd830) #1 0xb2bb8d in (anonymous namespace)::Converter::convertVariable(chpl::uast::Variable const*, bool) ($CHPL_HOME/bin/linux64-x86_64/chpl+0xb2bb8d) #2 0x1cb9657 ($CHPL_HOME/bin/linux64-x86_64/chpl+0x1cb9657) SUMMARY: AddressSanitizer: heap-use-after-free ($CHPL_HOME/bin/linux64-x86_64/chpl+0x587ab9) in CatchStmt::isCatchall() const Shadow bytes around the buggy address: 0x0c24800c0d70: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c24800c0d80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c24800c0d90: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c24800c0da0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa 0x0c24800c0db0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa =>0x0c24800c0dc0: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd[fd] 0x0c24800c0dd0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd 0x0c24800c0de0: fd fd fd fd fd fd fd fd fd fa fa fa fa fa fa fa 0x0c24800c0df0: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00 0x0c24800c0e00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 0x0c24800c0e10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 fa Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb ==14151==ABORTING ```printchplenv...
``` CHPL_HOST_PLATFORM: linux64 CHPL_HOST_COMPILER: gnu CHPL_HOST_CC: gcc CHPL_HOST_CXX: g++ CHPL_HOST_ARCH: x86_64 CHPL_TARGET_PLATFORM: linux64 CHPL_TARGET_COMPILER: gnu CHPL_TARGET_CC: gcc CHPL_TARGET_CXX: g++ CHPL_TARGET_LD: g++ CHPL_TARGET_ARCH: x86_64 CHPL_TARGET_CPU: native CHPL_LOCALE_MODEL: flat CHPL_COMM: none * CHPL_TASKS: fifo * CHPL_LAUNCHER: none CHPL_TIMERS: generic CHPL_UNWIND: none CHPL_HOST_MEM: cstdlib * CHPL_MEM: cstdlib * CHPL_ATOMICS: cstdlib CHPL_GMP: none * CHPL_HWLOC: none CHPL_RE2: none * CHPL_LLVM: none * CHPL_LLVM_SUPPORT: system CHPL_LLVM_CONFIG: <...> * CHPL_LLVM_VERSION: 14 CHPL_AUX_FILESYS: none CHPL_LIB_PIC: none CHPL_SANITIZE: address * CHPL_SANITIZE_EXE: address ```This same code also fails when compiling with
--verify
with an internal compiler error:.Discussion
It is not clear whether we should support type aliases of classes being used in a
catch
statement; however this did come up recently whenCodepointSplittingError
was renamed and had to be deprecated (see: https://github.com/chapel-lang/chapel/pull/22678). The deprecation strategy was to makeCodepointSplittingError
a deprecated type-alias for the new error class. Functionally, this works correctly; however, it is not passing address sanitization so we may need to rethink the deprecation strategy, or address what appears to be a bug summarized in the above code.