Linux GNU 11.4.0 Code Coverage Report


Directory: ./
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 35.4% 79 / 0 / 223
Functions: -% 0 / 1 / 1
Branches: 29.6% 42 / 0 / 142

OMCompiler/Compiler/Script/Obfuscate.mo
Line Branch Exec Source
1 /*
2 * This file is part of OpenModelica.
3 *
4 * Copyright (c) 1998-2026, Open Source Modelica Consortium (OSMC),
5 * c/o Linköpings universitet, Department of Computer and Information Science,
6 * SE-58183 Linköping, Sweden.
7 *
8 * All rights reserved.
9 *
10 * THIS PROGRAM IS PROVIDED UNDER THE TERMS OF AGPL VERSION 3 LICENSE OR
11 * THIS OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.8.
12 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES
13 * RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GNU AGPL
14 * VERSION 3, ACCORDING TO RECIPIENTS CHOICE.
15 *
16 * The OpenModelica software and the OSMC (Open Source Modelica Consortium)
17 * Public License (OSMC-PL) are obtained from OSMC, either from the above
18 * address, from the URLs:
19 * http://www.openmodelica.org or
20 * https://github.com/OpenModelica/ or
21 * http://www.ida.liu.se/projects/OpenModelica,
22 * and in the OpenModelica distribution.
23 *
24 * GNU AGPL version 3 is obtained from:
25 * https://www.gnu.org/licenses/licenses.html#GPL
26 *
27 * This program is distributed WITHOUT ANY WARRANTY; without
28 * even the implied warranty of MERCHANTABILITY or FITNESS
29 * FOR A PARTICULAR PURPOSE, EXCEPT AS EXPRESSLY SET FORTH
30 * IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE CONDITIONS OF OSMC-PL.
31 *
32 * See the full OSMC Public License conditions for more details.
33 *
34 */
35
36 encapsulated package Obfuscate
37 import Absyn;
38 import AbsynUtil;
39 import Dump;
40 import FBuiltin;
41 import SCode;
42 import SCodeUtil;
43 import StringUtil;
44 import UnorderedMap;
45 import Util;
46
47 type Mapping = UnorderedMap<String, String>;
48 type Builtins = UnorderedMap<String, ElementType>;
49
50 // Most builtin elements are not reserved keywords and can be shadowed by
51 // user elements. To try and avoid issues when we have e.g. a component named
52 // abs we keep track of what types of builtin elements we have and what type
53 // of element we're looking for with this enumeration.
54 type ElementType = enumeration(
55 TYPE,
56 FUNCTION,
57 TYPE_AND_FUNCTION,
58 OTHER
59 );
60
61 uniontype Env
62 record ENV
63 Mapping mapping;
64 Builtins builtins;
65 end ENV;
66 end Env;
67
68 function obfuscateProgram
69 "Obfuscates an SCode.Program by replacing names with generated identifiers,
70 such as Modelica.SIUnits.Angle => n23.n54.n13. Also takes the path and
71 comment for a class and obfuscates them too, which is needed by
72 saveTotalModel.
73
74 Note that the given class path does not affect what is obfuscated, this
75 function always obfuscate the entire SCode.Program that it's given."
76 input output SCode.Program program;
77 input output Absyn.Path classPath;
78 input output SCode.Comment classComment = SCode.noComment;
79 output String mapStr;
80 output Mapping mapping;
81 protected
82 Builtins builtins;
83 Env env;
84 algorithm
85 // The mapping table is used to keep track of which obfuscated name each
86 // original name is mapped to.
87 1 mapping := UnorderedMap.new<String>(stringHashDjb2, stringEqual);
88 // We don't want to obfuscate builtin names, so we keep track of them in a
89 // separate table.
90 1 builtins := makeBuiltins();
91 1 env := ENV(mapping, builtins);
92
93
4/4
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 1 time.
2 program := list(obfuscateElement(e, env) for e in program);
94 1 classPath := obfuscatePath(classPath, env, ElementType.TYPE);
95 1 classComment := obfuscateComment(classComment, env);
96
97 // Convert the mapping table to a JSON structure that can be used to look up
98 // which name is mapped to what.
99 1 mapStr := UnorderedMap.toJSON(env.mapping, Util.id, Util.id);
100 end obfuscateProgram;
101
102 function makeBuiltins
103 "Creates the table with builtin names."
104 output Builtins builtins;
105 protected
106 SCode.Program builtin_scode;
107 ElementType etype;
108 algorithm
109 1 builtins := UnorderedMap.new<ElementType>(stringHashDjb2, stringEqual);
110
111 1 (_, builtin_scode) := FBuiltin.getInitialFunctions();
112
113
2/2
✓ Branch 0 taken 98 times.
✓ Branch 1 taken 1 time.
99 for b in builtin_scode loop
114
2/2
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 84 times.
98 etype := if SCodeUtil.isFunction(b) then ElementType.FUNCTION else ElementType.TYPE;
115 98 UnorderedMap.add(SCodeUtil.elementName(b), etype, builtins);
116 end for;
117
118 // Builtin types.
119 1 UnorderedMap.add("Boolean" , ElementType.TYPE , builtins);
120 1 UnorderedMap.add("Clock" , ElementType.TYPE , builtins);
121 1 UnorderedMap.add("Real" , ElementType.TYPE , builtins);
122 // Builtin types that are also functions.
123 1 UnorderedMap.add("Integer" , ElementType.TYPE_AND_FUNCTION, builtins);
124 1 UnorderedMap.add("String" , ElementType.TYPE_AND_FUNCTION, builtins);
125 // Builtin type attributes.
126 1 UnorderedMap.add("displayUnit" , ElementType.OTHER , builtins);
127 1 UnorderedMap.add("fixed" , ElementType.OTHER , builtins);
128 1 UnorderedMap.add("max" , ElementType.OTHER , builtins);
129 1 UnorderedMap.add("min" , ElementType.OTHER , builtins);
130 1 UnorderedMap.add("nominal" , ElementType.OTHER , builtins);
131 1 UnorderedMap.add("quantity" , ElementType.OTHER , builtins);
132 1 UnorderedMap.add("start" , ElementType.OTHER , builtins);
133 1 UnorderedMap.add("stateSelect" , ElementType.OTHER , builtins);
134 1 UnorderedMap.add("time" , ElementType.OTHER , builtins);
135 1 UnorderedMap.add("unbounded" , ElementType.OTHER , builtins);
136 1 UnorderedMap.add("uncertain" , ElementType.OTHER , builtins);
137 1 UnorderedMap.add("unit" , ElementType.OTHER , builtins);
138 // Builtin functions.
139 1 UnorderedMap.add("constructor" , ElementType.FUNCTION , builtins);
140 1 UnorderedMap.add("destructor" , ElementType.FUNCTION , builtins);
141 1 UnorderedMap.add("$array" , ElementType.FUNCTION , builtins);
142 1 UnorderedMap.add("equalityConstraint", ElementType.FUNCTION , builtins);
143 end makeBuiltins;
144
145 function obfuscateElement
146 input output SCode.Element element;
147 input Env env;
148 algorithm
149 () := match element
150 case SCode.Element.IMPORT()
151 algorithm
152 ✗ element.imp := obfuscateImport(element.imp, env);
153 then
154 ();
155
156 case SCode.Element.EXTENDS()
157 algorithm
158 ✗ element.baseClassPath := obfuscatePath(element.baseClassPath, env, ElementType.TYPE);
159 ✗ element.modifications := obfuscateMod(element.modifications, env);
160 ✗ element.ann := obfuscateAnnotationOpt(element.ann, env);
161 then
162 ();
163
164 case SCode.Element.CLASS()
165 algorithm
166 1 element.name := obfuscateIdentifier(element.name, env, ElementType.TYPE_AND_FUNCTION);
167 1 element.prefixes := obfuscatePrefixes(element.prefixes, env);
168 1 element.classDef := obfuscateClassDef(element.classDef, env);
169 1 element.cmt := obfuscateComment(element.cmt, env);
170 then
171 ();
172
173 case SCode.Element.COMPONENT()
174 algorithm
175 1 element.name := obfuscateIdentifier(element.name, env, ElementType.OTHER);
176 1 element.prefixes := obfuscatePrefixes(element.prefixes, env);
177 1 element.attributes := obfuscateAttributes(element.attributes, env);
178 1 element.typeSpec := obfuscateTypeSpec(element.typeSpec, env);
179 1 element.modifications := obfuscateMod(element.modifications, env);
180 1 element.comment := obfuscateComment(element.comment, env);
181 1 element.condition := obfuscateExpOpt(element.condition, env);
182 then
183 ();
184
185 else ();
186 end match;
187 end obfuscateElement;
188
189 function obfuscateImport
190 input output Absyn.Import imp;
191 input Env env;
192 algorithm
193 () := match imp
194 case Absyn.Import.NAMED_IMPORT()
195 algorithm
196 ✗ imp.name := obfuscateIdentifier(imp.name, env, ElementType.OTHER);
197 ✗ imp.path := obfuscatePath(imp.path, env, ElementType.TYPE);
198 then
199 ();
200
201 case Absyn.Import.QUAL_IMPORT()
202 algorithm
203 ✗ imp.path := obfuscatePath(imp.path, env, ElementType.TYPE);
204 then
205 ();
206
207 case Absyn.Import.UNQUAL_IMPORT()
208 algorithm
209 ✗ imp.path := obfuscatePath(imp.path, env, ElementType.TYPE);
210 then
211 ();
212
213 case Absyn.Import.GROUP_IMPORT()
214 algorithm
215 ✗ imp.prefix := obfuscatePath(imp.prefix, env, ElementType.TYPE);
216 ✗ imp.groups := list(obfuscateGroupImport(g, env) for g in imp.groups);
217 then
218 ();
219 end match;
220 end obfuscateImport;
221
222 function obfuscateGroupImport
223 input output Absyn.GroupImport imp;
224 input Env env;
225 algorithm
226 () := match imp
227 case Absyn.GroupImport.GROUP_IMPORT_NAME()
228 algorithm
229 ✗ imp.name := obfuscateIdentifier(imp.name, env, ElementType.TYPE);
230 then
231 ();
232
233 case Absyn.GroupImport.GROUP_IMPORT_RENAME()
234 algorithm
235 ✗ imp.rename := obfuscateIdentifier(imp.rename, env, ElementType.OTHER);
236 ✗ imp.name := obfuscateIdentifier(imp.name, env, ElementType.TYPE);
237 then
238 ();
239 end match;
240 end obfuscateGroupImport;
241
242 function obfuscateClassDef
243 input output SCode.ClassDef cdef;
244 input Env env;
245 algorithm
246 () := match cdef
247 case SCode.ClassDef.PARTS()
248 algorithm
249
4/4
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 1 time.
3 cdef.elementLst := list(obfuscateElement(e, env) for e in cdef.elementLst);
250
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
1 cdef.normalEquationLst := list(obfuscateEquation(e, env) for e in cdef.normalEquationLst);
251
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
1 cdef.initialEquationLst := list(obfuscateEquation(e, env) for e in cdef.initialEquationLst);
252
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
1 cdef.normalAlgorithmLst := list(obfuscateAlgorithm(a, env) for a in cdef.normalAlgorithmLst);
253
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 time.
1 cdef.initialAlgorithmLst := list(obfuscateAlgorithm(a, env) for a in cdef.initialAlgorithmLst);
254 2 cdef.externalDecl := Util.applyOption(cdef.externalDecl,
255 function obfuscateExternalDecl(env = env));
256 then
257 ();
258
259 case SCode.ClassDef.CLASS_EXTENDS()
260 algorithm
261 ✗ cdef.modifications := obfuscateMod(cdef.modifications, env);
262 ✗ cdef.composition := obfuscateClassDef(cdef.composition, env);
263 then
264 ();
265
266 case SCode.ClassDef.DERIVED()
267 algorithm
268 ✗ cdef.typeSpec := obfuscateTypeSpec(cdef.typeSpec, env);
269 ✗ cdef.modifications := obfuscateMod(cdef.modifications, env);
270 ✗ cdef.attributes := obfuscateAttributes(cdef.attributes, env);
271 then
272 ();
273
274 case SCode.ClassDef.ENUMERATION()
275 algorithm
276 ✗ cdef.enumLst := list(obfuscateEnum(e, env) for e in cdef.enumLst);
277 then
278 ();
279
280 case SCode.ClassDef.OVERLOAD()
281 algorithm
282 ✗ cdef.pathLst := list(obfuscatePath(p, env, ElementType.TYPE) for p in cdef.pathLst);
283 then
284 ();
285
286 case SCode.ClassDef.PDER()
287 algorithm
288 ✗ cdef.functionPath := obfuscatePath(cdef.functionPath, env, ElementType.FUNCTION);
289 ✗ cdef.derivedVariables := list(obfuscateIdentifier(v, env, ElementType.OTHER) for v in cdef.derivedVariables);
290 then
291 ();
292 end match;
293 end obfuscateClassDef;
294
295 function obfuscateTypeSpec
296 input output Absyn.TypeSpec ty;
297 input Env env;
298 algorithm
299 () := match ty
300 case Absyn.TypeSpec.TPATH()
301 algorithm
302 1 ty.path := obfuscatePath(ty.path, env, ElementType.TYPE);
303 1 ty.arrayDim := obfuscateArrayDimsOpt(ty.arrayDim, env);
304 then
305 ();
306
307 case Absyn.TypeSpec.TCOMPLEX()
308 algorithm
309 ✗ ty.path := obfuscatePath(ty.path, env, ElementType.TYPE);
310 ✗ ty.typeSpecs := list(obfuscateTypeSpec(t, env) for t in ty.typeSpecs);
311 ✗ ty.arrayDim := obfuscateArrayDimsOpt(ty.arrayDim, env);
312 then
313 ();
314 end match;
315 end obfuscateTypeSpec;
316
317 function obfuscateEnum
318 input output SCode.Enum enum;
319 input Env env;
320 algorithm
321 ✗ enum.literal := obfuscateIdentifier(enum.literal, env, ElementType.OTHER);
322 enum.comment := obfuscateComment(enum.comment, env);
323 end obfuscateEnum;
324
325 function obfuscatePrefixes
326 input output SCode.Prefixes prefixes;
327 input Env env;
328 algorithm
329 2 prefixes.replaceablePrefix := obfuscateReplaceable(prefixes.replaceablePrefix, env);
330 end obfuscatePrefixes;
331
332 function obfuscateReplaceable
333 input output SCode.Replaceable repl;
334 input Env env;
335 protected
336 SCode.ConstrainClass cc;
337 algorithm
338 () := match repl
339 case SCode.Replaceable.REPLACEABLE(cc = SOME(cc))
340 algorithm
341 ✗ cc.constrainingClass := obfuscatePath(cc.constrainingClass, env, ElementType.OTHER);
342 ✗ cc.modifier := obfuscateMod(cc.modifier, env);
343 ✗ cc.comment := obfuscateComment(cc.comment, env);
344 ✗ repl.cc := SOME(cc);
345 then
346 ();
347
348 else ();
349 end match;
350 end obfuscateReplaceable;
351
352 function obfuscateAttributes
353 input output SCode.Attributes attributes;
354 input Env env;
355 algorithm
356 1 attributes.arrayDims := obfuscateArrayDims(attributes.arrayDims, env);
357 end obfuscateAttributes;
358
359 function obfuscateMod
360 input output SCode.Mod mod;
361 input Env env;
362 algorithm
363 () := match mod
364 case SCode.Mod.MOD()
365 algorithm
366 ✗ mod.subModLst := list(obfuscateSubMod(s, env) for s in mod.subModLst);
367 ✗ mod.binding := obfuscateExpOpt(mod.binding, env);
368 then
369 ();
370
371 case SCode.Mod.REDECL()
372 algorithm
373 ✗ mod.element := obfuscateElement(mod.element, env);
374 then
375 ();
376
377 else ();
378 end match;
379 end obfuscateMod;
380
381 function obfuscateSubMod
382 input output SCode.SubMod mod;
383 input Env env;
384 algorithm
385 ✗ mod.ident := obfuscateIdentifier(mod.ident, env, ElementType.OTHER);
386 mod.mod := obfuscateMod(mod.mod, env);
387 end obfuscateSubMod;
388
389 function obfuscatePath
390 input output Absyn.Path path;
391 input Env env;
392 input ElementType etype;
393 protected
394 Absyn.Ident name;
395 algorithm
396 () := match path
397 case Absyn.Path.IDENT()
398 algorithm
399 2 name := obfuscateIdentifier(path.name, env, etype);
400
401 // Don't obfuscate if it's a builtin name.
402
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
2 if referenceEq(name, path.name) then
403 1 return;
404 end if;
405
406 1 path.name := name;
407 then
408 ();
409
410 case Absyn.Path.QUALIFIED()
411 algorithm
412 ✗ name := obfuscateIdentifier(path.name, env, etype);
413
414 // Don't obfuscate if it's a builtin name, and don't obfuscate the
415 // rest of the path either.
416 ✗ if referenceEq(name, path.name) then
417 ✗ return;
418 end if;
419
420 ✗ path.name := name;
421 ✗ path.path := obfuscatePath(path.path, env, etype);
422 then
423 ();
424
425 case Absyn.Path.FULLYQUALIFIED()
426 algorithm
427 ✗ path.path := obfuscatePath(path.path, env, etype);
428 then
429 ();
430 end match;
431 end obfuscatePath;
432
433 function obfuscateIdentifier
434 input String id;
435 input Env env;
436 input ElementType etype;
437 output String outId;
438 output ElementType foundType;
439 protected
440 Builtins builtins = env.builtins;
441 Mapping mapping = env.mapping;
442 Option<ElementType> opt_ety;
443 algorithm
444 4 opt_ety := UnorderedMap.get(id, builtins);
445
446
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 3 times.
4 if isSome(opt_ety) then
447 1 SOME(foundType) := opt_ety;
448
449
1/2
✓ Branch 1 taken 1 time.
✗ Branch 2 not taken.
1 if isBuiltinInContext(etype, foundType) then
450 outId := id;
451 1 return;
452 end if;
453 else
454 foundType := ElementType.OTHER;
455 end if;
456
457 3 outId := UnorderedMap.addUpdate(id,
458 function makeId(index = UnorderedMap.size(mapping)), mapping);
459 end obfuscateIdentifier;
460
461 function isBuiltinInContext
462 input ElementType expectedType;
463 input ElementType actualType;
464 output Boolean res;
465 algorithm
466 res := match (expectedType, actualType)
467 // Looking for a type and found a builtin type.
468 case (ElementType.TYPE, ElementType.TYPE) then true;
469 case (ElementType.TYPE, ElementType.TYPE_AND_FUNCTION) then true;
470 // Looking for a function and found a builtin function.
471 case (ElementType.FUNCTION, ElementType.FUNCTION) then true;
472 case (ElementType.FUNCTION, ElementType.TYPE_AND_FUNCTION) then true;
473 // Looking for a type or function and found type or function.
474 case (ElementType.TYPE_AND_FUNCTION, ElementType.TYPE) then true;
475 case (ElementType.TYPE_AND_FUNCTION, ElementType.FUNCTION) then true;
476 case (ElementType.TYPE_AND_FUNCTION, ElementType.TYPE_AND_FUNCTION) then true;
477 // Looking for anything and found a builtin type, probably something like
478 // StateSelect used in an expression like StateSelect.prefer.
479 case (_, ElementType.TYPE) then true;
480 // Looking for anything and found something else, probably a builtin type
481 // attribute.
482 case (_, ElementType.OTHER) then true;
483 else false;
484 end match;
485 end isBuiltinInContext;
486
487 function makeId
488 input Option<String> oldId;
489 input Integer index;
490 output String id;
491 algorithm
492
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 1 time.
3 if isSome(oldId) then
493 1 SOME(id) := oldId;
494 else
495 2 id := "n" + String(index);
496 end if;
497 end makeId;
498
499 function obfuscateComment
500 input output SCode.Comment comment;
501 input Env env;
502 algorithm
503 3 comment.annotation_ := obfuscateAnnotationOpt(comment.annotation_, env);
504 comment.comment := NONE();
505 end obfuscateComment;
506
507 function obfuscateAnnotationOpt
508 input output Option<SCode.Annotation> ann;
509 input Env env;
510 algorithm
511 3 ann := Util.applyOption(ann, function obfuscateAnnotation(env = env));
512 end obfuscateAnnotationOpt;
513
514 function obfuscateAnnotation
515 input output SCode.Annotation ann;
516 input Env env;
517 algorithm
518 1 ann.modification := obfuscateAnnotationMod(ann.modification, env);
519 end obfuscateAnnotation;
520
521 function obfuscateAnnotationMod
522 input output SCode.Mod mod;
523 input Env env;
524 input Boolean obfuscateName = false;
525 input Boolean obfuscateBinding = true;
526 algorithm
527 () := match mod
528 case SCode.Mod.MOD()
529 algorithm
530
7/8
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 1 time.
✓ Branch 6 taken 2 times.
✓ Branch 9 taken 1 time.
✓ Branch 10 taken 1 time.
5 mod.subModLst := list(obfuscateAnnotationSubMod(s, env, obfuscateName)
531 for s guard isAllowedAnnotation(s) in mod.subModLst);
532
533
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 1 time.
2 if obfuscateBinding then
534 1 mod.binding := obfuscateExpOpt(mod.binding, env);
535 end if;
536 then
537 ();
538
539 else ();
540 end match;
541 end obfuscateAnnotationMod;
542
543 function isAllowedAnnotation
544 input SCode.SubMod mod;
545 output Boolean allowed;
546 algorithm
547 allowed := match mod.ident
548 case "Icon" then false;
549 case "Diagram" then false;
550 case "Dialog" then false;
551 case "IconMap" then false;
552 case "DiagramMap" then false;
553 case "Placement" then false;
554 case "Text" then false;
555 case "Line" then false;
556 case "defaultComponentName" then false;
557 case "defaultComponentPrefixes" then false;
558 case "missingInnerMessage" then false;
559 case "obsolete" then false;
560 case "unassignedMessage" then false;
561 case "Protection" then false;
562 case "Authorization" then false;
563
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 1 time.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
1 else StringUtil.startsWith(mod.ident, "__OpenModelica") or
564 not StringUtil.startsWith(mod.ident, "__");
565 end match;
566 end isAllowedAnnotation;
567
568 function obfuscateAnnotationSubMod
569 input output SCode.SubMod mod;
570 input Env env;
571 input Boolean obfuscateName;
572 protected
573 Boolean obfuscate_name, obfuscate_binding;
574 algorithm
575
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if obfuscateName then
576 ✗ mod.ident := obfuscateIdentifier(mod.ident, env, ElementType.OTHER);
577 end if;
578
579 obfuscate_name := match mod.ident
580 case "inverse" then true;
581 else false;
582 end match;
583
584 obfuscate_binding := match mod.ident
585 case "__OpenModelica_tearingSelect" then false;
586 else true;
587 end match;
588
589 1 mod.mod := obfuscateAnnotationMod(mod.mod, env, obfuscate_name, obfuscate_binding);
590 end obfuscateAnnotationSubMod;
591
592 function obfuscateExpOpt
593 input output Option<Absyn.Exp> exp;
594 input Env env;
595 algorithm
596 2 exp := Util.applyOption(exp, function obfuscateExp(env = env));
597 end obfuscateExpOpt;
598
599 function obfuscateExp
600 input output Absyn.Exp exp;
601 input Env env;
602 algorithm
603 ✗ exp := AbsynUtil.traverseExp(exp, obfuscateExpTraverse, env);
604 end obfuscateExp;
605
606 function obfuscateExpTraverse
607 input output Absyn.Exp exp;
608 input output Env env;
609 algorithm
610 () := match exp
611 case Absyn.Exp.CREF()
612 algorithm
613 // AbsynUtil.traverseExp traverses subscripts, so skip them here to
614 // avoid obfuscating them twice.
615 ✗ exp.componentRef := obfuscateCref(exp.componentRef, env, ElementType.OTHER, obfuscateSubs = false);
616 then
617 ();
618
619 case Absyn.Exp.CALL()
620 algorithm
621 ✗ exp.functionArgs := obfuscateFunctionArgs(exp.functionArgs, exp.function_, env);
622 ✗ exp.function_ := obfuscateCref(exp.function_, env, ElementType.FUNCTION, obfuscateSubs = false);
623 then
624 ();
625
626 case Absyn.Exp.PARTEVALFUNCTION()
627 algorithm
628 ✗ exp.functionArgs := obfuscateFunctionArgs(exp.functionArgs, exp.function_, env);
629 ✗ exp.function_ := obfuscateCref(exp.function_, env, ElementType.OTHER, obfuscateSubs = false);
630 then
631 ();
632
633 else ();
634 end match;
635 end obfuscateExpTraverse;
636
637 function obfuscateCref
638 input output Absyn.ComponentRef cref;
639 input Env env;
640 input ElementType etype;
641 input Boolean obfuscateSubs = true;
642 protected
643 Absyn.Ident name;
644 ElementType ety;
645 algorithm
646 () := match cref
647 case Absyn.ComponentRef.CREF_IDENT()
648 algorithm
649 ✗ name := obfuscateIdentifier(cref.name, env, etype);
650
651 // Don't obfuscate if it's a builtin name.
652 ✗ if referenceEq(name, cref.name) then
653 ✗ return;
654 end if;
655
656 ✗ cref.name := name;
657
658 ✗ if obfuscateSubs then
659 ✗ cref.subscripts := obfuscateSubscripts(cref.subscripts, env);
660 end if;
661 then
662 ();
663
664 case Absyn.ComponentRef.CREF_QUAL()
665 algorithm
666 ✗ (name, ety) := obfuscateIdentifier(cref.name, env, etype);
667
668 // Don't obfuscate if it's a builtin name, and don't obfuscate the
669 // rest of the cref either if it's a class.
670 //if referenceEq(name, cref.name) and ety <> ElementType.OTHER then
671 // return;
672 //end if;
673
674 ✗ if not referenceEq(name, cref.name) then
675 ✗ cref.name := name;
676 end if;
677
678 ✗ if ety == ElementType.OTHER then
679 ✗ if obfuscateSubs then
680 ✗ cref.subscripts := obfuscateSubscripts(cref.subscripts, env);
681 end if;
682
683 ✗ cref.componentRef := obfuscateCref(cref.componentRef, env, etype, obfuscateSubs);
684 end if;
685 then
686 ();
687
688 case Absyn.ComponentRef.CREF_FULLYQUALIFIED()
689 algorithm
690 ✗ cref.componentRef := obfuscateCref(cref.componentRef, env, etype, obfuscateSubs);
691 then
692 ();
693
694 else ();
695 end match;
696 end obfuscateCref;
697
698 function obfuscateSubscripts
699 input output list<Absyn.Subscript> subs;
700 input Env env;
701 algorithm
702
2/8
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 1 time.
✗ Branch 7 not taken.
✓ Branch 8 taken 1 time.
1 subs := list(obfuscateSubscript(s, env) for s in subs);
703 end obfuscateSubscripts;
704
705 function obfuscateSubscript
706 input output Absyn.Subscript sub;
707 input Env env;
708 algorithm
709 () := match sub
710 case Absyn.Subscript.SUBSCRIPT()
711 algorithm
712 ✗ sub.subscript := obfuscateExp(sub.subscript, env);
713 then
714 ();
715
716 else ();
717 end match;
718 end obfuscateSubscript;
719
720 function obfuscateFunctionArgs
721 "Obfuscates the names inside an Absyn.FunctionArgs (the expressions are
722 assumed to have already been obfuscated due to using AbsynUtil.traverseExp)."
723 input output Absyn.FunctionArgs args;
724 input Absyn.ComponentRef fnName;
725 input Env env;
726 algorithm
727 () := match args
728 // Normal function arguments, obfuscate the names of named arguments
729 // unless the function is builtin.
730 case Absyn.FunctionArgs.FUNCTIONARGS()
731 guard not listEmpty(args.argNames) and not isBuiltinCall(fnName, env)
732 algorithm
733 ✗ args.argNames := list(obfuscateNamedArg(a, env) for a in args.argNames);
734 then
735 ();
736
737 // Iterator arguments, obfuscate the iterators' names.
738 case Absyn.FunctionArgs.FOR_ITER_FARG()
739 algorithm
740 ✗ args.iterators := list(obfuscateForIterator(i, env) for i in args.iterators);
741 then
742 ();
743
744 else ();
745 end match;
746 end obfuscateFunctionArgs;
747
748 function obfuscateNamedArg
749 input output Absyn.NamedArg arg;
750 input Env env;
751 algorithm
752 ✗ arg.argName := obfuscateIdentifier(arg.argName, env, ElementType.OTHER);
753 end obfuscateNamedArg;
754
755 function obfuscateForIterator
756 input output Absyn.ForIterator iterator;
757 input Env env;
758 algorithm
759 ✗ iterator.name := obfuscateIdentifier(iterator.name, env, ElementType.OTHER);
760 end obfuscateForIterator;
761
762 function obfuscateArrayDimsOpt
763 input output Option<Absyn.ArrayDim> dims;
764 input Env env;
765 algorithm
766 1 dims := Util.applyOption(dims, function obfuscateArrayDims(env = env));
767 end obfuscateArrayDimsOpt;
768
769 function obfuscateArrayDims = obfuscateSubscripts;
770
771 function obfuscateExternalDecl
772 input output SCode.ExternalDecl extDecl;
773 input Env env;
774 algorithm
775 ✗ extDecl.args := list(obfuscateExp(a, env) for a in extDecl.args);
776 extDecl.output_ := Util.applyOption(extDecl.output_,
777 function obfuscateCref(env = env, etype = ElementType.OTHER, obfuscateSubs = true));
778 extDecl.annotation_ := obfuscateAnnotationOpt(extDecl.annotation_, env);
779 end obfuscateExternalDecl;
780
781 function obfuscateEquations
782 input output list<SCode.Equation> eql;
783 input Env env;
784 algorithm
785 ✗ eql := list(obfuscateEquation(eq, env) for eq in eql);
786 end obfuscateEquations;
787
788 function obfuscateEquation
789 input output SCode.Equation eq;
790 input Env env;
791 algorithm
792 () := match eq
793 case SCode.Equation.EQ_IF()
794 algorithm
795 ✗ eq.condition := list(obfuscateExp(e, env) for e in eq.condition);
796 ✗ eq.thenBranch := list(obfuscateEquations(e, env) for e in eq.thenBranch);
797 ✗ eq.elseBranch := obfuscateEquations(eq.elseBranch, env);
798 ✗ eq.comment := obfuscateComment(eq.comment, env);
799 then
800 ();
801
802 case SCode.Equation.EQ_EQUALS()
803 algorithm
804 ✗ eq.expLeft := obfuscateExp(eq.expLeft, env);
805 ✗ eq.expRight := obfuscateExp(eq.expRight, env);
806 ✗ eq.comment := obfuscateComment(eq.comment, env);
807 then
808 ();
809
810 case SCode.Equation.EQ_PDE()
811 algorithm
812 ✗ eq.expLeft := obfuscateExp(eq.expLeft, env);
813 ✗ eq.expRight := obfuscateExp(eq.expRight, env);
814 ✗ eq.comment := obfuscateComment(eq.comment, env);
815 then
816 ();
817
818 case SCode.Equation.EQ_CONNECT()
819 algorithm
820 ✗ eq.crefLeft := obfuscateCref(eq.crefLeft, env, ElementType.OTHER);
821 ✗ eq.crefRight := obfuscateCref(eq.crefRight, env, ElementType.OTHER);
822 ✗ eq.comment := obfuscateComment(eq.comment, env);
823 then
824 ();
825
826 case SCode.Equation.EQ_FOR()
827 algorithm
828 ✗ eq.index := obfuscateIdentifier(eq.index, env, ElementType.OTHER);
829 ✗ eq.range := obfuscateExpOpt(eq.range, env);
830 ✗ eq.eEquationLst := obfuscateEquations(eq.eEquationLst, env);
831 ✗ eq.comment := obfuscateComment(eq.comment, env);
832 then
833 ();
834
835 case SCode.Equation.EQ_WHEN()
836 algorithm
837 ✗ eq.condition := obfuscateExp(eq.condition, env);
838 ✗ eq.eEquationLst := obfuscateEquations(eq.eEquationLst, env);
839 ✗ eq.elseBranches := list(
840 (obfuscateExp(Util.tuple21(b), env),
841 obfuscateEquations(Util.tuple22(b), env)) for b in eq.elseBranches);
842 ✗ eq.comment := obfuscateComment(eq.comment, env);
843 then
844 ();
845
846 case SCode.Equation.EQ_ASSERT()
847 algorithm
848 ✗ eq.condition := obfuscateExp(eq.condition, env);
849 ✗ eq.message := obfuscateMessage(eq.message, "assert");
850 ✗ eq.level := obfuscateExp(eq.level, env);
851 ✗ eq.comment := obfuscateComment(eq.comment, env);
852 then
853 ();
854
855 case SCode.Equation.EQ_TERMINATE()
856 algorithm
857 ✗ eq.message := obfuscateMessage(eq.message, "terminate");
858 ✗ eq.comment := obfuscateComment(eq.comment, env);
859 then
860 ();
861
862 case SCode.Equation.EQ_REINIT()
863 algorithm
864 ✗ eq.cref := obfuscateExp(eq.cref, env);
865 ✗ eq.expReinit := obfuscateExp(eq.expReinit, env);
866 ✗ eq.comment := obfuscateComment(eq.comment, env);
867 then
868 ();
869
870 case SCode.Equation.EQ_NORETCALL()
871 algorithm
872 ✗ eq.exp := obfuscateExp(eq.exp, env);
873 ✗ eq.comment := obfuscateComment(eq.comment, env);
874 then
875 ();
876 end match;
877 end obfuscateEquation;
878
879 function obfuscateMessage
880 "Obfuscates the message of assert/terminate by replacing it with
881 '<%fnName%> message <%hash of message%>'"
882 input output Absyn.Exp message;
883 input String fnName;
884 protected
885 String msg_str;
886 algorithm
887 msg_str := match message
888 ✗ case Absyn.Exp.STRING() then message.value;
889 // The message should be a string, but just to be safe.
890 ✗ else Dump.printExpStr(message);
891 end match;
892
893 ✗ msg_str := String(stringHashDjb2(msg_str));
894 ✗ msg_str := fnName + " message " + msg_str;
895 ✗ message := Absyn.Exp.STRING(msg_str);
896 end obfuscateMessage;
897
898 function obfuscateAlgorithm
899 input output SCode.AlgorithmSection alg;
900 input Env env;
901 algorithm
902 ✗ alg.statements := obfuscateStatements(alg.statements, env);
903 end obfuscateAlgorithm;
904
905 function obfuscateStatements
906 input output list<SCode.Statement> stmts;
907 input Env env;
908 algorithm
909 ✗ stmts := list(obfuscateStatement(s, env) for s in stmts);
910 end obfuscateStatements;
911
912 function obfuscateStatement
913 input output SCode.Statement stmt;
914 input Env env;
915 algorithm
916 () := match stmt
917 case SCode.Statement.ALG_ASSIGN()
918 algorithm
919 ✗ stmt.assignComponent := obfuscateExp(stmt.assignComponent, env);
920 ✗ stmt.value := obfuscateExp(stmt.value, env);
921 ✗ stmt.comment := obfuscateComment(stmt.comment, env);
922 then
923 ();
924
925 case SCode.Statement.ALG_IF()
926 algorithm
927 ✗ stmt.boolExpr := obfuscateExp(stmt.boolExpr, env);
928 ✗ stmt.trueBranch := obfuscateStatements(stmt.trueBranch, env);
929 ✗ stmt.elseIfBranch := list(
930 (obfuscateExp(Util.tuple21(b), env),
931 obfuscateStatements(Util.tuple22(b), env)) for b in stmt.elseIfBranch);
932 ✗ stmt.elseBranch := obfuscateStatements(stmt.elseBranch, env);
933 ✗ stmt.comment := obfuscateComment(stmt.comment, env);
934 then
935 ();
936
937 case SCode.Statement.ALG_FOR()
938 algorithm
939 ✗ stmt.index := obfuscateIdentifier(stmt.index, env, ElementType.OTHER);
940 ✗ stmt.range := obfuscateExpOpt(stmt.range, env);
941 ✗ stmt.forBody := obfuscateStatements(stmt.forBody, env);
942 ✗ stmt.comment := obfuscateComment(stmt.comment, env);
943 then
944 ();
945
946 case SCode.Statement.ALG_PARFOR()
947 algorithm
948 ✗ stmt.index := obfuscateIdentifier(stmt.index, env, ElementType.OTHER);
949 ✗ stmt.range := obfuscateExpOpt(stmt.range, env);
950 ✗ stmt.parforBody := obfuscateStatements(stmt.parforBody, env);
951 ✗ stmt.comment := obfuscateComment(stmt.comment, env);
952 then
953 ();
954
955 case SCode.Statement.ALG_WHILE()
956 algorithm
957 ✗ stmt.boolExpr := obfuscateExp(stmt.boolExpr, env);
958 ✗ stmt.whileBody := obfuscateStatements(stmt.whileBody, env);
959 ✗ stmt.comment := obfuscateComment(stmt.comment, env);
960 then
961 ();
962
963 case SCode.Statement.ALG_WHEN_A()
964 algorithm
965 ✗ stmt.branches := list(
966 (obfuscateExp(Util.tuple21(b), env),
967 obfuscateStatements(Util.tuple22(b), env)) for b in stmt.branches);
968 ✗ stmt.comment := obfuscateComment(stmt.comment, env);
969 then
970 ();
971
972 case SCode.Statement.ALG_ASSERT()
973 algorithm
974 ✗ stmt.condition := obfuscateExp(stmt.condition, env);
975 ✗ stmt.message := obfuscateMessage(stmt.message, "assert");
976 ✗ stmt.level := obfuscateExp(stmt.level, env);
977 ✗ stmt.comment := obfuscateComment(stmt.comment, env);
978 then
979 ();
980
981 case SCode.Statement.ALG_TERMINATE()
982 algorithm
983 ✗ stmt.message := obfuscateMessage(stmt.message, "terminate");
984 ✗ stmt.comment := obfuscateComment(stmt.comment, env);
985 then
986 ();
987
988 case SCode.Statement.ALG_REINIT()
989 algorithm
990 ✗ stmt.cref := obfuscateExp(stmt.cref, env);
991 ✗ stmt.newValue := obfuscateExp(stmt.newValue, env);
992 ✗ stmt.comment := obfuscateComment(stmt.comment, env);
993 then
994 ();
995
996 case SCode.Statement.ALG_NORETCALL()
997 algorithm
998 ✗ stmt.exp := obfuscateExp(stmt.exp, env);
999 ✗ stmt.comment := obfuscateComment(stmt.comment, env);
1000 then
1001 ();
1002
1003 case SCode.Statement.ALG_RETURN()
1004 algorithm
1005 ✗ stmt.comment := obfuscateComment(stmt.comment, env);
1006 then
1007 ();
1008
1009 case SCode.Statement.ALG_BREAK()
1010 algorithm
1011 ✗ stmt.comment := obfuscateComment(stmt.comment, env);
1012 then
1013 ();
1014
1015 else ();
1016 end match;
1017 end obfuscateStatement;
1018
1019 function isBuiltinCall
1020 input Absyn.ComponentRef callName;
1021 input Env env;
1022 output Boolean res;
1023 protected
1024 String name;
1025 ElementType ety;
1026 algorithm
1027 ✗ name := AbsynUtil.crefFirstIdent(callName);
1028 ✗ ety := UnorderedMap.getOrDefault(name, env.builtins, ElementType.OTHER);
1029 ✗ res := ety == ElementType.FUNCTION or ety == ElementType.TYPE_AND_FUNCTION;
1030 end isBuiltinCall;
1031
1032 annotation(__OpenModelica_Interface="backend_tools");
1033 end Obfuscate;
1034