UNDER THE HOOD
Library calls
GuardLibrary.cpp guards a direct call of a function of the library table
(LibrarySpec.txt) that the unit does not
define, before the call (RFC 0035 §2.5 and amendment 7, RFC 0036 §6):
- Each pointer argument the row reads or writes is guarded over the bytes
its term gives (
bytes(t),count(t)times the element size, one element without a term), evaluated on the call’s arguments; astrlenterm is evaluated by the runtime inside the string’s addressable bytes. - A
strargument is guarded as a string:__weavec_rt_strlen(s, max, site)scans it and fails withunterminated-stringwhen the terminator is not addressable. Aprintf- orscanf-family call with a constant format guards each%sargument as a string and each%nargument as anint. - Fortified forms (
chk(…), RFC 0036 §6). A call of a fortified alias (__strcpy_chk(d, s, 8)) whose object-size argument is not(size_t)-1checks that it writes no more than that size: inline, or by passing the size to its wrapper aslimit. A write past the size within addressable bytes reportsintra-object-overflow. - A row’s
wrapper(NAME)clause replaces the call with__weavec_rt_NAME, with the call’s arguments, alimitwhen the row has a fortified alias, and the site (first when the call is variadic). The wrappers (runtime/weavec_libc.c) ofstrcpy,stpcpy,strcat,sprintf,vsprintf,snprintf,vsnprintfandgetscompute what the call writes before it writes; theprintf-family ones check each%sand%nargument, through ava_listtoo; thescanffamily checks what each conversion wrote; those ofmemchr,strchr,strcmp,strncmp,strcasecmpandstrncasecmpcheck only the bytes the call read up to where it stopped; the number parsers (strtoltostrtold,strtoimax,strtoumax,atoi,atol,atoll,atof) check after the call the bytes the C library read (up to the end pointer and the character that stopped it);mmapandmunmapclear the shadow of what they map. A wrapper is named after its row’s function (the parser checks it). The calls that write through no pointer are redirected late, by GuardExpand, so that the optimiser can still foldstrcmpof constants; GuardInsert guards only the first byte of their string arguments. Such a call that reads exactly a constant of at most 113 bytes keeps inline guards instead. - A row whose result is a
value(t)computed only from what it reads (strlen,strnlen) is replaced by the string guard that computest. - A
widerow scales itscountterms by the module’swchar_size; its strings are not scanned (a known gap: a wide string argument is not guarded). - A null the row accepts (
null-ok) passes. The arguments a call releases or reallocates are not guarded; the allocator validates them. - A copy’s operands must not overlap:
llvm.memcpy(except an aggregate assignment, which carries!tbaa.struct) and a row with adisjointclause get a__weavec.disjointmarker, and an overlap fails asoverlapping-copy.
A function outside the table is not checked at the call; its own accesses
are guarded if weavec-cc built it (assumption A2).