C++ guarantees initialization of static objects takes place before
threads can run, so we don't need all the locksInitialized fubar.
The native objects also release themselves which fixes a theoretical
leak we had: we never destroyed the lock or lockattr so they remained
reachable until program exit.
We could continue to acquire and release the lock in the corresponding
functions but that's not RAII and would be inconsistent with what we
do elsewhere in rpm, just convert to the local lock variable style.
$ rpm --define 'aaa %[%aaa]' --eval '%aaa'
let to a core dump due to a stack overflow. This was cause by the
generation of the error message failing due to being too deep in the
recursion of the macro expansion - creating more error messages.
Resetting the depth counter allows rendering the error message. As we are
failing and breaking off the parse run this is fine to do.
Thanks to Miro Hrončok for reporting
Resolves: #3197
If the resulting flags cannot be returned, the caller has no way to
strip the quote characters. So we must assume that we are not to
return quotes in this case.
Fixes issue #3145
Use an STL stack to store the macro entries sharing the name to separate
the data from its containing structure, this lets the macro entries be
proper C++ objects that manage their own business only and thus can be
also directly stored containers, doing away with manual allocation.
And now that these entries no longer need any special care, we can
delete all the copy-control fubar from the main macro context: it's all
standard library storage now and don't need our handholding.
Use an STL map for the macro entry table, this matches exactly the behavior
we manually did with the C array.
The variable length array at end of macro entry structs is not really
C++, use native strings for the storage. It's slower, but not tragically
so. For now, keep name, opts and body as const char pointers though to
the c_str() items to avoid having to change everything at once.
Popping macros is a bit clunky and repetitive, we'll clean it up later.
findEntry() returns a pointer to the macro entry itself instead of
pointer to pointer, which simplifies things a bit further.
This is a wee bit slower than the "raw C" counterpart, but by no means
tragically so and moving to native structures opens up other opportunities
in turn, both optimization and feature wise. Further work will be easier
now that the highly optimized but also tangled up data structure is
(mostly) untangled.
The macro contexts being static structs, they get their destructor
automatically called at program end. Which counter-intuitively *causes*
a leak if macros are stored in an STL container and rpmFreeMacros()
isn't called, because then the container clears itself and the macros
are left dangling, whereas without the destructor they are still
reachable. freeMacros() obviously wants to be a member function but
trying to keep things in the struct land for now.
Doesn't really change anything as of now, but this is needed for moving
the macro storage to C++ container.
freeArgs() only popped any local macros once, so if a local macro was
pushed multiple times, whether through %define or multiple identical
options getting passed, we leaked any remaining macros to the outside
scope.
Simply pop the local macros in a loop to fix. Have the internal
popMacro() return the previous pointer (if any) to simplify the job.
We even had an expected-fail test for this, now passing, but add a
more straightforward reproducer too.
This bug was circa 26 years old. Some might call it vintage at this point.
Fixes: #3056
C lets us do this but in C++ needs to run destructors at end of scope,
so they better be properly initialized...
These are all over the place but so trivial putting them to different
commits doesn't make much sense.
This really belongs to a separate function in the first place, and doing
so allows us to turn 'b' into a const char *, which in turn makes
the assignment to string literal "" in the url2path case legitimate.
Fun times and no functional changes.
This should be an error for consistency with other macro argument
checking but as there appear to be usages in the wild, make it a
warning for now.
Fixes: #2932
This changes the behaviour of %dirname to something sane. No longer
return the argument unchanged if there is no / found. Also handle
several cornercases properly.
Resolves: #2928
A problem with the old handling of %quote was that it leaked to
the outside. This commit strips the quote characters if they are
not used in argument splitting.
We also keep track of the quotes when defining macros so that
we stay compatible to the old implementation.
This makes the %shescape macro work use all arguments like we
already do in the %quote macro.
I.e.:
%{shescpae:hello world} -> 'hello world'
%{shescpae hello world} -> 'hello' 'world'
"long int" on at least x86 Linux is exactly the same as a plain "int",
so calculations can easily overflow. 32bit systems are not expected to
have hundreds of gigabytes of memory but a 32bit process on a x86_64 can
run into all sorts of funny things, such having 500GB system memory. At
which point the type capable of addressing all of process memory is
absolutely useless for calculating the total memory.
Use uint64_t in the memory calculations to make the size explicit. Of course
one day we may cross that border too, but I hope to be retired by then.
Fixes https://issues.redhat.com/browse/RHEL-16557
Now that we can, just define __file_lineno as an auxiliary macro that
only does any work in the rare case where an error or warning occurred.
This saves an enormous amount of huffing and puffing defining and
undefining macros that are not used at all in the normal paths, on
every rpm startup and spec parse.
Technically we could use a common macro function for both but as they're
in separate libraries, this doesn't seem worth the few lines of saving.
Add rpmPushMacroAux() function which allows registering auxiliary macros
implemented in C and some required helper facilities: export the types,
rpmMacroBufAppend*() and rpmMacroBufErr() functions, and finally
add rpmMacroEntryPriv() to let macro retrieve their private data.
And that's all folks.
Having everything accessible to everything encourages fast and loose
includes from places one shouldn't be using, and makes it easy for
those cases to hide in plain sight as well. There were reasons for
the top-level include back in 2007 but our codebase is a rather
different beast these days. Limiting access through per-target
include directories on everything nicely highlights the exceptions
and makes the whole more controllable and manageable.
This change looks huge, but it's just due to stripping no longer valid
prefixes from all the gazillion internal includes. No rpm-side
functionality is affected, this is just source-level hygiene operation.
"total" equals calling with no arguments, "proc" and "thread" consider
further constraints, what is implemented here is heuristics based on
available physical memory and address-space and %_smp_tasksize_proc /
%_smp_tasksize_thread tunables.
Change the previous %getncpus related tests to use %getconfdir instead,
they are testing unexpected arguments behavior for this type of macro,
not %getncpus itself. Add a test for the actual functionality: if nproc
is available, test that our total matches with that, and that defining
tasksize to total memory only allocates one thread. Optimally we'd
test separately for 32bit address space limitations but that gets tough
when we have no idea where this will be executed.
This is the same issue as commit 1767bc4fd8
was with Lua, and so the same fix works: restore the nesting level
from the macro context when re-entering macro engine from %[]
expression. Analysis and suggested fix by Michael Schroeder,
reproducer from Miro Hrončok.
Add tests for both %[] and %{expr:...}, although the latter isn't
affected because the expression is macro-expanded beforehand.
Fixes: #2354
Despite all the Lua magic we already do, it's annoyingly often the case
that shelling out is easier (or at least shorter) than doing the same in
Lua (substrings, length etc)
Add shorthand macros %gsub, %len, %lower, %rep, %reverse, %sub and
%upper which simply wrap the corresponding Lua string.* functions for
convenience.
This means that finally there's just one place that when adding support
for new compress formats, there's in theory there's just one place to
update. Reality is a little more complicated, but hey...
Adjust tests a bit, and rather test functionality than command output
because those reflect command paths which we can't easily adjust now.
This improves compatibility with old rpm versions. If an argument
is present, the macro expands to it in verbose mode and to an
empty string if not in verbose mode.
Macros like %getncpus should not treat the following text as
macro arguments. E.g. 'make -j %getncpus all' should work and
not complain about an unexpected argument.
We still treat arguments passed via %{foo:arg} or %{foo arg} as an
error for builtin macros. (They are silently ignored for user
defined macros.)
This means no special new line processing and '\' unescaping. Thus
"%{define foo body}" works similar to "%define foo {body}" except
that the parsing in spec files works because copyNextLineFromOFI()
knows how to deal with macros.
doXXX() used to return the parsed characters for ME_PARSE macros
and the caller added them to the "parsed" variable.
We now directly pass parsed as argument and let the doXXX()
functions do the adding. This will allow us to differentiate
between "%define foo bar" and "%{define foo bar}" in a
future commit.
No functual changes.
The builtin macros used to expand the arguments themselfs. This
works for the %{foo:bar} syntax, but it means that for %{foo bar}
the argument is expanded twice: once before the argument is split
and then in the macro function.
Simplify the code by always doing the expansion when creating
the argument vector.
Realizing that we have dynamic string buffer available in the macro
engine... so we don't need a dumb worst case malloc and all the other
crap in the old tag format era implementation.